« Return to Thread: Update of editing/selection code in khtml

Update of editing/selection code in khtml

by Bugzilla from tsjoker@gmail.com :: Rate this Message:

Reply to Author | View in Thread

Hello,

I'd like to write a short note about what I've been doing lately.
I've taken latest classes from WebCore that are responsible for editing, selecting etc and start to port / update old classes that we already have.
Here is the short list of important ones:
DOM::Selection
DOM::SelectionController
DOM::Position
DOM::PositionIterator
DOM::VisiblePosition

I'm attaching the current diff between my master and work kdelibs branches.
A lot of stuff is still missing, and needs some work, but I hope to have it more or less stable for 4.3 soft freeze.
However, caret positioning and movement, selection already somewhat works.

Please feel free to comment.

Best regards,
Vyacheslav Tokarev (vtokarev)

[editing.patch]

diff --git a/cmake/modules/FindKDE4Internal.cmake b/cmake/modules/FindKDE4Internal.cmake
index 09115cf..b4bc3fe 100644
--- a/cmake/modules/FindKDE4Internal.cmake
+++ b/cmake/modules/FindKDE4Internal.cmake
@@ -1042,6 +1042,8 @@ if (CMAKE_COMPILER_IS_GNUCXX)
       string(REGEX MATCH "(--enable-libstdcxx-allocator=mt)" _GCC_COMPILED_WITH_BAD_ALLOCATOR "${_gcc_alloc_info}")
    endif (GCC_IS_NEWER_THAN_4_1)
 
+   set(__KDE_HAVE_GCC_VISIBILITY 0)
+
    if (__KDE_HAVE_GCC_VISIBILITY AND GCC_IS_NEWER_THAN_4_1 AND NOT _GCC_COMPILED_WITH_BAD_ALLOCATOR)
       set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
       set (KDE4_C_FLAGS "-fvisibility=hidden")
diff --git a/khtml/CMakeLists.txt b/khtml/CMakeLists.txt
index 2ce70da..d7124d9 100644
--- a/khtml/CMakeLists.txt
+++ b/khtml/CMakeLists.txt
@@ -367,9 +367,17 @@ set(khtmlxml_STAT_SRCS
   ${CMAKE_SOURCE_DIR}/khtml/xml/dom_restyler.cpp
   ${CMAKE_SOURCE_DIR}/khtml/xml/ClassNames.cpp
   ${CMAKE_SOURCE_DIR}/khtml/xml/ClassNodeList.cpp
-  ${CMAKE_SOURCE_DIR}/khtml/xml/dom_position.cpp
-  ${CMAKE_SOURCE_DIR}/khtml/xml/dom_positioniterator.cpp
-  ${CMAKE_SOURCE_DIR}/khtml/xml/dom_selection.cpp
+  #${CMAKE_SOURCE_DIR}/khtml/xml/dom_position.cpp
+  #${CMAKE_SOURCE_DIR}/khtml/xml/dom_positioniterator.cpp
+  #${CMAKE_SOURCE_DIR}/khtml/xml/dom_selection.cpp
+  ${CMAKE_SOURCE_DIR}/khtml/xml/VisiblePosition.cpp
+  ${CMAKE_SOURCE_DIR}/khtml/xml/Position.cpp
+  ${CMAKE_SOURCE_DIR}/khtml/xml/PositionIterator.cpp
+  ${CMAKE_SOURCE_DIR}/khtml/xml/editing_helper.cpp
+  ${CMAKE_SOURCE_DIR}/khtml/xml/visible_units.cpp
+  ${CMAKE_SOURCE_DIR}/khtml/editing/TextIterator.cpp
+  ${CMAKE_SOURCE_DIR}/khtml/xml/Selection.cpp
+  ${CMAKE_SOURCE_DIR}/khtml/xml/SelectionController.cpp
 )
 
 # khtml/imload/Makefile.am: khtmlimload
diff --git a/khtml/css/css_base.cpp b/khtml/css/css_base.cpp
index 4f0a44b..9927982 100644
--- a/khtml/css/css_base.cpp
+++ b/khtml/css/css_base.cpp
@@ -310,12 +310,12 @@ bool CSSSelector::operator == ( const CSSSelector &other ) const
     while ( sel1 && sel2 ) {
         //assert(sel1->_pseudoType != PseudoNotParsed);
         //assert(sel2->_pseudoType != PseudoNotParsed);
- if ( sel1->tagLocalName.id() != sel2->tagLocalName.id() || sel1->attrLocalName.id() != sel2->attrLocalName.id() ||
-         sel1->tagNamespace.id() != sel2->tagNamespace.id() || sel1->attrNamespace.id() != sel2->attrNamespace.id() ||
+        if (sel1->value != sel2->value ||
+             makeId(sel1->tagLocalName.id(), sel1->attrLocalName.id()) != makeId(sel2->tagLocalName.id(), sel2->attrLocalName.id()) ||
      sel1->relation != sel2->relation || sel1->match != sel2->match ||
-     sel1->value != sel2->value ||
+             makeId(sel1->tagNamespace.id(), sel1->attrNamespace.id()) != makeId(sel2->tagNamespace.id(), sel2->attrNamespace.id()) ||
              sel1->pseudoType() != sel2->pseudoType() ||
-             sel1->string_arg != sel2->string_arg)
+             strcmp(sel1->string_arg.implementation(), sel2->string_arg.implementation()))
     return false;
  sel1 = sel1->tagHistory;
  sel2 = sel2->tagHistory;
diff --git a/khtml/editing/TextIterator.cpp b/khtml/editing/TextIterator.cpp
new file mode 100644
index 0000000..03dfe81
--- /dev/null
+++ b/khtml/editing/TextIterator.cpp
@@ -0,0 +1,1465 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2005 Alexey Proskuryakov.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "TextIterator.h"
+
+/*#include "CharacterNames.h"
+#include "Document.h"
+#include "Element.h"
+#include "HTMLNames.h"
+#include "htmlediting.h"
+#include "InlineTextBox.h"
+#include "Position.h"
+#include "Range.h"
+#include "RenderTableCell.h"
+#include "RenderTableRow.h"
+#include "RenderTextControl.h"*/
+#include "xml/visible_units.h"
+#include "xml/editing_helper.h"
+#include "xml/dom_elementimpl.h"
+#include "rendering/render_object.h"
+#include <algorithm>
+#include "xml/VisiblePosition.h"
+#include "xml/Position.h"
+#include "rendering/render_table.h"
+
+using namespace std;
+//using namespace WTF::Unicode;
+
+using namespace DOM;
+
+namespace khtml {
+#define ExceptionCode int
+
+// Buffer that knows how to compare with a search target.
+// Keeps enough of the previous text to be able to search in the future, but no more.
+class CircularSearchBuffer : Noncopyable {
+public:
+    CircularSearchBuffer(const DOMString& target, bool isCaseSensitive);
+
+    void clear() { m_cursor = 0; m_isBufferFull = false; }
+    void append(QChar);
+
+    bool isMatch() const;
+    unsigned length() const;
+
+private:
+    void append(QChar, bool isCharacterStart);
+
+    DOMString m_target;
+    bool m_isCaseSensitive;
+
+    Vector<QChar> m_characterBuffer;
+    Vector<bool> m_isCharacterStartBuffer;
+    bool m_isBufferFull;
+    unsigned m_cursor;
+};
+
+// --------
+
+TextIterator::TextIterator()
+    : m_startContainer(0)
+    , m_startOffset(0)
+    , m_endContainer(0)
+    , m_endOffset(0)
+    , m_positionNode(0)
+    , m_lastCharacter(0)
+    , m_emitCharactersBetweenAllVisiblePositions(false)
+    , m_enterTextControls(false)
+{
+}
+
+TextIterator::TextIterator(const RangeImpl* r, bool emitCharactersBetweenAllVisiblePositions, bool enterTextControls)
+    : m_inShadowContent(false)
+    , m_startContainer(0)
+    , m_startOffset(0)
+    , m_endContainer(0)
+    , m_endOffset(0)
+    , m_positionNode(0)
+    , m_emitCharactersBetweenAllVisiblePositions(emitCharactersBetweenAllVisiblePositions)
+    , m_enterTextControls(enterTextControls)
+{
+    if (!r)
+        return;
+
+    //ExceptionCode ec = 0;
+    int ec = 0;
+    
+    // get and validate the range endpoints
+    NodeImpl *startContainer = r->startContainer(ec);
+    int startOffset = r->startOffset(ec);
+    NodeImpl *endContainer = r->endContainer(ec);
+    int endOffset = r->endOffset(ec);
+    if (ec)
+        return;
+
+    // Callers should be handing us well-formed ranges. If we discover that this isn't
+    // the case, we could consider changing this assertion to an early return.
+    ASSERT(r->boundaryPointsValid());
+
+    // remember range - this does not change
+    m_startContainer = startContainer;
+    m_startOffset = startOffset;
+    m_endContainer = endContainer;
+    m_endOffset = endOffset;
+
+    for (NodeImpl* n = startContainer; n; n = n->parentNode()) {
+        if (n->isShadowNode()) {
+            m_inShadowContent = true;
+            break;
+        }
+    }
+
+    // set up the current node for processing
+    m_node = r->firstNode();
+    if (m_node == 0)
+        return;
+    m_offset = m_node == m_startContainer ? m_startOffset : 0;
+    m_handledNode = false;
+    m_handledChildren = false;
+
+    // calculate first out of bounds node
+    m_pastEndNode = r->pastLastNode();
+
+    // initialize node processing state
+    m_needAnotherNewline = false;
+    m_textBox = 0;
+
+    // initialize record of previous node processing
+    m_haveEmitted = false;
+    m_lastTextNode = 0;
+    m_lastTextNodeEndedWithCollapsedSpace = false;
+    m_lastCharacter = 0;
+
+#ifndef NDEBUG
+    // need this just because of the assert in advance()
+    m_positionNode = m_node;
+#endif
+
+    // identify the first run
+    advance();
+}
+
+void TextIterator::advance()
+{
+    // reset the run information
+    m_positionNode = 0;
+    m_textLength = 0;
+
+    // handle remembered node that needed a newline after the text node's newline
+    if (m_needAnotherNewline) {
+        // Emit the extra newline, and position it *inside* m_node, after m_node's
+        // contents, in case it's a block, in the same way that we position the first
+        // newline.  The range for the emitted newline should start where the line
+        // break begins.
+        // FIXME: It would be cleaner if we emitted two newlines during the last
+        // iteration, instead of using m_needAnotherNewline.
+        NodeImpl* baseNode = m_node->lastChild() ? m_node->lastChild() : m_node;
+        emitCharacter('\n', baseNode->parentNode(), baseNode, 1, 1);
+        m_needAnotherNewline = false;
+        return;
+    }
+
+    // handle remembered text box
+    if (m_textBox) {
+        handleTextBox();
+        if (m_positionNode)
+            return;
+    }
+
+    while (m_node && m_node != m_pastEndNode) {
+        // if the range ends at offset 0 of an element, represent the
+        // position, but not the content, of that element e.g. if the
+        // node is a blockflow element, emit a newline that
+        // precedes the element
+        if (m_node == m_endContainer && m_endOffset == 0) {
+            representNodeOffsetZero();
+            m_node = 0;
+            return;
+        }
+        
+        RenderObject *renderer = m_node->renderer();
+        if (!renderer) {
+            m_handledNode = true;
+            m_handledChildren = true;
+        } else {
+            // handle current node according to its type
+            if (!m_handledNode) {
+                if (renderer->isText() && m_node->nodeType() == Node::TEXT_NODE) // FIXME: What about CDATA_SECTION_NODE?
+                    m_handledNode = handleTextNode();
+                else if (renderer && (/*FIXME khtml renderer->isImage() || */renderer->isWidget() /*|| (renderer->element() && renderer->element()->isControl())*/))
+                    m_handledNode = handleReplacedElement();
+                else
+                    m_handledNode = handleNonTextNode();
+                if (m_positionNode)
+                    return;
+            }
+        }
+
+        // find a new current node to handle in depth-first manner,
+        // calling exitNode() as we come back thru a parent node
+        NodeImpl *next = m_handledChildren ? 0 : m_node->firstChild();
+        m_offset = 0;
+        if (!next) {
+            next = m_node->nextSibling();
+            if (!next) {
+                bool pastEnd = m_node->traverseNextNode() == m_pastEndNode;
+                NodeImpl* parentNode = m_node->parentNode();
+                if (!parentNode && m_inShadowContent) {
+                    m_inShadowContent = false;
+                    parentNode = m_node->shadowParentNode();
+                }
+                while (!next && parentNode) {
+                    if (pastEnd && parentNode == m_endContainer || m_endContainer->isDescendantOf(parentNode))
+                        return;
+                    bool haveRenderer = m_node->renderer();
+                    m_node = parentNode;
+                    parentNode = m_node->parentNode();
+                    if (!parentNode && m_inShadowContent) {
+                        m_inShadowContent = false;
+                        parentNode = m_node->shadowParentNode();
+                    }
+                    if (haveRenderer)
+                        exitNode();
+                    if (m_positionNode) {
+                        m_handledNode = true;
+                        m_handledChildren = true;
+                        return;
+                    }
+                    next = m_node->nextSibling();
+                }
+            }
+        }
+
+        // set the new current node
+        m_node = next;
+        m_handledNode = false;
+        m_handledChildren = false;
+
+        // how would this ever be?
+        if (m_positionNode)
+            return;
+    }
+}
+
+static inline bool compareBoxStart(const InlineTextBox *first, const InlineTextBox *second)
+{
+    return first->start() < second->start();
+}
+
+bool TextIterator::handleTextNode()
+{
+    RenderText* renderer = static_cast<RenderText*>(m_node->renderer());
+    if (renderer->style()->visibility() != VISIBLE)
+        return false;
+        
+    m_lastTextNode = m_node;
+    DOMString str(renderer->text(), renderer->length());
+
+    // handle pre-formatted text
+    /*FIXME khtml porrt if (!renderer->style()->collapseWhiteSpace()) {
+        int runStart = m_offset;
+        if (m_lastTextNodeEndedWithCollapsedSpace) {
+            emitCharacter(' ', m_node, 0, runStart, runStart);
+            return false;
+        }
+        int strLength = str.length();
+        int end = (m_node == m_endContainer) ? m_endOffset : INT_MAX;
+        int runEnd = min(strLength, end);
+
+        if (runStart >= runEnd)
+            return true;
+
+        emitText(m_node, runStart, runEnd);
+        return true;
+    }*/
+
+    if (!renderer->firstTextBox() && str.length() > 0) {
+        m_lastTextNodeEndedWithCollapsedSpace = true; // entire block is collapsed space
+        return true;
+    }
+
+    // Used when text boxes are out of order (Hebrew/Arabic w/ embeded LTR text)
+    /*FIXME ktml if (renderer->containsReversedText()) {
+        m_sortedTextBoxes.clear();
+        for (InlineTextBox * textBox = renderer->firstTextBox(); textBox; textBox = textBox->nextTextBox()) {
+            m_sortedTextBoxes.append(textBox);
+        }
+        std::sort(m_sortedTextBoxes.begin(), m_sortedTextBoxes.end(), compareBoxStart);
+        m_sortedTextBoxesPosition = 0;
+    }*/
+    
+    m_textBox = /*renderer->containsReversedText()*/false ? m_sortedTextBoxes[0] : renderer->firstTextBox();
+    handleTextBox();
+    return true;
+}
+
+void TextIterator::handleTextBox()
+{    
+    RenderText *renderer = static_cast<RenderText *>(m_node->renderer());
+    DOMString str(renderer->text(), renderer->length());
+    int start = m_offset;
+    int end = (m_node == m_endContainer) ? m_endOffset : INT_MAX;
+    while (m_textBox) {
+        int textBoxStart = m_textBox->m_start;
+        int runStart = max(textBoxStart, start);
+
+        // Check for collapsed space at the start of this run.
+        InlineTextBox *firstTextBox = /*fixme khtml renderer->containsReversedText()*/false ? m_sortedTextBoxes[0] : renderer->firstTextBox();
+        bool needSpace = m_lastTextNodeEndedWithCollapsedSpace
+            || (m_textBox == firstTextBox && textBoxStart == runStart && runStart > 0);
+        if (needSpace && !isCollapsibleWhitespace(m_lastCharacter) && m_lastCharacter != QChar()) {
+            emitCharacter(' ', m_node, 0, runStart, runStart);
+            return;
+        }
+        int textBoxEnd = textBoxStart + m_textBox->m_len;
+        int runEnd = min(textBoxEnd, end);
+        
+        // Determine what the next text box will be, but don't advance yet
+        InlineTextBox *nextTextBox = 0;
+        /*FIXME khtml if (renderer->containsReversedText()) {
+            if (m_sortedTextBoxesPosition + 1 < m_sortedTextBoxes.size())
+                nextTextBox = m_sortedTextBoxes[m_sortedTextBoxesPosition + 1];
+        } else */
+            nextTextBox = m_textBox->nextTextBox();
+
+        if (runStart < runEnd) {
+            // Handle either a single newline character (which becomes a space),
+            // or a run of characters that does not include a newline.
+            // This effectively translates newlines to spaces without copying the text.
+            if (str[runStart] == '\n') {
+                emitCharacter(' ', m_node, 0, runStart, runStart + 1);
+                m_offset = runStart + 1;
+            } else {
+                int subrunEnd = str.find('\n', runStart);
+                if (subrunEnd == -1 || subrunEnd > runEnd)
+                    subrunEnd = runEnd;
+    
+                m_offset = subrunEnd;
+                emitText(m_node, runStart, subrunEnd);
+            }
+
+            // If we are doing a subrun that doesn't go to the end of the text box,
+            // come back again to finish handling this text box; don't advance to the next one.
+            if (m_positionEndOffset < textBoxEnd)
+                return;
+
+            // Advance and return
+            int nextRunStart = nextTextBox ? nextTextBox->m_start : str.length();
+            if (nextRunStart > runEnd)
+                m_lastTextNodeEndedWithCollapsedSpace = true; // collapsed space between runs or at the end
+            m_textBox = nextTextBox;
+            /*FIXME khtml if (renderer->containsReversedText())
+                ++m_sortedTextBoxesPosition;*/
+            return;
+        }
+        // Advance and continue
+        m_textBox = nextTextBox;
+        /*FIXME khtml if (renderer->containsReversedText())
+            ++m_sortedTextBoxesPosition;*/
+    }
+}
+
+bool TextIterator::handleReplacedElement()
+{
+    RenderObject* renderer = m_node->renderer();
+    if (renderer->style()->visibility() != VISIBLE)
+        return false;
+
+    if (m_lastTextNodeEndedWithCollapsedSpace) {
+        emitCharacter(' ', m_lastTextNode->parentNode(), m_lastTextNode, 1, 1);
+        return false;
+    }
+
+    /*if (m_enterTextControls && (renderer->isTextArea() || renderer->isTextField())) {
+        FIXME khtml m_node = static_cast<RenderTextControl*>(renderer)->innerTextElement();
+        m_offset = 0;
+        m_inShadowContent = true;
+        return false;
+    }*/
+
+    m_haveEmitted = true;
+
+    if (m_emitCharactersBetweenAllVisiblePositions) {
+        // We want replaced elements to behave like punctuation for boundary
+        // finding, and to simply take up space for the selection preservation
+        // code in moveParagraphs, so we use a comma.
+        emitCharacter(',', m_node->parentNode(), m_node, 0, 1);
+        return true;
+    }
+
+    m_positionNode = m_node->parentNode();
+    m_positionOffsetBaseNode = m_node;
+    m_positionStartOffset = 0;
+    m_positionEndOffset = 1;
+
+    m_textCharacters = 0;
+    m_textLength = 0;
+
+    m_lastCharacter = 0;
+
+    return true;
+}
+
+static bool shouldEmitTabBeforeNode(NodeImpl* node)
+{
+    RenderObject* r = node->renderer();
+    
+    // Table cells are delimited by tabs.
+    if (!r || !isTableCell(node))
+        return false;
+    
+    // Want a tab before every cell other than the first one
+    RenderTableCell* rc = static_cast<RenderTableCell*>(r);
+    RenderTable* t = rc->table();
+    return t && (t->cellBefore(rc) || t->cellAbove(rc));
+}
+
+static bool shouldEmitNewlineForNode(NodeImpl* node)
+{
+    // br elements are represented by a single newline.
+    RenderObject* r = node->renderer();
+    if (!r)
+        return /*node->hasTagName(brTag)*/node->id() == ID_BR;
+        
+    return r->isBR();
+}
+
+static bool shouldEmitNewlinesBeforeAndAfterNode(NodeImpl* node)
+{
+    // Block flow (versus inline flow) is represented by having
+    // a newline both before and after the element.
+    RenderObject* r = node->renderer();
+    if (!r) {
+        return (node->hasTagName(/*blockquoteTag*/ID_BLOCKQUOTE)
+                || node->hasTagName(/*ddTag*/ID_DD)
+                || node->hasTagName(/*divTag*/ID_DIV)
+                || node->hasTagName(/*dlTag*/ID_DL)
+                || node->hasTagName(/*dtTag*/ID_DT)
+                || node->hasTagName(/*h1Tag*/ID_H1)
+                || node->hasTagName(/*h2Tag*/ID_H2)
+                || node->hasTagName(/*h3Tag*/ID_H3)
+                || node->hasTagName(/*h4Tag*/ID_H4)
+                || node->hasTagName(/*h5Tag*/ID_H5)
+                || node->hasTagName(/*h6Tag*/ID_H6)
+                || node->hasTagName(/*hrTag*/ID_HR)
+                || node->hasTagName(/*liTag*/ID_LI)
+                || node->hasTagName(/*listingTag*/ID_LISTING)
+                || node->hasTagName(/*olTag*/ID_OL)
+                || node->hasTagName(/*pTag*/ID_P)
+                || node->hasTagName(/*preTag*/ID_PRE)
+                || node->hasTagName(/*trTag*/ID_TR)
+                || node->hasTagName(/*ulTag*/ID_UL));
+    }
+    
+    // Need to make an exception for table cells, because they are blocks, but we
+    // want them tab-delimited rather than having newlines before and after.
+    if (isTableCell(node))
+        return false;
+    
+    // Need to make an exception for table row elements, because they are neither
+    // "inline" or "RenderBlock", but we want newlines for them.
+    if (r->isTableRow()) {
+        RenderTable* t = static_cast<RenderTableRow*>(r)->table();
+        if (t && !t->isInline())
+            return true;
+    }
+    
+    return !r->isInline() && r->isRenderBlock() && !r->isFloatingOrPositioned() && !r->isBody();
+}
+
+static bool shouldEmitNewlineAfterNode(NodeImpl* node)
+{
+    // FIXME: It should be better but slower to create a VisiblePosition here.
+    if (!shouldEmitNewlinesBeforeAndAfterNode(node))
+        return false;
+    // Check if this is the very last renderer in the document.
+    // If so, then we should not emit a newline.
+    while ((node = node->traverseNextSibling()))
+        if (node->renderer())
+            return true;
+    return false;
+}
+
+static bool shouldEmitNewlineBeforeNode(NodeImpl* node)
+{
+    return shouldEmitNewlinesBeforeAndAfterNode(node);
+}
+
+static bool shouldEmitExtraNewlineForNode(NodeImpl* node)
+{
+    // When there is a significant collapsed bottom margin, emit an extra
+    // newline for a more realistic result.  We end up getting the right
+    // result even without margin collapsing. For example: <div><p>text</p></div>
+    // will work right even if both the <div> and the <p> have bottom margins.
+    RenderObject* r = node->renderer();
+    if (!r)
+        return false;
+    
+    // NOTE: We only do this for a select set of nodes, and fwiw WinIE appears
+    // not to do this at all
+    if (/*node->hasTagName(h1Tag)*/node->id() == ID_H1
+        || node->hasTagName(/*h2Tag*/ID_H2)
+        || node->hasTagName(/*h3Tag*/ID_H3)
+        || node->hasTagName(/*h4Tag*/ID_H4)
+        || node->hasTagName(/*h5Tag*/ID_H5)
+        || node->hasTagName(/*h6Tag*/ID_H6)
+        || node->hasTagName(/*pTag*/ID_P)) {
+        RenderStyle* style = r->style();
+        if (style) {
+            int bottomMargin = r->collapsedMarginBottom();
+            int fontSize = style->fontMetrics().averageCharWidth()/*FIXME khtml Description().computedPixelSize()*/;
+            if (bottomMargin * 2 >= fontSize)
+                return true;
+        }
+    }
+    
+    return false;
+}
+
+// Whether or not we should emit a character as we enter m_node (if it's a container) or as we hit it (if it's atomic).
+bool TextIterator::shouldRepresentNodeOffsetZero()
+{
+    if (m_emitCharactersBetweenAllVisiblePositions && m_node->renderer() && m_node->renderer()->isTable())
+        return true;
+        
+    // Leave element positioned flush with start of a paragraph
+    // (e.g. do not insert tab before a table cell at the start of a paragraph)
+    if (m_lastCharacter == '\n')
+        return false;
+    
+    // Otherwise, show the position if we have emitted any characters
+    if (m_haveEmitted)
+        return true;
+    
+    // We've not emitted anything yet. Generally, there is no need for any positioning then.
+    // The only exception is when the element is visually not in the same line as
+    // the start of the range (e.g. the range starts at the end of the previous paragraph).
+    // NOTE: Creating VisiblePositions and comparing them is relatively expensive, so we
+    // make quicker checks to possibly avoid that. Another check that we could make is
+    // is whether the inline vs block flow changed since the previous visible element.
+    // I think we're already in a special enough case that that won't be needed, tho.
+
+    // No character needed if this is the first node in the range.
+    if (m_node == m_startContainer)
+        return false;
+    
+    // If we are outside the start container's subtree, assume we need to emit.
+    // FIXME: m_startContainer could be an inline block
+    if (!m_node->isDescendantOf(m_startContainer))
+        return true;
+
+    // If we started as m_startContainer offset 0 and the current node is a descendant of
+    // the start container, we already had enough context to correctly decide whether to
+    // emit after a preceding block. We chose not to emit (m_haveEmitted is false),
+    // so don't second guess that now.
+    // NOTE: Is this really correct when m_node is not a leftmost descendant? Probably
+    // immaterial since we likely would have already emitted something by now.
+    if (m_startOffset == 0)
+        return false;
+        
+    // If this node is unrendered or invisible the VisiblePosition checks below won't have much meaning.
+    // Additionally, if the range we are iterating over contains huge sections of unrendered content,
+    // we would create VisiblePositions on every call to this function without this check.
+    if (!m_node->renderer() || m_node->renderer()->style()->visibility() != VISIBLE)
+        return false;
+    
+    // The currPos.isNotNull() check is needed because positions in non-html content
+    // (like svg) do not have visible positions, and we don't want to emit for them either.
+    VisiblePosition startPos = VisiblePosition(m_startContainer, m_startOffset, DOWNSTREAM);
+    VisiblePosition currPos = VisiblePosition(m_node, 0, DOWNSTREAM);
+    return currPos.isNotNull() && !inSameLine(startPos, currPos);
+}
+
+bool TextIterator::shouldEmitSpaceBeforeAndAfterNode(NodeImpl* node)
+{
+    return node->renderer() && node->renderer()->isTable() && (node->renderer()->isInline() || m_emitCharactersBetweenAllVisiblePositions);
+}
+
+void TextIterator::representNodeOffsetZero()
+{
+    // Emit a character to show the positioning of m_node.
+    
+    // When we haven't been emitting any characters, shouldRepresentNodeOffsetZero() can
+    // create VisiblePositions, which is expensive.  So, we perform the inexpensive checks
+    // on m_node to see if it necessitates emitting a character first and will early return
+    // before encountering shouldRepresentNodeOffsetZero()s worse case behavior.
+    if (shouldEmitTabBeforeNode(m_node)) {
+        if (shouldRepresentNodeOffsetZero())
+            emitCharacter('\t', m_node->parentNode(), m_node, 0, 0);
+    } else if (shouldEmitNewlineBeforeNode(m_node)) {
+        if (shouldRepresentNodeOffsetZero())
+            emitCharacter('\n', m_node->parentNode(), m_node, 0, 0);
+    } else if (shouldEmitSpaceBeforeAndAfterNode(m_node)) {
+        if (shouldRepresentNodeOffsetZero())
+            emitCharacter(' ', m_node->parentNode(), m_node, 0, 0);
+    }
+}
+
+bool TextIterator::handleNonTextNode()
+{
+    if (shouldEmitNewlineForNode(m_node))
+        emitCharacter('\n', m_node->parentNode(), m_node, 0, 1);
+    else if (m_emitCharactersBetweenAllVisiblePositions && m_node->renderer() && m_node->renderer()->isHR())
+        emitCharacter(' ', m_node->parentNode(), m_node, 0, 1);
+    else
+        representNodeOffsetZero();
+
+    return true;
+}
+
+void TextIterator::exitNode()
+{
+    // prevent emitting a newline when exiting a collapsed block at beginning of the range
+    // FIXME: !m_haveEmitted does not necessarily mean there was a collapsed block... it could
+    // have been an hr (e.g.). Also, a collapsed block could have height (e.g. a table) and
+    // therefore look like a blank line.
+    if (!m_haveEmitted)
+        return;
+        
+    // Emit with a position *inside* m_node, after m_node's contents, in
+    // case it is a block, because the run should start where the
+    // emitted character is positioned visually.
+    NodeImpl* baseNode = m_node->lastChild() ? m_node->lastChild() : m_node;
+    // FIXME: This shouldn't require the m_lastTextNode to be true, but we can't change that without making
+    // the logic in _web_attributedStringFromRange match.  We'll get that for free when we switch to use
+    // TextIterator in _web_attributedStringFromRange.
+    // See <rdar://problem/5428427> for an example of how this mismatch will cause problems.
+    if (m_lastTextNode && shouldEmitNewlineAfterNode(m_node)) {
+        // use extra newline to represent margin bottom, as needed
+        bool addNewline = shouldEmitExtraNewlineForNode(m_node);
+        
+        // FIXME: We need to emit a '\n' as we leave an empty block(s) that
+        // contain a VisiblePosition when doing selection preservation.
+        if (m_lastCharacter != '\n') {
+            // insert a newline with a position following this block's contents.
+            emitCharacter('\n', baseNode->parentNode(), baseNode, 1, 1);
+            // remember whether to later add a newline for the current node
+            ASSERT(!m_needAnotherNewline);
+            m_needAnotherNewline = addNewline;
+        } else if (addNewline)
+            // insert a newline with a position following this block's contents.
+            emitCharacter('\n', baseNode->parentNode(), baseNode, 1, 1);
+    }
+    
+    // If nothing was emitted, see if we need to emit a space.
+    if (!m_positionNode && shouldEmitSpaceBeforeAndAfterNode(m_node))
+        emitCharacter(' ', baseNode->parentNode(), baseNode, 1, 1);
+}
+
+void TextIterator::emitCharacter(QChar c, NodeImpl *textNode, NodeImpl *offsetBaseNode, int textStartOffset, int textEndOffset)
+{
+    m_haveEmitted = true;
+    
+    // remember information with which to construct the TextIterator::range()
+    // NOTE: textNode is often not a text node, so the range will specify child nodes of positionNode
+    m_positionNode = textNode;
+    m_positionOffsetBaseNode = offsetBaseNode;
+    m_positionStartOffset = textStartOffset;
+    m_positionEndOffset = textEndOffset;
+
+    // remember information with which to construct the TextIterator::characters() and length()
+    m_singleCharacterBuffer = c;
+    m_textCharacters = &m_singleCharacterBuffer;
+    m_textLength = 1;
+
+    // remember some iteration state
+    m_lastTextNodeEndedWithCollapsedSpace = false;
+    m_lastCharacter = c;
+}
+
+void TextIterator::emitText(NodeImpl* textNode, int textStartOffset, int textEndOffset)
+{
+    RenderText* renderer = static_cast<RenderText*>(m_node->renderer());
+    DOMString str(renderer->text(), renderer->length());
+    ASSERT(str.characters());
+
+    m_positionNode = textNode;
+    m_positionOffsetBaseNode = 0;
+    m_positionStartOffset = textStartOffset;
+    m_positionEndOffset = textEndOffset;
+    m_textCharacters = str.characters() + textStartOffset;
+    m_textLength = textEndOffset - textStartOffset;
+    m_lastCharacter = str[textEndOffset - 1];
+
+    m_lastTextNodeEndedWithCollapsedSpace = false;
+    m_haveEmitted = true;
+}
+
+PassRefPtr<RangeImpl> TextIterator::range() const
+{
+    // use the current run information, if we have it
+    if (m_positionNode) {
+        if (m_positionOffsetBaseNode) {
+            int index = m_positionOffsetBaseNode->nodeIndex();
+            m_positionStartOffset += index;
+            m_positionEndOffset += index;
+            m_positionOffsetBaseNode = 0;
+        }
+        return RangeImpl::create(m_positionNode->document(), m_positionNode, m_positionStartOffset, m_positionNode, m_positionEndOffset);
+    }
+
+    // otherwise, return the end of the overall range we were given
+    if (m_endContainer)
+        return RangeImpl::create(m_endContainer->document(), m_endContainer, m_endOffset, m_endContainer, m_endOffset);
+        
+    return 0;
+}
+    
+NodeImpl* TextIterator::node() const
+{
+    RefPtr<RangeImpl> textRange = range();
+    if (!textRange)
+        return 0;
+
+    NodeImpl* node = textRange->startContainer();
+    if (!node)
+        return 0;
+    if (node->offsetInCharacters())
+        return node;
+    
+    return node->childNode(textRange->startOffset());
+}
+
+// --------
+
+SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator() : m_positionNode(0)
+{
+}
+
+SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator(const RangeImpl *r)
+{
+    m_positionNode = 0;
+
+    if (!r)
+        return;
+
+    int exception = 0;
+    NodeImpl *startNode = r->startContainer(exception);
+    if (exception)
+        return;
+    NodeImpl *endNode = r->endContainer(exception);
+    if (exception)
+        return;
+    int startOffset = r->startOffset(exception);
+    if (exception)
+        return;
+    int endOffset = r->endOffset(exception);
+    if (exception)
+        return;
+
+    if (!startNode->offsetInCharacters()) {
+        if (startOffset >= 0 && startOffset < static_cast<int>(startNode->childNodeCount())) {
+            startNode = startNode->childNode(startOffset);
+            startOffset = 0;
+        }
+    }
+    if (!endNode->offsetInCharacters()) {
+        if (endOffset > 0 && endOffset <= static_cast<int>(endNode->childNodeCount())) {
+            endNode = endNode->childNode(endOffset - 1);
+            endOffset = endNode->offsetInCharacters() ? endNode->maxCharacterOffset() : endNode->childNodeCount();
+        }
+    }
+
+    m_node = endNode;
+    m_offset = endOffset;
+    m_handledNode = false;
+    m_handledChildren = endOffset == 0;
+
+    m_startNode = startNode;
+    m_startOffset = startOffset;
+    m_endNode = endNode;
+    m_endOffset = endOffset;
+    
+#ifndef NDEBUG
+    // Need this just because of the assert.
+    m_positionNode = endNode;
+#endif
+
+    m_lastTextNode = 0;
+    m_lastCharacter = '\n';
+    
+    if (startOffset == 0 || !startNode->firstChild()) {
+        m_pastStartNode = startNode->previousSibling();
+        while (!m_pastStartNode && startNode->parentNode()) {
+            startNode = startNode->parentNode();
+            m_pastStartNode = startNode->previousSibling();
+        }
+    } else
+        m_pastStartNode = startNode->childNode(startOffset - 1);
+
+    advance();
+}
+
+void SimplifiedBackwardsTextIterator::advance()
+{
+    ASSERT(m_positionNode);
+
+    m_positionNode = 0;
+    m_textLength = 0;
+
+    while (m_node && m_node != m_pastStartNode) {
+        // Don't handle node if we start iterating at [node, 0].
+        if (!m_handledNode && !(m_node == m_endNode && m_endOffset == 0)) {
+            RenderObject *renderer = m_node->renderer();
+            if (renderer && renderer->isText() && m_node->nodeType() == Node::TEXT_NODE) {
+                // FIXME: What about CDATA_SECTION_NODE?
+                if (renderer->style()->visibility() == VISIBLE && m_offset > 0)
+                    m_handledNode = handleTextNode();
+            } else if (renderer && (/*FIXME khtml renderer->isImage() || */renderer->isWidget())) {
+                if (renderer->style()->visibility() == VISIBLE && m_offset > 0)
+                    m_handledNode = handleReplacedElement();
+            } else
+                m_handledNode = handleNonTextNode();
+            if (m_positionNode)
+                return;
+        }
+
+        NodeImpl* next = m_handledChildren ? 0 : m_node->lastChild();
+        if (!next) {
+            // Exit empty containers as we pass over them or containers
+            // where [container, 0] is where we started iterating.
+            if (!m_handledNode &&
+                canHaveChildrenForEditing(m_node) &&
+                m_node->parentNode() &&
+                (!m_node->lastChild() || m_node == m_endNode && m_endOffset == 0)) {
+                exitNode();
+                if (m_positionNode) {
+                    m_handledNode = true;
+                    m_handledChildren = true;
+                    return;
+                }            
+            }
+            // Exit all other containers.
+            next = m_node->previousSibling();
+            while (!next) {
+                if (!m_node->parentNode())
+                    break;
+                m_node = m_node->parentNode();
+                exitNode();
+                if (m_positionNode) {
+                    m_handledNode = true;
+                    m_handledChildren = true;
+                    return;
+                }
+                next = m_node->previousSibling();
+            }
+        }
+        
+        m_node = next;
+        m_offset = m_node ? caretMaxOffset(m_node) : 0;
+        m_handledNode = false;
+        m_handledChildren = false;
+        
+        if (m_positionNode)
+            return;
+    }
+}
+
+bool SimplifiedBackwardsTextIterator::handleTextNode()
+{
+    m_lastTextNode = m_node;
+
+    RenderText *renderer = static_cast<RenderText *>(m_node->renderer());
+    DOMString str(renderer->text(), renderer->length());
+
+    if (!renderer->firstTextBox() && str.length() > 0)
+        return true;
+
+    m_positionEndOffset = m_offset;
+
+    m_offset = (m_node == m_startNode) ? m_startOffset : 0;
+    m_positionNode = m_node;
+    m_positionStartOffset = m_offset;
+    m_textLength = m_positionEndOffset - m_positionStartOffset;
+    m_textCharacters = str.characters() + m_positionStartOffset;
+
+    m_lastCharacter = str[m_positionEndOffset - 1];
+
+    return true;
+}
+
+bool SimplifiedBackwardsTextIterator::handleReplacedElement()
+{
+    unsigned index = m_node->nodeIndex();
+    // We want replaced elements to behave like punctuation for boundary
+    // finding, and to simply take up space for the selection preservation
+    // code in moveParagraphs, so we use a comma.  Unconditionally emit
+    // here because this iterator is only used for boundary finding.
+    emitCharacter(',', m_node->parentNode(), index, index + 1);
+    return true;
+}
+
+bool SimplifiedBackwardsTextIterator::handleNonTextNode()
+{    
+    // We can use a linefeed in place of a tab because this simple iterator is only used to
+    // find boundaries, not actual content.  A linefeed breaks words, sentences, and paragraphs.
+    if (shouldEmitNewlineForNode(m_node) ||
+        shouldEmitNewlineAfterNode(m_node) ||
+        shouldEmitTabBeforeNode(m_node)) {
+        unsigned index = m_node->nodeIndex();
+        // The start of this emitted range is wrong, ensuring correctness would require
+        // VisiblePositions and so would be slow.  previousBoundary expects this.
+        emitCharacter('\n', m_node->parentNode(), index + 1, index + 1);
+    }
+    
+    return true;
+}
+
+void SimplifiedBackwardsTextIterator::exitNode()
+{
+    if (shouldEmitNewlineForNode(m_node) ||
+        shouldEmitNewlineBeforeNode(m_node) ||
+        shouldEmitTabBeforeNode(m_node))
+        // The start of this emitted range is wrong, ensuring correctness would require
+        // VisiblePositions and so would be slow.  previousBoundary expects this.
+        emitCharacter('\n', m_node, 0, 0);
+}
+
+void SimplifiedBackwardsTextIterator::emitCharacter(QChar c, NodeImpl *node, int startOffset, int endOffset)
+{
+    m_singleCharacterBuffer = c;
+    m_positionNode = node;
+    m_positionStartOffset = startOffset;
+    m_positionEndOffset = endOffset;
+    m_textCharacters = &m_singleCharacterBuffer;
+    m_textLength = 1;
+    m_lastCharacter = c;
+}
+
+PassRefPtr<RangeImpl> SimplifiedBackwardsTextIterator::range() const
+{
+    if (m_positionNode)
+        return RangeImpl::create(m_positionNode->document(), m_positionNode, m_positionStartOffset, m_positionNode, m_positionEndOffset);
+    
+    return RangeImpl::create(m_startNode->document(), m_startNode, m_startOffset, m_startNode, m_startOffset);
+}
+
+// --------
+
+CharacterIterator::CharacterIterator()
+    : m_offset(0)
+    , m_runOffset(0)
+    , m_atBreak(true)
+{
+}
+
+CharacterIterator::CharacterIterator(const RangeImpl *r, bool emitCharactersBetweenAllVisiblePositions, bool enterTextControls)
+    : m_offset(0)
+    , m_runOffset(0)
+    , m_atBreak(true)
+    , m_textIterator(r, emitCharactersBetweenAllVisiblePositions, enterTextControls)
+{
+    while (!atEnd() && m_textIterator.length() == 0)
+        m_textIterator.advance();
+}
+
+PassRefPtr<RangeImpl> CharacterIterator::range() const
+{
+    RefPtr<RangeImpl> r = m_textIterator.range();
+    if (!m_textIterator.atEnd()) {
+        if (m_textIterator.length() <= 1) {
+            ASSERT(m_runOffset == 0);
+        } else {
+            int exception = 0;
+            NodeImpl *n = r->startContainer(exception);
+            ASSERT(n == r->endContainer(exception));
+            int offset = r->startOffset(exception) + m_runOffset;
+            r->setStart(n, offset, exception);
+            r->setEnd(n, offset + 1, exception);
+        }
+    }
+    return r.release();
+}
+
+void CharacterIterator::advance(int count)
+{
+    if (count <= 0) {
+        ASSERT(count == 0);
+        return;
+    }
+    
+    m_atBreak = false;
+
+    // easy if there is enough left in the current m_textIterator run
+    int remaining = m_textIterator.length() - m_runOffset;
+    if (count < remaining) {
+        m_runOffset += count;
+        m_offset += count;
+        return;
+    }
+
+    // exhaust the current m_textIterator run
+    count -= remaining;
+    m_offset += remaining;
+    
+    // move to a subsequent m_textIterator run
+    for (m_textIterator.advance(); !atEnd(); m_textIterator.advance()) {
+        int runLength = m_textIterator.length();
+        if (runLength == 0)
+            m_atBreak = true;
+        else {
+            // see whether this is m_textIterator to use
+            if (count < runLength) {
+                m_runOffset = count;
+                m_offset += count;
+                return;
+            }
+            
+            // exhaust this m_textIterator run
+            count -= runLength;
+            m_offset += runLength;
+        }
+    }
+
+    // ran to the end of the m_textIterator... no more runs left
+    m_atBreak = true;
+    m_runOffset = 0;
+}
+
+DOMString CharacterIterator::string(int numChars)
+{
+    Vector<QChar> result;
+    result.reserveCapacity(numChars);
+    while (numChars > 0 && !atEnd()) {
+        int runSize = min(numChars, length());
+        result.append(characters(), runSize);
+        numChars -= runSize;
+        advance(runSize);
+    }
+    int len = result.size();
+    return DOMString(result.data(), len);
+}
+
+// --------
+
+WordAwareIterator::WordAwareIterator()
+: m_previousText(0), m_didLookAhead(false)
+{
+}
+
+WordAwareIterator::WordAwareIterator(const RangeImpl *r)
+: m_previousText(0), m_didLookAhead(false), m_textIterator(r)
+{
+    m_didLookAhead = true;  // so we consider the first chunk from the text iterator
+    advance();              // get in position over the first chunk of text
+}
+
+// We're always in one of these modes:
+// - The current chunk in the text iterator is our current chunk
+//      (typically its a piece of whitespace, or text that ended with whitespace)
+// - The previous chunk in the text iterator is our current chunk
+//      (we looked ahead to the next chunk and found a word boundary)
+// - We built up our own chunk of text from many chunks from the text iterator
+
+// FIXME: Perf could be bad for huge spans next to each other that don't fall on word boundaries
+
+void WordAwareIterator::advance()
+{
+    m_previousText = 0;
+    m_buffer.clear();      // toss any old buffer we built up
+
+    // If last time we did a look-ahead, start with that looked-ahead chunk now
+    if (!m_didLookAhead) {
+        ASSERT(!m_textIterator.atEnd());
+        m_textIterator.advance();
+    }
+    m_didLookAhead = false;
+
+    // Go to next non-empty chunk
+    while (!m_textIterator.atEnd() && m_textIterator.length() == 0)
+        m_textIterator.advance();
+    m_range = m_textIterator.range();
+
+    if (m_textIterator.atEnd())
+        return;
+    
+    while (1) {
+        // If this chunk ends in whitespace we can just use it as our chunk.
+        if (isSpaceOrNewline(m_textIterator.characters()[m_textIterator.length() - 1]))
+            return;
+
+        // If this is the first chunk that failed, save it in previousText before look ahead
+        if (m_buffer.isEmpty()) {
+            m_previousText = m_textIterator.characters();
+            m_previousLength = m_textIterator.length();
+        }
+
+        // Look ahead to next chunk.  If it is whitespace or a break, we can use the previous stuff
+        m_textIterator.advance();
+        if (m_textIterator.atEnd() || m_textIterator.length() == 0 || isSpaceOrNewline(m_textIterator.characters()[0])) {
+            m_didLookAhead = true;
+            return;
+        }
+
+        if (m_buffer.isEmpty()) {
+            // Start gobbling chunks until we get to a suitable stopping point
+            m_buffer.append(m_previousText, m_previousLength);
+            m_previousText = 0;
+        }
+        m_buffer.append(m_textIterator.characters(), m_textIterator.length());
+        int exception = 0;
+        m_range->setEnd(m_textIterator.range()->endContainer(exception), m_textIterator.range()->endOffset(exception), exception);
+    }
+}
+
+int WordAwareIterator::length() const
+{
+    if (!m_buffer.isEmpty())
+        return m_buffer.size();
+    if (m_previousText)
+        return m_previousLength;
+    return m_textIterator.length();
+}
+
+const QChar* WordAwareIterator::characters() const
+{
+    if (!m_buffer.isEmpty())
+        return m_buffer.data();
+    if (m_previousText)
+        return m_previousText;
+    return m_textIterator.characters();
+}
+
+// --------
+
+CircularSearchBuffer::CircularSearchBuffer(const DOMString& s, bool isCaseSensitive)
+    : m_target(/*isCaseSensitive ?*/ s /*: s.foldCase()*/)
+    , m_isCaseSensitive(isCaseSensitive)
+    , m_characterBuffer(m_target.length())
+    , m_isCharacterStartBuffer(m_target.length())
+    , m_isBufferFull(false)
+    , m_cursor(0)
+{
+    ASSERT(!m_target.isEmpty());
+    //FIXME khtml m_target.replace(noBreakSpace, ' ');
+}
+
+inline void CircularSearchBuffer::append(QChar c, bool isStart)
+{
+    m_characterBuffer[m_cursor] = c == /*FIXME khtml noBreakSpace ? ' ' : */c;
+    m_isCharacterStartBuffer[m_cursor] = isStart;
+    if (++m_cursor == m_target.length()) {
+        m_cursor = 0;
+        m_isBufferFull = true;
+    }
+}
+
+inline void CircularSearchBuffer::append(QChar c)
+{
+    if (m_isCaseSensitive) {
+        append(c, true);
+        return;
+    }
+    const int maxFoldedCharacters = 16; // sensible maximum is 3, this should be more than enough
+    QChar foldedCharacters[maxFoldedCharacters];
+    bool error;
+    int numFoldedCharacters = 0;// FIXME khtml foldCase(foldedCharacters, maxFoldedCharacters, &c, 1, &error);
+    ASSERT(!error);
+    ASSERT(numFoldedCharacters);
+    ASSERT(numFoldedCharacters <= maxFoldedCharacters);
+    if (!error && numFoldedCharacters) {
+        numFoldedCharacters = min(numFoldedCharacters, maxFoldedCharacters);
+        append(foldedCharacters[0], true);
+        for (int i = 1; i < numFoldedCharacters; ++i)
+            append(foldedCharacters[i], false);
+    }
+}
+
+inline bool CircularSearchBuffer::isMatch() const
+{
+    if (!m_isBufferFull)
+        return false;
+    if (!m_isCharacterStartBuffer[m_cursor])
+        return false;
+
+    unsigned tailSpace = m_target.length() - m_cursor;
+    return memcmp(&m_characterBuffer[m_cursor], m_target.characters(), tailSpace * sizeof(QChar)) == 0
+        && memcmp(&m_characterBuffer[0], m_target.characters() + tailSpace, m_cursor * sizeof(QChar)) == 0;
+}
+
+// Returns the number of characters that were appended to the buffer (what we are searching in).
+// That's not necessarily the same length as the passed-in target string, because case folding
+// can make two strings match even though they're not the same length.
+unsigned CircularSearchBuffer::length() const
+{
+    ASSERT(isMatch());
+
+    unsigned bufferSize = m_target.length();
+    unsigned length = 0;
+    for (unsigned i = 0; i < bufferSize; ++i)
+        length += m_isCharacterStartBuffer[i];
+    return length;
+}
+
+// --------
+
+int TextIterator::rangeLength(const RangeImpl *r, bool forSelectionPreservation)
+{
+    int length = 0;
+    for (TextIterator it(r, forSelectionPreservation); !it.atEnd(); it.advance())
+        length += it.length();
+    
+    return length;
+}
+
+PassRefPtr<RangeImpl> TextIterator::subrange(RangeImpl* entireRange, int characterOffset, int characterCount)
+{
+    CharacterIterator chars(entireRange);
+
+    chars.advance(characterOffset);
+    RefPtr<RangeImpl> start = chars.range();
+
+    chars.advance(characterCount);
+    RefPtr<RangeImpl> end = chars.range();
+    
+    ExceptionCode ec = 0;
+    RefPtr<RangeImpl> result(RangeImpl::create(entireRange->ownerDocument(),
+                                    start->startContainer(ec),
+                                    start->startOffset(ec),
+                                    end->startContainer(ec),
+                                    end->startOffset(ec)));
+    ASSERT(!ec);
+    
+    return result.release();
+}
+
+PassRefPtr<RangeImpl> TextIterator::rangeFromLocationAndLength(ElementImpl *scope, int rangeLocation, int rangeLength, bool forSelectionPreservation)
+{
+#if 0
+    RefPtr<RangeImpl> resultRange = scope->document()->createRange();
+
+    int docTextPosition = 0;
+    int rangeEnd = rangeLocation + rangeLength;
+    bool startRangeFound = false;
+
+    RefPtr<RangeImpl> textRunRange;
+
+    TextIterator it(rangeOfContents(scope).get(), forSelectionPreservation);
+    
+    // FIXME: the atEnd() check shouldn't be necessary, workaround for <http://bugs.webkit.org/show_bug.cgi?id=6289>.
+    if (rangeLocation == 0 && rangeLength == 0 && it.atEnd()) {
+        int exception = 0;
+        textRunRange = it.range();
+        
+        resultRange->setStart(textRunRange->startContainer(exception), 0, exception);
+        ASSERT(exception == 0);
+        resultRange->setEnd(textRunRange->startContainer(exception), 0, exception);
+        ASSERT(exception == 0);
+        
+        return resultRange.release();
+    }
+
+    for (; !it.atEnd(); it.advance()) {
+        int len = it.length();
+        textRunRange = it.range();
+        
+        bool foundStart = rangeLocation >= docTextPosition && rangeLocation <= docTextPosition + len;
+        bool foundEnd = rangeEnd >= docTextPosition && rangeEnd <= docTextPosition + len;
+        
+        // Fix textRunRange->endPosition(), but only if foundStart || foundEnd, because it is only
+        // in those cases that textRunRange is used.
+        if (foundStart || foundEnd) {
+            // FIXME: This is a workaround for the fact that the end of a run is often at the wrong
+            // position for emitted '\n's.
+            if (len == 1 && it.characters()[0] == QChar('\n')) {
+                Position runStart = textRunRange->startPosition();
+                Position runEnd = VisiblePosition(runStart).next().deepEquivalent();
+                if (runEnd.isNotNull()) {
+                    ExceptionCode ec = 0;
+                    textRunRange->setEnd(runEnd.node(), runEnd.offset(), ec);
+                }
+            }
+        }
+
+        if (foundStart) {
+            startRangeFound = true;
+            int exception = 0;
+            if (textRunRange->startContainer(exception)->isTextNode()) {
+                int offset = rangeLocation - docTextPosition;
+                resultRange->setStart(textRunRange->startContainer(exception), offset + textRunRange->startOffset(exception), exception);
+            } else {
+                if (rangeLocation == docTextPosition)
+                    resultRange->setStart(textRunRange->startContainer(exception), textRunRange->startOffset(exception), exception);
+                else
+                    resultRange->setStart(textRunRange->endContainer(exception), textRunRange->endOffset(exception), exception);
+            }
+        }
+
+        if (foundEnd) {
+            int exception = 0;
+            if (textRunRange->startContainer(exception)->isTextNode()) {
+                int offset = rangeEnd - docTextPosition;
+                resultRange->setEnd(textRunRange->startContainer(exception), offset + textRunRange->startOffset(exception), exception);
+            } else {
+                if (rangeEnd == docTextPosition)
+                    resultRange->setEnd(textRunRange->startContainer(exception), textRunRange->startOffset(exception), exception);
+                else
+                    resultRange->setEnd(textRunRange->endContainer(exception), textRunRange->endOffset(exception), exception);
+            }
+            docTextPosition += len;
+            break;
+        }
+        docTextPosition += len;
+    }
+    
+    if (!startRangeFound)
+        return 0;
+    
+    if (rangeLength != 0 && rangeEnd > docTextPosition) { // rangeEnd is out of bounds
+        int exception = 0;
+        resultRange->setEnd(textRunRange->endContainer(exception), textRunRange->endOffset(exception), exception);
+    }
+    
+    return resultRange.release();
+#endif
+    return 0;
+}
+
+// --------
+    
+QChar* plainTextToMallocAllocatedBuffer(const RangeImpl* r, unsigned& bufferLength)
+{
+    QChar* result = 0;
+
+    // Do this in pieces to avoid massive reallocations if there is a large amount of text.
+    // Use system malloc for buffers since they can consume lots of memory and current TCMalloc is unable return it back to OS.
+    static const unsigned cMaxSegmentSize = 1 << 16;
+    bufferLength = 0;
+    typedef pair<QChar*, unsigned> TextSegment;
+    Vector<TextSegment>* textSegments = 0;
+    Vector<QChar> textBuffer;
+    textBuffer.reserveCapacity(cMaxSegmentSize);
+    for (TextIterator it(r); !it.atEnd(); it.advance()) {
+        if (textBuffer.size() && textBuffer.size() + it.length() > cMaxSegmentSize) {
+            QChar* newSegmentBuffer = static_cast<QChar*>(malloc(textBuffer.size() * sizeof(QChar)));
+            if (!newSegmentBuffer)
+                goto exit;
+            memcpy(newSegmentBuffer, textBuffer.data(), textBuffer.size() * sizeof(QChar));
+            if (!textSegments)
+                textSegments = new Vector<TextSegment>;
+            textSegments->append(make_pair(newSegmentBuffer, (unsigned)textBuffer.size()));
+            textBuffer.clear();
+        }
+        textBuffer.append(it.characters(), it.length());
+        bufferLength += it.length();
+    }
+
+    if (!bufferLength)
+        return 0;
+
+    // Since we know the size now, we can make a single buffer out of the pieces with one big alloc
+    result = static_cast<QChar*>(malloc(bufferLength * sizeof(QChar)));
+    if (!result)
+        goto exit;
+
+    {
+        QChar* resultPos = result;
+        if (textSegments) {
+            unsigned size = textSegments->size();
+            for (unsigned i = 0; i < size; ++i) {
+                const TextSegment& segment = textSegments->at(i);
+                memcpy(resultPos, segment.first, segment.second * sizeof(QChar));
+                resultPos += segment.second;
+            }
+        }
+        memcpy(resultPos, textBuffer.data(), textBuffer.size() * sizeof(QChar));
+    }
+
+exit:
+    if (textSegments) {
+        unsigned size = textSegments->size();
+        for (unsigned i = 0; i < size; ++i)
+            free(textSegments->at(i).first);
+        delete textSegments;
+    }
+    return result;
+}
+
+DOMString plainText(const RangeImpl* r)
+{
+    unsigned length;
+    QChar* buf = plainTextToMallocAllocatedBuffer(r, length);
+    if (!buf)
+        return "";
+    DOMString result(buf, length);
+    free(buf);
+    return result;
+}
+
+PassRefPtr<RangeImpl> findPlainText(const RangeImpl* range, const DOMString& target, bool forward, bool caseSensitive)
+{
+    // FIXME: Can we do Boyer-Moore or equivalent instead for speed?
+
+    ExceptionCode ec = 0;
+    RefPtr<RangeImpl> result = range->cloneRange(ec);
+    result->collapse(!forward, ec);
+
+    // FIXME: This code does not allow \n at the moment because of issues with <br>.
+    // Once we fix those, we can remove this check.
+    if (target.isEmpty() || target.find('\n') != -1)
+        return result.release();
+
+    unsigned matchStart = 0;
+    unsigned matchLength = 0;
+    {
+        CircularSearchBuffer searchBuffer(target, caseSensitive);
+        CharacterIterator it(range, false, true);
+        for (;;) {
+            if (searchBuffer.isMatch()) {
+                // Note that we found a match, and where we found it.
+                unsigned matchEnd = it.characterOffset();
+                matchLength = searchBuffer.length();
+                ASSERT(matchLength);
+                ASSERT(matchEnd >= matchLength);
+                matchStart = matchEnd - matchLength;
+                // If searching forward, stop on the first match.
+                // If searching backward, don't stop, so we end up with the last match.
+                if (forward)
+                    break;
+            }
+            if (it.atBreak()) {
+                if (it.atEnd())
+                    break;
+                searchBuffer.clear();
+            }
+            searchBuffer.append(it.characters()[0]);
+            it.advance(1);
+        }
+    }
+
+    if (matchLength) {
+        CharacterIterator it(range, false, true);
+        it.advance(matchStart);
+        result->setStart(it.range()->startContainer(ec), it.range()->startOffset(ec), ec);
+        it.advance(matchLength - 1);
+        result->setEnd(it.range()->endContainer(ec), it.range()->endOffset(ec), ec);
+    }
+
+    return result.release();
+}
+
+}
diff --git a/khtml/editing/TextIterator.h b/khtml/editing/TextIterator.h
new file mode 100644
index 0000000..0bdec89
--- /dev/null
+++ b/khtml/editing/TextIterator.h
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2004, 2006 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TextIterator_h
+#define TextIterator_h
+
+//#include "InlineTextBox.h"
+//#include "Range.h"
+#include "xml/dom2_rangeimpl.h"
+#include <wtf/Vector.h>
+#include "rendering/render_text.h"
+
+namespace DOM
+{
+    class ElementImpl;
+    class NodeImpl;
+};
+
+using namespace DOM;
+
+namespace khtml {
+
+// FIXME: Can't really answer this question correctly without knowing the white-space mode.
+// FIXME: Move this somewhere else in the editing directory. It doesn't belong here.
+inline bool isCollapsibleWhitespace(QChar c)
+{
+    switch (c.unicode()) {
+        case ' ':
+        case '\n':
+            return true;
+        default:
+            return false;
+    }
+}
+
+DOMString plainText(const RangeImpl*);
+QChar* plainTextToMallocAllocatedBuffer(const RangeImpl*, unsigned& bufferLength);
+PassRefPtr<RangeImpl> findPlainText(const RangeImpl*, const DOMString&, bool forward, bool caseSensitive);
+
+// Iterates through the DOM range, returning all the text, and 0-length boundaries
+// at points where replaced elements break up the text flow.  The text comes back in
+// chunks so as to optimize for performance of the iteration.
+
+class TextIterator {
+public:
+    TextIterator();
+    explicit TextIterator(const RangeImpl*, bool emitCharactersBetweenAllVisiblePositions = false, bool enterTextControls = false);
+    
+    bool atEnd() const { return !m_positionNode; }
+    void advance();
+    
+    int length() const { return m_textLength; }
+    const QChar* characters() const { return m_textCharacters; }
+    
+    PassRefPtr<RangeImpl> range() const;
+    NodeImpl* node() const;
+    
+    static int rangeLength(const RangeImpl*, bool spacesForReplacedElements = false);
+    static PassRefPtr<RangeImpl> rangeFromLocationAndLength(ElementImpl* scope, int rangeLocation, int rangeLength, bool spacesForReplacedElements = false);
+    static PassRefPtr<RangeImpl> subrange(RangeImpl* entireRange, int characterOffset, int characterCount);
+    
+private:
+    void exitNode();
+    bool shouldRepresentNodeOffsetZero();
+    bool shouldEmitSpaceBeforeAndAfterNode(NodeImpl*);
+    void representNodeOffsetZero();
+    bool handleTextNode();
+    bool handleReplacedElement();
+    bool handleNonTextNode();
+    void handleTextBox();
+    void emitCharacter(QChar, NodeImpl *textNode, NodeImpl *offsetBaseNode, int textStartOffset, int textEndOffset);
+    void emitText(NodeImpl *textNode, int textStartOffset, int textEndOffset);
+    
+    // Current position, not necessarily of the text being returned, but position
+    // as we walk through the DOM tree.
+    NodeImpl *m_node;
+    int m_offset;
+    bool m_handledNode;
+    bool m_handledChildren;
+    bool m_inShadowContent;
+    
+    // The range.
+    NodeImpl *m_startContainer;
+    int m_startOffset;
+    NodeImpl *m_endContainer;
+    int m_endOffset;
+    NodeImpl *m_pastEndNode;
+    
+    // The current text and its position, in the form to be returned from the iterator.
+    NodeImpl *m_positionNode;
+    mutable NodeImpl *m_positionOffsetBaseNode;
+    mutable int m_positionStartOffset;
+    mutable int m_positionEndOffset;
+    const QChar* m_textCharacters;
+    int m_textLength;
+    
+    // Used when there is still some pending text from the current node; when these
+    // are false and 0, we go back to normal iterating.
+    bool m_needAnotherNewline;
+    InlineTextBox *m_textBox;
+    
+    // Used to do the whitespace collapsing logic.
+    NodeImpl *m_lastTextNode;    
+    bool m_lastTextNodeEndedWithCollapsedSpace;
+    QChar m_lastCharacter;
+    
+    // Used for whitespace characters that aren't in the DOM, so we can point at them.
+    QChar m_singleCharacterBuffer;
+    
+    // Used when text boxes are out of order (Hebrew/Arabic w/ embeded LTR text)
+    Vector<InlineTextBox*> m_sortedTextBoxes;
+    size_t m_sortedTextBoxesPosition;
+    
+    // Used when deciding whether to emit a "positioning" (e.g. newline) before any other content
+    bool m_haveEmitted;
+    
+    // Used by selection preservation code.  There should be one character emitted between every VisiblePosition
+    // in the Range used to create the TextIterator.
+    // FIXME <rdar://problem/6028818>: This functionality should eventually be phased out when we rewrite
+    // moveParagraphs to not clone/destroy moved content.
+    bool m_emitCharactersBetweenAllVisiblePositions;
+    bool m_enterTextControls;
+};
+
+// Iterates through the DOM range, returning all the text, and 0-length boundaries
+// at points where replaced elements break up the text flow.  The text comes back in
+// chunks so as to optimize for performance of the iteration.
+class SimplifiedBackwardsTextIterator {
+public:
+    SimplifiedBackwardsTextIterator();
+    explicit SimplifiedBackwardsTextIterator(const RangeImpl *);
+    
+    bool atEnd() const { return !m_positionNode; }
+    void advance();
+    
+    int length() const { return m_textLength; }
+    const QChar* characters() const { return m_textCharacters; }
+    
+    PassRefPtr<RangeImpl> range() const;
+        
+private:
+    void exitNode();
+    bool handleTextNode();
+    bool handleReplacedElement();
+    bool handleNonTextNode();
+    void emitCharacter(QChar, NodeImpl *Node, int startOffset, int endOffset);
+    
+    // Current position, not necessarily of the text being returned, but position
+    // as we walk through the DOM tree.
+    NodeImpl* m_node;
+    int m_offset;
+    bool m_handledNode;
+    bool m_handledChildren;
+    
+    // End of the range.
+    NodeImpl* m_startNode;
+    int m_startOffset;
+    // Start of the range.
+    NodeImpl* m_endNode;
+    int m_endOffset;
+    
+    // The current text and its position, in the form to be returned from the iterator.
+    NodeImpl* m_positionNode;
+    int m_positionStartOffset;
+    int m_positionEndOffset;
+    const QChar* m_textCharacters;
+    int m_textLength;
+
+    // Used to do the whitespace logic.
+    NodeImpl* m_lastTextNode;    
+    QChar m_lastCharacter;
+    
+    // Used for whitespace characters that aren't in the DOM, so we can point at them.
+    QChar m_singleCharacterBuffer;
+    
+    // The node after the last node this iterator should process.
+    NodeImpl* m_pastStartNode;
+};
+
+// Builds on the text iterator, adding a character position so we can walk one
+// character at a time, or faster, as needed. Useful for searching.
+class CharacterIterator {
+public:
+    CharacterIterator();
+    explicit CharacterIterator(const RangeImpl* r, bool emitCharactersBetweenAllVisiblePositions = false, bool enterTextControls = false);
+    
+    void advance(int numCharacters);
+    
+    bool atBreak() const { return m_atBreak; }
+    bool atEnd() const { return m_textIterator.atEnd(); }
+    
+    int length() const { return m_textIterator.length() - m_runOffset; }
+    const QChar* characters() const { return m_textIterator.characters() + m_runOffset; }
+    DOMString string(int numChars);
+    
+    int characterOffset() const { return m_offset; }
+    PassRefPtr<RangeImpl> range() const;
+        
+private:
+    int m_offset;
+    int m_runOffset;
+    bool m_atBreak;
+    
+    TextIterator m_textIterator;
+};
+    
+// Very similar to the TextIterator, except that the chunks of text returned are "well behaved",
+// meaning they never end split up a word.  This is useful for spellcheck or (perhaps one day) searching.
+class WordAwareIterator {
+public:
+    WordAwareIterator();
+    explicit WordAwareIterator(const RangeImpl *r);
+
+    bool atEnd() const { return !m_didLookAhead && m_textIterator.atEnd(); }
+    void advance();
+    
+    int length() const;
+    const QChar* characters() const;
+    
+    // Range of the text we're currently returning
+    PassRefPtr<RangeImpl> range() const { return m_range; }
+
+private:
+    // text from the previous chunk from the textIterator
+    const QChar* m_previousText;
+    int m_previousLength;
+
+    // many chunks from textIterator concatenated
+    Vector<QChar> m_buffer;
+    
+    // Did we have to look ahead in the textIterator to confirm the current chunk?
+    bool m_didLookAhead;
+
+    RefPtr<RangeImpl> m_range;
+
+    TextIterator m_textIterator;
+};
+
+}
+
+#endif
diff --git a/khtml/editing/editing.cpp b/khtml/editing/editing.cpp
index 1fa5eda..6175088 100644
--- a/khtml/editing/editing.cpp
+++ b/khtml/editing/editing.cpp
@@ -30,7 +30,7 @@ EditorContext::~EditorContext() {
 }
 
 void EditorContext::reset() {
-  m_selection = Selection();
+  // FIXME m_selection = DOM::SelectionController();
   m_dragCaret = Selection();
   
   m_caretBlinkTimer = -1;
diff --git a/khtml/editing/editing_p.h b/khtml/editing/editing_p.h
index 761bea8..c9e095b 100644
--- a/khtml/editing/editing_p.h
+++ b/khtml/editing/editing_p.h
@@ -21,7 +21,8 @@
 #ifndef EDITING_P_H
 #define EDITING_P_H
 
-#include "xml/dom_selection.h"
+#include "xml/Selection.h"
+#include "xml/SelectionController.h"
 
 #include <limits.h>
 
@@ -39,9 +40,9 @@ struct EditorContext {
 
   enum { NoXPosForVerticalArrowNavigation = INT_MIN };
 
-  DOM::Selection::ETextGranularity m_selectionGranularity;
+  DOM::TextGranularity m_selectionGranularity;
 
-  DOM::Selection m_selection;
+  DOM::SelectionController m_selection;
   DOM::Selection m_dragCaret;
   int m_caretBlinkTimer;
 
@@ -51,7 +52,7 @@ struct EditorContext {
 
   bool m_beganSelectingText:1;
 
-  void beginSelectingText(DOM::Selection::ETextGranularity granularity) {
+  void beginSelectingText(DOM::TextGranularity granularity) {
     m_beganSelectingText   = true;
     m_selectionGranularity = granularity;
   }
@@ -59,8 +60,9 @@ struct EditorContext {
   int m_xPosForVerticalArrowNavigation;
   DOM::Editor *m_editor;
 
-  EditorContext()
-  : m_caretBlinkTimer(-1),
+  EditorContext(KHTMLPart* part)
+  : m_selection(part),
+    m_caretBlinkTimer(-1),
     m_caretVisible(true),
     m_caretBlinks(true),
     m_caretPaint(true),
diff --git a/khtml/editing/editor.cpp b/khtml/editing/editor.cpp
index aa11582..a3cb6d1 100644
--- a/khtml/editing/editor.cpp
+++ b/khtml/editing/editor.cpp
@@ -354,7 +354,7 @@ DOMString Editor::selectionStartStylePropertyValue(int stylePropertyID) const
 
 CSSStyleDeclarationImpl *Editor::selectionComputedStyle(NodeImpl *&nodeToRemove) const
 {
-  nodeToRemove = 0;
+  /*nodeToRemove = 0;
 
   if (!m_part->xmlDocImpl())
     return 0;
@@ -387,7 +387,9 @@ CSSStyleDeclarationImpl *Editor::selectionComputedStyle(NodeImpl *&nodeToRemove)
     nodeToRemove = styleElement;
   }
 
-  return new RenderStyleDeclarationImpl(styleElement);
+  return new RenderStyleDeclarationImpl(styleElement);*/
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    return 0;
 }
 
 EditCommand Editor::lastEditCommand() const
@@ -414,7 +416,8 @@ void Editor::appliedEditing(EditCommand &cmd)
   }
     m_part->selectionLayoutChanged();
   // ### only emit if caret pos changed
-    m_part->emitCaretPositionChanged(cmd.endingSelection().caretPos());
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    // FIXME m_part->emitCaretPositionChanged(cmd.endingSelection().caretPos());
 }
 
 void Editor::unappliedEditing(EditCommand &cmd)
@@ -429,7 +432,8 @@ void Editor::unappliedEditing(EditCommand &cmd)
 #else
   m_part->selectionLayoutChanged();
   // ### only emit if caret pos changed
-  m_part->emitCaretPositionChanged(cmd.startingSelection().caretPos());
+  kDebug() << "NOT IMPLEMENTED" << endl;
+  //m_part->emitCaretPositionChanged(cmd.startingSelection().caretPos());
 #endif
   d->m_lastEditCommand = EditCommand::emptyCommand();
 }
@@ -446,7 +450,8 @@ void Editor::reappliedEditing(EditCommand &cmd)
 #else
   m_part->selectionLayoutChanged();
   // ### only emit if caret pos changed
-  m_part->emitCaretPositionChanged(cmd.endingSelection().caretPos());
+  kDebug() << "NOT IMPLEMENTED" << endl;
+  //m_part->emitCaretPositionChanged(cmd.endingSelection().caretPos());
 #endif
   d->m_lastEditCommand = EditCommand::emptyCommand();
 }
@@ -491,14 +496,14 @@ bool Editor::handleKeyEvent(QKeyEvent *_ke)
       kDebug(6200) << "========== KEY_DELETE ==========" << endl;
       if (selectionToDelete.state() == Selection::CARET) {
           Position pos(selectionToDelete.start());
-          kDebug(6200) << "pos.inLastEditableInRootEditableElement " << pos.inLastEditableInRootEditableElement() << " pos.offset " << pos.offset() << " pos.max " << pos.node()->caretMaxRenderedOffset() << endl;
-          if (pos.nextCharacterPosition() == pos) {
+          // FIXME kDebug(6200) << "pos.inLastEditableInRootEditableElement " << pos.inLastEditableInRootEditableElement() << " pos.offset " << pos.offset() << " pos.max " << pos.node()->caretMaxRenderedOffset() << endl;
+          /*FIXME khtml if (pos.nextCharacterPosition() == pos) {
               // we're at the end of a root editable block...do nothing
               kDebug(6200) << "no delete!!!!!!!!!!" << endl;
               break;
-          }
-          m_part->d->editor_context.m_selection
-                               = Selection(pos, pos.nextCharacterPosition());
+          }*/
+          /*FIXME m_part->d->editor_context.m_selection
+                               = Selection(pos, pos.nextCharacterPosition());*/
       }
       // fall through
     }
diff --git a/khtml/editing/htmlediting.cpp b/khtml/editing/htmlediting.cpp
index 8d128aa..40b1f09 100644
--- a/khtml/editing/htmlediting.cpp
+++ b/khtml/editing/htmlediting.cpp
@@ -35,6 +35,10 @@
 #include "xml/dom_selection.h"
 #include "xml/dom_textimpl.h"
 
+#include "xml/PositionIterator.h"
+#include "xml/Position.h"
+#include "xml/Selection.h"
+
 using DOM::CSSStyleDeclarationImpl;
 using DOM::DocumentImpl;
 using DOM::ElementImpl;
diff --git a/khtml/editing/htmlediting_impl.cpp b/khtml/editing/htmlediting_impl.cpp
index e0b2d2b..40940cf 100644
--- a/khtml/editing/htmlediting_impl.cpp
+++ b/khtml/editing/htmlediting_impl.cpp
@@ -47,6 +47,10 @@
 #include "xml/dom2_rangeimpl.h"
 #include "xml/dom2_viewsimpl.h"
 
+#include "xml/Position.h"
+#include "xml/PositionIterator.h"
+#include "xml/Selection.h"
+
 #include "khtml_part.h"
 #include "khtmlview.h"
 
@@ -157,13 +161,14 @@ static Position leadingWhitespacePosition(const Position &pos)
 {
     assert(pos.notEmpty());
 
-    Selection selection(pos);
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    /*FIXME khtml Selection selection(pos);
     Position prev = pos.previousCharacterPosition();
     if (prev != pos && prev.node()->inSameContainingBlockFlowElement(pos.node()) && prev.node()->isTextNode()) {
         DOMString string = static_cast<TextImpl *>(prev.node())->data();
         if (isWS(string[prev.offset()]))
             return prev;
-    }
+    }*/
 
     return Position();
 }
@@ -172,7 +177,7 @@ static Position trailingWhitespacePosition(const Position &pos)
 {
     assert(pos.notEmpty());
 
-    if (pos.node()->isTextNode()) {
+    /*if (pos.node()->isTextNode()) {
         TextImpl *textNode = static_cast<TextImpl *>(pos.node());
         if (pos.offset() >= (long)textNode->length()) {
             Position next = pos.nextCharacterPosition();
@@ -187,7 +192,7 @@ static Position trailingWhitespacePosition(const Position &pos)
             if (isWS(string[pos.offset()]))
                 return pos;
         }
-    }
+    }*/
 
     return Position();
 }
@@ -614,7 +619,8 @@ int ApplyStyleCommandImpl::commandID() const
 
 void ApplyStyleCommandImpl::doApply()
 {
-    if (endingSelection().state() != Selection::RANGE)
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    /*if (endingSelection().state() != Selection::RANGE)
         return;
 
     // adjust to the positions we want to use for applying style
@@ -655,7 +661,7 @@ void ApplyStyleCommandImpl::doApply()
                 break;
             node = node->traverseNextNode();
         }
-    }
+    }*/
 }
 
 //------------------------------------------------------------------------------------------
@@ -736,7 +742,7 @@ void ApplyStyleCommandImpl::removeStyle(const Position &start, const Position &e
 
 bool ApplyStyleCommandImpl::nodeFullySelected(const NodeImpl *node) const
 {
-    assert(node);
+    /*assert(node);
 
     Position end(endingSelection().end().equivalentUpstreamPosition());
 
@@ -748,7 +754,9 @@ bool ApplyStyleCommandImpl::nodeFullySelected(const NodeImpl *node) const
             return end.offset() >= child->caretMaxOffset();
     }
 
-    return node == end.node() || !node->isAncestor(end.node());
+    return node == end.node() || !node->isAncestor(end.node());*/
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    return false;
 }
 
 //------------------------------------------------------------------------------------------
@@ -939,7 +947,7 @@ int DeleteCollapsibleWhitespaceCommandImpl::commandID() const
 
 static bool shouldDeleteUpstreamPosition(const Position &pos)
 {
-    if (!pos.node()->isTextNode())
+    /*if (!pos.node()->isTextNode())
         return false;
 
     RenderObject *renderer = pos.node()->renderer();
@@ -963,14 +971,15 @@ static bool shouldDeleteUpstreamPosition(const Position &pos)
         }
         if (pos.offset() >= box->m_start && pos.offset() < box->m_start + box->m_len)
             return false;
-    }
+    }*/
+    kDebug() << "NOT IMPLEMENTED" << endl;
 
     return true;
 }
 
 Position DeleteCollapsibleWhitespaceCommandImpl::deleteWhitespace(const Position &pos)
 {
-    Position upstream = pos.equivalentUpstreamPosition();
+    /*FIXME khtml Position upstream = pos.equivalentUpstreamPosition();
     Position downstream = pos.equivalentDownstreamPosition();
 
     bool del = shouldDeleteUpstreamPosition(upstream);
@@ -1044,12 +1053,14 @@ Position DeleteCollapsibleWhitespaceCommandImpl::deleteWhitespace(const Position
         it.setPosition(next);
     }
 
-    return endingPosition;
+    return endingPosition;*/
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    return Position();
 }
 
 void DeleteCollapsibleWhitespaceCommandImpl::doApply()
 {
-    // If selection has not been set to a custom selection when the command was created,
+    /*// If selection has not been set to a custom selection when the command was created,
     // use the current ending selection.
     if (!m_hasSelectionToCollapse)
         m_selectionToCollapse = endingSelection();
@@ -1070,7 +1081,8 @@ void DeleteCollapsibleWhitespaceCommandImpl::doApply()
         endPosition = deleteWhitespace(endPosition);
         setEndingSelection(Selection(startPosition, endPosition));
         kDebug(6200) << "=====================================================";
-    }
+    }*/
+    kDebug() << "NOT IMPLEMENTED" << endl;
 }
 
 //------------------------------------------------------------------------------------------
@@ -1097,7 +1109,7 @@ int DeleteSelectionCommandImpl::commandID() const
 
 void DeleteSelectionCommandImpl::joinTextNodesWithSameStyle()
 {
-    Selection selection = endingSelection();
+    /*Selection selection = endingSelection();
 
     if (selection.state() != Selection::CARET)
         return;
@@ -1136,12 +1148,12 @@ void DeleteSelectionCommandImpl::joinTextNodesWithSameStyle()
                 kDebug(6200) << "joinTextNodesWithSameStyle [2]";
             }
         }
-    }
+    }*/
 }
 
 bool DeleteSelectionCommandImpl::containsOnlyWhitespace(const Position &start, const Position &end)
 {
-    // Returns whether the range contains only whitespace characters.
+    /*// Returns whether the range contains only whitespace characters.
     // This is inclusive of the start, but not of the end.
     PositionIterator it(start);
     while (!it.atEnd()) {
@@ -1157,12 +1169,14 @@ bool DeleteSelectionCommandImpl::containsOnlyWhitespace(const Position &start, c
         if (it.current() == end)
             break;
     }
-    return true;
+    return true;*/
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    return false;
 }
 
 void DeleteSelectionCommandImpl::doApply()
 {
-    // If selection has not been set to a custom selection when the command was created,
+    /*// If selection has not been set to a custom selection when the command was created,
     // use the current ending selection.
     if (!m_hasSelectionToDelete)
         m_selectionToDelete = endingSelection();
@@ -1362,7 +1376,8 @@ void DeleteSelectionCommandImpl::doApply()
     debugPosition("ending position:     ", endingPosition);
     setEndingSelection(endingPosition);
 
-    kDebug(6200) << "-----------------------------------------------------";
+    kDebug(6200) << "-----------------------------------------------------";*/
+        kDebug() << "NOT IMPLEMENTED" << endl;
 }
 
 //------------------------------------------------------------------------------------------
@@ -1433,12 +1448,12 @@ void InputNewlineCommandImpl::insertNodeAfterPosition(NodeImpl *node, const Posi
     // Insert the BR after the caret position. In the case the
     // position is a block, do an append. We don't want to insert
     // the BR *after* the block.
-    Position upstream(pos.equivalentUpstreamPosition());
+    /*Position upstream(pos.equivalentUpstreamPosition());
     NodeImpl *cb = pos.node()->enclosingBlockFlowElement();
     if (cb == pos.node())
         appendNode(cb, node);
     else
-        insertNodeAfter(node, pos.node());
+        insertNodeAfter(node, pos.node());*/
 }
 
 void InputNewlineCommandImpl::insertNodeBeforePosition(NodeImpl *node, const Position &pos)
@@ -1446,17 +1461,17 @@ void InputNewlineCommandImpl::insertNodeBeforePosition(NodeImpl *node, const Pos
     // Insert the BR after the caret position. In the case the
     // position is a block, do an append. We don't want to insert
     // the BR *before* the block.
-    Position upstream(pos.equivalentUpstreamPosition());
+    /*Position upstream(pos.equivalentUpstreamPosition());
     NodeImpl *cb = pos.node()->enclosingBlockFlowElement();
     if (cb == pos.node())
         appendNode(cb, node);
     else
-        insertNodeBefore(node, pos.node());
+        insertNodeBefore(node, pos.node());*/
 }
 
 void InputNewlineCommandImpl::doApply()
 {
-    deleteSelection();
+    /*deleteSelection();
     Selection selection = endingSelection();
 
     int exceptionCode = 0;
@@ -1508,7 +1523,7 @@ void InputNewlineCommandImpl::doApply()
         insertNodeBefore(textBeforeNode, textNode);
         insertNodeBefore(nodeToInsert, textNode);
         setEndingSelection(Position(textNode, 0));
-    }
+    }*/
 }
 
 //------------------------------------------------------------------------------------------
@@ -1560,7 +1575,7 @@ void InputTextCommandImpl::deleteCharacter()
 
 Position InputTextCommandImpl::prepareForTextInsertion(bool adjustDownstream)
 {
-    // Prepare for text input by looking at the current position.
+    /*// Prepare for text input by looking at the current position.
     // It may be necessary to insert a text node to receive characters.
     Selection selection = endingSelection();
     assert(selection.state() == Selection::CARET);
@@ -1630,12 +1645,13 @@ Position InputTextCommandImpl::prepareForTextInsertion(bool adjustDownstream)
             pos = Position(editingTextNode, 0);
         }
     }
-    return pos;
+    return pos;*/
+    return Position();
 }
 
 void InputTextCommandImpl::execute(const DOMString &text)
 {
-    Selection selection = endingSelection();
+    /*Selection selection = endingSelection();
     bool adjustDownstream = selection.start().isFirstRenderedPositionOnLine();
 
     // Delete the current selection, or collapse whitespace, as needed
@@ -1668,17 +1684,20 @@ void InputTextCommandImpl::execute(const DOMString &text)
             // those nbsp's added by the editor to make rendering come out right.
             replaceText(textNode, offset - 1, 1, " ");
         }
+        kDebug() << "BEFORE INSERT:" << DOMString(textNode->data()) << endl;
+        kDebug() << offset << endl;
         insertText(textNode, offset, text);
+        kDebug() << "AFTER INSERT:" << DOMString(textNode->data()) << endl;
     }
     setEndingSelection(Position(textNode, offset + text.length()));
-    m_charactersAdded += text.length();
+    m_charactersAdded += text.length();*/
 }
 
 void InputTextCommandImpl::insertSpace(TextImpl *textNode, unsigned long offset)
 {
     assert(textNode);
 
-    DOMString text(textNode->data());
+    /*DOMString text(textNode->data());
 
     // count up all spaces and newlines in front of the caret
     // delete all collapsed ones
@@ -1716,7 +1735,7 @@ void InputTextCommandImpl::insertSpace(TextImpl *textNode, unsigned long offset)
     }
 
     // insert an nbsp
-    insertText(textNode, offset, nonBreakingSpaceString());
+    insertText(textNode, offset, nonBreakingSpaceString());*/
 }
 
 //------------------------------------------------------------------------------------------
@@ -1893,7 +1912,7 @@ int ReplaceSelectionCommandImpl::commandID() const
 
 void ReplaceSelectionCommandImpl::doApply()
 {
-    NodeImpl *firstChild = m_fragment->firstChild();
+    /*NodeImpl *firstChild = m_fragment->firstChild();
     NodeImpl *lastChild = m_fragment->lastChild();
 
     Selection selection = endingSelection();
@@ -1958,7 +1977,7 @@ void ReplaceSelectionCommandImpl::doApply()
             // Place the cursor after what was inserted.
             setEndingSelection(Position(lastLeaf, lastLeaf->caretMaxOffset()));
         }
-    }
+    }*/
 }
 
 //------------------------------------------------------------------------------------------
@@ -1980,7 +1999,7 @@ int MoveSelectionCommandImpl::commandID() const
 
 void MoveSelectionCommandImpl::doApply()
 {
-    Selection selection = endingSelection();
+    /*Selection selection = endingSelection();
     assert(selection.state() == Selection::RANGE);
 
     // Update the position otherwise it may become invalid after the selection is deleted.
@@ -2000,7 +2019,7 @@ void MoveSelectionCommandImpl::doApply()
 
     setEndingSelection(Position(positionNode, positionOffset));
     ReplaceSelectionCommand cmd(document(), m_fragment, true);
-    applyCommandToComposite(cmd);
+    applyCommandToComposite(cmd);*/
 }
 
 //------------------------------------------------------------------------------------------
@@ -2395,7 +2414,7 @@ void TypingCommandImpl::insertNewline()
 
 void TypingCommandImpl::issueCommandForDeleteKey()
 {
-    Selection selectionToDelete = endingSelection();
+    /*Selection selectionToDelete = endingSelection();
     assert(selectionToDelete.state() != Selection::NONE);
 
     if (selectionToDelete.state() == Selection::CARET) {
@@ -2407,7 +2426,7 @@ void TypingCommandImpl::issueCommandForDeleteKey()
         selectionToDelete = Selection(pos.previousCharacterPosition(), pos);
     }
     deleteSelection(selectionToDelete);
-    typingAddedToOpenCommand();
+    typingAddedToOpenCommand();*/
 }
 
 void TypingCommandImpl::deleteKeyPressed()
diff --git a/khtml/editing/htmlediting_impl.h b/khtml/editing/htmlediting_impl.h
index 7de4fc8..78cfb72 100644
--- a/khtml/editing/htmlediting_impl.h
+++ b/khtml/editing/htmlediting_impl.h
@@ -29,8 +29,8 @@
 #include "misc/shared.h"
 #include "htmlediting.h"
 
-#include "xml/dom_position.h"
-#include "xml/dom_selection.h"
+#include "xml/Position.h"
+#include "xml/Selection.h"
 #include "dom/dom_string.h"
 
 #include <QList>
diff --git a/khtml/editing/jsediting.cpp b/khtml/editing/jsediting.cpp
index bb437db..e84e828 100644
--- a/khtml/editing/jsediting.cpp
+++ b/khtml/editing/jsediting.cpp
@@ -31,6 +31,7 @@
 #include "css/cssvalues.h"
 #include "css/css_valueimpl.h"
 #include "xml/dom_selection.h"
+#include "xml/Selection.h"
 #include "xml/dom_docimpl.h"
 #include "dom/dom_string.h"
 
@@ -360,7 +361,7 @@ static bool enabled(KHTMLPart * /*part*/)
 
 static bool enabledAnySelection(KHTMLPart *part)
 {
-    return KPAC::caret(part).notEmpty();
+    return !KPAC::caret(part).isNone();
 }
 
 #ifndef NO_SUPPORT_PASTE
diff --git a/khtml/find/khtmlfind.cpp b/khtml/find/khtmlfind.cpp
index 841c0ea..5742b96 100644
--- a/khtml/find/khtmlfind.cpp
+++ b/khtml/find/khtmlfind.cpp
@@ -28,7 +28,7 @@
 #include "html/html_documentimpl.h"
 #include "rendering/render_text.h"
 #include "misc/htmlhashes.h"
-#include "xml/dom_selection.h"
+#include "xml/Selection.h"
 
 #include "khtmlview.h"
 
@@ -565,7 +565,7 @@ void KHTMLFind::slotHighlight( const QString& /*text*/, int index, int length )
   }
   Q_ASSERT ( prev != itEnd );
 
-  sel.moveTo(sel.start(), Position((*prev).node, index + length - (*prev).index));
+  //FIXME khtml port sel.moveTo(sel.start(), Position((*prev).node, index + length - (*prev).index));
 
 #if 0
   kDebug(6050) << "slotHighlight: " << d->m_selectionStart.handle() << "," << d->m_startOffset << " - " <<
diff --git a/khtml/html/html_formimpl.cpp b/khtml/html/html_formimpl.cpp
index ee8583b..3810246 100644
--- a/khtml/html/html_formimpl.cpp
+++ b/khtml/html/html_formimpl.cpp
@@ -2554,6 +2554,33 @@ void HTMLSelectElementImpl::notifyOptionSelected(HTMLOptionElementImpl *selected
     setChanged(true);
 }
 
+bool HTMLSelectElementImpl::canSelectAll() const
+{
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    //return !usesMenuList();
+    return false;
+}
+
+void HTMLSelectElementImpl::selectAll()
+{
+    /*ASSERT(!usesMenuList());
+    if (!renderer() || !multiple())
+        return;
+    
+    // Save the selection so it can be compared to the new selectAll selection when we call onChange
+    saveLastSelection();
+    
+    m_activeSelectionState = true;
+    setActiveSelectionAnchorIndex(nextSelectableListIndex(-1));
+    setActiveSelectionEndIndex(previousSelectableListIndex(-1));
+    
+    updateListBoxSelection(false);
+    listBoxOnChange();*/
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    return;
+}
+
+
 // -------------------------------------------------------------------------
 
 HTMLKeygenElementImpl::HTMLKeygenElementImpl(DocumentImpl* doc, HTMLFormElementImpl* f)
diff --git a/khtml/html/html_formimpl.h b/khtml/html/html_formimpl.h
index 2652dc4..b9ee7a4 100644
--- a/khtml/html/html_formimpl.h
+++ b/khtml/html/html_formimpl.h
@@ -444,6 +444,9 @@ public:
     virtual void reset();
     void notifyOptionSelected(HTMLOptionElementImpl *selectedOption, bool selected);
 
+    virtual bool canSelectAll() const;
+    virtual void selectAll();
+
 private:
     void recalcListItems() const;
 
diff --git a/khtml/khtml_events.cpp b/khtml/khtml_events.cpp
index 1500301..22fcda8 100644
--- a/khtml/khtml_events.cpp
+++ b/khtml/khtml_events.cpp
@@ -47,15 +47,16 @@ khtml::MouseEvent::~MouseEvent()
 
 long khtml::MouseEvent::offset() const
 {
-    Position pos;
+    VisiblePosition pos;
     if (innerNode().handle()) {
         // FIXME: Shouldn't be necessary to skip text nodes.
         DOM::Node inner = innerNode();
         if (inner.nodeType() == Node::TEXT_NODE)
             inner = inner.parentNode();
-        pos = inner.handle()->positionForCoordinates(m_x, m_y);
+        if (inner.handle() && inner.handle()->renderer())
+        pos = inner.handle()->renderer()->positionForCoordinates(m_x, m_y);
     }
-    return pos.offset();
+    return pos.deepEquivalent().offset();
 }
 
 const char *khtml::MousePressEvent::s_strMousePressEvent = "khtml/Events/MousePressEvent";
diff --git a/khtml/khtml_part.cpp b/khtml/khtml_part.cpp
index c4cfd30..074cc8e 100644
--- a/khtml/khtml_part.cpp
+++ b/khtml/khtml_part.cpp
@@ -50,6 +50,7 @@
 #include "rendering/render_text.h"
 #include "rendering/render_frames.h"
 #include "rendering/render_layer.h"
+#include "rendering/render_canvas.h"
 #include "misc/htmlhashes.h"
 #include "misc/loader.h"
 #include "misc/khtml_partaccessor.h"
@@ -58,6 +59,7 @@
 #include "xml/xml_tokenizer.h"
 #include "css/cssstyleselector.h"
 #include "css/csshelper.h"
+#include "xml/Selection.h"
 using namespace DOM;
 
 #include "khtmlview.h"
@@ -2799,9 +2801,10 @@ void KHTMLPart::initCaret()
       } else
         node = d->m_doc;
       if (!node) return;
+      kDebug() << "selection moveTo" << node << getPrintableName(node->id()) << endl;
       d->editor_context.m_selection.moveTo(Position(node, 0));
-      d->editor_context.m_selection.setNeedsLayout();
-      d->editor_context.m_selection.needsCaretRepaint();
+      /*d->editor_context.m_selection.setNeedsLayout();
+      d->editor_context.m_selection.needsCaretRepaint();*/
     }
   }
 }
@@ -2809,13 +2812,14 @@ void KHTMLPart::initCaret()
 static void setCaretInvisibleIfNeeded(KHTMLPart *part)
 {
   // On contenteditable nodes, don't hide the caret
-  if (!khtml::KHTMLPartAccessor::caret(part).caretPos().node()->isContentEditable())
-    part->setCaretVisible(false);
+  kDebug() << "NOT IMPLEMENTED" << endl;
+  /*if (!khtml::KHTMLPartAccessor::caret(part).caretPos().node()->isContentEditable())
+    part->setCaretVisible(false);*/
 }
 
 void KHTMLPart::setCaretMode(bool enable)
 {
-  kDebug(6200) << enable;
+  //FIXME kDebug(6200) << enable;
   if (isCaretMode() == enable) return;
   d->setFlagRecursively(&KHTMLPartPrivate::m_caretMode, enable);
   // FIXME: this won't work on frames as expected
@@ -2894,21 +2898,13 @@ void KHTMLPart::setCaretDisplayPolicyNonFocused(CaretDisplayPolicy policy)
 #endif
 }
 
-void KHTMLPart::setCaretVisible(bool show)
+void KHTMLPart::setCaretVisible(bool flag)
 {
-  if (show) {
-    NodeImpl *caretNode = d->editor_context.m_selection.caretPos().node();
-    if (isCaretMode() || (caretNode && caretNode->isContentEditable())) {
-        invalidateSelection();
-        enableFindAheadActions(false);
-    }
-  } else {
-
-    if (d->editor_context.m_caretBlinkTimer >= 0)
-        killTimer(d->editor_context.m_caretBlinkTimer);
+    if (d->editor_context.m_caretVisible == flag)
+        return;
     clearCaretRectIfNeeded();
-
-  }
+    d->editor_context.m_caretVisible = flag;
+    selectionLayoutChanged();
 }
 
 void KHTMLPart::findTextBegin()
@@ -2971,6 +2967,10 @@ void KHTMLPart::slotFindAheadText()
   KParts::ReadOnlyPart *part = currentFrame();
   if (!part)
     return;
+  if (isEditable() || (xmlDocImpl() && xmlDocImpl()->focusNode() && xmlDocImpl()->focusNode()->isContentEditable())) {
+      kDebug() << "ignore find ahead action" << endl;
+      return;
+  }
   if (!part->inherits("KHTMLPart") )
   {
       kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it";
@@ -3034,7 +3034,9 @@ bool KHTMLPart::findTextNext( bool reverse )
 
 QString KHTMLPart::selectedTextAsHTML() const
 {
-  const Selection &sel = d->editor_context.m_selection;
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    return QString();
+  /*const Selection &sel = d->editor_context.m_selection;
   if(!hasSelection()) {
     kDebug() << "Selection is not valid. Returning empty selection";
     return QString();
@@ -3047,7 +3049,7 @@ QString KHTMLPart::selectedTextAsHTML() const
   if(r.isNull() || r.isDetached())
     return QString();
   int exceptioncode = 0; //ignore the result
-  return r.handle()->toHTML(exceptioncode).string();
+  return r.handle()->toHTML(exceptioncode).string();*/
 }
 
 QString KHTMLPart::selectedText() const
@@ -3055,7 +3057,7 @@ QString KHTMLPart::selectedText() const
   bool hasNewLine = true;
   bool seenTDTag = false;
   QString text;
-  const Selection &sel = d->editor_context.m_selection;
+  const Selection &sel = d->editor_context.m_selection.selection();
   DOM::Node n = sel.start().node();
   while(!n.isNull()) {
       if(n.nodeType() == DOM::Node::TEXT_NODE && n.handle()->renderer()) {
@@ -3208,17 +3210,17 @@ QString KHTMLPart::simplifiedSelectedText() const
 
 bool KHTMLPart::hasSelection() const
 {
-    return !d->editor_context.m_selection.isEmpty() && !d->editor_context.m_selection.isCollapsed();
+    return d->editor_context.m_selection.isNone()/* && !d->editor_context.m_selection.isCollapsed()*/;
 }
 
 DOM::Range KHTMLPart::selection() const
 {
-    return d->editor_context.m_selection.toRange();
+    return d->editor_context.m_selection.toDOMRange();
 }
 
 void KHTMLPart::selection(DOM::Node &s, long &so, DOM::Node &e, long &eo) const
 {
-    DOM::Range r = d->editor_context.m_selection.toRange();
+    DOM::Range r = d->editor_context.m_selection.toDOMRange();
     s = r.startContainer();
     so = r.startOffset();
     e = r.endContainer();
@@ -3227,12 +3229,13 @@ void KHTMLPart::selection(DOM::Node &s, long &so, DOM::Node &e, long &eo) const
 
 void KHTMLPart::setSelection( const DOM::Range &r )
 {
-    setCaret(r);
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    //setCaret(r);
 }
 
 const Selection &KHTMLPart::caret() const
 {
-  return d->editor_context.m_selection;
+  return d->editor_context.m_selection.selection();
 }
 
 const Selection &KHTMLPart::dragCaret() const
@@ -3242,57 +3245,62 @@ const Selection &KHTMLPart::dragCaret() const
 
 void KHTMLPart::setCaret(const Selection &s, bool closeTyping)
 {
-  if (d->editor_context.m_selection != s) {
+    kDebug() << "NOT IMPLEMENTED" << endl;
+  /*if (d->editor_context.m_selection != s) {
     clearCaretRectIfNeeded();
     setFocusNodeIfNeeded(s);
     d->editor_context.m_selection = s;
     notifySelectionChanged(closeTyping);
-  }
+  }*/
 }
 
 void KHTMLPart::setDragCaret(const DOM::Selection &dragCaret)
 {
-  if (d->editor_context.m_dragCaret != dragCaret) {
+    kDebug() << "NOT IMPLEMENTED!" << endl;
+  /*if (d->editor_context.m_dragCaret != dragCaret) {
     d->editor_context.m_dragCaret.needsCaretRepaint();
     d->editor_context.m_dragCaret = dragCaret;
     d->editor_context.m_dragCaret.needsCaretRepaint();
-  }
+  }*/
 }
 
 void KHTMLPart::clearSelection()
 {
-  clearCaretRectIfNeeded();
+    kDebug() << "NOT IMPLEMENTED" << endl;
+  /*clearCaretRectIfNeeded();
   setFocusNodeIfNeeded(d->editor_context.m_selection);
 #ifdef APPLE_CHANGES
   d->editor_context.m_selection.clear();
 #else
   d->editor_context.m_selection.collapse();
 #endif
-  notifySelectionChanged();
+  notifySelectionChanged();*/
 }
 
 void KHTMLPart::invalidateSelection()
 {
-  clearCaretRectIfNeeded();
-  d->editor_context.m_selection.setNeedsLayout();
-  selectionLayoutChanged();
+    d->editor_context.m_selection.setNeedsLayout();
+    selectionLayoutChanged();
 }
 
 void KHTMLPart::setSelectionVisible(bool flag)
 {
-  if (d->editor_context.m_caretVisible == flag)
+    //kDebug() << "NOT IMPLEMENTED" << endl;
+    d->editor_context.m_caretVisible = flag;
+  /*if (d->editor_context.m_caretVisible == flag)
     return;
 
   clearCaretRectIfNeeded();
   setFocusNodeIfNeeded(d->editor_context.m_selection);
   d->editor_context.m_caretVisible = flag;
-//   notifySelectionChanged();
+//   notifySelectionChanged();*/
 }
 
 #if 1
 void KHTMLPart::slotClearSelection()
 {
-  if (!isCaretMode()
+    kDebug() << "NOT IMPLEMENTED" << endl;
+  /*if (!isCaretMode()
        && d->editor_context.m_selection.state() != Selection::NONE
        && !d->editor_context.m_selection.caretPos().node()->isContentEditable())
     clearCaretRectIfNeeded();
@@ -3303,70 +3311,129 @@ void KHTMLPart::slotClearSelection()
   d->editor_context.m_selection.collapse();
 #endif
   if (hadSelection)
-    notifySelectionChanged();
+    notifySelectionChanged();*/
 }
 #endif
 
+DOM::SelectionController* KHTMLPart::selectionController() const
+{
+    return &d->editor_context.m_selection;
+}
+
 void KHTMLPart::clearCaretRectIfNeeded()
 {
-  if (d->editor_context.m_caretPaint) {
-    d->editor_context.m_caretPaint = false;
-    d->editor_context.m_selection.needsCaretRepaint();
-  }
+    if (d->editor_context.m_caretPaint) {
+        d->editor_context.m_caretPaint = false;
+        d->editor_context.m_selection.invalidateCaretRect();
+    }
 }
 
-void KHTMLPart::setFocusNodeIfNeeded(const Selection &s)
+void KHTMLPart::setFocusedNodeIfNeeded()
 {
-  if (!xmlDocImpl() || s.state() == Selection::NONE)
-    return;
+    kDebug() << "set focus" << d->editor_context.m_selection.isNone() << (!d->editor_context.m_selection.isFocusedAndActive()) << endl;
+    if (!xmlDocImpl() || d->editor_context.m_selection.isNone() || !d->editor_context.m_selection.isFocusedAndActive())
+        return;
 
-  NodeImpl *n = s.start().node();
-  NodeImpl *target = (n && n->isContentEditable()) ? n : 0;
-  if (!target) {
-    while (n && n != s.end().node()) {
-      if (n->isContentEditable()) {
-        target = n;
-        break;
-      }
-      n = n->traverseNextNode();
+    NodeImpl* target = d->editor_context.m_selection.rootEditableElement();
+    kDebug() << "root editable element:" << target << endl;
+    if (target) {
+        kDebug() << "root id:" << getPrintableName(target->id()) << endl;
+        RenderObject* renderer = target->renderer();
+
+        // Walk up the render tree to search for a node to focus.
+        // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
+        while (renderer) {
+            kDebug() << "renderer" << renderer << endl;
+            // We don't want to set focus on a subframe when selecting in a parent frame,
+            // so add the !isFrameElement check here. There's probably a better way to make this
+            // work in the long term, but this is the safest fix at this time.
+            kDebug() << "target" << target << target->isMouseFocusable() << endl;
+            if (target/*FIXME khtml && target->isMouseFocusable() && !isFrameElement(target)*/) {
+                //page()->focusController()->setFocusedNode(target, this);
+                xmlDocImpl()->setFocusNode(target); // ???
+                return;
+            }
+            renderer = renderer->parent();
+            if (renderer)
+                target = renderer->element();
+        }
+        kDebug() << "no luck" << endl;
+        xmlDocImpl()->setFocusNode(0);
     }
-  }
-  assert(target == 0 || target->isContentEditable());
+}
 
-  if (target) {
-    for ( ; target && !target->isFocusable(); target = target->parentNode())
-      {}
-    if (target && target->isMouseFocusable())
-      xmlDocImpl()->setFocusNode(target);
-    else if (!target || !target->focused())
-      xmlDocImpl()->setFocusNode(0);
-  }
+khtml::RenderCanvas* KHTMLPart::contentRenderer() const
+{
+    DocumentImpl* doc = xmlDocImpl();
+    if (!doc)
+        return 0;
+    khtml::RenderObject* object = doc->renderer();
+    if (!object)
+        return 0;
+    ASSERT(object->isRenderCanvas());
+    return static_cast<khtml::RenderCanvas*>(object);
 }
 
 void KHTMLPart::selectionLayoutChanged()
 {
-  // kill any caret blink timer now running
-  if (d->editor_context.m_caretBlinkTimer >= 0) {
-    killTimer(d->editor_context.m_caretBlinkTimer);
-    d->editor_context.m_caretBlinkTimer = -1;
-  }
+    bool caretRectChanged = selectionController()->recomputeCaretRect();
+    kDebug() << "caret rect changed:" << caretRectChanged << endl;
 
-  // see if a new caret blink timer needs to be started
-  if (d->editor_context.m_caretVisible
-      && d->editor_context.m_selection.state() != Selection::NONE) {
-    d->editor_context.m_caretPaint = isCaretMode()
-        || d->editor_context.m_selection.caretPos().node()->isContentEditable();
-    if (d->editor_context.m_caretBlinks && d->editor_context.m_caretPaint)
-      d->editor_context.m_caretBlinkTimer = startTimer(qApp->cursorFlashTime() / 2);
-    d->editor_context.m_selection.needsCaretRepaint();
-  }
+//#if ENABLE(TEXT_CARET)
+    /*FIXME khtml bool shouldBlink = d->editor_context.m_caretVisible
+        && selectionController()->isCaret() && selectionController()->isContentEditable();
 
-  if (d->m_doc)
-    d->m_doc->updateSelection();
+    // If the caret moved, stop the blink timer so we can restart with a
+    // black caret in the new location.
+    if (caretRectChanged || !shouldBlink)
+        d->editor_context.m_caretBlinkTimer.stop();
+
+    // Start blinking with a black caret. Be sure not to restart if we're
+    // already blinking in the right location.
+    if (shouldBlink && !d->editor_context.m_caretBlinkTimer.isActive()) {
+        if (double blinkInterval = theme()->caretBlinkInterval())
+            d->editor_context.m_caretBlinkTimer.startRepeating(blinkInterval);
+
+        if (!d->m_caretPaint) {
+            d->m_caretPaint = true;
+            selectionController()->invalidateCaretRect();
+        }
+    }*/
+    d->editor_context.m_caretPaint = true;
+    selectionController()->invalidateCaretRect();
+//#else
+//    if (!caretRectChanged)
+//        return;
+//#endif
+
+    khtml::RenderCanvas* view = contentRenderer();
+    if (!view)
+        return;
 
-  // Always clear the x position used for vertical arrow navigation.
-  // It will be restored by the vertical arrow navigation code if necessary.
-  d->editor_context.m_xPosForVerticalArrowNavigation = d->editor_context.NoXPosForVerticalArrowNavigation;
+    Selection selection = this->selectionController()->selection();
+        
+    if (!selection.isRange())
+        view->clearSelection();
+    else {
+        // Use the rightmost candidate for the start of the selection, and the leftmost candidate for the end of the selection.
+        // Example: foo <a>bar</a>.  Imagine that a line wrap occurs after 'foo', and that 'bar' is selected.   If we pass [foo, 3]
+        // as the start of the selection, the selection painting code will think that content on the line containing 'foo' is selected
+        // and will fill the gap before 'bar'.
+        Position startPos = selection.start();
+        if (startPos.downstream().isCandidate())
+            startPos = startPos.downstream();
+        Position endPos = selection.end();
+        if (endPos.upstream().isCandidate())
+            endPos = endPos.upstream();
+        
+        // We can get into a state where the selection endpoints map to the same VisiblePosition when a selection is deleted
+        // because we don't yet notify the SelectionController of text removal.
+        if (startPos.isNotNull() && endPos.isNotNull() && selection.visibleStart() != selection.visibleEnd()) {
+            RenderObject *startRenderer = startPos.node()->renderer();
+            RenderObject *endRenderer = endPos.node()->renderer();
+            view->setSelection(startRenderer, startPos.offset(), endRenderer, endPos.offset());
+        }
+    }
 }
 
 void KHTMLPart::notifySelectionChanged(bool closeTyping)
@@ -3384,14 +3451,23 @@ void KHTMLPart::notifySelectionChanged(bool closeTyping)
 
 }
 
+void KHTMLPart::caretBlinkTimerFired(/*Timer<Frame>**/)
+{
+#if ENABLE(TEXT_CARET)
+    ASSERT(d->m_caretVisible);
+    ASSERT(selectionController()->isCaret());
+    bool caretPaint = d->m_caretPaint;
+    if (selectionController()->isCaretBlinkingSuspended() && caretPaint)
+        return;
+    d->m_caretPaint = !caretPaint;
+    selection()->invalidateCaretRect();
+#endif
+}
+
 void KHTMLPart::timerEvent(QTimerEvent *e)
 {
   if (e->timerId() == d->editor_context.m_caretBlinkTimer) {
-    if (d->editor_context.m_caretBlinks &&
-        d->editor_context.m_selection.state() != Selection::NONE) {
-      d->editor_context.m_caretPaint = !d->editor_context.m_caretPaint;
-      d->editor_context.m_selection.needsCaretRepaint();
-    }
+    caretBlinkTimerFired();
   } else if (e->timerId() == d->m_DNSPrefetchTimer) {
       // kDebug( 6050 ) << "will lookup " << d->m_DNSPrefetchQueue.head() << d->m_numDNSPrefetchedNames;
       KIO::HostInfo::prefetchHost( d->m_DNSPrefetchQueue.dequeue() );
@@ -3436,15 +3512,19 @@ bool KHTMLPart::mayPrefetchHostname( const QString& name )
     return true;
 }
 
-void KHTMLPart::paintCaret(QPainter *p, const QRect &rect) const
+void KHTMLPart::paintCaret(QPainter *p, int tx, int ty, const QRect &clipRect) const
 {
-  if (d->editor_context.m_caretPaint)
-    d->editor_context.m_selection.paintCaret(p, rect);
+    //FIXME khtml if (d->editor_context.m_caretPaint && d->editor_context.m_caretVisible)
+        selectionController()->paintCaret(p, tx, ty, clipRect);
 }
 
-void KHTMLPart::paintDragCaret(QPainter *p, const QRect &rect) const
+void KHTMLPart::paintDragCaret(QPainter *p, int tx, int ty, const QRect &clipRect) const
 {
-  d->editor_context.m_dragCaret.paintCaret(p, rect);
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    /*SelectionController* dragCaretController = d->m_page->dragCaretController();
+    ASSERT(dragCaretController->selection().isCaret());
+    if (dragCaretController->selection().start().node()->document()->frame() == this)
+        dragCaretController->paintCaret(p, tx, ty, clipRect);*/
 }
 
 DOM::Editor *KHTMLPart::editor() const {
@@ -5900,7 +5980,8 @@ void KHTMLPart::customEvent( QEvent *event )
 
 bool KHTMLPart::isPointInsideSelection(int x, int y)
 {
-  // Treat a collapsed selection like no selection.
+  return d->editor_context.m_selection.contains(QPoint(x, y));
+  /*// Treat a collapsed selection like no selection.
   if (d->editor_context.m_selection.state() == Selection::CARET)
     return false;
   if (!xmlDocImpl()->renderer())
@@ -5912,7 +5993,7 @@ bool KHTMLPart::isPointInsideSelection(int x, int y)
   if (!innerNode || !innerNode->renderer())
     return false;
 
-  return innerNode->isPointInsideSelection(x, y, d->editor_context.m_selection);
+  return innerNode->isPointInsideSelection(x, y, d->editor_context.m_selection);*/
 }
 
 /** returns the position of the first inline text box of the line at
@@ -5984,7 +6065,8 @@ static bool lastRunAt(khtml::RenderObject *renderNode, int y, NodeImpl *&endNode
 
 void KHTMLPart::handleMousePressEventDoubleClick(khtml::MouseDoubleClickEvent *event)
 {
-    QMouseEvent *mouse = event->qmouseEvent();
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    /*QMouseEvent *mouse = event->qmouseEvent();
     DOM::Node innerNode = event->innerNode();
 
     Selection selection;
@@ -6003,12 +6085,13 @@ void KHTMLPart::handleMousePressEventDoubleClick(khtml::MouseDoubleClickEvent *e
     }
 
     setCaret(selection);
-    startAutoScroll();
+    startAutoScroll();*/
 }
 
 void KHTMLPart::handleMousePressEventTripleClick(khtml::MouseDoubleClickEvent *event)
 {
-    QMouseEvent *mouse = event->qmouseEvent();
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    /*QMouseEvent *mouse = event->qmouseEvent();
     DOM::Node innerNode = event->innerNode();
 
     Selection selection;
@@ -6026,48 +6109,65 @@ void KHTMLPart::handleMousePressEventTripleClick(khtml::MouseDoubleClickEvent *e
         d->editor_context.beginSelectingText(Selection::LINE);
     }
 
-    setCaret(selection);
+    setCaret(selection);*/
     startAutoScroll();
 }
 
 void KHTMLPart::handleMousePressEventSingleClick(khtml::MousePressEvent *event)
 {
     QMouseEvent *mouse = event->qmouseEvent();
-    DOM::Node innerNode = event->innerNode();
-
-    if (mouse->button() == Qt::LeftButton) {
-        Selection sel;
 
-        if (!innerNode.isNull() && innerNode.handle()->renderer() &&
-            innerNode.handle()->renderer()->shouldSelect()) {
-            bool extendSelection = mouse->modifiers() & Qt::ShiftModifier;
+    if (mouse->button() != Qt::LeftButton)
+        return;// false;
 
-            // Don't restart the selection when the mouse is pressed on an
-            // existing selection so we can allow for text dragging.
-            if (!extendSelection && isPointInsideSelection(event->x(), event->y())) {
-                return;
-            }
-            Position pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()));
-            if (pos.isEmpty())
-                pos = Position(innerNode.handle(), innerNode.handle()->caretMinOffset());
-
-            sel = caret();
-            if (extendSelection && sel.notEmpty()) {
-                sel.clearModifyBias();
-                sel.setExtent(pos);
-                if (d->editor_context.m_selectionGranularity != Selection::CHARACTER) {
-                    sel.expandUsingGranularity(d->editor_context.m_selectionGranularity);
-                }
-                d->editor_context.m_beganSelectingText = true;
-            } else {
-                sel = pos;
-                d->editor_context.m_selectionGranularity = Selection::CHARACTER;
-            }
-        }
+    DOM::Node innerNode = event->innerNode();
+    if (!(!innerNode.isNull() && innerNode.handle()->renderer() && innerNode.handle()->renderer()->shouldSelect()/* && m_mouseDownMayStartSelect*/))
+        return;// false;
+
+    // Extend the selection if the Shift key is down, unless the click is in a link.
+    bool extendSelection = (mouse->modifiers() & Qt::ShiftModifier);//FIXME khtml && !event.isOverLink();
+
+    // Don't restart the selection when the mouse is pressed on an
+    // existing selection so we can allow for text dragging.
+    /*FIXME khtml QPoint vPoint = m_frame->view()->windowToContents(event.event().pos());
+    if (!extendSelection && m_frame->selection()->contains(vPoint)) {
+        m_mouseDownWasSingleClickInSelection = true;
+        return;// false;
+    }*/
+
+    VisiblePosition visiblePos(innerNode.handle()->renderer()->positionForPoint(QPoint(event->x(), event->y())));
+    if (visiblePos.isNull())
+        visiblePos = VisiblePosition(innerNode.handle(), 0, DOWNSTREAM);
+    Position pos = visiblePos.deepEquivalent();
+
+    Selection newSelection = /*m_frame->*/selectionController()->selection();
+    if (extendSelection && newSelection.isCaretOrRange()) {
+        /*m_frame->*/selectionController()->setLastChangeWasHorizontalExtension(false);
+
+        // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
+        // was created right-to-left
+        Position start = newSelection.start();
+        Position end = newSelection.end();
+        short before = RangeImpl::compareBoundaryPoints(pos.node(), pos.offset(), start.node(), start.offset());
+        if (before <= 0)
+            newSelection = Selection(pos, end);
+        else
+            newSelection = Selection(start, pos);
 
-        setCaret(sel);
-        startAutoScroll();
+        if (/*m_frame->*/selectionGranularity() != CharacterGranularity)
+            newSelection.expandUsingGranularity(/*m_frame->*/(TextGranularity)selectionGranularity());
+        d->editor_context.m_beganSelectingText = true;
+    } else {
+        newSelection = Selection(visiblePos);
+        /*m_frame->*/setSelectionGranularity(CharacterGranularity);
     }
+    
+    if (/*m_frame->*/shouldChangeSelection(newSelection))
+        /*m_frame->*/selectionController()->setSelection(newSelection);
+
+    startAutoScroll();
+    
+    return;// true;
 }
 
 void KHTMLPart::khtmlMousePressEvent( khtml::MousePressEvent *event )
@@ -6150,30 +6250,36 @@ bool KHTMLPart::isExtendingSelection() const
 
 void KHTMLPart::extendSelectionTo(int x, int y, const DOM::Node &innerNode)
 {
-    // handle making selection
-    Position pos(innerNode.handle()->positionForCoordinates(x, y));
+    // mostly get from WebCore::EventHandler.updateSelectionForMouseDrag
+    if (!innerNode.handle())
+        return;
+
+    RenderObject* targetRenderer = innerNode.handle()->renderer();
+    if (!targetRenderer)
+        return;
+
+    VisiblePosition targetPosition(targetRenderer->positionForCoordinates(x, y));
 
     // Don't modify the selection if we're not on a node.
-    if (pos.isEmpty())
+    if (targetPosition.isNull())
         return;
 
-    // Restart the selection if this is the first mouse move. This work is usually
-    // done in khtmlMousePressEvent, but not if the mouse press was on an existing selection.
-    Selection sel = caret();
-    sel.clearModifyBias();
+    Selection newSelection = selectionController()->selection();
+
     if (!d->editor_context.m_beganSelectingText) {
-        // We are beginning a selection during press-drag, when the original click
-        // wasn't appropriate for one. Make sure to set the granularity.
-        d->editor_context.beginSelectingText(Selection::CHARACTER);
-        sel.moveTo(pos);
+        d->editor_context.m_beganSelectingText = true;
+        newSelection = Selection(targetPosition);
     }
 
-    sel.setExtent(pos);
-    if (d->editor_context.m_selectionGranularity != Selection::CHARACTER) {
-        sel.expandUsingGranularity(d->editor_context.m_selectionGranularity);
-    }
-    setCaret(sel);
+    newSelection.setExtent(targetPosition);
+
+    if (selectionGranularity() != CharacterGranularity)
+        newSelection.expandUsingGranularity((TextGranularity)selectionGranularity());
 
+    if (shouldChangeSelection(newSelection)) {
+        selectionController()->setLastChangeWasHorizontalExtension(false);
+        selectionController()->setSelection(newSelection);
+    }
 }
 #endif // KHTML_NO_SELECTION
 
@@ -6375,7 +6481,7 @@ void KHTMLPart::khtmlMouseReleaseEvent( khtml::MouseReleaseEvent *event )
 #ifndef KHTML_NO_SELECTION
   {
 
-    // Clear the selection if the mouse didn't move after the last mouse press.
+/*FIXME khtml port    // Clear the selection if the mouse didn't move after the last mouse press.
     // We do this so when clicking on the selection, the selection goes away.
     // However, if we are editing, place the caret.
     if (!d->editor_context.m_beganSelectingText
@@ -6388,7 +6494,7 @@ void KHTMLPart::khtmlMouseReleaseEvent( khtml::MouseReleaseEvent *event )
 #endif
         selection.moveTo(d->editor_context.m_selection.base().node()->positionForCoordinates(event->x(), event->y()));
       setCaret(selection);
-    }
+    }*/
     // get selected text and paste to the clipboard
 #ifndef QT_NO_CLIPBOARD
     QString text = selectedText();
@@ -6588,6 +6694,55 @@ void KHTMLPart::selectAll()
   emitSelectionChanged();
 }
 
+/*TextGranularity*/int KHTMLPart::selectionGranularity() const
+{
+    return d->editor_context.m_selectionGranularity;
+}
+
+void KHTMLPart::setSelectionGranularity(/*TextGranularity*/int granularity) const
+{
+    d->editor_context.m_selectionGranularity = (TextGranularity)granularity;
+}
+
+void KHTMLPart::setSelectionFromNone()
+{
+    // Put a caret inside the body if the entire frame is editable (either the
+    // entire WebView is editable or designMode is on for this document).
+    DocumentImpl *doc = xmlDocImpl();
+    if (!doc || !d->editor_context.m_selection.isNone() || !isEditable())
+        return;
+        
+    NodeImpl* node = doc->documentElement();
+    while (node && !node->hasTagName(/*bodyTag*/ID_BODY))
+        node = node->traverseNextNode();
+    if (node)
+        d->editor_context.m_selection.setSelection(Selection(Position(node, 0), DOWNSTREAM));
+}
+
+
+bool KHTMLPart::shouldChangeSelection(const Selection& newSelection) const
+{
+    return shouldChangeSelection(d->editor_context.m_selection.selection(), newSelection, newSelection.affinity(), false);
+}
+
+bool KHTMLPart::shouldChangeSelection(const Selection& oldSelection, const Selection& newSelection, /*EAffinity*/int affinity, bool stillSelecting) const
+{
+    return true;
+    /*FIXME khtml port return editor()->client()->shouldChangeSelectedRange(oldSelection.toRange().get(), newSelection.toRange().get(),
+                                                         affinity, stillSelecting);*/
+}
+
+void KHTMLPart::notifyRendererOfSelectionChange(bool userTriggered)
+{
+    /*FIXME khtml RenderObject* renderer = 0;
+    if (selection()->rootEditableElement())
+        renderer = selection()->rootEditableElement()->shadowAncestorNode()->renderer();
+
+    // If the current selection is in a textfield or textarea, notify the renderer that the selection has changed
+    if (renderer && (renderer->isTextArea() || renderer->isTextField()))
+        static_cast<RenderTextControl*>(renderer)->selectionChanged(userTriggered);*/
+}
+
 bool KHTMLPart::checkLinkSecurity(const KUrl &linkURL,const KLocalizedString &message, const QString &button)
 {
   bool linkAllowed = true;
@@ -6804,9 +6959,10 @@ KEncodingDetector *KHTMLPart::createDecoder()
 
 void KHTMLPart::emitCaretPositionChanged(const DOM::Position &pos) {
   // pos must not be already converted to range-compliant coordinates
-  Position rng_pos = pos.equivalentRangeCompliantPosition();
+  kDebug() << "NOT IMPLEMENTED" << endl;
+  /*Position rng_pos = pos.equivalentRangeCompliantPosition();
   Node node = rng_pos.node();
-  emit caretPositionChanged(node, rng_pos.offset());
+  emit caretPositionChanged(node, rng_pos.offset());*/
 }
 
 void KHTMLPart::restoreScrollPosition()
diff --git a/khtml/khtml_part.h b/khtml/khtml_part.h
index 1464f4b..83f5a1e 100644
--- a/khtml/khtml_part.h
+++ b/khtml/khtml_part.h
@@ -70,6 +70,7 @@ namespace DOM
   class HTMLObjectBaseElementImpl;
   class Position;
   class Selection;
+  class SelectionController;
   class Range;
   class Editor;
 }
@@ -104,6 +105,7 @@ namespace khtml
   struct EditorContext;
   class EditCommandImpl;
   class KHTMLPartAccessor;
+  class RenderCanvas;
 }
 
 namespace KJS {
@@ -231,6 +233,7 @@ class KHTML_EXPORT KHTMLPart : public KParts::ReadOnlyPart
   friend class DOM::DocumentImpl;
   friend class DOM::HTMLDocumentImpl;
   friend class DOM::Selection;
+  friend class DOM::SelectionController;
   friend class DOM::Editor;
   friend class KHTMLPartBrowserHostExtension;
   friend class khtml::HTMLTokenizer;
@@ -1118,6 +1121,19 @@ public:
    */
   bool inProgress() const;
 
+  // new editing stuff from WebCore
+  // taken from page/Frame
+  /*DOM::TextGranularity*/int selectionGranularity() const;
+  void setSelectionGranularity(/*DOM::TextGranularity*/int) const;
+
+  void setSelectionFromNone();
+
+  bool shouldChangeSelection(const DOM::Selection&) const;
+  bool shouldChangeSelection(const DOM::Selection& oldSelection, const DOM::Selection& newSelection, /*DOM::EAffinity*/int, bool stillSelecting) const;
+  // KHTML port bool shouldDeleteSelection(const DOM::Selection&) const;
+
+  void notifyRendererOfSelectionChange(bool userTriggered);
+
 Q_SIGNALS:
   /**
    * Emitted if the cursor is moved over an URL.
@@ -1640,11 +1656,16 @@ private:
   enum StatusBarPriority { BarDefaultText, BarHoverText, BarOverrideText };
   void setStatusBarText( const QString& text, StatusBarPriority p);
 
+  khtml::RenderCanvas* contentRenderer() const;
+
   bool restoreURL( const KUrl &url );
+  DOM::SelectionController* selectionController() const;
   void clearCaretRectIfNeeded();
-  void setFocusNodeIfNeeded(const DOM::Selection &);
+  void setFocusedNodeIfNeeded();
   void selectionLayoutChanged();
   void notifySelectionChanged(bool closeTyping=true);
+  void caretBlinkTimerFired();
+
   void resetFromScript();
   void emitSelectionChanged();
   void onFirstData();
@@ -1833,12 +1854,12 @@ private:
   /**
    * Paints the caret.
    */
-  void paintCaret(QPainter *p, const QRect &rect) const;
+  void paintCaret(QPainter *p, int tx, int ty, const QRect &clipRect) const;
 
   /**
    * Paints the drag caret.
    */
-  void paintDragCaret(QPainter *p, const QRect &rect) const;
+  void paintDragCaret(QPainter *p, int tx, int ty, const QRect &clipRect) const;
 
   /**
    * Returns selectedText without any leading or trailing whitespace,
diff --git a/khtml/khtmlpart_p.h b/khtml/khtmlpart_p.h
index 6a4b884..429c198 100644
--- a/khtml/khtmlpart_p.h
+++ b/khtml/khtmlpart_p.h
@@ -145,7 +145,7 @@ class KHTMLPartPrivate
   KHTMLPartPrivate& operator=(const KHTMLPartPrivate&);
 public:
   KHTMLPartPrivate(KHTMLPart* part, QObject* parent) :
-    m_find( part )
+    editor_context(part), m_find( part )
   {
     q     = part;
     m_doc = 0L;
diff --git a/khtml/khtmlview.cpp b/khtml/khtmlview.cpp
index 88e2e52..9543426 100644
--- a/khtml/khtmlview.cpp
+++ b/khtml/khtmlview.cpp
@@ -1412,7 +1412,7 @@ void KHTMLView::mouseMoveEvent( QMouseEvent * _mouse )
     LinkCursor linkCursor = LINK_NORMAL;
     switch ( style ? style->cursor() : CURSOR_AUTO) {
     case CURSOR_AUTO:
-        if ( r && r->isText() && !r->isPointInsideSelection(xm, ym, m_part->caret()) )
+        //FIXME khtml port if ( r && r->isText() && !r->isPointInsideSelection(xm, ym, m_part->caret()) )
             c = QCursor(Qt::IBeamCursor);
         if ( mev.url.length() && m_part->settings()->changeCursor() ) {
             c = m_part->urlCursor();
@@ -4411,10 +4411,10 @@ void KHTMLView::slotMouseScrollTimer()
 }
 
 
-static DOM::Position positionOfLineBoundary(const DOM::Position &pos, bool toEnd)
+/*static DOM::Position positionOfLineBoundary(const DOM::Position &pos, bool toEnd)
 {
     Selection sel = pos;
-    sel.expandUsingGranularity(Selection::LINE);
+    sel.expandUsingGranularity(DOM::LINE);
     return toEnd ? sel.end() : sel.start();
 }
 
@@ -4426,15 +4426,11 @@ inline static DOM::Position positionOfLineBegin(const DOM::Position &pos)
 inline static DOM::Position positionOfLineEnd(const DOM::Position &pos)
 {
     return positionOfLineBoundary(pos, true);
-}
+}*/
 
 bool KHTMLView::caretKeyPressEvent(QKeyEvent *_ke)
 {
-  EditorContext *ec = &m_part->d->editor_context;
-  Selection &caret = ec->m_selection;
-  Position old_pos = caret.caretPos();
-  Position pos = old_pos;
-  bool recalcXPos = true;
+  SelectionController* controller = m_part->selectionController();
   bool handled = true;
 
   bool ctrl = _ke->modifiers() & Qt::ControlModifier;
@@ -4444,21 +4440,23 @@ bool KHTMLView::caretKeyPressEvent(QKeyEvent *_ke)
 
     // -- Navigational keys
     case Qt::Key_Down:
-      pos = old_pos.nextLinePosition(caret.xPosForVerticalArrowNavigation(Selection::EXTENT));
-      recalcXPos = false;
+        controller->modify((shift) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::FORWARD, LineGranularity, true);
+        handled = true;
       break;
 
     case Qt::Key_Up:
-      pos = old_pos.previousLinePosition(caret.xPosForVerticalArrowNavigation(Selection::EXTENT));
-      recalcXPos = false;
+        controller->modify((shift) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::BACKWARD, LineGranularity, true);
+        handled = true;
       break;
 
     case Qt::Key_Left:
-      pos = ctrl ? old_pos.previousWordPosition() : old_pos.previousCharacterPosition();
+        controller->modify((shift) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::LEFT, CharacterGranularity, true);
+        handled = true;
       break;
 
     case Qt::Key_Right:
-      pos = ctrl ? old_pos.nextWordPosition() : old_pos.nextCharacterPosition();
+        controller->modify((shift) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::RIGHT, CharacterGranularity, true);
+        handled = true;
       break;
 
     case Qt::Key_PageDown:
@@ -4473,14 +4471,14 @@ bool KHTMLView::caretKeyPressEvent(QKeyEvent *_ke)
       if (ctrl)
         /*moveCaretToDocumentBoundary(false)*/; // ###
       else
-        pos = positionOfLineBegin(old_pos);
+        //pos = positionOfLineBegin(old_pos);
       break;
 
     case Qt::Key_End:
       if (ctrl)
         /*moveCaretToDocumentBoundary(true)*/; // ###
       else
-        pos = positionOfLineEnd(old_pos);
+        //pos = positionOfLineEnd(old_pos);
       break;
 
     default:
@@ -4488,24 +4486,6 @@ bool KHTMLView::caretKeyPressEvent(QKeyEvent *_ke)
 
   }/*end switch*/
 
-  if (pos != old_pos) {
-    m_part->clearCaretRectIfNeeded();
-
-    caret.moveTo(shift ? caret.nonCaretPos() : pos, pos);
-    int old_x = caret.xPosForVerticalArrowNavigation(Selection::CARETPOS);
-
-    m_part->selectionLayoutChanged();
-
-    // restore old x-position to prevent recalculation
-    if (!recalcXPos)
-      m_part->d->editor_context.m_xPosForVerticalArrowNavigation = old_x;
-
-    m_part->emitCaretPositionChanged(pos);
-    // ### check when to emit it
-    m_part->notifySelectionChanged();
-
-  }
-
   if (handled) _ke->accept();
   return handled;
 }
diff --git a/khtml/misc/helper.cpp b/khtml/misc/helper.cpp
index c1b408d..1b7401c 100644
--- a/khtml/misc/helper.cpp
+++ b/khtml/misc/helper.cpp
@@ -45,7 +45,7 @@ void setPrintPainter( QPainter *printer )
     printpainter = printer;
 }
 
-void findWordBoundary(QChar *chars, int len, int position, int *start, int *end)
+void findWordBoundary(const QChar *chars, int len, int position, int *start, int *end)
 {
     if (chars[position].isSpace()) {
         int pos = position;
@@ -77,6 +77,42 @@ void findWordBoundary(QChar *chars, int len, int position, int *start, int *end)
     }
 }
 
+int findNextWordFromIndex(const QChar* chars, int len, int position, bool forward)
+{
+    int dir = forward ? 1 : -1;
+    int i;
+    for (i = position; i < len && i >= 0; i += dir)
+        if (chars[i].isLetterOrNumber()) return i;
+    return i;
+    /*FIXME khtml port UBreakIterator* it = wordBreakIterator(chars, len);
+
+    if (forward) {
+        position = ubrk_following(it, position);
+        while (position != UBRK_DONE) {
+            // We stop searching when the character preceeding the break
+            // is alphanumeric.
+            if (position < len && u_isalnum(chars[position - 1]))
+                return position;
+
+            position = ubrk_following(it, position);
+        }
+
+        return len;
+    } else {
+        position = ubrk_preceding(it, position);
+        while (position != UBRK_DONE) {
+            // We stop searching when the character following the break
+            // is alphanumeric.
+            if (position > 0 && u_isalnum(chars[position]))
+                return position;
+
+            position = ubrk_preceding(it, position);
+        }
+
+        return 0;
+    }*/
+}
+
 }
 
 // color mapping code
diff --git a/khtml/misc/helper.h b/khtml/misc/helper.h
index a698805..dbf5abb 100644
--- a/khtml/misc/helper.h
+++ b/khtml/misc/helper.h
@@ -43,7 +43,8 @@ namespace khtml
     QRgb qRgbaFromHsla(double h, double s, double l, double a);
     QColor colorForCSSValue( int css_value );
 
-    void findWordBoundary(QChar *chars, int len, int position, int *start, int *end);
+    void findWordBoundary(const QChar *chars, int len, int position, int *start, int *end);
+    int findNextWordFromIndex(const QChar*, int len, int position, bool forward);
 
     //enumerator for findSelectionNode
     enum FindSelectionResult { SelectionPointBefore,
diff --git a/khtml/rendering/render_block.cpp b/khtml/rendering/render_block.cpp
index a373ea6..cbba0eb 100644
--- a/khtml/rendering/render_block.cpp
+++ b/khtml/rendering/render_block.cpp
@@ -42,8 +42,9 @@
 
 #include <xml/dom_nodeimpl.h>
 #include <xml/dom_docimpl.h>
-#include <xml/dom_position.h>
-#include <xml/dom_selection.h>
+#include <xml/Position.h>
+#include <xml/Selection.h>
+#include "xml/SelectionController.h"
 #include <html/html_formimpl.h>
 #include <misc/htmltags.h>
 
@@ -54,6 +55,10 @@ using namespace DOM;
 
 namespace khtml {
 
+// Number of pixels to allow as a fudge factor when clicking above or below a line.
+// clicking up to verticalLineClickFudgeFactor pixels above a line will correspond to the closest point on the line.  
+const int verticalLineClickFudgeFactor= 3;
+
 // -------------------------------------------------------------------------------------------------------
 
 // Our MarginInfo state used when laying out block children.
@@ -1756,8 +1761,10 @@ void RenderBlock::paintObject(PaintInfo& pI, int _tx, int _ty, bool shouldPaintO
         NodeImpl *baseNode = s.extent().node();
         RenderObject *renderer = baseNode ? baseNode->renderer() : 0;
         if (renderer && renderer->containingBlock() == this && (part->isCaretMode() || baseNode->isContentEditable())) {
-            part->paintCaret(pI.p, pI.r);
-            part->paintDragCaret(pI.p, pI.r);
+            paintCaret(pI, _tx, _ty, CursorCaret);
+            paintCaret(pI, _tx, _ty, DragCaret);
+            //part->paintCaret(pI.p, pI.r);
+            //part->paintDragCaret(pI.p, pI.r);
         }
     }
 
@@ -1773,6 +1780,30 @@ void RenderBlock::paintObject(PaintInfo& pI, int _tx, int _ty, bool shouldPaintO
 #endif
 }
 
+void RenderBlock::paintCaret(PaintInfo& paintInfo, int tx, int ty, CaretType type)
+{
+    //kDebug() << "paint caret:" << tx << ty << type << endl;
+    SelectionController* selection = type == CursorCaret ? document()->part()->selectionController() : 0;//FIXME khtml document()->part()->dragCaretController();
+
+    if (type != CursorCaret) return; // FIXME add support for drag caret
+
+    // Ask the SelectionController if the caret should be painted by this block
+    RenderObject* caretPainter = selection->caretRenderer();
+    //kDebug() << "caret renderer:" << (caretPainter == this) << endl;
+    //kDebug() << "editable or caret mode:" << (selection->isContentEditable() || document()->part()->isCaretMode()) << endl;
+    //paintInfo.p->fillRect(tx, ty, width(), height(), Qt::green);
+    if (caretPainter == this && (selection->isContentEditable() || document()->part()->isCaretMode())) {
+        // Convert the painting offset into the local coordinate system of this renderer,
+        // to match the localCaretRect computed by the SelectionController
+        offsetForContents(tx, ty);
+
+        if (type == CursorCaret)
+            document()->part()->paintCaret(paintInfo.p, tx, ty, paintInfo.r);
+        else
+            document()->part()->paintDragCaret(paintInfo.p, tx, ty, paintInfo.r);
+    }
+}
+
 void RenderBlock::paintFloats(PaintInfo& pI, int _tx, int _ty, bool paintSelection)
 {
     if (!m_floatingObjects)
@@ -2697,85 +2728,141 @@ Position RenderBlock::positionForRenderer(RenderObject *renderer, bool start) co
     if (!node)
         return Position();
 
-    long offset = start ? node->caretMinOffset() : node->caretMaxOffset();
+    ASSERT(renderer == node->renderer());
+
+    int offset = start ? renderer->caretMinOffset() : renderer->caretMaxOffset();
+
     return Position(node, offset);
 }
 
-Position RenderBlock::positionForCoordinates(int _x, int _y)
+VisiblePosition RenderBlock::positionForCoordinates(int x, int y)
 {
     if (isTable())
-        return RenderFlow::positionForCoordinates(_x, _y);
-
-    int absx, absy;
-    absolutePosition(absx, absy);
-
-    int top = absy + borderTop() + paddingTop();
-    int bottom = top + contentHeight();
-
-    if (_y < top)
-        // y coordinate is above block
-        return positionForRenderer(firstLeafChild(), true);
+        return RenderFlow::positionForCoordinates(x, y);
+
+    int top = borderTop();
+    int bottom = top + borderTopExtra() + paddingTop() + contentHeight() + paddingBottom() + borderBottomExtra();
+
+    int left = borderLeft();
+    int right = left + paddingLeft() + contentWidth() + paddingRight();
+
+    NodeImpl* n = element();
+    
+    int contentsX = x;
+    int contentsY = y;
+    offsetForContents(contentsX, contentsY);
+
+    if (isReplaced()) {
+        if (y < 0 || y < height() && x < 0)
+            return VisiblePosition(n, caretMinOffset(), DOWNSTREAM);
+        if (y >= height() || y >= 0 && x >= width())
+            return VisiblePosition(n, caretMaxOffset(), DOWNSTREAM);
+    }
+
+    // If we start inside the shadow tree, we will stay inside (even if the point is above or below).
+    if (!(n && n->isShadowNode()) && !childrenInline()) {
+        // Don't return positions inside editable roots for coordinates outside those roots, except for coordinates outside
+        // a document that is entirely editable.
+        bool isEditableRoot = n && n->rootEditableElement() == n && n->id() != ID_BODY && n->id() != ID_HTML/*!n->hasTagName(bodyTag) && !n->hasTagName(htmlTag)*/;
+
+        if (y < top || (isEditableRoot && (y < bottom && x < left))) {
+            if (!isEditableRoot)
+                if (RenderObject* c = firstChild()) { // FIXME: This code doesn't make any sense.  This child could be an inline or a positioned element or a float or a compact, etc.
+                    VisiblePosition p = c->positionForCoordinates(contentsX - c->xPos(), contentsY - c->yPos());
+                    if (p.isNotNull())
+                        return p;
+                }
+            if (n) {
+                if (NodeImpl* sp = n->shadowParentNode())
+                    n = sp;
+                if (NodeImpl* p = n->parent())
+                    return VisiblePosition(p, n->nodeIndex(), DOWNSTREAM);
+            }
+            return VisiblePosition(n, 0, DOWNSTREAM);
+        }
 
-    if (_y >= bottom)
-        // y coordinate is below block
-        return positionForRenderer(lastLeafChild(), false);
+        if (y >= bottom || (isEditableRoot && (y >= top && x >= right))) {
+            if (!isEditableRoot)
+                if (RenderObject* c = lastChild()) { // FIXME: This code doesn't make any sense.  This child could be an inline or a positioned element or a float or a compact, ect.
+                    VisiblePosition p = c->positionForCoordinates(contentsX - c->xPos(), contentsY - c->yPos());
+                    if (p.isNotNull())
+                        return p;
+                }
+            if (n) {
+                if (NodeImpl* sp = n->shadowParentNode())
+                    n = sp;
+                if (NodeImpl* p = n->parent())
+                    return VisiblePosition(p, n->nodeIndex() + 1, DOWNSTREAM);
+            }
+            return VisiblePosition(n, 0, DOWNSTREAM);
+        }
+    }
 
     if (childrenInline()) {
         if (!firstRootBox())
-            return Position(element(), 0);
+            return VisiblePosition(n, 0, DOWNSTREAM);
 
-        if (_y >= top && _y < absy + firstRootBox()->topOverflow())
+        if (contentsY < firstRootBox()->topOverflow() - verticalLineClickFudgeFactor)
             // y coordinate is above first root line box
-            return positionForBox(firstRootBox()->firstLeafChild(), true);
-
+            return VisiblePosition(positionForBox(firstRootBox()->firstLeafChild(), true), DOWNSTREAM);
+        
         // look for the closest line box in the root box which is at the passed-in y coordinate
-        for (RootInlineBox *root = firstRootBox(); root; root = root->nextRootBox()) {
-            top = absy + root->topOverflow();
+        for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
             // set the bottom based on whether there is a next root box
             if (root->nextRootBox())
-                bottom = absy + root->nextRootBox()->topOverflow();
+                // FIXME: make the break point halfway between the bottom of the previous root box and the top of the next root box
+                bottom = root->nextRootBox()->topOverflow();
             else
-                bottom = absy + root->bottomOverflow();
+                bottom = root->bottomOverflow() + verticalLineClickFudgeFactor;
             // check if this root line box is located at this y coordinate
-            if (_y >= top && _y < bottom && root->firstChild()) {
-                InlineBox *closestBox = root->closestLeafChildForXPos(_x, absx);
-                if (closestBox) {
+            if (contentsY < bottom && root->firstChild()) {
+                InlineBox* closestBox = root->closestLeafChildForXPos(x);
+                if (closestBox)
                     // pass the box a y position that is inside it
-                    return closestBox->object()->positionForCoordinates(_x, absy + closestBox->m_y);
-                }
+                    return closestBox->object()->positionForCoordinates(contentsX, closestBox->m_y);
             }
         }
 
         if (lastRootBox())
             // y coordinate is below last root line box
-            return positionForBox(lastRootBox()->lastLeafChild(), false);
+            return VisiblePosition(positionForBox(lastRootBox()->lastLeafChild(), false), DOWNSTREAM);
 
-        return Position(element(), 0);
+        return VisiblePosition(n, 0, DOWNSTREAM);
     }
-
-    // see if any child blocks exist at this y coordinate
-    for (RenderObject *renderer = firstChild(); renderer; renderer = renderer->nextSibling()) {
-        if (renderer->isFloatingOrPositioned())
+    
+    // See if any child blocks exist at this y coordinate.
+    if (firstChild() && contentsY < firstChild()->yPos())
+        return VisiblePosition(n, 0, DOWNSTREAM);
+    for (RenderObject* renderer = firstChild(); renderer; renderer = renderer->nextSibling()) {
+        if (renderer->height() == 0 || renderer->style()->visibility() != VISIBLE || renderer->isFloatingOrPositioned())
             continue;
-        renderer->absolutePosition(absx, top);
-        RenderObject *next = renderer->nextSibling();
+        RenderObject* next = renderer->nextSibling();
         while (next && next->isFloatingOrPositioned())
             next = next->nextSibling();
-        if (next)
-            next->absolutePosition(absx, bottom);
+        if (next)
+            bottom = next->yPos();
         else
-            bottom = top + contentHeight();
-        if (_y >= top && _y < bottom) {
-            return renderer->positionForCoordinates(_x, _y);
-        }
+            bottom = top + scrollHeight();
+        if (contentsY >= renderer->yPos() && contentsY < bottom)
+            return renderer->positionForCoordinates(contentsX - renderer->xPos(), contentsY - renderer->yPos());
     }
+    
+    return RenderFlow::positionForCoordinates(x, y);
+}
 
-    // pass along to the first child
-    if (firstChild())
-        return firstChild()->positionForCoordinates(_x, _y);
+void RenderBlock::offsetForContents(int& tx, int& ty) const
+{
+    ty -= borderTopExtra();
+    
+    if (hasOverflowClip())
+        m_layer->scrollOffset(tx, ty);
 
-    // still no luck...return this render object's element and offset 0
-    return Position(element(), 0);
+    /*FIXME khtml port if (m_hasColumns) {
+        QPoint contentsPoint(tx, ty);
+        adjustPointToColumnContents(contentsPoint);
+        tx = contentsPoint.x();
+        ty = contentsPoint.y();
+    }*/
 }
 
 void RenderBlock::calcMinMaxWidth()
diff --git a/khtml/rendering/render_block.h b/khtml/rendering/render_block.h
index bdc5d48..09ce59b 100644
--- a/khtml/rendering/render_block.h
+++ b/khtml/rendering/render_block.h
@@ -36,6 +36,8 @@ namespace DOM {
 
 namespace khtml {
 
+enum CaretType { CursorCaret, DragCaret };
+
 class RenderBlock : public RenderFlow
 {
 public:
@@ -139,6 +141,7 @@ public:
     virtual void paint(PaintInfo& i, int tx, int ty);
     void paintObject(PaintInfo& i, int tx, int ty, bool paintOutline = true);
     void paintFloats(PaintInfo& i, int _tx, int _ty, bool paintSelection = false);
+    void paintCaret(PaintInfo&, int tx, int ty, CaretType);
 
     void insertFloatingObject(RenderObject *o);
     void removeFloatingObject(RenderObject *o);
@@ -185,7 +188,7 @@ public:
 
     bool isPointInScrollbar(int x, int y, int tx, int ty);
 
-    virtual DOM::Position positionForCoordinates(int x, int y);
+    virtual DOM::VisiblePosition positionForCoordinates(int x, int y);
 
     virtual void calcMinMaxWidth();
     void calcInlineMinMaxWidth();
@@ -215,6 +218,9 @@ private:
     DOM::Position positionForBox(InlineBox *box, bool start=true) const;
     DOM::Position positionForRenderer(RenderObject *renderer, bool start=true) const;
 
+    // Adjust tx and ty from painting offsets to the local coords of this renderer
+    void offsetForContents(int& tx, int& ty) const;
+
 protected:
     struct FloatingObject {
         enum Type {
diff --git a/khtml/rendering/render_box.cpp b/khtml/rendering/render_box.cpp
index 47ca122..1552052 100644
--- a/khtml/rendering/render_box.cpp
+++ b/khtml/rendering/render_box.cpp
@@ -1073,6 +1073,111 @@ void RenderBox::relativePositionOffset(int &tx, int &ty) const
     }
 }
 
+// FIXME for now it's implemented via khtml RenderObject::absolutePosition() in RenderObject::localToAbsolute
+#if 0
+QPointF RenderBox::localToAbsolute(QPointF localPoint, bool fixed, bool useTransforms) const
+{
+    int x, y;
+    absolutePosition(x, y, fixed);
+    return localPoint + QPointF(x, y);
+    /* FIXME khtml WC code if (RenderView* v = view()) {
+        if (LayoutState* layoutState = v->layoutState()) {
+            IntSize offset = layoutState->m_offset;
+            offset.expand(m_x, m_y);
+            localPoint += offset;
+            if (style()->position() == RelativePosition && m_layer)
+                localPoint += m_layer->relativePositionOffset();
+            return localPoint;
+        }
+    }
+
+    if (style()->position() == FixedPosition)
+        fixed = true;
+
+    RenderObject* o = container();
+    if (o) {
+        if (useTransforms && m_layer && m_layer->transform()) {
+            fixed = false;  // Elements with transforms act as a containing block for fixed position descendants
+            localPoint = m_layer->transform()->mapPoint(localPoint);
+        }
+
+        localPoint += offsetFromContainer(o);
+
+        return o->localToAbsoluteForContent(localPoint, fixed, useTransforms);
+    }
+    
+    return FloatPoint();*/
+}
+#endif
+
+QSize RenderBox::offsetFromContainer(RenderObject* o) const
+{
+    ASSERT(o == container());
+
+    QSize offset;
+    if (isRelPositioned()) {
+        int x, y;
+        relativePositionOffset(x, y);
+        offset += QSize(x, y);
+    }
+
+    if (!isInline() || isReplaced()) {
+        //RenderBlock* cb;
+        if (o->isBlockFlow() && style()->position() != PABSOLUTE && style()->position() != PFIXED
+                /*FIXME WebCore && (cb = static_cast<RenderBlock*>(o))->hasColumns()*/) {
+            QRect rect(m_x, m_y, 1, 1);
+            //cb->adjustRectForColumns(rect);
+            offset += QSize(rect.x(), rect.y());
+        } else
+            offset += QSize(QSize(m_x, m_y));
+    }
+
+    if (o->hasOverflowClip())
+        offset -= o->layer()->scrolledContentOffset();
+
+    if (style()->position() == PABSOLUTE)
+        offset += offsetForPositionedInContainer(o);
+
+    return offset;
+}
+
+QSize RenderBox::offsetForPositionedInContainer(RenderObject* container) const
+{
+    if (!container->isRelPositioned() || !container->isInlineFlow())
+        return QSize();
+
+    // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
+    // box from the rest of the content, but only in the cases where we know we're positioned
+    // relative to the inline itself.
+
+    QSize offset;
+    RenderFlow* flow = static_cast<RenderFlow*>(container);
+    int sx;
+    int sy;
+    if (flow->firstLineBox()) {
+        sx = flow->firstLineBox()->xPos();
+        sy = flow->firstLineBox()->yPos();
+    } else {
+        sx = flow->staticX();
+        sy = flow->staticY();
+    }
+
+    if (!hasStaticX())
+        offset.setWidth(sx);
+    // This is not terribly intuitive, but we have to match other browsers.  Despite being a block display type inside
+    // an inline, we still keep our x locked to the left of the relative positioned inline.  Arguably the correct
+    // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
+    // do.
+    else if (!style()->isOriginalDisplayInlineType())
+        // Avoid adding in the left border/padding of the containing block twice.  Subtract it out.
+        offset.setWidth(sx - (containingBlock()->borderLeft() + containingBlock()->paddingLeft()));
+
+    if (!hasStaticY())
+        offset.setHeight(sy);
+
+    return offset;
+}
+
 void RenderBox::calcWidth()
 {
 #ifdef DEBUG_LAYOUT
@@ -2562,6 +2667,62 @@ bool RenderBox::handleEvent(const DOM::EventImpl& e)
     return RenderContainer::handleEvent(e);
 }
 
+QRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, int* extraWidthToEndOfLine)
+{
+    // VisiblePositions at offsets inside containers either a) refer to the positions before/after
+    // those containers (tables and select elements) or b) refer to the position inside an empty block.
+    // They never refer to children.
+    // FIXME: Paint the carets inside empty blocks differently than the carets before/after elements.
+
+    // FIXME: What about border and padding?
+    const int caretWidth = 1;
+    QRect rect(xPos(), yPos(), caretWidth, m_height);
+    TextDirection direction = box ? box->direction() : style()->direction();
+
+    kDebug() << "Initial rect:" << rect << endl;
+
+    if ((!caretOffset) ^ (direction == LTR))
+        rect.translate(m_width - caretWidth, 0);
+
+    kDebug() << "After translate:" << rect << endl;
+
+    if (box) {
+        kDebug() << "Box is not null" << endl;
+        RootInlineBox* rootBox = box->root();
+        int top = rootBox->topOverflow();
+        rect.setY(top);
+        rect.setHeight(rootBox->bottomOverflow() - top);
+        kDebug() << "rect updated" << rect << endl;
+    }
+
+    // If height of box is smaller than font height, use the latter one,
+    // otherwise the caret might become invisible.
+    //
+    // Also, if the box is not a replaced element, always use the font height.
+    // This prevents the "big caret" bug described in:
+    // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
+    //
+    // FIXME: ignoring :first-line, missing good reason to take care of
+    //int fontHeight = style()->font().height();
+    const QFontMetrics &fm = style()->fontMetrics();
+    int fontHeight = fm.height();
+
+    kDebug() << "font height:" << fontHeight << endl;
+
+    if (fontHeight > rect.height() || !isReplaced() && !isTable())
+        rect.setHeight(fontHeight);
+
+    if (extraWidthToEndOfLine)
+        *extraWidthToEndOfLine = xPos() + m_width - rect.right();
+
+    kDebug() << "rect absolute:" << rect << endl;
+
+    // Move to local coords
+    rect.translate(-xPos(), -yPos());
+    kDebug() << "rect local:" << rect << endl;
+    return rect;
+}
+
 void RenderBox::caretPos(int /*offset*/, int flags, int &_x, int &_y, int &width, int &height) const
 {
 #if 0
diff --git a/khtml/rendering/render_box.h b/khtml/rendering/render_box.h
index f4461bc..97de39d 100644
--- a/khtml/rendering/render_box.h
+++ b/khtml/rendering/render_box.h
@@ -99,6 +99,13 @@ public:
     virtual short containingBlockWidth(RenderObject* providedCB=0) const;
     void relativePositionOffset(int &tx, int &ty) const;
 
+    //virtual QPointF localToAbsolute(QPointF localPoint = QPointF(), bool fixed = false, bool useTransforms = false) const;
+    //virtual FloatPoint absoluteToLocal(FloatPoint containerPoint, bool fixed = false, bool useTransforms = false) const;
+    //virtual FloatQuad localToAbsoluteQuad(const FloatQuad&, bool fixed = false) const;
+
+    virtual QSize offsetFromContainer(RenderObject*) const;
+    QSize offsetForPositionedInContainer(RenderObject*) const;
+
     virtual void calcWidth();
     virtual void calcHeight();
 
@@ -117,6 +124,7 @@ public:
     int staticX() const { return m_staticX; }
     int staticY() const { return m_staticY; }
 
+    virtual QRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
     virtual void caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height) const;
 
     void calcHorizontalMargins(const Length& ml, const Length& mr, int cw);
diff --git a/khtml/rendering/render_br.cpp b/khtml/rendering/render_br.cpp
index 57e062c..e79c317 100644
--- a/khtml/rendering/render_br.cpp
+++ b/khtml/rendering/render_br.cpp
@@ -21,10 +21,7 @@
  */
 #include "render_br.h"
 
-#include "xml/dom_position.h"
-
 using namespace khtml;
-using DOM::Position;
 
 RenderBR::RenderBR(DOM::NodeImpl* node)
     : RenderText(node, new DOM::DOMStringImpl(QChar('\n')))
@@ -51,9 +48,9 @@ unsigned long RenderBR::caretMaxRenderedOffset() const
     return 1;
 }
 
-Position RenderBR::positionForCoordinates(int _x, int _y)
+DOM::VisiblePosition RenderBR::positionForCoordinates(int /*x*/, int /*y*/)
 {
-    return Position(element(), 0);
+    return DOM::VisiblePosition(element(), 0, DOM::DOWNSTREAM);
 }
 
 #if 0
diff --git a/khtml/rendering/render_br.h b/khtml/rendering/render_br.h
index 7f2e482..eeec315 100644
--- a/khtml/rendering/render_br.h
+++ b/khtml/rendering/render_br.h
@@ -65,7 +65,7 @@ public:
     virtual long caretMaxOffset() const;
     virtual unsigned long caretMaxRenderedOffset() const;
     
-    virtual DOM::Position positionForCoordinates(int _x, int _y);
+    virtual DOM::VisiblePosition positionForCoordinates(int _x, int _y);
 #if 0
     virtual void caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height) const;
 #endif
diff --git a/khtml/rendering/render_canvas.h b/khtml/rendering/render_canvas.h
index 620740e..544bdd7 100644
--- a/khtml/rendering/render_canvas.h
+++ b/khtml/rendering/render_canvas.h
@@ -66,6 +66,8 @@ public:
     bool needsFullRepaint() const;
     void deferredRepaint( RenderObject* o );
     void scheduleDeferredRepaints();
+    // WebCore API
+    void repaintViewRectangle(QRect r, bool asap = false) { repaintViewRectangle(r.x(), r.y(), r.width(), r.height(), asap); }
 
     virtual void paint(PaintInfo&, int tx, int ty);
     virtual void paintBoxDecorations(PaintInfo& paintInfo, int _tx, int _ty);
diff --git a/khtml/rendering/render_container.cpp b/khtml/rendering/render_container.cpp
index 87979fd..d026cbc 100644
--- a/khtml/rendering/render_container.cpp
+++ b/khtml/rendering/render_container.cpp
@@ -35,14 +35,18 @@
 #include "rendering/render_inline.h"
 #include "rendering/render_layer.h"
 #include "xml/dom_docimpl.h"
-#include "xml/dom_position.h"
 #include "css/css_valueimpl.h"
 
+#include "xml/VisiblePosition.h"
+#include "xml/Position.h"
+#include "xml/editing_helper.h"
+
 #include <kdebug.h>
 #include <assert.h>
 #include <limits.h>
 
 using DOM::Position;
+using DOM::VisiblePosition;
 using namespace khtml;
 
 RenderContainer::RenderContainer(DOM::NodeImpl* node)
@@ -651,32 +655,88 @@ void RenderContainer::removeSuperfluousAnonymousBlockChild( RenderObject* child
     child->detach();
 }
 
-Position RenderContainer::positionForCoordinates(int _x, int _y)
+VisiblePosition RenderContainer::positionForCoordinates(int x, int y)
 {
     // no children...return this render object's element, if there is one, and offset 0
-    if (!firstChild())
-        return Position(element(), 0);
-  
-    // look for the geometrically-closest child and pass off to that child
-    int min = INT_MAX;
-    RenderObject *closestRenderer = firstChild();
-    for (RenderObject *renderer = firstChild(); renderer; renderer = renderer->nextSibling()) {
-        int absx, absy;
-        renderer->absolutePosition(absx, absy);
-            
-        int top = absy + borderTop() + paddingTop();
+    if (!m_first/*Child*/)
+        return VisiblePosition(element(), 0, DOWNSTREAM);
+        
+    if (isTable() && element()) {
+        int right = contentWidth() + borderRight() + paddingRight() + borderLeft() + paddingLeft();
+        int bottom = contentHeight() + borderTop() + paddingTop() + borderBottom() + paddingBottom();
+        
+        if (x < 0 || x > right || y < 0 || y > bottom) {
+            if (x <= right / 2)
+                return VisiblePosition(Position(element(), 0));
+            else
+                return VisiblePosition(Position(element(), maxDeepOffset(element())));
+        }
+    }
+
+    // Pass off to the closest child.
+    int minDist = INT_MAX;
+    RenderObject* closestRenderer = 0;
+    int newX = x;
+    int newY = y;
+    if (isTableRow()) {
+        newX += xPos();
+        newY += yPos();
+    }
+    for (RenderObject* renderer = m_first/*Child*/; renderer; renderer = renderer->nextSibling()) {
+        if (!renderer->firstChild() && !renderer->isInline() && !renderer->isBlockFlow()
+            || renderer->style()->visibility() != VISIBLE)
+            continue;
+        
+        int top = borderTop() + paddingTop() + (isTableRow() ? 0 : renderer->yPos());
         int bottom = top + renderer->contentHeight();
-        int left = absx + borderLeft() + paddingLeft();
+        int left = borderLeft() + paddingLeft() + (isTableRow() ? 0 : renderer->xPos());
         int right = left + renderer->contentWidth();
-            
-        int cmp;
-        cmp = abs(_y - top);    if (cmp < min) { closestRenderer = renderer; min = cmp; }
-        cmp = abs(_y - bottom); if (cmp < min) { closestRenderer = renderer; min = cmp; }
-        cmp = abs(_x - left);   if (cmp < min) { closestRenderer = renderer; min = cmp; }
-        cmp = abs(_x - right);  if (cmp < min) { closestRenderer = renderer; min = cmp; }
-    }
+        
+        if (x <= right && x >= left && y <= top && y >= bottom) {
+            if (renderer->isTableRow())
+                return renderer->positionForCoordinates(x + newX - renderer->xPos(), y + newY - renderer->yPos());
+            return renderer->positionForCoordinates(x - renderer->xPos(), y - renderer->yPos());
+        }
 
-    return closestRenderer->positionForCoordinates(_x, _y);
+        // Find the distance from (x, y) to the box.  Split the space around the box into 8 pieces
+        // and use a different compare depending on which piece (x, y) is in.
+        QPoint cmp;
+        if (x > right) {
+            if (y < top)
+                cmp = QPoint(right, top);
+            else if (y > bottom)
+                cmp = QPoint(right, bottom);
+            else
+                cmp = QPoint(right, y);
+        } else if (x < left) {
+            if (y < top)
+                cmp = QPoint(left, top);
+            else if (y > bottom)
+                cmp = QPoint(left, bottom);
+            else
+                cmp = QPoint(left, y);
+        } else {
+            if (y < top)
+                cmp = QPoint(x, top);
+            else
+                cmp = QPoint(x, bottom);
+        }
+        
+        int x1minusx2 = cmp.x() - x;
+        int y1minusy2 = cmp.y() - y;
+        
+        int dist = x1minusx2 * x1minusx2 + y1minusy2 * y1minusy2;
+        if (dist < minDist) {
+            closestRenderer = renderer;
+            minDist = dist;
+        }
+    }
+    
+    if (closestRenderer)
+        return closestRenderer->positionForCoordinates(newX - closestRenderer->xPos(), newY - closestRenderer->yPos());
+    
+    return VisiblePosition(element(), 0, DOWNSTREAM);
 }
+
     
 #undef DEBUG_LAYOUT
diff --git a/khtml/rendering/render_container.h b/khtml/rendering/render_container.h
index 06f7f65..417819d 100644
--- a/khtml/rendering/render_container.h
+++ b/khtml/rendering/render_container.h
@@ -62,7 +62,7 @@ public:
 
     virtual void setStyle(RenderStyle* _style);
 
-    virtual DOM::Position positionForCoordinates(int x, int y);
+    virtual DOM::VisiblePosition positionForCoordinates(int x, int y);
 
 protected:
     // Generate CSS content
diff --git a/khtml/rendering/render_flow.cpp b/khtml/rendering/render_flow.cpp
index c872389..e3b09f9 100644
--- a/khtml/rendering/render_flow.cpp
+++ b/khtml/rendering/render_flow.cpp
@@ -577,3 +577,86 @@ int RenderFlow::highestPosition(bool includeOverflowInterior, bool includeSelf)
 
     return top;
 }
+
+QRect RenderFlow::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
+{
+    // Do the normal calculation in most cases.
+    if (firstChild() || style()->display() == INLINE)
+        return RenderContainer::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine);
+
+    // This is a special case:
+    // The element is not an inline element, and it's empty. So we have to
+    // calculate a fake position to indicate where objects are to be inserted.
+    
+    // FIXME: This does not take into account either :first-line or :first-letter
+    // However, as soon as some content is entered, the line boxes will be
+    // constructed and this kludge is not called any more. So only the caret size
+    // of an empty :first-line'd block is wrong. I think we can live with that.
+    // FIXME khtml: port firstLineStyle RenderStyle* currentStyle = firstLineStyle();
+    kDebug() << "NOT IMPLEMENTED: firstLineStyle" << endl;
+    RenderStyle* currentStyle = style();
+    int height = lineHeight(true);
+    const int caretWidth = 1;
+
+    enum CaretAlignment { alignLeft, alignRight, alignCenter };
+
+    CaretAlignment alignment = alignLeft;
+
+    switch (currentStyle->textAlign()) {
+        case TAAUTO:
+        case JUSTIFY:
+            if (currentStyle->direction() == RTL)
+                alignment = alignRight;
+            break;
+        case LEFT:
+        case KHTML_LEFT:
+            break;
+        case CENTER:
+        case KHTML_CENTER:
+            alignment = alignCenter;
+            break;
+        case RIGHT:
+        case KHTML_RIGHT:
+            alignment = alignRight;
+            break;
+    }
+
+    int x = borderLeft() + paddingLeft();
+    int w = width();
+
+    switch (alignment) {
+        case alignLeft:
+            break;
+        case alignCenter:
+            x = (x + w - (borderRight() + paddingRight())) / 2;
+            break;
+        case alignRight:
+            x = w - (borderRight() + paddingRight());
+            break;
+    }
+
+    if (extraWidthToEndOfLine) {
+        if (isRenderBlock()) {
+            *extraWidthToEndOfLine = w - (x + caretWidth);
+        } else {
+            // FIXME: This code looks wrong.
+            // myRight and containerRight are set up, but then clobbered.
+            // So *extraWidthToEndOfLine will always be 0 here.
+
+            int myRight = x + caretWidth;
+            kDebug() << "NOT IMPLEMENTED" << endl;
+            // FIXME: why call localToAbsoluteForContent() twice here, too?
+            /* FIXME khtml QPointF absRightPoint = localToAbsoluteForContent(QPointF(myRight, 0));
+
+            int containerRight = containingBlock()->xPos() + containingBlockWidth();
+            QPointF absContainerPoint = localToAbsoluteForContent(QPointF(containerRight, 0));
+
+            *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x();*/
+        }
+    }
+
+    int y = paddingTop() + borderTop();
+
+    return QRect(x, y, caretWidth, height);
+}
+
diff --git a/khtml/rendering/render_flow.h b/khtml/rendering/render_flow.h
index b4b8965..19f4567 100644
--- a/khtml/rendering/render_flow.h
+++ b/khtml/rendering/render_flow.h
@@ -85,6 +85,8 @@ public:
     virtual int rightmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const;
     virtual int leftmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const;
 
+    virtual QRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
+
 protected:
     // An inline can be split with blocks occurring in between the inline content.
     // When this occurs we need a pointer to our next object.  We can basically be
diff --git a/khtml/rendering/render_inline.cpp b/khtml/rendering/render_inline.cpp
index bc7c221..56b87c2 100644
--- a/khtml/rendering/render_inline.cpp
+++ b/khtml/rendering/render_inline.cpp
@@ -907,7 +907,7 @@ bool RenderInline::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
     return inside;
 }
 
-Position RenderInline::positionForCoordinates(int x, int y)
+DOM::VisiblePosition RenderInline::positionForCoordinates(int x, int y)
 {
     for (RenderObject *c = continuation(); c; c = c->continuation()) {
         if (c->isInline() || c->firstChild())
diff --git a/khtml/rendering/render_inline.h b/khtml/rendering/render_inline.h
index ca79180..bdfb150 100644
--- a/khtml/rendering/render_inline.h
+++ b/khtml/rendering/render_inline.h
@@ -80,7 +80,7 @@ public:
     virtual int offsetLeft() const;
     virtual int offsetTop() const;
 
-    virtual DOM::Position positionForCoordinates(int x, int y);
+    virtual DOM::VisiblePosition positionForCoordinates(int x, int y);
 
     virtual void caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height) const;
     void paintOutlines(QPainter *p, int tx, int ty);    
diff --git a/khtml/rendering/render_layer.cpp b/khtml/rendering/render_layer.cpp
index b1353a2..b2b822e 100644
--- a/khtml/rendering/render_layer.cpp
+++ b/khtml/rendering/render_layer.cpp
@@ -613,31 +613,33 @@ void RenderLayer::insertOnlyThisLayer()
 
 void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const
 {
-    if (ancestorLayer == this)
-        return;
-
-    if (m_object->style()->position() == PFIXED) {
-        // Add in the offset of the view.  We can obtain this by calling
-        // absolutePosition() on the RenderCanvas.
-        int xOff, yOff;
-        m_object->absolutePosition(xOff, yOff, true);
-        x += xOff;
-        y += yOff;
-        return;
-    }
+    const RenderLayer* layer = this;
+    while (1) {
+        if (ancestorLayer == layer) return;
+
+        if (layer->m_object->style()->position() == PFIXED) {
+            // Add in the offset of the view.  We can obtain this by calling
+            // absolutePosition() on the RenderCanvas.
+            int xOff, yOff;
+            layer->m_object->absolutePosition(xOff, yOff, true);
+            x += xOff;
+            y += yOff;
+            return;
+        }
 
-    RenderLayer* parentLayer;
-    if (m_object->style()->position() == PABSOLUTE)
-        parentLayer = enclosingPositionedAncestor();
-    else
-        parentLayer = parent();
+        RenderLayer* parentLayer;
+        if (layer->m_object->style()->position() == PABSOLUTE)
+            parentLayer = layer->enclosingPositionedAncestor();
+        else
+            parentLayer = layer->parent();
 
-    if (!parentLayer) return;
+        if (!parentLayer) return;
 
-    parentLayer->convertToLayerCoords(ancestorLayer, x, y);
+        x += layer->xPos();
+        y += layer->yPos();
 
-    x += xPos();
-    y += yPos();
+        layer = parentLayer;
+    }
 }
 
 void RenderLayer::scrollOffset(int& x, int& y)
diff --git a/khtml/rendering/render_layer.h b/khtml/rendering/render_layer.h
index 4e502c9..f8d723b 100644
--- a/khtml/rendering/render_layer.h
+++ b/khtml/rendering/render_layer.h
@@ -178,8 +178,9 @@ public:
     void scrollOffset(int& x, int& y);
     void subtractScrollOffset(int& x, int& y);
     void checkInlineRelOffset(const RenderObject* o, int& x, int& y);
-    short scrollXOffset() { return m_scrollX; }
-    int scrollYOffset() { return m_scrollY; }
+    short scrollXOffset() const { return m_scrollX; }
+    int scrollYOffset() const { return m_scrollY; }
+    QSize scrolledContentOffset() const { return QSize(scrollXOffset()/*WebCore + m_scrollLeftOverflow*/, scrollYOffset()); }
     void scrollToOffset(int x, int y, bool updateScrollbars = true, bool repaint = true);
     void scrollToXOffset(int x) { scrollToOffset(x, m_scrollY); }
     void scrollToYOffset(int y) { scrollToOffset(m_scrollX, y); }
diff --git a/khtml/rendering/render_line.cpp b/khtml/rendering/render_line.cpp
index c67bcf8..7d6563c 100644
--- a/khtml/rendering/render_line.cpp
+++ b/khtml/rendering/render_line.cpp
@@ -326,7 +326,7 @@ InlineBox* InlineBox::lastLeafChild()
     return this;
 }
 
-InlineBox* InlineBox::closestLeafChildForXPos(int _x, int _tx)
+/*FIXME to remove InlineBox* InlineBox::closestLeafChildForXPos(int _x, int _tx)
 {
     if (!isInlineFlowBox())
         return this;
@@ -340,6 +340,16 @@ InlineBox* InlineBox::closestLeafChildForXPos(int _x, int _tx)
         return this;
 
     return box->closestLeafChildForXPos(_x, _tx);
+}*/
+
+InlineBox* InlineBox::nextLeafChild()
+{
+    return parent() ? parent()->firstLeafChildAfterBox(this) : 0;
+}
+
+InlineBox* InlineBox::prevLeafChild()
+{
+    return parent() ? parent()->lastLeafChildBeforeBox(this) : 0;
 }
 
 int InlineFlowBox::marginLeft() const
@@ -1181,6 +1191,43 @@ void RootInlineBox::setLineBreakInfo(RenderObject* obj, unsigned breakPos, const
         m_lineBreakContext->ref();
 }
 
+bool isEditableLeaf(InlineBox* leaf)
+{
+    return leaf && leaf->object() && leaf->object()->element() && leaf->object()->element()->isContentEditable();
+}
+
+InlineBox* RootInlineBox::closestLeafChildForXPos(int x, bool onlyEditableLeaves)
+{
+    InlineBox* firstLeaf = firstLeafChildAfterBox();
+    InlineBox* lastLeaf = lastLeafChildBeforeBox();
+    if (firstLeaf == lastLeaf && (!onlyEditableLeaves || isEditableLeaf(firstLeaf)))
+        return firstLeaf;
+
+    // Avoid returning a list marker when possible.
+    if (x <= firstLeaf->m_x && !firstLeaf->object()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(firstLeaf)))
+        // The x coordinate is less or equal to left edge of the firstLeaf.
+        // Return it.
+        return firstLeaf;
+
+    if (x >= lastLeaf->m_x + lastLeaf->m_width && !lastLeaf->object()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(lastLeaf)))
+        // The x coordinate is greater or equal to right edge of the lastLeaf.
+        // Return it.
+        return lastLeaf;
+
+    InlineBox* closestLeaf = 0;
+    for (InlineBox* leaf = firstLeaf; leaf; leaf = leaf->nextLeafChild()) {
+        if (!leaf->object()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(leaf))) {
+            closestLeaf = leaf;
+            if (x < leaf->m_x + leaf->m_width)
+                // The x coordinate is less than the right edge of the box.
+                // Return it.
+                return leaf;
+        }
+    }
+
+    return closestLeaf ? closestLeaf : lastLeaf;
+}
+
 InlineBox* InlineFlowBox::firstLeafChild()
 {
     InlineBox *box = firstChild();
@@ -1230,3 +1277,23 @@ InlineBox* InlineFlowBox::closestChildForXPos(int _x, int _tx)
     return 0;
 }
 
+InlineBox* InlineFlowBox::firstLeafChildAfterBox(InlineBox* start)
+{
+    InlineBox* leaf = 0;
+    for (InlineBox* box = start ? start->nextOnLine() : firstChild(); box && !leaf; box = box->nextOnLine())
+        leaf = box->firstLeafChild();
+    if (start && !leaf && parent())
+        return parent()->firstLeafChildAfterBox(this);
+    return leaf;
+}
+
+InlineBox* InlineFlowBox::lastLeafChildBeforeBox(InlineBox* start)
+{
+    InlineBox* leaf = 0;
+    for (InlineBox* box = start ? start->prevOnLine() : lastChild(); box && !leaf; box = box->prevOnLine())
+        leaf = box->lastLeafChild();
+    if (start && !leaf && parent())
+        return parent()->lastLeafChildBeforeBox(this);
+    return leaf;
+}
+
diff --git a/khtml/rendering/render_line.h b/khtml/rendering/render_line.h
index 99f3e3d..511354e 100644
--- a/khtml/rendering/render_line.h
+++ b/khtml/rendering/render_line.h
@@ -91,7 +91,10 @@ public:
 
     virtual InlineBox* firstLeafChild();
     virtual InlineBox* lastLeafChild();
-    InlineBox* closestLeafChildForXPos(int _x, int _tx);
+    //FIXME to remove InlineBox* closestLeafChildForXPos(int _x, int _tx);
+
+    InlineBox* nextLeafChild();
+    InlineBox* prevLeafChild();
 
     RenderObject* object() const { return m_object; }
 
@@ -125,6 +128,13 @@ public:
     virtual long caretMaxOffset() const;
     virtual unsigned long caretMaxRenderedOffset() const;
 
+    virtual bool isLineBreak() const { return false; }
+
+    int bidiLevel() { return 0; }
+    EDirection direction() const { return LTR; }
+    // FIXME make it direction-wise
+    int caretLeftmostOffset() const { return caretMinOffset(); }
+    int caretRightmostOffset() const { return caretMaxOffset(); }
 
     bool isDirty() const { return m_dirty; }
     void markDirty(bool dirty = true) { m_dirty = dirty; }
@@ -223,6 +233,9 @@ public:
     virtual InlineBox* lastLeafChild();
     InlineBox* closestChildForXPos(int _x, int _tx);
 
+    InlineBox* firstLeafChildAfterBox(InlineBox* start = 0);
+    InlineBox* lastLeafChildBeforeBox(InlineBox* start = 0);
+
     virtual void setConstructed() {
         InlineBox::setConstructed();
         if (m_firstChild)
@@ -363,6 +376,8 @@ public:
     
     void childRemoved(InlineBox* box);
 
+    InlineBox* closestLeafChildForXPos(int x, bool onlyEditableLeaves = false);
+
 protected:
     int m_topOverflow;
     int m_bottomOverflow;
diff --git a/khtml/rendering/render_object.cpp b/khtml/rendering/render_object.cpp
index cee71e4..2b0a94c 100644
--- a/khtml/rendering/render_object.cpp
+++ b/khtml/rendering/render_object.cpp
@@ -41,7 +41,7 @@
 
 #include "xml/dom_elementimpl.h"
 #include "xml/dom_docimpl.h"
-#include "xml/dom_position.h"
+#include "xml/Position.h"
 #include "dom/dom_doc.h"
 #include "misc/htmlhashes.h"
 #include "misc/loader.h"
@@ -456,6 +456,56 @@ RenderObject *RenderObject::lastLeafChild() const
     return r;
 }
 
+RenderObject* RenderObject::nextInPreOrder() const
+{
+    if (RenderObject* o = firstChild())
+        return o;
+
+    return nextInPreOrderAfterChildren();
+}
+
+RenderObject* RenderObject::nextInPreOrderAfterChildren() const
+{
+    RenderObject* o;
+    if (!(o = nextSibling())) {
+        o = parent();
+        while (o && !o->nextSibling())
+            o = o->parent();
+        if (o)
+            o = o->nextSibling();
+    }
+
+    return o;
+}
+
+RenderObject* RenderObject::nextInPreOrder(RenderObject* stayWithin) const
+{
+    if (RenderObject* o = firstChild())
+        return o;
+
+    return nextInPreOrderAfterChildren(stayWithin);
+}
+
+RenderObject* RenderObject::nextInPreOrderAfterChildren(RenderObject* stayWithin) const
+{
+    if (this == stayWithin)
+        return 0;
+
+    RenderObject* o;
+    if (!(o = nextSibling())) {
+        o = parent();
+        while (o && !o->nextSibling()) {
+            if (o == stayWithin)
+                return 0;
+            o = o->parent();
+        }
+        if (o)
+            o = o->nextSibling();
+    }
+
+    return o;
+}
+
 static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject*& newObject,
                       RenderLayer*& beforeChild)
 {
@@ -2231,6 +2281,26 @@ void RenderObject::caretPos(int /*offset*/, int /*flags*/, int &_x, int &_y, int
                     // to check for validity, only test the x-coordinate for >= 0.
 }
 
+QSize RenderObject::offsetFromContainer(RenderObject* o) const
+{
+    ASSERT(o == container());
+
+    QSize offset(0, o->borderTopExtra());
+
+    if (o->hasOverflowClip())
+        offset -= o->layer()->scrolledContentOffset();
+
+    return offset;
+}
+
+QRect RenderObject::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
+{
+   if (extraWidthToEndOfLine)
+       *extraWidthToEndOfLine = 0;
+
+    return QRect();
+}
+
 int RenderObject::paddingTop() const
 {
     int w = 0;
@@ -2387,17 +2457,9 @@ void RenderObject::arenaDelete(RenderArena *arena)
     arenaDelete(arena, dynamic_cast<void *>(this));
 }
 
-Position RenderObject::positionForCoordinates(int /*x*/, int /*y*/)
+VisiblePosition RenderObject::positionForCoordinates(int x, int y)
 {
-    return Position(element(), caretMinOffset());
-}
-
-bool RenderObject::isPointInsideSelection(int x, int y, const Selection &sel) const
-{
-    SelectionState selstate = selectionState();
-    if (selstate == SelectionInside) return true;
-    if (selstate == SelectionNone || !element()) return false;
-    return element()->isPointInsideSelection(x, y, sel);
+    return VisiblePosition(element(), caretMinOffset(), DOWNSTREAM);
 }
 
 #if 0
@@ -2782,6 +2844,16 @@ unsigned long RenderObject::caretMaxRenderedOffset() const
     return 0;
 }
 
+int RenderObject::previousOffset(int current) const
+{
+    return current - 1;
+}
+
+int RenderObject::nextOffset(int current) const
+{
+    return current + 1;
+}
+
 InlineBox *RenderObject::inlineBox(long /*offset*/)
 {
     if (isBox())
@@ -3081,6 +3153,40 @@ AffineTransform RenderObject::absoluteTransform() const
 }
 // END SVG
 
+QPointF RenderObject::localToAbsolute(QPointF localPoint, bool fixed, bool useTransforms) const
+{
+    int x, y;
+    absolutePosition(x, y, fixed);
+    return localPoint + QPointF(x, y);
+}
+
+/*FloatPoint RenderObject::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool useTransforms) const
+{
+    RenderObject* o = parent();
+    if (o) {
+        FloatPoint localPoint = o->absoluteToLocal(containerPoint, fixed, useTransforms);
+        localPoint.move(0.0f, -static_cast<float>(o->borderTopExtra()));
+        if (o->hasOverflowClip())
+            localPoint += o->layer()->scrolledContentOffset();
+        return localPoint;
+    }
+    return FloatPoint();
+}*/
+
+/*FloatQuad RenderObject::localToAbsoluteQuad(const FloatQuad& localQuad, bool fixed) const
+{
+    RenderObject* o = parent();
+    if (o) {
+        FloatQuad quad = localQuad;
+        quad.move(0.0f, static_cast<float>(o->borderTopExtra()));
+        if (o->hasOverflowClip())
+            quad -= o->layer()->scrolledContentOffset();
+        return o->localToAbsoluteQuad(quad, fixed);
+    }
+
+    return FloatQuad();
+}*/
+
 #undef RED_LUMINOSITY
 #undef GREEN_LUMINOSITY
 #undef BLUE_LUMINOSITY
diff --git a/khtml/rendering/render_object.h b/khtml/rendering/render_object.h
index ef684a1..e7bf46c 100644
--- a/khtml/rendering/render_object.h
+++ b/khtml/rendering/render_object.h
@@ -41,6 +41,8 @@
 #include "rendering/render_style.h"
 #include <QtCore/QTextIStream>
 
+#include "xml/VisiblePosition.h"
+
 // svg
 #include "FloatRect.h"
 #include "AffineTransform.h"
@@ -165,6 +167,12 @@ public:
     RenderObject *firstLeafChild() const;
     RenderObject *lastLeafChild() const;
 
+    RenderObject* nextInPreOrder() const;
+    RenderObject* nextInPreOrder(RenderObject* stayWithin) const;
+    RenderObject* nextInPreOrderAfterChildren() const;
+    RenderObject* nextInPreOrderAfterChildren(RenderObject* stayWithin) const;
+    RenderObject* previousInPreOrder() const;
+
     virtual bool childAllowed() const { return false; }
     virtual int borderTopExtra() const { return 0; }
     virtual int borderBottomExtra() const { return 0; }
@@ -580,7 +588,8 @@ public:
     virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, HitTestAction, bool inside = false);
     void setInnerNode(NodeInfo& info);
 
-    virtual DOM::Position positionForCoordinates(int x, int y);
+    virtual DOM::VisiblePosition positionForCoordinates(int x, int y);
+    DOM::VisiblePosition positionForPoint(const QPoint& point) { return positionForCoordinates(point.x(), point.y()); }
 
     // set the style of the object.
     virtual void setStyle(RenderStyle *style);
@@ -759,7 +768,6 @@ public:
     virtual SelectionState selectionState() const { return SelectionNone;}
     virtual void setSelectionState(SelectionState) {}
     bool shouldSelect() const;
-    virtual bool isPointInsideSelection(int x, int y, const DOM::Selection &) const;
 
     DOM::NodeImpl* draggableNode(bool dhtmlOK, bool uaOK, bool& dhtmlWillDrag) const;
 
@@ -785,6 +793,14 @@ public:
      */
     virtual void caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height) const;
 
+    /**
+     * Returns the local coordinates of the caret within this render object.
+     * @param caretOffset zero-based offset determining position within the render object.
+     * @param extraWidthToEndOfLine optional out arg to give extra width to end of line -
+     * useful for character range rect computations
+     */
+    virtual QRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
+
     // returns the lowest position of the lowest object in that particular object.
     // This 'height' is relative to the topleft of the margin box of the object.
     // Implemented in RenderFlow.
@@ -834,12 +850,37 @@ public:
     virtual long caretMaxOffset() const;
     virtual unsigned long caretMaxRenderedOffset() const;
 
+    virtual int previousOffset(int current) const;
+    virtual int nextOffset(int current) const;
+
     virtual void updatePixmap(const QRect&, CachedImage *);
 
     QRegion visibleFlowRegion(int x, int y) const;
 
     virtual void removeSuperfluousAnonymousBlockChild( RenderObject* ) {}
 
+    // Convert the given local point to absolute coordinates
+    // FIXME: Temporary. If useTransforms is true, take transforms into account. Eventually localToAbsolute() will always be transform-aware.
+    virtual QPointF localToAbsolute(QPointF localPoint = QPointF(), bool fixed = false, bool useTransforms = false) const;
+    //virtual FloatPoint absoluteToLocal(FloatPoint, bool fixed = false, bool useTransforms = false) const
+
+    // This function is used to deal with the extra top space that can occur in table cells (called borderTopExtra).
+    // The children of the cell do not factor this space in, so we have to add it in.  Any code that wants to
+    // accurately deal with the contents of a cell must call this function instad of absolutePosition.
+    QPointF localToAbsoluteForContent(QPointF localPoint = QPointF(), bool fixed = false, bool useTransforms = false) const
+    {
+        //localPoint.translate(0.0f, static_cast<float>(borderTopExtra()));
+        localPoint.ry() += borderTopExtra();
+        return localToAbsolute(localPoint, fixed, useTransforms);
+    }
+
+    // Return the offset from the container() renderer (excluding transforms)
+    virtual QSize offsetFromContainer(RenderObject*) const;
+
+    // Convert a local quad to an absolute quad, taking transforms into account.
+    // virtual FloatQuad localToAbsoluteQuad(const FloatQuad&, bool fixed = false) const;
+
+
 protected:
     virtual void selectionStartEnd(int& spos, int& epos);
 
diff --git a/khtml/rendering/render_replaced.cpp b/khtml/rendering/render_replaced.cpp
index 25aeedb..515fbc1 100644
--- a/khtml/rendering/render_replaced.cpp
+++ b/khtml/rendering/render_replaced.cpp
@@ -129,50 +129,37 @@ FindSelectionResult RenderReplaced::checkSelectionPoint(int _x, int _y, int _tx,
     return SelectionPointInside;
 }
 
-long RenderReplaced::caretMinOffset() const
-{
-    return 0;
-}
-
-// Returns 1 since a replaced element can have the caret positioned
-// at its beginning (0), or at its end (1).
-long RenderReplaced::caretMaxOffset() const
-{
-    return 1;
-}
-
 unsigned long RenderReplaced::caretMaxRenderedOffset() const
 {
     return 1;
 }
 
-Position RenderReplaced::positionForCoordinates(int _x, int _y)
+VisiblePosition RenderReplaced::positionForCoordinates(int x, int y)
 {
-    InlineBox *box = placeHolderBox();
+    InlineBox* box = placeHolderBox()/*inlineBoxWrapper()*/;
     if (!box)
-        return Position(element(), 0);
-  
-    RootInlineBox *root = box->root();
-  
-    int absx, absy;
-    containingBlock()->absolutePosition(absx, absy);
-  
-    int top = absy + root->topOverflow();
-    int bottom = root->nextRootBox() ? absy + root->nextRootBox()->topOverflow() : absy + root->bottomOverflow();
-  
-    if (_y < top)
-        return Position(element(), caretMinOffset()); // coordinates are above
-        
-    if (_y >= bottom)
-        return Position(element(), caretMaxOffset()); // coordinates are below
-        
+        return VisiblePosition(element(), 0, DOWNSTREAM);
+
+    // FIXME: This code is buggy if the replaced element is relative positioned.
+
+    RootInlineBox* root = box->root();
+
+    int top = root->topOverflow();
+    int bottom = root->nextRootBox() ? root->nextRootBox()->topOverflow() : root->bottomOverflow();
+
+    if (y + yPos() < top)
+        return VisiblePosition(element(), caretMinOffset(), DOWNSTREAM); // coordinates are above
+    
+    if (y + yPos() >= bottom)
+        return VisiblePosition(element(), caretMaxOffset(), DOWNSTREAM); // coordinates are below
+    
     if (element()) {
-        if (_x <= absx + xPos() + (width() / 2))
-            return Position(element(), 0);
-        return Position(element(), 1);
+        if (x <= width() / 2)
+            return VisiblePosition(element(), 0, DOWNSTREAM);
+        return VisiblePosition(element(), 1, DOWNSTREAM);
     }
-  
-    return RenderBox::positionForCoordinates(_x, _y);
+
+    return RenderBox::positionForCoordinates(x, y);
 }
 
 // -----------------------------------------------------------------------------
diff --git a/khtml/rendering/render_replaced.h b/khtml/rendering/render_replaced.h
index 93702cc..f6c244b 100644
--- a/khtml/rendering/render_replaced.h
+++ b/khtml/rendering/render_replaced.h
@@ -63,10 +63,8 @@ public:
                                                      DOM::NodeImpl*& node, int & offset,
      SelPointState & );
 
-    virtual long caretMinOffset() const;
-    virtual long caretMaxOffset() const;
     virtual unsigned long caretMaxRenderedOffset() const;
-    virtual DOM::Position positionForCoordinates(int x, int y);
+    virtual DOM::VisiblePosition positionForCoordinates(int x, int y);
     virtual bool forceTransparentText() const { return false; }
 
 protected:
diff --git a/khtml/rendering/render_style.h b/khtml/rendering/render_style.h
index 5f1503d..2dff58a 100644
--- a/khtml/rendering/render_style.h
+++ b/khtml/rendering/render_style.h
@@ -1184,6 +1184,16 @@ public:
         // normal | nowrap | pre-line
         return false;
     }
+    static bool preserveNewline(EWhiteSpace ws)
+    {
+        // Normal and nowrap do not preserve newlines.
+        return ws != NORMAL && ws != NOWRAP;
+    }
+
+    bool preserveNewline() const
+    {
+        return preserveNewline(whiteSpace());
+    }
 
     const QColor & backgroundColor() const { return background->m_color; }
     CachedImage *backgroundImage() const { return background->m_background.m_image; }
diff --git a/khtml/rendering/render_text.cpp b/khtml/rendering/render_text.cpp
index a6c5763..191fee5 100644
--- a/khtml/rendering/render_text.cpp
+++ b/khtml/rendering/render_text.cpp
@@ -32,8 +32,9 @@
 #include "render_canvas.h"
 #include "break_lines.h"
 #include "render_arena.h"
-#include <xml/dom_nodeimpl.h>
-#include <xml/dom_position.h>
+#include "xml/dom_nodeimpl.h"
+#include "xml/Position.h"
+#include "xml/VisiblePosition.h"
 
 #include <misc/loader.h>
 #include <misc/helper.h>
@@ -513,6 +514,68 @@ unsigned long InlineTextBox::caretMaxRenderedOffset() const
     return m_start + m_len;
 }
 
+int InlineTextBox::offsetForPosition(int _x, bool /*includePartialGlyphs*/) const
+{
+    int rx, offset;
+    offset = offsetForPoint(_x, rx);
+    kDebug() << "offset for position(" << m_x << "):" <<  _x << offset << rx << endl;
+    kDebug() << "char at:" << renderText()->characters()[offset] << endl;
+    return offset;
+    /*if (isLineBreak())
+        return 0;
+
+    RenderText* text = static_cast<RenderText*>(m_object);
+    RenderStyle *style = text->style(m_firstLine);
+    const QFont* f = &style->font();
+    return f->offsetForPosition(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()),
+                                _x - m_x, includePartialGlyphs);*/
+}
+
+int InlineTextBox::positionForOffset(int offset) const
+{
+    kDebug() << "offset:" << offset << endl;
+    kDebug() << "curent inline box:" << m_start << m_len << endl;
+    return m_x + widthFromStart(offset - m_start);
+    //return offset;
+    /*ASSERT(offset >= m_start);
+    ASSERT(offset <= m_start + m_len);
+
+    if (isLineBreak())
+        return m_x;
+
+    RenderText* text = static_cast<RenderText*>(m_object);
+    const QFont& f = text->style(m_firstLine)->font();
+    int from = direction() == RTL ? offset - m_start : 0;
+    int to = direction() == RTL ? m_len : offset - m_start;
+    // FIXME: Do we need to add rightBearing here?
+    return enclosingIntRect(f.selectionRectForText(TextRun(text->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride),
+                                                   IntPoint(m_x, 0), 0, from, to)).right();*/
+}
+
+bool InlineTextBox::containsCaretOffset(int offset) const
+{
+    // Offsets before the box are never "in".
+    if (offset < m_start)
+        return false;
+
+    int pastEnd = m_start + m_len;
+
+    // Offsets inside the box (not at either edge) are always "in".
+    if (offset < pastEnd)
+        return true;
+
+    // Offsets outside the box are always "out".
+    if (offset > pastEnd)
+        return false;
+
+    /*FIXME port to khtml // Offsets at the end are "out" for line breaks (they are on the next line).
+    if (isLineBreak())
+        return false;*/
+
+    // Offsets at the end are "in" for normal boxes (but the caller has to check affinity).
+    return true;
+}
+
 int InlineTextBox::offsetForPoint(int _x, int &ax) const
 {
   // Do binary search for finding out offset, saves some time for long
@@ -934,49 +997,119 @@ FindSelectionResult RenderText::checkSelectionPoint(int _x, int _y, int _tx, int
     return SelectionPointAfter;
 }
 
-
-Position RenderText::positionForCoordinates(int _x, int _y)
+VisiblePosition RenderText::positionForCoordinates(int x, int y)
 {
-    if (!firstTextBox() || stringLength() == 0)
-        return Position(element(), 0);
+    kDebug() << "coordinates:" << x << y << endl;
+    kDebug() << str->string() << endl;
+    if (!firstTextBox() || textLength() == 0)
+        return VisiblePosition(element(), 0, DOWNSTREAM);
 
     int absx, absy;
     containingBlock()->absolutePosition(absx, absy);
 
-    if (_y < absy + firstTextBox()->root()->bottomOverflow() && _x < absx + firstTextBox()->m_x) {
+    x -= absx;
+    y -= absy;
+    kDebug() << "local coordinates" << x << y << endl;
+
+    // Get the offset for the position, since this will take rtl text into account.
+    int offset;
+
+    // FIXME: We should be able to roll these special cases into the general cases in the loop below.
+    if (firstTextBox() && y < firstTextBox()->root()->bottomOverflow() && x < firstTextBox()->m_x) {
+        kDebug() << "first box" << endl;
         // at the y coordinate of the first line or above
-        // and the x coordinate is to the left than the first text box left edge
-        return Position(element(), firstTextBox()->m_start);
+        // and the x coordinate is to the left of the first text box left edge
+        offset = firstTextBox()->offsetForPosition(x);
+        return VisiblePosition(element(), offset + firstTextBox()->m_start, DOWNSTREAM);
     }
-
-    if (_y >= absy + lastTextBox()->root()->topOverflow() && _x >= absx + lastTextBox()->m_x + lastTextBox()->m_width) {
+    if (lastTextBox() && y >= lastTextBox()->root()->topOverflow() && x >= lastTextBox()->m_x + lastTextBox()->m_width) {
+        kDebug() << "last box" << endl;
         // at the y coordinate of the last line or below
-        // and the x coordinate is to the right than the last text box right edge
-        return Position(element(), lastTextBox()->m_start + lastTextBox()->m_len);
+        // and the x coordinate is to the right of the last text box right edge
+        offset = lastTextBox()->offsetForPosition(x);
+        return VisiblePosition(element(), offset + lastTextBox()->m_start, DOWNSTREAM);
     }
 
+    InlineTextBox* lastBoxAbove = 0;
     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
-        if (_y >= absy + box->root()->topOverflow() && _y < absy + box->root()->bottomOverflow()) {
-            if (_x < absx + box->m_x + box->m_width) {
-                // and the x coordinate is to the left of the right edge of this box
-                // check to see if position goes in this box
-                int offset;
-                box->checkSelectionPoint(_x, _y, absx, absy, offset);
-                if (offset != -1) {
-                    return Position(element(), offset + box->m_start);
-                }
+        kDebug() << "top" << box->root()->topOverflow() << endl;
+        if (y >= box->root()->topOverflow()) {
+            int bottom = box->root()->nextRootBox() ? box->root()->nextRootBox()->topOverflow() : box->root()->bottomOverflow();
+            kDebug() << "bottom" << bottom << endl;
+            if (y < bottom) {
+                offset = box->offsetForPosition(x);
+
+                if (x == box->m_x)
+                    // the x coordinate is equal to the left edge of this box
+                    // the affinity must be downstream so the position doesn't jump back to the previous line
+                    return VisiblePosition(element(), offset + box->m_start, DOWNSTREAM);
+
+                if (x < box->m_x + box->m_width)
+                    // and the x coordinate is to the left of the right edge of this box
+                    // check to see if position goes in this box
+                    return VisiblePosition(element(), offset + box->m_start, offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
+
+                if (!box->prevOnLine() && x < box->m_x)
+                    // box is first on line
+                    // and the x coordinate is to the left of the first text box left edge
+                    return VisiblePosition(element(), offset + box->m_start, DOWNSTREAM);
+
+                if (!box->nextOnLine())
+                    // box is last on line
+                    // and the x coordinate is to the right of the last text box right edge
+                    // generate VisiblePosition, use UPSTREAM affinity if possible
+                    return VisiblePosition(element(), offset + box->m_start, offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
             }
-            else if (!box->prevOnLine() && _x < absx + box->m_x)
-                // box is first on line
-                // and the x coordinate is to the left than the first text box left edge
-                return Position(element(), box->m_start);
-            else if (!box->nextOnLine() && _x >= absx + box->m_x + box->m_width)
-                // box is last on line
-                // and the x coordinate is to the right than the last text box right edge
-                return Position(element(), box->m_start + box->m_len);
+            lastBoxAbove = box;
         }
     }
-    return Position(element(), 0);
+
+    return VisiblePosition(element(), lastBoxAbove ? lastBoxAbove->m_start + lastBoxAbove->m_len : 0, DOWNSTREAM);
+}
+
+QRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
+{
+    if (!inlineBox)
+        return QRect();
+
+    ASSERT(inlineBox->isInlineTextBox());
+    if (!inlineBox->isInlineTextBox())
+        return QRect();
+
+    kDebug() << "Find caret for offset:" << caretOffset << endl;
+    InlineTextBox* box = static_cast<InlineTextBox*>(inlineBox);
+
+    int height = box->root()->bottomOverflow() - box->root()->topOverflow();
+    int top = box->root()->topOverflow();
+
+    kDebug() << "height, top:" << height << top << endl;
+
+    int left = box->positionForOffset(caretOffset);
+
+    kDebug() << "position for offset" << left << endl;
+
+    int rootLeft = box->root()->xPos();
+    kDebug() << "root left" << rootLeft << endl;
+    // FIXME: should we use the width of the root inline box or the
+    // width of the containing block for this?
+    if (extraWidthToEndOfLine)
+        *extraWidthToEndOfLine = (box->root()->width() + rootLeft) - (left + 1);
+
+    RenderBlock* cb = containingBlock();
+    if (cb) kDebug() << "containing block" << cb->renderName() << endl;
+    if (style()->autoWrap()) {
+        kDebug() << "autowrap" << endl;
+        int availableWidth = cb->lineWidth(top);
+        kDebug() << "available width" << availableWidth << endl;
+        if (box->direction() == LTR)
+            left = qMin(left, rootLeft + availableWidth - 1);
+        else
+            left = qMax(left, rootLeft);
+    }
+
+    const int caretWidth = 1;
+    kDebug() << "result caret:" << QRect(left, top, caretWidth, height) << endl;
+    return QRect(left, top, caretWidth, height);
 }
 
 void RenderText::caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height) const
@@ -1023,13 +1156,18 @@ void RenderText::caretPos(int offset, int flags, int &_x, int &_y, int &width, i
 
 long RenderText::caretMinOffset() const
 {
-  if (!m_firstTextBox) return 0;
-  // FIXME: it is *not* guaranteed that the first run contains the lowest offset
-  // Either make this a linear search (slow),
-  // or maintain an index (needs much mem),
-  // or calculate and store it in bidi.cpp (needs calculation even if not needed)
-  // (LS)
-  return m_firstTextBox->m_start;
+    // FIXME: it is *not* guaranteed that the first run contains the lowest offset
+    // Either make this a linear search (slow),
+    // or maintain an index (needs much mem),
+    // or calculate and store it in bidi.cpp (needs calculation even if not needed)
+    // (LS)
+    InlineTextBox* box = firstTextBox();
+    if (!box)
+        return 0;
+    int minOffset = box->m_start;
+    for (box = box->nextTextBox(); box; box = box->nextTextBox())
+        minOffset = qMin(minOffset, box->m_start);
+    return minOffset;
 }
 
 long RenderText::caretMaxOffset() const
@@ -1048,12 +1186,46 @@ unsigned long RenderText::caretMaxRenderedOffset() const
 {
     int l = 0;
     // ### no guarantee that the order is ascending
-    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
+    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
         l += box->m_len;
-    }
     return l;
 }
 
+bool InlineTextBox::isLineBreak() const
+{
+    return object()->isBR() || (object()->style()->preserveNewline() && len() == 1 && (/***/renderText()->text())[start()] == '\n');
+}
+
+int RenderText::previousOffset(int current) const
+{
+    /*FIXME khtml port!!! StringImpl* si = m_text.get();
+    TextBreakIterator* iterator = characterBreakIterator(si->characters(), si->length());
+    if (!iterator)
+        return current - 1;
+
+    long result = textBreakPreceding(iterator, current);
+    if (result == TextBreakDone)
+        result = current - 1;
+
+    return result;*/
+    return current - 1;
+}
+
+int RenderText::nextOffset(int current) const
+{
+    /*FIXME khtml port!!! StringImpl* si = m_text.get();
+    TextBreakIterator* iterator = characterBreakIterator(si->characters(), si->length());
+    if (!iterator)
+        return current + 1;
+
+    long result = textBreakFollowing(iterator, current);
+    if (result == TextBreakDone)
+        result = current + 1;
+
+    return result;*/
+    return current + 1;
+}
+
 InlineBox *RenderText::inlineBox(long offset)
 {
     // ### make educated guess about most likely position
diff --git a/khtml/rendering/render_text.h b/khtml/rendering/render_text.h
index 16106a7..ea5a2a7 100644
--- a/khtml/rendering/render_text.h
+++ b/khtml/rendering/render_text.h
@@ -80,6 +80,8 @@ public:
     // Overridden to prevent the normal delete from being called.
     void operator delete(void* ptr, size_t sz);
 
+    virtual bool isLineBreak() const;
+
 private:
     // The normal operator new is disallowed.
     void* operator new(size_t sz) throw();
@@ -127,6 +129,11 @@ public:
     virtual long caretMaxOffset() const;
     virtual unsigned long caretMaxRenderedOffset() const;
 
+    virtual int offsetForPosition(int x, bool includePartialGlyphs = true) const;
+    virtual int positionForOffset(int offset) const;
+
+    bool containsCaretOffset(int offset) const; // false for offset after line break
+
     /** returns the associated render text
      */
     const RenderText *renderText() const;
@@ -180,7 +187,7 @@ public:
 
     virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, HitTestAction hitTestAction, bool inBox);
 
-    virtual DOM::Position positionForCoordinates(int _x, int _y);
+    virtual DOM::VisiblePosition positionForCoordinates(int _x, int _y);
 
     // Return before, after (offset set to max), or inside the text, at @p offset
     virtual FindSelectionResult checkSelectionPoint( int _x, int _y, int _tx, int _ty,
@@ -191,6 +198,8 @@ public:
     QChar *text() const { if (str) return str->s; else return 0; }
     unsigned int stringLength() const { return str->l; } // non virtual implementation of length()
     virtual void position(InlineBox* box, int from, int len, bool reverse);
+    QChar* characters() const { return text(); }
+    unsigned int textLength() const { return stringLength(); }
 
     virtual unsigned int width(unsigned int from, unsigned int len, const Font *f) const;
     virtual unsigned int width(unsigned int from, unsigned int len, bool firstLine = false) const;
@@ -239,6 +248,7 @@ public:
     virtual bool absolutePosition(int &/*xPos*/, int &/*yPos*/, bool f = false) const;
     bool posOfChar(int ch, int &x, int &y) const;
     virtual bool isPointInsideSelection(int x, int y, const DOM::Selection &) const;
+    virtual QRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
 
     virtual short marginLeft() const { return style()->marginLeft().minWidth(0); }
     virtual short marginRight() const { return style()->marginRight().minWidth(0); }
@@ -270,6 +280,9 @@ public:
     virtual long caretMaxOffset() const;
     virtual unsigned long caretMaxRenderedOffset() const;
 
+    virtual int previousOffset(int current) const;
+    virtual int nextOffset(int current) const;
+
     /** Find the text box that includes the character at @p offset
      * and return pos, which is the position of the char in the run.
      * @param offset zero-based offset into DOM string
diff --git a/khtml/test_regression.cpp b/khtml/test_regression.cpp
index 4effa3e..0389d98 100644
--- a/khtml/test_regression.cpp
+++ b/khtml/test_regression.cpp
@@ -1130,7 +1130,7 @@ void RegressionTest::dumpRenderTree( QTextStream &outputStream, KHTMLPart* part
     DOM::DocumentImpl* doc = static_cast<DocumentImpl*>( part->document().handle() );
     if ( !doc || !doc->renderer() )
         return;
-    doc->renderer()->layer()->dump( outputStream );
+    //FIXME !!!! doc->renderer()->layer()->dump( outputStream );
 
     // Dump frames if any
     // Get list of names instead of frames() to sort the list alphabetically
diff --git a/khtml/test_regression_fontoverload.cpp b/khtml/test_regression_fontoverload.cpp
index 01b253c..de8cfca 100644
--- a/khtml/test_regression_fontoverload.cpp
+++ b/khtml/test_regression_fontoverload.cpp
@@ -176,7 +176,7 @@ public:
 
     void recalcAdvances(int len, QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
     {
-        QFontEngineXLFD::recalcAdvances(len, glyphs, flags);
+        QFontEngineXLFD::recalcAdvances(/*len, */glyphs, flags);
 
         // Go through the glyhs with glyph 0 and fix up their x advance
         // to make sense (or at least match Qt3)
@@ -189,13 +189,13 @@ public:
                 fallBackWidth = xfs->ascent;
         }
 
-        QGlyphLayout* g = glyphs + len;
+        /* FIXME QGlyphLayout* g = glyphs + len;
         while (g != glyphs) {
             --g;
-            if (!g->glyph) {
-                g->advance.x = fallBackWidth;
+            if (!g->glyphs) {
+                g->advances_x = fallBackWidth;
             }
-        }
+        }*/
     }
 
     Type type() const
@@ -246,7 +246,7 @@ class KDE_EXPORT QX11PaintEngine: public QPaintEngine
 
 void QX11PaintEngine::drawFreetype(const QPointF &p, const QTextItemInt &si)
 {
-    if (!si.num_glyphs) return;
+    /*FIXME if (!si.num_glyphs) return;
 
     QFakeFontEngine *eng = static_cast<QFakeFontEngine*>(si.fontEngine);
 
@@ -288,7 +288,7 @@ void QX11PaintEngine::drawFreetype(const QPointF &p, const QTextItemInt &si)
         p->fillRect(rect, p->pen().color());
 
         x += advance;
-    }
+    }*/
 }
 
 
diff --git a/khtml/todo b/khtml/todo
new file mode 100644
index 0000000..5fda3af
--- /dev/null
+++ b/khtml/todo
@@ -0,0 +1,4 @@
+1. port localCaretRect
+2. port localToAbsolute/absoluteToLocal/Quad...
+
+
diff --git a/khtml/xml/Position.cpp b/khtml/xml/Position.cpp
new file mode 100644
index 0000000..33ca14b
--- /dev/null
+++ b/khtml/xml/Position.cpp
@@ -0,0 +1,1025 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "xml/Position.h"
+#include "xml/PositionIterator.h"
+
+#include "xml/dom_elementimpl.h"
+#include "rendering/render_text.h"
+#include "editing/htmlediting.h"
+#include "xml/editing_helper.h"
+#include "xml/VisiblePosition.h"
+#include "xml/visible_units.h"
+#include "xml/dom2_rangeimpl.h"
+#include "editing/TextIterator.h"
+#include "rendering/render_block.h"
+
+/* #include "CSSComputedStyleDeclaration.h"
+#include "CString.h"
+#include "CharacterNames.h"
+#include "Document.h"
+#include "Element.h"
+#include "HTMLNames.h"
+#include "Logging.h"
+#include "PositionIterator.h"
+#include "RenderBlock.h"
+#include "Text.h"
+#include "TextIterator.h"
+#include "htmlediting.h"
+#include "visible_units.h"
+#include <stdio.h>*/
+
+using namespace khtml;
+
+namespace DOM {
+
+static NodeImpl *nextRenderedEditable(NodeImpl *node)
+{
+    while (1) {
+        node = node->nextEditable();
+        if (!node)
+            return 0;
+        RenderObject* renderer = node->renderer();
+        if (!renderer)
+            continue;
+        if (/* FIXME khtml renderer->inlineBoxWrapper() || */renderer->isText() && static_cast<RenderText*>(renderer)->firstTextBox())
+            return node;
+    }
+    return 0;
+}
+
+static NodeImpl *previousRenderedEditable(NodeImpl *node)
+{
+    while (1) {
+        node = node->previousEditable();
+        if (!node)
+            return 0;
+        RenderObject* renderer = node->renderer();
+        if (!renderer)
+            continue;
+        if (/* FIXME khtml renderer->inlineBoxWrapper() || */renderer->isText() && static_cast<RenderText*>(renderer)->firstTextBox())
+            return node;
+    }
+    return 0;
+}
+
+ElementImpl* Position::documentElement() const
+{
+    if (NodeImpl* n = node())
+        if (ElementImpl* e = n->document()->documentElement())
+            return e;
+    return 0;
+}
+
+ElementImpl *Position::element() const
+{
+    NodeImpl *n;
+    for (n = node(); n && !n->isElementNode(); n = n->parentNode())
+        ; // empty loop body
+    return static_cast<ElementImpl *>(n);
+}
+
+/* FIXME khtml PassRefPtr<CSSComputedStyleDeclaration> Position::computedStyle() const
+{
+    Element* elem = element();
+    if (!elem)
+        return 0;
+    return WebCore::computedStyle(elem);
+}*/
+
+Position Position::previous(EUsingComposedCharacters usingComposedCharacters) const
+{
+    NodeImpl *n = node();
+    if (!n)
+        return *this;
+    
+    int o = offset();
+    // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
+    assert(o >= 0);
+
+    if (o > 0) {
+        NodeImpl *child = n->childNode(o - 1);
+        if (child) {
+            return Position(child, maxDeepOffset(child));
+        }
+        // There are two reasons child might be 0:
+        //   1) The node is node like a text node that is not an element, and therefore has no children.
+        //      Going backward one character at a time is correct.
+        //   2) The old offset was a bogus offset like (<br>, 1), and there is no child.
+        //      Going from 1 to 0 is correct.
+        return Position(n, usingComposedCharacters ? uncheckedPreviousOffset(n, o) : o - 1);
+    }
+
+    NodeImpl *parent = n->parentNode();
+    if (!parent)
+        return *this;
+
+    return Position(parent, n->nodeIndex());
+}
+
+Position Position::next(EUsingComposedCharacters usingComposedCharacters) const
+{
+    NodeImpl *n = node();
+    if (!n)
+        return *this;
+    
+    int o = offset();
+    // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
+    assert(o >= 0);
+
+    NodeImpl* child = n->childNode(o);
+    if (child || !n->hasChildNodes() && o < maxDeepOffset(n)) {
+        if (child)
+            return Position(child, 0);
+            
+        // There are two reasons child might be 0:
+        //   1) The node is node like a text node that is not an element, and therefore has no children.
+        //      Going forward one character at a time is correct.
+        //   2) The new offset is a bogus offset like (<br>, 1), and there is no child.
+        //      Going from 0 to 1 is correct.
+        return Position(n, usingComposedCharacters ? uncheckedNextOffset(n, o) : o + 1);
+    }
+
+    NodeImpl *parent = n->parentNode();
+    if (!parent)
+        return *this;
+
+    return Position(parent, n->nodeIndex() + 1);
+}
+
+int Position::uncheckedPreviousOffset(const NodeImpl* n, int current)
+{
+    return n->renderer() ? n->renderer()->previousOffset(current) : current - 1;
+}
+
+int Position::uncheckedNextOffset(const NodeImpl* n, int current)
+{
+    return n->renderer() ? n->renderer()->nextOffset(current) : current + 1;
+}
+
+bool Position::atStart() const
+{
+    NodeImpl *n = node();
+    if (!n)
+        return true;
+    
+    return offset() <= 0 && n->parent() == 0;
+}
+
+bool Position::atEnd() const
+{
+    NodeImpl *n = node();
+    if (!n)
+        return true;
+    
+    return n->parent() == 0 && offset() >= maxDeepOffset(n);
+}
+
+int Position::renderedOffset() const
+{
+    if (!node()->isTextNode())
+        return offset();
+  
+    if (!node()->renderer())
+        return offset();
+                    
+    int result = 0;
+    RenderText *textRenderer = static_cast<RenderText *>(node()->renderer());
+    for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
+        int start = box->m_start;
+        int end = box->m_start + box->m_len;
+        if (offset() < start)
+            return result;
+        if (offset() <= end) {
+            result += offset() - start;
+            return result;
+        }
+        result += box->m_len;
+    }
+    return result;
+}
+
+// return first preceding DOM position rendered at a different location, or "this"
+Position Position::previousCharacterPosition(EAffinity affinity) const
+{
+    if (isNull())
+        return Position();
+
+    NodeImpl *fromRootEditableElement = node()->rootEditableElement();
+
+    bool atStartOfLine = isStartOfLine(VisiblePosition(*this, affinity));
+    bool rendered = isCandidate();
+    
+    Position currentPos = *this;
+    while (!currentPos.atStart()) {
+        currentPos = currentPos.previous();
+
+        if (currentPos.node()->rootEditableElement() != fromRootEditableElement)
+            return *this;
+
+        if (atStartOfLine || !rendered) {
+            if (currentPos.isCandidate())
+                return currentPos;
+        } else if (rendersInDifferentPosition(currentPos))
+            return currentPos;
+    }
+    
+    return *this;
+}
+
+// return first following position rendered at a different location, or "this"
+Position Position::nextCharacterPosition(EAffinity affinity) const
+{
+    if (isNull())
+        return Position();
+
+    NodeImpl *fromRootEditableElement = node()->rootEditableElement();
+
+    bool atEndOfLine = isEndOfLine(VisiblePosition(*this, affinity));
+    bool rendered = isCandidate();
+    
+    Position currentPos = *this;
+    while (!currentPos.atEnd()) {
+        currentPos = currentPos.next();
+
+        if (currentPos.node()->rootEditableElement() != fromRootEditableElement)
+            return *this;
+
+        if (atEndOfLine || !rendered) {
+            if (currentPos.isCandidate())
+                return currentPos;
+        } else if (rendersInDifferentPosition(currentPos))
+            return currentPos;
+    }
+    
+    return *this;
+}
+
+// Whether or not [node, 0] and [node, maxDeepOffset(node)] are their own VisiblePositions.
+// If true, adjacent candidates are visually distinct.
+// FIXME: Disregard nodes with renderers that have no height, as we do in isCandidate.
+// FIXME: Share code with isCandidate, if possible.
+static bool endsOfNodeAreVisuallyDistinctPositions(NodeImpl* node)
+{
+    if (!node || !node->renderer())
+        return false;
+        
+    if (!node->renderer()->isInline())
+        return true;
+        
+    // Don't include inline tables.
+    if (node->id() == ID_TABLE)
+        return false;
+    
+    // There is a VisiblePosition inside an empty inline-block container.
+    return node->renderer()->isReplaced() && canHaveChildrenForEditing(node) && node->renderer()->height() != 0 && !node->firstChild();
+}
+
+static NodeImpl* enclosingVisualBoundary(NodeImpl* node)
+{
+    while (node && !endsOfNodeAreVisuallyDistinctPositions(node))
+        node = node->parentNode();
+        
+    return node;
+}
+
+// upstream() and downstream() want to return positions that are either in a
+// text node or at just before a non-text node.  This method checks for that.
+static bool isStreamer(const PositionIterator& pos)
+{
+    if (!pos.node())
+        return true;
+        
+    if (isAtomicNode(pos.node()))
+        return true;
+        
+    return pos.atStartOfNode();
+}
+
+// This function and downstream() are used for moving back and forth between visually equivalent candidates.
+// For example, for the text node "foo     bar" where whitespace is collapsible, there are two candidates
+// that map to the VisiblePosition between 'b' and the space.  This function will return the left candidate
+// and downstream() will return the right one.
+// Also, upstream() will return [boundary, 0] for any of the positions from [boundary, 0] to the first candidate
+// in boundary, where endsOfNodeAreVisuallyDistinctPositions(boundary) is true.
+Position Position::upstream() const
+{
+    NodeImpl* startNode = node();
+    if (!startNode)
+        return Position();
+    
+    // iterate backward from there, looking for a qualified position
+    NodeImpl* boundary = enclosingVisualBoundary(startNode);
+    PositionIterator lastVisible = *this;
+    PositionIterator currentPos = lastVisible;
+    bool startEditable = startNode->isContentEditable();
+    NodeImpl* lastNode = startNode;
+    for (; !currentPos.atStart(); currentPos.decrement()) {
+        NodeImpl* currentNode = currentPos.node();
+        
+        // Don't check for an editability change if we haven't moved to a different node,
+        // to avoid the expense of computing isContentEditable().
+        if (currentNode != lastNode) {
+            // Don't change editability.
+            bool currentEditable = currentNode->isContentEditable();
+            if (startEditable != currentEditable)
+                break;
+            lastNode = currentNode;
+        }
+
+        // If we've moved to a position that is visually disinct, return the last saved position. There
+        // is code below that terminates early if we're *about* to move to a visually distinct position.
+        if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
+            return lastVisible;
+
+        // skip position in unrendered or invisible node
+        RenderObject* renderer = currentNode->renderer();
+        if (!renderer || renderer->style()->visibility() != VISIBLE)
+            continue;
+                
+        // track last visible streamer position
+        if (isStreamer(currentPos))
+            lastVisible = currentPos;
+        
+        // Don't move past a position that is visually distinct.  We could rely on code above to terminate and
+        // return lastVisible on the next iteration, but we terminate early to avoid doing a nodeIndex() call.
+        if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentPos.atStartOfNode())
+            return lastVisible;
+
+        // Return position after tables and nodes which have content that can be ignored.
+        if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) {
+            if (currentPos.atEndOfNode())
+                return Position(currentNode, maxDeepOffset(currentNode));
+            continue;
+        }
+
+        // return current position if it is in rendered text
+        if (renderer->isText() && static_cast<RenderText*>(renderer)->firstTextBox()) {
+            if (currentNode != startNode) {
+                // This assertion fires in layout tests in the case-transform.html test because
+                // of a mix-up between offsets in the text in the DOM tree with text in the
+                // render tree which can have a different length due to case transformation.
+                // Until we resolve that, disable this so we can run the layout tests!
+                //ASSERT(currentOffset >= renderer->caretMaxOffset());
+                return Position(currentNode, renderer->caretMaxOffset());
+            }
+
+            unsigned textOffset = currentPos.offsetInLeafNode();
+            RenderText* textRenderer = static_cast<RenderText*>(renderer);
+            InlineTextBox* lastTextBox = textRenderer->lastTextBox();
+            for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
+                if (textOffset <= box->start() + box->len()) {
+                    if (textOffset > box->start())
+                        return currentPos;
+                    continue;
+                }
+
+                if (box == lastTextBox || textOffset != box->start() + box->len() + 1)
+                    continue;
+
+                // The text continues on the next line only if the last text box is not on this line and
+                // none of the boxes on this line have a larger start offset.
+
+                bool continuesOnNextLine = true;
+                InlineBox* otherBox = box;
+                while (continuesOnNextLine) {
+                    otherBox = otherBox->nextLeafChild();
+                    if (!otherBox)
+                        break;
+                    if (otherBox == lastTextBox || otherBox->object() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() > textOffset)
+                        continuesOnNextLine = false;
+                }
+
+                otherBox = box;
+                while (continuesOnNextLine) {
+                    otherBox = otherBox->prevLeafChild();
+                    if (!otherBox)
+                        break;
+                    if (otherBox == lastTextBox || otherBox->object() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() > textOffset)
+                        continuesOnNextLine = false;
+                }
+
+                if (continuesOnNextLine)
+                    return currentPos;
+            }
+        }
+    }
+
+    return lastVisible;
+}
+
+// This function and upstream() are used for moving back and forth between visually equivalent candidates.
+// For example, for the text node "foo     bar" where whitespace is collapsible, there are two candidates
+// that map to the VisiblePosition between 'b' and the space.  This function will return the right candidate
+// and upstream() will return the left one.
+// Also, downstream() will return the last position in the last atomic node in boundary for all of the positions
+// in boundary after the last candidate, where endsOfNodeAreVisuallyDistinctPositions(boundary).
+Position Position::downstream() const
+{
+    NodeImpl* startNode = node();
+    if (!startNode)
+        return Position();
+
+    // iterate forward from there, looking for a qualified position
+    NodeImpl* boundary = enclosingVisualBoundary(startNode);
+    PositionIterator lastVisible = *this;
+    PositionIterator currentPos = lastVisible;
+    bool startEditable = startNode->isContentEditable();
+    NodeImpl* lastNode = startNode;
+    for (; !currentPos.atEnd(); currentPos.increment()) {  
+        NodeImpl* currentNode = currentPos.node();
+        
+        // Don't check for an editability change if we haven't moved to a different node,
+        // to avoid the expense of computing isContentEditable().
+        if (currentNode != lastNode) {
+            // Don't change editability.
+            bool currentEditable = currentNode->isContentEditable();
+            if (startEditable != currentEditable)
+                break;
+            lastNode = currentNode;
+        }
+
+        // stop before going above the body, up into the head
+        // return the last visible streamer position
+        if (/*currentNode->hasTagName(bodyTag)*/currentNode->id() == ID_BODY && currentPos.atEndOfNode())
+            break;
+            
+        // Do not move to a visually distinct position.
+        if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
+            return lastVisible;
+        // Do not move past a visually disinct position.
+        // Note: The first position after the last in a node whose ends are visually distinct
+        // positions will be [boundary->parentNode(), originalBlock->nodeIndex() + 1].
+        if (boundary && boundary->parentNode() == currentNode)
+            return lastVisible;
+
+        // skip position in unrendered or invisible node
+        RenderObject* renderer = currentNode->renderer();
+        if (!renderer || renderer->style()->visibility() != VISIBLE)
+            continue;
+            
+        // track last visible streamer position
+        if (isStreamer(currentPos))
+            lastVisible = currentPos;
+
+        // Return position before tables and nodes which have content that can be ignored.
+        if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) {
+            if (currentPos.offsetInLeafNode() <= renderer->caretMinOffset())
+                return Position(currentNode, renderer->caretMinOffset());
+            continue;
+        }
+
+        // return current position if it is in rendered text
+        if (renderer->isText() && static_cast<RenderText*>(renderer)->firstTextBox()) {
+            if (currentNode != startNode) {
+                ASSERT(currentPos.atStartOfNode());
+                return Position(currentNode, renderer->caretMinOffset());
+            }
+
+            unsigned textOffset = currentPos.offsetInLeafNode();
+            RenderText* textRenderer = static_cast<RenderText*>(renderer);
+            InlineTextBox* lastTextBox = textRenderer->lastTextBox();
+            for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
+                if (textOffset <= box->end()) {
+                    if (textOffset >= box->start())
+                        return currentPos;
+                    continue;
+                }
+
+                if (box == lastTextBox || textOffset != box->start() + box->len())
+                    continue;
+
+                // The text continues on the next line only if the last text box is not on this line and
+                // none of the boxes on this line have a larger start offset.
+
+                bool continuesOnNextLine = true;
+                InlineBox* otherBox = box;
+                while (continuesOnNextLine) {
+                    otherBox = otherBox->nextLeafChild();
+                    if (!otherBox)
+                        break;
+                    if (otherBox == lastTextBox || otherBox->object() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() >= textOffset)
+                        continuesOnNextLine = false;
+                }
+
+                otherBox = box;
+                while (continuesOnNextLine) {
+                    otherBox = otherBox->prevLeafChild();
+                    if (!otherBox)
+                        break;
+                    if (otherBox == lastTextBox || otherBox->object() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() >= textOffset)
+                        continuesOnNextLine = false;
+                }
+
+                if (continuesOnNextLine)
+                    return currentPos;
+            }
+        }
+    }
+    
+    return lastVisible;
+}
+
+bool Position::hasRenderedNonAnonymousDescendantsWithHeight(RenderObject* renderer)
+{
+    RenderObject* stop = renderer->nextInPreOrderAfterChildren();
+    for (RenderObject *o = renderer->firstChild(); o && o != stop; o = o->nextInPreOrder())
+        if (o->element() && o->height())
+            return true;
+            
+    return false;
+}
+
+bool Position::nodeIsUserSelectNone(NodeImpl* node)
+{
+    // FIXME: port khtml return node && node->renderer() && node->renderer()->style()->userSelect() == SELECT_NONE;
+    return false;
+}
+
+bool Position::isCandidate() const
+{
+    //kDebug() << "this" << (*this) << endl;
+    //kDebug() << "isNull" << isNull() << endl;
+    if (isNull())
+        return false;
+        
+    RenderObject *renderer = node()->renderer();
+    if (!renderer)
+        return false;
+    //kDebug() << "renderer" << renderer << endl;
+    
+    if (renderer->style()->visibility() != VISIBLE)
+        return false;
+    //kDebug() << "visible style" << endl;
+
+    //kDebug() << "isBR" << renderer->isBR() << endl;
+    if (renderer->isBR())
+        return offset() == 0 && !nodeIsUserSelectNone(node()->parent());
+
+    //kDebug() << "isText()" << renderer->isText() << endl;
+    if (renderer->isText())
+        return inRenderedText() && !nodeIsUserSelectNone(node());
+
+    if (isTableElement(node()) || editingIgnoresContent(node()))
+        return (offset() == 0 || offset() == maxDeepOffset(node())) && !nodeIsUserSelectNone(node()->parent());
+
+    if (/*!node()->hasTagName(htmlTag)*/node()->id() != ID_HTML && renderer->isBlockFlow() && !hasRenderedNonAnonymousDescendantsWithHeight(renderer) &&
+       (renderer->height() || /*node()->hasTagName(bodyTag)*/node()->id() == ID_BODY))
+        return offset() == 0 && !nodeIsUserSelectNone(node());
+    
+    return false;
+}
+
+bool Position::inRenderedText() const
+{
+    if (isNull() || !node()->isTextNode())
+        return false;
+        
+    RenderObject *renderer = node()->renderer();
+    if (!renderer)
+        return false;
+    
+    RenderText *textRenderer = static_cast<RenderText *>(renderer);
+    for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
+        //kDebug() << "box" << box->m_start << box->m_len << endl;
+        if (offset() < box->m_start /*FIXME: port to khtml && !textRenderer->containsReversedText()*/) {
+            // The offset we're looking for is before this node
+            // this means the offset must be in content that is
+            // not rendered. Return false.
+            //kDebug() << "offset to the left" << offset() << box->m_start << endl;
+            return false;
+        }
+        //kDebug() << "in box" << box->containsCaretOffset(offset()) << endl;
+        if (box->containsCaretOffset(offset()))
+            // Return false for offsets inside composed characters.
+            return offset() == 0 || offset() == textRenderer->nextOffset(textRenderer->previousOffset(offset()));
+    }
+    
+    return false;
+}
+
+static unsigned caretMaxRenderedOffset(const NodeImpl* n)
+{
+    RenderObject* r = n->renderer();
+    if (r)
+        return r->caretMaxRenderedOffset();
+    
+    if (n->isCharacterDataNode())
+        return static_cast<const CharacterDataImpl*>(n)->length();
+    return 1;
+}
+
+bool Position::isRenderedCharacter() const
+{
+    if (isNull() || !node()->isTextNode())
+        return false;
+        
+    RenderObject *renderer = node()->renderer();
+    if (!renderer)
+        return false;
+    
+    RenderText *textRenderer = static_cast<RenderText *>(renderer);
+    for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
+        if (offset() < box->m_start/*FIXME khtml port && !textRenderer->containsReversedText()*/) {
+            // The offset we're looking for is before this node
+            // this means the offset must be in content that is
+            // not rendered. Return false.
+            return false;
+        }
+        if (offset() >= box->m_start && offset() < box->m_start + box->m_len)
+            return true;
+    }
+    
+    return false;
+}
+
+bool Position::rendersInDifferentPosition(const Position &pos) const
+{
+    if (isNull() || pos.isNull())
+        return false;
+
+    RenderObject *renderer = node()->renderer();
+    if (!renderer)
+        return false;
+    
+    RenderObject *posRenderer = pos.node()->renderer();
+    if (!posRenderer)
+        return false;
+
+    if (renderer->style()->visibility() != VISIBLE ||
+        posRenderer->style()->visibility() != VISIBLE)
+        return false;
+    
+    if (node() == pos.node()) {
+        if (/*node()->hasTagName(brTag)*/node()->id() == ID_BR)
+            return false;
+
+        if (offset() == pos.offset())
+            return false;
+            
+        if (!node()->isTextNode() && !pos.node()->isTextNode()) {
+            if (offset() != pos.offset())
+                return true;
+        }
+    }
+    
+    if (/*node()->hasTagName(brTag)*/node()->id() == ID_BR && pos.isCandidate())
+        return true;
+                
+    if (/*pos.node()->hasTagName(brTag)*/pos.node()->id() == ID_BR && isCandidate())
+        return true;
+                
+    if (node()->enclosingBlockFlowElement() != pos.node()->enclosingBlockFlowElement())
+        return true;
+
+    if (node()->isTextNode() && !inRenderedText())
+        return false;
+
+    if (pos.node()->isTextNode() && !pos.inRenderedText())
+        return false;
+
+    int thisRenderedOffset = renderedOffset();
+    int posRenderedOffset = pos.renderedOffset();
+
+    if (renderer == posRenderer && thisRenderedOffset == posRenderedOffset)
+        return false;
+
+    int ignoredCaretOffset;
+    InlineBox* b1;
+    getInlineBoxAndOffset(DOWNSTREAM, b1, ignoredCaretOffset);
+    InlineBox* b2;
+    pos.getInlineBoxAndOffset(DOWNSTREAM, b2, ignoredCaretOffset);
+
+    /*FIXME add debugging LOG(Editing, "renderer:               %p [%p]\n", renderer, b1);
+    LOG(Editing, "thisRenderedOffset:         %d\n", thisRenderedOffset);
+    LOG(Editing, "posRenderer:            %p [%p]\n", posRenderer, b2);
+    LOG(Editing, "posRenderedOffset:      %d\n", posRenderedOffset);
+    LOG(Editing, "node min/max:           %d:%d\n", caretMinOffset(node()), caretMaxRenderedOffset(node()));
+    LOG(Editing, "pos node min/max:       %d:%d\n", caretMinOffset(pos.node()), caretMaxRenderedOffset(pos.node()));
+    LOG(Editing, "----------------------------------------------------------------------\n");*/
+
+    if (!b1 || !b2) {
+        return false;
+    }
+
+    if (b1->root() != b2->root()) {
+        return true;
+    }
+
+    if (nextRenderedEditable(node()) == pos.node() &&
+        thisRenderedOffset == (int)caretMaxRenderedOffset(node()) && posRenderedOffset == 0) {
+        return false;
+    }
+    
+    if (previousRenderedEditable(node()) == pos.node() &&
+        thisRenderedOffset == 0 && posRenderedOffset == (int)caretMaxRenderedOffset(pos.node())) {
+        return false;
+    }
+
+    return true;
+}
+
+// This assumes that it starts in editable content.
+Position Position::leadingWhitespacePosition(EAffinity affinity, bool considerNonCollapsibleWhitespace) const
+{
+    ASSERT(isEditablePosition(*this));
+    if (isNull())
+        return Position();
+    
+    if (/*upstream().node()->hasTagName(brTag)*/upstream().node()->id() == ID_BR)
+        return Position();
+
+    Position prev = previousCharacterPosition(affinity);
+    if (prev != *this && prev.node()->inSameContainingBlockFlowElement(node()) && prev.node()->isTextNode()) {
+        DOMString string = static_cast<TextImpl *>(prev.node())->data();
+        QChar c = string[prev.offset()];
+        if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c)/*FIXME khtml port || c == noBreakSpace*/) : isCollapsibleWhitespace(c))
+            if (isEditablePosition(prev))
+                return prev;
+    }
+
+    return Position();
+}
+
+// This assumes that it starts in editable content.
+Position Position::trailingWhitespacePosition(EAffinity affinity, bool considerNonCollapsibleWhitespace) const
+{
+    ASSERT(isEditablePosition(*this));
+    if (isNull())
+        return Position();
+    
+    VisiblePosition v(*this);
+    QChar c = v.characterAfter();
+    // The space must not be in another paragraph and it must be editable.
+    if (!isEndOfParagraph(v) && v.next(true).isNotNull())
+        if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c)/*FIXME khtml port || c == noBreakSpace*/) : isCollapsibleWhitespace(c))
+            return *this;
+    
+    return Position();
+}
+
+void Position::getInlineBoxAndOffset(EAffinity affinity, InlineBox*& inlineBox, int& caretOffset) const
+{
+    TextDirection primaryDirection = LTR;
+    for (RenderObject* r = node()->renderer(); r; r = r->parent()) {
+        if (r->isBlockFlow()) {
+            primaryDirection = r->style()->direction();
+            break;
+        }
+    }
+    getInlineBoxAndOffset(affinity, primaryDirection, inlineBox, caretOffset);
+}
+
+static bool isNonTextLeafChild(RenderObject* object)
+{
+    if (object->firstChild())
+        return false;
+    if (object->isText())
+        return false;
+    return true;
+}
+
+static InlineTextBox* searchAheadForBetterMatch(RenderObject* renderer)
+{
+    InlineTextBox* match = 0;
+    int minOffset = INT_MAX;
+    RenderBlock* container = renderer->containingBlock();
+    RenderObject* next = renderer;
+    while ((next = next->nextInPreOrder(container))) {
+        if (next->isRenderBlock())
+            break;
+        if (next->isBR())
+            break;
+        if (isNonTextLeafChild(next))
+            break;
+        if (next->isText()) {
+            for (InlineTextBox* box = static_cast<RenderText*>(next)->firstTextBox(); box; box = box->nextTextBox()) {
+                int caretMinOffset = box->caretMinOffset();
+                if (caretMinOffset < minOffset) {
+                    match = box;
+                    minOffset = caretMinOffset;
+                }
+            }
+        }
+    }
+    return match;
+}
+
+void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
+{
+    caretOffset = offset();
+    //kDebug() << "caretOffset" << caretOffset << endl;
+    RenderObject* renderer = node()->renderer();
+    //kDebug() << "renderer" << renderer->renderName() << endl;
+    if (!renderer->isText()) {
+        inlineBox = renderer->inlineBox/*Wrapper*/();
+        if (!inlineBox || caretOffset > inlineBox->caretMinOffset() && caretOffset < inlineBox->caretMaxOffset())
+            return;
+    } else {
+        RenderText* textRenderer = static_cast<RenderText*>(renderer);
+
+        InlineTextBox* box;
+        InlineTextBox* candidate = 0;
+
+        for (box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
+            int caretMinOffset = box->caretMinOffset();
+            int caretMaxOffset = box->caretMaxOffset();
+            //kDebug() << "box" << caretMinOffset << caretMaxOffset << endl;
+
+            if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset/*FIXME khtml port || caretOffset == caretMaxOffset && box->isLineBreak()*/)
+                continue;
+
+            if (caretOffset > caretMinOffset && caretOffset < caretMaxOffset) {
+                inlineBox = box;
+                return;
+            }
+
+            if ((caretOffset == caretMinOffset) ^ (affinity == UPSTREAM))
+                break;
+
+            candidate = box;
+        }
+        if (candidate && !box && affinity == DOWNSTREAM) {
+            box = searchAheadForBetterMatch(textRenderer);
+            if (box)
+                caretOffset = box->caretMinOffset();
+        }
+        inlineBox = box ? box : candidate;
+    }
+
+    if (!inlineBox)
+        return;
+
+    unsigned char level = inlineBox->bidiLevel();
+
+    if (inlineBox->direction() == primaryDirection) {
+        if (caretOffset == inlineBox->caretRightmostOffset()) {
+            InlineBox* nextBox = inlineBox->nextLeafChild();
+            if (!nextBox || nextBox->bidiLevel() >= level)
+                return;
+
+            level = nextBox->bidiLevel();
+            InlineBox* prevBox = inlineBox;
+            do {
+                prevBox = prevBox->prevLeafChild();
+            } while (prevBox && prevBox->bidiLevel() > level);
+
+            if (prevBox && prevBox->bidiLevel() == level)   // For example, abc FED 123 ^ CBA
+                return;
+
+            // For example, abc 123 ^ CBA
+            while (InlineBox* nextBox = inlineBox->nextLeafChild()) {
+                if (nextBox->bidiLevel() < level)
+                    break;
+                inlineBox = nextBox;
+            }
+            caretOffset = inlineBox->caretRightmostOffset();
+        } else {
+            InlineBox* prevBox = inlineBox->prevLeafChild();
+            if (!prevBox || prevBox->bidiLevel() >= level)
+                return;
+
+            level = prevBox->bidiLevel();
+            InlineBox* nextBox = inlineBox;
+            do {
+                nextBox = nextBox->nextLeafChild();
+            } while (nextBox && nextBox->bidiLevel() > level);
+
+            if (nextBox && nextBox->bidiLevel() == level)
+                return;
+
+            while (InlineBox* prevBox = inlineBox->prevLeafChild()) {
+                if (prevBox->bidiLevel() < level)
+                    break;
+                inlineBox = prevBox;
+            }
+            caretOffset = inlineBox->caretLeftmostOffset();
+        }
+        return;
+    }
+
+    if (caretOffset == inlineBox->caretLeftmostOffset()) {
+        InlineBox* prevBox = inlineBox->prevLeafChild();
+        if (!prevBox || prevBox->bidiLevel() < level) {
+            // Left edge of a secondary run. Set to the right edge of the entire run.
+            while (InlineBox* nextBox = inlineBox->nextLeafChild()) {
+                if (nextBox->bidiLevel() < level)
+                    break;
+                inlineBox = nextBox;
+            }
+            caretOffset = inlineBox->caretRightmostOffset();
+        } else if (prevBox->bidiLevel() > level) {
+            // Right edge of a "tertiary" run. Set to the left edge of that run.
+            while (InlineBox* tertiaryBox = inlineBox->prevLeafChild()) {
+                if (tertiaryBox->bidiLevel() <= level)
+                    break;
+                inlineBox = tertiaryBox;
+            }
+            caretOffset = inlineBox->caretLeftmostOffset();
+        }
+    } else {
+        InlineBox* nextBox = inlineBox->nextLeafChild();
+        if (!nextBox || nextBox->bidiLevel() < level) {
+            // Right edge of a secondary run. Set to the left edge of the entire run.
+            while (InlineBox* prevBox = inlineBox->prevLeafChild()) {
+                if (prevBox->bidiLevel() < level)
+                    break;
+                inlineBox = prevBox;
+            }
+            caretOffset = inlineBox->caretLeftmostOffset();
+        } else if (nextBox->bidiLevel() > level) {
+            // Left edge of a "tertiary" run. Set to the right edge of that run.
+            while (InlineBox* tertiaryBox = inlineBox->nextLeafChild()) {
+                if (tertiaryBox->bidiLevel() <= level)
+                    break;
+                inlineBox = tertiaryBox;
+            }
+            caretOffset = inlineBox->caretRightmostOffset();
+        }
+    }
+}
+
+void Position::debugPosition(const char* msg) const
+{
+    /*if (isNull())
+        fprintf(stderr, "Position [%s]: null\n", msg);
+    else
+        fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, node()->nodeName().utf8().data(), node(), offset());*/
+}
+
+#ifndef NDEBUG
+
+void Position::formatForDebugger(char* buffer, unsigned length) const
+{
+    /*String result;
+    
+    if (isNull())
+        result = "<null>";
+    else {
+        char s[1024];
+        result += "offset ";
+        result += String::number(offset());
+        result += " of ";
+        node()->formatForDebugger(s, sizeof(s));
+        result += s;
+    }
+          
+    strncpy(buffer, result.utf8().data(), length - 1);*/
+}
+
+void Position::showTreeForThis() const
+{
+    /*if (node())
+        node()->showTreeForThis();*/
+}
+
+#endif
+
+Position startPosition(const RangeImpl* r)
+{
+    return r ? r->startPosition() : Position();
+}
+
+Position endPosition(const RangeImpl* r)
+{
+    return r ? r->endPosition() : Position();
+}
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+
+void showTree(const khtml::Position& pos)
+{
+    pos.showTreeForThis();
+}
+
+void showTree(const khtml::Position* pos)
+{
+    if (pos)
+        pos->showTreeForThis();
+}
+
+#endif
diff --git a/khtml/xml/Position.h b/khtml/xml/Position.h
new file mode 100644
index 0000000..3486a10
--- /dev/null
+++ b/khtml/xml/Position.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Position_h
+#define Position_h
+
+/*#include "TextAffinity.h"
+#include "TextDirection.h"*/
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include "rendering/render_style.h"
+
+namespace khtml
+{
+// FIXME khtml class CSSComputedStyleDeclarationImpl;
+class InlineBox;
+class RenderObject;
+}
+
+namespace DOM
+{
+
+using khtml::InlineBox;
+using khtml::RenderObject;
+
+// FIXME should be removed
+typedef enum { UPSTREAM = 0, DOWNSTREAM = 1 } EAffinity;
+typedef khtml::EDirection TextDirection;
+
+enum EUsingComposedCharacters { NotUsingComposedCharacters = false, UsingComposedCharacters = true };
+
+// FIXME: Reduce the number of operations we have on a Position.
+// This should be more like a humble struct, without so many different
+// member functions. We should find better homes for these functions.
+
+class Position {
+public:
+    RefPtr<NodeImpl> container;
+    int posOffset; // to be renamed to offset when we get rid of offset()
+
+    Position() : posOffset(0) { }
+    Position(PassRefPtr<NodeImpl> c, int o) : container(c), posOffset(o) { }
+
+    void clear() { container.clear(); posOffset = 0; }
+
+    NodeImpl* node() const { return container.get(); }
+    int offset() const { return posOffset; }
+    ElementImpl* documentElement() const;
+
+    bool isNull() const { return !container; }
+    bool isNotNull() const { return container; }
+
+    ElementImpl* element() const;
+    // FIXME khtml PassRefPtr<CSSComputedStyleDeclarationImpl> computedStyle() const;
+
+    // Move up or down the DOM by one position.
+    // Offsets are computed using render text for nodes that have renderers - but note that even when
+    // using composed characters, the result may be inside a single user-visible character if a ligature is formed.
+    Position previous(EUsingComposedCharacters usingComposedCharacters=NotUsingComposedCharacters) const;
+    Position next(EUsingComposedCharacters usingComposedCharacters=NotUsingComposedCharacters) const;
+    static int uncheckedPreviousOffset(const NodeImpl*, int current);
+    static int uncheckedNextOffset(const NodeImpl*, int current);
+
+    bool atStart() const;
+    bool atEnd() const;
+
+    // FIXME: Make these non-member functions and put them somewhere in the editing directory.
+    // These aren't really basic "position" operations. More high level editing helper functions.
+    Position leadingWhitespacePosition(EAffinity, bool considerNonCollapsibleWhitespace = false) const;
+    Position trailingWhitespacePosition(EAffinity, bool considerNonCollapsibleWhitespace = false) const;
+    
+    // These return useful visually equivalent positions.
+    Position upstream() const;
+    Position downstream() const;
+    
+    bool isCandidate() const;
+    bool inRenderedText() const;
+    bool isRenderedCharacter() const;
+    bool rendersInDifferentPosition(const Position&) const;
+
+    void getInlineBoxAndOffset(EAffinity, InlineBox*&, int& caretOffset) const;
+    void getInlineBoxAndOffset(EAffinity, TextDirection primaryDirection, InlineBox*&, int& caretOffset) const;
+
+    static bool hasRenderedNonAnonymousDescendantsWithHeight(RenderObject*);
+    static bool nodeIsUserSelectNone(NodeImpl*);
+    
+    void debugPosition(const char* msg = "") const;
+
+#ifndef NDEBUG
+    void formatForDebugger(char* buffer, unsigned length) const;
+    void showTreeForThis() const;
+#endif
+    
+private:
+    int renderedOffset() const;
+
+    Position previousCharacterPosition(EAffinity) const;
+    Position nextCharacterPosition(EAffinity) const;
+};
+
+inline bool operator==(const Position& a, const Position& b)
+{
+    return a.container == b.container && a.posOffset == b.posOffset;
+}
+
+inline bool operator!=(const Position& a, const Position& b)
+{
+    return !(a == b);
+}
+
+inline QDebug operator<<(QDebug stream, const Position& position)
+{
+    NodeImpl* node = position.node();
+    return (stream << "[node:" << node << (node ? node->nodeName() : QString("")) << "; offset:"
+            << position.offset() << "]");
+}
+
+Position startPosition(const RangeImpl*);
+Position endPosition(const RangeImpl*);
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+// Outside the WebCore namespace for ease of invocation from gdb.
+void showTree(const khtml::Position&);
+void showTree(const khtml::Position*);
+#endif
+
+#endif // Position_h
diff --git a/khtml/xml/PositionIterator.cpp b/khtml/xml/PositionIterator.cpp
new file mode 100644
index 0000000..b6aaa39
--- /dev/null
+++ b/khtml/xml/PositionIterator.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "xml/PositionIterator.h"
+#include "editing/htmlediting.h"
+#include "rendering/render_object.h"
+#include "xml/editing_helper.h"
+
+using namespace khtml;
+
+namespace DOM {
+
+PositionIterator::operator Position() const
+{
+    return Position(m_parent, m_child ? m_child->nodeIndex() : (m_parent->hasChildNodes() ? maxDeepOffset(m_parent) : m_offset));
+}
+
+void PositionIterator::increment()
+{
+    if (!m_parent)
+        return;
+
+    if (m_child) {
+        m_parent = m_child;
+        m_child = m_parent->firstChild();
+        m_offset = 0;
+        return;
+    }
+
+    if (!m_parent->hasChildNodes() && m_offset < maxDeepOffset(m_parent))
+        m_offset = Position::uncheckedNextOffset(m_parent, m_offset);
+    else {
+        m_child = m_parent;
+        m_parent = m_child->parentNode();
+        m_child = m_child->nextSibling();
+        m_offset = 0;
+    }
+}
+
+void PositionIterator::decrement()
+{
+    if (!m_parent)
+        return;
+
+    if (m_child) {
+        m_parent = m_child->previousSibling();
+        if (m_parent) {
+            m_child = 0;
+            m_offset = m_parent->hasChildNodes() ? 0 : maxDeepOffset(m_parent);
+        } else {
+            m_child = m_child->parentNode();
+            m_parent = m_child->parentNode();
+            m_offset = 0;
+        }
+        return;
+    }
+
+    if (m_offset) {
+        m_offset = Position::uncheckedPreviousOffset(m_parent, m_offset);
+    } else {
+        if (m_parent->hasChildNodes()) {
+            m_parent = m_parent->lastChild();
+            if (!m_parent->hasChildNodes())
+                m_offset = maxDeepOffset(m_parent);
+        } else {
+            m_child = m_parent;
+            m_parent = m_parent->parentNode();
+        }
+    }
+}
+
+bool PositionIterator::atStart() const
+{
+    if (!m_parent)
+        return true;
+    if (m_parent->parentNode())
+        return false;
+    return !m_parent->hasChildNodes() && !m_offset || m_child && !m_child->previousSibling();
+}
+
+bool PositionIterator::atEnd() const
+{
+    if (!m_parent)
+        return true;
+    if (m_child)
+        return false;
+    return !m_parent->parentNode() && (m_parent->hasChildNodes() || m_offset >= maxDeepOffset(m_parent));
+}
+
+bool PositionIterator::atStartOfNode() const
+{
+    if (!m_parent)
+        return true;
+    if (!m_child)
+        return !m_parent->hasChildNodes() && !m_offset;
+    return !m_child->previousSibling();
+}
+
+bool PositionIterator::atEndOfNode() const
+{
+    if (!m_parent)
+        return true;
+    if (m_child)
+        return false;
+    return m_parent->hasChildNodes() || m_offset >= maxDeepOffset(m_parent);
+}
+
+bool PositionIterator::isCandidate() const
+{
+    if (!m_parent)
+        return false;
+
+    RenderObject* renderer = m_parent->renderer();
+    if (!renderer)
+        return false;
+    
+    if (renderer->style()->visibility() != VISIBLE)
+        return false;
+
+    if (renderer->isBR())
+        return !m_offset && !Position::nodeIsUserSelectNone(m_parent->parent());
+
+    if (renderer->isText())
+        return Position(*this).inRenderedText() && !Position::nodeIsUserSelectNone(m_parent);
+
+    if (isTableElement(m_parent) || editingIgnoresContent(m_parent))
+        return (atStartOfNode() || atEndOfNode()) && !Position::nodeIsUserSelectNone(m_parent->parent());
+
+    // FIXME khtml should be hasTagName translated into more robust matching?
+    if (!m_parent->id() == ID_HTML && renderer->isBlockFlow() && !Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer) &&
+       (renderer->height() || m_parent->id() == ID_BODY))
+        return atStartOfNode() && !Position::nodeIsUserSelectNone(m_parent);
+    
+    return false;
+}
+
+} // namespace WebCore
diff --git a/khtml/xml/PositionIterator.h b/khtml/xml/PositionIterator.h
new file mode 100644
index 0000000..0841ef4
--- /dev/null
+++ b/khtml/xml/PositionIterator.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PositionIterator_h
+#define PositionIterator_h
+
+#include "xml/Position.h"
+#include "xml/dom_nodeimpl.h"
+
+namespace DOM {
+
+// A Position iterator with constant-time
+// increment, decrement, and several predicates on the Position it is at.
+// Conversion to/from Position is O(n) in the offset.
+class PositionIterator {
+public:
+    PositionIterator()
+        : m_parent(0)
+        , m_child(0)
+        , m_offset(0)
+    {
+    }
+
+    PositionIterator(const Position& pos)
+        : m_parent(pos.node())
+        , m_child(m_parent->childNode(pos.offset()))
+        , m_offset(m_child ? 0 : pos.offset())
+    {
+    }
+    operator Position() const;
+
+    void increment();
+    void decrement();
+
+    NodeImpl* node() const { return m_parent; }
+    int offsetInLeafNode() const { return m_offset; }
+
+    bool atStart() const;
+    bool atEnd() const;
+    bool atStartOfNode() const;
+    bool atEndOfNode() const;
+    bool isCandidate() const;
+
+private:
+    NodeImpl* m_parent;
+    NodeImpl* m_child;
+    int m_offset;
+};
+
+} // namespace WebCore
+
+#endif // PositionIterator_h
diff --git a/khtml/xml/Selection.cpp b/khtml/xml/Selection.cpp
new file mode 100644
index 0000000..c23bdc7
--- /dev/null
+++ b/khtml/xml/Selection.cpp
@@ -0,0 +1,618 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+  
+/*#include "config.h"
+#include "Selection.h"
+
+#include "CString.h"
+#include "Document.h"
+#include "Element.h"
+#include "htmlediting.h"
+#include "VisiblePosition.h"
+#include "visible_units.h"
+#include "Range.h"
+#include <wtf/Assertions.h>
+#include <stdio.h>*/
+
+#include "xml/Selection.h"
+#include "xml/dom2_rangeimpl.h"
+#include "xml/visible_units.h"
+#include "xml/editing_helper.h"
+
+using namespace khtml;
+
+namespace DOM {
+
+Selection::Selection()
+    : m_affinity(DOWNSTREAM)
+    , m_granularity(CharacterGranularity)
+    , m_state(NONE)
+    , m_baseIsFirst(true)
+{
+}
+
+Selection::Selection(const Position& pos, EAffinity affinity)
+    : m_base(pos)
+    , m_extent(pos)
+    , m_affinity(affinity)
+    , m_granularity(CharacterGranularity)
+{
+    validate();
+}
+
+Selection::Selection(const Position& base, const Position& extent, EAffinity affinity)
+    : m_base(base)
+    , m_extent(extent)
+    , m_affinity(affinity)
+    , m_granularity(CharacterGranularity)
+{
+    validate();
+}
+
+Selection::Selection(const VisiblePosition& pos)
+    : m_base(pos.deepEquivalent())
+    , m_extent(pos.deepEquivalent())
+    , m_affinity(pos.affinity())
+    , m_granularity(CharacterGranularity)
+{
+    validate();
+}
+
+Selection::Selection(const VisiblePosition& base, const VisiblePosition& extent)
+    : m_base(base.deepEquivalent())
+    , m_extent(extent.deepEquivalent())
+    , m_affinity(base.affinity())
+    , m_granularity(CharacterGranularity)
+{
+    validate();
+}
+
+Selection::Selection(const RangeImpl* range, EAffinity affinity)
+    : m_base(range->startPosition())
+    , m_extent(range->endPosition())
+    , m_affinity(affinity)
+    , m_granularity(CharacterGranularity)
+{
+    validate();
+}
+
+Selection Selection::selectionFromContentsOfNode(NodeImpl* node)
+{
+    return Selection(Position(node, 0), Position(node, maxDeepOffset(node)), DOWNSTREAM);
+}
+
+void Selection::setBase(const Position& position)
+{
+    m_base = position;
+    validate();
+}
+
+void Selection::setBase(const VisiblePosition& visiblePosition)
+{
+    m_base = visiblePosition.deepEquivalent();
+    validate();
+}
+
+void Selection::setExtent(const Position& position)
+{
+    m_extent = position;
+    validate();
+}
+
+void Selection::setExtent(const VisiblePosition& visiblePosition)
+{
+    m_extent = visiblePosition.deepEquivalent();
+    validate();
+}
+
+PassRefPtr<RangeImpl> Selection::toRange() const
+{
+    if (isNone())
+        return 0;
+
+    // Make sure we have an updated layout since this function is called
+    // in the course of running edit commands which modify the DOM.
+    // Failing to call this can result in equivalentXXXPosition calls returning
+    // incorrect results.
+    m_start.node()->document()->updateLayout();
+
+    // Check again, because updating layout can clear the selection.
+    if (isNone())
+        return 0;
+
+    Position s, e;
+    if (isCaret()) {
+        // If the selection is a caret, move the range start upstream. This helps us match
+        // the conventions of text editors tested, which make style determinations based
+        // on the character before the caret, if any.
+        s = rangeCompliantEquivalent(m_start.upstream());
+        e = s;
+    } else {
+        // If the selection is a range, select the minimum range that encompasses the selection.
+        // Again, this is to match the conventions of text editors tested, which make style
+        // determinations based on the first character of the selection.
+        // For instance, this operation helps to make sure that the "X" selected below is the
+        // only thing selected. The range should not be allowed to "leak" out to the end of the
+        // previous text node, or to the beginning of the next text node, each of which has a
+        // different style.
+        //
+        // On a treasure map, <b>X</b> marks the spot.
+        //                       ^ selected
+        //
+        ASSERT(isRange());
+        s = m_start.downstream();
+        e = m_end.upstream();
+        if (RangeImpl::compareBoundaryPoints(s.node(), s.offset(), e.node(), e.offset()) > 0) {
+            // Make sure the start is before the end.
+            // The end can wind up before the start if collapsed whitespace is the only thing selected.
+            Position tmp = s;
+            s = e;
+            e = tmp;
+        }
+        s = rangeCompliantEquivalent(s);
+        e = rangeCompliantEquivalent(e);
+    }
+
+    /*FIXME khtmlExceptionCode*/int ec = 0;
+    RefPtr<RangeImpl> result(RangeImpl::create(s.node()->document()));
+    result->setStart(s.node(), s.offset(), ec);
+    if (ec) {
+        //FIXME khtml LOG_ERROR("Exception setting Range start from Selection: %d", ec);
+        return 0;
+    }
+    result->setEnd(e.node(), e.offset(), ec);
+    if (ec) {
+        //FIXME khtml LOG_ERROR("Exception setting Range end from Selection: %d", ec);
+        return 0;
+    }
+    return result.release();
+}
+
+bool Selection::expandUsingGranularity(TextGranularity granularity)
+{
+    if (isNone())
+        return false;
+
+    m_granularity = granularity;
+    validate();
+    return true;
+}
+
+void Selection::appendTrailingWhitespace()
+{
+    VisiblePosition end = VisiblePosition(m_end, m_affinity);
+    while (end.isNotNull() && isSpaceOrNewline(end.characterAfter()))
+        end = end.next();
+    m_end = end.deepEquivalent();
+}
+
+void Selection::validate()
+{
+    // Move the selection to rendered positions, if possible.
+    bool baseAndExtentEqual = m_base == m_extent;
+    if (m_base.isNotNull()) {
+        m_base = VisiblePosition(m_base, m_affinity).deepEquivalent();
+        if (baseAndExtentEqual)
+            m_extent = m_base;
+    }
+    if (m_extent.isNotNull() && !baseAndExtentEqual)
+        m_extent = VisiblePosition(m_extent, m_affinity).deepEquivalent();
+
+    // Make sure we do not have a dangling base or extent.
+    if (m_base.isNull() && m_extent.isNull())
+        m_baseIsFirst = true;
+    else if (m_base.isNull()) {
+        m_base = m_extent;
+        m_baseIsFirst = true;
+    } else if (m_extent.isNull()) {
+        m_extent = m_base;
+        m_baseIsFirst = true;
+    } else {
+        m_baseIsFirst = comparePositions(m_base, m_extent) <= 0;
+    }
+
+    if (m_baseIsFirst) {
+        m_start = m_base;
+        m_end = m_extent;
+    } else {
+        m_start = m_extent;
+        m_end = m_base;
+    }
+
+    // Expand the selection if requested.
+    switch (m_granularity) {
+        case CharacterGranularity:
+            // Don't do any expansion.
+            break;
+        case WordGranularity: {
+            // General case: Select the word the caret is positioned inside of, or at the start of (RightWordIfOnBoundary).
+            // Edge case: If the caret is after the last word in a soft-wrapped line or the last word in
+            // the document, select that last word (LeftWordIfOnBoundary).
+            // Edge case: If the caret is after the last word in a paragraph, select from the the end of the
+            // last word to the line break (also RightWordIfOnBoundary);
+            VisiblePosition start = VisiblePosition(m_start, m_affinity);
+            VisiblePosition originalEnd(m_end, m_affinity);
+            EWordSide side = RightWordIfOnBoundary;
+            if (isEndOfDocument(start) || (isEndOfLine(start) && !isStartOfLine(start) && !isEndOfParagraph(start)))
+                side = LeftWordIfOnBoundary;
+            m_start = startOfWord(start, side).deepEquivalent();
+            side = RightWordIfOnBoundary;
+            if (isEndOfDocument(originalEnd) || (isEndOfLine(originalEnd) && !isStartOfLine(originalEnd) && !isEndOfParagraph(originalEnd)))
+                side = LeftWordIfOnBoundary;
+                
+            VisiblePosition wordEnd(endOfWord(originalEnd, side));
+            VisiblePosition end(wordEnd);
+            
+            if (isEndOfParagraph(originalEnd)) {
+                // Select the paragraph break (the space from the end of a paragraph to the start of
+                // the next one) to match TextEdit.
+                end = wordEnd.next();
+                
+                if (NodeImpl* table = isFirstPositionAfterTable(end)) {
+                    // The paragraph break after the last paragraph in the last cell of a block table ends
+                    // at the start of the paragraph after the table.
+                    if (isBlock(table))
+                        end = end.next(true);
+                    else
+                        end = wordEnd;
+                }
+                
+                if (end.isNull())
+                    end = wordEnd;
+                    
+            }
+                
+            m_end = end.deepEquivalent();
+            break;
+        }
+        case SentenceGranularity: {
+            m_start = startOfSentence(VisiblePosition(m_start, m_affinity)).deepEquivalent();
+            m_end = endOfSentence(VisiblePosition(m_end, m_affinity)).deepEquivalent();
+            break;
+        }
+        case LineGranularity: {
+            m_start = startOfLine(VisiblePosition(m_start, m_affinity)).deepEquivalent();
+            VisiblePosition end = endOfLine(VisiblePosition(m_end, m_affinity));
+            // If the end of this line is at the end of a paragraph, include the space
+            // after the end of the line in the selection.
+            if (isEndOfParagraph(end)) {
+                VisiblePosition next = end.next();
+                if (next.isNotNull())
+                    end = next;
+            }
+            m_end = end.deepEquivalent();
+            break;
+        }
+        case LineBoundary:
+            m_start = startOfLine(VisiblePosition(m_start, m_affinity)).deepEquivalent();
+            m_end = endOfLine(VisiblePosition(m_end, m_affinity)).deepEquivalent();
+            break;
+        case ParagraphGranularity: {
+            VisiblePosition pos(m_start, m_affinity);
+            if (isStartOfLine(pos) && isEndOfDocument(pos))
+                pos = pos.previous();
+            m_start = startOfParagraph(pos).deepEquivalent();
+            VisiblePosition visibleParagraphEnd = endOfParagraph(VisiblePosition(m_end, m_affinity));
+            
+            // Include the "paragraph break" (the space from the end of this paragraph to the start
+            // of the next one) in the selection.
+            VisiblePosition end(visibleParagraphEnd.next());
+            
+            if (NodeImpl* table = isFirstPositionAfterTable(end)) {
+                // The paragraph break after the last paragraph in the last cell of a block table ends
+                // at the start of the paragraph after the table, not at the position just after the table.
+                if (isBlock(table))
+                    end = end.next(true);
+                // There is no parargraph break after the last paragraph in the last cell of an inline table.
+                else
+                    end = visibleParagraphEnd;
+            }
+            
+            if (end.isNull())
+                end = visibleParagraphEnd;
+                
+            m_end = end.deepEquivalent();
+            break;
+        }
+        case DocumentBoundary:
+            m_start = startOfDocument(VisiblePosition(m_start, m_affinity)).deepEquivalent();
+            m_end = endOfDocument(VisiblePosition(m_end, m_affinity)).deepEquivalent();
+            break;
+        case ParagraphBoundary:
+            m_start = startOfParagraph(VisiblePosition(m_start, m_affinity)).deepEquivalent();
+            m_end = endOfParagraph(VisiblePosition(m_end, m_affinity)).deepEquivalent();
+            break;
+        case SentenceBoundary:
+            m_start = startOfSentence(VisiblePosition(m_start, m_affinity)).deepEquivalent();
+            m_end = endOfSentence(VisiblePosition(m_end, m_affinity)).deepEquivalent();
+            break;
+    }
+    
+    // Make sure we do not have a dangling start or end.
+    if (m_start.isNull())
+        m_start = m_end;
+    if (m_end.isNull())
+        m_end = m_start;
+    
+    adjustForEditableContent();
+
+    // adjust the state
+    if (m_start.isNull()) {
+        ASSERT(m_end.isNull());
+        m_state = NONE;
+
+        // enforce downstream affinity if not caret, as affinity only
+        // makes sense for caret
+        m_affinity = DOWNSTREAM;
+    } else if (m_start == m_end || m_start.upstream() == m_end.upstream()) {
+        m_state = CARET;
+    } else {
+        m_state = RANGE;
+
+        // enforce downstream affinity if not caret, as affinity only
+        // makes sense for caret
+        m_affinity = DOWNSTREAM;
+
+        // "Constrain" the selection to be the smallest equivalent range of nodes.
+        // This is a somewhat arbitrary choice, but experience shows that it is
+        // useful to make to make the selection "canonical" (if only for
+        // purposes of comparing selections). This is an ideal point of the code
+        // to do this operation, since all selection changes that result in a RANGE
+        // come through here before anyone uses it.
+        // FIXME: Canonicalizing is good, but haven't we already done it (when we
+        // set these two positions to VisiblePosition deepEquivalent()s above)?
+        m_start = m_start.downstream();
+        m_end = m_end.upstream();
+    }
+}
+
+// FIXME: This function breaks the invariant of this class.
+// But because we use Selection to store values in editing commands for use when
+// undoing the command, we need to be able to create a selection that while currently
+// invalid, will be valid once the changes are undone. This is a design problem.
+// To fix it we either need to change the invariants of Selection or create a new
+// class for editing to use that can manipulate selections that are not currently valid.
+void Selection::setWithoutValidation(const Position& base, const Position& extent)
+{
+    ASSERT(!base.isNull());
+    ASSERT(!extent.isNull());
+    ASSERT(base != extent);
+    ASSERT(m_affinity == DOWNSTREAM);
+    ASSERT(m_granularity == CharacterGranularity);
+    m_base = base;
+    m_extent = extent;
+    m_baseIsFirst = comparePositions(base, extent) <= 0;
+    if (m_baseIsFirst) {
+        m_start = base;
+        m_end = extent;
+    } else {
+        m_start = extent;
+        m_end = base;
+    }
+    m_state = RANGE;
+}
+
+void Selection::adjustForEditableContent()
+{
+    if (m_base.isNull() || m_start.isNull() || m_end.isNull())
+        return;
+
+    NodeImpl* baseRoot = highestEditableRoot(m_base);
+    NodeImpl* startRoot = highestEditableRoot(m_start);
+    NodeImpl* endRoot = highestEditableRoot(m_end);
+    
+    NodeImpl* baseEditableAncestor = lowestEditableAncestor(m_base.node());
+    
+    // The base, start and end are all in the same region.  No adjustment necessary.
+    if (baseRoot == startRoot && baseRoot == endRoot)
+        return;
+    
+    // The selection is based in editable content.
+    if (baseRoot) {
+        // If the start is outside the base's editable root, cap it at the start of that root.
+        // If the start is in non-editable content that is inside the base's editable root, put it
+        // at the first editable position after start inside the base's editable root.
+        if (startRoot != baseRoot) {
+            VisiblePosition first = firstEditablePositionAfterPositionInRoot(m_start, baseRoot);
+            m_start = first.deepEquivalent();
+            if (m_start.isNull()) {
+                ASSERT_NOT_REACHED();
+                m_start = m_end;
+            }
+        }
+        // If the end is outside the base's editable root, cap it at the end of that root.
+        // If the end is in non-editable content that is inside the base's root, put it
+        // at the last editable position before the end inside the base's root.
+        if (endRoot != baseRoot) {
+            VisiblePosition last = lastEditablePositionBeforePositionInRoot(m_end, baseRoot);
+            m_end = last.deepEquivalent();
+            if (m_end.isNull()) {
+                ASSERT_NOT_REACHED();
+                m_end = m_start;
+            }
+        }
+    // The selection is based in non-editable content.
+    } else {
+        // FIXME: Non-editable pieces inside editable content should be atomic, in the same way that editable
+        // pieces in non-editable content are atomic.
+    
+        // The selection ends in editable content or non-editable content inside a different editable ancestor,
+        // move backward until non-editable content inside the same lowest editable ancestor is reached.
+        NodeImpl* endEditableAncestor = lowestEditableAncestor(m_end.node());
+        if (endRoot || endEditableAncestor != baseEditableAncestor) {
+            
+            Position p = previousVisuallyDistinctCandidate(m_end);
+            NodeImpl* shadowAncestor = endRoot ? endRoot->shadowAncestorNode() : 0;
+            if (p.isNull() && endRoot && (shadowAncestor != endRoot))
+                p = Position(shadowAncestor, maxDeepOffset(shadowAncestor));
+            while (p.isNotNull() && !(lowestEditableAncestor(p.node()) == baseEditableAncestor && !isEditablePosition(p))) {
+                NodeImpl* root = editableRootForPosition(p);
+                shadowAncestor = root ? root->shadowAncestorNode() : 0;
+                p = isAtomicNode(p.node()) ? positionBeforeNode(p.node()) : previousVisuallyDistinctCandidate(p);
+                if (p.isNull() && (shadowAncestor != root))
+                    p = Position(shadowAncestor, maxDeepOffset(shadowAncestor));
+            }
+            VisiblePosition previous(p);
+            
+            if (previous.isNull()) {
+                ASSERT_NOT_REACHED();
+                m_base = Position();
+                m_extent = Position();
+                validate();
+                return;
+            }
+            m_end = previous.deepEquivalent();
+        }
+
+        // The selection starts in editable content or non-editable content inside a different editable ancestor,
+        // move forward until non-editable content inside the same lowest editable ancestor is reached.
+        NodeImpl* startEditableAncestor = lowestEditableAncestor(m_start.node());      
+        if (startRoot || startEditableAncestor != baseEditableAncestor) {
+            Position p = nextVisuallyDistinctCandidate(m_start);
+            NodeImpl* shadowAncestor = startRoot ? startRoot->shadowAncestorNode() : 0;
+            if (p.isNull() && startRoot && (shadowAncestor != startRoot))
+                p = Position(shadowAncestor, 0);
+            while (p.isNotNull() && !(lowestEditableAncestor(p.node()) == baseEditableAncestor && !isEditablePosition(p))) {
+                NodeImpl* root = editableRootForPosition(p);
+                shadowAncestor = root ? root->shadowAncestorNode() : 0;
+                p = isAtomicNode(p.node()) ? positionAfterNode(p.node()) : nextVisuallyDistinctCandidate(p);
+                if (p.isNull() && (shadowAncestor != root))
+                    p = Position(shadowAncestor, 0);
+            }
+            VisiblePosition next(p);
+            
+            if (next.isNull()) {
+                ASSERT_NOT_REACHED();
+                m_base = Position();
+                m_extent = Position();
+                validate();
+                return;
+            }
+            m_start = next.deepEquivalent();
+        }
+    }
+    
+    // Correct the extent if necessary.
+    if (baseEditableAncestor != lowestEditableAncestor(m_extent.node()))
+        m_extent = m_baseIsFirst ? m_end : m_start;
+}
+
+bool Selection::isContentEditable() const
+{
+    return isEditablePosition(start());
+}
+
+bool Selection::isContentRichlyEditable() const
+{
+    return isRichlyEditablePosition(start());
+}
+
+ElementImpl* Selection::rootEditableElement() const
+{
+    return editableRootForPosition(start());
+}
+
+NodeImpl* Selection::shadowTreeRootNode() const
+{
+    //FIXME khtml return start().node() ? start().node()->shadowTreeRootNode() : 0;
+    return 0;
+}
+
+void Selection::debugPosition() const
+{
+    if (!m_start.node())
+        return;
+
+    fprintf(stderr, "Selection =================\n");
+
+    if (m_start == m_end) {
+        Position pos = m_start;
+        kDebug() << "pos: " << pos.node()->nodeName() << " " <<  pos.node() << " " << pos.offset() << endl;
+        //fprintf(stderr, "pos:        %s %p:%d\n", pos.node()->nodeName().utf8().data(), pos.node(), pos.offset());
+    } else {
+        Position pos = m_start;
+        kDebug() << "pos: " << pos.node()->nodeName() << " " <<  pos.node() << " " << pos.offset() << endl;
+        kDebug() << "-----------------------------------" << endl;
+        //fprintf(stderr, "start:      %s %p:%d\n", pos.node()->nodeName().utf8().data(), pos.node(), pos.offset());
+        //fprintf(stderr, "-----------------------------------\n");
+        pos = m_end;
+        kDebug() << "pos: " << pos.node()->nodeName() << " " <<  pos.node() << " " << pos.offset() << endl;
+        kDebug() << "-----------------------------------" << endl;
+        //fprintf(stderr, "end:        %s %p:%d\n", pos.node()->nodeName().utf8().data(), pos.node(), pos.offset());
+        //fprintf(stderr, "-----------------------------------\n");
+    }
+
+    fprintf(stderr, "================================\n");
+}
+
+#ifndef NDEBUG
+
+void Selection::formatForDebugger(char* buffer, unsigned length) const
+{
+    String result;
+    String s;
+    
+    if (isNone()) {
+        result = "<none>";
+    } else {
+        const int FormatBufferSize = 1024;
+        char s[FormatBufferSize];
+        result += "from ";
+        start().formatForDebugger(s, FormatBufferSize);
+        result += s;
+        result += " to ";
+        end().formatForDebugger(s, FormatBufferSize);
+        result += s;
+    }
+
+    strncpy(buffer, result.utf8().data(), length - 1);
+}
+
+void Selection::showTreeForThis() const
+{
+    if (start().node()) {
+        start().node()->showTreeAndMark(start().node(), "S", end().node(), "E");
+        fprintf(stderr, "start offset: %d, end offset: %d\n", start().offset(), end().offset());
+    }
+}
+
+#endif
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+
+void showTree(const WebCore::Selection& sel)
+{
+    sel.showTreeForThis();
+}
+
+void showTree(const WebCore::Selection* sel)
+{
+    if (sel)
+        sel->showTreeForThis();
+}
+
+#endif
diff --git a/khtml/xml/Selection.h b/khtml/xml/Selection.h
new file mode 100644
index 0000000..0e4d557
--- /dev/null
+++ b/khtml/xml/Selection.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Selection_h
+#define Selection_h
+
+#include "xml/VisiblePosition.h"
+
+namespace DOM {
+
+// FIXME: This really should be broken up into more than one concept.
+// Frame doesn't need the 3 boundaries in this enum.
+enum TextGranularity {
+    CharacterGranularity,
+    WordGranularity,
+    SentenceGranularity,
+    LineGranularity,
+    ParagraphGranularity,
+    SentenceBoundary,
+    LineBoundary,
+    ParagraphBoundary,
+    DocumentBoundary
+};
+
+class Position;
+
+const EAffinity SEL_DEFAULT_AFFINITY = DOWNSTREAM;
+
+class Selection {
+public:
+    enum EState { NONE, CARET, RANGE };
+    enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT };
+
+    Selection();
+
+    Selection(const Position&, EAffinity);
+    Selection(const Position&, const Position&, EAffinity);
+
+    Selection(const RangeImpl*, EAffinity = SEL_DEFAULT_AFFINITY);
+    
+    Selection(const VisiblePosition&);
+    Selection(const VisiblePosition&, const VisiblePosition&);
+
+    static Selection selectionFromContentsOfNode(NodeImpl*);
+
+    EState state() const { return m_state; }
+
+    void setAffinity(EAffinity affinity) { m_affinity = affinity; }
+    EAffinity affinity() const { return m_affinity; }
+
+    void setBase(const Position&);
+    void setBase(const VisiblePosition&);
+    void setExtent(const Position&);
+    void setExtent(const VisiblePosition&);
+    
+    Position base() const { return m_base; }
+    Position extent() const { return m_extent; }    
+    Position start() const { return m_start; }
+    Position end() const { return m_end; }
+    
+    VisiblePosition visibleStart() const { return VisiblePosition(m_start, isRange() ? DOWNSTREAM : affinity()); }
+    VisiblePosition visibleEnd() const { return VisiblePosition(m_end, isRange() ? UPSTREAM : affinity()); }
+
+    bool isNone() const { return state() == NONE; }
+    bool isCaret() const { return state() == CARET; }
+    bool isRange() const { return state() == RANGE; }
+    bool isCaretOrRange() const { return state() != NONE; }
+
+    bool isBaseFirst() const { return m_baseIsFirst; }
+
+    void appendTrailingWhitespace();
+
+    bool expandUsingGranularity(TextGranularity granularity);
+    TextGranularity granularity() const { return m_granularity; }
+
+    PassRefPtr<RangeImpl> toRange() const;
+    
+    ElementImpl* rootEditableElement() const;
+    bool isContentEditable() const;
+    bool isContentRichlyEditable() const;
+    NodeImpl* shadowTreeRootNode() const;
+    
+    void debugPosition() const;
+
+#ifndef NDEBUG
+    void formatForDebugger(char* buffer, unsigned length) const;
+    void showTreeForThis() const;
+#endif
+
+    void setWithoutValidation(const Position&, const Position&);
+
+private:
+    void validate();
+    void adjustForEditableContent();
+
+    Position m_base;                  // base position for the selection
+    Position m_extent;                // extent position for the selection
+    Position m_start;                 // start position for the selection
+    Position m_end;                   // end position for the selection
+
+    EAffinity m_affinity;             // the upstream/downstream affinity of the caret
+    TextGranularity m_granularity;   // granularity of start/end selection
+
+    // these are cached, can be recalculated by validate()
+    EState m_state;                   // the state of the selection
+    bool m_baseIsFirst;               // true if base is before the extent
+};
+
+inline bool operator==(const Selection& a, const Selection& b)
+{
+    return a.start() == b.start() && a.end() == b.end() && a.affinity() == b.affinity() && a.granularity() == b.granularity() && a.isBaseFirst() == b.isBaseFirst();
+}
+
+inline bool operator!=(const Selection& a, const Selection& b)
+{
+    return !(a == b);
+}
+
+// khtml: for debug
+inline QDebug operator<<(QDebug stream, const Selection& selection)
+{
+    return (stream << "[base:" << endl << selection.base() << endl
+            << "extent:" << endl << selection.extent() << endl
+            << "start:" << endl << selection.start() << endl
+            << "end:" << endl << selection.end() << "]");
+}
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+// Outside the WebCore namespace for ease of invocation from gdb.
+void showTree(const WebCore::Selection&);
+void showTree(const WebCore::Selection*);
+#endif
+
+#endif // Selection_h
diff --git a/khtml/xml/SelectionController.cpp b/khtml/xml/SelectionController.cpp
new file mode 100644
index 0000000..ba506d6
--- /dev/null
+++ b/khtml/xml/SelectionController.cpp
@@ -0,0 +1,1300 @@
+/*
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+  
+/*#include "config.h"
+#include "SelectionController.h"
+
+#include "CString.h"
+#include "DeleteSelectionCommand.h"
+#include "Document.h"
+#include "Editor.h"
+#include "Element.h"
+#include "EventHandler.h"
+#include "EventNames.h"
+#include "ExceptionCode.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "HitTestRequest.h"
+#include "HitTestResult.h"
+#include "Page.h"
+#include "Range.h"
+#include "RenderTheme.h"
+#include "RenderView.h"
+#include "TextIterator.h"
+#include "TypingCommand.h"
+#include "htmlediting.h"
+#include "visible_units.h"
+#include <stdio.h>*/
+
+#include "xml/SelectionController.h"
+#include "xml/visible_units.h"
+#include "xml/editing_helper.h"
+#include "khtml_part.h"
+#include "editing/editor.h"
+#include "rendering/render_object.h"
+#include "rendering/render_canvas.h"
+#include "editing/htmlediting.h"
+#include "rendering/render_layer.h"
+#include "html/html_formimpl.h"
+
+#define EDIT_DEBUG 0
+
+using namespace khtml;
+
+namespace DOM {
+
+//using namespace HTMLNames;
+
+const int NoXPosForVerticalArrowNavigation = INT_MIN;
+
+SelectionController::SelectionController(KHTMLPart* frame, bool isDragCaretController)
+    : m_frame(frame)
+    , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation)
+    , m_needsLayout(true)
+    , m_absCaretBoundsDirty(true)
+    , m_lastChangeWasHorizontalExtension(false)
+    , m_isDragCaretController(isDragCaretController)
+    , m_isCaretBlinkingSuspended(false)
+    , m_focused(false)
+{
+}
+
+void SelectionController::moveTo(const VisiblePosition &pos, bool userTriggered)
+{
+    setSelection(Selection(pos.deepEquivalent(), pos.deepEquivalent(), pos.affinity()), true, true, userTriggered);
+}
+
+void SelectionController::moveTo(const VisiblePosition &base, const VisiblePosition &extent, bool userTriggered)
+{
+    setSelection(Selection(base.deepEquivalent(), extent.deepEquivalent(), base.affinity()), true, true, userTriggered);
+}
+
+void SelectionController::moveTo(const Position &pos, EAffinity affinity, bool userTriggered)
+{
+    setSelection(Selection(pos, affinity), true, true, userTriggered);
+}
+
+void SelectionController::moveTo(const RangeImpl *r, EAffinity affinity, bool userTriggered)
+{
+    setSelection(Selection(startPosition(r), endPosition(r), affinity), true, true, userTriggered);
+}
+
+void SelectionController::moveTo(const Position &base, const Position &extent, EAffinity affinity, bool userTriggered)
+{
+    setSelection(Selection(base, extent, affinity), true, true, userTriggered);
+}
+
+void SelectionController::setSelection(const Selection& s, bool closeTyping, bool clearTypingStyle, bool userTriggered)
+{
+    kDebug() << s << endl;
+    if (m_isDragCaretController) {
+        kDebug() << "drag caret, returning..." << endl;
+        invalidateCaretRect();
+        m_sel = s;
+        m_needsLayout = true;
+        invalidateCaretRect();
+        return;
+    }
+    if (!m_frame) {
+        m_sel = s;
+        return;
+    }
+
+    if (s.base().node() && s.base().node()->document() != m_frame->xmlDocImpl()) {
+        s.base().node()->document()->part()->selectionController()->setSelection(s, closeTyping, clearTypingStyle, userTriggered);
+        return;
+    }
+
+    if (closeTyping)
+        TypingCommand::closeTyping(m_frame->editor()->lastEditCommand());
+
+    if (clearTypingStyle)
+        kDebug() << "NOT IMPLEMENTED: clear typing style on part" << endl;
+        //FIXME khtml m_frame->clearTypingStyle();
+
+    if (m_sel == s)
+        return;
+
+    Selection oldSelection = m_sel;
+
+    m_sel = s;
+
+    m_needsLayout = true;
+
+    if (!s.isNone())
+        m_frame->setFocusedNodeIfNeeded();
+
+    m_frame->selectionLayoutChanged();
+    // Always clear the x position used for vertical arrow navigation.
+    // It will be restored by the vertical arrow navigation code if necessary.
+    m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation;
+    selectFrameElementInParentIfFullySelected();
+    m_frame->notifyRendererOfSelectionChange(userTriggered);
+    //FIXME khtml m_frame->respondToChangedSelection(oldSelection, closeTyping);
+    if (userTriggered)
+        kDebug() << "NOT IMPLEMENTED: reveal caret" << endl;
+        //FIXME khtml m_frame->revealCaret(RenderLayer::gAlignToEdgeIfNeeded);
+
+    notifyAccessibilityForSelectionChange();
+}
+
+static bool removingNodeRemovesPosition(NodeImpl* node, const Position& position)
+{
+    if (!position.node())
+        return false;
+        
+    if (position.node() == node)
+        return true;
+    
+    if (!node->isElementNode())
+        return false;
+    
+    ElementImpl* element = static_cast<ElementImpl*>(node);
+    return element->contains(position.node()) || element->contains(position.node()->shadowAncestorNode());
+}
+
+void SelectionController::nodeWillBeRemoved(NodeImpl *node)
+{
+    if (isNone())
+        return;
+        
+    // There can't be a selection inside a fragment, so if a fragment's node is being removed,
+    // the selection in the document that created the fragment needs no adjustment.
+    if (node && highestAncestor(node)->nodeType() == Node::DOCUMENT_FRAGMENT_NODE)
+        return;
+    
+    bool baseRemoved = removingNodeRemovesPosition(node, m_sel.base());
+    bool extentRemoved = removingNodeRemovesPosition(node, m_sel.extent());
+    bool startRemoved = removingNodeRemovesPosition(node, m_sel.start());
+    bool endRemoved = removingNodeRemovesPosition(node, m_sel.end());
+    
+    bool clearRenderTreeSelection = false;
+    bool clearDOMTreeSelection = false;
+
+    if (startRemoved || endRemoved) {
+        // FIXME: When endpoints are removed, we should just alter the selection, instead of blowing it away.
+        clearRenderTreeSelection = true;
+        clearDOMTreeSelection = true;
+    } else if (baseRemoved || extentRemoved) {
+        // The base and/or extent are about to be removed, but the start and end aren't.
+        // Change the base and extent to the start and end, but don't re-validate the
+        // selection, since doing so could move the start and end into the node
+        // that is about to be removed.
+        if (m_sel.isBaseFirst())
+            m_sel.setWithoutValidation(m_sel.start(), m_sel.end());
+        else
+            m_sel.setWithoutValidation(m_sel.end(), m_sel.start());
+    // FIXME: This could be more efficient if we had an isNodeInRange function on Ranges.
+    } else if (RangeImpl::compareBoundaryPoints(m_sel.start(), Position(node, 0)) == -1 &&
+               RangeImpl::compareBoundaryPoints(m_sel.end(), Position(node, 0)) == 1) {
+        // If we did nothing here, when this node's renderer was destroyed, the rect that it
+        // occupied would be invalidated, but, selection gaps that change as a result of
+        // the removal wouldn't be invalidated.
+        // FIXME: Don't do so much unnecessary invalidation.
+        clearRenderTreeSelection = true;
+    }
+
+    if (clearRenderTreeSelection) {
+        RefPtr<DocumentImpl> document = m_sel.start().node()->document();
+        document->updateRendering();
+        if (RenderCanvas* view = static_cast<RenderCanvas*>(document->renderer()))
+            view->clearSelection();
+    }
+
+    if (clearDOMTreeSelection)
+        setSelection(Selection(), false, false);
+}
+
+void SelectionController::willBeModified(EAlteration alter, EDirection direction)
+{
+    switch (alter) {
+        case MOVE:
+            m_lastChangeWasHorizontalExtension = false;
+            break;
+        case EXTEND:
+            if (!m_lastChangeWasHorizontalExtension) {
+                m_lastChangeWasHorizontalExtension = true;
+                Position start = m_sel.start();
+                Position end = m_sel.end();
+                switch (direction) {
+                    // FIXME: right for bidi?
+                    case RIGHT:
+                    case FORWARD:
+                        m_sel.setBase(start);
+                        m_sel.setExtent(end);
+                        break;
+                    case LEFT:
+                    case BACKWARD:
+                        m_sel.setBase(end);
+                        m_sel.setExtent(start);
+                        break;
+                }
+            }
+            break;
+    }
+}
+
+VisiblePosition SelectionController::modifyExtendingRightForward(TextGranularity granularity)
+{
+    VisiblePosition pos(m_sel.extent(), m_sel.affinity());
+    switch (granularity) {
+        case CharacterGranularity:
+            pos = pos.next(true);
+            break;
+        case WordGranularity:
+            pos = nextWordPosition(pos);
+            break;
+        case SentenceGranularity:
+            pos = nextSentencePosition(pos);
+            break;
+        case LineGranularity:
+            pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
+            break;
+        case ParagraphGranularity:
+            pos = nextParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
+            break;
+        case SentenceBoundary:
+            pos = endOfSentence(VisiblePosition(m_sel.end(), m_sel.affinity()));
+            break;
+        case LineBoundary:
+            pos = endOfLine(VisiblePosition(m_sel.end(), m_sel.affinity()));
+            break;
+        case ParagraphBoundary:
+            pos = endOfParagraph(VisiblePosition(m_sel.end(), m_sel.affinity()));
+            break;
+        case DocumentBoundary:
+            pos = VisiblePosition(m_sel.end(), m_sel.affinity());
+            if (isEditablePosition(pos.deepEquivalent()))
+                pos = endOfEditableContent(pos);
+            else
+                pos = endOfDocument(pos);
+            break;
+    }
+    
+    return pos;
+}
+
+VisiblePosition SelectionController::modifyMovingRight(TextGranularity granularity)
+{
+    VisiblePosition pos;
+    switch (granularity) {
+        case CharacterGranularity:
+            if (isRange())
+                pos = VisiblePosition(m_sel.end(), m_sel.affinity());
+            else
+                pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).right(true);
+            break;
+        case WordGranularity:
+        case SentenceGranularity:
+        case LineGranularity:
+        case ParagraphGranularity:
+        case SentenceBoundary:
+        case LineBoundary:
+        case ParagraphBoundary:
+        case DocumentBoundary:
+            // FIXME: Implement all of the above.
+            pos = modifyMovingForward(granularity);
+            break;
+    }
+    return pos;
+}
+
+VisiblePosition SelectionController::modifyMovingForward(TextGranularity granularity)
+{
+    VisiblePosition pos;
+    // FIXME: Stay in editable content for the less common granularities.
+    switch (granularity) {
+        case CharacterGranularity:
+            if (isRange())
+                pos = VisiblePosition(m_sel.end(), m_sel.affinity());
+            else
+                pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).next(true);
+            break;
+        case WordGranularity:
+            pos = nextWordPosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
+            break;
+        case SentenceGranularity:
+            pos = nextSentencePosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
+            break;
+        case LineGranularity: {
+            // down-arrowing from a range selection that ends at the start of a line needs
+            // to leave the selection at that line start (no need to call nextLinePosition!)
+            pos = VisiblePosition(m_sel.end(), m_sel.affinity());
+            if (!isRange() || !isStartOfLine(pos))
+                pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(START));
+            break;
+        }
+        case ParagraphGranularity:
+            pos = nextParagraphPosition(VisiblePosition(m_sel.end(), m_sel.affinity()), xPosForVerticalArrowNavigation(START));
+            break;
+        case SentenceBoundary:
+            pos = endOfSentence(VisiblePosition(m_sel.end(), m_sel.affinity()));
+            break;
+        case LineBoundary:
+            pos = endOfLine(VisiblePosition(m_sel.end(), m_sel.affinity()));
+            break;
+        case ParagraphBoundary:
+            pos = endOfParagraph(VisiblePosition(m_sel.end(), m_sel.affinity()));
+            break;
+        case DocumentBoundary:
+            pos = VisiblePosition(m_sel.end(), m_sel.affinity());
+            if (isEditablePosition(pos.deepEquivalent()))
+                pos = endOfEditableContent(pos);
+            else
+                pos = endOfDocument(pos);
+            break;
+            
+    }
+    return pos;
+}
+
+VisiblePosition SelectionController::modifyExtendingLeftBackward(TextGranularity granularity)
+{
+    VisiblePosition pos(m_sel.extent(), m_sel.affinity());
+        
+    // Extending a selection backward by word or character from just after a table selects
+    // the table.  This "makes sense" from the user perspective, esp. when deleting.
+    // It was done here instead of in VisiblePosition because we want VPs to iterate
+    // over everything.
+    switch (granularity) {
+        case CharacterGranularity:
+            pos = pos.previous(true);
+            break;
+        case WordGranularity:
+            pos = previousWordPosition(pos);
+            break;
+        case SentenceGranularity:
+            pos = previousSentencePosition(pos);
+            break;
+        case LineGranularity:
+            pos = previousLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
+            break;
+        case ParagraphGranularity:
+            pos = previousParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
+            break;
+        case SentenceBoundary:
+            pos = startOfSentence(VisiblePosition(m_sel.start(), m_sel.affinity()));
+            break;
+        case LineBoundary:
+            pos = startOfLine(VisiblePosition(m_sel.start(), m_sel.affinity()));
+            break;
+        case ParagraphBoundary:
+            pos = startOfParagraph(VisiblePosition(m_sel.start(), m_sel.affinity()));
+            break;
+        case DocumentBoundary:
+            pos = VisiblePosition(m_sel.start(), m_sel.affinity());
+            if (isEditablePosition(pos.deepEquivalent()))
+                pos = startOfEditableContent(pos);
+            else
+                pos = startOfDocument(pos);
+            break;
+    }
+    return pos;
+}
+
+VisiblePosition SelectionController::modifyMovingLeft(TextGranularity granularity)
+{
+    VisiblePosition pos;
+    switch (granularity) {
+        case CharacterGranularity:
+            if (isRange())
+                pos = VisiblePosition(m_sel.start(), m_sel.affinity());
+            else
+                pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).left(true);
+            break;
+        case WordGranularity:
+        case SentenceGranularity:
+        case LineGranularity:
+        case ParagraphGranularity:
+        case SentenceBoundary:
+        case LineBoundary:
+        case ParagraphBoundary:
+        case DocumentBoundary:
+            // FIXME: Implement all of the above.
+            pos = modifyMovingBackward(granularity);
+            break;
+    }
+    return pos;
+}
+
+VisiblePosition SelectionController::modifyMovingBackward(TextGranularity granularity)
+{
+    VisiblePosition pos;
+    switch (granularity) {
+        case CharacterGranularity:
+            if (isRange())
+                pos = VisiblePosition(m_sel.start(), m_sel.affinity());
+            else
+                pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).previous(true);
+            break;
+        case WordGranularity:
+            pos = previousWordPosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
+            break;
+        case SentenceGranularity:
+            pos = previousSentencePosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
+            break;
+        case LineGranularity:
+            pos = previousLinePosition(VisiblePosition(m_sel.start(), m_sel.affinity()), xPosForVerticalArrowNavigation(START));
+            break;
+        case ParagraphGranularity:
+            pos = previousParagraphPosition(VisiblePosition(m_sel.start(), m_sel.affinity()), xPosForVerticalArrowNavigation(START));
+            break;
+        case SentenceBoundary:
+            pos = startOfSentence(VisiblePosition(m_sel.start(), m_sel.affinity()));
+            break;
+        case LineBoundary:
+            pos = startOfLine(VisiblePosition(m_sel.start(), m_sel.affinity()));
+            break;
+        case ParagraphBoundary:
+            pos = startOfParagraph(VisiblePosition(m_sel.start(), m_sel.affinity()));
+            break;
+        case DocumentBoundary:
+            pos = VisiblePosition(m_sel.start(), m_sel.affinity());
+            if (isEditablePosition(pos.deepEquivalent()))
+                pos = startOfEditableContent(pos);
+            else
+                pos = startOfDocument(pos);
+            break;
+    }
+    return pos;
+}
+
+bool SelectionController::modify(EAlteration alter, EDirection dir, TextGranularity granularity, bool userTriggered)
+{
+    kDebug() << "modify" << alter << dir << granularity << userTriggered << endl;
+    if (userTriggered) {
+        SelectionController trialSelectionController;
+        trialSelectionController.setLastChangeWasHorizontalExtension(m_lastChangeWasHorizontalExtension);
+        trialSelectionController.setSelection(m_sel);
+        trialSelectionController.modify(alter, dir, granularity, false);
+
+        bool change = m_frame->shouldChangeSelection(trialSelectionController.selection());
+        if (!change)
+            return false;
+    }
+
+    if (m_frame)
+        m_frame->setSelectionGranularity(granularity);
+    
+    willBeModified(alter, dir);
+
+    VisiblePosition pos;
+    switch (dir) {
+        case RIGHT:
+            if (alter == MOVE)
+                pos = modifyMovingRight(granularity);
+            else
+                pos = modifyExtendingRightForward(granularity);
+            break;
+        case FORWARD:
+            if (alter == EXTEND)
+                pos = modifyExtendingRightForward(granularity);
+            else
+                pos = modifyMovingForward(granularity);
+            break;
+        case LEFT:
+            if (alter == MOVE)
+                pos = modifyMovingLeft(granularity);
+            else
+                pos = modifyExtendingLeftBackward(granularity);
+            break;
+        case BACKWARD:
+            if (alter == EXTEND)
+                pos = modifyExtendingLeftBackward(granularity);
+            else
+                pos = modifyMovingBackward(granularity);
+            break;
+    }
+
+    if (pos.isNull())
+        return false;
+    
+    // Some of the above operations set an xPosForVerticalArrowNavigation.
+    // Setting a selection will clear it, so save it to possibly restore later.
+    // Note: the START position type is arbitrary because it is unused, it would be
+    // the requested position type if there were no xPosForVerticalArrowNavigation set.
+    int x = xPosForVerticalArrowNavigation(START);
+
+    switch (alter) {
+        case MOVE:
+            moveTo(pos, userTriggered);
+            break;
+        case EXTEND:
+            setExtent(pos, userTriggered);
+            break;
+    }
+    
+    if (granularity == LineGranularity || granularity == ParagraphGranularity)
+        m_xPosForVerticalArrowNavigation = x;
+
+    if (userTriggered) {
+        // User modified selection change also sets the granularity back to character.
+        // NOTE: The one exception is that we need to keep word granularity to
+        // preserve smart delete behavior when extending by word (e.g. double-click),
+        // then shift-option-right arrow, then delete needs to smart delete, per TextEdit.
+        if (!(alter == EXTEND && granularity == WordGranularity && m_frame->selectionGranularity() == WordGranularity))
+            m_frame->setSelectionGranularity(CharacterGranularity);
+    }
+
+    setNeedsLayout();
+
+    return true;
+}
+
+// FIXME: Maybe baseline would be better?
+static bool absoluteCaretY(const VisiblePosition &c, int &y)
+{
+    QRect rect = c.absoluteCaretBounds();
+    if (rect.isEmpty())
+        return false;
+    y = rect.y() + rect.height() / 2;
+    return true;
+}
+
+bool SelectionController::modify(EAlteration alter, int verticalDistance, bool userTriggered)
+{
+    if (verticalDistance == 0)
+        return false;
+
+    if (userTriggered) {
+        SelectionController trialSelectionController;
+        trialSelectionController.setSelection(m_sel);
+        trialSelectionController.modify(alter, verticalDistance, false);
+
+        bool change = m_frame->shouldChangeSelection(trialSelectionController.selection());
+        if (!change)
+            return false;
+    }
+
+    bool up = verticalDistance < 0;
+    if (up)
+        verticalDistance = -verticalDistance;
+
+    willBeModified(alter, up ? BACKWARD : FORWARD);
+
+    VisiblePosition pos;
+    int xPos = 0;
+    switch (alter) {
+        case MOVE:
+            pos = VisiblePosition(up ? m_sel.start() : m_sel.end(), m_sel.affinity());
+            xPos = xPosForVerticalArrowNavigation(up ? START : END);
+            m_sel.setAffinity(up ? UPSTREAM : DOWNSTREAM);
+            break;
+        case EXTEND:
+            pos = VisiblePosition(m_sel.extent(), m_sel.affinity());
+            xPos = xPosForVerticalArrowNavigation(EXTENT);
+            m_sel.setAffinity(DOWNSTREAM);
+            break;
+    }
+
+    int startY;
+    if (!absoluteCaretY(pos, startY))
+        return false;
+    if (up)
+        startY = -startY;
+    int lastY = startY;
+
+    VisiblePosition result;
+    VisiblePosition next;
+    for (VisiblePosition p = pos; ; p = next) {
+        next = (up ? previousLinePosition : nextLinePosition)(p, xPos);
+        if (next.isNull() || next == p)
+            break;
+        int nextY;
+        if (!absoluteCaretY(next, nextY))
+            break;
+        if (up)
+            nextY = -nextY;
+        if (nextY - startY > verticalDistance)
+            break;
+        if (nextY >= lastY) {
+            lastY = nextY;
+            result = next;
+        }
+    }
+
+    if (result.isNull())
+        return false;
+
+    switch (alter) {
+        case MOVE:
+            moveTo(result, userTriggered);
+            break;
+        case EXTEND:
+            setExtent(result, userTriggered);
+            break;
+    }
+
+    if (userTriggered)
+        m_frame->setSelectionGranularity(CharacterGranularity);
+
+    return true;
+}
+
+bool SelectionController::expandUsingGranularity(TextGranularity granularity)
+{
+    if (isNone())
+        return false;
+
+    m_sel.expandUsingGranularity(granularity);
+    m_needsLayout = true;
+    return true;
+}
+
+int SelectionController::xPosForVerticalArrowNavigation(EPositionType type)
+{
+    int x = 0;
+
+    if (isNone())
+        return x;
+
+    Position pos;
+    switch (type) {
+        case START:
+            pos = m_sel.start();
+            break;
+        case END:
+            pos = m_sel.end();
+            break;
+        case BASE:
+            pos = m_sel.base();
+            break;
+        case EXTENT:
+            pos = m_sel.extent();
+            break;
+    }
+
+    KHTMLView *frame = pos.node()->document()->view();
+    if (!frame)
+        return x;
+        
+    if (m_xPosForVerticalArrowNavigation == NoXPosForVerticalArrowNavigation) {
+        VisiblePosition visiblePosition(pos, m_sel.affinity());
+        // VisiblePosition creation can fail here if a node containing the selection becomes visibility:hidden
+        // after the selection is created and before this function is called.
+        x = visiblePosition.isNotNull() ? visiblePosition.xOffsetForVerticalNavigation() : 0;
+        m_xPosForVerticalArrowNavigation = x;
+    }
+    else
+        x = m_xPosForVerticalArrowNavigation;
+        
+    return x;
+}
+
+void SelectionController::clear()
+{
+    setSelection(Selection());
+}
+
+void SelectionController::setBase(const VisiblePosition &pos, bool userTriggered)
+{
+    setSelection(Selection(pos.deepEquivalent(), m_sel.extent(), pos.affinity()), true, true, userTriggered);
+}
+
+void SelectionController::setExtent(const VisiblePosition &pos, bool userTriggered)
+{
+    setSelection(Selection(m_sel.base(), pos.deepEquivalent(), pos.affinity()), true, true, userTriggered);
+}
+
+void SelectionController::setBase(const Position &pos, EAffinity affinity, bool userTriggered)
+{
+    setSelection(Selection(pos, m_sel.extent(), affinity), true, true, userTriggered);
+}
+
+void SelectionController::setExtent(const Position &pos, EAffinity affinity, bool userTriggered)
+{
+    setSelection(Selection(m_sel.base(), pos, affinity), true, true, userTriggered);
+}
+
+void SelectionController::setNeedsLayout(bool flag)
+{
+    m_needsLayout = flag;
+}
+
+void SelectionController::layout()
+{
+    if (isNone() || !m_sel.start().node()->inDocument() || !m_sel.end().node()->inDocument()) {
+        m_caretRect = QRect();
+        return;
+    }
+    kDebug() << "in layout" << endl;
+
+    m_sel.start().node()->document()->updateRendering();
+    
+    m_caretRect = QRect();
+        
+    if (isCaret()) {
+        kDebug() << "caret selection" << endl;
+        VisiblePosition pos(m_sel.start(), m_sel.affinity());
+        if (pos.isNotNull()) {
+            kDebug() << "position not null" << endl;
+            ASSERT(pos.deepEquivalent().node()->renderer());
+            
+            // First compute a rect local to the renderer at the selection start
+            RenderObject* renderer;
+            QRect localRect = pos.localCaretRect(renderer);
+            if (renderer) kDebug() << "renderer for rect:" << renderer->renderName() << endl;
+
+            kDebug() << "local caret rect:" << localRect << endl;
+
+            // Get the renderer that will be responsible for painting the caret (which
+            // is either the renderer we just found, or one of its containers)
+            RenderObject* caretPainter = caretRenderer();
+
+            // Compute an offset between the renderer and the caretPainter
+            QSize offsetFromPainter;
+            bool unrooted = false;
+            while (renderer != caretPainter) {
+                RenderObject* containerObject = renderer->container();
+                if (!containerObject) {
+                    unrooted = true;
+                    break;
+                }
+                kDebug() << "container:" << containerObject->renderName() << endl;
+                offsetFromPainter += renderer->offsetFromContainer(containerObject);
+                kDebug() << "new offset:" << offsetFromPainter << endl;
+                renderer = containerObject;
+            }
+            
+            if (!unrooted) {
+                // Move the caret rect to the coords of the painter
+                localRect.translate(offsetFromPainter.width(), offsetFromPainter.height());
+                kDebug() << "unrooted" << localRect << endl;
+                m_caretRect = localRect;
+            }
+            
+            m_absCaretBoundsDirty = true;
+        }
+    }
+
+    m_needsLayout = false;
+}
+
+RenderObject* SelectionController::caretRenderer() const
+{
+    NodeImpl* node = m_sel.start().node();
+    kDebug() << "selection node:" << getPrintableName(node->id()) << endl;
+    if (!node)
+        return 0;
+
+    RenderObject* renderer = node->renderer();
+    if (!renderer)
+        return 0;
+
+    // if caretNode is a block and caret is inside it then caret should be painted by that block
+    bool paintedByBlock = renderer->isBlockFlow() && caretRendersInsideNode(node);
+    return paintedByBlock ? renderer : renderer->containingBlock();
+}
+
+QRect SelectionController::localCaretRect() const
+{
+    if (m_needsLayout)
+        const_cast<SelectionController *>(this)->layout();
+    
+    return m_caretRect;
+}
+
+QRect SelectionController::absoluteCaretBounds()
+{
+    recomputeCaretRect();
+    return m_absCaretBounds;
+}
+
+static QRect repaintRectForCaret(QRect caret)
+{
+    if (caret.isEmpty())
+        return QRect();
+    // Ensure that the dirty rect intersects the block that paints the caret even in the case where
+    // the caret itself is just outside the block. See <https://bugs.webkit.org/show_bug.cgi?id=19086>.
+    //caret.inflateX(1);
+    caret.setX(caret.x() - 1);
+    caret.setWidth(caret.width() + 2);
+    return caret;
+}
+
+QRect SelectionController::caretRepaintRect() const
+{
+    QRect localRect = repaintRectForCaret(localCaretRect());
+    
+    RenderObject* caretPainter = caretRenderer();
+    if (caretPainter) {
+        kDebug() << "caret painter:" << caretPainter->renderName() << endl;
+        kDebug() << "Local caret rect:" << localRect << endl;
+        int absx, absy;
+        caretPainter->absolutePosition(absx, absy);
+        kDebug() << "absolute position" << absx << absy << endl;
+        localRect.translate(absx, absy);
+        kDebug() << "absolute rect:" << localRect << endl;
+        return localRect;
+        // FIXME return QRect(x0, y0, x - x0, y - y0);
+        // FIXME return caretPainter->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
+    }
+
+    return QRect();
+}
+
+bool SelectionController::recomputeCaretRect()
+{
+    if (!m_frame || !m_frame->xmlDocImpl())
+        return false;
+        
+    //FrameView* v = m_frame->document()->view();
+    KHTMLView* v = m_frame->xmlDocImpl()->view();
+    if (!v)
+        return false;
+
+    if (!m_needsLayout)
+        return false;
+
+    QRect oldRect = m_caretRect;
+    m_needsLayout = true;
+    QRect newRect = localCaretRect();
+    if (oldRect == newRect && !m_absCaretBoundsDirty)
+        return false;
+
+    QRect oldAbsRepaintRect = m_absCaretBounds;
+    m_absCaretBounds = caretRepaintRect();
+    m_absCaretBoundsDirty = false;
+    
+    if (oldAbsRepaintRect == m_absCaretBounds)
+        return false;
+    
+    if (RenderCanvas* view = static_cast<RenderCanvas*>(m_frame->xmlDocImpl()->renderer())) {
+        kDebug() << "repaint old:" << oldAbsRepaintRect << endl;
+        view->repaintViewRectangle(oldAbsRepaintRect, false);
+        kDebug() << "repaint new:" << m_absCaretBounds << endl;
+        view->repaintViewRectangle(m_absCaretBounds, false);
+    }
+
+    return true;
+}
+
+void SelectionController::invalidateCaretRect()
+{
+    if (!isCaret())
+        return;
+
+    DocumentImpl* d = m_sel.start().node()->document();
+
+    // recomputeCaretRect will always return false for the drag caret,
+    // because its m_frame is always 0.
+    bool caretRectChanged = recomputeCaretRect();
+
+    // EDIT FIXME: This is an unfortunate hack.
+    // Basically, we can't trust this layout position since we
+    // can't guarantee that the check to see if we are in unrendered
+    // content will work at this point. We may have to wait for
+    // a layout and re-render of the document to happen. So, resetting this
+    // flag will cause another caret layout to happen the first time
+    // that we try to paint the caret after this call. That one will work since
+    // it happens after the document has accounted for any editing
+    // changes which may have been done.
+    // And, we need to leave this layout here so the caret moves right
+    // away after clicking.
+    m_needsLayout = true;
+
+    if (!caretRectChanged) {
+        if (RenderCanvas* view = static_cast<RenderCanvas*>(d->renderer()))
+            view->repaintViewRectangle(caretRepaintRect(), false);
+    }
+}
+
+void SelectionController::paintCaret(QPainter* p, int tx, int ty, const QRect& clipRect)
+{
+    kDebug() << "paint at" << tx << ty << "clip" << clipRect << endl;
+    kDebug() << "selection is caret:" << m_sel.isCaret() << endl;
+    if (! m_sel.isCaret())
+        return;
+
+    if (m_needsLayout)
+        layout();
+
+    QRect drawingRect = localCaretRect();
+    drawingRect.translate(tx, ty);
+    QRect caret = drawingRect;//FIXME khtml .intersected(clipRect);
+    kDebug() << "caret rect:" << caret << endl;
+    if (!caret.isEmpty()) {
+        QColor caretColor = Qt::black;
+        ElementImpl* element = rootEditableElement();
+        if (element && element->renderer())
+            caretColor = element->renderer()->style()->color();
+
+        p->fillRect(caret, caretColor);
+    }
+}
+
+void SelectionController::debugRenderer(RenderObject *r, bool selected) const
+{
+// FIXME khtml port
+#if 0
+    if (r->node()->isElementNode()) {
+        Element *element = static_cast<Element *>(r->node());
+        fprintf(stderr, "%s%s\n", selected ? "==> " : "    ", element->localName().string().utf8().data());
+    }
+    else if (r->isText()) {
+        RenderText* textRenderer = static_cast<RenderText*>(r);
+        if (textRenderer->textLength() == 0 || !textRenderer->firstTextBox()) {
+            fprintf(stderr, "%s#text (empty)\n", selected ? "==> " : "    ");
+            return;
+        }
+        
+        static const int max = 36;
+        DOMString text = textRenderer->text();
+        int textLength = text.length();
+        if (selected) {
+            int offset = 0;
+            if (r->node() == m_sel.start().node())
+                offset = m_sel.start().offset();
+            else if (r->node() == m_sel.end().node())
+                offset = m_sel.end().offset();
+                
+            int pos;
+            InlineTextBox *box = textRenderer->findNextInlineTextBox(offset, pos);
+            text = text.substring(box->m_start, box->m_len);
+            
+            DOMString show;
+            int mid = max / 2;
+            int caret = 0;
+            
+            // text is shorter than max
+            if (textLength < max) {
+                show = text;
+                caret = pos;
+            }
+            
+            // too few characters to left
+            else if (pos - mid < 0) {
+                show = text.left(max - 3) + "...";
+                caret = pos;
+            }
+            
+            // enough characters on each side
+            else if (pos - mid >= 0 && pos + mid <= textLength) {
+                show = "..." + text.substring(pos - mid + 3, max - 6) + "...";
+                caret = mid;
+            }
+            
+            // too few characters on right
+            else {
+                show = "..." + text.right(max - 3);
+                caret = pos - (textLength - show.length());
+            }
+            
+            show.replace('\n', ' ');
+            show.replace('\r', ' ');
+            fprintf(stderr, "==> #text : \"%s\" at offset %d\n", show.utf8().data(), pos);
+            fprintf(stderr, "           ");
+            for (int i = 0; i < caret; i++)
+                fprintf(stderr, " ");
+            fprintf(stderr, "^\n");
+        }
+        else {
+            if ((int)text.length() > max)
+                text = text.left(max - 3) + "...";
+            else
+                text = text.left(max);
+            fprintf(stderr, "    #text : \"%s\"\n", text.utf8().data());
+        }
+    }
+#endif
+}
+
+bool SelectionController::contains(const QPoint& point)
+{
+    DocumentImpl* document = m_frame->xmlDocImpl();
+    
+    // Treat a collapsed selection like no selection.
+    if (!isRange())
+        return false;
+    if (!document->renderer())
+        return false;
+
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    return false;
+    
+    /*HitTestRequest request(true, true);
+    HitTestResult result(point);
+    document->renderer()->layer()->hitTest(request, result);
+    NodeImpl* innerNode = result.innerNode();
+    if (!innerNode || !innerNode->renderer())
+        return false;
+    
+    VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(result.localPoint()));
+    if (visiblePos.isNull())
+        return false;
+        
+    if (m_sel.visibleStart().isNull() || m_sel.visibleEnd().isNull())
+        return false;
+        
+    Position start(m_sel.visibleStart().deepEquivalent());
+    Position end(m_sel.visibleEnd().deepEquivalent());
+    Position p(visiblePos.deepEquivalent());
+
+    return comparePositions(start, p) <= 0 && comparePositions(p, end) <= 0;*/
+}
+
+// Workaround for the fact that it's hard to delete a frame.
+// Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
+// Can't do this implicitly as part of every setSelection call because in some contexts it might not be good
+// for the focus to move to another frame. So instead we call it from places where we are selecting with the
+// mouse or the keyboard after setting the selection.
+void SelectionController::selectFrameElementInParentIfFullySelected()
+{
+    // Find the parent frame; if there is none, then we have nothing to do.
+    kDebug() << "frame deletion is not yet implemented" << endl;
+    return;
+#if 0
+    Frame* parent = m_frame->tree()->parent();
+    if (!parent)
+        return;
+    Page* page = m_frame->page();
+    if (!page)
+        return;
+
+    // Check if the selection contains the entire frame contents; if not, then there is nothing to do.
+    if (!isRange())
+        return;
+    if (!isStartOfDocument(selection().visibleStart()))
+        return;
+    if (!isEndOfDocument(selection().visibleEnd()))
+        return;
+
+    // Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
+    DocumentImpl* doc = m_frame->xmlDocImpl();
+    if (!doc)
+        return;
+    ElementImpl* ownerElement = doc->ownerElement();
+    if (!ownerElement)
+        return;
+    NodeImpl* ownerElementParent = ownerElement->parentNode();
+    if (!ownerElementParent)
+        return;
+        
+    // This method's purpose is it to make it easier to select iframes (in order to delete them).  Don't do anything if the iframe isn't deletable.
+    if (!ownerElementParent->isContentEditable())
+        return;
+
+    // Create compute positions before and after the element.
+    unsigned ownerElementNodeIndex = ownerElement->nodeIndex();
+    VisiblePosition beforeOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex, SEL_DEFAULT_AFFINITY));
+    VisiblePosition afterOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex + 1, VP_UPSTREAM_IF_POSSIBLE));
+
+    // Focus on the parent frame, and then select from before this element to after.
+    Selection newSelection(beforeOwnerElement, afterOwnerElement);
+    if (parent->shouldChangeSelection(newSelection)) {
+        page->focusController()->setFocusedFrame(parent);
+        parent->selection()->setSelection(newSelection);
+    }
+#endif
+}
+
+void SelectionController::selectAll()
+{
+    DocumentImpl* document = m_frame->xmlDocImpl();
+    if (!document)
+        return;
+    
+    if (document->focusedNode() && document->focusedNode()->canSelectAll()) {
+        document->focusedNode()->selectAll();
+        return;
+    }
+    
+    NodeImpl* root = 0;
+    if (isContentEditable())
+        root = highestEditableRoot(m_sel.start());
+    else {
+        root = shadowTreeRootNode();
+        if (!root)
+            root = document->documentElement();
+    }
+    if (!root)
+        return;
+    Selection newSelection(Selection::selectionFromContentsOfNode(root));
+    if (m_frame->shouldChangeSelection(newSelection))
+        setSelection(newSelection);
+    selectFrameElementInParentIfFullySelected();
+    m_frame->notifyRendererOfSelectionChange(true);
+}
+
+bool SelectionController::setSelectedRange(RangeImpl* range, EAffinity affinity, bool closeTyping)
+{
+    if (!range)
+        return false;
+
+    /*ExceptionCode*/int ec = 0;
+    NodeImpl* startContainer = range->startContainer(ec);
+    if (ec)
+        return false;
+
+    NodeImpl* endContainer = range->endContainer(ec);
+    if (ec)
+        return false;
+    
+    ASSERT(startContainer);
+    ASSERT(endContainer);
+    ASSERT(startContainer->document() == endContainer->document());
+    
+    m_frame->xmlDocImpl()->updateLayout/*IgnorePendingStylesheets*/();
+
+    // Non-collapsed ranges are not allowed to start at the end of a line that is wrapped,
+    // they start at the beginning of the next line instead
+    bool collapsed = range->collapsed(ec);
+    if (ec)
+        return false;
+    
+    int startOffset = range->startOffset(ec);
+    if (ec)
+        return false;
+
+    int endOffset = range->endOffset(ec);
+    if (ec)
+        return false;
+    
+    // FIXME: Can we provide extentAffinity?
+    VisiblePosition visibleStart(startContainer, startOffset, collapsed ? affinity : DOWNSTREAM);
+    VisiblePosition visibleEnd(endContainer, endOffset, SEL_DEFAULT_AFFINITY);
+    setSelection(Selection(visibleStart, visibleEnd), closeTyping);
+    return true;
+}
+
+bool SelectionController::isInPasswordField() const
+{
+    NodeImpl* startNode = start().node();
+    if (!startNode)
+        return false;
+
+    startNode = startNode->shadowAncestorNode();
+    if (!startNode)
+        return false;
+
+    if (!startNode->hasTagName(/*inputTag*/ID_INPUT))
+        return false;
+    
+    return static_cast<HTMLInputElementImpl*>(startNode)->inputType() == HTMLInputElementImpl::PASSWORD;
+}
+
+bool SelectionController::caretRendersInsideNode(NodeImpl* node) const
+{
+    if (!node)
+        return false;
+    return !isTableElement(node) && !editingIgnoresContent(node);
+}
+
+void SelectionController::focusedOrActiveStateChanged()
+{
+    bool activeAndFocused = isFocusedAndActive();
+
+    // Because RenderObject::selectionBackgroundColor() and
+    // RenderObject::selectionForegroundColor() check if the frame is active,
+    // we have to update places those colors were painted.
+    if (RenderCanvas* view = static_cast<RenderCanvas*>(m_frame->xmlDocImpl()->renderer()))
+        kDebug() << "NOT IMPLEMENTED" << "should repaint some rectangle" << endl;
+        // view->repaintViewRectangle(enclosingIntRect(m_frame->selectionBounds()));
+
+    // Caret appears in the active frame.
+    if (activeAndFocused)
+        m_frame->setSelectionFromNone();
+    m_frame->setCaretVisible(activeAndFocused);
+// FIXME khtml port
+#if 0
+    // Update for caps lock state
+    m_frame->eventHandler()->capsLockStateMayHaveChanged();
+
+    // Because CSSStyleSelector::checkOneSelector() and
+    // RenderTheme::isFocused() check if the frame is active, we have to
+    // update style and theme state that depended on those.
+    if (NodeImpl* node = m_frame->xmlDocImpl()->focusedNode()) {
+        node->setChanged();
+        if (RenderObject* renderer = node->renderer())
+            if (renderer && renderer->style()->hasAppearance())
+                theme()->stateChanged(renderer, FocusState);
+    }
+
+    // Secure keyboard entry is set by the active frame.
+    if (m_frame->xmlDocImpl()->useSecureKeyboardEntryWhenActive())
+        m_frame->setUseSecureKeyboardEntry(activeAndFocused);
+#endif
+}
+
+void SelectionController::pageActivationChanged()
+{
+    focusedOrActiveStateChanged();
+}
+
+void SelectionController::setFocused(bool flag)
+{
+    if (m_focused == flag)
+        return;
+    m_focused = flag;
+
+    focusedOrActiveStateChanged();
+
+    if (DocumentImpl* doc = m_frame->xmlDocImpl())
+        kDebug() << "NOT IMPLEMENTED: dispatchWindowEvent" << endl;
+        //FIXME khtml doc->dispatchWindowEvent(flag ? eventNames().focusEvent : eventNames().blurEvent, false, false);
+}
+
+bool SelectionController::isFocusedAndActive() const
+{
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    return true;
+    //FIXME khtml port return m_focused && m_frame->page() && m_frame->page()->focusController()->isActive();
+}
+
+#ifndef NDEBUG
+
+void SelectionController::formatForDebugger(char* buffer, unsigned length) const
+{
+    m_sel.formatForDebugger(buffer, length);
+}
+
+void SelectionController::showTreeForThis() const
+{
+    m_sel.showTreeForThis();
+}
+
+#endif
+
+}
+
+#ifndef NDEBUG
+
+void showTree(const WebCore::SelectionController& sel)
+{
+    sel.showTreeForThis();
+}
+
+void showTree(const WebCore::SelectionController* sel)
+{
+    if (sel)
+        sel->showTreeForThis();
+}
+
+#endif
diff --git a/khtml/xml/SelectionController.h b/khtml/xml/SelectionController.h
new file mode 100644
index 0000000..e66d457
--- /dev/null
+++ b/khtml/xml/SelectionController.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SelectionController_h
+#define SelectionController_h
+
+#include "Selection.h"
+#include "xml/dom2_rangeimpl.h"
+#include <wtf/Noncopyable.h>
+#include "dom/dom2_range.h"
+
+class KHTMLPart;
+
+namespace DOM {
+
+class VisiblePosition;
+
+class SelectionController : Noncopyable {
+public:
+    enum EAlteration { MOVE, EXTEND };
+    enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT };
+
+    SelectionController(KHTMLPart* = 0, bool isDragCaretController = false);
+
+    ElementImpl* rootEditableElement() const { return m_sel.rootEditableElement(); }
+    bool isContentEditable() const { return m_sel.isContentEditable(); }
+    bool isContentRichlyEditable() const { return m_sel.isContentRichlyEditable(); }
+    NodeImpl* shadowTreeRootNode() const { return m_sel.shadowTreeRootNode(); }
+    
+    void moveTo(const RangeImpl*, EAffinity, bool userTriggered = false);
+    void moveTo(const VisiblePosition&, bool userTriggered = false);
+    void moveTo(const VisiblePosition&, const VisiblePosition&, bool userTriggered = false);
+    void moveTo(const Position&, EAffinity, bool userTriggered = false);
+    void moveTo(const Position&, const Position&, EAffinity, bool userTriggered = false);
+
+    const Selection& selection() const { return m_sel; }
+    void setSelection(const Selection&, bool closeTyping = true, bool clearTypingStyle = true, bool userTriggered = false);
+    bool setSelectedRange(RangeImpl*, EAffinity, bool closeTyping);
+    void selectAll();
+    void clear();
+    
+    // Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
+    void selectFrameElementInParentIfFullySelected();
+
+    bool contains(const QPoint&);
+
+    Selection::EState state() const { return m_sel.state(); }
+
+    EAffinity affinity() const { return m_sel.affinity(); }
+
+    bool modify(EAlteration, EDirection, TextGranularity, bool userTriggered = false);
+    bool modify(EAlteration, int verticalDistance, bool userTriggered = false);
+    bool expandUsingGranularity(TextGranularity);
+
+    void setBase(const VisiblePosition&, bool userTriggered = false);
+    void setBase(const Position&, EAffinity, bool userTriggered = false);
+    void setExtent(const VisiblePosition&, bool userTriggered = false);
+    void setExtent(const Position&, EAffinity, bool userTriggered = false);
+
+    Position base() const { return m_sel.base(); }
+    Position extent() const { return m_sel.extent(); }
+    Position start() const { return m_sel.start(); }
+    Position end() const { return m_sel.end(); }
+
+    // Return the renderer that is responsible for painting the caret (in the selection start node)
+    RenderObject* caretRenderer() const;
+
+    // Caret rect local to the caret's renderer
+    QRect localCaretRect() const;
+    // Bounds of (possibly transformed) caret in absolute coords
+    QRect absoluteCaretBounds();
+    void setNeedsLayout(bool flag = true);
+
+    void setLastChangeWasHorizontalExtension(bool b) { m_lastChangeWasHorizontalExtension = b; }
+    void willBeModified(EAlteration, EDirection);
+    
+    bool isNone() const { return m_sel.isNone(); }
+    bool isCaret() const { return m_sel.isCaret(); }
+    bool isRange() const { return m_sel.isRange(); }
+    bool isCaretOrRange() const { return m_sel.isCaretOrRange(); }
+    bool isInPasswordField() const;
+    
+    PassRefPtr<RangeImpl> toRange() const { return m_sel.toRange(); }
+    Range toDOMRange() const { return Range(start().node(), start().offset(), end().node(), end().offset()); }
+
+    void debugRenderer(RenderObject*, bool selected) const;
+    
+    void nodeWillBeRemoved(NodeImpl*);
+
+    bool recomputeCaretRect(); // returns true if caret rect moved
+    void invalidateCaretRect();
+    void paintCaret(QPainter* p, int tx, int ty, const QRect& clipRect);
+
+    // Used to suspend caret blinking while the mouse is down.
+    void setCaretBlinkingSuspended(bool suspended) { m_isCaretBlinkingSuspended = suspended; }
+    bool isCaretBlinkingSuspended() const { return m_isCaretBlinkingSuspended; }
+
+    // Focus
+    void setFocused(bool);
+    bool isFocusedAndActive() const;
+    void pageActivationChanged();
+
+#ifndef NDEBUG
+    void formatForDebugger(char* buffer, unsigned length) const;
+    void showTreeForThis() const;
+#endif
+
+private:
+    enum EPositionType { START, END, BASE, EXTENT };
+
+    VisiblePosition modifyExtendingRightForward(TextGranularity);
+    VisiblePosition modifyMovingRight(TextGranularity);
+    VisiblePosition modifyMovingForward(TextGranularity);
+    VisiblePosition modifyExtendingLeftBackward(TextGranularity);
+    VisiblePosition modifyMovingLeft(TextGranularity);
+    VisiblePosition modifyMovingBackward(TextGranularity);
+
+    void layout();
+    QRect caretRepaintRect() const;
+
+    int xPosForVerticalArrowNavigation(EPositionType);
+    
+/*#if PLATFORM(MAC)
+    void notifyAccessibilityForSelectionChange();
+#else*/
+    void notifyAccessibilityForSelectionChange() {};
+//#endif
+
+    void focusedOrActiveStateChanged();
+    bool caretRendersInsideNode(NodeImpl*) const;
+
+    //Frame* m_frame;
+    KHTMLPart* m_frame;
+    int m_xPosForVerticalArrowNavigation;
+
+    Selection m_sel;
+
+    QRect m_caretRect;        // caret rect in coords local to the renderer responsible for painting the caret
+    QRect m_absCaretBounds;   // absolute bounding rect for the caret
+    
+    bool m_needsLayout : 1;       // true if the caret and expectedVisible rectangles need to be calculated
+    bool m_absCaretBoundsDirty: 1;
+    bool m_lastChangeWasHorizontalExtension : 1;
+    bool m_isDragCaretController : 1;
+    bool m_isCaretBlinkingSuspended : 1;
+    bool m_focused : 1;
+
+};
+
+inline bool operator==(const SelectionController& a, const SelectionController& b)
+{
+    return a.start() == b.start() && a.end() == b.end() && a.affinity() == b.affinity();
+}
+
+inline bool operator!=(const SelectionController& a, const SelectionController& b)
+{
+    return !(a == b);
+}
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+// Outside the WebCore namespace for ease of invocation from gdb.
+void showTree(const WebCore::SelectionController&);
+void showTree(const WebCore::SelectionController*);
+#endif
+
+#endif // SelectionController_h
diff --git a/khtml/xml/TextBreakIterator.h b/khtml/xml/TextBreakIterator.h
new file mode 100644
index 0000000..5f46de2
--- /dev/null
+++ b/khtml/xml/TextBreakIterator.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2006 Lars Knoll <lars@...>
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TextBreakIterator_h
+#define TextBreakIterator_h
+
+//#include <wtf/unicode/Unicode.h>
+#include <QChar>
+
+namespace khtml {
+
+    class TextBreakIterator;
+
+    // Note: The returned iterator is good only until you get another iterator.
+    TextBreakIterator* characterBreakIterator(const QChar*, int length);
+    TextBreakIterator* wordBreakIterator(const QChar*, int length);
+    TextBreakIterator* lineBreakIterator(const QChar*, int length);
+    TextBreakIterator* sentenceBreakIterator(const QChar*, int length);
+
+    int textBreakFirst(TextBreakIterator*);
+    int textBreakNext(TextBreakIterator*);
+    int textBreakCurrent(TextBreakIterator*);
+    int textBreakPreceding(TextBreakIterator*, int);
+    int textBreakFollowing(TextBreakIterator*, int);
+    bool isTextBreak(TextBreakIterator*, int);
+
+    const int TextBreakDone = -1;
+
+}
+
+#endif
diff --git a/khtml/xml/TextBreakIteratorICU.cpp b/khtml/xml/TextBreakIteratorICU.cpp
new file mode 100644
index 0000000..d889fde
--- /dev/null
+++ b/khtml/xml/TextBreakIteratorICU.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2006 Lars Knoll <lars@...>
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+//#include "config.h"
+#include "TextBreakIterator.h"
+
+#include "TextBreakIteratorInternalICU.h"
+
+//#include <unicode/ubrk.h>
+#include <wtf/Assertions.h>
+
+namespace khtml {
+
+static TextBreakIterator* setUpIterator(bool& createdIterator, TextBreakIterator*& iterator,
+    UBreakIteratorType type, const QChar* string, int length)
+{
+    if (!string)
+        return 0;
+
+    if (!createdIterator) {
+        UErrorCode openStatus = U_ZERO_ERROR;
+        iterator = static_cast<TextBreakIterator*>(ubrk_open(type, currentTextBreakLocaleID(), 0, 0, &openStatus));
+        createdIterator = true;
+        ASSERT_WITH_MESSAGE(U_SUCCESS(openStatus), "ICU could not open a break iterator: %s (%d)", u_errorName(openStatus), openStatus);
+    }
+    if (!iterator)
+        return 0;
+
+    UErrorCode setTextStatus = U_ZERO_ERROR;
+    ubrk_setText(iterator, string, length, &setTextStatus);
+    if (U_FAILURE(setTextStatus))
+        return 0;
+
+    return iterator;
+}
+
+TextBreakIterator* characterBreakIterator(const UChar* string, int length)
+{
+    static bool createdCharacterBreakIterator = false;
+    static TextBreakIterator* staticCharacterBreakIterator;
+    return setUpIterator(createdCharacterBreakIterator,
+        staticCharacterBreakIterator, UBRK_CHARACTER, string, length);
+}
+
+TextBreakIterator* wordBreakIterator(const UChar* string, int length)
+{
+    static bool createdWordBreakIterator = false;
+    static TextBreakIterator* staticWordBreakIterator;
+    return setUpIterator(createdWordBreakIterator,
+        staticWordBreakIterator, UBRK_WORD, string, length);
+}
+
+TextBreakIterator* lineBreakIterator(const UChar* string, int length)
+{
+    static bool createdLineBreakIterator = false;
+    static TextBreakIterator* staticLineBreakIterator;
+    return setUpIterator(createdLineBreakIterator,
+        staticLineBreakIterator, UBRK_LINE, string, length);
+}
+
+TextBreakIterator* sentenceBreakIterator(const UChar* string, int length)
+{
+    static bool createdSentenceBreakIterator = false;
+    static TextBreakIterator* staticSentenceBreakIterator;
+    return setUpIterator(createdSentenceBreakIterator,
+        staticSentenceBreakIterator, UBRK_SENTENCE, string, length);
+}
+
+int textBreakFirst(TextBreakIterator* bi)
+{
+    return ubrk_first(bi);
+}
+
+int textBreakNext(TextBreakIterator* bi)
+{
+    return ubrk_next(bi);
+}
+
+int textBreakPreceding(TextBreakIterator* bi, int pos)
+{
+    return ubrk_preceding(bi, pos);
+}
+
+int textBreakFollowing(TextBreakIterator* bi, int pos)
+{
+    return ubrk_following(bi, pos);
+}
+
+int textBreakCurrent(TextBreakIterator* bi)
+{
+    return ubrk_current(bi);
+}
+
+bool isTextBreak(TextBreakIterator* bi, int pos)
+{
+    return ubrk_isBoundary(bi, pos);
+}
+
+}
diff --git a/khtml/xml/TextBreakIteratorInternalICU.h b/khtml/xml/TextBreakIteratorInternalICU.h
new file mode 100644
index 0000000..d4b25e7
--- /dev/null
+++ b/khtml/xml/TextBreakIteratorInternalICU.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TextBreakIteratorInternalICU_h
+#define TextBreakIteratorInternalICU_h
+
+#include <wtf/unicode/Unicode.h>
+
+namespace WebCore {
+
+    const char* currentTextBreakLocaleID();
+
+}
+
+#endif
diff --git a/khtml/xml/VisiblePosition.cpp b/khtml/xml/VisiblePosition.cpp
new file mode 100644
index 0000000..2ec9201
--- /dev/null
+++ b/khtml/xml/VisiblePosition.cpp
@@ -0,0 +1,700 @@
+/*
+ * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "VisiblePosition.h"
+
+#include "xml/dom_docimpl.h"
+#include "editing/htmlediting.h"
+#include "xml/dom2_rangeimpl.h"
+
+#include "rendering/render_line.h"
+#include "xml/editing_helper.h"
+#include "xml/visible_units.h"
+
+/*#include "CString.h"
+#include "Document.h"
+#include "Element.h"
+#include "FloatRect.h"
+#include "HTMLNames.h"
+#include "InlineTextBox.h"
+#include "Logging.h"
+#include "Range.h"
+#include "Text.h"
+#include "htmlediting.h"
+#include "visible_units.h"
+#include <stdio.h>*/
+
+#define TextDirection EDirection
+
+using namespace khtml;
+
+namespace DOM {
+
+VisiblePosition::VisiblePosition(const Position &pos, EAffinity affinity)
+{
+    init(pos, affinity);
+}
+
+VisiblePosition::VisiblePosition(NodeImpl *node, int offset, EAffinity affinity)
+{
+    ASSERT(offset >= 0);
+    init(Position(node, offset), affinity);
+}
+
+void VisiblePosition::init(const Position& position, EAffinity affinity)
+{
+    m_affinity = affinity;
+
+    //kDebug() << "init VisiblePosition at position" << position << affinity << endl;
+    
+    m_deepPosition = canonicalPosition(position);
+
+    //kDebug() << "deep position" << m_deepPosition << endl;
+    // When not at a line wrap, make sure to end up with DOWNSTREAM affinity.
+    if (m_affinity == UPSTREAM && (isNull() || inSameLine(VisiblePosition(position, DOWNSTREAM), *this)))
+        m_affinity = DOWNSTREAM;
+}
+
+VisiblePosition VisiblePosition::next(bool stayInEditableContent) const
+{
+    VisiblePosition next(nextVisuallyDistinctCandidate(m_deepPosition), m_affinity);
+    
+    if (!stayInEditableContent)
+        return next;
+    
+    return honorEditableBoundaryAtOrAfter(next);
+}
+
+VisiblePosition VisiblePosition::previous(bool stayInEditableContent) const
+{
+    // find first previous DOM position that is visible
+    Position pos = previousVisuallyDistinctCandidate(m_deepPosition);
+    
+    // return null visible position if there is no previous visible position
+    if (pos.atStart())
+        return VisiblePosition();
+        
+    VisiblePosition prev = VisiblePosition(pos, DOWNSTREAM);
+    ASSERT(prev != *this);
+    
+#ifndef NDEBUG
+    // we should always be able to make the affinity DOWNSTREAM, because going previous from an
+    // UPSTREAM position can never yield another UPSTREAM position (unless line wrap length is 0!).
+    if (prev.isNotNull() && m_affinity == UPSTREAM) {
+        VisiblePosition temp = prev;
+        temp.setAffinity(UPSTREAM);
+        ASSERT(inSameLine(temp, prev));
+    }
+#endif
+
+    if (!stayInEditableContent)
+        return prev;
+    
+    return honorEditableBoundaryAtOrBefore(prev);
+}
+
+Position VisiblePosition::leftVisuallyDistinctCandidate() const
+{
+    Position p = m_deepPosition;
+    if (!p.node())
+        return Position();
+
+    Position downstreamStart = p.downstream();
+    TextDirection primaryDirection = LTR;
+    for (RenderObject* r = p.node()->renderer(); r; r = r->parent()) {
+        if (r->isBlockFlow()) {
+            primaryDirection = r->style()->direction();
+            break;
+        }
+    }
+
+    while (true) {
+        InlineBox* box;
+        int offset;
+        p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
+        if (!box)
+            return primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
+
+        RenderObject* renderer = box->object();
+
+        while (true) {
+            if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretRightmostOffset())
+                return box->direction() == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
+
+            offset = box->direction() == LTR ? renderer->previousOffset(offset) : renderer->nextOffset(offset);
+
+            int caretMinOffset = box->caretMinOffset();
+            int caretMaxOffset = box->caretMaxOffset();
+
+            if (offset > caretMinOffset && offset < caretMaxOffset)
+                break;
+
+            if (box->direction() == LTR ? offset < caretMinOffset : offset > caretMaxOffset) {
+                // Overshot to the left.
+                InlineBox* prevBox = box->prevLeafChild();
+                if (!prevBox)
+                    return primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
+
+                // Reposition at the other logical position corresponding to our edge's visual position and go for another round.
+                box = prevBox;
+                renderer = box->object();
+                offset = prevBox->caretRightmostOffset();
+                continue;
+            }
+
+            ASSERT(offset == box->caretLeftmostOffset());
+
+            unsigned char level = box->bidiLevel();
+            InlineBox* prevBox = box->prevLeafChild();
+
+            if (box->direction() == primaryDirection) {
+                if (!prevBox || prevBox->bidiLevel() >= level)
+                    break;
+
+                level = prevBox->bidiLevel();
+
+                InlineBox* nextBox = box;
+                do {
+                    nextBox = nextBox->nextLeafChild();
+                } while (nextBox && nextBox->bidiLevel() > level);
+
+                if (nextBox && nextBox->bidiLevel() == level)
+                    break;
+
+                while (InlineBox* prevBox = box->prevLeafChild()) {
+                    if (prevBox->bidiLevel() < level)
+                        break;
+                    box = prevBox;
+                }
+                renderer = box->object();
+                offset = box->caretRightmostOffset();
+                if (box->direction() == primaryDirection)
+                    break;
+                continue;
+            }
+
+            if (prevBox) {
+                box = prevBox;
+                renderer = box->object();
+                offset = box->caretRightmostOffset();
+                if (box->bidiLevel() > level) {
+                    do {
+                        prevBox = box->prevLeafChild();
+                    } while (prevBox && prevBox->bidiLevel() > level);
+
+                    if (!prevBox || prevBox->bidiLevel() < level)
+                        continue;
+                }
+            } else {
+                // Trailing edge of a secondary run. Set to the leading edge of the entire run.
+                while (true) {
+                    while (InlineBox* nextBox = box->nextLeafChild()) {
+                        if (nextBox->bidiLevel() < level)
+                            break;
+                        box = nextBox;
+                    }
+                    if (box->bidiLevel() == level)
+                        break;
+                    level = box->bidiLevel();
+                    while (InlineBox* prevBox = box->prevLeafChild()) {
+                        if (prevBox->bidiLevel() < level)
+                            break;
+                        box = prevBox;
+                    }
+                    if (box->bidiLevel() == level)
+                        break;
+                    level = box->bidiLevel();
+                }
+                renderer = box->object();
+                offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset();
+            }
+            break;
+        }
+
+        p = Position(renderer->element(), offset);
+
+        if (p.isCandidate() && p.downstream() != downstreamStart || p.atStart() || p.atEnd())
+            return p;
+    }
+}
+
+VisiblePosition VisiblePosition::left(bool stayInEditableContent) const
+{
+    Position pos = leftVisuallyDistinctCandidate();
+    if (pos.atStart() || pos.atEnd())
+        return VisiblePosition();
+
+    VisiblePosition left = VisiblePosition(pos, DOWNSTREAM);
+    ASSERT(left != *this);
+
+    if (!stayInEditableContent)
+        return left;
+
+    // FIXME: This may need to do something different from "before".
+    return honorEditableBoundaryAtOrBefore(left);
+}
+
+Position VisiblePosition::rightVisuallyDistinctCandidate() const
+{
+    Position p = m_deepPosition;
+    if (!p.node())
+        return Position();
+
+    Position downstreamStart = p.downstream();
+    TextDirection primaryDirection = LTR;
+    for (RenderObject* r = p.node()->renderer(); r; r = r->parent()) {
+        if (r->isBlockFlow()) {
+            primaryDirection = r->style()->direction();
+            break;
+        }
+    }
+
+    while (true) {
+        InlineBox* box;
+        int offset;
+        p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
+        if (!box)
+            return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
+
+        RenderObject* renderer = box->object();
+
+        while (true) {
+            if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretLeftmostOffset())
+                return box->direction() == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
+
+            offset = box->direction() == LTR ? renderer->nextOffset(offset) : renderer->previousOffset(offset);
+
+            int caretMinOffset = box->caretMinOffset();
+            int caretMaxOffset = box->caretMaxOffset();
+
+            if (offset > caretMinOffset && offset < caretMaxOffset)
+                break;
+
+            if (box->direction() == LTR ? offset > caretMaxOffset : offset < caretMinOffset) {
+                // Overshot to the right.
+                InlineBox* nextBox = box->nextLeafChild();
+                if (!nextBox)
+                    return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
+
+                // Reposition at the other logical position corresponding to our edge's visual position and go for another round.
+                box = nextBox;
+                renderer = box->object();
+                offset = nextBox->caretLeftmostOffset();
+                continue;
+            }
+
+            ASSERT(offset == box->caretRightmostOffset());
+
+            unsigned char level = box->bidiLevel();
+            InlineBox* nextBox = box->nextLeafChild();
+
+            if (box->direction() == primaryDirection) {
+                if (!nextBox || nextBox->bidiLevel() >= level)
+                    break;
+
+                level = nextBox->bidiLevel();
+
+                InlineBox* prevBox = box;
+                do {
+                    prevBox = prevBox->prevLeafChild();
+                } while (prevBox && prevBox->bidiLevel() > level);
+
+                if (prevBox && prevBox->bidiLevel() == level)   // For example, abc FED 123 ^ CBA
+                    break;
+
+                // For example, abc 123 ^ CBA
+                while (InlineBox* nextBox = box->nextLeafChild()) {
+                    if (nextBox->bidiLevel() < level)
+                        break;
+                    box = nextBox;
+                }
+                renderer = box->object();
+                offset = box->caretLeftmostOffset();
+                if (box->direction() == primaryDirection)
+                    break;
+                continue;
+            }
+
+            if (nextBox) {
+                box = nextBox;
+                renderer = box->object();
+                offset = box->caretLeftmostOffset();
+                if (box->bidiLevel() > level) {
+                    do {
+                        nextBox = box->nextLeafChild();
+                    } while (nextBox && nextBox->bidiLevel() > level);
+
+                    if (!nextBox || nextBox->bidiLevel() < level)
+                        continue;
+                }
+            } else {
+                // Trailing edge of a secondary run. Set to the leading edge of the entire run.
+                while (true) {
+                    while (InlineBox* prevBox = box->prevLeafChild()) {
+                        if (prevBox->bidiLevel() < level)
+                            break;
+                        box = prevBox;
+                    }
+                    if (box->bidiLevel() == level)
+                        break;
+                    level = box->bidiLevel();
+                    while (InlineBox* nextBox = box->nextLeafChild()) {
+                        if (nextBox->bidiLevel() < level)
+                            break;
+                        box = nextBox;
+                    }
+                    if (box->bidiLevel() == level)
+                        break;
+                    level = box->bidiLevel();
+                }
+                renderer = box->object();
+                offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset();
+            }
+            break;
+        }
+
+        p = Position(renderer->element(), offset);
+
+        if (p.isCandidate() && p.downstream() != downstreamStart || p.atStart() || p.atEnd())
+            return p;
+    }
+}
+
+VisiblePosition VisiblePosition::right(bool stayInEditableContent) const
+{
+    Position pos = rightVisuallyDistinctCandidate();
+    if (pos.atStart() || pos.atEnd())
+        return VisiblePosition();
+
+    VisiblePosition right = VisiblePosition(pos, DOWNSTREAM);
+    ASSERT(right != *this);
+
+    if (!stayInEditableContent)
+        return right;
+
+    // FIXME: This may need to do something different from "after".
+    return honorEditableBoundaryAtOrAfter(right);
+}
+
+VisiblePosition VisiblePosition::honorEditableBoundaryAtOrBefore(const VisiblePosition &pos) const
+{
+    if (pos.isNull())
+        return pos;
+    
+    NodeImpl* highestRoot = highestEditableRoot(deepEquivalent());
+    
+    // Return empty position if pos is not somewhere inside the editable region containing this position
+    if (highestRoot && !pos.deepEquivalent().node()->isDescendantOf(highestRoot))
+        return VisiblePosition();
+        
+    // Return pos itself if the two are from the very same editable region, or both are non-editable
+    // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
+    // to it is allowed.  Selection::adjustForEditableContent has this problem too.
+    if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
+        return pos;
+  
+    // Return empty position if this position is non-editable, but pos is editable
+    // FIXME: Move to the previous non-editable region.
+    if (!highestRoot)
+        return VisiblePosition();
+
+    // Return the last position before pos that is in the same editable region as this position
+    return lastEditablePositionBeforePositionInRoot(pos.deepEquivalent(), highestRoot);
+}
+
+VisiblePosition VisiblePosition::honorEditableBoundaryAtOrAfter(const VisiblePosition &pos) const
+{
+    if (pos.isNull())
+        return pos;
+    
+    NodeImpl* highestRoot = highestEditableRoot(deepEquivalent());
+    
+    // Return empty position if pos is not somewhere inside the editable region containing this position
+    if (highestRoot && !pos.deepEquivalent().node()->isDescendantOf(highestRoot))
+        return VisiblePosition();
+    
+    // Return pos itself if the two are from the very same editable region, or both are non-editable
+    // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
+    // to it is allowed.  Selection::adjustForEditableContent has this problem too.
+    if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
+        return pos;
+
+    // Return empty position if this position is non-editable, but pos is editable
+    // FIXME: Move to the next non-editable region.
+    if (!highestRoot)
+        return VisiblePosition();
+
+    // Return the next position after pos that is in the same editable region as this position
+    return firstEditablePositionAfterPositionInRoot(pos.deepEquivalent(), highestRoot);
+}
+
+Position canonicalizeCandidate(const Position& candidate)
+{
+    if (candidate.isNull())
+        return Position();
+    ASSERT(candidate.isCandidate());
+    Position upstream = candidate.upstream();
+    if (upstream.isCandidate())
+        return upstream;
+    return candidate;
+}
+
+Position VisiblePosition::canonicalPosition(const Position& position)
+{
+    // FIXME (9535):  Canonicalizing to the leftmost candidate means that if we're at a line wrap, we will
+    // ask renderers to paint downstream carets for other renderers.
+    // To fix this, we need to either a) add code to all paintCarets to pass the responsibility off to
+    // the appropriate renderer for VisiblePosition's like these, or b) canonicalize to the rightmost candidate
+    // unless the affinity is upstream.
+    NodeImpl* node = position.node();
+    if (!node)
+        return Position();
+
+    //KHTML node->document()->updateLayoutIgnorePendingStylesheets();
+    node->document()->updateLayout();
+
+    Position candidate = position.upstream();
+    //kDebug() << "upstream" << candidate << endl;
+    if (candidate.isCandidate())
+        return candidate;
+    candidate = position.downstream();
+    //kDebug() << "downstream" << candidate << endl;
+    if (candidate.isCandidate())
+        return candidate;
+
+    // When neither upstream or downstream gets us to a candidate (upstream/downstream won't leave
+    // blocks or enter new ones), we search forward and backward until we find one.
+    Position next = canonicalizeCandidate(nextCandidate(position));
+    Position prev = canonicalizeCandidate(previousCandidate(position));
+    //kDebug() << "next position" << next << endl;
+    //kDebug() << "previous position" << prev << endl;
+    NodeImpl* nextNode = next.node();
+    NodeImpl* prevNode = prev.node();
+
+    // The new position must be in the same editable element. Enforce that first.
+    // Unless the descent is from a non-editable html element to an editable body.
+    if (/*node->hasTagName(htmlTag)*/node->id() == ID_HTML && !node->isContentEditable())
+        return next.isNotNull() ? next : prev;
+
+    NodeImpl* editingRoot = editableRootForPosition(position);
+        
+    // If the html element is editable, descending into its body will look like a descent
+    // from non-editable to editable content since rootEditableElement() always stops at the body.
+    if (editingRoot && /*editingRoot->hasTagName(htmlTag)*/editingRoot->id() == ID_HTML || position.node()->isDocumentNode())
+        return next.isNotNull() ? next : prev;
+        
+    bool prevIsInSameEditableElement = prevNode && editableRootForPosition(prev) == editingRoot;
+    bool nextIsInSameEditableElement = nextNode && editableRootForPosition(next) == editingRoot;
+    if (prevIsInSameEditableElement && !nextIsInSameEditableElement)
+        return prev;
+        
+    if (nextIsInSameEditableElement && !prevIsInSameEditableElement)
+        return next;
+        
+    if (!nextIsInSameEditableElement && !prevIsInSameEditableElement)
+        return Position();
+
+    // The new position should be in the same block flow element. Favor that.
+    NodeImpl *originalBlock = node->enclosingBlockFlowElement();
+    bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) && nextNode != originalBlock;
+    bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) && prevNode != originalBlock;
+    if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock)
+        return prev;
+      
+    //kDebug() << "fall through: return next" << endl;
+    return next;
+}
+
+QChar VisiblePosition::characterAfter() const
+{
+    // We canonicalize to the first of two equivalent candidates, but the second of the two candidates
+    // is the one that will be inside the text node containing the character after this visible position.
+    Position pos = m_deepPosition.downstream();
+    NodeImpl* node = pos.node();
+    if (!node || !node->isTextNode())
+        return 0;
+    TextImpl* textNode = static_cast<TextImpl*>(pos.node());
+    int offset = pos.offset();
+    if ((unsigned)offset >= textNode->length())
+        return 0;
+    return textNode->data()[offset];
+}
+
+QRect VisiblePosition::localCaretRect(RenderObject*& renderer) const
+{
+    NodeImpl* node = m_deepPosition.node();
+    if (!node) {
+        renderer = 0;
+        return QRect();
+    }
+    
+    renderer = node->renderer();
+    if (!renderer)
+        return QRect();
+
+    InlineBox* inlineBox;
+    int caretOffset;
+    getInlineBoxAndOffset(inlineBox, caretOffset);
+
+    if (inlineBox)
+        renderer = inlineBox->object();
+
+    return renderer->localCaretRect(inlineBox, caretOffset);
+}
+
+QRect VisiblePosition::absoluteCaretBounds() const
+{
+    RenderObject* renderer;
+    QRect localRect = localCaretRect(renderer);
+    if (localRect.isEmpty() || !renderer)
+        return QRect();
+
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    //return renderer->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
+    return QRect(); // FIXME khtml: port!!!
+}
+
+int VisiblePosition::xOffsetForVerticalNavigation() const
+{
+    RenderObject* renderer;
+    QRect localRect = localCaretRect(renderer);
+    if (localRect.isEmpty() || !renderer)
+        return 0;
+
+    // This ignores transforms on purpose, for now. Vertical navigation is done
+    // without consulting transforms, so that 'up' in transformed text is 'up'
+    // relative to the text, not absolute 'up'.
+    return renderer->localToAbsolute(localRect.bottomLeft()).x();
+}
+
+void VisiblePosition::debugPosition(const char* msg) const
+{
+    /*FIXME if (isNull())
+        fprintf(stderr, "Position [%s]: null\n", msg);
+    else
+        fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, m_deepPosition.node()->nodeName().utf8().data(), m_deepPosition.node(), m_deepPosition.offset());*/
+}
+
+#ifndef NDEBUG
+
+void VisiblePosition::formatForDebugger(char* buffer, unsigned length) const
+{
+    m_deepPosition.formatForDebugger(buffer, length);
+}
+
+void VisiblePosition::showTreeForThis() const
+{
+    m_deepPosition.showTreeForThis();
+}
+
+#endif
+
+PassRefPtr<RangeImpl> makeRange(const VisiblePosition &start, const VisiblePosition &end)
+{
+    Position s = rangeCompliantEquivalent(start);
+    Position e = rangeCompliantEquivalent(end);
+    return RangeImpl::create(s.node()->document(), s.node(), s.offset(), e.node(), e.offset());
+}
+
+VisiblePosition startVisiblePosition(const RangeImpl *r, EAffinity affinity)
+{
+    int exception = 0;
+    return VisiblePosition(r->startContainer(exception), r->startOffset(exception), affinity);
+}
+
+VisiblePosition endVisiblePosition(const RangeImpl *r, EAffinity affinity)
+{
+    int exception = 0;
+    return VisiblePosition(r->endContainer(exception), r->endOffset(exception), affinity);
+}
+
+bool setStart(RangeImpl *r, const VisiblePosition &visiblePosition)
+{
+    if (!r)
+        return false;
+    Position p = rangeCompliantEquivalent(visiblePosition);
+    int code = 0;
+    r->setStart(p.node(), p.offset(), code);
+    return code == 0;
+}
+
+bool setEnd(RangeImpl *r, const VisiblePosition &visiblePosition)
+{
+    if (!r)
+        return false;
+    Position p = rangeCompliantEquivalent(visiblePosition);
+    int code = 0;
+    r->setEnd(p.node(), p.offset(), code);
+    return code == 0;
+}
+
+NodeImpl *enclosingBlockFlowElement(const VisiblePosition &visiblePosition)
+{
+    if (visiblePosition.isNull())
+        return NULL;
+
+    return visiblePosition.deepEquivalent().node()->enclosingBlockFlowElement();
+}
+
+bool isFirstVisiblePositionInNode(const VisiblePosition &visiblePosition, const NodeImpl *node)
+{
+    if (visiblePosition.isNull())
+        return false;
+    
+    if (!visiblePosition.deepEquivalent().node()->isDescendantOf(node))
+        return false;
+        
+    VisiblePosition previous = visiblePosition.previous();
+    return previous.isNull() || !previous.deepEquivalent().node()->isDescendantOf(node);
+}
+
+bool isLastVisiblePositionInNode(const VisiblePosition &visiblePosition, const NodeImpl *node)
+{
+    if (visiblePosition.isNull())
+        return false;
+    
+    if (!visiblePosition.deepEquivalent().node()->isDescendantOf(node))
+        return false;
+                
+    VisiblePosition next = visiblePosition.next();
+    return next.isNull() || !next.deepEquivalent().node()->isDescendantOf(node);
+}
+
+}  // namespace WebCore
+
+#ifndef NDEBUG
+
+void showTree(const WebCore::VisiblePosition* vpos)
+{
+    if (vpos)
+        vpos->showTreeForThis();
+}
+
+void showTree(const WebCore::VisiblePosition& vpos)
+{
+    vpos.showTreeForThis();
+}
+
+#endif
diff --git a/khtml/xml/VisiblePosition.h b/khtml/xml/VisiblePosition.h
new file mode 100644
index 0000000..3fc696f
--- /dev/null
+++ b/khtml/xml/VisiblePosition.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef VisiblePosition_h
+#define VisiblePosition_h
+
+#include "xml/dom_nodeimpl.h"
+#include "xml/Position.h"
+
+namespace khtml
+{
+class InlineBox;
+}
+
+using khtml::InlineBox;
+
+namespace DOM {
+
+// VisiblePosition default affinity is downstream because
+// the callers do not really care (they just want the
+// deep position without regard to line position), and this
+// is cheaper than UPSTREAM
+#define VP_DEFAULT_AFFINITY DOWNSTREAM
+
+// Callers who do not know where on the line the position is,
+// but would like UPSTREAM if at a line break or DOWNSTREAM
+// otherwise, need a clear way to specify that.  The
+// constructors auto-correct UPSTREAM to DOWNSTREAM if the
+// position is not at a line break.
+#define VP_UPSTREAM_IF_POSSIBLE UPSTREAM
+
+class VisiblePosition {
+public:
+    // NOTE: UPSTREAM affinity will be used only if pos is at end of a wrapped line,
+    // otherwise it will be converted to DOWNSTREAM
+    VisiblePosition() : m_affinity(VP_DEFAULT_AFFINITY) { }
+    VisiblePosition(NodeImpl*, int offset, EAffinity);
+    VisiblePosition(const Position&, EAffinity = VP_DEFAULT_AFFINITY);
+
+    void clear() { m_deepPosition.clear(); }
+
+    bool isNull() const { return m_deepPosition.isNull(); }
+    bool isNotNull() const { return m_deepPosition.isNotNull(); }
+
+    Position deepEquivalent() const { return m_deepPosition; }
+    EAffinity affinity() const { ASSERT(m_affinity == UPSTREAM || m_affinity == DOWNSTREAM); return m_affinity; }
+    void setAffinity(EAffinity affinity) { m_affinity = affinity; }
+
+    // next() and previous() will increment/decrement by a character cluster.
+    VisiblePosition next(bool stayInEditableContent = false) const;
+    VisiblePosition previous(bool stayInEditableContent = false) const;
+    VisiblePosition honorEditableBoundaryAtOrBefore(const VisiblePosition&) const;
+    VisiblePosition honorEditableBoundaryAtOrAfter(const VisiblePosition&) const;
+
+    VisiblePosition left(bool stayInEditableContent = false) const;
+    VisiblePosition right(bool stayInEditableContent = false) const;
+
+    QChar characterAfter() const;
+    QChar characterBefore() const { return previous().characterAfter(); }
+    
+    void debugPosition(const char* msg = "") const;
+    
+    ElementImpl* rootEditableElement() const { return m_deepPosition.isNotNull() ? m_deepPosition.node()->rootEditableElement() : 0; }
+    
+    void getInlineBoxAndOffset(InlineBox*& inlineBox, int& caretOffset) const
+    {
+        m_deepPosition.getInlineBoxAndOffset(m_affinity, inlineBox, caretOffset);
+    }
+
+    void getInlineBoxAndOffset(TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
+    {
+        m_deepPosition.getInlineBoxAndOffset(m_affinity, primaryDirection, inlineBox, caretOffset);
+    }
+
+    // Rect is local to the returned renderer
+    QRect localCaretRect(RenderObject*&) const;
+    // Bounds of (possibly transformed) caret in absolute coords
+    QRect absoluteCaretBounds() const;
+    // Abs x position of the caret ignoring transforms.
+    // FIXME: navigation with transforms should be smarter.
+    int xOffsetForVerticalNavigation() const;
+
+#ifndef NDEBUG
+    void formatForDebugger(char* buffer, unsigned length) const;
+    void showTreeForThis() const;
+#endif
+
+private:
+    void init(const Position&, EAffinity);
+    Position canonicalPosition(const Position&);
+
+    Position leftVisuallyDistinctCandidate() const;
+    Position rightVisuallyDistinctCandidate() const;
+
+    Position m_deepPosition;
+    EAffinity m_affinity;
+};
+
+// FIXME: This shouldn't ignore affinity.
+inline bool operator==(const VisiblePosition& a, const VisiblePosition& b)
+{
+    return a.deepEquivalent() == b.deepEquivalent();
+}
+
+inline bool operator!=(const VisiblePosition& a, const VisiblePosition& b)
+{
+    return !(a == b);
+}
+
+PassRefPtr<RangeImpl> makeRange(const VisiblePosition&, const VisiblePosition&);
+bool setStart(RangeImpl*, const VisiblePosition&);
+bool setEnd(RangeImpl*, const VisiblePosition&);
+VisiblePosition startVisiblePosition(const RangeImpl*, EAffinity);
+VisiblePosition endVisiblePosition(const RangeImpl*, EAffinity);
+
+NodeImpl *enclosingBlockFlowElement(const VisiblePosition&);
+
+bool isFirstVisiblePositionInNode(const VisiblePosition&, const NodeImpl*);
+bool isLastVisiblePositionInNode(const VisiblePosition&, const NodeImpl*);
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+// Outside the WebCore namespace for ease of invocation from gdb.
+void showTree(const khtml::VisiblePosition*);
+void showTree(const khtml::VisiblePosition&);
+#endif
+
+#endif // VisiblePosition_h
diff --git a/khtml/xml/dom2_rangeimpl.cpp b/khtml/xml/dom2_rangeimpl.cpp
index c3b6969..5504add 100644
--- a/khtml/xml/dom2_rangeimpl.cpp
+++ b/khtml/xml/dom2_rangeimpl.cpp
@@ -64,6 +64,21 @@ RangeImpl::RangeImpl(DocumentImpl *_ownerDocument,
     m_detached = false;
 }
 
+PassRefPtr<RangeImpl> RangeImpl::create(PassRefPtr<DocumentImpl> ownerDocument)
+{
+    return adoptRef(new RangeImpl(ownerDocument.get()));
+}
+
+PassRefPtr<RangeImpl> RangeImpl::create(PassRefPtr<DocumentImpl> ownerDocument, PassRefPtr<NodeImpl> startContainer, int startOffset, PassRefPtr<NodeImpl> endContainer, int endOffset)
+{
+    return adoptRef(new RangeImpl(ownerDocument.get(), startContainer.get(), startOffset, endContainer.get(), endOffset));
+}
+
+/*PassRefPtr<Range> Range::create(PassRefPtr<Document> ownerDocument, const Position& start, const Position& end)
+{
+    return adoptRef(new Range(ownerDocument, start.container.get(), start.posOffset, end.container.get(), end.posOffset));
+}*/
+
 RangeImpl::~RangeImpl()
 {
     m_ownerDocument->deref();
@@ -375,7 +390,12 @@ short RangeImpl::compareBoundaryPoints( NodeImpl *containerA, long offsetA, Node
     else  return 1;                        // A is after B
 }
 
-bool RangeImpl::boundaryPointsValid(  )
+short RangeImpl::compareBoundaryPoints(const Position& a, const Position& b)
+{
+    return compareBoundaryPoints(a.container.get(), a.posOffset, b.container.get(), b.posOffset);
+}
+
+bool RangeImpl::boundaryPointsValid(  ) const
 {
     short valid =  compareBoundaryPoints( m_startContainer, m_startOffset,
                                           m_endContainer, m_endOffset );
@@ -1281,7 +1301,7 @@ void RangeImpl::checkNodeBA( NodeImpl *n, int &exceptioncode ) const
 
 }
 
-RangeImpl *RangeImpl::cloneRange(int &exceptioncode)
+RangeImpl *RangeImpl::cloneRange(int &exceptioncode) const
 {
     if (m_detached) {
         exceptioncode = DOMException::INVALID_STATE_ERR;
@@ -1690,4 +1710,157 @@ bool RangeImpl::containedByReadOnly() {
     return false;
 }
 
+// RangeBoundaryPoint implementation
+inline RangeBoundaryPoint::RangeBoundaryPoint()
+    : m_childBefore(0)
+{
+}
+
+inline RangeBoundaryPoint::RangeBoundaryPoint(PassRefPtr<NodeImpl> container)
+    : m_position(container, 0)
+    , m_childBefore(0)
+{
+}
+
+inline NodeImpl* RangeBoundaryPoint::container() const
+{
+    return m_position.container.get();
+}
+
+inline NodeImpl* RangeBoundaryPoint::childBefore() const
+{
+    return m_childBefore;
+}
+
+inline const Position& RangeBoundaryPoint::position() const
+{
+    if (m_position.posOffset >= 0)
+        return m_position;
+    ASSERT(m_childBefore);
+    m_position.posOffset = m_childBefore->nodeIndex() + 1;
+    return m_position;
+}
+
+inline int RangeBoundaryPoint::offset() const
+{
+    return position().posOffset;
+}
+
+inline void RangeBoundaryPoint::clear()
+{
+    m_position.clear();
+    m_childBefore = 0;
+}
+
+inline void RangeBoundaryPoint::set(PassRefPtr<NodeImpl> container, int offset, NodeImpl* childBefore)
+{
+    ASSERT(offset >= 0);
+    ASSERT(childBefore == (offset ? container->childNode(offset - 1) : 0));
+    m_position.container = container;
+    m_position.posOffset = offset;
+    m_childBefore = childBefore;
+}
+
+inline void RangeBoundaryPoint::setOffset(int offset)
+{
+    ASSERT(m_position.container);
+    ASSERT(m_position.container->offsetInCharacters());
+    ASSERT(m_position.posOffset >= 0);
+    ASSERT(!m_childBefore);
+    m_position.posOffset = offset;
+}
+
+inline void RangeBoundaryPoint::setToChild(NodeImpl* child)
+{
+    ASSERT(child);
+    ASSERT(child->parentNode());
+    m_position.container = child->parentNode();
+    m_childBefore = child->previousSibling();
+    m_position.posOffset = m_childBefore ? invalidOffset : 0;
+}
+
+inline void RangeBoundaryPoint::setToStart(PassRefPtr<NodeImpl> container)
+{
+    ASSERT(container);
+    m_position.container = container;
+    m_position.posOffset = 0;
+    m_childBefore = 0;
+}
+
+inline void RangeBoundaryPoint::setToEnd(PassRefPtr<NodeImpl> container)
+{
+    ASSERT(container);
+    m_position.container = container;
+    if (m_position.container->offsetInCharacters()) {
+        m_position.posOffset = m_position.container->maxCharacterOffset();
+        m_childBefore = 0;
+    } else {
+        m_childBefore = m_position.container->lastChild();
+        m_position.posOffset = m_childBefore ? invalidOffset : 0;
+    }
+}
+
+inline void RangeBoundaryPoint::childBeforeWillBeRemoved()
+{
+    ASSERT(m_position.posOffset);
+    m_childBefore = m_childBefore->previousSibling();
+    if (!m_childBefore)
+        m_position.posOffset = 0;
+    else if (m_position.posOffset > 0)
+        --m_position.posOffset;
+}
+
+inline void RangeBoundaryPoint::invalidateOffset() const
+{
+    m_position.posOffset = invalidOffset;
+}
+
+inline bool operator==(const RangeBoundaryPoint& a, const RangeBoundaryPoint& b)
+{
+    if (a.container() != b.container())
+        return false;
+    if (a.childBefore() || b.childBefore()) {
+        if (a.childBefore() != b.childBefore())
+            return false;
+    } else {
+        if (a.offset() != b.offset())
+            return false;
+    }
+    return true;
+}
+
+NodeImpl* RangeImpl::firstNode() const
+{
+    if (!m_startContainer)
+        return 0;
+    if (m_startContainer->offsetInCharacters())
+        return m_startContainer;
+    if (NodeImpl* child = m_startContainer->childNode(m_startOffset))
+        return child;
+    if (!m_startOffset)
+        return m_startContainer;
+    return m_startContainer->traverseNextSibling();
+}
+
+NodeImpl* RangeImpl::pastLastNode() const
+{
+    if (!m_startContainer || m_endContainer)
+        return 0;
+    if (m_endContainer->offsetInCharacters())
+        return m_endContainer->traverseNextSibling();
+    if (NodeImpl* child = m_endContainer->childNode(m_endOffset))
+        return child;
+    return m_endContainer->traverseNextSibling();
+}
+
+PassRefPtr<RangeImpl> rangeOfContents(NodeImpl* node)
+{
+    ASSERT(node);
+    RefPtr<RangeImpl> range = RangeImpl::create(node->document());
+    int exception = 0;
+    range->selectNodeContents(node, exception);
+    return range.release();
+}
+
 // kate: indent-width 4; replace-tabs off; tab-width 8; space-indent off;
+
diff --git a/khtml/xml/dom2_rangeimpl.h b/khtml/xml/dom2_rangeimpl.h
index f41184d..1e1fb80 100644
--- a/khtml/xml/dom2_rangeimpl.h
+++ b/khtml/xml/dom2_rangeimpl.h
@@ -28,13 +28,49 @@
 
 #include "dom/dom2_range.h"
 #include "misc/shared.h"
+#include "wtf/RefPtr.h"
+#include "xml/Position.h"
+
+using namespace WTF;
 
 namespace DOM {
 
+class RangeBoundaryPoint {
+public:
+    RangeBoundaryPoint();
+    explicit RangeBoundaryPoint(PassRefPtr<NodeImpl> container);
+
+    const Position& position() const;
+    NodeImpl* container() const;
+    int offset() const;
+    NodeImpl* childBefore() const;
+
+    void clear();
+
+    void set(PassRefPtr<NodeImpl> container, int offset, NodeImpl* childBefore);
+    void setOffset(int offset);
+    void setToChild(NodeImpl* child);
+    void setToStart(PassRefPtr<NodeImpl> container);
+    void setToEnd(PassRefPtr<NodeImpl> container);
+
+    void childBeforeWillBeRemoved();
+    void invalidateOffset() const;
+
+private:
+    static const int invalidOffset = -1;
+
+    mutable Position m_position;
+    NodeImpl* m_childBefore;
+};
+
 class RangeImpl : public khtml::Shared<RangeImpl>
 {
     friend class DocumentImpl;
 public:
+    static PassRefPtr<RangeImpl> create(PassRefPtr<DocumentImpl>);
+    static PassRefPtr<RangeImpl> create(PassRefPtr<DocumentImpl>, PassRefPtr<NodeImpl> startContainer, int startOffset, PassRefPtr<NodeImpl> endContainer, int endOffset);
+    // static PassRefPtr<Range> create(PassRefPtr<Document>, const Position&, const Position&);
+
     RangeImpl(DocumentImpl *_ownerDocument);
     RangeImpl(DocumentImpl *_ownerDocument,
               NodeImpl *_startContainer, long _startOffset,
@@ -42,12 +78,24 @@ public:
 
     ~RangeImpl();
 
+    DocumentImpl* ownerDocument() const { return m_ownerDocument; }
+    NodeImpl* startContainer() const { return m_startContainer; }
+    int startOffset() const { return m_startOffset; }
+    NodeImpl* endContainer() const { return m_endContainer; }
+    int endOffset() const { return m_endOffset; }
+
     NodeImpl *startContainer(int &exceptioncode) const;
     long startOffset(int &exceptioncode) const;
     NodeImpl *endContainer(int &exceptioncode) const;
     long endOffset(int &exceptioncode) const;
     bool collapsed(int &exceptioncode) const;
 
+    const Position startPosition() const { return Position(m_startContainer, m_startOffset); }
+    const Position endPosition() const { return Position(m_endContainer, m_endOffset); }
+
+    NodeImpl* firstNode() const;
+    NodeImpl* pastLastNode() const;
+
     NodeImpl *commonAncestorContainer(int &exceptioncode);
     static NodeImpl *commonAncestorContainer(NodeImpl *containerA, NodeImpl *containerB);
     void setStart ( NodeImpl *refNode, long offset, int &exceptioncode );
@@ -55,7 +103,8 @@ public:
     void collapse ( bool toStart, int &exceptioncode );
     short compareBoundaryPoints ( Range::CompareHow how, RangeImpl *sourceRange, int &exceptioncode );
     static short compareBoundaryPoints ( NodeImpl *containerA, long offsetA, NodeImpl *containerB, long offsetB );
-    bool boundaryPointsValid (  );
+    static short compareBoundaryPoints(const Position&, const Position&);
+    bool boundaryPointsValid (  ) const;
     void deleteContents ( int &exceptioncode );
     DocumentFragmentImpl *extractContents ( int &exceptioncode );
     DocumentFragmentImpl *cloneContents ( int &exceptioncode );
@@ -83,7 +132,7 @@ public:
 
     void detach ( int &exceptioncode );
     bool isDetached() const;
-    RangeImpl *cloneRange(int &exceptioncode);
+    RangeImpl *cloneRange(int &exceptioncode) const;
 
     void setStartAfter( NodeImpl *refNode, int &exceptioncode );
     void setEndBefore( NodeImpl *refNode, int &exceptioncode );
@@ -121,6 +170,8 @@ private:
     unsigned long maxStartOffset() const;
 };
 
+PassRefPtr<RangeImpl> rangeOfContents(NodeImpl*);
+
 } // namespace
 
 #endif
diff --git a/khtml/xml/dom_docimpl.cpp b/khtml/xml/dom_docimpl.cpp
index 4850f76..2e242c8 100644
--- a/khtml/xml/dom_docimpl.cpp
+++ b/khtml/xml/dom_docimpl.cpp
@@ -1586,7 +1586,7 @@ void DocumentImpl::updateSelection()
 
     RenderCanvas *canvas = static_cast<RenderCanvas*>(m_render);
     Selection s = part()->caret();
-    if (s.isEmpty() || s.state() == Selection::CARET) {
+    if (s.isNone() || s.state() == Selection::CARET) {
         canvas->clearSelection();
     }
     else {
@@ -2445,13 +2445,15 @@ void DocumentImpl::quietResetFocus()
 
 void DocumentImpl::setFocusNode(NodeImpl *newFocusNode)
 {
+    kDebug() << "set focus node" << newFocusNode << endl;
+    if (newFocusNode) kDebug() << "node:" << getPrintableName(newFocusNode->id()) << endl;
     // don't process focus changes while detaching
     if( !m_render ) return;
 
     // See if the new node is really focusable. It might not be
     // if focus() was called explicitly.
-    if (newFocusNode && !newFocusNode->isFocusable())
-        return;
+    /*if (newFocusNode && !newFocusNode->isFocusable())
+        return;*/
 
     // Make sure newFocusNode is actually in this document
     if (newFocusNode && (newFocusNode->document() != this))
diff --git a/khtml/xml/dom_docimpl.h b/khtml/xml/dom_docimpl.h
index 6de2584..d9e129e 100644
--- a/khtml/xml/dom_docimpl.h
+++ b/khtml/xml/dom_docimpl.h
@@ -431,6 +431,9 @@ public:
     NodeImpl* activeNode() const { return m_activeNode; }
     void setActiveNode(NodeImpl *newActiveNode);
 
+    // FIXME to replace for WC compat
+    NodeImpl* focusedNode() const { return focusNode(); }
+
     // Updates for :target (CSS3 selector).
     void setCSSTarget(NodeImpl* n);
     NodeImpl* getCSSTarget() { return m_cssTarget; }
diff --git a/khtml/xml/dom_elementimpl.cpp b/khtml/xml/dom_elementimpl.cpp
index 659015b..38b7123 100644
--- a/khtml/xml/dom_elementimpl.cpp
+++ b/khtml/xml/dom_elementimpl.cpp
@@ -784,6 +784,7 @@ void ElementImpl::defaultEventHandler(EventImpl *e)
                 e->setDefaultHandled();
                 return;
             }
+            kDebug() << "at node: " << getPrintableName(id()) << "[" << (this) << "]" << endl;
             if (isContentEditableElement && part->editor()->handleKeyEvent(static_cast<KeyEventBaseImpl*>(e)->qKeyEvent())) {
                 e->setDefaultHandled();
                 return;
@@ -985,6 +986,9 @@ bool ElementImpl::isFocusable() const
 
 bool ElementImpl::isContentEditable() const
 {
+    // FIXME khtml to remove
+    if (document()->part() && document()->part()->isCaretMode())
+        return true;
     if (document()->part() && document()->part()->isEditable())
         return true;
 
diff --git a/khtml/xml/dom_nodeimpl.cpp b/khtml/xml/dom_nodeimpl.cpp
index 725551c..59ede90 100644
--- a/khtml/xml/dom_nodeimpl.cpp
+++ b/khtml/xml/dom_nodeimpl.cpp
@@ -33,8 +33,8 @@
 #include "dom_textimpl.h"
 #include "dom2_eventsimpl.h"
 #include "dom_docimpl.h"
-#include "xml/dom_position.h"
-#include "xml/dom_selection.h"
+#include "xml/Position.h"
+#include "xml/Selection.h"
 #include "dom_restyler.h"
 #include "ClassNodeList.h"
 #include "html/html_objectimpl.h"
@@ -340,9 +340,17 @@ kDebug(6200) << "getCaret: r " << r << " " << (r?r->renderName():QString()) << "
 
 bool NodeImpl::isContentEditable() const
 {
+    if (document() && document()->part() && document()->part()->isCaretMode())
+        return true;
     return m_parent ? m_parent->isContentEditable() : false;
 }
 
+bool NodeImpl::isContentRichlyEditable() const
+{
+    return isContentEditable();
+    //FIXME khtml return parent() && parent()->isContentRichlyEditable();
+}
+
 QRect NodeImpl::getRect() const
 {
     int _x, _y;
@@ -734,7 +742,7 @@ void NodeImpl::defaultEventHandler(EventImpl*)
 {
 }
 
-unsigned long NodeImpl::childNodeCount()
+unsigned long NodeImpl::childNodeCount() const
 {
     return 0;
 }
@@ -760,6 +768,30 @@ NodeImpl *NodeImpl::traverseNextNode(NodeImpl *stayWithin) const
     return 0;
 }
 
+NodeImpl *NodeImpl::traverseNextSibling(const NodeImpl* stayWithin) const
+{
+    if (this == stayWithin)
+        return 0;
+    if (nextSibling())
+        return nextSibling();
+    const NodeImpl *n = this;
+    while (n && !n->nextSibling() && (!stayWithin || n->parentNode() != stayWithin))
+        n = n->parentNode();
+    if (n)
+        return n->nextSibling();
+    return 0;
+}
+
+NodeImpl* NodeImpl::traverseNextNodePostOrder() const
+{
+    NodeImpl* next = nextSibling();
+    if (!next)
+        return parentNode();
+    while (NodeImpl* firstChild = next->firstChild())
+        next = firstChild;
+    return next;
+}
+
 NodeImpl *NodeImpl::traversePreviousNode() const
 {
     if (previousSibling()) {
@@ -776,6 +808,36 @@ NodeImpl *NodeImpl::traversePreviousNode() const
     }
 }
 
+NodeImpl *NodeImpl::traversePreviousNodePostOrder(const NodeImpl *stayWithin) const
+{
+    if (lastChild())
+        return lastChild();
+    if (this == stayWithin)
+        return 0;
+    if (previousSibling())
+        return previousSibling();
+    const NodeImpl *n = this;
+    while (n && !n->previousSibling() && (!stayWithin || n->parentNode() != stayWithin))
+        n = n->parentNode();
+    if (n)
+        return n->previousSibling();
+    return 0;
+}
+
+NodeImpl* NodeImpl::traversePreviousSiblingPostOrder(const NodeImpl* stayWithin) const
+{
+    if (this == stayWithin)
+        return 0;
+    if (previousSibling())
+        return previousSibling();
+    const NodeImpl *n = this;
+    while (n && !n->previousSibling() && (!stayWithin || n->parentNode() != stayWithin))
+        n = n->parentNode();
+    if (n)
+        return n->previousSibling();
+    return 0;
+}
+
 void NodeImpl::checkSetPrefix(const DOMString &_prefix, int &exceptioncode)
 {
     // Perform error checking as required by spec for setting Node.prefix. Used by
@@ -862,7 +924,7 @@ void NodeImpl::checkAddChild(NodeImpl *newChild, int &exceptioncode)
     }
 }
 
-bool NodeImpl::isAncestor( NodeImpl *other ) const
+bool NodeImpl::isAncestor( const NodeImpl *other ) const
 {
     // Return true if other is the same as this node or an ancestor of it, otherwise false
     const NodeImpl *n;
@@ -873,6 +935,13 @@ bool NodeImpl::isAncestor( NodeImpl *other ) const
     return false;
 }
 
+bool NodeImpl::contains(const NodeImpl* node) const
+{
+    if (!node)
+        return false;
+    return this == node || node->isDescendantOf(this);
+}
+
 bool NodeImpl::childAllowed( NodeImpl *newChild )
 {
     return childTypeAllowed(newChild->nodeType());
@@ -1172,25 +1241,16 @@ ElementImpl *NodeImpl::enclosingBlockFlowElement() const
     return 0;
 }
 
-ElementImpl *NodeImpl::rootEditableElement() const
+ElementImpl* NodeImpl::rootEditableElement() const
 {
-  if (!isContentEditable())
-        return 0;
-
-    NodeImpl *n = const_cast<NodeImpl *>(this);
-    NodeImpl *result = n->isEditableBlock() ? n : 0;
-    while (1) {
-        n = n->parentNode();
-        if (!n || !n->isContentEditable())
-            break;
-        if (n->id() == ID_BODY) {
-            result = n;
+    ElementImpl* result = 0;
+    for (NodeImpl* n = const_cast<NodeImpl*>(this); n && n->isContentEditable(); n = n->parentNode()) {
+        if (n->isElementNode())
+            result = static_cast<ElementImpl*>(n);
+        if (n->hasTagName(ID_BODY))
             break;
-        }
-        if (n->isBlockFlow())
-            result = n;
     }
-    return static_cast<ElementImpl *>(result);
+    return result;
 }
 
 bool NodeImpl::inSameRootEditableElement(NodeImpl *n)
@@ -1203,6 +1263,7 @@ bool NodeImpl::inSameContainingBlockFlowElement(NodeImpl *n)
     return n ? enclosingBlockFlowElement() == n->enclosingBlockFlowElement() : false;
 }
 
+#if 0 //TODO remove
 Position NodeImpl::positionForCoordinates(int x, int y) const
 {
     if (renderer())
@@ -1237,6 +1298,7 @@ bool NodeImpl::isPointInsideSelection(int x, int y, const Selection &sel) const
     return false;
 
 }
+#endif
 
 NodeListImpl* NodeImpl::getElementsByTagName(const DOMString &tagName)
 {
@@ -1868,7 +1930,7 @@ void NodeBaseImpl::setHovered(bool hover)
         document()->dynamicDomRestyler().restyleDependent(static_cast<ElementImpl*>(this), HoverDependency);
 }
 
-unsigned long NodeBaseImpl::childNodeCount()
+unsigned long NodeBaseImpl::childNodeCount() const
 {
     unsigned long count = 0;
     NodeImpl *n;
diff --git a/khtml/xml/dom_nodeimpl.h b/khtml/xml/dom_nodeimpl.h
index 401851e..58426d4 100644
--- a/khtml/xml/dom_nodeimpl.h
+++ b/khtml/xml/dom_nodeimpl.h
@@ -90,6 +90,7 @@ public:
 
     //stuff for WebCore DOM & SVG
     virtual bool hasTagName(const QualifiedName& /*name*/) const { return false; }
+    bool hasTagName(unsigned tag) const { return id() == tag; }
 
     // DOM methods & attributes for Node
     virtual DOMString nodeName() const;
@@ -139,12 +140,17 @@ public:
     virtual bool isXMLElementNode() const { return false; }
     virtual bool isGenericFormElement() const { return false; }
     virtual bool containsOnlyWhitespace() const { return false; }
+    virtual bool isCharacterDataNode() const { return false; }
     bool isBlockFlow() const;
 
     // methods for WebCore api compat (SVG)
+    // FIXME khtml: implements these methods
     virtual bool isSVGElement() const { return false; }
     virtual bool isShadowNode() const { return false; }
     virtual NodeImpl* shadowParentNode() { return 0; }
+    NodeImpl* shadowAncestorNode() const { return 0; }
+
+    bool isSameNode(NodeImpl* other) const { return this == other; }
 
     DOMString textContent() const;
     void setTextContent(const DOMString& text, int& ec);
@@ -182,8 +188,9 @@ public:
     bool inSameRootEditableElement(NodeImpl *);
     bool inSameContainingBlockFlowElement(NodeImpl *);
 
-    Position positionForCoordinates(int x, int y) const;
-    bool isPointInsideSelection(int x, int y, const Selection &) const;
+    // FIXME khtml deprecated
+    //Position positionForCoordinates(int x, int y) const;
+    //bool isPointInsideSelection(int x, int y, const Selection &) const;
 
     // used by the parser. Doesn't do as many error checkings as
     // appendChild(), and returns the node into which will be parsed next.
@@ -286,6 +293,7 @@ public:
     virtual bool isInline() const;
 
     virtual bool isContentEditable() const;
+    virtual bool isContentRichlyEditable() const;
     virtual void getCaret(int offset, bool override, int &_x, int &_y, int &width, int &height);
     virtual QRect getRect() const;
 
@@ -330,7 +338,7 @@ public:
 
     virtual bool isReadOnly();
     virtual bool childTypeAllowed( unsigned short /*type*/ ) { return false; }
-    virtual unsigned long childNodeCount();
+    virtual unsigned long childNodeCount() const;
     virtual NodeImpl *childNode(unsigned long index);
 
     /**
@@ -346,6 +354,16 @@ public:
      */
     NodeImpl *traverseNextNode(NodeImpl *stayWithin = 0) const;
 
+    // Like traverseNextNode, but skips children and starts with the next sibling.
+    NodeImpl *traverseNextSibling(const NodeImpl* stayWithin = 0) const;
+
+    // Like traverseNextNode, but visits parents after their children.
+    NodeImpl* traverseNextNodePostOrder() const;
+
+    // Like traversePreviousNode, but visits parents before their children.
+    NodeImpl* traversePreviousNodePostOrder(const NodeImpl *stayWithin = 0) const;
+    NodeImpl* traversePreviousSiblingPostOrder(const NodeImpl *stayWithin = 0) const;
+
     /**
      * Does a reverse pre-order traversal to find the node that comes before the current one in document order
      *
@@ -366,8 +384,10 @@ public:
 
     void checkSetPrefix(const DOMString &_prefix, int &exceptioncode);
     void checkAddChild(NodeImpl *newChild, int &exceptioncode);
-    bool isAncestor( NodeImpl *other ) const;
+    bool isAncestor( const NodeImpl *other ) const;
+    bool isDescendantOf(const NodeImpl *other) const { return isAncestor(other); }
     virtual bool childAllowed( NodeImpl *newChild );
+    bool contains(const NodeImpl*) const;
 
     // Used to determine whether range offsets use characters or node indices.
     virtual bool offsetInCharacters() const { return false; }
@@ -380,6 +400,10 @@ public:
     virtual long caretMaxOffset() const;
     virtual unsigned long caretMaxRenderedOffset() const;
 
+    // FIXME: We should try to find a better location for these methods.
+    virtual bool canSelectAll() const { return false; }
+    virtual void selectAll() { }
+
     // -----------------------------------------------------------------------------
     // Integration with rendering tree
 
@@ -561,7 +585,7 @@ public:
     virtual void setFocus(bool=true);
     virtual void setActive(bool=true);
     virtual void setHovered(bool=true);
-    virtual unsigned long childNodeCount();
+    virtual unsigned long childNodeCount() const;
     virtual NodeImpl *childNode(unsigned long index);
 
 protected:
diff --git a/khtml/xml/dom_position.cpp b/khtml/xml/dom_position.cpp
index 24b7fdc..020870c 100644
--- a/khtml/xml/dom_position.cpp
+++ b/khtml/xml/dom_position.cpp
@@ -441,7 +441,10 @@ Position Position::nextLinePosition(int x) const
     if (root) {
         int absx, absy;
         containingBlock->absolutePosition(absx, absy);
+        kDebug() << "containing block" << containingBlock->renderName() << endl;
+        kDebug() << "absolute positions" << absx << absy << endl;
         RenderObject *renderer = root->closestLeafChildForXPos(x, absx)->object();
+        kDebug() << "renderer" << renderer->renderName() << x << (absy + root->topOverflow()) << endl;
         return renderer->positionForCoordinates(x, absy + root->topOverflow());
     }
 
diff --git a/khtml/xml/dom_position.h b/khtml/xml/dom_position.h
index 9132c36..aa7be3c 100644
--- a/khtml/xml/dom_position.h
+++ b/khtml/xml/dom_position.h
@@ -25,6 +25,7 @@
 
 #ifndef __dom_position_h__
 #define __dom_position_h__
+#if 0
 
 namespace DOM {
 
@@ -99,5 +100,6 @@ inline bool operator!=(const Position &a, const Position &b)
 }
 
 } // namespace DOM
+#endif
 
 #endif // __dom_position_h__
diff --git a/khtml/xml/dom_positioniterator.cpp b/khtml/xml/dom_positioniterator.cpp
index 5b47f51..46c13db 100644
--- a/khtml/xml/dom_positioniterator.cpp
+++ b/khtml/xml/dom_positioniterator.cpp
@@ -27,6 +27,8 @@
 
 #include "dom_nodeimpl.h"
 
+#include "editing/htmlediting.h"
+
 namespace DOM {
 
 Position PositionIterator::peekPrevious() const
@@ -55,7 +57,7 @@ Position PositionIterator::peekNext() const
     if (pos.isEmpty())
         return pos;
     
-    if (pos.offset() >= pos.node()->maxOffset()) {
+    if (pos.offset() >= /*khtml::maxDeepOffset(pos.node())*/pos.node()->maxOffset()) {
         NodeImpl *nextNode = pos.node()->nextLeafNode();
         if (nextNode)
             pos = Position(nextNode, 0);
diff --git a/khtml/xml/dom_positioniterator.h b/khtml/xml/dom_positioniterator.h
index 6650754..3985c74 100644
--- a/khtml/xml/dom_positioniterator.h
+++ b/khtml/xml/dom_positioniterator.h
@@ -25,6 +25,7 @@
 
 #ifndef _PositionIterator_h_
 #define _PositionIterator_h_
+#if 0
 
 #include "dom_position.h"
 
@@ -57,5 +58,5 @@ private:
 };
 
 } // namespace DOM
-
+#endif
 #endif // _PositionIterator_h_
diff --git a/khtml/xml/dom_selection.cpp b/khtml/xml/dom_selection.cpp
index b46fb95..510f79f 100644
--- a/khtml/xml/dom_selection.cpp
+++ b/khtml/xml/dom_selection.cpp
@@ -188,7 +188,7 @@ void Selection::moveTo(const Position &pos)
 
 void Selection::moveTo(const Position &base, const Position &extent)
 {
-//   kdDebug(6200) << "Selection::moveTo: base(" << base.node() << "," << base.offset() << "), extent(" << extent.node() << "," << extent.offset() << ")" << endl;
+    kdDebug(6200) << "Selection::moveTo: base(" << base.node() << "," << base.offset() << "), extent(" << extent.node() << "," << extent.offset() << ")" << endl;
     assignBaseAndExtent(base, extent);
     validate();
 }
@@ -465,6 +465,7 @@ Range Selection::toRange() const
 
 void Selection::layoutCaret()
 {
+    //kDebug() << kBacktrace() << endl;
     if (isEmpty() || !caretPos().node()->renderer()) {
         m_caretX = m_caretY = m_caretSize = 0;
     }
@@ -473,6 +474,7 @@ void Selection::layoutCaret()
         // upstream/downstream affinity to get the right position.
         int w;
         caretPos().node()->renderer()->caretPos(caretPos().offset(), true, m_caretX, m_caretY, w, m_caretSize);
+        kDebug() << caretPos().node()->renderer()->renderName() << caretPos().offset() << m_caretX << m_caretY << endl;
     }
 
     m_needsCaretLayout = false;
@@ -560,6 +562,7 @@ void Selection::paintCaret(QPainter *p, const QRect &rect)
 void Selection::validate(ETextGranularity granularity)
 {
     // move the base and extent nodes to their equivalent leaf positions
+    kDebug() << "granularity:" << granularity << endl;
     bool baseAndExtentEqual = base() == extent();
     if (base().notEmpty()) {
         Position pos = base().equivalentLeafPosition();
@@ -595,6 +598,8 @@ void Selection::validate(ETextGranularity granularity)
 
     // calculate the correct start and end positions
     if (granularity == CHARACTER) {
+        kDebug() << "base:" << base().node() << base().offset() << endl;
+        kDebug() << "extent:" << extent().node() << extent().offset() << endl;
         if (m_baseIsStart)
             assignStartAndEnd(base(), extent());
         else
diff --git a/khtml/xml/dom_selection.h b/khtml/xml/dom_selection.h
index bc27279..138c351 100644
--- a/khtml/xml/dom_selection.h
+++ b/khtml/xml/dom_selection.h
@@ -25,8 +25,9 @@
 
 #ifndef __dom_selection_h__
 #define __dom_selection_h__
+#if 0
 
-#include "xml/dom_position.h"
+#include "xml/Position.h"
 
 class KHTMLPart;
 class KHTMLView;
@@ -55,7 +56,6 @@ public:
     // From NSTextView.h:
     // NSSelectionAffinityUpstream = 0
     // NSSelectionAffinityDownstream = 1
-    enum EAffinity { UPSTREAM = 0, DOWNSTREAM = 1 };
 
     Selection();
     Selection(const Range &);
@@ -166,5 +166,6 @@ inline bool operator!=(const Selection &a, const Selection &b)
 }
 
 } // namespace DOM
+#endif
 
 #endif  // __dom_selection_h__
diff --git a/khtml/xml/dom_stringimpl.h b/khtml/xml/dom_stringimpl.h
index d5ea3a7..1451b3c 100644
--- a/khtml/xml/dom_stringimpl.h
+++ b/khtml/xml/dom_stringimpl.h
@@ -149,6 +149,15 @@ inline bool strcmp(const DOMStringImpl* a, const DOMStringImpl* b)
 
 bool strcasecmp(const DOMStringImpl* a, const DOMStringImpl* b);
 
+static inline bool isSpaceOrNewline(QChar c)
+{
+    // Use isASCIISpace() for basic Latin-1.
+    // This will include newlines, which aren't included in Unicode DirWS.
+    //return c <= 0x7F ? WTF::isASCIISpace(c) : WTF::Unicode::direction(c) == WTF::Unicode::WhiteSpaceNeutral;
+    // FIXME: use better function
+    return c.isSpace();
+}
+
 }
 
 namespace khtml
diff --git a/khtml/xml/dom_textimpl.cpp b/khtml/xml/dom_textimpl.cpp
index 16ca653..e5973c2 100644
--- a/khtml/xml/dom_textimpl.cpp
+++ b/khtml/xml/dom_textimpl.cpp
@@ -121,6 +121,7 @@ void CharacterDataImpl::appendData( const DOMString &arg, int &exceptioncode )
 
 void CharacterDataImpl::insertData( const unsigned long offset, const DOMString &arg, int &exceptioncode )
 {
+    kDebug() << "now about to insert data" << endl;
     exceptioncode = 0;
     checkCharDataOperation(offset, exceptioncode);
     if (exceptioncode)
diff --git a/khtml/xml/dom_textimpl.h b/khtml/xml/dom_textimpl.h
index 08804db..3c760a9 100644
--- a/khtml/xml/dom_textimpl.h
+++ b/khtml/xml/dom_textimpl.h
@@ -75,6 +75,7 @@ public:
     virtual long caretMaxOffset() const;
     virtual unsigned long caretMaxRenderedOffset() const;
 
+    virtual bool isCharacterDataNode() const { return false; }
 protected:
     // note: since DOMStrings are shared, str should always be copied when making
     // a change or returning a string
diff --git a/khtml/xml/editing.cpp b/khtml/xml/editing.cpp
new file mode 100644
index 0000000..575114a
--- /dev/null
+++ b/khtml/xml/editing.cpp
@@ -0,0 +1,1023 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "htmlediting.h"
+
+#include "CharacterNames.h"
+#include "Document.h"
+#include "EditingText.h"
+#include "HTMLElement.h"
+#include "HTMLInterchange.h"
+#include "HTMLNames.h"
+#include "PositionIterator.h"
+#include "RenderObject.h"
+#include "RegularExpression.h"
+#include "Range.h"
+#include "Selection.h"
+#include "Text.h"
+#include "TextIterator.h"
+#include "VisiblePosition.h"
+#include "visible_units.h"
+#include <wtf/StdLibExtras.h>
+
+#if ENABLE(WML)
+#include "WMLNames.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// Atomic means that the node has no children, or has children which are ignored for the
+// purposes of editing.
+bool isAtomicNode(const Node *node)
+{
+    return node && (!node->hasChildNodes() || editingIgnoresContent(node));
+}
+
+// Returns true for nodes that either have no content, or have content that is ignored (skipped
+// over) while editing.  There are no VisiblePositions inside these nodes.
+bool editingIgnoresContent(const Node* node)
+{
+    return !canHaveChildrenForEditing(node) && !node->isTextNode();
+}
+
+bool canHaveChildrenForEditing(const Node* node)
+{
+    return !node->hasTagName(hrTag) &&
+           !node->hasTagName(brTag) &&
+           !node->hasTagName(imgTag) &&
+           !node->hasTagName(buttonTag) &&
+           !node->hasTagName(inputTag) &&
+           !node->hasTagName(textareaTag) &&
+           !node->hasTagName(objectTag) &&
+           !node->hasTagName(iframeTag) &&
+           !node->hasTagName(embedTag) &&
+           !node->hasTagName(appletTag) &&
+           !node->hasTagName(selectTag) &&
+#if ENABLE(WML)
+           !node->hasTagName(WMLNames::doTag) &&
+#endif
+           !node->isTextNode();
+}
+
+// Compare two positions, taking into account the possibility that one or both
+// could be inside a shadow tree. Only works for non-null values.
+int comparePositions(const Position& a, const Position& b)
+{
+    Node* nodeA = a.node();
+    ASSERT(nodeA);
+    Node* nodeB = b.node();
+    ASSERT(nodeB);
+    int offsetA = a.offset();
+    int offsetB = b.offset();
+
+    Node* shadowAncestorA = nodeA->shadowAncestorNode();
+    if (shadowAncestorA == nodeA)
+        shadowAncestorA = 0;
+    Node* shadowAncestorB = nodeB->shadowAncestorNode();
+    if (shadowAncestorB == nodeB)
+        shadowAncestorB = 0;
+
+    int bias = 0;
+    if (shadowAncestorA != shadowAncestorB) {
+        if (shadowAncestorA) {
+            nodeA = shadowAncestorA;
+            offsetA = 0;
+            bias = 1;
+        }
+        if (shadowAncestorB) {
+            nodeB = shadowAncestorB;
+            offsetB = 0;
+            bias = -1;
+        }
+    }
+
+    int result = Range::compareBoundaryPoints(nodeA, offsetA, nodeB, offsetB);
+    return result ? result : bias;
+}
+
+Node* highestEditableRoot(const Position& position)
+{
+    Node* node = position.node();
+    if (!node)
+        return 0;
+        
+    Node* highestRoot = editableRootForPosition(position);
+    if (!highestRoot)
+        return 0;
+    
+    node = highestRoot;
+    while (node) {
+        if (node->isContentEditable())
+            highestRoot = node;
+        if (node->hasTagName(bodyTag))
+            break;
+        node = node->parentNode();
+    }
+    
+    return highestRoot;
+}
+
+Node* lowestEditableAncestor(Node* node)
+{
+    if (!node)
+        return 0;
+    
+    Node *lowestRoot = 0;
+    while (node) {
+        if (node->isContentEditable())
+            return node->rootEditableElement();
+        if (node->hasTagName(bodyTag))
+            break;
+        node = node->parentNode();
+    }
+    
+    return lowestRoot;
+}
+
+bool isEditablePosition(const Position& p)
+{
+    Node* node = p.node();
+    if (!node)
+        return false;
+        
+    if (node->renderer() && node->renderer()->isTable())
+        node = node->parentNode();
+    
+    return node->isContentEditable();
+}
+
+bool isRichlyEditablePosition(const Position& p)
+{
+    Node* node = p.node();
+    if (!node)
+        return false;
+        
+    if (node->renderer() && node->renderer()->isTable())
+        node = node->parentNode();
+    
+    return node->isContentRichlyEditable();
+}
+
+Element* editableRootForPosition(const Position& p)
+{
+    Node* node = p.node();
+    if (!node)
+        return 0;
+        
+    if (node->renderer() && node->renderer()->isTable())
+        node = node->parentNode();
+    
+    return node->rootEditableElement();
+}
+
+bool isContentEditable(const Node* node)
+{
+    return node->isContentEditable();
+}
+
+Position nextCandidate(const Position& position)
+{
+    PositionIterator p = position;
+    while (!p.atEnd()) {
+        p.increment();
+        if (p.isCandidate())
+            return p;
+    }
+    return Position();
+}
+
+Position nextVisuallyDistinctCandidate(const Position& position)
+{
+    Position p = position;
+    Position downstreamStart = p.downstream();
+    while (!p.atEnd()) {
+        p = p.next(UsingComposedCharacters);
+        if (p.isCandidate() && p.downstream() != downstreamStart)
+            return p;
+    }
+    return Position();
+}
+
+Position previousCandidate(const Position& position)
+{
+    PositionIterator p = position;
+    while (!p.atStart()) {
+        p.decrement();
+        if (p.isCandidate())
+            return p;
+    }
+    return Position();
+}
+
+Position previousVisuallyDistinctCandidate(const Position& position)
+{
+    Position p = position;
+    Position downstreamStart = p.downstream();
+    while (!p.atStart()) {
+        p = p.previous(UsingComposedCharacters);
+        if (p.isCandidate() && p.downstream() != downstreamStart)
+            return p;
+    }
+    return Position();
+}
+
+VisiblePosition firstEditablePositionAfterPositionInRoot(const Position& position, Node* highestRoot)
+{
+    // position falls before highestRoot.
+    if (comparePositions(position, Position(highestRoot, 0)) == -1 && highestRoot->isContentEditable())
+        return VisiblePosition(Position(highestRoot, 0));
+        
+    Position p = position;
+    
+    if (Node* shadowAncestor = p.node()->shadowAncestorNode())
+        if (shadowAncestor != p.node())
+            p = Position(shadowAncestor, maxDeepOffset(shadowAncestor));
+    
+    while (p.node() && !isEditablePosition(p) && p.node()->isDescendantOf(highestRoot))
+        p = isAtomicNode(p.node()) ? positionAfterNode(p.node()) : nextVisuallyDistinctCandidate(p);
+    
+    if (p.node() && !p.node()->isDescendantOf(highestRoot))
+        return VisiblePosition();
+    
+    return VisiblePosition(p);
+}
+
+VisiblePosition lastEditablePositionBeforePositionInRoot(const Position& position, Node* highestRoot)
+{
+    // When position falls after highestRoot, the result is easy to compute.
+    if (comparePositions(position, Position(highestRoot, maxDeepOffset(highestRoot))) == 1)
+        return VisiblePosition(Position(highestRoot, maxDeepOffset(highestRoot)));
+        
+    Position p = position;
+    
+    if (Node* shadowAncestor = p.node()->shadowAncestorNode())
+        if (shadowAncestor != p.node())
+            p = Position(shadowAncestor, 0);
+    
+    while (p.node() && !isEditablePosition(p) && p.node()->isDescendantOf(highestRoot))
+        p = isAtomicNode(p.node()) ? positionBeforeNode(p.node()) : previousVisuallyDistinctCandidate(p);
+    
+    if (p.node() && !p.node()->isDescendantOf(highestRoot))
+        return VisiblePosition();
+    
+    return VisiblePosition(p);
+}
+
+// Whether or not content before and after this node will collapse onto the same line as it.
+bool isBlock(const Node* node)
+{
+    return node && node->renderer() && !node->renderer()->isInline();
+}
+
+// FIXME: Deploy this in all of the places where enclosingBlockFlow/enclosingBlockFlowOrTableElement are used.
+// FIXME: Pass a position to this function.  The enclosing block of [table, x] for example, should be the
+// block that contains the table and not the table, and this function should be the only one responsible for
+// knowing about these kinds of special cases.
+Node* enclosingBlock(Node* node)
+{
+    return enclosingNodeOfType(Position(node, 0), &isBlock);
+}
+
+Position rangeCompliantEquivalent(const Position& pos)
+{
+    if (pos.isNull())
+        return Position();
+
+    Node *node = pos.node();
+    
+    if (pos.offset() <= 0) {
+        if (node->parentNode() && (editingIgnoresContent(node) || isTableElement(node)))
+            return positionBeforeNode(node);
+        return Position(node, 0);
+    }
+    
+    if (node->offsetInCharacters())
+        return Position(node, min(node->maxCharacterOffset(), pos.offset()));
+    
+    int maxCompliantOffset = node->childNodeCount();
+    if (pos.offset() > maxCompliantOffset) {
+        if (node->parentNode())
+            return positionAfterNode(node);
+        
+        // there is no other option at this point than to
+        // use the highest allowed position in the node
+        return Position(node, maxCompliantOffset);
+    }
+
+    // Editing should never generate positions like this.
+    if ((pos.offset() < maxCompliantOffset) && editingIgnoresContent(node)) {
+        ASSERT_NOT_REACHED();
+        return node->parentNode() ? positionBeforeNode(node) : Position(node, 0);
+    }
+    
+    if (pos.offset() == maxCompliantOffset && (editingIgnoresContent(node) || isTableElement(node)))
+        return positionAfterNode(node);
+    
+    return Position(pos);
+}
+
+Position rangeCompliantEquivalent(const VisiblePosition& vpos)
+{
+    return rangeCompliantEquivalent(vpos.deepEquivalent());
+}
+
+// This method is used to create positions in the DOM. It returns the maximum valid offset
+// in a node.  It returns 1 for some elements even though they do not have children, which
+// creates technically invalid DOM Positions.  Be sure to call rangeCompliantEquivalent
+// on a Position before using it to create a DOM Range, or an exception will be thrown.
+int maxDeepOffset(const Node *node)
+{
+    ASSERT(node);
+    if (!node)
+        return 0;
+    if (node->offsetInCharacters())
+        return node->maxCharacterOffset();
+        
+    if (node->hasChildNodes())
+        return node->childNodeCount();
+    
+    // NOTE: This should preempt the childNodeCount for, e.g., select nodes
+    if (editingIgnoresContent(node))
+        return 1;
+
+    return 0;
+}
+
+String stringWithRebalancedWhitespace(const String& string, bool startIsStartOfParagraph, bool endIsEndOfParagraph)
+{
+    DEFINE_STATIC_LOCAL(String, twoSpaces, ("  "));
+    DEFINE_STATIC_LOCAL(String, nbsp, ("\xa0"));
+    DEFINE_STATIC_LOCAL(String, pattern, (" \xa0"));
+
+    String rebalancedString = string;
+
+    rebalancedString.replace(noBreakSpace, ' ');
+    rebalancedString.replace('\n', ' ');
+    rebalancedString.replace('\t', ' ');
+    
+    rebalancedString.replace(twoSpaces, pattern);
+    
+    if (startIsStartOfParagraph && rebalancedString[0] == ' ')
+        rebalancedString.replace(0, 1, nbsp);
+    int end = rebalancedString.length() - 1;
+    if (endIsEndOfParagraph && rebalancedString[end] == ' ')
+        rebalancedString.replace(end, 1, nbsp);    
+
+    return rebalancedString;
+}
+
+bool isTableStructureNode(const Node *node)
+{
+    RenderObject *r = node->renderer();
+    return (r && (r->isTableCell() || r->isTableRow() || r->isTableSection() || r->isTableCol()));
+}
+
+const String& nonBreakingSpaceString()
+{
+    DEFINE_STATIC_LOCAL(String, nonBreakingSpaceString, (&noBreakSpace, 1));
+    return nonBreakingSpaceString;
+}
+
+// FIXME: need to dump this
+bool isSpecialElement(const Node *n)
+{
+    if (!n)
+        return false;
+        
+    if (!n->isHTMLElement())
+        return false;
+
+    if (n->isLink())
+        return true;
+
+    RenderObject *renderer = n->renderer();
+    if (!renderer)
+        return false;
+        
+    if (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE)
+        return true;
+
+    if (renderer->style()->isFloating())
+        return true;
+
+    if (renderer->style()->position() != StaticPosition)
+        return true;
+        
+    return false;
+}
+
+// Checks if a string is a valid tag for the FormatBlockCommand function of execCommand. Expects lower case strings.
+bool validBlockTag(const String& blockTag)
+{
+    if (blockTag == "address" ||
+        blockTag == "blockquote" ||
+        blockTag == "dd" ||
+        blockTag == "div" ||
+        blockTag == "dl" ||
+        blockTag == "dt" ||
+        blockTag == "h1" ||
+        blockTag == "h2" ||
+        blockTag == "h3" ||
+        blockTag == "h4" ||
+        blockTag == "h5" ||
+        blockTag == "h6" ||
+        blockTag == "p" ||
+        blockTag == "pre")
+        return true;
+    return false;
+}
+
+static Node* firstInSpecialElement(const Position& pos)
+{
+    Node* rootEditableElement = pos.node()->rootEditableElement();
+    for (Node* n = pos.node(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
+        if (isSpecialElement(n)) {
+            VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
+            VisiblePosition firstInElement = VisiblePosition(n, 0, DOWNSTREAM);
+            if (isTableElement(n) && vPos == firstInElement.next())
+                return n;
+            if (vPos == firstInElement)
+                return n;
+        }
+    return 0;
+}
+
+static Node* lastInSpecialElement(const Position& pos)
+{
+    Node* rootEditableElement = pos.node()->rootEditableElement();
+    for (Node* n = pos.node(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
+        if (isSpecialElement(n)) {
+            VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
+            VisiblePosition lastInElement = VisiblePosition(n, n->childNodeCount(), DOWNSTREAM);
+            if (isTableElement(n) && vPos == lastInElement.previous())
+                return n;
+            if (vPos == lastInElement)
+                return n;
+        }
+    return 0;
+}
+
+bool isFirstVisiblePositionInSpecialElement(const Position& pos)
+{
+    return firstInSpecialElement(pos);
+}
+
+Position positionBeforeContainingSpecialElement(const Position& pos, Node** containingSpecialElement)
+{
+    Node* n = firstInSpecialElement(pos);
+    if (!n)
+        return pos;
+    Position result = positionBeforeNode(n);
+    if (result.isNull() || result.node()->rootEditableElement() != pos.node()->rootEditableElement())
+        return pos;
+    if (containingSpecialElement)
+        *containingSpecialElement = n;
+    return result;
+}
+
+bool isLastVisiblePositionInSpecialElement(const Position& pos)
+{
+    return lastInSpecialElement(pos);
+}
+
+Position positionAfterContainingSpecialElement(const Position& pos, Node **containingSpecialElement)
+{
+    Node* n = lastInSpecialElement(pos);
+    if (!n)
+        return pos;
+    Position result = positionAfterNode(n);
+    if (result.isNull() || result.node()->rootEditableElement() != pos.node()->rootEditableElement())
+        return pos;
+    if (containingSpecialElement)
+        *containingSpecialElement = n;
+    return result;
+}
+
+Position positionOutsideContainingSpecialElement(const Position &pos, Node **containingSpecialElement)
+{
+    if (isFirstVisiblePositionInSpecialElement(pos))
+        return positionBeforeContainingSpecialElement(pos, containingSpecialElement);
+    if (isLastVisiblePositionInSpecialElement(pos))
+        return positionAfterContainingSpecialElement(pos, containingSpecialElement);
+    return pos;
+}
+
+Node* isFirstPositionAfterTable(const VisiblePosition& visiblePosition)
+{
+    Position upstream(visiblePosition.deepEquivalent().upstream());
+    if (upstream.node() && upstream.node()->renderer() && upstream.node()->renderer()->isTable() && upstream.offset() == maxDeepOffset(upstream.node()))
+        return upstream.node();
+    
+    return 0;
+}
+
+Node* isLastPositionBeforeTable(const VisiblePosition& visiblePosition)
+{
+    Position downstream(visiblePosition.deepEquivalent().downstream());
+    if (downstream.node() && downstream.node()->renderer() && downstream.node()->renderer()->isTable() && downstream.offset() == 0)
+        return downstream.node();
+    
+    return 0;
+}
+
+Position positionBeforeNode(const Node *node)
+{
+    return Position(node->parentNode(), node->nodeIndex());
+}
+
+Position positionAfterNode(const Node *node)
+{
+    return Position(node->parentNode(), node->nodeIndex() + 1);
+}
+
+bool isListElement(Node *n)
+{
+    return (n && (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(dlTag)));
+}
+
+Node* enclosingNodeWithTag(const Position& p, const QualifiedName& tagName)
+{
+    if (p.isNull())
+        return 0;
+        
+    Node* root = highestEditableRoot(p);
+    for (Node* n = p.node(); n; n = n->parentNode()) {
+        if (root && !isContentEditable(n))
+            continue;
+        if (n->hasTagName(tagName))
+            return n;
+        if (n == root)
+            return 0;
+    }
+    
+    return 0;
+}
+
+Node* enclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*), bool onlyReturnEditableNodes)
+{
+    if (p.isNull())
+        return 0;
+        
+    Node* root = highestEditableRoot(p);
+    for (Node* n = p.node(); n; n = n->parentNode()) {
+        // Don't return a non-editable node if the input position was editable, since
+        // the callers from editing will no doubt want to perform editing inside the returned node.
+        if (root && !isContentEditable(n) && onlyReturnEditableNodes)
+            continue;
+        if ((*nodeIsOfType)(n))
+            return n;
+        if (n == root)
+            return 0;
+    }
+    
+    return 0;
+}
+
+Node* highestEnclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*))
+{
+    Node* highest = 0;
+    Node* root = highestEditableRoot(p);
+    for (Node* n = p.node(); n; n = n->parentNode()) {
+        if ((*nodeIsOfType)(n))
+            highest = n;
+        if (n == root)
+            break;
+    }
+    
+    return highest;
+}
+
+Node* enclosingTableCell(const Position& p)
+{
+    return enclosingNodeOfType(p, &isTableCell);
+}
+
+Node* enclosingAnchorElement(const Position& p)
+{
+    if (p.isNull())
+        return 0;
+    
+    Node* node = p.node();
+    while (node && !(node->isElementNode() && node->isLink()))
+        node = node->parentNode();
+    return node;
+}
+
+Node* enclosingList(Node* node)
+{
+    if (!node)
+        return 0;
+        
+    Node* root = highestEditableRoot(Position(node, 0));
+    
+    for (Node* n = node->parentNode(); n; n = n->parentNode()) {
+        if (n->hasTagName(ulTag) || n->hasTagName(olTag))
+            return n;
+        if (n == root)
+            return 0;
+    }
+    
+    return 0;
+}
+
+Node* enclosingListChild(Node *node)
+{
+    if (!node)
+        return 0;
+    // Check for a list item element, or for a node whose parent is a list element.  Such a node
+    // will appear visually as a list item (but without a list marker)
+    Node* root = highestEditableRoot(Position(node, 0));
+    
+    // FIXME: This function is inappropriately named if it starts with node instead of node->parentNode()
+    for (Node* n = node; n && n->parentNode(); n = n->parentNode()) {
+        if (n->hasTagName(liTag) || isListElement(n->parentNode()))
+            return n;
+        if (n == root || isTableCell(n))
+            return 0;
+    }
+    
+    return 0;
+}
+
+static Node* embeddedSublist(Node* listItem)
+{
+    // Check the DOM so that we'll find collapsed sublists without renderers.
+    for (Node* n = listItem->firstChild(); n; n = n->nextSibling()) {
+        if (isListElement(n))
+            return n;
+    }
+    
+    return 0;
+}
+
+static Node* appendedSublist(Node* listItem)
+{
+    // Check the DOM so that we'll find collapsed sublists without renderers.
+    for (Node* n = listItem->nextSibling(); n; n = n->nextSibling()) {
+        if (isListElement(n))
+            return n;
+        if (n->renderer() && n->renderer()->isListItem())
+            return 0;
+    }
+    
+    return 0;
+}
+
+Node* enclosingEmptyListItem(const VisiblePosition& visiblePos)
+{
+    // Check that position is on a line by itself inside a list item
+    Node* listChildNode = enclosingListChild(visiblePos.deepEquivalent().node());
+    if (!listChildNode || !isStartOfParagraph(visiblePos) || !isEndOfParagraph(visiblePos))
+        return 0;
+        
+    VisiblePosition firstInListChild(Position(listChildNode, 0));
+    VisiblePosition lastInListChild(Position(listChildNode, maxDeepOffset(listChildNode)));
+    
+    if (firstInListChild != visiblePos || lastInListChild != visiblePos)
+        return 0;
+    
+    if (embeddedSublist(listChildNode) || appendedSublist(listChildNode))
+        return 0;
+        
+    return listChildNode;
+}
+
+Node* outermostEnclosingListChild(Node* node)
+{
+    Node* listNode = 0;
+    Node* nextNode = node;
+    while ((nextNode = enclosingListChild(nextNode)))
+        listNode = nextNode;
+    return listNode;
+}
+
+Node* outermostEnclosingList(Node* node)
+{
+    Node* listNode = 0;
+    Node* nextNode = node;
+    while ((nextNode = enclosingList(nextNode)))
+        listNode = nextNode;
+    return listNode;
+}
+
+Node* highestAncestor(Node* node)
+{
+    ASSERT(node);
+    Node* parent = node;
+    while ((node = node->parentNode()))
+        parent = node;
+    return parent;
+}
+
+// FIXME: do not require renderer, so that this can be used within fragments, or rename to isRenderedTable()
+bool isTableElement(Node* n)
+{
+    if (!n || !n->isElementNode())
+        return false;
+
+    RenderObject* renderer = n->renderer();
+    return (renderer && (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE));
+}
+
+bool isTableCell(const Node* node)
+{
+    RenderObject* r = node->renderer();
+    if (!r)
+        return node->hasTagName(tdTag) || node->hasTagName(thTag);
+    
+    return r->isTableCell();
+}
+
+PassRefPtr<Element> createDefaultParagraphElement(Document *document)
+{
+    ExceptionCode ec = 0;
+    RefPtr<Element> element = document->createElementNS(xhtmlNamespaceURI, "div", ec);
+    ASSERT(ec == 0);
+    return element.release();
+}
+
+PassRefPtr<Element> createBreakElement(Document *document)
+{
+    ExceptionCode ec = 0;
+    RefPtr<Element> breakNode = document->createElementNS(xhtmlNamespaceURI, "br", ec);
+    ASSERT(ec == 0);
+    return breakNode.release();
+}
+
+PassRefPtr<Element> createOrderedListElement(Document *document)
+{
+    ExceptionCode ec = 0;
+    RefPtr<Element> element = document->createElementNS(xhtmlNamespaceURI, "ol", ec);
+    ASSERT(ec == 0);
+    return element.release();
+}
+
+PassRefPtr<Element> createUnorderedListElement(Document *document)
+{
+    ExceptionCode ec = 0;
+    RefPtr<Element> element = document->createElementNS(xhtmlNamespaceURI, "ul", ec);
+    ASSERT(ec == 0);
+    return element.release();
+}
+
+PassRefPtr<Element> createListItemElement(Document *document)
+{
+    ExceptionCode ec = 0;
+    RefPtr<Element> breakNode = document->createElementNS(xhtmlNamespaceURI, "li", ec);
+    ASSERT(ec == 0);
+    return breakNode.release();
+}
+
+PassRefPtr<Element> createElement(Document* document, const String& tagName)
+{
+    ExceptionCode ec = 0;
+    RefPtr<Element> breakNode = document->createElementNS(xhtmlNamespaceURI, tagName, ec);
+    ASSERT(ec == 0);
+    return breakNode.release();
+}
+
+bool isTabSpanNode(const Node *node)
+{
+    return node && node->hasTagName(spanTag) && node->isElementNode() && static_cast<const Element *>(node)->getAttribute(classAttr) == AppleTabSpanClass;
+}
+
+bool isTabSpanTextNode(const Node *node)
+{
+    return node && node->isTextNode() && node->parentNode() && isTabSpanNode(node->parentNode());
+}
+
+Node *tabSpanNode(const Node *node)
+{
+    return isTabSpanTextNode(node) ? node->parentNode() : 0;
+}
+
+Position positionBeforeTabSpan(const Position& pos)
+{
+    Node *node = pos.node();
+    if (isTabSpanTextNode(node))
+        node = tabSpanNode(node);
+    else if (!isTabSpanNode(node))
+        return pos;
+    
+    return positionBeforeNode(node);
+}
+
+PassRefPtr<Element> createTabSpanElement(Document* document, PassRefPtr<Node> tabTextNode)
+{
+    // make the span to hold the tab
+    ExceptionCode ec = 0;
+    RefPtr<Element> spanElement = document->createElementNS(xhtmlNamespaceURI, "span", ec);
+    ASSERT(ec == 0);
+    spanElement->setAttribute(classAttr, AppleTabSpanClass);
+    spanElement->setAttribute(styleAttr, "white-space:pre");
+
+    // add tab text to that span
+    if (!tabTextNode)
+        tabTextNode = document->createEditingTextNode("\t");
+    spanElement->appendChild(tabTextNode, ec);
+    ASSERT(ec == 0);
+
+    return spanElement.release();
+}
+
+PassRefPtr<Element> createTabSpanElement(Document* document, const String& tabText)
+{
+    return createTabSpanElement(document, document->createTextNode(tabText));
+}
+
+PassRefPtr<Element> createTabSpanElement(Document* document)
+{
+    return createTabSpanElement(document, PassRefPtr<Node>());
+}
+
+bool isNodeRendered(const Node *node)
+{
+    if (!node)
+        return false;
+
+    RenderObject *renderer = node->renderer();
+    if (!renderer)
+        return false;
+
+    return renderer->style()->visibility() == VISIBLE;
+}
+
+Node *nearestMailBlockquote(const Node *node)
+{
+    for (Node *n = const_cast<Node *>(node); n; n = n->parentNode()) {
+        if (isMailBlockquote(n))
+            return n;
+    }
+    return 0;
+}
+
+unsigned numEnclosingMailBlockquotes(const Position& p)
+{
+    unsigned num = 0;
+    for (Node* n = p.node(); n; n = n->parentNode())
+        if (isMailBlockquote(n))
+            num++;
+    
+    return num;
+}
+
+bool isMailBlockquote(const Node *node)
+{
+    if (!node || !node->isElementNode() && !node->hasTagName(blockquoteTag))
+        return false;
+        
+    return static_cast<const Element *>(node)->getAttribute("type") == "cite";
+}
+
+int caretMinOffset(const Node* n)
+{
+    RenderObject* r = n->renderer();
+    ASSERT(!n->isCharacterDataNode() || !r || r->isText()); // FIXME: This was a runtime check that seemingly couldn't fail; changed it to an assertion for now.
+    return r ? r->caretMinOffset() : 0;
+}
+
+int caretMaxOffset(const Node* n)
+{
+    RenderObject* r = n->renderer();
+    ASSERT(!n->isCharacterDataNode() || !r || r->isText()); // FIXME: This was a runtime check that seemingly couldn't fail; changed it to an assertion for now.
+    if (r)
+        return r->caretMaxOffset();
+
+    if (n->isCharacterDataNode()) {
+        const CharacterData* c = static_cast<const CharacterData*>(n);
+        return static_cast<int>(c->length());
+    }
+    return 1;
+}
+
+bool lineBreakExistsAtPosition(const VisiblePosition& visiblePosition)
+{
+    if (visiblePosition.isNull())
+        return false;
+        
+    Position downstream(visiblePosition.deepEquivalent().downstream());
+    return downstream.node()->hasTagName(brTag) ||
+           downstream.node()->isTextNode() && downstream.node()->renderer()->style()->preserveNewline() && visiblePosition.characterAfter() == '\n';
+}
+
+// Modifies selections that have an end point at the edge of a table
+// that contains the other endpoint so that they don't confuse
+// code that iterates over selected paragraphs.
+Selection selectionForParagraphIteration(const Selection& original)
+{
+    Selection newSelection(original);
+    VisiblePosition startOfSelection(newSelection.visibleStart());
+    VisiblePosition endOfSelection(newSelection.visibleEnd());
+    
+    // If the end of the selection to modify is just after a table, and
+    // if the start of the selection is inside that table, then the last paragraph
+    // that we'll want modify is the last one inside the table, not the table itself
+    // (a table is itself a paragraph).
+    if (Node* table = isFirstPositionAfterTable(endOfSelection))
+        if (startOfSelection.deepEquivalent().node()->isDescendantOf(table))
+            newSelection = Selection(startOfSelection, endOfSelection.previous(true));
+    
+    // If the start of the selection to modify is just before a table,
+    // and if the end of the selection is inside that table, then the first paragraph
+    // we'll want to modify is the first one inside the table, not the paragraph
+    // containing the table itself.
+    if (Node* table = isLastPositionBeforeTable(startOfSelection))
+        if (endOfSelection.deepEquivalent().node()->isDescendantOf(table))
+            newSelection = Selection(startOfSelection.next(true), endOfSelection);
+    
+    return newSelection;
+}
+
+
+int indexForVisiblePosition(VisiblePosition& visiblePosition)
+{
+    if (visiblePosition.isNull())
+        return 0;
+    Position p(visiblePosition.deepEquivalent());
+    RefPtr<Range> range = Range::create(p.node()->document(), Position(p.node()->document(), 0), rangeCompliantEquivalent(p));
+    return TextIterator::rangeLength(range.get(), true);
+}
+
+PassRefPtr<Range> avoidIntersectionWithNode(const Range* range, Node* node)
+{
+    if (!range)
+        return 0;
+
+    Document* document = range->ownerDocument();
+
+    Node* startContainer = range->startContainer();
+    int startOffset = range->startOffset();
+    Node* endContainer = range->endContainer();
+    int endOffset = range->endOffset();
+
+    if (!startContainer)
+        return 0;
+
+    ASSERT(endContainer);
+
+    if (startContainer == node || startContainer->isDescendantOf(node)) {
+        ASSERT(node->parentNode());
+        startContainer = node->parentNode();
+        startOffset = node->nodeIndex();
+    }
+    if (endContainer == node || endContainer->isDescendantOf(node)) {
+        ASSERT(node->parentNode());
+        endContainer = node->parentNode();
+        endOffset = node->nodeIndex();
+    }
+
+    return Range::create(document, startContainer, startOffset, endContainer, endOffset);
+}
+
+Selection avoidIntersectionWithNode(const Selection& selection, Node* node)
+{
+    if (selection.isNone())
+        return Selection(selection);
+        
+    Selection updatedSelection(selection);
+    Node* base = selection.base().node();
+    Node* extent = selection.extent().node();
+    ASSERT(base);
+    ASSERT(extent);
+    
+    if (base == node || base->isDescendantOf(node)) {
+        ASSERT(node->parentNode());
+        updatedSelection.setBase(Position(node->parentNode(), node->nodeIndex()));
+    }
+    
+    if (extent == node || extent->isDescendantOf(node)) {
+        ASSERT(node->parentNode());
+        updatedSelection.setExtent(Position(node->parentNode(), node->nodeIndex()));
+    }
+        
+    return updatedSelection;
+}
+
+} // namespace WebCore
diff --git a/khtml/xml/editing.h b/khtml/xml/editing.h
new file mode 100644
index 0000000..96c4dcb
--- /dev/null
+++ b/khtml/xml/editing.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2004, 2006 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef htmlediting_h
+#define htmlediting_h
+
+#include <wtf/Forward.h>
+#include "HTMLNames.h"
+
+namespace WebCore {
+
+class Document;
+class Element;
+class Node;
+class Position;
+class Range;
+class Selection;
+class String;
+class VisiblePosition;
+
+Position rangeCompliantEquivalent(const Position&);
+Position rangeCompliantEquivalent(const VisiblePosition&);
+int maxDeepOffset(const Node*);
+bool isAtomicNode(const Node*);
+bool editingIgnoresContent(const Node*);
+bool canHaveChildrenForEditing(const Node*);
+Node* highestEditableRoot(const Position&);
+VisiblePosition firstEditablePositionAfterPositionInRoot(const Position&, Node*);
+VisiblePosition lastEditablePositionBeforePositionInRoot(const Position&, Node*);
+int comparePositions(const Position&, const Position&);
+Node* lowestEditableAncestor(Node*);
+bool isContentEditable(const Node*);
+Position nextCandidate(const Position&);
+Position nextVisuallyDistinctCandidate(const Position&);
+Position previousCandidate(const Position&);
+Position previousVisuallyDistinctCandidate(const Position&);
+bool isEditablePosition(const Position&);
+bool isRichlyEditablePosition(const Position&);
+Element* editableRootForPosition(const Position&);
+bool isBlock(const Node*);
+Node* enclosingBlock(Node*);
+
+String stringWithRebalancedWhitespace(const String&, bool, bool);
+const String& nonBreakingSpaceString();
+
+//------------------------------------------------------------------------------------------
+
+Position positionBeforeNode(const Node*);
+Position positionAfterNode(const Node*);
+
+PassRefPtr<Range> avoidIntersectionWithNode(const Range*, Node*);
+Selection avoidIntersectionWithNode(const Selection&, Node*);
+
+bool isSpecialElement(const Node*);
+bool validBlockTag(const String&);
+
+PassRefPtr<Element> createDefaultParagraphElement(Document*);
+PassRefPtr<Element> createBreakElement(Document*);
+PassRefPtr<Element> createOrderedListElement(Document*);
+PassRefPtr<Element> createUnorderedListElement(Document*);
+PassRefPtr<Element> createListItemElement(Document*);
+PassRefPtr<Element> createElement(Document*, const String&);
+
+bool isTabSpanNode(const Node*);
+bool isTabSpanTextNode(const Node*);
+Node* tabSpanNode(const Node*);
+Position positionBeforeTabSpan(const Position&);
+PassRefPtr<Element> createTabSpanElement(Document*);
+PassRefPtr<Element> createTabSpanElement(Document*, PassRefPtr<Node> tabTextNode);
+PassRefPtr<Element> createTabSpanElement(Document*, const String& tabText);
+
+bool isNodeRendered(const Node*);
+bool isMailBlockquote(const Node*);
+Node* nearestMailBlockquote(const Node*);
+unsigned numEnclosingMailBlockquotes(const Position&);
+int caretMinOffset(const Node*);
+int caretMaxOffset(const Node*);
+
+//------------------------------------------------------------------------------------------
+
+bool isTableStructureNode(const Node*);
+PassRefPtr<Element> createBlockPlaceholderElement(Document*);
+
+bool isFirstVisiblePositionInSpecialElement(const Position&);
+Position positionBeforeContainingSpecialElement(const Position&, Node** containingSpecialElement=0);
+bool isLastVisiblePositionInSpecialElement(const Position&);
+Position positionAfterContainingSpecialElement(const Position&, Node** containingSpecialElement=0);
+Position positionOutsideContainingSpecialElement(const Position&, Node** containingSpecialElement=0);
+Node* isLastPositionBeforeTable(const VisiblePosition&);
+Node* isFirstPositionAfterTable(const VisiblePosition&);
+
+Node* enclosingNodeWithTag(const Position&, const QualifiedName&);
+Node* enclosingNodeOfType(const Position&, bool (*nodeIsOfType)(const Node*), bool onlyReturnEditableNodes = true);
+Node* highestEnclosingNodeOfType(const Position&, bool (*nodeIsOfType)(const Node*));
+Node* enclosingTableCell(const Position&);
+Node* enclosingEmptyListItem(const VisiblePosition&);
+Node* enclosingAnchorElement(const Position&);
+bool isListElement(Node*);
+Node* enclosingList(Node*);
+Node* outermostEnclosingList(Node*);
+Node* enclosingListChild(Node*);
+Node* highestAncestor(Node*);
+bool isTableElement(Node*);
+bool isTableCell(const Node*);
+
+bool lineBreakExistsAtPosition(const VisiblePosition&);
+
+Selection selectionForParagraphIteration(const Selection&);
+
+int indexForVisiblePosition(VisiblePosition&);
+
+}
+
+#endif
diff --git a/khtml/xml/editing_helper.cpp b/khtml/xml/editing_helper.cpp
new file mode 100644
index 0000000..9b4642c
--- /dev/null
+++ b/khtml/xml/editing_helper.cpp
@@ -0,0 +1,1017 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "xml/editing_helper.h"
+
+#include "xml/dom_docimpl.h"
+#include "xml/Position.h"
+#include "xml/dom2_rangeimpl.h"
+#include "xml/VisiblePosition.h"
+#include "rendering/render_object.h"
+#include "xml/PositionIterator.h"
+#include "xml/dom_textimpl.h"
+#include "xml/Selection.h"
+
+using namespace DOM;
+
+using namespace std;
+
+namespace khtml {
+
+// Atomic means that the node has no children, or has children which are ignored for the
+// purposes of editing.
+bool isAtomicNode(const NodeImpl *node)
+{
+    return node && (!node->hasChildNodes() || editingIgnoresContent(node));
+}
+
+// Returns true for nodes that either have no content, or have content that is ignored (skipped
+// over) while editing.  There are no VisiblePositions inside these nodes.
+bool editingIgnoresContent(const NodeImpl* node)
+{
+    return !canHaveChildrenForEditing(node) && !node->isTextNode();
+}
+
+bool canHaveChildrenForEditing(const NodeImpl* node)
+{
+    if (node->isTextNode()) return false;
+    switch (node->id()) {
+        case ID_HR:
+        case ID_BR:
+        case ID_IMG:
+        case ID_IMAGE: // ???
+        case ID_BUTTON:
+        case ID_INPUT:
+        case ID_TEXTAREA:
+        case ID_OBJECT:
+        case ID_IFRAME:
+        case ID_EMBED:
+        case ID_APPLET:
+        case ID_SELECT:
+            return false;
+    }
+    return true;
+}
+
+// Compare two positions, taking into account the possibility that one or both
+// could be inside a shadow tree. Only works for non-null values.
+int comparePositions(const Position& a, const Position& b)
+{
+    NodeImpl* nodeA = a.node();
+    assert(nodeA);
+    NodeImpl* nodeB = b.node();
+    assert(nodeB);
+    int offsetA = a.offset();
+    int offsetB = b.offset();
+
+    NodeImpl* shadowAncestorA = nodeA->shadowAncestorNode();
+    if (shadowAncestorA == nodeA)
+        shadowAncestorA = 0;
+    NodeImpl* shadowAncestorB = nodeB->shadowAncestorNode();
+    if (shadowAncestorB == nodeB)
+        shadowAncestorB = 0;
+
+    int bias = 0;
+    if (shadowAncestorA != shadowAncestorB) {
+        if (shadowAncestorA) {
+            nodeA = shadowAncestorA;
+            offsetA = 0;
+            bias = 1;
+        }
+        if (shadowAncestorB) {
+            nodeB = shadowAncestorB;
+            offsetB = 0;
+            bias = -1;
+        }
+    }
+
+    int result = RangeImpl::compareBoundaryPoints(nodeA, offsetA, nodeB, offsetB);
+    return result ? result : bias;
+}
+
+NodeImpl* highestEditableRoot(const Position& position)
+{
+    NodeImpl* node = position.node();
+    if (!node)
+        return 0;
+        
+    NodeImpl* highestRoot = editableRootForPosition(position);
+    if (!highestRoot)
+        return 0;
+    
+    node = highestRoot;
+    while (node) {
+        if (node->isContentEditable())
+            highestRoot = node;
+        if (node->id() == ID_BODY)
+            break;
+        node = node->parentNode();
+    }
+    
+    return highestRoot;
+}
+
+NodeImpl* lowestEditableAncestor(NodeImpl* node)
+{
+    if (!node)
+        return 0;
+    
+    NodeImpl *lowestRoot = 0;
+    while (node) {
+        if (node->isContentEditable())
+            return node->rootEditableElement();
+        if (node->id() == ID_BODY)
+            break;
+        node = node->parentNode();
+    }
+    
+    return lowestRoot;
+}
+
+bool isEditablePosition(const Position& p)
+{
+    NodeImpl* node = p.node();
+    if (!node)
+        return false;
+        
+    if (node->renderer() && node->renderer()->isTable())
+        node = node->parentNode();
+    
+    return node->isContentEditable();
+}
+
+bool isRichlyEditablePosition(const Position& p)
+{
+    NodeImpl* node = p.node();
+    if (!node)
+        return false;
+        
+    if (node->renderer() && node->renderer()->isTable())
+        node = node->parentNode();
+    
+    return node->isContentRichlyEditable();
+}
+
+ElementImpl* editableRootForPosition(const Position& p)
+{
+    NodeImpl* node = p.node();
+    if (!node)
+        return 0;
+        
+    if (node->renderer() && node->renderer()->isTable())
+        node = node->parentNode();
+    
+    return node->rootEditableElement();
+}
+
+bool isContentEditable(const NodeImpl* node)
+{
+    return node->isContentEditable();
+}
+
+Position nextCandidate(const Position& position)
+{
+    PositionIterator p = position;
+    while (!p.atEnd()) {
+        p.increment();
+        if (p.isCandidate())
+            return p;
+    }
+    return Position();
+}
+
+Position nextVisuallyDistinctCandidate(const Position& position)
+{
+    Position p = position;
+    Position downstreamStart = p.downstream();
+    while (!p.atEnd()) {
+        p = p.next(UsingComposedCharacters);
+        if (p.isCandidate() && p.downstream() != downstreamStart)
+            return p;
+    }
+    return Position();
+}
+
+Position previousCandidate(const Position& position)
+{
+    PositionIterator p = position;
+    while (!p.atStart()) {
+        p.decrement();
+        if (p.isCandidate())
+            return p;
+    }
+    return Position();
+}
+
+Position previousVisuallyDistinctCandidate(const Position& position)
+{
+    Position p = position;
+    Position downstreamStart = p.downstream();
+    while (!p.atStart()) {
+        p = p.previous(UsingComposedCharacters);
+        if (p.isCandidate() && p.downstream() != downstreamStart)
+            return p;
+    }
+    return Position();
+}
+
+VisiblePosition firstEditablePositionAfterPositionInRoot(const Position& position, NodeImpl* highestRoot)
+{
+    // position falls before highestRoot.
+    if (comparePositions(position, Position(highestRoot, 0)) == -1 && highestRoot->isContentEditable())
+        return VisiblePosition(Position(highestRoot, 0));
+        
+    Position p = position;
+    
+    if (NodeImpl* shadowAncestor = p.node()->shadowAncestorNode())
+        if (shadowAncestor != p.node())
+            p = Position(shadowAncestor, maxDeepOffset(shadowAncestor));
+    
+    while (p.node() && !isEditablePosition(p) && p.node()->isAncestor(highestRoot))
+        p = isAtomicNode(p.node()) ? positionAfterNode(p.node()) : nextVisuallyDistinctCandidate(p);
+    
+    if (p.node() && !p.node()->isAncestor(highestRoot))
+        return VisiblePosition();
+    
+    return VisiblePosition(p);
+}
+
+VisiblePosition lastEditablePositionBeforePositionInRoot(const Position& position, NodeImpl* highestRoot)
+{
+    // When position falls after highestRoot, the result is easy to compute.
+    if (comparePositions(position, Position(highestRoot, maxDeepOffset(highestRoot))) == 1)
+        return VisiblePosition(Position(highestRoot, maxDeepOffset(highestRoot)));
+        
+    Position p = position;
+    
+    if (NodeImpl* shadowAncestor = p.node()->shadowAncestorNode())
+        if (shadowAncestor != p.node())
+            p = Position(shadowAncestor, 0);
+    
+    while (p.node() && !isEditablePosition(p) && p.node()->isAncestor(highestRoot))
+        p = isAtomicNode(p.node()) ? positionBeforeNode(p.node()) : previousVisuallyDistinctCandidate(p);
+    
+    if (p.node() && !p.node()->isAncestor(highestRoot))
+        return VisiblePosition();
+    
+    return VisiblePosition(p);
+}
+
+// Whether or not content before and after this node will collapse onto the same line as it.
+bool isBlock(const NodeImpl* node)
+{
+    return node && node->renderer() && !node->renderer()->isInline();
+}
+
+// FIXME: Deploy this in all of the places where enclosingBlockFlow/enclosingBlockFlowOrTableElementImpl are used.
+// FIXME: Pass a position to this function.  The enclosing block of [table, x] for example, should be the
+// block that contains the table and not the table, and this function should be the only one responsible for
+// knowing about these kinds of special cases.
+NodeImpl* enclosingBlock(NodeImpl* node)
+{
+    return enclosingNodeImplOfType(Position(node, 0), &isBlock);
+}
+
+Position rangeCompliantEquivalent(const Position& pos)
+{
+    if (pos.isNull())
+        return Position();
+
+    NodeImpl *node = pos.node();
+    
+    if (pos.offset() <= 0) {
+        if (node->parentNode() && (editingIgnoresContent(node) || isTableElement(node)))
+            return positionBeforeNode(node);
+        return Position(node, 0);
+    }
+    
+    if (node->offsetInCharacters())
+        return Position(node, min(node->maxCharacterOffset(), pos.offset()));
+    
+    int maxCompliantOffset = node->childNodeCount();
+    if (pos.offset() > maxCompliantOffset) {
+        if (node->parentNode())
+            return positionAfterNode(node);
+        
+        // there is no other option at this point than to
+        // use the highest allowed position in the node
+        return Position(node, maxCompliantOffset);
+    }
+
+    // Editing should never generate positions like this.
+    if ((pos.offset() < maxCompliantOffset) && editingIgnoresContent(node)) {
+        // FIXME khtml? ASSERT_NOT_REACHED();
+        return node->parentNode() ? positionBeforeNode(node) : Position(node, 0);
+    }
+    
+    if (pos.offset() == maxCompliantOffset && (editingIgnoresContent(node) || isTableElement(node)))
+        return positionAfterNode(node);
+    
+    return Position(pos);
+}
+
+Position rangeCompliantEquivalent(const VisiblePosition& vpos)
+{
+    return rangeCompliantEquivalent(vpos.deepEquivalent());
+}
+
+// This method is used to create positions in the DOM. It returns the maximum valid offset
+// in a node.  It returns 1 for some elements even though they do not have children, which
+// creates technically invalid DOM Positions.  Be sure to call rangeCompliantEquivalent
+// on a Position before using it to create a DOM RangeImpl, or an exception will be thrown.
+int maxDeepOffset(const NodeImpl *node)
+{
+    assert(node);
+    if (!node)
+        return 0;
+    if (node->offsetInCharacters())
+        return node->maxCharacterOffset();
+        
+    if (node->hasChildNodes())
+        return node->childNodeCount();
+    
+    // NOTE: This should preempt the childNodeCount for, e.g., select nodes
+    if (editingIgnoresContent(node))
+        return 1;
+
+    return 0;
+}
+
+#define DEFINE_STATIC_LOCAL(a, b, c) a b(c);
+
+/*DOMString stringWithRebalancedWhitespace(const DOMString& string, bool startIsStartOfParagraph, bool endIsEndOfParagraph)
+{
+    DEFINE_STATIC_LOCAL(DOMString, twoSpaces, ("  "));
+    DEFINE_STATIC_LOCAL(DOMString, nbsp, ("\xa0"));
+    DEFINE_STATIC_LOCAL(DOMString, pattern, (" \xa0"));
+
+    DOMString rebalancedString = string;
+
+    rebalancedString.replace(noBreakSpace, ' ');
+    rebalancedString.replace('\n', ' ');
+    rebalancedString.replace('\t', ' ');
+    
+    rebalancedString.replace(twoSpaces, pattern);
+    
+    if (startIsStartOfParagraph && rebalancedString[0] == ' ')
+        rebalancedString.replace(0, 1, nbsp);
+    int end = rebalancedString.length() - 1;
+    if (endIsEndOfParagraph && rebalancedString[end] == ' ')
+        rebalancedString.replace(end, 1, nbsp);    
+
+    return rebalancedString;
+}*/
+
+bool isTableStructureNode(const NodeImpl *node)
+{
+    RenderObject *r = node->renderer();
+    return (r && (r->isTableCell() || r->isTableRow() || r->isTableSection() || r->isTableCol()));
+}
+
+/*FIXME khtml const DOMString& nonBreakingSpaceString()
+{
+    DEFINE_STATIC_LOCAL(DOMString, nonBreakingSpaceString, (&noBreakSpace, 1));
+    return nonBreakingSpaceString;
+}*/
+
+// FIXME: need to dump this
+bool isSpecialElement(const NodeImpl *n)
+{
+    if (!n)
+        return false;
+        
+    if (!n->isHTMLElement())
+        return false;
+
+    /*FIXME khtml if (n->isLink())
+        return true;*/
+
+    RenderObject *renderer = n->renderer();
+    if (!renderer)
+        return false;
+        
+    if (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE)
+        return true;
+
+    if (renderer->style()->isFloating())
+        return true;
+
+    if (renderer->style()->position() != PSTATIC)
+        return true;
+        
+    return false;
+}
+
+// Checks if a string is a valid tag for the FormatBlockCommand function of execCommand. Expects lower case strings.
+bool validBlockTag(const DOMString& blockTag)
+{
+    if (blockTag == "address" ||
+        blockTag == "blockquote" ||
+        blockTag == "dd" ||
+        blockTag == "div" ||
+        blockTag == "dl" ||
+        blockTag == "dt" ||
+        blockTag == "h1" ||
+        blockTag == "h2" ||
+        blockTag == "h3" ||
+        blockTag == "h4" ||
+        blockTag == "h5" ||
+        blockTag == "h6" ||
+        blockTag == "p" ||
+        blockTag == "pre")
+        return true;
+    return false;
+}
+
+static NodeImpl* firstInSpecialElement(const Position& pos)
+{
+    NodeImpl* rootEditableElementImpl = pos.node()->rootEditableElement();
+    for (NodeImpl* n = pos.node(); n && n->rootEditableElement() == rootEditableElementImpl; n = n->parentNode())
+        if (isSpecialElement(n)) {
+            VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
+            VisiblePosition firstInElementImpl = VisiblePosition(n, 0, DOWNSTREAM);
+            if (isTableElement(n) && vPos == firstInElementImpl.next())
+                return n;
+            if (vPos == firstInElementImpl)
+                return n;
+        }
+    return 0;
+}
+
+static NodeImpl* lastInSpecialElement(const Position& pos)
+{
+    NodeImpl* rootEditableElementImpl = pos.node()->rootEditableElement();
+    for (NodeImpl* n = pos.node(); n && n->rootEditableElement() == rootEditableElementImpl; n = n->parentNode())
+        if (isSpecialElement(n)) {
+            VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
+            VisiblePosition lastInElementImpl = VisiblePosition(n, n->childNodeCount(), DOWNSTREAM);
+            if (isTableElement(n) && vPos == lastInElementImpl.previous())
+                return n;
+            if (vPos == lastInElementImpl)
+                return n;
+        }
+    return 0;
+}
+
+bool isFirstVisiblePositionInSpecialElement(const Position& pos)
+{
+    return firstInSpecialElement(pos);
+}
+
+Position positionBeforeContainingSpecialElement(const Position& pos, NodeImpl** containingSpecialElementImpl)
+{
+    NodeImpl* n = firstInSpecialElement(pos);
+    if (!n)
+        return pos;
+    Position result = positionBeforeNode(n);
+    if (result.isNull() || result.node()->rootEditableElement() != pos.node()->rootEditableElement())
+        return pos;
+    if (containingSpecialElementImpl)
+        *containingSpecialElementImpl = n;
+    return result;
+}
+
+bool isLastVisiblePositionInSpecialElement(const Position& pos)
+{
+    return lastInSpecialElement(pos);
+}
+
+Position positionAfterContainingSpecialElement(const Position& pos, NodeImpl **containingSpecialElementImpl)
+{
+    NodeImpl* n = lastInSpecialElement(pos);
+    if (!n)
+        return pos;
+    Position result = positionAfterNode(n);
+    if (result.isNull() || result.node()->rootEditableElement() != pos.node()->rootEditableElement())
+        return pos;
+    if (containingSpecialElementImpl)
+        *containingSpecialElementImpl = n;
+    return result;
+}
+
+Position positionOutsideContainingSpecialElement(const Position &pos, NodeImpl **containingSpecialElementImpl)
+{
+    if (isFirstVisiblePositionInSpecialElement(pos))
+        return positionBeforeContainingSpecialElement(pos, containingSpecialElementImpl);
+    if (isLastVisiblePositionInSpecialElement(pos))
+        return positionAfterContainingSpecialElement(pos, containingSpecialElementImpl);
+    return pos;
+}
+
+NodeImpl* isFirstPositionAfterTable(const VisiblePosition& visiblePosition)
+{
+    Position upstream(visiblePosition.deepEquivalent().upstream());
+    if (upstream.node() && upstream.node()->renderer() && upstream.node()->renderer()->isTable() && upstream.offset() == maxDeepOffset(upstream.node()))
+        return upstream.node();
+    
+    return 0;
+}
+
+NodeImpl* isLastPositionBeforeTable(const VisiblePosition& visiblePosition)
+{
+    Position downstream(visiblePosition.deepEquivalent().downstream());
+    if (downstream.node() && downstream.node()->renderer() && downstream.node()->renderer()->isTable() && downstream.offset() == 0)
+        return downstream.node();
+    
+    return 0;
+}
+
+Position positionBeforeNode(const NodeImpl *node)
+{
+    return Position(node->parentNode(), node->nodeIndex());
+}
+
+Position positionAfterNode(const NodeImpl *node)
+{
+    return Position(node->parentNode(), node->nodeIndex() + 1);
+}
+
+bool isListElement(NodeImpl *n)
+{
+    return (n && (n->hasTagName(/*ulTag*/ID_UL) || n->hasTagName(/*olTag*/ID_OL) || n->hasTagName(/*dlTag*/ID_DL)));
+}
+
+NodeImpl* enclosingNodeImplWithTag(const Position& p, const QualifiedName& tagName)
+{
+    if (p.isNull())
+        return 0;
+        
+    NodeImpl* root = highestEditableRoot(p);
+    for (NodeImpl* n = p.node(); n; n = n->parentNode()) {
+        if (root && !isContentEditable(n))
+            continue;
+        if (n->hasTagName(tagName))
+            return n;
+        if (n == root)
+            return 0;
+    }
+    
+    return 0;
+}
+
+NodeImpl* enclosingNodeImplOfType(const Position& p, bool (*nodeIsOfType)(const NodeImpl*), bool onlyReturnEditableNodes)
+{
+    if (p.isNull())
+        return 0;
+        
+    NodeImpl* root = highestEditableRoot(p);
+    for (NodeImpl* n = p.node(); n; n = n->parentNode()) {
+        // Don't return a non-editable node if the input position was editable, since
+        // the callers from editing will no doubt want to perform editing inside the returned node.
+        if (root && !isContentEditable(n) && onlyReturnEditableNodes)
+            continue;
+        if ((*nodeIsOfType)(n))
+            return n;
+        if (n == root)
+            return 0;
+    }
+    
+    return 0;
+}
+
+NodeImpl* highestEnclosingNodeImplOfType(const Position& p, bool (*nodeIsOfType)(const NodeImpl*))
+{
+    NodeImpl* highest = 0;
+    NodeImpl* root = highestEditableRoot(p);
+    for (NodeImpl* n = p.node(); n; n = n->parentNode()) {
+        if ((*nodeIsOfType)(n))
+            highest = n;
+        if (n == root)
+            break;
+    }
+    
+    return highest;
+}
+
+NodeImpl* enclosingTableCell(const Position& p)
+{
+    return enclosingNodeImplOfType(p, &isTableCell);
+}
+
+NodeImpl* enclosingAnchorElement(const Position& p)
+{
+    if (p.isNull())
+        return 0;
+    
+    NodeImpl* node = p.node();
+    while (node && !(node->isElementNode()/*FIXME khtml && node->isLink()*/))
+        node = node->parentNode();
+    return node;
+}
+
+NodeImpl* enclosingList(NodeImpl* node)
+{
+    if (!node)
+        return 0;
+        
+    NodeImpl* root = highestEditableRoot(Position(node, 0));
+    
+    for (NodeImpl* n = node->parentNode(); n; n = n->parentNode()) {
+        if (n->hasTagName(/*ulTag*/ID_UL) || n->hasTagName(/*olTag*/ID_OL))
+            return n;
+        if (n == root)
+            return 0;
+    }
+    
+    return 0;
+}
+
+NodeImpl* enclosingListChild(NodeImpl *node)
+{
+    if (!node)
+        return 0;
+    // Check for a list item element, or for a node whose parent is a list element.  Such a node
+    // will appear visually as a list item (but without a list marker)
+    NodeImpl* root = highestEditableRoot(Position(node, 0));
+    
+    // FIXME: This function is inappropriately named if it starts with node instead of node->parentNode()
+    for (NodeImpl* n = node; n && n->parentNode(); n = n->parentNode()) {
+        if (n->hasTagName(/*liTag*/ID_LI) || isListElement(n->parentNode()))
+            return n;
+        if (n == root || isTableCell(n))
+            return 0;
+    }
+    
+    return 0;
+}
+
+static NodeImpl* embeddedSublist(NodeImpl* listItem)
+{
+    // Check the DOM so that we'll find collapsed sublists without renderers.
+    for (NodeImpl* n = listItem->firstChild(); n; n = n->nextSibling()) {
+        if (isListElement(n))
+            return n;
+    }
+    
+    return 0;
+}
+
+static NodeImpl* appendedSublist(NodeImpl* listItem)
+{
+    // Check the DOM so that we'll find collapsed sublists without renderers.
+    for (NodeImpl* n = listItem->nextSibling(); n; n = n->nextSibling()) {
+        if (isListElement(n))
+            return n;
+        if (n->renderer() && n->renderer()->isListItem())
+            return 0;
+    }
+    
+    return 0;
+}
+
+NodeImpl* enclosingEmptyListItem(const VisiblePosition& visiblePos)
+{
+    // Check that position is on a line by itself inside a list item
+    NodeImpl* listChildNodeImpl = enclosingListChild(visiblePos.deepEquivalent().node());
+    if (!listChildNodeImpl || !isStartOfParagraph(visiblePos) || !isEndOfParagraph(visiblePos))
+        return 0;
+        
+    VisiblePosition firstInListChild(Position(listChildNodeImpl, 0));
+    VisiblePosition lastInListChild(Position(listChildNodeImpl, maxDeepOffset(listChildNodeImpl)));
+    
+    if (firstInListChild != visiblePos || lastInListChild != visiblePos)
+        return 0;
+    
+    if (embeddedSublist(listChildNodeImpl) || appendedSublist(listChildNodeImpl))
+        return 0;
+        
+    return listChildNodeImpl;
+}
+
+NodeImpl* outermostEnclosingListChild(NodeImpl* node)
+{
+    NodeImpl* listNodeImpl = 0;
+    NodeImpl* nextNodeImpl = node;
+    while ((nextNodeImpl = enclosingListChild(nextNodeImpl)))
+        listNodeImpl = nextNodeImpl;
+    return listNodeImpl;
+}
+
+NodeImpl* outermostEnclosingList(NodeImpl* node)
+{
+    NodeImpl* listNodeImpl = 0;
+    NodeImpl* nextNodeImpl = node;
+    while ((nextNodeImpl = enclosingList(nextNodeImpl)))
+        listNodeImpl = nextNodeImpl;
+    return listNodeImpl;
+}
+
+NodeImpl* highestAncestor(NodeImpl* node)
+{
+    assert(node);
+    NodeImpl* parent = node;
+    while ((node = node->parentNode()))
+        parent = node;
+    return parent;
+}
+
+// FIXME: do not require renderer, so that this can be used within fragments, or rename to isRenderedTable()
+bool isTableElement(NodeImpl* n)
+{
+    if (!n || !n->isElementNode())
+        return false;
+
+    RenderObject* renderer = n->renderer();
+    return (renderer && (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE));
+}
+
+bool isTableCell(const NodeImpl* node)
+{
+    RenderObject* r = node->renderer();
+    if (!r)
+        return node->hasTagName(/*tdTag*/ID_TD) || node->hasTagName(/*thTag*/ID_TH);
+    
+    return r->isTableCell();
+}
+
+PassRefPtr<ElementImpl> createDefaultParagraphElement(DocumentImpl *document)
+{
+    /*ExceptionCode*/int ec = 0;
+    RefPtr<ElementImpl> element = document->createElementNS(XHTML_NAMESPACE, "div", &ec);
+    assert(ec == 0);
+    return element.release();
+}
+
+PassRefPtr<ElementImpl> createBreakElement(DocumentImpl *document)
+{
+    /*ExceptionCode*/int ec = 0;
+    RefPtr<ElementImpl> breakNodeImpl = document->createElementNS(XHTML_NAMESPACE, "br", &ec);
+    assert(ec == 0);
+    return breakNodeImpl.release();
+}
+
+PassRefPtr<ElementImpl> createOrderedListElement(DocumentImpl *document)
+{
+    /*ExceptionCode*/int ec = 0;
+    RefPtr<ElementImpl> element = document->createElementNS(XHTML_NAMESPACE, "ol", &ec);
+    assert(ec == 0);
+    return element.release();
+}
+
+PassRefPtr<ElementImpl> createUnorderedListElement(DocumentImpl *document)
+{
+    /*ExceptionCode*/int ec = 0;
+    RefPtr<ElementImpl> element = document->createElementNS(XHTML_NAMESPACE, "ul", &ec);
+    assert(ec == 0);
+    return element.release();
+}
+
+PassRefPtr<ElementImpl> createListItemElement(DocumentImpl *document)
+{
+    /*ExceptionCode*/int ec = 0;
+    RefPtr<ElementImpl> breakNodeImpl = document->createElementNS(XHTML_NAMESPACE, "li", &ec);
+    assert(ec == 0);
+    return breakNodeImpl.release();
+}
+
+PassRefPtr<ElementImpl> createElement(DocumentImpl* document, const DOMString& tagName)
+{
+    /*ExceptionCode*/int ec = 0;
+    RefPtr<ElementImpl> breakNodeImpl = document->createElementNS(XHTML_NAMESPACE, tagName, &ec);
+    assert(ec == 0);
+    return breakNodeImpl.release();
+}
+
+bool isTabSpanNode(const NodeImpl *node)
+{
+    return node && node->hasTagName(/*spanTag*/ID_SPAN) && node->isElementNode();// && static_cast<const ElementImpl *>(node)->getAttribute(/*classAttr*/ATTR_CLASS) == AppleTabSpanClass;
+}
+
+bool isTabSpanTextNode(const NodeImpl *node)
+{
+    return node && node->isTextNode() && node->parentNode() && isTabSpanNode(node->parentNode());
+}
+
+NodeImpl *tabSpanNode(const NodeImpl *node)
+{
+    return isTabSpanTextNode(node) ? node->parentNode() : 0;
+}
+
+Position positionBeforeTabSpan(const Position& pos)
+{
+    NodeImpl *node = pos.node();
+    if (isTabSpanTextNode(node))
+        node = tabSpanNode(node);
+    else if (!isTabSpanNode(node))
+        return pos;
+    
+    return positionBeforeNode(node);
+}
+
+PassRefPtr<ElementImpl> createTabSpanElement(DocumentImpl* document, PassRefPtr<NodeImpl> tabTextNodeImpl)
+{
+    // make the span to hold the tab
+    /*ExceptionCode*/int ec = 0;
+    RefPtr<ElementImpl> spanElementImpl = document->createElementNS(XHTML_NAMESPACE, "span", &ec);
+    assert(ec == 0);
+    //FIXME khtml spanElementImpl->setAttribute(classAttr, AppleTabSpanClass);
+    //FIXME khtml spanElementImpl->setAttribute(styleAttr, "white-space:pre");
+
+    // add tab text to that span
+    if (!tabTextNodeImpl)
+        tabTextNodeImpl = document->createEditingTextNode("\t");
+    spanElementImpl->appendChild(tabTextNodeImpl.get(), ec);
+    assert(ec == 0);
+
+    return spanElementImpl.release();
+}
+
+PassRefPtr<ElementImpl> createTabSpanElement(DocumentImpl* document, const DOMString& tabText)
+{
+    return createTabSpanElement(document, document->createTextNode(tabText));
+}
+
+PassRefPtr<ElementImpl> createTabSpanElement(DocumentImpl* document)
+{
+    return createTabSpanElement(document, PassRefPtr<NodeImpl>());
+}
+
+bool isNodeImplRendered(const NodeImpl *node)
+{
+    if (!node)
+        return false;
+
+    RenderObject *renderer = node->renderer();
+    if (!renderer)
+        return false;
+
+    return renderer->style()->visibility() == VISIBLE;
+}
+
+NodeImpl *nearestMailBlockquote(const NodeImpl *node)
+{
+    for (NodeImpl *n = const_cast<NodeImpl *>(node); n; n = n->parentNode()) {
+        if (isMailBlockquote(n))
+            return n;
+    }
+    return 0;
+}
+
+unsigned numEnclosingMailBlockquotes(const Position& p)
+{
+    unsigned num = 0;
+    for (NodeImpl* n = p.node(); n; n = n->parentNode())
+        if (isMailBlockquote(n))
+            num++;
+    
+    return num;
+}
+
+bool isMailBlockquote(const NodeImpl *node)
+{
+    if (!node || !node->isElementNode()/*FIXME khtml && !node->hasTagName(blockquoteTag)*/)
+        return false;
+        
+    //return static_cast<const ElementImpl *>(node)->getAttribute("type") == "cite";
+    return false;
+}
+
+int caretMinOffset(const NodeImpl* n)
+{
+    RenderObject* r = n->renderer();
+    assert(!n->isCharacterDataNode() || !r || r->isText()); // FIXME: This was a runtime check that seemingly couldn't fail; changed it to an assertion for now.
+    return r ? r->caretMinOffset() : 0;
+}
+
+int caretMaxOffset(const NodeImpl* n)
+{
+    RenderObject* r = n->renderer();
+    assert(!n->isCharacterDataNode() || !r || r->isText()); // FIXME: This was a runtime check that seemingly couldn't fail; changed it to an assertion for now.
+    if (r)
+        return r->caretMaxOffset();
+
+    if (n->isCharacterDataNode()) {
+        const CharacterDataImpl* c = static_cast<const CharacterDataImpl*>(n);
+        return static_cast<int>(c->length());
+    }
+    return 1;
+}
+
+bool lineBreakExistsAtPosition(const VisiblePosition& visiblePosition)
+{
+    if (visiblePosition.isNull())
+        return false;
+        
+    Position downstream(visiblePosition.deepEquivalent().downstream());
+    return downstream.node()->hasTagName(/*brTag*/ID_BR) ||
+           downstream.node()->isTextNode() && downstream.node()->renderer()->style()->preserveNewline() && visiblePosition.characterAfter() == '\n';
+}
+
+// Modifies selections that have an end point at the edge of a table
+// that contains the other endpoint so that they don't confuse
+// code that iterates over selected paragraphs.
+Selection selectionForParagraphIteration(const Selection& original)
+{
+    Selection newSelection(original);
+    VisiblePosition startOfSelection(newSelection.visibleStart());
+    VisiblePosition endOfSelection(newSelection.visibleEnd());
+    
+    // If the end of the selection to modify is just after a table, and
+    // if the start of the selection is inside that table, then the last paragraph
+    // that we'll want modify is the last one inside the table, not the table itself
+    // (a table is itself a paragraph).
+    if (NodeImpl* table = isFirstPositionAfterTable(endOfSelection))
+        if (startOfSelection.deepEquivalent().node()->isAncestor(table))
+            newSelection = Selection(startOfSelection, endOfSelection.previous(true));
+    
+    // If the start of the selection to modify is just before a table,
+    // and if the end of the selection is inside that table, then the first paragraph
+    // we'll want to modify is the first one inside the table, not the paragraph
+    // containing the table itself.
+    if (NodeImpl* table = isLastPositionBeforeTable(startOfSelection))
+        if (endOfSelection.deepEquivalent().node()->isAncestor(table))
+            newSelection = Selection(startOfSelection.next(true), endOfSelection);
+    
+    return newSelection;
+}
+
+
+int indexForVisiblePosition(VisiblePosition& visiblePosition)
+{
+    kDebug() << "NOT IMPLEMENTED" << endl;
+    return 0;
+    /*if (visiblePosition.isNull())
+        return 0;
+    Position p(visiblePosition.deepEquivalent());
+    RefPtr<RangeImpl> range = RangeImpl::create(p.node()->document(), Position(p.node()->document(), 0), rangeCompliantEquivalent(p));
+    return TextIterator::rangeLength(range.get(), true);*/
+}
+
+PassRefPtr<RangeImpl> avoidIntersectionWithNode(const RangeImpl* range, NodeImpl* node)
+{
+    if (!range)
+        return 0;
+
+    DocumentImpl* document = range->ownerDocument();
+
+    NodeImpl* startContainer = range->startContainer();
+    int startOffset = range->startOffset();
+    NodeImpl* endContainer = range->endContainer();
+    int endOffset = range->endOffset();
+
+    if (!startContainer)
+        return 0;
+
+    assert(endContainer);
+
+    if (startContainer == node || startContainer->isAncestor(node)) {
+        assert(node->parentNode());
+        startContainer = node->parentNode();
+        startOffset = node->nodeIndex();
+    }
+    if (endContainer == node || endContainer->isAncestor(node)) {
+        assert(node->parentNode());
+        endContainer = node->parentNode();
+        endOffset = node->nodeIndex();
+    }
+
+    return RangeImpl::create(document, startContainer, startOffset, endContainer, endOffset);
+}
+
+Selection avoidIntersectionWithNode(const Selection& selection, NodeImpl* node)
+{
+    if (selection.isNone())
+        return Selection(selection);
+        
+    Selection updatedSelection(selection);
+    NodeImpl* base = selection.base().node();
+    NodeImpl* extent = selection.extent().node();
+    assert(base);
+    assert(extent);
+    
+    if (base == node || base->isAncestor(node)) {
+        assert(node->parentNode());
+        updatedSelection.setBase(Position(node->parentNode(), node->nodeIndex()));
+    }
+    
+    if (extent == node || extent->isAncestor(node)) {
+        assert(node->parentNode());
+        updatedSelection.setExtent(Position(node->parentNode(), node->nodeIndex()));
+    }
+        
+    return updatedSelection;
+}
+
+} // namespace WebCore
diff --git a/khtml/xml/editing_helper.h b/khtml/xml/editing_helper.h
new file mode 100644
index 0000000..32e01f6
--- /dev/null
+++ b/khtml/xml/editing_helper.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2004, 2006 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef htmlediting_h
+#define htmlediting_h
+
+#include <wtf/Forward.h>
+#include "xml/visible_units.h"
+
+namespace DOM
+{
+    class DocumentImpl;
+    class ElementImpl;
+    class NodeImpl;
+    class RangeImpl;
+    class Selection;
+    class DOMString;
+    class Position;
+    class VisiblePosition;
+}
+
+using namespace DOM;
+
+namespace khtml
+{
+
+Position rangeCompliantEquivalent(const Position&);
+Position rangeCompliantEquivalent(const VisiblePosition&);
+int maxDeepOffset(const NodeImpl*);
+bool isAtomicNode(const NodeImpl*);
+bool editingIgnoresContent(const NodeImpl*);
+bool canHaveChildrenForEditing(const NodeImpl*);
+NodeImpl* highestEditableRoot(const Position&);
+VisiblePosition firstEditablePositionAfterPositionInRoot(const Position&, NodeImpl*);
+VisiblePosition lastEditablePositionBeforePositionInRoot(const Position&, NodeImpl*);
+int comparePositions(const Position&, const Position&);
+NodeImpl* lowestEditableAncestor(NodeImpl*);
+bool isContentEditable(const NodeImpl*);
+Position nextCandidate(const Position&);
+Position nextVisuallyDistinctCandidate(const Position&);
+Position previousCandidate(const Position&);
+Position previousVisuallyDistinctCandidate(const Position&);
+bool isEditablePosition(const Position&);
+bool isRichlyEditablePosition(const Position&);
+ElementImpl* editableRootForPosition(const Position&);
+bool isBlock(const NodeImpl*);
+NodeImpl* enclosingBlock(NodeImpl*);
+
+// FIXME khtml DOMString stringWithRebalancedWhitespace(const DOMString&, bool, bool);
+// FIXME khtml const DOMString& nonBreakingSpaceString();
+
+//------------------------------------------------------------------------------------------
+
+Position positionBeforeNode(const NodeImpl*);
+Position positionAfterNode(const NodeImpl*);
+
+PassRefPtr<RangeImpl> avoidIntersectionWithNode(const RangeImpl*, NodeImpl*);
+Selection avoidIntersectionWithNode(const Selection&, NodeImpl*);
+
+bool isSpecialElement(const NodeImpl*);
+bool validBlockTag(const DOMString&);
+
+PassRefPtr<ElementImpl> createDefaultParagraphElement(DocumentImpl*);
+PassRefPtr<ElementImpl> createBreakElement(DocumentImpl*);
+PassRefPtr<ElementImpl> createOrderedListElement(DocumentImpl*);
+PassRefPtr<ElementImpl> createUnorderedListElement(DocumentImpl*);
+PassRefPtr<ElementImpl> createListItemElement(DocumentImpl*);
+PassRefPtr<ElementImpl> createElement(DocumentImpl*, const DOMString&);
+
+bool isTabSpanNode(const NodeImpl*);
+bool isTabSpanTextNode(const NodeImpl*);
+NodeImpl* tabSpanNode(const NodeImpl*);
+Position positionBeforeTabSpan(const Position&);
+PassRefPtr<ElementImpl> createTabSpanElement(DocumentImpl*);
+PassRefPtr<ElementImpl> createTabSpanElement(DocumentImpl*, PassRefPtr<NodeImpl> tabTextNodeImpl);
+PassRefPtr<ElementImpl> createTabSpanElement(DocumentImpl*, const DOMString& tabText);
+
+bool isNodeImplRendered(const NodeImpl*);
+bool isMailBlockquote(const NodeImpl*);
+NodeImpl* nearestMailBlockquote(const NodeImpl*);
+unsigned numEnclosingMailBlockquotes(const Position&);
+int caretMinOffset(const NodeImpl*);
+int caretMaxOffset(const NodeImpl*);
+
+//------------------------------------------------------------------------------------------
+
+bool isTableStructureNode(const NodeImpl*);
+PassRefPtr<ElementImpl> createBlockPlaceholderElement(DocumentImpl*);
+
+bool isFirstVisiblePositionInSpecialElement(const Position&);
+Position positionBeforeContainingSpecialElement(const Position&, NodeImpl** containingSpecialElementImpl=0);
+bool isLastVisiblePositionInSpecialElement(const Position&);
+Position positionAfterContainingSpecialElement(const Position&, NodeImpl** containingSpecialElementImpl=0);
+Position positionOutsideContainingSpecialElement(const Position&, NodeImpl** containingSpecialElementImpl=0);
+NodeImpl* isLastPositionBeforeTable(const VisiblePosition&);
+NodeImpl* isFirstPositionAfterTable(const VisiblePosition&);
+
+// FIXME khtml port to ID NodeImpl* enclosingNodeImplWithTag(const Position&, const QualifiedName&);
+NodeImpl* enclosingNodeImplOfType(const Position&, bool (*nodeIsOfType)(const NodeImpl*), bool onlyReturnEditableNodeImpls = true);
+NodeImpl* highestEnclosingNodeImplOfType(const Position&, bool (*nodeIsOfType)(const NodeImpl*));
+NodeImpl* enclosingTableCell(const Position&);
+NodeImpl* enclosingEmptyListItem(const VisiblePosition&);
+NodeImpl* enclosingAnchorElement(const Position&);
+bool isListElement(NodeImpl*);
+NodeImpl* enclosingList(NodeImpl*);
+NodeImpl* outermostEnclosingList(NodeImpl*);
+NodeImpl* enclosingListChild(NodeImpl*);
+NodeImpl* highestAncestor(NodeImpl*);
+bool isTableElement(NodeImpl*);
+bool isTableCell(const NodeImpl*);
+
+bool lineBreakExistsAtPosition(const VisiblePosition&);
+
+Selection selectionForParagraphIteration(const Selection&);
+
+int indexForVisiblePosition(VisiblePosition&);
+
+}
+
+#endif
diff --git a/khtml/xml/visible_units.cpp b/khtml/xml/visible_units.cpp
new file mode 100644
index 0000000..3986826
--- /dev/null
+++ b/khtml/xml/visible_units.cpp
@@ -0,0 +1,1003 @@
+/*
+ * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*#include "config.h"
+#include "visible_units.h"
+
+#include "Document.h"
+#include "Element.h"
+#include "HTMLNames.h"
+#include "RenderBlock.h"
+#include "RenderLayer.h"
+#include "TextBoundaries.h"
+#include "TextBreakIterator.h"
+#include "TextIterator.h"
+#include "htmlediting.h"*/
+
+#include "xml/visible_units.h"
+#include "xml/VisiblePosition.h"
+#include "xml/dom_nodeimpl.h"
+#include "xml/dom_elementimpl.h"
+#include "xml/editing_helper.h"
+#include "xml/dom2_rangeimpl.h"
+#include "rendering/render_object.h"
+#include "rendering/render_text.h"
+#include "rendering/render_block.h"
+#include "editing/TextIterator.h"
+#include "rendering/render_layer.h"
+
+namespace DOM {
+
+//using namespace HTMLNames;
+using namespace khtml;
+
+static VisiblePosition previousBoundary(const VisiblePosition &c, unsigned (*searchFunction)(const QChar *, unsigned))
+{
+    Position pos = c.deepEquivalent();
+    NodeImpl *n = pos.node();
+    if (!n)
+        return VisiblePosition();
+    DocumentImpl *d = n->document();
+    NodeImpl *de = d->documentElement();
+    if (!de)
+        return VisiblePosition();
+    NodeImpl *boundary = n->enclosingBlockFlowElement();
+    if (!boundary)
+        return VisiblePosition();
+    bool isContentEditable = boundary->isContentEditable();
+    while (boundary && boundary != de && boundary->parentNode() && isContentEditable == boundary->parentNode()->isContentEditable())
+        boundary = boundary->parentNode();
+
+    Position start = rangeCompliantEquivalent(Position(boundary, 0));
+    Position end = rangeCompliantEquivalent(pos);
+    RefPtr<RangeImpl> searchRange = RangeImpl::create(d);
+    
+    int exception = 0;
+    searchRange->setStart(start.node(), start.offset(), exception);
+    searchRange->setEnd(end.node(), end.offset(), exception);
+    
+    ASSERT(!exception);
+    if (exception)
+        return VisiblePosition();
+        
+    SimplifiedBackwardsTextIterator it(searchRange.get());
+    Vector<QChar, 1024> string;
+    unsigned next = 0;
+    bool inTextSecurityMode = start.node() && start.node()->renderer()/*KHTML && start.node()->renderer()->style()->textSecurity() != TSNONE*/;
+    while (!it.atEnd()) {
+        // iterate to get chunks until the searchFunction returns a non-zero value.
+        if (!inTextSecurityMode)
+            string.prepend(it.characters(), it.length());
+        else {
+            // Treat bullets used in the text security mode as regular characters when looking for boundaries
+            /*FIXME khtml port DOMString iteratorString(it.characters(), it.length());
+            iteratorString = iteratorString.implementation()->secure('x');
+            string.prepend(iteratorString.characters(), iteratorString.length());*/
+        }
+        
+        next = searchFunction(string.data(), string.size());
+        if (next != 0)
+            break;
+        it.advance();
+    }
+    
+    if (it.atEnd() && next == 0) {
+        pos = it.range()->startPosition();
+    } else if (next != 0) {
+        NodeImpl *node = it.range()->startContainer(exception);
+        if (node->isTextNode() || (node->renderer() && node->renderer()->isBR()))
+            // The next variable contains a usable index into a text node
+            pos = Position(node, next);
+        else {
+            // Use the end of the found range, the start is not guaranteed to
+            // be correct.
+            Position end = it.range()->endPosition();
+            VisiblePosition boundary(end);
+            unsigned i = it.length() - next;
+            while (i--)
+                boundary = boundary.previous();
+            return boundary;
+        }
+    }
+
+    return VisiblePosition(pos, DOWNSTREAM);
+}
+
+static VisiblePosition nextBoundary(const VisiblePosition &c, unsigned (*searchFunction)(const QChar *, unsigned))
+{
+    Position pos = c.deepEquivalent();
+    NodeImpl *n = pos.node();
+    if (!n)
+        return VisiblePosition();
+    DocumentImpl *d = n->document();
+    NodeImpl *de = d->documentElement();
+    if (!de)
+        return VisiblePosition();
+    NodeImpl *boundary = n->enclosingBlockFlowElement();
+    if (!boundary)
+        return VisiblePosition();
+    bool isContentEditable = boundary->isContentEditable();
+    while (boundary && boundary != de && boundary->parentNode() && isContentEditable == boundary->parentNode()->isContentEditable())
+        boundary = boundary->parentNode();
+
+    RefPtr<RangeImpl> searchRange(d->createRange());
+    Position start(rangeCompliantEquivalent(pos));
+    /*ExceptionCode*/int ec = 0;
+    searchRange->selectNodeContents(boundary, ec);
+    searchRange->setStart(start.node(), start.offset(), ec);
+    TextIterator it(searchRange.get(), true);
+    Vector<QChar, 1024> string;
+    unsigned next = 0;
+    bool inTextSecurityMode = false; // FIXME khtml port start.node() && start.node()->renderer() && start.node()->renderer()->style()->textSecurity() != TSNONE;
+    while (!it.atEnd()) {
+        // Keep asking the iterator for chunks until the search function
+        // returns an end value not equal to the length of the string passed to it.
+        if (!inTextSecurityMode)
+            string.append(it.characters(), it.length());
+        else {
+            // Treat bullets used in the text security mode as regular characters when looking for boundaries
+            /*FIXME khtml port DOMString iteratorString(it.characters(), it.length());
+            iteratorString = iteratorString.impl()->secure('x');
+            string.append(iteratorString.characters(), iteratorString.length());*/
+        }
+
+        next = searchFunction(string.data(), string.size());
+        if (next != string.size())
+            break;
+        it.advance();
+    }
+    
+    if (it.atEnd() && next == string.size()) {
+        pos = it.range()->startPosition();
+    } else if (next != 0) {
+        // Use the character iterator to translate the next value into a DOM position.
+        CharacterIterator charIt(searchRange.get(), true);
+        charIt.advance(next - 1);
+        pos = charIt.range()->endPosition();
+        
+        // FIXME: workaround for collapsed range (where only start position is correct) emitted for some emitted newlines (see rdar://5192593)
+        VisiblePosition visPos = VisiblePosition(pos);
+        if (visPos == VisiblePosition(charIt.range()->startPosition()))
+            pos = visPos.next(true).deepEquivalent();
+    }
+
+    // generate VisiblePosition, use UPSTREAM affinity if possible
+    return VisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE);
+}
+
+// ---------
+
+static unsigned startWordBoundary(const QChar* characters, unsigned length)
+{
+    int start, end;
+    findWordBoundary(characters, length, length, &start, &end);
+    return start;
+}
+
+VisiblePosition startOfWord(const VisiblePosition &c, EWordSide side)
+{
+    // FIXME: This returns a null VP for c at the start of the document
+    // and side == LeftWordIfOnBoundary
+    VisiblePosition p = c;
+    if (side == RightWordIfOnBoundary) {
+        // at paragraph end, the startofWord is the current position
+        if (isEndOfParagraph(c))
+            return c;
+        
+        p = c.next();
+        if (p.isNull())
+            return c;
+    }
+    return previousBoundary(p, startWordBoundary);
+}
+
+static unsigned endWordBoundary(const QChar* characters, unsigned length)
+{
+    int start, end;
+    findWordBoundary(characters, length, 0, &start, &end);
+    return end;
+}
+
+VisiblePosition endOfWord(const VisiblePosition &c, EWordSide side)
+{
+    VisiblePosition p = c;
+    if (side == LeftWordIfOnBoundary) {
+        if (isStartOfParagraph(c))
+            return c;
+            
+        p = c.previous();
+        if (p.isNull())
+            return c;
+    } else if (isEndOfParagraph(c))
+        return c;
+    
+    return nextBoundary(p, endWordBoundary);
+}
+
+static unsigned previousWordPositionBoundary(const QChar* characters, unsigned length)
+{
+    return findNextWordFromIndex(characters, length, length, false);
+}
+
+VisiblePosition previousWordPosition(const VisiblePosition &c)
+{
+    VisiblePosition prev = previousBoundary(c, previousWordPositionBoundary);
+    return c.honorEditableBoundaryAtOrAfter(prev);
+}
+
+static unsigned nextWordPositionBoundary(const QChar* characters, unsigned length)
+{
+    return findNextWordFromIndex(characters, length, 0, true);
+}
+
+VisiblePosition nextWordPosition(const VisiblePosition &c)
+{
+    VisiblePosition next = nextBoundary(c, nextWordPositionBoundary);    
+    return c.honorEditableBoundaryAtOrBefore(next);
+}
+
+// ---------
+
+static RootInlineBox *rootBoxForLine(const VisiblePosition &c)
+{
+    Position p = c.deepEquivalent();
+    NodeImpl *node = p.node();
+    if (!node)
+        return 0;
+
+    RenderObject *renderer = node->renderer();
+    if (!renderer)
+        return 0;
+
+    InlineBox* box;
+    int offset;
+    c.getInlineBoxAndOffset(box, offset);
+    
+    return box ? box->root() : 0;
+}
+
+static VisiblePosition positionAvoidingFirstPositionInTable(const VisiblePosition& c)
+{
+    // return table offset 0 instead of the first VisiblePosition inside the table
+    VisiblePosition previous = c.previous();
+    if (isLastPositionBeforeTable(previous))
+        return previous;
+    
+    return c;
+}
+
+static VisiblePosition startPositionForLine(const VisiblePosition& c)
+{
+    if (c.isNull())
+        return VisiblePosition();
+
+    RootInlineBox *rootBox = rootBoxForLine(c);
+    if (!rootBox) {
+        // There are VisiblePositions at offset 0 in blocks without
+        // RootInlineBoxes, like empty editable blocks and bordered blocks.
+        Position p = c.deepEquivalent();
+        if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && p.offset() == 0)
+            return positionAvoidingFirstPositionInTable(c);
+        
+        return VisiblePosition();
+    }
+    
+    // Generated content (e.g. list markers and CSS :before and :after
+    // pseudoelements) have no corresponding DOM element, and so cannot be
+    // represented by a VisiblePosition.  Use whatever follows instead.
+    InlineBox *startBox = rootBox->firstLeafChild();
+    NodeImpl *startNode;
+    while (1) {
+        if (!startBox)
+            return VisiblePosition();
+
+        RenderObject *startRenderer = startBox->object();
+        if (!startRenderer)
+            return VisiblePosition();
+
+        startNode = startRenderer->element();
+        if (startNode)
+            break;
+        
+        startBox = startBox->nextLeafChild();
+    }
+    
+    int startOffset = 0;
+    if (startBox->isInlineTextBox()) {
+        InlineTextBox *startTextBox = static_cast<InlineTextBox *>(startBox);
+        startOffset = startTextBox->m_start;
+    }
+  
+    VisiblePosition visPos = VisiblePosition(startNode, startOffset, DOWNSTREAM);
+    return positionAvoidingFirstPositionInTable(visPos);
+}
+
+VisiblePosition startOfLine(const VisiblePosition& c)
+{
+    VisiblePosition visPos = startPositionForLine(c);
+    
+    if (visPos.isNotNull()) {
+        // Make sure the start of line is not greater than the given input position.  Else use the previous position to
+        // obtain start of line.  This condition happens when the input position is before the space character at the end
+        // of a soft-wrapped non-editable line. In this scenario, startPositionForLine would incorrectly hand back a position
+        // greater than the input position.  This fix is to account for the discrepancy between lines with webkit-line-break:after-white-space
+        // style versus lines without that style, which would break before a space by default.
+        Position p = visPos.deepEquivalent();
+        if (p.offset() > c.deepEquivalent().offset() && p.node()->isSameNode(c.deepEquivalent().node())) {
+            visPos = c.previous();
+            if (visPos.isNull())
+                return VisiblePosition();
+            visPos = startPositionForLine(visPos);
+        }
+    }
+
+    return c.honorEditableBoundaryAtOrAfter(visPos);
+}
+
+static VisiblePosition endPositionForLine(const VisiblePosition& c)
+{
+    if (c.isNull())
+        return VisiblePosition();
+
+    RootInlineBox *rootBox = rootBoxForLine(c);
+    if (!rootBox) {
+        // There are VisiblePositions at offset 0 in blocks without
+        // RootInlineBoxes, like empty editable blocks and bordered blocks.
+        Position p = c.deepEquivalent();
+        if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && p.offset() == 0)
+            return c;
+        return VisiblePosition();
+    }
+    
+    // Generated content (e.g. list markers and CSS :before and :after
+    // pseudoelements) have no corresponding DOM element, and so cannot be
+    // represented by a VisiblePosition.  Use whatever precedes instead.
+    NodeImpl *endNode;
+    InlineBox *endBox = rootBox->lastLeafChild();
+    while (1) {
+        if (!endBox)
+            return VisiblePosition();
+
+        RenderObject *endRenderer = endBox->object();
+        if (!endRenderer)
+            return VisiblePosition();
+
+        endNode = endRenderer->element();
+        if (endNode)
+            break;
+        
+        endBox = endBox->prevLeafChild();
+    }
+    
+    int endOffset = 1;
+    if (/*endNode->hasTagName(brTag)*/endNode->id() == ID_BR) {
+        endOffset = 0;
+    } else if (endBox->isInlineTextBox()) {
+        InlineTextBox *endTextBox = static_cast<InlineTextBox *>(endBox);
+        endOffset = endTextBox->m_start;
+        /*FIXME khtml port if (!endTextBox->isLineBreak())*/
+            endOffset += endTextBox->m_len;
+    }
+    
+    return VisiblePosition(endNode, endOffset, VP_UPSTREAM_IF_POSSIBLE);
+}
+
+VisiblePosition endOfLine(const VisiblePosition& c)
+{
+    VisiblePosition visPos = endPositionForLine(c);
+    
+    // Make sure the end of line is at the same line as the given input position.  Else use the previous position to
+    // obtain end of line.  This condition happens when the input position is before the space character at the end
+    // of a soft-wrapped non-editable line. In this scenario, endPositionForLine would incorrectly hand back a position
+    // in the next line instead. This fix is to account for the discrepancy between lines with webkit-line-break:after-white-space style
+    // versus lines without that style, which would break before a space by default.
+    if (!inSameLine(c, visPos)) {
+        visPos = c.previous();
+        if (visPos.isNull())
+            return VisiblePosition();
+        visPos = endPositionForLine(visPos);
+    }
+    
+    return c.honorEditableBoundaryAtOrBefore(visPos);
+}
+
+bool inSameLine(const VisiblePosition &a, const VisiblePosition &b)
+{
+    return a.isNotNull() && startOfLine(a) == startOfLine(b);
+}
+
+bool isStartOfLine(const VisiblePosition &p)
+{
+    return p.isNotNull() && p == startOfLine(p);
+}
+
+bool isEndOfLine(const VisiblePosition &p)
+{
+    return p.isNotNull() && p == endOfLine(p);
+}
+
+// The first leaf before node that has the same editability as node.
+static NodeImpl* previousLeafWithSameEditability(NodeImpl* node)
+{
+    bool editable = node->isContentEditable();
+    NodeImpl* n = node->previousLeafNode();
+    while (n) {
+        if (editable == n->isContentEditable())
+            return n;
+        n = n->previousLeafNode();
+    }
+    return 0;
+}
+
+VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int x)
+{
+    Position p = visiblePosition.deepEquivalent();
+    NodeImpl *node = p.node();
+    NodeImpl* highestRoot = highestEditableRoot(p);
+    if (!node)
+        return VisiblePosition();
+    //kDebug() << node->nodeName() << node << endl;
+    //kDebug() << x << endl;
+    //if (highestRoot)
+    //    kDebug() << "highest root" << highestRoot->nodeName() << endl;
+  
+    node->document()->updateLayout/*IgnorePendingStylesheets*/();
+    
+    RenderObject *renderer = node->renderer();
+    if (!renderer)
+        return VisiblePosition();
+
+    RenderBlock *containingBlock = 0;
+    RootInlineBox *root = 0;
+    InlineBox* box;
+    int ignoredCaretOffset;
+    visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
+    if (box) {
+        //kDebug() << "have box" << endl;
+        root = box->root()->prevRootBox();
+        if (root)
+            containingBlock = renderer->containingBlock();
+    }
+
+    if (!root) {
+        //kDebug() << "NO ROOT" << endl;
+        // This containing editable block does not have a previous line.
+        // Need to move back to previous containing editable block in this root editable
+        // block and find the last root line box in that block.
+        NodeImpl* startBlock = enclosingBlock(node);
+        //if (startBlock) kDebug() << "start block" << startBlock << startBlock->nodeName() << endl;
+        NodeImpl* n = previousLeafWithSameEditability(node);
+        //if (n) kDebug() << "previous leaf" << n <<  n->nodeName() << endl;
+        while (n && startBlock == enclosingBlock(n))
+            n = previousLeafWithSameEditability(n);
+        while (n) {
+            if (highestEditableRoot(Position(n, 0)) != highestRoot)
+                break;
+            Position pos(n, caretMinOffset(n));
+            //kDebug() << "position" << pos << endl;
+            if (pos.isCandidate()) {
+                ASSERT(n->renderer());
+                Position maxPos(n, caretMaxOffset(n));
+                //kDebug() << "isCandidate" << maxPos << endl;
+                maxPos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset);
+                if (box) {
+                    // previous root line box found
+                    root = box->root();
+                    containingBlock = n->renderer()->containingBlock();
+                    break;
+                }
+
+                return VisiblePosition(pos, DOWNSTREAM);
+            }
+            n = previousLeafWithSameEditability(n);
+        }
+    }
+    
+    if (root) {
+        //kDebug() << "Have Root" << endl;
+        // FIXME: Can be wrong for multi-column layout and with transforms.
+        QPointF absPos = containingBlock->localToAbsoluteForContent(QPointF());
+        if (containingBlock->hasOverflowClip()) {
+            QSize offset = containingBlock->layer()->scrolledContentOffset();
+            absPos.rx() -= offset.width();
+            absPos.ry() -= offset.height();
+        }
+        RenderObject *renderer = root->closestLeafChildForXPos(x - absPos.x(), isEditablePosition(p))->object();
+        NodeImpl* node = renderer->node();
+        if (editingIgnoresContent(node))
+            return Position(node->parent(), node->nodeIndex());
+        return renderer->positionForCoordinates(x - absPos.x(), root->topOverflow());
+    }
+    
+    // Could not find a previous line. This means we must already be on the first line.
+    // Move to the start of the content in this block, which effectively moves us
+    // to the start of the line we're on.
+    NodeImpl* rootElement = node->isContentEditable() ? node->rootEditableElement() : node->document()->documentElement();
+    return VisiblePosition(rootElement, 0, DOWNSTREAM);
+}
+
+static NodeImpl* nextLeafWithSameEditability(NodeImpl* node, int offset)
+{
+    bool editable = node->isContentEditable();
+    ASSERT(offset >= 0);
+    NodeImpl* child = node->childNode(offset);
+    NodeImpl* n = child ? child->nextLeafNode() : node->nextLeafNode();
+    while (n) {
+        if (editable == n->isContentEditable())
+            return n;
+        n = n->nextLeafNode();
+    }
+    return 0;
+}
+
+static NodeImpl* nextLeafWithSameEditability(NodeImpl* node)
+{
+    if (!node)
+        return 0;
+    
+    bool editable = node->isContentEditable();
+    NodeImpl* n = node->nextLeafNode();
+    while (n) {
+        if (editable == n->isContentEditable())
+            return n;
+        n = n->nextLeafNode();
+    }
+    return 0;
+}
+
+VisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x)
+{
+    Position p = visiblePosition.deepEquivalent();
+    //kDebug() << "For position:" << p << endl;
+    NodeImpl *node = p.node();
+    NodeImpl* highestRoot = highestEditableRoot(p);
+    if (!node)
+        return VisiblePosition();
+    
+    node->document()->updateLayout/*IgnorePendingStylesheets*/();
+
+    RenderObject *renderer = node->renderer();
+    if (!renderer)
+        return VisiblePosition();
+
+    RenderBlock *containingBlock = 0;
+    RootInlineBox *root = 0;
+    InlineBox* box;
+    int ignoredCaretOffset;
+    visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
+    if (box) {
+        root = box->root()->nextRootBox();
+        if (root)
+            containingBlock = renderer->containingBlock();
+    }
+
+    if (!root) {
+        //kDebug() << "no root" << endl;
+        // This containing editable block does not have a next line.
+        // Need to move forward to next containing editable block in this root editable
+        // block and find the first root line box in that block.
+        NodeImpl* startBlock = enclosingBlock(node);
+        NodeImpl* n = nextLeafWithSameEditability(node, p.offset());
+        while (n && startBlock == enclosingBlock(n))
+            n = nextLeafWithSameEditability(n);
+        while (n) {
+            //kDebug() << "at node" << n << n->nodeName() << endl;
+            if (highestEditableRoot(Position(n, 0)) != highestRoot)
+                break;
+            Position pos(n, caretMinOffset(n));
+            //kDebug() << "position" << pos << endl;
+            if (pos.isCandidate()) {
+                ASSERT(n->renderer());
+                pos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset);
+                if (box) {
+                    // next root line box found
+                    root = box->root();
+                    containingBlock = n->renderer()->containingBlock();
+                    //kDebug() << "next root box found" << endl;
+                    break;
+                }
+                //kDebug() << "return position" << endl;
+                return VisiblePosition(pos, DOWNSTREAM);
+            }
+            n = nextLeafWithSameEditability(n);
+        }
+    }
+    
+    if (root) {
+        //kDebug() << "root" << endl;
+        // FIXME: Can be wrong for multi-column layout and with transforms.
+        QPointF absPos = containingBlock->localToAbsoluteForContent(QPointF());
+        if (containingBlock->hasOverflowClip()) {
+            QSize offset = containingBlock->layer()->scrolledContentOffset();
+            absPos.rx() -= offset.width();
+            absPos.ry() -= offset.height();
+        }
+
+        RenderObject *renderer = root->closestLeafChildForXPos(x - absPos.x(), isEditablePosition(p))->object();
+        NodeImpl* node = renderer->node();
+        if (editingIgnoresContent(node))
+            return Position(node->parent(), node->nodeIndex());
+        return renderer->positionForCoordinates(x - absPos.x(), root->topOverflow());
+    }    
+
+    // Could not find a next line. This means we must already be on the last line.
+    // Move to the end of the content in this block, which effectively moves us
+    // to the end of the line we're on.
+    ElementImpl* rootElement = node->isContentEditable() ? node->rootEditableElement() : node->document()->documentElement();
+    return VisiblePosition(rootElement, rootElement ? rootElement->childNodeCount() : 0, DOWNSTREAM);
+}
+
+// ---------
+
+static unsigned startSentenceBoundary(const QChar* characters, unsigned length)
+{
+    /*FIXME khtml TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
+    // FIXME: The following function can return -1; we don't handle that.
+    return textBreakPreceding(iterator, length);*/
+    kDebug() << "NOT IMPLEMENTED!" << endl;
+    return 0;
+}
+
+VisiblePosition startOfSentence(const VisiblePosition &c)
+{
+    return previousBoundary(c, startSentenceBoundary);
+}
+
+static unsigned endSentenceBoundary(const QChar* characters, unsigned length)
+{
+    /*FIXME khtml TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
+    return textBreakNext(iterator);*/
+    kDebug() << "NOT IMPLEMENTED!" << endl;
+    return 0;
+}
+
+// FIXME: This includes the space after the punctuation that marks the end of the sentence.
+VisiblePosition endOfSentence(const VisiblePosition &c)
+{
+    return nextBoundary(c, endSentenceBoundary);
+}
+
+static unsigned previousSentencePositionBoundary(const QChar* characters, unsigned length)
+{
+    /*FIXME khtml // FIXME: This is identical to startSentenceBoundary. I'm pretty sure that's not right.
+    TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
+    // FIXME: The following function can return -1; we don't handle that.
+    return textBreakPreceding(iterator, length);*/
+    kDebug() << "NOT IMPLEMENTED!" << endl;
+    return 0;
+}
+
+VisiblePosition previousSentencePosition(const VisiblePosition &c)
+{
+    VisiblePosition prev = previousBoundary(c, previousSentencePositionBoundary);
+    return c.honorEditableBoundaryAtOrAfter(prev);
+}
+
+static unsigned nextSentencePositionBoundary(const QChar* characters, unsigned length)
+{
+    /*FIXME khtml // FIXME: This is identical to endSentenceBoundary.  This isn't right, it needs to
+    // move to the equivlant position in the following sentence.
+    TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
+    return textBreakFollowing(iterator, 0);*/
+    kDebug() << "NOT IMPLEMENTED!" << endl;
+    return 0;
+}
+
+VisiblePosition nextSentencePosition(const VisiblePosition &c)
+{
+    VisiblePosition next = nextBoundary(c, nextSentencePositionBoundary);    
+    return c.honorEditableBoundaryAtOrBefore(next);
+}
+
+// FIXME: Broken for positions before/after images that aren't inline (5027702)
+VisiblePosition startOfParagraph(const VisiblePosition &c)
+{
+    Position p = c.deepEquivalent();
+    NodeImpl *startNode = p.node();
+
+    if (!startNode)
+        return VisiblePosition();
+    
+    if (startNode->renderer()
+        && ((startNode->renderer()->isTable() && !startNode->renderer()->isInline())
+            || startNode->renderer()->isHR())
+        && p.offset() == maxDeepOffset(startNode))
+        return VisiblePosition(Position(startNode, 0));
+
+    NodeImpl* startBlock = enclosingBlock(startNode);
+
+    NodeImpl *node = startNode;
+    int offset = p.offset();
+
+    NodeImpl *n = startNode;
+    while (n) {
+        if (n->isContentEditable() != startNode->isContentEditable())
+            break;
+        RenderObject *r = n->renderer();
+        if (!r) {
+            n = n->traversePreviousNodePostOrder(startBlock);
+            continue;
+        }
+        RenderStyle *style = r->style();
+        if (style->visibility() != VISIBLE) {
+            n = n->traversePreviousNodePostOrder(startBlock);
+            continue;
+        }
+        
+        if (r->isBR() || isBlock(n))
+            break;
+            
+        if (r->isText()) {
+            if (style->preserveNewline()) {
+                const QChar* chars = static_cast<RenderText*>(r)->characters();
+                int i = static_cast<RenderText*>(r)->textLength();
+                int o = offset;
+                if (n == startNode && o < i)
+                    i = max(0, o);
+                while (--i >= 0)
+                    if (chars[i] == '\n')
+                        return VisiblePosition(n, i + 1, DOWNSTREAM);
+            }
+            node = n;
+            offset = 0;
+            n = n->traversePreviousNodePostOrder(startBlock);
+        } else if (editingIgnoresContent(n) || isTableElement(n)) {
+            node = n;
+            offset = 0;
+            n = n->previousSibling() ? n->previousSibling() : n->traversePreviousNodePostOrder(startBlock);
+        } else
+            n = n->traversePreviousNodePostOrder(startBlock);
+    }
+
+    return VisiblePosition(node, offset, DOWNSTREAM);
+}
+
+// FIXME: Broken for positions before/after images that aren't inline (5027702)
+VisiblePosition endOfParagraph(const VisiblePosition &c)
+{    
+    if (c.isNull())
+        return VisiblePosition();
+
+    Position p = c.deepEquivalent();
+    NodeImpl* startNode = p.node();
+
+    if (startNode->renderer()
+        && ((startNode->renderer()->isTable() && !startNode->renderer()->isInline())
+            || startNode->renderer()->isHR())
+        && p.offset() == 0)
+        return VisiblePosition(Position(startNode, maxDeepOffset(startNode)));
+    
+    NodeImpl* startBlock = enclosingBlock(startNode);
+    NodeImpl *stayInsideBlock = startBlock;
+    
+    NodeImpl *node = startNode;
+    int offset = p.offset();
+
+    NodeImpl *n = startNode;
+    while (n) {
+        if (n->isContentEditable() != startNode->isContentEditable())
+            break;
+        RenderObject *r = n->renderer();
+        if (!r) {
+            n = n->traverseNextNode(stayInsideBlock);
+            continue;
+        }
+        RenderStyle *style = r->style();
+        if (style->visibility() != VISIBLE) {
+            n = n->traverseNextNode(stayInsideBlock);
+            continue;
+        }
+        
+        if (r->isBR() || isBlock(n))
+            break;
+            
+        // FIXME: We avoid returning a position where the renderer can't accept the caret.
+        // We should probably do this in other cases such as startOfParagraph.
+        if (r->isText() && r->caretMaxRenderedOffset() > 0) {
+            int length = static_cast<RenderText*>(r)->textLength();
+            if (style->preserveNewline()) {
+                const QChar* chars = static_cast<RenderText*>(r)->characters();
+                int o = n == startNode ? offset : 0;
+                for (int i = o; i < length; ++i)
+                    if (chars[i] == '\n')
+                        return VisiblePosition(n, i, DOWNSTREAM);
+            }
+            node = n;
+            offset = r->caretMaxOffset();
+            n = n->traverseNextNode(stayInsideBlock);
+        } else if (editingIgnoresContent(n) || isTableElement(n)) {
+            node = n;
+            offset = maxDeepOffset(n);
+            n = n->traverseNextSibling(stayInsideBlock);
+        } else
+            n = n->traverseNextNode(stayInsideBlock);
+    }
+
+    return VisiblePosition(node, offset, DOWNSTREAM);
+}
+
+VisiblePosition startOfNextParagraph(const VisiblePosition& visiblePosition)
+{
+    VisiblePosition paragraphEnd(endOfParagraph(visiblePosition));
+    VisiblePosition afterParagraphEnd(paragraphEnd.next(true));
+    // The position after the last position in the last cell of a table
+    // is not the start of the next paragraph.
+    if (isFirstPositionAfterTable(afterParagraphEnd))
+        return afterParagraphEnd.next(true);
+    return afterParagraphEnd;
+}
+
+bool inSameParagraph(const VisiblePosition &a, const VisiblePosition &b)
+{
+    return a.isNotNull() && startOfParagraph(a) == startOfParagraph(b);
+}
+
+bool isStartOfParagraph(const VisiblePosition &pos)
+{
+    return pos.isNotNull() && pos == startOfParagraph(pos);
+}
+
+bool isEndOfParagraph(const VisiblePosition &pos)
+{
+    return pos.isNotNull() && pos == endOfParagraph(pos);
+}
+
+VisiblePosition previousParagraphPosition(const VisiblePosition &p, int x)
+{
+    VisiblePosition pos = p;
+    do {
+        VisiblePosition n = previousLinePosition(pos, x);
+        if (n.isNull() || n == pos)
+            return p;
+        pos = n;
+    } while (inSameParagraph(p, pos));
+    return pos;
+}
+
+VisiblePosition nextParagraphPosition(const VisiblePosition &p, int x)
+{
+    VisiblePosition pos = p;
+    do {
+        VisiblePosition n = nextLinePosition(pos, x);
+        if (n.isNull() || n == pos)
+            return p;
+        pos = n;
+    } while (inSameParagraph(p, pos));
+    return pos;
+}
+
+// ---------
+
+VisiblePosition startOfBlock(const VisiblePosition &c)
+{
+    Position p = c.deepEquivalent();
+    NodeImpl *startNode = p.node();
+    if (!startNode)
+        return VisiblePosition();
+    return VisiblePosition(Position(startNode->enclosingBlockFlowElement(), 0), DOWNSTREAM);
+}
+
+VisiblePosition endOfBlock(const VisiblePosition &c)
+{
+    Position p = c.deepEquivalent();
+
+    NodeImpl *startNode = p.node();
+    if (!startNode)
+        return VisiblePosition();
+
+    NodeImpl *startBlock = startNode->enclosingBlockFlowElement();
+    
+    return VisiblePosition(startBlock, startBlock->childNodeCount(), VP_DEFAULT_AFFINITY);  
+}
+
+bool inSameBlock(const VisiblePosition &a, const VisiblePosition &b)
+{
+    return !a.isNull() && enclosingBlockFlowElement(a) == enclosingBlockFlowElement(b);
+}
+
+bool isStartOfBlock(const VisiblePosition &pos)
+{
+    return pos.isNotNull() && pos == startOfBlock(pos);
+}
+
+bool isEndOfBlock(const VisiblePosition &pos)
+{
+    return pos.isNotNull() && pos == endOfBlock(pos);
+}
+
+// ---------
+
+VisiblePosition startOfDocument(const NodeImpl* node)
+{
+    if (!node)
+        return VisiblePosition();
+    
+    return VisiblePosition(node->document()->documentElement(), 0, DOWNSTREAM);
+}
+
+VisiblePosition startOfDocument(const VisiblePosition &c)
+{
+    return startOfDocument(c.deepEquivalent().node());
+}
+
+VisiblePosition endOfDocument(const NodeImpl* node)
+{
+    if (!node || !node->document())
+        return VisiblePosition();
+    
+    ElementImpl* doc = node->document()->documentElement();
+    return VisiblePosition(doc, doc->childNodeCount(), DOWNSTREAM);
+}
+
+VisiblePosition endOfDocument(const VisiblePosition &c)
+{
+    return endOfDocument(c.deepEquivalent().node());
+}
+
+bool inSameDocument(const VisiblePosition &a, const VisiblePosition &b)
+{
+    Position ap = a.deepEquivalent();
+    NodeImpl *an = ap.node();
+    if (!an)
+        return false;
+    Position bp = b.deepEquivalent();
+    NodeImpl *bn = bp.node();
+    if (an == bn)
+        return true;
+
+    return an->document() == bn->document();
+}
+
+bool isStartOfDocument(const VisiblePosition &p)
+{
+    return p.isNotNull() && p.previous().isNull();
+}
+
+bool isEndOfDocument(const VisiblePosition &p)
+{
+    return p.isNotNull() && p.next().isNull();
+}
+
+// ---------
+
+VisiblePosition startOfEditableContent(const VisiblePosition& visiblePosition)
+{
+    NodeImpl* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
+    if (!highestRoot)
+        return VisiblePosition();
+
+    return VisiblePosition(highestRoot, 0, DOWNSTREAM);
+}
+
+VisiblePosition endOfEditableContent(const VisiblePosition& visiblePosition)
+{
+    NodeImpl* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
+    if (!highestRoot)
+        return VisiblePosition();
+
+    return VisiblePosition(highestRoot, maxDeepOffset(highestRoot), DOWNSTREAM);
+}
+
+}
diff --git a/khtml/xml/visible_units.h b/khtml/xml/visible_units.h
new file mode 100644
index 0000000..bd610f6
--- /dev/null
+++ b/khtml/xml/visible_units.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef visible_units_h
+#define visible_units_h
+
+/*#include "Document.h"
+#include "TextAffinity.h"*/
+
+namespace DOM {
+
+class NodeImpl;
+class VisiblePosition;
+
+enum EWordSide { RightWordIfOnBoundary = false, LeftWordIfOnBoundary = true };
+
+// words
+VisiblePosition startOfWord(const VisiblePosition &, EWordSide = RightWordIfOnBoundary);
+VisiblePosition endOfWord(const VisiblePosition &, EWordSide = RightWordIfOnBoundary);
+VisiblePosition previousWordPosition(const VisiblePosition &);
+VisiblePosition nextWordPosition(const VisiblePosition &);
+
+// sentences
+VisiblePosition startOfSentence(const VisiblePosition &);
+VisiblePosition endOfSentence(const VisiblePosition &);
+VisiblePosition previousSentencePosition(const VisiblePosition &);
+VisiblePosition nextSentencePosition(const VisiblePosition &);
+
+// lines
+VisiblePosition startOfLine(const VisiblePosition &);
+VisiblePosition endOfLine(const VisiblePosition &);
+VisiblePosition previousLinePosition(const VisiblePosition &, int x);
+VisiblePosition nextLinePosition(const VisiblePosition &, int x);
+bool inSameLine(const VisiblePosition &, const VisiblePosition &);
+bool isStartOfLine(const VisiblePosition &);
+bool isEndOfLine(const VisiblePosition &);
+
+// paragraphs (perhaps a misnomer, can be divided by line break elements)
+VisiblePosition startOfParagraph(const VisiblePosition&);
+VisiblePosition endOfParagraph(const VisiblePosition&);
+VisiblePosition startOfNextParagraph(const VisiblePosition&);
+VisiblePosition previousParagraphPosition(const VisiblePosition &, int x);
+VisiblePosition nextParagraphPosition(const VisiblePosition &, int x);
+bool inSameParagraph(const VisiblePosition &, const VisiblePosition &);
+bool isStartOfParagraph(const VisiblePosition &);
+bool isEndOfParagraph(const VisiblePosition &);
+
+// blocks (true paragraphs; line break elements don't break blocks)
+VisiblePosition startOfBlock(const VisiblePosition &);
+VisiblePosition endOfBlock(const VisiblePosition &);
+bool inSameBlock(const VisiblePosition &, const VisiblePosition &);
+bool isStartOfBlock(const VisiblePosition &);
+bool isEndOfBlock(const VisiblePosition &);
+
+// document
+VisiblePosition startOfDocument(const DOM::NodeImpl*);
+VisiblePosition endOfDocument(const DOM::NodeImpl*);
+VisiblePosition startOfDocument(const VisiblePosition &);
+VisiblePosition endOfDocument(const VisiblePosition &);
+bool inSameDocument(const VisiblePosition &, const VisiblePosition &);
+bool isStartOfDocument(const VisiblePosition &);
+bool isEndOfDocument(const VisiblePosition &);
+
+// editable content
+VisiblePosition startOfEditableContent(const VisiblePosition&);
+VisiblePosition endOfEditableContent(const VisiblePosition&);
+
+} // namespace WebCore
+
+#endif // VisiblePosition_h
diff --git a/plasma/extenderitem.cpp b/plasma/extenderitem.cpp
index fd89b13..d7a89ff 100644
--- a/plasma/extenderitem.cpp
+++ b/plasma/extenderitem.cpp
@@ -674,10 +674,12 @@ void ExtenderItemPrivate::updateToolBox()
 
 void ExtenderItemPrivate::repositionToolbox()
 {
+    if (toolboxLayout && toolbox) {
     QSizeF minimum = toolboxLayout->minimumSize();
     toolbox->setPos(q->size().width() - minimum.width() - bgRight,
                     (dragHandleRect().height()/2) -
                     (minimum.height()/2) + bgTop);
+    }
 }
 
 Applet *ExtenderItemPrivate::hostApplet() const

 « Return to Thread: Update of editing/selection code in khtml