Reviewed by Darin.
authorharrison <harrison@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 10 Feb 2005 00:30:06 +0000 (00:30 +0000)
committerharrison <harrison@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 10 Feb 2005 00:30:06 +0000 (00:30 +0000)
        <rdar://problem/3937447> Mail-689: Arrow key navigation in new message body stops working when a line ends with a bold word

        Added affinity to VisiblePosition.  Changed Selection code to use affinity more.

        (Partial) <rdar://problem/3982096> editing/pasteboard/paste-text-007 is failing

        Changed ReplaceSelectionCommand to also pay attention to the top children of the incoming fragment, not just the very last node inserted, when deciding whether to insert a paragraph for the Apple interchange newline.

        * khtml/ecma/kjs_window.cpp:
        (SelectionFunc::tryCall):
        * khtml/editing/htmlediting.cpp:
        (khtml::EditCommandPtr::setStartingSelection):
        (khtml::EditCommandPtr::setEndingSelection):
        (khtml::EditCommand::setStartingSelection):
        (khtml::EditCommand::setEndingSelection):
        (khtml::CompositeEditCommand::deleteInsignificantTextDownstream):
        (khtml::CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessary):
        (khtml::ApplyStyleCommand::splitTextAtStartIfNeeded):
        (khtml::ApplyStyleCommand::splitTextAtEndIfNeeded):
        (khtml::ApplyStyleCommand::splitTextElementAtStartIfNeeded):
        (khtml::ApplyStyleCommand::splitTextElementAtEndIfNeeded):
        (khtml::ApplyStyleCommand::mergeStartWithPreviousIfIdentical):
        (khtml::ApplyStyleCommand::mergeEndWithNextIfIdentical):
        (khtml::ApplyStyleCommand::joinChildTextNodes):
        (khtml::DeleteSelectionCommand::initializePositionData):
        (khtml::DeleteSelectionCommand::handleGeneralDelete):
        (khtml::DeleteSelectionCommand::calculateTypingStyleAfterDelete):
        (khtml::DeleteSelectionCommand::doApply):
        (khtml::InsertLineBreakCommand::doApply):
        (khtml::InsertParagraphSeparatorCommand::doApply):
        (khtml::InsertParagraphSeparatorInQuotedContentCommand::doApply):
        (khtml::InsertTextCommand::input):
        (khtml::MoveSelectionCommand::doApply):
        (khtml::ReplaceSelectionCommand::ReplaceSelectionCommand):
        (khtml::ReplaceSelectionCommand::~ReplaceSelectionCommand):
        (khtml::ReplaceSelectionCommand::doApply):
        (khtml::ReplaceSelectionCommand::completeHTMLReplacement):
        (khtml::ReplaceSelectionCommand::updateNodesInserted):
        (khtml::TypingCommand::deleteKeyPressed):
        (khtml::TypingCommand::forwardDeleteKeyPressed):
        (khtml::TypingCommand::markMisspellingsAfterTyping):
        * khtml/editing/htmlediting.h:
        * khtml/editing/selection.cpp:
        (khtml::Selection::Selection):
        (khtml::Selection::init):
        (khtml::Selection::moveTo):
        (khtml::Selection::modifyExtendingRightForward):
        (khtml::Selection::modifyMovingRightForward):
        (khtml::Selection::modifyExtendingLeftBackward):
        (khtml::Selection::modifyMovingLeftBackward):
        (khtml::Selection::modify):
        (khtml::Selection::xPosForVerticalArrowNavigation):
        (khtml::Selection::clear):
        (khtml::Selection::setBase):
        (khtml::Selection::setExtent):
        (khtml::Selection::setBaseAndExtent):
        (khtml::Selection::layout):
        (khtml::Selection::validate):
        * khtml/editing/selection.h:
        (khtml::Selection::startAffinity):
        (khtml::Selection::endAffinity):
        (khtml::Selection::baseAffinity):
        (khtml::Selection::extentAffinity):
        (khtml::operator==):
        * khtml/editing/text_affinity.h:
        (khtml::):
        * khtml/editing/visible_position.cpp:
        (khtml::VisiblePosition::VisiblePosition):
        (khtml::VisiblePosition::init):
        (khtml::VisiblePosition::initUpstream):
        (khtml::VisiblePosition::initDownstream):
        (khtml::VisiblePosition::next):
        (khtml::VisiblePosition::previous):
        (khtml::startVisiblePosition):
        (khtml::endVisiblePosition):
        * khtml/editing/visible_position.h:
        (khtml::VisiblePosition::):
        (khtml::VisiblePosition::VisiblePosition):
        (khtml::VisiblePosition::affinity):
        (khtml::VisiblePosition::setAffinity):
        (khtml::operator==):
        * khtml/editing/visible_units.cpp:
        (khtml::previousBoundary):
        (khtml::nextBoundary):
        (khtml::startOfLine):
        (khtml::endOfLine):
        (khtml::previousLinePosition):
        (khtml::nextLinePosition):
        (khtml::startOfParagraph):
        (khtml::endOfParagraph):
        (khtml::previousParagraphPosition):
        (khtml::nextParagraphPosition):
        (khtml::startOfBlock):
        (khtml::endOfBlock):
        (khtml::startOfDocument):
        (khtml::endOfDocument):
        * khtml/editing/visible_units.h:
        * khtml/khtml_part.cpp:
        (KHTMLPart::findTextNext):
        (KHTMLPart::selectClosestWordFromMouseEvent):
        (KHTMLPart::handleMousePressEventTripleClick):
        (KHTMLPart::handleMousePressEventSingleClick):
        (KHTMLPart::handleMouseMoveEventSelection):
        (KHTMLPart::khtmlMouseReleaseEvent):
        (KHTMLPart::selectAll):
        (KHTMLPart::computeAndSetTypingStyle):
        (KHTMLPart::selectionComputedStyle):
        * khtml/rendering/render_br.cpp:
        (RenderBR::positionForCoordinates):
        * khtml/xml/dom_docimpl.cpp:
        (DocumentImpl::updateSelection):
        * khtml/xml/dom_nodeimpl.cpp:
        (NodeBaseImpl::setFocus):
        * khtml/xml/dom_position.cpp:
        (DOM::Position::previousCharacterPosition):
        (DOM::Position::nextCharacterPosition):
        * khtml/xml/dom_position.h:
        * kwq/KWQAccObject.mm:
        (-[KWQAccObject value]):
        (-[KWQAccObject visiblePositionForStartOfTextMarkerRange:]):
        (-[KWQAccObject visiblePositionForEndOfTextMarkerRange:]):
        (-[KWQAccObject accessibilityAttributeValue:]):
        (-[KWQAccObject doAXLineForTextMarker:]):
        (-[KWQAccObject doAXTextMarkerRangeForLine:]):
        (-[KWQAccObject doAXTextMarkerForPosition:]):
        (-[KWQAccObject doAXLeftLineTextMarkerRangeForTextMarker:]):
        (-[KWQAccObject doAXRightLineTextMarkerRangeForTextMarker:]):
        (-[KWQAccObject doAXNextWordEndTextMarkerForTextMarker:]):
        (-[KWQAccObject doAXPreviousWordStartTextMarkerForTextMarker:]):
        (-[KWQAccObject doAXNextLineEndTextMarkerForTextMarker:]):
        (-[KWQAccObject doAXPreviousLineStartTextMarkerForTextMarker:]):
        (-[KWQAccObject doSetAXSelectedTextMarkerRange:]):
        * kwq/KWQAccObjectCache.mm:
        (KWQAccObjectCache::textMarkerForVisiblePosition):
        (KWQAccObjectCache::visiblePositionForTextMarker):
        * kwq/KWQKHTMLPart.mm:
        (KWQKHTMLPart::findString):
        (KWQKHTMLPart::advanceToNextMisspelling):
        (KWQKHTMLPart::styleForSelectionStart):
        (KWQKHTMLPart::baseWritingDirectionForSelectionStart):
        (KWQKHTMLPart::setSelectionFromNone):
        (KWQKHTMLPart::respondToChangedSelection):
        * kwq/WebCoreBridge.mm:
        (-[WebCoreBridge setSelectedDOMRange:affinity:]):
        (-[WebCoreBridge selectionAffinity]):
        (-[WebCoreBridge setMarkDOMRange:]):
        (-[WebCoreBridge _visiblePositionForPoint:]):
        (-[WebCoreBridge moveDragCaretToPoint:]):
        (-[WebCoreBridge editableDOMRangeForPoint:]):
        (-[WebCoreBridge ensureSelectionVisible]):
        (-[WebCoreBridge rangeOfCharactersAroundCaret]):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@8554 268f45cc-cd09-0410-ab3c-d52691b4dbfc

23 files changed:
WebCore/ChangeLog-2005-08-23
WebCore/khtml/ecma/kjs_window.cpp
WebCore/khtml/editing/SelectionController.cpp
WebCore/khtml/editing/SelectionController.h
WebCore/khtml/editing/htmlediting.cpp
WebCore/khtml/editing/htmlediting.h
WebCore/khtml/editing/selection.cpp
WebCore/khtml/editing/selection.h
WebCore/khtml/editing/text_affinity.h
WebCore/khtml/editing/visible_position.cpp
WebCore/khtml/editing/visible_position.h
WebCore/khtml/editing/visible_units.cpp
WebCore/khtml/editing/visible_units.h
WebCore/khtml/khtml_part.cpp
WebCore/khtml/rendering/render_br.cpp
WebCore/khtml/xml/dom_docimpl.cpp
WebCore/khtml/xml/dom_nodeimpl.cpp
WebCore/khtml/xml/dom_position.cpp
WebCore/khtml/xml/dom_position.h
WebCore/kwq/KWQAccObject.mm
WebCore/kwq/KWQAccObjectCache.mm
WebCore/kwq/KWQKHTMLPart.mm
WebCore/kwq/WebCoreBridge.mm

index b1c3debb46b88b200a5ad32086832fc3880b4a3b..fec2b0df6605b0373d3cc5c557677d4de71c93b3 100644 (file)
@@ -1,3 +1,159 @@
+2005-02-09  David Harrison  <harrison@apple.com>
+
+        Reviewed by Darin.
+        
+        <rdar://problem/3937447> Mail-689: Arrow key navigation in new message body stops working when a line ends with a bold word
+        
+        Added affinity to VisiblePosition.  Changed Selection code to use affinity more.
+        
+        (Partial) <rdar://problem/3982096> editing/pasteboard/paste-text-007 is failing
+        
+        Changed ReplaceSelectionCommand to also pay attention to the top children of the incoming fragment, not just the very last node inserted, when deciding whether to insert a paragraph for the Apple interchange newline.
+
+        * khtml/ecma/kjs_window.cpp:
+        (SelectionFunc::tryCall):
+        * khtml/editing/htmlediting.cpp:
+        (khtml::EditCommandPtr::setStartingSelection):
+        (khtml::EditCommandPtr::setEndingSelection):
+        (khtml::EditCommand::setStartingSelection):
+        (khtml::EditCommand::setEndingSelection):
+        (khtml::CompositeEditCommand::deleteInsignificantTextDownstream):
+        (khtml::CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessary):
+        (khtml::ApplyStyleCommand::splitTextAtStartIfNeeded):
+        (khtml::ApplyStyleCommand::splitTextAtEndIfNeeded):
+        (khtml::ApplyStyleCommand::splitTextElementAtStartIfNeeded):
+        (khtml::ApplyStyleCommand::splitTextElementAtEndIfNeeded):
+        (khtml::ApplyStyleCommand::mergeStartWithPreviousIfIdentical):
+        (khtml::ApplyStyleCommand::mergeEndWithNextIfIdentical):
+        (khtml::ApplyStyleCommand::joinChildTextNodes):
+        (khtml::DeleteSelectionCommand::initializePositionData):
+        (khtml::DeleteSelectionCommand::handleGeneralDelete):
+        (khtml::DeleteSelectionCommand::calculateTypingStyleAfterDelete):
+        (khtml::DeleteSelectionCommand::doApply):
+        (khtml::InsertLineBreakCommand::doApply):
+        (khtml::InsertParagraphSeparatorCommand::doApply):
+        (khtml::InsertParagraphSeparatorInQuotedContentCommand::doApply):
+        (khtml::InsertTextCommand::input):
+        (khtml::MoveSelectionCommand::doApply):
+        (khtml::ReplaceSelectionCommand::ReplaceSelectionCommand):
+        (khtml::ReplaceSelectionCommand::~ReplaceSelectionCommand):
+        (khtml::ReplaceSelectionCommand::doApply):
+        (khtml::ReplaceSelectionCommand::completeHTMLReplacement):
+        (khtml::ReplaceSelectionCommand::updateNodesInserted):
+        (khtml::TypingCommand::deleteKeyPressed):
+        (khtml::TypingCommand::forwardDeleteKeyPressed):
+        (khtml::TypingCommand::markMisspellingsAfterTyping):
+        * khtml/editing/htmlediting.h:
+        * khtml/editing/selection.cpp:
+        (khtml::Selection::Selection):
+        (khtml::Selection::init):
+        (khtml::Selection::moveTo):
+        (khtml::Selection::modifyExtendingRightForward):
+        (khtml::Selection::modifyMovingRightForward):
+        (khtml::Selection::modifyExtendingLeftBackward):
+        (khtml::Selection::modifyMovingLeftBackward):
+        (khtml::Selection::modify):
+        (khtml::Selection::xPosForVerticalArrowNavigation):
+        (khtml::Selection::clear):
+        (khtml::Selection::setBase):
+        (khtml::Selection::setExtent):
+        (khtml::Selection::setBaseAndExtent):
+        (khtml::Selection::layout):
+        (khtml::Selection::validate):
+        * khtml/editing/selection.h:
+        (khtml::Selection::startAffinity):
+        (khtml::Selection::endAffinity):
+        (khtml::Selection::baseAffinity):
+        (khtml::Selection::extentAffinity):
+        (khtml::operator==):
+        * khtml/editing/text_affinity.h:
+        (khtml::):
+        * khtml/editing/visible_position.cpp:
+        (khtml::VisiblePosition::VisiblePosition):
+        (khtml::VisiblePosition::init):
+        (khtml::VisiblePosition::initUpstream):
+        (khtml::VisiblePosition::initDownstream):
+        (khtml::VisiblePosition::next):
+        (khtml::VisiblePosition::previous):
+        (khtml::startVisiblePosition):
+        (khtml::endVisiblePosition):
+        * khtml/editing/visible_position.h:
+        (khtml::VisiblePosition::):
+        (khtml::VisiblePosition::VisiblePosition):
+        (khtml::VisiblePosition::affinity):
+        (khtml::VisiblePosition::setAffinity):
+        (khtml::operator==):
+        * khtml/editing/visible_units.cpp:
+        (khtml::previousBoundary):
+        (khtml::nextBoundary):
+        (khtml::startOfLine):
+        (khtml::endOfLine):
+        (khtml::previousLinePosition):
+        (khtml::nextLinePosition):
+        (khtml::startOfParagraph):
+        (khtml::endOfParagraph):
+        (khtml::previousParagraphPosition):
+        (khtml::nextParagraphPosition):
+        (khtml::startOfBlock):
+        (khtml::endOfBlock):
+        (khtml::startOfDocument):
+        (khtml::endOfDocument):
+        * khtml/editing/visible_units.h:
+        * khtml/khtml_part.cpp:
+        (KHTMLPart::findTextNext):
+        (KHTMLPart::selectClosestWordFromMouseEvent):
+        (KHTMLPart::handleMousePressEventTripleClick):
+        (KHTMLPart::handleMousePressEventSingleClick):
+        (KHTMLPart::handleMouseMoveEventSelection):
+        (KHTMLPart::khtmlMouseReleaseEvent):
+        (KHTMLPart::selectAll):
+        (KHTMLPart::computeAndSetTypingStyle):
+        (KHTMLPart::selectionComputedStyle):
+        * khtml/rendering/render_br.cpp:
+        (RenderBR::positionForCoordinates):
+        * khtml/xml/dom_docimpl.cpp:
+        (DocumentImpl::updateSelection):
+        * khtml/xml/dom_nodeimpl.cpp:
+        (NodeBaseImpl::setFocus):
+        * khtml/xml/dom_position.cpp:
+        (DOM::Position::previousCharacterPosition):
+        (DOM::Position::nextCharacterPosition):
+        * khtml/xml/dom_position.h:
+        * kwq/KWQAccObject.mm:
+        (-[KWQAccObject value]):
+        (-[KWQAccObject visiblePositionForStartOfTextMarkerRange:]):
+        (-[KWQAccObject visiblePositionForEndOfTextMarkerRange:]):
+        (-[KWQAccObject accessibilityAttributeValue:]):
+        (-[KWQAccObject doAXLineForTextMarker:]):
+        (-[KWQAccObject doAXTextMarkerRangeForLine:]):
+        (-[KWQAccObject doAXTextMarkerForPosition:]):
+        (-[KWQAccObject doAXLeftLineTextMarkerRangeForTextMarker:]):
+        (-[KWQAccObject doAXRightLineTextMarkerRangeForTextMarker:]):
+        (-[KWQAccObject doAXNextWordEndTextMarkerForTextMarker:]):
+        (-[KWQAccObject doAXPreviousWordStartTextMarkerForTextMarker:]):
+        (-[KWQAccObject doAXNextLineEndTextMarkerForTextMarker:]):
+        (-[KWQAccObject doAXPreviousLineStartTextMarkerForTextMarker:]):
+        (-[KWQAccObject doSetAXSelectedTextMarkerRange:]):
+        * kwq/KWQAccObjectCache.mm:
+        (KWQAccObjectCache::textMarkerForVisiblePosition):
+        (KWQAccObjectCache::visiblePositionForTextMarker):
+        * kwq/KWQKHTMLPart.mm:
+        (KWQKHTMLPart::findString):
+        (KWQKHTMLPart::advanceToNextMisspelling):
+        (KWQKHTMLPart::styleForSelectionStart):
+        (KWQKHTMLPart::baseWritingDirectionForSelectionStart):
+        (KWQKHTMLPart::setSelectionFromNone):
+        (KWQKHTMLPart::respondToChangedSelection):
+        * kwq/WebCoreBridge.mm:
+        (-[WebCoreBridge setSelectedDOMRange:affinity:]):
+        (-[WebCoreBridge selectionAffinity]):
+        (-[WebCoreBridge setMarkDOMRange:]):
+        (-[WebCoreBridge _visiblePositionForPoint:]):
+        (-[WebCoreBridge moveDragCaretToPoint:]):
+        (-[WebCoreBridge editableDOMRangeForPoint:]):
+        (-[WebCoreBridge ensureSelectionVisible]):
+        (-[WebCoreBridge rangeOfCharactersAroundCaret]):
+
 2005-02-09  Chris Blumenberg  <cblu@apple.com>
 
        Fixed: <rdar://problem/3985211> Seed: Mail: Drag-and-drop destination indicator / insertion point disappears
index a22ef493cdf907122f93672998ad8e7f3d66d598..0bdb34b1bd930acdcd55b5d8af1dd84368464762 100644 (file)
@@ -2431,15 +2431,15 @@ Value SelectionFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
         switch (id) {
             case Selection::Collapse:
                 TypingCommand::closeTyping(part->lastEditCommand());
-                part->setSelection(khtml::Selection(Position(KJS::toNode(args[0]).handle(), args[1].toInt32(exec))));
+                part->setSelection(khtml::Selection(Position(KJS::toNode(args[0]).handle(), args[1].toInt32(exec)), khtml::SEL_DEFAULT_AFFINITY));
                 break;
             case Selection::CollapseToEnd:
                 TypingCommand::closeTyping(part->lastEditCommand());
-                part->setSelection(khtml::Selection(part->selection().end()));
+                part->setSelection(khtml::Selection(part->selection().end(), part->selection().endAffinity()));
                 break;
             case Selection::CollapseToStart:
                 TypingCommand::closeTyping(part->lastEditCommand());
-                part->setSelection(khtml::Selection(part->selection().start()));
+                part->setSelection(khtml::Selection(part->selection().start(), part->selection().startAffinity()));
                 break;
             case Selection::Empty:
                 TypingCommand::closeTyping(part->lastEditCommand());
@@ -2449,12 +2449,12 @@ Value SelectionFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
                 TypingCommand::closeTyping(part->lastEditCommand());
                 Position base(KJS::toNode(args[0]).handle(), args[1].toInt32(exec));
                 Position extent(KJS::toNode(args[2]).handle(), args[3].toInt32(exec));
-                part->setSelection(khtml::Selection(base, extent));
+                part->setSelection(khtml::Selection(base, khtml::SEL_DEFAULT_AFFINITY, extent, khtml::SEL_DEFAULT_AFFINITY));
                 break;
             }
             case Selection::SetPosition:
                 TypingCommand::closeTyping(part->lastEditCommand());
-                part->setSelection(khtml::Selection(Position(KJS::toNode(args[0]).handle(), args[1].toInt32(exec))));
+                part->setSelection(khtml::Selection(Position(KJS::toNode(args[0]).handle(), args[1].toInt32(exec)), khtml::SEL_DEFAULT_AFFINITY));
                 break;
             case Selection::Modify: {
                 TypingCommand::closeTyping(part->lastEditCommand());
index b0eeee4f6dec33a3737a3596a514f1100903ae82..ec0b9447d1e4fd7c373bd51e98f7beca615ef917 100644 (file)
@@ -67,34 +67,41 @@ namespace khtml {
 
 Selection::Selection()
 {
-    init();
+    init(DOWNSTREAM);
 }
 
-Selection::Selection(const Position &pos)
+Selection::Selection(const Position &pos, EAffinity affinity)
     : m_base(pos), m_extent(pos)
 {
-    init();
+    init(affinity);
     validate();
 }
 
-Selection::Selection(const Range &r)
+Selection::Selection(const Range &r, EAffinity baseAffinity, EAffinity extentAffinity)
     : m_base(startPosition(r)), m_extent(endPosition(r))
 {
-    init();
+    init(baseAffinity);
     validate();
 }
 
-Selection::Selection(const Position &base, const Position &extent)
+Selection::Selection(const Position &base, EAffinity baseAffinity, const Position &extent, EAffinity extentAffinity)
     : m_base(base), m_extent(extent)
 {
-    init();
+    init(baseAffinity);
+    validate();
+}
+
+Selection::Selection(const VisiblePosition &visiblePos)
+    : m_base(visiblePos.position()), m_extent(visiblePos.position())
+{
+    init(visiblePos.affinity());
     validate();
 }
 
 Selection::Selection(const VisiblePosition &base, const VisiblePosition &extent)
     : m_base(base.position()), m_extent(extent.position())
 {
-    init();
+    init(base.affinity());
     validate();
 }
 
@@ -117,11 +124,12 @@ Selection::Selection(const Selection &o)
     }
 }
 
-void Selection::init()
+void Selection::init(EAffinity affinity)
 {
+    // FIXME: set extentAffinity
     m_state = NONE; 
-    m_affinity = UPSTREAM;
     m_baseIsStart = true;
+    m_affinity = affinity;
     m_needsLayout = true;
     m_modifyBiasSet = false;
 }
@@ -153,75 +161,55 @@ Selection &Selection::operator=(const Selection &o)
     return *this;
 }
 
-void Selection::setAffinity(EAffinity affinity)
+void Selection::moveTo(const VisiblePosition &pos)
 {
-    if (affinity == m_affinity)
-        return;
-        
-    m_affinity = affinity;
-    setNeedsLayout();
-}
-
-void Selection::modifyAffinity(EAlter alter, EDirection dir, ETextGranularity granularity)
-{
-    switch (granularity) {
-        case CHARACTER:
-        case WORD:
-            m_affinity = DOWNSTREAM;
-            break;
-        case PARAGRAPH:
-        case LINE:
-        case PARAGRAPH_BOUNDARY:
-        case DOCUMENT_BOUNDARY:
-            // These granularities should not change affinity.
-            break;
-        case LINE_BOUNDARY: {
-            // When extending, leave affinity unchanged.
-            if (alter == MOVE) {
-                switch (dir) {
-                    case FORWARD:
-                    case RIGHT:
-                        m_affinity = UPSTREAM;
-                        break;
-                    case BACKWARD:
-                    case LEFT:
-                        m_affinity = DOWNSTREAM;
-                        break;
-                }
-            }
-            break;
-        }
-    }
-    setNeedsLayout();
+    // FIXME: use extentAffinity
+    m_affinity = pos.affinity();
+    m_base = pos.deepEquivalent();
+    m_extent = pos.deepEquivalent();
+    validate();
 }
 
-void Selection::moveTo(const Range &r)
+void Selection::moveTo(const VisiblePosition &base, const VisiblePosition &extent)
 {
-    m_affinity = UPSTREAM;
-    m_base = startPosition(r);
-    m_extent = endPosition(r);
+    // FIXME: use extentAffinity
+    m_affinity = base.affinity();
+    m_base = base.deepEquivalent();
+    m_extent = extent.deepEquivalent();
     validate();
 }
 
 void Selection::moveTo(const Selection &o)
 {
-    m_affinity = UPSTREAM;
+    // FIXME: copy extentAffinity
+    m_affinity = o.m_affinity;
     m_base = o.m_start;
     m_extent = o.m_end;
     validate();
 }
 
-void Selection::moveTo(const Position &pos)
+void Selection::moveTo(const Position &pos, EAffinity affinity)
 {
-    m_affinity = UPSTREAM;
+    // FIXME: use extentAffinity
+    m_affinity = affinity;
     m_base = pos;
     m_extent = pos;
     validate();
 }
 
-void Selection::moveTo(const Position &base, const Position &extent)
+void Selection::moveTo(const Range &r, EAffinity baseAffinity, EAffinity extentAffinity)
 {
-    m_affinity = UPSTREAM;
+    // FIXME: use extentAffinity
+    m_affinity = baseAffinity;
+    m_base = startPosition(r);
+    m_extent = endPosition(r);
+    validate();
+}
+
+void Selection::moveTo(const Position &base, EAffinity baseAffinity, const Position &extent, EAffinity extentAffinity)
+{
+    // FIXME: use extentAffinity
+    m_affinity = baseAffinity;
     m_base = base;
     m_extent = extent;
     validate();
@@ -256,7 +244,7 @@ void Selection::setModifyBias(EAlter alter, EDirection direction)
 
 VisiblePosition Selection::modifyExtendingRightForward(ETextGranularity granularity)
 {
-    VisiblePosition pos(m_extent);
+    VisiblePosition pos(m_extent, m_affinity);
     switch (granularity) {
         case CHARACTER:
             pos = pos.next();
@@ -271,15 +259,16 @@ VisiblePosition Selection::modifyExtendingRightForward(ETextGranularity granular
             pos = nextLinePosition(pos, m_affinity, xPosForVerticalArrowNavigation(EXTENT));
             break;
         case LINE_BOUNDARY:
-            pos = endOfLine(VisiblePosition(m_end), m_affinity);
+            pos = endOfLine(VisiblePosition(m_end, m_affinity), UPSTREAM);
             break;
         case PARAGRAPH_BOUNDARY:
-            pos = endOfParagraph(VisiblePosition(m_end));
+            pos = endOfParagraph(VisiblePosition(m_end, m_affinity));
             break;
         case DOCUMENT_BOUNDARY:
             pos = endOfDocument(pos);
             break;
     }
+    
     return pos;
 }
 
@@ -289,15 +278,15 @@ VisiblePosition Selection::modifyMovingRightForward(ETextGranularity granularity
     switch (granularity) {
         case CHARACTER:
             if (isRange()) 
-                pos = VisiblePosition(m_end);
+                pos = VisiblePosition(m_end, m_affinity);
             else
-                pos = VisiblePosition(m_extent).next();
+                pos = VisiblePosition(m_extent, m_affinity).next();
             break;
         case WORD:
-            pos = nextWordPosition(VisiblePosition(m_extent));
+            pos = nextWordPosition(VisiblePosition(m_extent, m_affinity));
             break;
         case PARAGRAPH:
-            pos = nextParagraphPosition(VisiblePosition(m_end), m_affinity, xPosForVerticalArrowNavigation(END, isRange()));
+            pos = nextParagraphPosition(VisiblePosition(m_end, m_affinity), m_affinity, xPosForVerticalArrowNavigation(END, isRange()));
             break;
         case LINE: {
             // This somewhat complicated code is needed to handle the case where there is a
@@ -309,26 +298,25 @@ VisiblePosition Selection::modifyMovingRightForward(ETextGranularity granularity
             // <rdar://problem/3875618> REGRESSION (Mail): Hitting down arrow with full line selected skips line (br case)
             // <rdar://problem/3875641> REGRESSION (Mail): Hitting down arrow with full line selected skips line (div case)
             if (isCaret()) {
-                pos = VisiblePosition(m_end);
-            }
-            else if (isRange()) {
+                pos = VisiblePosition(m_end, m_affinity);
+            } else if (isRange()) {
                 Position p(m_end.upstream());
                 if (p.node()->id() == ID_BR)
-                    pos = VisiblePosition(Position(p.node(), 0));
+                    pos = VisiblePosition(Position(p.node(), 0), UPSTREAM);
                 else
-                    pos = VisiblePosition(p);
+                    pos = VisiblePosition(p, UPSTREAM);
             }
             pos = nextLinePosition(pos, m_affinity, xPosForVerticalArrowNavigation(END, isRange()));
             break;
         }
         case LINE_BOUNDARY:
-            pos = endOfLine(VisiblePosition(m_end), m_affinity);
+            pos = endOfLine(VisiblePosition(m_end, m_affinity), UPSTREAM);
             break;
         case PARAGRAPH_BOUNDARY:
-            pos = endOfParagraph(VisiblePosition(m_end));
+            pos = endOfParagraph(VisiblePosition(m_end, m_affinity));
             break;
         case DOCUMENT_BOUNDARY:
-            pos = endOfDocument(VisiblePosition(m_end));
+            pos = endOfDocument(VisiblePosition(m_end, m_affinity));
             break;
     }
     return pos;
@@ -336,7 +324,7 @@ VisiblePosition Selection::modifyMovingRightForward(ETextGranularity granularity
 
 VisiblePosition Selection::modifyExtendingLeftBackward(ETextGranularity granularity)
 {
-    VisiblePosition pos(m_extent);
+    VisiblePosition pos(m_extent, m_affinity);
     switch (granularity) {
         case CHARACTER:
             pos = pos.previous();
@@ -351,10 +339,10 @@ VisiblePosition Selection::modifyExtendingLeftBackward(ETextGranularity granular
             pos = previousLinePosition(pos, m_affinity, xPosForVerticalArrowNavigation(EXTENT));
             break;
         case LINE_BOUNDARY:
-            pos = startOfLine(VisiblePosition(m_start), m_affinity);
+            pos = startOfLine(VisiblePosition(m_start, m_affinity), DOWNSTREAM);
             break;
         case PARAGRAPH_BOUNDARY:
-            pos = startOfParagraph(VisiblePosition(m_start));
+            pos = startOfParagraph(VisiblePosition(m_start, m_affinity));
             break;
         case DOCUMENT_BOUNDARY:
             pos = startOfDocument(pos);
@@ -369,27 +357,27 @@ VisiblePosition Selection::modifyMovingLeftBackward(ETextGranularity granularity
     switch (granularity) {
         case CHARACTER:
             if (isRange()) 
-                pos = VisiblePosition(m_start);
+                pos = VisiblePosition(m_start, m_affinity);
             else
-                pos = VisiblePosition(m_extent).previous();
+                pos = VisiblePosition(m_extent, m_affinity).previous();
             break;
         case WORD:
-            pos = previousWordPosition(VisiblePosition(m_extent));
+            pos = previousWordPosition(VisiblePosition(m_extent, m_affinity));
             break;
         case PARAGRAPH:
-            pos = previousParagraphPosition(VisiblePosition(m_start), m_affinity, xPosForVerticalArrowNavigation(START, isRange()));
+            pos = previousParagraphPosition(VisiblePosition(m_start, m_affinity), m_affinity, xPosForVerticalArrowNavigation(START, isRange()));
             break;
         case LINE:
-            pos = previousLinePosition(VisiblePosition(m_start), m_affinity, xPosForVerticalArrowNavigation(START, isRange()));
+            pos = previousLinePosition(VisiblePosition(m_start, m_affinity), m_affinity, xPosForVerticalArrowNavigation(START, isRange()));
             break;
         case LINE_BOUNDARY:
-            pos = startOfLine(VisiblePosition(m_start), m_affinity);
+            pos = startOfLine(VisiblePosition(m_start, m_affinity), DOWNSTREAM);
             break;
         case PARAGRAPH_BOUNDARY:
-            pos = startOfParagraph(VisiblePosition(m_start));
+            pos = startOfParagraph(VisiblePosition(m_start, m_affinity));
             break;
         case DOCUMENT_BOUNDARY:
-            pos = startOfDocument(VisiblePosition(m_start));
+            pos = startOfDocument(VisiblePosition(m_start, m_affinity));
             break;
     }
     return pos;
@@ -400,7 +388,6 @@ bool Selection::modify(EAlter alter, EDirection dir, ETextGranularity granularit
     setModifyBias(alter, dir);
 
     VisiblePosition pos;
-
     switch (dir) {
         // EDIT FIXME: These need to handle bidi
         case RIGHT:
@@ -422,20 +409,16 @@ bool Selection::modify(EAlter alter, EDirection dir, ETextGranularity granularit
     if (pos.isNull())
         return false;
 
-    // Save and restore affinity here before calling setAffinity. 
-    // The moveTo() and setExtent() calls reset affinity and this 
-    // is undesirable here.
-    EAffinity savedAffinity = m_affinity;
     switch (alter) {
         case MOVE:
-            moveTo(pos.deepEquivalent());
+            moveTo(pos);
             break;
         case EXTEND:
-            setExtent(pos.deepEquivalent());
+            setExtent(pos);
             break;
     }
-    m_affinity = savedAffinity;
-    modifyAffinity(alter, dir, granularity);
+
+    setNeedsLayout();
 
     return true;
 }
@@ -470,15 +453,14 @@ bool Selection::modify(EAlter alter, int verticalDistance)
     setModifyBias(alter, up ? BACKWARD : FORWARD);
 
     VisiblePosition pos;
-    int xPos = 0; /* initialized only to make compiler happy */
-
+    int xPos = 0;
     switch (alter) {
         case MOVE:
-            pos = VisiblePosition(up ? m_start : m_end);
+            pos = VisiblePosition(up ? m_start : m_end, m_affinity);
             xPos = xPosForVerticalArrowNavigation(up ? START : END, isRange());
             break;
         case EXTEND:
-            pos = VisiblePosition(m_extent);
+            pos = VisiblePosition(m_extent, m_affinity);
             xPos = xPosForVerticalArrowNavigation(EXTENT);
             break;
     }
@@ -491,7 +473,6 @@ bool Selection::modify(EAlter alter, int verticalDistance)
     int lastY = startY;
 
     VisiblePosition result;
-
     VisiblePosition next;
     for (VisiblePosition p = pos; ; p = next) {
         next = (up ? previousLinePosition : nextLinePosition)(p, m_affinity, xPos);
@@ -515,10 +496,10 @@ bool Selection::modify(EAlter alter, int verticalDistance)
 
     switch (alter) {
         case MOVE:
-            moveTo(result.deepEquivalent());
+            moveTo(result);
             break;
         case EXTEND:
-            setExtent(result.deepEquivalent());
+            setExtent(result);
             break;
     }
 
@@ -563,10 +544,10 @@ int Selection::xPosForVerticalArrowNavigation(EPositionType type, bool recalc) c
     if (recalc || part->xPosForVerticalArrowNavigation() == KHTMLPart::NoXPosForVerticalArrowNavigation) {
         switch (m_affinity) {
             case DOWNSTREAM:
-                pos = VisiblePosition(pos).downstreamDeepEquivalent();
+                pos = VisiblePosition(pos, m_affinity).downstreamDeepEquivalent();
                 break;
             case UPSTREAM:
-                pos = VisiblePosition(pos).deepEquivalent();
+                pos = VisiblePosition(pos, m_affinity).deepEquivalent();
                 break;
         }
         x = pos.node()->renderer()->caretRect(pos.offset(), m_affinity).x();
@@ -580,29 +561,55 @@ int Selection::xPosForVerticalArrowNavigation(EPositionType type, bool recalc) c
 
 void Selection::clear()
 {
-    m_affinity = UPSTREAM;
+    m_affinity = SEL_DEFAULT_AFFINITY;
     m_base.clear();
     m_extent.clear();
     validate();
 }
 
-void Selection::setBase(const Position &pos)
+void Selection::setBase(const VisiblePosition &pos)
 {
-    m_affinity = UPSTREAM;
+    m_affinity = pos.affinity();
+    m_base = pos.deepEquivalent();
+    validate();
+}
+
+void Selection::setExtent(const VisiblePosition &pos)
+{
+    // FIXME: Support extentAffinity
+    m_extent = pos.deepEquivalent();
+    validate();
+}
+
+void Selection::setBaseAndExtent(const VisiblePosition &base, const VisiblePosition &extent)
+{
+    // FIXME: Support extentAffinity
+    m_affinity = base.affinity();
+    m_base = base.deepEquivalent();
+    m_extent = extent.deepEquivalent();
+    validate();
+}
+
+
+void Selection::setBase(const Position &pos, EAffinity baseAffinity)
+{
+    m_affinity = baseAffinity;
     m_base = pos;
     validate();
 }
 
-void Selection::setExtent(const Position &pos)
+void Selection::setExtent(const Position &pos, EAffinity extentAffinity)
 {
-    m_affinity = UPSTREAM;
+    // FIXME: Support extentAffinity for real
+    m_affinity = extentAffinity;
     m_extent = pos;
     validate();
 }
 
-void Selection::setBaseAndExtent(const Position &base, const Position &extent)
+void Selection::setBaseAndExtent(const Position &base, EAffinity baseAffinity, const Position &extent, EAffinity extentAffinity)
 {
-    m_affinity = UPSTREAM;
+    // FIXME: extentAffinity
+    m_affinity = baseAffinity;
     m_base = base;
     m_extent = extent;
     validate();
@@ -691,10 +698,10 @@ void Selection::layout()
         Position pos = m_start;
         switch (m_affinity) {
             case DOWNSTREAM:
-                pos = VisiblePosition(m_start).downstreamDeepEquivalent();
+                pos = VisiblePosition(m_start, m_affinity).downstreamDeepEquivalent();
                 break;
             case UPSTREAM:
-                pos = VisiblePosition(m_start).deepEquivalent();
+                pos = VisiblePosition(m_start, m_affinity).deepEquivalent();
                 break;
         }
         if (pos.isNotNull()) {
@@ -808,14 +815,14 @@ void Selection::validate(ETextGranularity granularity)
     if (m_base.isNotNull()) {
         m_base.node()->getDocument()->updateLayout();
         updatedLayout = true;
-        m_base = VisiblePosition(m_base).deepEquivalent();
+        m_base = VisiblePosition(m_base, m_affinity).deepEquivalent();
         if (baseAndExtentEqual)
             m_extent = m_base;
     }
     if (m_extent.isNotNull() && !baseAndExtentEqual) {
         if (!updatedLayout)
             m_extent.node()->getDocument()->updateLayout();
-        m_extent = VisiblePosition(m_extent).deepEquivalent();
+        m_extent = VisiblePosition(m_extent, m_affinity).deepEquivalent();
     }
 
     // Make sure we do not have a dangling start or end
@@ -870,50 +877,50 @@ void Selection::validate(ETextGranularity granularity)
                 // Another exception is when double-clicking at the start of a line.
                 // However, the end of the document is an exception and always selects the previous word even though it could be
                 // both the start of a line and after a hard line break.
-                VisiblePosition pos(m_base);
+                VisiblePosition pos(m_base, m_affinity);
                 EWordSide side = LeftWordIfOnBoundary;
                 if ((isEndOfParagraph(pos) || isStartOfLine(pos, m_affinity)) && !isEndOfDocument(pos))
                     side = RightWordIfOnBoundary;
                 m_start = startOfWord(pos, side).deepEquivalent();
                 m_end = endOfWord(pos, side).deepEquivalent();
             } else if (m_baseIsStart) {
-                m_start = startOfWord(VisiblePosition(m_base)).deepEquivalent();
-                m_end = endOfWord(VisiblePosition(m_extent)).deepEquivalent();
+                m_start = startOfWord(VisiblePosition(m_base, m_affinity)).deepEquivalent();
+                m_end = endOfWord(VisiblePosition(m_extent, m_affinity)).deepEquivalent();
             } else {
-                m_start = startOfWord(VisiblePosition(m_extent)).deepEquivalent();
-                m_end = endOfWord(VisiblePosition(m_base)).deepEquivalent();
+                m_start = startOfWord(VisiblePosition(m_extent, m_affinity)).deepEquivalent();
+                m_end = endOfWord(VisiblePosition(m_base, m_affinity)).deepEquivalent();
             }
             break;
         case LINE:
         case LINE_BOUNDARY:
             if (m_baseIsStart) {
-                m_start = startOfLine(VisiblePosition(m_base), m_affinity).deepEquivalent();
-                m_end = endOfLine(VisiblePosition(m_extent), m_affinity, IncludeLineBreak).deepEquivalent();
+                m_start = startOfLine(VisiblePosition(m_base, m_affinity), m_affinity).deepEquivalent();
+                m_end = endOfLine(VisiblePosition(m_extent, m_affinity), m_affinity, IncludeLineBreak).deepEquivalent();
             } else {
-                m_start = startOfLine(VisiblePosition(m_extent), m_affinity).deepEquivalent();
-                m_end = endOfLine(VisiblePosition(m_base), m_affinity, IncludeLineBreak).deepEquivalent();
+                m_start = startOfLine(VisiblePosition(m_extent, m_affinity), m_affinity).deepEquivalent();
+                m_end = endOfLine(VisiblePosition(m_base, m_affinity), m_affinity, IncludeLineBreak).deepEquivalent();
             }
             break;
         case PARAGRAPH:
             if (m_baseIsStart) {
-                m_start = startOfParagraph(VisiblePosition(m_base)).deepEquivalent();
-                m_end = endOfParagraph(VisiblePosition(m_extent), IncludeLineBreak).deepEquivalent();
+                m_start = startOfParagraph(VisiblePosition(m_base, m_affinity)).deepEquivalent();
+                m_end = endOfParagraph(VisiblePosition(m_extent, m_affinity), IncludeLineBreak).deepEquivalent();
             } else {
-                m_start = startOfParagraph(VisiblePosition(m_extent)).deepEquivalent();
-                m_end = endOfParagraph(VisiblePosition(m_base), IncludeLineBreak).deepEquivalent();
+                m_start = startOfParagraph(VisiblePosition(m_extent, m_affinity)).deepEquivalent();
+                m_end = endOfParagraph(VisiblePosition(m_base, m_affinity), IncludeLineBreak).deepEquivalent();
             }
             break;
         case DOCUMENT_BOUNDARY:
-            m_start = startOfDocument(VisiblePosition(m_base)).deepEquivalent();
-            m_end = endOfDocument(VisiblePosition(m_base)).deepEquivalent();
+            m_start = startOfDocument(VisiblePosition(m_base, m_affinity)).deepEquivalent();
+            m_end = endOfDocument(VisiblePosition(m_base, m_affinity)).deepEquivalent();
             break;
         case PARAGRAPH_BOUNDARY:
             if (m_baseIsStart) {
-                m_start = startOfParagraph(VisiblePosition(m_base)).deepEquivalent();
-                m_end = endOfParagraph(VisiblePosition(m_extent)).deepEquivalent();
+                m_start = startOfParagraph(VisiblePosition(m_base, m_affinity)).deepEquivalent();
+                m_end = endOfParagraph(VisiblePosition(m_extent, m_affinity)).deepEquivalent();
             } else {
-                m_start = startOfParagraph(VisiblePosition(m_extent)).deepEquivalent();
-                m_end = endOfParagraph(VisiblePosition(m_base)).deepEquivalent();
+                m_start = startOfParagraph(VisiblePosition(m_extent, m_affinity)).deepEquivalent();
+                m_end = endOfParagraph(VisiblePosition(m_base, m_affinity)).deepEquivalent();
             }
             break;
     }
index b6c35827b3875681d58bc3460258fe0e23d45259..e14de864c3e809bf93feb7b6cdfabf71179dbad5 100644 (file)
@@ -44,33 +44,40 @@ public:
     enum EState { NONE, CARET, RANGE };
     enum EAlter { MOVE, EXTEND };
     enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT };
+#define SEL_DEFAULT_AFFINITY DOWNSTREAM
+
+// FIXME: Implement as "caller does not know whether it is OK to be upstream,
+// but that would be the desired affinity"
+#define SEL_PREFER_UPSTREAM_AFFINITY DOWNSTREAM
 
     typedef DOM::Range Range;
     typedef DOM::Position Position;
 
     Selection();
-    Selection(const Range &);
+    Selection(const Range &, EAffinity baseAffinity, EAffinity extentAffinity);
     Selection(const VisiblePosition &);
     Selection(const VisiblePosition &, const VisiblePosition &);
-    Selection(const Position &);
-    Selection(const Position &, const Position &);
+    Selection(const Position &, EAffinity affinity);
+    Selection(const Position &, EAffinity, const Position &, EAffinity);
     Selection(const Selection &);
 
     Selection &operator=(const Selection &o);
-    Selection &operator=(const Range &r) { moveTo(r); return *this; }
     Selection &operator=(const VisiblePosition &r) { moveTo(r); return *this; }
-    Selection &operator=(const Position &r) { moveTo(r); return *this; }
-    
-    void moveTo(const Range &);
+
+    void moveTo(const Range &, EAffinity baseAffinity, EAffinity extentAffinity);
     void moveTo(const VisiblePosition &);
     void moveTo(const VisiblePosition &, const VisiblePosition &);
-    void moveTo(const Position &);
-    void moveTo(const Position &, const Position &);
+    void moveTo(const Position &, EAffinity);
+    void moveTo(const Position &, EAffinity, const Position &, EAffinity);
     void moveTo(const Selection &);
 
     EState state() const { return m_state; }
-    EAffinity affinity() const { return m_affinity; }
-    void setAffinity(EAffinity);
+    
+    // FIXME: These should support separate baseAffinity and extentAffinity
+    EAffinity startAffinity() const { return m_affinity; }
+    EAffinity endAffinity() const { return m_affinity; }
+    EAffinity baseAffinity() const { return m_affinity; }
+    EAffinity extentAffinity() const { return m_affinity; }
 
     bool modify(EAlter, EDirection, ETextGranularity);
     bool modify(EAlter, int verticalDistance);
@@ -81,9 +88,9 @@ public:
     void setExtent(const VisiblePosition &);
     void setBaseAndExtent(const VisiblePosition &base, const VisiblePosition &extent);
 
-    void setBase(const Position &pos);
-    void setExtent(const Position &pos);
-    void setBaseAndExtent(const Position &base, const Position &extent);
+    void setBase(const Position &pos, EAffinity affinity);
+    void setExtent(const Position &pos, EAffinity affinity);
+    void setBaseAndExtent(const Position &base, EAffinity baseAffinity, const Position &extent, EAffinity extentAffinity);
 
     Position base() const { return m_base; }
     Position extent() const { return m_extent; }
@@ -116,7 +123,7 @@ public:
 private:
     enum EPositionType { START, END, BASE, EXTENT };
 
-    void init();
+    void init(EAffinity affinity);
     void validate(ETextGranularity granularity = CHARACTER);
 
     VisiblePosition modifyExtendingRightForward(ETextGranularity);
@@ -124,8 +131,6 @@ private:
     VisiblePosition modifyExtendingLeftBackward(ETextGranularity);
     VisiblePosition modifyMovingLeftBackward(ETextGranularity);
 
-    void modifyAffinity(EAlter, EDirection, ETextGranularity);
-
     void layout();
     void needsCaretRepaint();
     void paintCaret(QPainter *p, const QRect &rect);
@@ -152,7 +157,7 @@ private:
 
 inline bool operator==(const Selection &a, const Selection &b)
 {
-    return a.start() == b.start() && a.end() == b.end() && a.affinity() == b.affinity();
+    return a.start() == b.start() && a.end() == b.end() && a.startAffinity() == b.startAffinity();
 }
 
 inline bool operator!=(const Selection &a, const Selection &b)
index 7054f6b71cebe87470c9cba6582ef6924ebdf24a..6254b45055e7d7658e0784b8bde6f17fefb26cde 100644 (file)
@@ -324,12 +324,38 @@ void EditCommandPtr::setStartingSelection(const Selection &s) const
     get()->setStartingSelection(s);
 }
 
+void EditCommandPtr::setStartingSelection(const VisiblePosition &p) const
+{
+    IF_IMPL_NULL_RETURN;
+    get()->setStartingSelection(p);
+}
+
+void EditCommandPtr::setStartingSelection(const Position &p, EAffinity affinity) const
+{
+    IF_IMPL_NULL_RETURN;
+    Selection s = Selection(p, affinity);
+    get()->setStartingSelection(s);
+}
+
 void EditCommandPtr::setEndingSelection(const Selection &s) const
 {
     IF_IMPL_NULL_RETURN;
     get()->setEndingSelection(s);
 }
 
+void EditCommandPtr::setEndingSelection(const VisiblePosition &p) const
+{
+    IF_IMPL_NULL_RETURN;
+    get()->setStartingSelection(p);
+}
+
+void EditCommandPtr::setEndingSelection(const Position &p, EAffinity affinity) const
+{
+    IF_IMPL_NULL_RETURN;
+    Selection s = Selection(p, affinity);
+    get()->setEndingSelection(s);
+}
+
 CSSMutableStyleDeclarationImpl *EditCommandPtr::typingStyle() const
 {
     IF_IMPL_NULL_RETURN_ARG(0);
@@ -567,12 +593,40 @@ void EditCommand::setStartingSelection(const Selection &s)
         cmd->m_startingSelection = s;
 }
 
+void EditCommand::setStartingSelection(const VisiblePosition &p)
+{
+    Selection s = Selection(p);
+    for (EditCommand *cmd = this; cmd; cmd = cmd->m_parent)
+        cmd->m_startingSelection = s;
+}
+
+void EditCommand::setStartingSelection(const Position &p, EAffinity affinity)
+{
+    Selection s = Selection(p, affinity);
+    for (EditCommand *cmd = this; cmd; cmd = cmd->m_parent)
+        cmd->m_startingSelection = s;
+}
+
 void EditCommand::setEndingSelection(const Selection &s)
 {
     for (EditCommand *cmd = this; cmd; cmd = cmd->m_parent)
         cmd->m_endingSelection = s;
 }
 
+void EditCommand::setEndingSelection(const VisiblePosition &p)
+{
+    Selection s = Selection(p);
+    for (EditCommand *cmd = this; cmd; cmd = cmd->m_parent)
+        cmd->m_endingSelection = s;
+}
+
+void EditCommand::setEndingSelection(const Position &p, EAffinity affinity)
+{
+    Selection s = Selection(p, affinity);
+    for (EditCommand *cmd = this; cmd; cmd = cmd->m_parent)
+        cmd->m_endingSelection = s;
+}
+
 void EditCommand::assignTypingStyle(CSSMutableStyleDeclarationImpl *style)
 {
     if (m_typingStyle == style)
@@ -950,7 +1004,7 @@ void CompositeEditCommand::deleteInsignificantText(const Position &start, const
 
 void CompositeEditCommand::deleteInsignificantTextDownstream(const DOM::Position &pos)
 {
-    Position end = VisiblePosition(pos).next().deepEquivalent().downstream(StayInBlock);
+    Position end = VisiblePosition(pos, VP_DEFAULT_AFFINITY).next().deepEquivalent().downstream(StayInBlock);
     deleteInsignificantText(pos, end);
 }
 
@@ -1012,7 +1066,7 @@ void CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessary(const Posi
     if (pos.isNull())
         return;
         
-    VisiblePosition visiblePos(pos);
+    VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY);
     VisiblePosition visibleParagraphStart(startOfParagraph(visiblePos));
     VisiblePosition visibleParagraphEnd(endOfParagraph(visiblePos, IncludeLineBreak));
     Position paragraphStart = visibleParagraphStart.deepEquivalent().upstream(StayInBlock);
@@ -1759,7 +1813,7 @@ bool ApplyStyleCommand::splitTextAtStartIfNeeded(const Position &start, const Po
         long endOffsetAdjustment = start.node() == end.node() ? start.offset() : 0;
         TextImpl *text = static_cast<TextImpl *>(start.node());
         splitTextNode(text, start.offset());
-        setEndingSelection(Selection(Position(start.node(), 0), Position(end.node(), end.offset() - endOffsetAdjustment)));
+        setEndingSelection(Selection(Position(start.node(), 0), SEL_DEFAULT_AFFINITY, Position(end.node(), end.offset() - endOffsetAdjustment), SEL_DEFAULT_AFFINITY));
         return true;
     }
     return false;
@@ -1775,7 +1829,7 @@ bool ApplyStyleCommand::splitTextAtEndIfNeeded(const Position &start, const Posi
         ASSERT(prevNode);
         NodeImpl *startNode = start.node() == end.node() ? prevNode : start.node();
         ASSERT(startNode);
-        setEndingSelection(Selection(Position(startNode, start.offset()), Position(prevNode, prevNode->caretMaxOffset())));
+        setEndingSelection(Selection(Position(startNode, start.offset()), SEL_DEFAULT_AFFINITY, Position(prevNode, prevNode->caretMaxOffset()), SEL_DEFAULT_AFFINITY));
         return true;
     }
     return false;
@@ -1788,7 +1842,7 @@ bool ApplyStyleCommand::splitTextElementAtStartIfNeeded(const Position &start, c
         TextImpl *text = static_cast<TextImpl *>(start.node());
         splitTextNodeContainingElement(text, start.offset());
 
-        setEndingSelection(Selection(Position(start.node()->parentNode(), start.node()->nodeIndex()), Position(end.node(), end.offset() - endOffsetAdjustment)));
+        setEndingSelection(Selection(Position(start.node()->parentNode(), start.node()->nodeIndex()), SEL_DEFAULT_AFFINITY, Position(end.node(), end.offset() - endOffsetAdjustment), SEL_DEFAULT_AFFINITY));
         return true;
     }
     return false;
@@ -1804,7 +1858,7 @@ bool ApplyStyleCommand::splitTextElementAtEndIfNeeded(const Position &start, con
         ASSERT(prevNode);
         NodeImpl *startNode = start.node() == end.node() ? prevNode : start.node();
         ASSERT(startNode);
-        setEndingSelection(Selection(Position(startNode, start.offset()), Position(prevNode->parent(), prevNode->nodeIndex() + 1)));
+        setEndingSelection(Selection(Position(startNode, start.offset()), SEL_DEFAULT_AFFINITY, Position(prevNode->parent(), prevNode->nodeIndex() + 1), SEL_DEFAULT_AFFINITY));
         return true;
     }
     return false;
@@ -1879,8 +1933,8 @@ bool ApplyStyleCommand::mergeStartWithPreviousIfIdentical(const Position &start,
         long startOffsetAdjustment = startChild->nodeIndex();
         long endOffsetAdjustment = startNode == end.node() ? startOffsetAdjustment : 0;
 
-        setEndingSelection(Selection(Position(startNode, startOffsetAdjustment),
-                                     Position(end.node(), end.offset() + endOffsetAdjustment))); 
+        setEndingSelection(Selection(Position(startNode, startOffsetAdjustment), SEL_DEFAULT_AFFINITY,
+                                     Position(end.node(), end.offset() + endOffsetAdjustment), SEL_DEFAULT_AFFINITY)); 
 
         return true;
     }
@@ -1922,8 +1976,8 @@ bool ApplyStyleCommand::mergeEndWithNextIfIdentical(const Position &start, const
 
         int endOffset = nextChild ? nextChild->nodeIndex() : nextElement->childNodes()->length();
 
-        setEndingSelection(Selection(Position(startNode, start.offset()), 
-                                     Position(nextElement, endOffset)));
+        setEndingSelection(Selection(Position(startNode, start.offset()), SEL_DEFAULT_AFFINITY, 
+                                     Position(nextElement, endOffset), SEL_DEFAULT_AFFINITY));
         return true;
     }
 
@@ -2099,7 +2153,7 @@ void ApplyStyleCommand::joinChildTextNodes(NodeImpl *node, const Position &start
         }
     }
 
-    setEndingSelection(Selection(newStart, newEnd));
+    setEndingSelection(Selection(newStart, SEL_DEFAULT_AFFINITY, newEnd, SEL_DEFAULT_AFFINITY));
 }
 
 //------------------------------------------------------------------------------------------
@@ -2191,7 +2245,7 @@ void DeleteSelectionCommand::initializePositionData()
     m_leadingWhitespace = m_upstreamStart.leadingWhitespacePosition();
     bool hasLeadingWhitespaceBeforeAdjustment = m_leadingWhitespace.isNotNull();
     if (m_smartDelete && hasLeadingWhitespaceBeforeAdjustment) {
-        Position pos = VisiblePosition(start).previous().deepEquivalent();
+        Position pos = VisiblePosition(start, m_selectionToDelete.startAffinity()).previous().deepEquivalent();
         // Expand out one character upstream for smart delete and recalculate
         // positions based on this change.
         m_upstreamStart = pos.upstream(StayInBlock);
@@ -2204,7 +2258,7 @@ void DeleteSelectionCommand::initializePositionData()
     if (m_smartDelete && !hasLeadingWhitespaceBeforeAdjustment && m_trailingWhitespace.isNotNull()) {
         // Expand out one character downstream for smart delete and recalculate
         // positions based on this change.
-        Position pos = VisiblePosition(end).next().deepEquivalent();
+        Position pos = VisiblePosition(end, m_selectionToDelete.endAffinity()).next().deepEquivalent();
         m_upstreamEnd = pos.upstream(StayInBlock);
         m_downstreamEnd = pos.downstream(StayInBlock);
         m_trailingWhitespace = m_downstreamEnd.trailingWhitespacePosition();
@@ -2225,7 +2279,7 @@ void DeleteSelectionCommand::initializePositionData()
     // Handle detecting if the line containing the selection end is itself fully selected.
     // This is one of the tests that determines if block merging of content needs to be done.
     //
-    VisiblePosition visibleEnd(end);
+    VisiblePosition visibleEnd(end, m_selectionToDelete.endAffinity());
     if (isFirstVisiblePositionInParagraph(visibleEnd) || isLastVisiblePositionInParagraph(visibleEnd)) {
         Position previousLineStart = previousLinePosition(visibleEnd, DOWNSTREAM, 0).deepEquivalent();
         if (previousLineStart.isNull() || RangeImpl::compareBoundaryPoints(previousLineStart, m_downstreamStart) >= 0)
@@ -2330,7 +2384,7 @@ void DeleteSelectionCommand::setStartNode(NodeImpl *node)
 void DeleteSelectionCommand::handleGeneralDelete()
 {
     int startOffset = m_upstreamStart.offset();
-    VisiblePosition visibleEnd = VisiblePosition(m_downstreamEnd);
+    VisiblePosition visibleEnd = VisiblePosition(m_downstreamEnd, m_selectionToDelete.endAffinity());
     bool endAtEndOfBlock = isEndOfBlock(visibleEnd);
 
     // Handle some special cases where the selection begins and ends on specific visible units.
@@ -2356,7 +2410,7 @@ void DeleteSelectionCommand::handleGeneralDelete()
         // Don't delete the BR element
         setStartNode(m_startNode->traverseNextNode());
     }
-    else if (m_startBlock != m_endBlock && isStartOfBlock(VisiblePosition(m_upstreamStart))) {
+    else if (m_startBlock != m_endBlock && isStartOfBlock(VisiblePosition(m_upstreamStart, m_selectionToDelete.startAffinity()))) {
         if (!isStartOfBlock(visibleEnd) && endAtEndOfBlock) {
             // Delete all the children of the block, but not the block itself.
             setStartNode(m_startBlock->firstChild());
@@ -2604,8 +2658,8 @@ void DeleteSelectionCommand::calculateTypingStyleAfterDelete(bool insertedPlaceh
         // of the preceding line and retains it even if you click away, click back, and
         // then start typing. In this case, the typing style is applied right now, and
         // is not retained until the next typing action.
-        Position pastPlaceholder = endOfParagraph(VisiblePosition(m_endingPosition)).deepEquivalent();
-        setEndingSelection(Selection(m_endingPosition, pastPlaceholder));
+        Position pastPlaceholder = endOfParagraph(VisiblePosition(m_endingPosition, m_selectionToDelete.endAffinity())).deepEquivalent();
+        setEndingSelection(Selection(m_endingPosition, m_selectionToDelete.endAffinity(), pastPlaceholder, DOWNSTREAM));
         applyStyle(m_typingStyle, EditActionUnspecified);
         m_typingStyle->deref();
         m_typingStyle = 0;
@@ -2655,6 +2709,10 @@ void DeleteSelectionCommand::doApply()
     if (!m_selectionToDelete.isRange())
         return;
 
+    // save this to later make the selection with
+    EAffinity affinity = m_selectionToDelete.startAffinity();
+    
+    // set up our state
     initializePositionData();
 
     if (!m_startBlock || !m_endBlock) {
@@ -2687,7 +2745,7 @@ void DeleteSelectionCommand::doApply()
     bool insertedPlaceholder = insertBlockPlaceholderIfNeeded(m_endingPosition.node());
     calculateTypingStyleAfterDelete(insertedPlaceholder);
     debugPosition("endingPosition   ", m_endingPosition);
-    setEndingSelection(m_endingPosition);
+    setEndingSelection(Selection(m_endingPosition, affinity));
     clearTransientState();
     rebalanceWhitespace();
 }
@@ -2797,7 +2855,7 @@ void InsertLineBreakCommand::doApply()
     Position pos(selection.start().upstream(StayInBlock));
     bool atStart = pos.offset() <= pos.node()->caretMinOffset();
     bool atEnd = pos.offset() >= pos.node()->caretMaxOffset();
-    bool atEndOfBlock = isLastVisiblePositionInBlock(VisiblePosition(pos));
+    bool atEndOfBlock = isLastVisiblePositionInBlock(VisiblePosition(pos, selection.startAffinity()));
     
     if (atEndOfBlock) {
         LOG(Editing, "input newline case 1");
@@ -2814,13 +2872,13 @@ void InsertLineBreakCommand::doApply()
             bool hasTrailingBR = next && next->id() == ID_BR && pos.node()->enclosingBlockFlowElement() == next->enclosingBlockFlowElement();
             insertNodeAfterPosition(nodeToInsert, pos);
             if (hasTrailingBR) {
-                setEndingSelection(Position(next, 0));
+                setEndingSelection(Selection(Position(next, 0), DOWNSTREAM));
             }
             else if (!document()->inStrictMode()) {
                 // Insert an "extra" BR at the end of the block. 
                 ElementImpl *extraBreakNode = createBreakElement(document());
                 insertNodeAfter(extraBreakNode, nodeToInsert);
-                setEndingSelection(Position(extraBreakNode, 0));
+                setEndingSelection(Position(extraBreakNode, 0), DOWNSTREAM);
             }
         }
     }
@@ -2829,7 +2887,7 @@ void InsertLineBreakCommand::doApply()
         // Insert node before downstream position, and place caret there as well. 
         Position endingPosition = pos.downstream(StayInBlock);
         insertNodeBeforePosition(nodeToInsert, endingPosition);
-        setEndingSelection(endingPosition);
+        setEndingSelection(endingPosition, DOWNSTREAM);
     }
     else if (atEnd) {
         LOG(Editing, "input newline case 3");
@@ -2837,7 +2895,7 @@ void InsertLineBreakCommand::doApply()
         // of the current position, reckoned before inserting the BR in between.
         Position endingPosition = pos.downstream(StayInBlock);
         insertNodeAfterPosition(nodeToInsert, pos);
-        setEndingSelection(endingPosition);
+        setEndingSelection(endingPosition, DOWNSTREAM);
     }
     else {
         // Split a text node
@@ -2861,7 +2919,7 @@ void InsertLineBreakCommand::doApply()
             insertTextIntoNode(textNode, 0, nonBreakingSpaceString());
         }
         
-        setEndingSelection(endingPosition);
+        setEndingSelection(endingPosition, DOWNSTREAM);
     }
 
     // Handle the case where there is a typing style.
@@ -2877,7 +2935,7 @@ void InsertLineBreakCommand::doApply()
         int exception;
         rangeAroundNode->selectNode(nodeToInsert, exception);
 
-        setEndingSelection(Selection(rangeAroundNode));
+        setEndingSelection(Selection(rangeAroundNode, DOWNSTREAM, UPSTREAM));
         applyStyle(typingStyle);
 
         setEndingSelection(selectionBeforeStyle);
@@ -3002,6 +3060,7 @@ void InsertParagraphSeparatorCommand::doApply()
     // moving the selection downstream so it is in the ending block (if that block is
     // still around, that is).
     Position pos = selection.start();
+    EAffinity affinity = selection.startAffinity();
         
     if (selection.isRange()) {
         NodeImpl *startBlockBeforeDelete = selection.start().node()->enclosingBlockFlowElement();
@@ -3011,12 +3070,13 @@ void InsertParagraphSeparatorCommand::doApply()
         deleteSelection(false, false);
         if (doneAfterDelete) {
             document()->updateLayout();
-            setEndingSelection(endingSelection().start().downstream());
+            setEndingSelection(endingSelection().start().downstream(), DOWNSTREAM);
             rebalanceWhitespace();
             applyStyleAfterInsertion();
             return;
         }
         pos = endingSelection().start();
+        affinity = endingSelection().startAffinity();
     }
 
     calculateStyleBeforeInsertion(pos);
@@ -3027,7 +3087,7 @@ void InsertParagraphSeparatorCommand::doApply()
     if (!startBlock || !startBlock->parentNode())
         return;
 
-    VisiblePosition visiblePos(pos);
+    VisiblePosition visiblePos(pos, affinity);
     bool isFirstInBlock = isFirstVisiblePositionInBlock(visiblePos);
     bool isLastInBlock = isLastVisiblePositionInBlock(visiblePos);
     bool startBlockIsRoot = startBlock == startBlock->rootEditableElement();
@@ -3049,7 +3109,7 @@ void InsertParagraphSeparatorCommand::doApply()
             insertNodeAfter(blockToInsert, startBlock);
         }
         insertBlockPlaceholder(blockToInsert);
-        setEndingSelection(Position(blockToInsert, 0));
+        setEndingSelection(Position(blockToInsert, 0), DOWNSTREAM);
         applyStyleAfterInsertion();
         return;
     }
@@ -3064,9 +3124,9 @@ void InsertParagraphSeparatorCommand::doApply()
         NodeImpl *refNode = isFirstInBlock && !startBlockIsRoot ? startBlock : pos.node();
         insertNodeBefore(blockToInsert, refNode);
         insertBlockPlaceholder(blockToInsert);
-        setEndingSelection(Position(blockToInsert, 0));
+        setEndingSelection(Position(blockToInsert, 0), DOWNSTREAM);
         applyStyleAfterInsertion();
-        setEndingSelection(pos);
+        setEndingSelection(pos, DOWNSTREAM);
         return;
     }
 
@@ -3079,7 +3139,7 @@ void InsertParagraphSeparatorCommand::doApply()
         NodeImpl *refNode = isLastInBlock && !startBlockIsRoot ? startBlock : pos.node();
         insertNodeAfter(blockToInsert, refNode);
         insertBlockPlaceholder(blockToInsert);
-        setEndingSelection(Position(blockToInsert, 0));
+        setEndingSelection(Position(blockToInsert, 0), DOWNSTREAM);
         applyStyleAfterInsertion();
         return;
     }
@@ -3184,7 +3244,7 @@ void InsertParagraphSeparatorCommand::doApply()
         }
     }
 
-    setEndingSelection(Position(blockToInsert, 0));
+    setEndingSelection(Position(blockToInsert, 0), DOWNSTREAM);
     rebalanceWhitespace();
     applyStyleAfterInsertion();
 }
@@ -3212,9 +3272,11 @@ void InsertParagraphSeparatorInQuotedContentCommand::doApply()
     
     // Delete the current selection.
     Position pos = selection.start();
+    EAffinity affinity = selection.startAffinity();
     if (selection.isRange()) {
         deleteSelection(false, false);
         pos = endingSelection().start().upstream();
+        affinity = endingSelection().startAffinity();
     }
     
     // Find the top-most blockquote from the start.
@@ -3238,7 +3300,7 @@ void InsertParagraphSeparatorInQuotedContentCommand::doApply()
     m_breakNode->ref();
     insertNodeAfter(m_breakNode, topBlockquote);
 
-    if (!isLastVisiblePositionInNode(VisiblePosition(pos), topBlockquote)) {
+    if (!isLastVisiblePositionInNode(VisiblePosition(pos, affinity), topBlockquote)) {
         // Split at pos if in the middle of a text node.
         if (startNode->isTextNode()) {
             TextImpl *textNode = static_cast<TextImpl *>(startNode);
@@ -3318,7 +3380,7 @@ void InsertParagraphSeparatorInQuotedContentCommand::doApply()
     }
     
     // Put the selection right before the break.
-    setEndingSelection(Position(m_breakNode, 0));
+    setEndingSelection(Position(m_breakNode, 0), DOWNSTREAM);
     rebalanceWhitespace();
 }
 
@@ -3378,7 +3440,7 @@ Position InsertTextCommand::prepareForTextInsertion(bool adjustDownstream)
 void InsertTextCommand::input(const DOMString &text, bool selectInsertedText)
 {
     Selection selection = endingSelection();
-    bool adjustDownstream = isFirstVisiblePositionOnLine(VisiblePosition(selection.start().downstream(StayInBlock)));
+    bool adjustDownstream = isFirstVisiblePositionOnLine(VisiblePosition(selection.start().downstream(StayInBlock), DOWNSTREAM));
 
     // Delete the current selection, or collapse whitespace, as needed
     if (selection.isRange())
@@ -3442,7 +3504,7 @@ void InsertTextCommand::input(const DOMString &text, bool selectInsertedText)
         m_charactersAdded += text.length();
     }
 
-    setEndingSelection(Selection(startPosition, endPosition));
+    setEndingSelection(Selection(startPosition, DOWNSTREAM, endPosition, SEL_DEFAULT_AFFINITY));
 
     // Handle the case where there is a typing style.
     // FIXME: Improve typing style.
@@ -3452,7 +3514,7 @@ void InsertTextCommand::input(const DOMString &text, bool selectInsertedText)
         applyStyle(typingStyle);
 
     if (!selectInsertedText)
-        setEndingSelection(endingSelection().end());
+        setEndingSelection(endingSelection().end(), endingSelection().endAffinity());
 }
 
 void InsertTextCommand::insertSpace(TextImpl *textNode, unsigned long offset)
@@ -3608,7 +3670,7 @@ void MoveSelectionCommand::doApply()
     if (!pos.node()->inDocument())
         pos = endingSelection().start();
 
-    setEndingSelection(pos);
+    setEndingSelection(pos, endingSelection().startAffinity());
     EditCommandPtr cmd(new ReplaceSelectionCommand(document(), m_fragment, true, m_smartMove));
     applyCommandToComposite(cmd);
 }
@@ -4092,6 +4154,7 @@ ReplaceSelectionCommand::ReplaceSelectionCommand(DocumentImpl *document, Documen
       m_fragment(fragment),
       m_firstNodeInserted(0),
       m_lastNodeInserted(0),
+      m_lastTopNodeInserted(0),
       m_selectReplacement(selectReplacement), 
       m_smartReplace(smartReplace)
 {
@@ -4103,39 +4166,44 @@ ReplaceSelectionCommand::~ReplaceSelectionCommand()
         m_firstNodeInserted->deref();
     if (m_lastNodeInserted)
         m_lastNodeInserted->deref();
+    if (m_lastTopNodeInserted)
+        m_lastTopNodeInserted->deref();
 }
 
 void ReplaceSelectionCommand::doApply()
 {
+    // collect information about the current selection, prior to deleting the selection
     Selection selection = endingSelection();
     ASSERT(selection.isCaretOrRange());
-    VisiblePosition visibleStart(selection.start());
-    VisiblePosition visibleEnd(selection.end());
+    VisiblePosition visibleStart(selection.start(), selection.startAffinity());
+    VisiblePosition visibleEnd(selection.end(), selection.endAffinity());
     bool startAtStartOfBlock = isFirstVisiblePositionInBlock(visibleStart);
     bool startAtEndOfBlock = isLastVisiblePositionInBlock(visibleStart);
     bool startAtBlockBoundary = startAtStartOfBlock || startAtEndOfBlock;
     NodeImpl *startBlock = selection.start().node()->enclosingBlockFlowElement();
     NodeImpl *endBlock = selection.end().node()->enclosingBlockFlowElement();
+
+    // decide whether to later merge content into the startBlock
     bool mergeStart = false;
     if (startBlock == startBlock->rootEditableElement() && startAtStartOfBlock && startAtEndOfBlock) {
-        // Empty document. Merge neither start nor end.
+        // empty document, so no merge
         mergeStart = false;
-    }
-    else {
+    } else {
+        // merge if current selection starts inside a paragraph, or there is only one block and no interchange newline to add
         mergeStart = !isStartOfParagraph(visibleStart) || (!m_fragment.hasInterchangeNewline() && !m_fragment.hasMoreThanOneBlock());
     }
     
+    // decide whether to later append nodes to the end
     bool moveNodesAfterEnd = !m_fragment.hasInterchangeNewline() && (startBlock != endBlock || m_fragment.hasMoreThanOneBlock());
     
     Position startPos = Position(selection.start().node()->enclosingBlockFlowElement(), 0);
     Position endPos; 
     EStayInBlock upstreamStayInBlock = StayInBlock;
 
-    // Delete the current selection, or collapse whitespace, as needed
+    // delete the current range selection, or insert paragraph for caret selection, as needed
     if (selection.isRange()) {
         deleteSelection(false, !(m_fragment.hasInterchangeNewline() || m_fragment.hasMoreThanOneBlock()));
-    }
-    else if (selection.isCaret() && !startAtBlockBoundary &&
+    } else if (selection.isCaret() && !startAtBlockBoundary &&
              !m_fragment.hasInterchangeNewline() && m_fragment.hasMoreThanOneBlock() && !isEndOfParagraph(visibleEnd)) {
         // The start and the end need to wind up in separate blocks.
         // Insert a paragraph separator to make that happen.
@@ -4143,64 +4211,72 @@ void ReplaceSelectionCommand::doApply()
         upstreamStayInBlock = DoNotStayInBlock;
     }
     
+    // calculate the start and end of the resulting selection
     selection = endingSelection();
-    if (startAtStartOfBlock && startBlock->inDocument())
+    if (startAtStartOfBlock && startBlock->inDocument()) {
         startPos = Position(startBlock, 0);
-    else if (startAtEndOfBlock)
+    } else if (startAtEndOfBlock) {
         startPos = selection.start().downstream(StayInBlock);
-    else
+    } else {
         startPos = selection.start().upstream(upstreamStayInBlock);
+    }
     endPos = selection.end().downstream(); 
     
-    // This command does not use any typing style that is set as a residual effect of
-    // a delete.
+    // replacement command does not use any typing style that is set as a residual effect of the pre-delete
     // FIXME: Improve typing style.
     // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
     KHTMLPart *part = document()->part();
     part->clearTypingStyle();
     setTypingStyle(0);
 
+    // done if there is nothing to add
     if (!m_fragment.firstChild())
         return;
     
-    // Now that we are about to add content, check to see if a placeholder element
-    // can be removed.
+    // now that we are about to add content, check whether a placeholder element can be removed
+    // if so, do it and update startPos and endPos
     NodeImpl *block = startPos.node()->enclosingBlockFlowElement();
     NodeImpl *placeholderBlock = 0;
     if (removeBlockPlaceholderIfNeeded(block)) {
         placeholderBlock = block;
         Position pos = Position(block, 0);
-        if (!endPos.node()->inDocument()) // endPos might have been in the placeholder just removed.
+        // endPos might have been in the placeholder just removed
+        if (!endPos.node()->inDocument())
             endPos = pos;
         startPos = pos;
     }
     
+    // check whether to "smart replace" needs to add leading and/or trailing space
     bool addLeadingSpace = false;
     bool addTrailingSpace = false;
     if (m_smartReplace) {
         addLeadingSpace = startPos.leadingWhitespacePosition().isNotNull();
         if (addLeadingSpace) {
-            QChar previousChar = VisiblePosition(startPos).previous().character();
+            QChar previousChar = VisiblePosition(startPos, VP_DEFAULT_AFFINITY).previous().character();
             if (!previousChar.isNull()) {
                 addLeadingSpace = !part->isCharacterSmartReplaceExempt(previousChar, true);
             }
         }
         addTrailingSpace = endPos.trailingWhitespacePosition().isNotNull();
         if (addTrailingSpace) {
-            QChar thisChar = VisiblePosition(endPos).character();
+            QChar thisChar = VisiblePosition(endPos, VP_DEFAULT_AFFINITY).character();
             if (!thisChar.isNull()) {
                 addTrailingSpace = !part->isCharacterSmartReplaceExempt(thisChar, false);
             }
         }
     }
-
-    // Merge content into the start block, if necessary.
+    
+    // There are five steps to adding the content: merge blocks at start, add remaining blocks,
+    // add "smart replace" space, handle trailing newline, clean up.
+    
+    // initially, we say the insertion point is the start of selection
     document()->updateLayout();
     Position insertionPos = startPos;
+
+    // step 1: merge content into the start block, if that is needed
     if (mergeStart) {
-        NodeImpl *node = m_fragment.mergeStartNode();
-        if (node) {
-            NodeImpl *refNode = node;
+        NodeImpl *refNode = m_fragment.mergeStartNode();
+        if (refNode) {
             NodeImpl *node = refNode ? refNode->nextSibling() : 0;
             insertNodeAtAndUpdateNodesInserted(refNode, startPos.node(), startPos.offset());
             while (node && !isProbablyBlock(node)) {
@@ -4210,6 +4286,8 @@ void ReplaceSelectionCommand::doApply()
                 node = next;
             }
         }
+        
+        // update insertion point to be at the end of the last block inserted
         if (m_lastNodeInserted) {
             document()->updateLayout();
             insertionPos = Position(m_lastNodeInserted, m_lastNodeInserted->caretMaxOffset());
@@ -4217,28 +4295,27 @@ void ReplaceSelectionCommand::doApply()
     }
 
     // prune empty nodes from fragment
+    // NOTE: why was this not done earlier, before the mergeStart?
     m_fragment.pruneEmptyNodes();
     
-    // Merge everything remaining.
-    NodeImpl *node = m_fragment.firstChild();
-    if (node) {
-        NodeImpl *refNode = node;
+    // step 2 : merge everything remaining in the fragment
+    if (m_fragment.firstChild()) {
+        NodeImpl *refNode = m_fragment.firstChild();
         NodeImpl *node = refNode ? refNode->nextSibling() : 0;
         NodeImpl *insertionBlock = insertionPos.node()->enclosingBlockFlowElement();
         bool insertionBlockIsBody = insertionBlock->id() == ID_BODY;
-        VisiblePosition visiblePos(insertionPos);
+        VisiblePosition visiblePos(insertionPos, DOWNSTREAM);
         if (!insertionBlockIsBody && isProbablyBlock(refNode) && isFirstVisiblePositionInBlock(visiblePos))
             insertNodeBeforeAndUpdateNodesInserted(refNode, insertionBlock);
         else if (!insertionBlockIsBody && isProbablyBlock(refNode) && isLastVisiblePositionInBlock(visiblePos)) {
             insertNodeAfterAndUpdateNodesInserted(refNode, insertionBlock);
-        }
-        else if (mergeStart && !isProbablyBlock(refNode)){
+        } else if (mergeStart && !isProbablyBlock(refNode)) {
             Position pos = insertionPos.downstream();
             insertNodeAtAndUpdateNodesInserted(refNode, pos.node(), pos.offset());
-        }
-        else {
+        } else {
             insertNodeAtAndUpdateNodesInserted(refNode, insertionPos.node(), insertionPos.offset());
         }
+        
         while (node) {
             NodeImpl *next = node->nextSibling();
             insertNodeAfterAndUpdateNodesInserted(node, refNode);
@@ -4249,7 +4326,7 @@ void ReplaceSelectionCommand::doApply()
         insertionPos = Position(m_lastNodeInserted, m_lastNodeInserted->caretMaxOffset());
     }
 
-    // Handle "smart replace" whitespace
+    // step 3 : handle "smart replace" whitespace
     if (addTrailingSpace && m_lastNodeInserted) {
         if (m_lastNodeInserted->isTextNode()) {
             TextImpl *text = static_cast<TextImpl *>(m_lastNodeInserted);
@@ -4262,6 +4339,7 @@ void ReplaceSelectionCommand::doApply()
             if (!m_firstNodeInserted)
                 m_firstNodeInserted = node;
             m_lastNodeInserted = node;
+            m_lastTopNodeInserted = node;
             insertionPos = Position(node, 1);
         }
     }
@@ -4270,26 +4348,24 @@ void ReplaceSelectionCommand::doApply()
         if (m_firstNodeInserted->isTextNode()) {
             TextImpl *text = static_cast<TextImpl *>(m_firstNodeInserted);
             insertTextIntoNode(text, 0, nonBreakingSpaceString());
-        }
-        else {
+        } else {
             NodeImpl *node = document()->createEditingTextNode(nonBreakingSpaceString());
             insertNodeBefore(node, m_firstNodeInserted);
         }
     }
 
-    // Handle trailing newline
+    // step 4 : handle trailing newline
     if (m_fragment.hasInterchangeNewline()) {
-        if (startBlock == endBlock && isEndOfDocument(VisiblePosition(insertionPos))) {
-            setEndingSelection(insertionPos);
+        if (startBlock == endBlock && !isProbablyBlock(m_lastTopNodeInserted) && !isProbablyBlock(m_lastTopNodeInserted)) {
+            setEndingSelection(insertionPos, DOWNSTREAM);
             insertParagraphSeparator();
             endPos = endingSelection().end().downstream();
         }
         completeHTMLReplacement(startPos, endPos);
-    }
-    else {
+    } else {
         if (m_lastNodeInserted && m_lastNodeInserted->id() == ID_BR && !document()->inStrictMode()) {
             document()->updateLayout();
-            VisiblePosition pos(Position(m_lastNodeInserted, 0));
+            VisiblePosition pos(Position(m_lastNodeInserted, 0), DOWNSTREAM);
             if (isLastVisiblePositionInBlock(pos)) {
                 NodeImpl *next = m_lastNodeInserted->traverseNextNode();
                 bool hasTrailingBR = next && next->id() == ID_BR && m_lastNodeInserted->enclosingBlockFlowElement() == next->enclosingBlockFlowElement();
@@ -4333,6 +4409,7 @@ void ReplaceSelectionCommand::doApply()
         completeHTMLReplacement();
     }
     
+    // step 5 : mop up
     if (placeholderBlock) {
         document()->updateLayout();
         if (!placeholderBlock->renderer() || placeholderBlock->renderer()->height() == 0)
@@ -4344,7 +4421,10 @@ void ReplaceSelectionCommand::completeHTMLReplacement(const Position &start, con
  {
     if (start.isNull() || !start.node()->inDocument() || end.isNull() || !end.node()->inDocument())
         return;
-    m_selectReplacement ? setEndingSelection(Selection(start, end)) : setEndingSelection(end);
+    if (m_selectReplacement)
+        setEndingSelection(Selection(start, SEL_DEFAULT_AFFINITY, end, SEL_DEFAULT_AFFINITY));
+    else
+        setEndingSelection(end, SEL_DEFAULT_AFFINITY);
     rebalanceWhitespace();
 }
 
@@ -4374,14 +4454,14 @@ void ReplaceSelectionCommand::completeHTMLReplacement()
     
     Position start(firstLeaf, firstLeaf->caretMinOffset());
     Position end(lastLeaf, lastLeaf->caretMaxOffset());
-    Selection replacementSelection(start, end);
+    Selection replacementSelection(start, SEL_DEFAULT_AFFINITY, end, SEL_DEFAULT_AFFINITY);
     if (m_selectReplacement) {
         // Select what was inserted.
         setEndingSelection(replacementSelection);
     } 
     else {
         // Place the cursor after what was inserted, and mark misspellings in the inserted content.
-        setEndingSelection(end);
+        setEndingSelection(end, SEL_DEFAULT_AFFINITY);
     }
     rebalanceWhitespace();
 }
@@ -4414,6 +4494,13 @@ void ReplaceSelectionCommand::updateNodesInserted(NodeImpl *node)
     if (!node)
         return;
 
+    // update m_lastTopNodeInserted
+    node->ref();
+    if (m_lastTopNodeInserted)
+        m_lastTopNodeInserted->deref();
+    m_lastTopNodeInserted = node;
+    
+    // update m_firstNodeInserted
     if (!m_firstNodeInserted) {
         m_firstNodeInserted = node;
         m_firstNodeInserted->ref();
@@ -4421,7 +4508,8 @@ void ReplaceSelectionCommand::updateNodesInserted(NodeImpl *node)
     
     if (node == m_lastNodeInserted)
         return;
-        
+    
+    // update m_lastNodeInserted
     NodeImpl *old = m_lastNodeInserted;
     m_lastNodeInserted = node->lastDescendent();
     m_lastNodeInserted->ref();
@@ -4789,7 +4877,7 @@ void TypingCommand::deleteKeyPressed(DocumentImpl *document, bool smartDelete)
     }
     else {
         Selection selection = part->selection();
-        if (selection.isCaret() && VisiblePosition(selection.start()).previous().isNull()) {
+        if (selection.isCaret() && VisiblePosition(selection.start(), selection.startAffinity()).previous().isNull()) {
             // do nothing for a delete key at the start of an editable element.
         }
         else {
@@ -4814,7 +4902,7 @@ void TypingCommand::forwardDeleteKeyPressed(DocumentImpl *document, bool smartDe
     }
     else {
         Selection selection = part->selection();
-        if (selection.isCaret() && isEndOfDocument(VisiblePosition(selection.start()))) {
+        if (selection.isCaret() && isEndOfDocument(VisiblePosition(selection.start(), selection.startAffinity()))) {
             // do nothing for a delete key at the start of an editable element.
         }
         else {
@@ -4946,7 +5034,7 @@ void TypingCommand::markMisspellingsAfterTyping()
     // Since the word containing the current selection is never marked, this does a check to
     // see if typing made a new word that is not in the current selection. Basically, you
     // get this by being at the end of a word and typing a space.    
-    VisiblePosition start(endingSelection().start());
+    VisiblePosition start(endingSelection().start(), endingSelection().startAffinity());
     VisiblePosition previous = start.previous();
     if (previous.isNotNull()) {
         VisiblePosition p1 = startOfWord(previous, LeftWordIfOnBoundary);
@@ -5030,10 +5118,10 @@ void TypingCommand::deleteKeyPressed()
             // Do nothing in the case that the caret is at the start of a
             // root editable element or at the start of a document.
             Position pos(endingSelection().start());
-            Position start = VisiblePosition(pos).previous().deepEquivalent();
-            Position end = VisiblePosition(pos).deepEquivalent();
+            Position start = VisiblePosition(pos, endingSelection().startAffinity()).previous().deepEquivalent();
+            Position end = VisiblePosition(pos, endingSelection().startAffinity()).deepEquivalent();
             if (start.isNotNull() && end.isNotNull() && start.node()->rootEditableElement() == end.node()->rootEditableElement())
-                selectionToDelete = Selection(start, end);
+                selectionToDelete = Selection(start, SEL_DEFAULT_AFFINITY, end, SEL_DEFAULT_AFFINITY);
             break;
         }
         case Selection::NONE:
@@ -5061,10 +5149,10 @@ void TypingCommand::forwardDeleteKeyPressed()
             // Do nothing in the case that the caret is at the start of a
             // root editable element or at the start of a document.
             Position pos(endingSelection().start());
-            Position start = VisiblePosition(pos).next().deepEquivalent();
-            Position end = VisiblePosition(pos).deepEquivalent();
+            Position start = VisiblePosition(pos, endingSelection().startAffinity()).next().deepEquivalent();
+            Position end = VisiblePosition(pos, endingSelection().startAffinity()).deepEquivalent();
             if (start.isNotNull() && end.isNotNull() && start.node()->rootEditableElement() == end.node()->rootEditableElement())
-                selectionToDelete = Selection(start, end);
+                selectionToDelete = Selection(start, SEL_DEFAULT_AFFINITY, end, SEL_DEFAULT_AFFINITY);
             break;
         }
         case Selection::NONE:
index e5e810c51ca396961470fff1acabf919aa10e5e3..aa8bca1c15db775fb91c5a6316e48b24bf254369 100644 (file)
@@ -75,7 +75,11 @@ public:
     Selection endingSelection() const;
 
     void setStartingSelection(const Selection &s) const;
+    void setStartingSelection(const VisiblePosition &p) const;
+    void setStartingSelection(const DOM::Position &p, EAffinity affinity) const;
     void setEndingSelection(const Selection &s) const;
+    void setEndingSelection(const VisiblePosition &p) const;
+    void setEndingSelection(const DOM::Position &p, EAffinity affinity) const;
 
     DOM::CSSMutableStyleDeclarationImpl *typingStyle() const;
     void setTypingStyle(DOM::CSSMutableStyleDeclarationImpl *) const;
@@ -152,7 +156,11 @@ public:
     void setState(ECommandState state) { m_state = state; }
 
     void setStartingSelection(const Selection &s);
+    void setStartingSelection(const VisiblePosition &p);
+    void setStartingSelection(const DOM::Position &p, EAffinity affinity);
     void setEndingSelection(const Selection &s);
+    void setEndingSelection(const VisiblePosition &p);
+    void setEndingSelection(const DOM::Position &p, EAffinity affinity);
 
     DOM::CSSMutableStyleDeclarationImpl *typingStyle() const { return m_typingStyle; };
     void setTypingStyle(DOM::CSSMutableStyleDeclarationImpl *);
@@ -717,6 +725,7 @@ private:
     ReplacementFragment m_fragment;
     DOM::NodeImpl *m_firstNodeInserted;
     DOM::NodeImpl *m_lastNodeInserted;
+    DOM::NodeImpl *m_lastTopNodeInserted;
     bool m_selectReplacement;
     bool m_smartReplace;
 };
index b0eeee4f6dec33a3737a3596a514f1100903ae82..ec0b9447d1e4fd7c373bd51e98f7beca615ef917 100644 (file)
@@ -67,34 +67,41 @@ namespace khtml {
 
 Selection::Selection()
 {
-    init();
+    init(DOWNSTREAM);
 }
 
-Selection::Selection(const Position &pos)
+Selection::Selection(const Position &pos, EAffinity affinity)
     : m_base(pos), m_extent(pos)
 {
-    init();
+    init(affinity);
     validate();
 }
 
-Selection::Selection(const Range &r)
+Selection::Selection(const Range &r, EAffinity baseAffinity, EAffinity extentAffinity)
     : m_base(startPosition(r)), m_extent(endPosition(r))
 {
-    init();
+    init(baseAffinity);
     validate();
 }
 
-Selection::Selection(const Position &base, const Position &extent)
+Selection::Selection(const Position &base, EAffinity baseAffinity, const Position &extent, EAffinity extentAffinity)
     : m_base(base), m_extent(extent)
 {
-    init();
+    init(baseAffinity);
+    validate();
+}
+
+Selection::Selection(const VisiblePosition &visiblePos)
+    : m_base(visiblePos.position()), m_extent(visiblePos.position())
+{
+    init(visiblePos.affinity());
     validate();
 }
 
 Selection::Selection(const VisiblePosition &base, const VisiblePosition &extent)
     : m_base(base.position()), m_extent(extent.position())
 {
-    init();
+    init(base.affinity());
     validate();
 }
 
@@ -117,11 +124,12 @@ Selection::Selection(const Selection &o)
     }
 }
 
-void Selection::init()
+void Selection::init(EAffinity affinity)
 {
+    // FIXME: set extentAffinity
     m_state = NONE; 
-    m_affinity = UPSTREAM;
     m_baseIsStart = true;
+    m_affinity = affinity;
     m_needsLayout = true;
     m_modifyBiasSet = false;
 }
@@ -153,75 +161,55 @@ Selection &Selection::operator=(const Selection &o)
     return *this;
 }
 
-void Selection::setAffinity(EAffinity affinity)
+void Selection::moveTo(const VisiblePosition &pos)
 {
-    if (affinity == m_affinity)
-        return;
-        
-    m_affinity = affinity;
-    setNeedsLayout();
-}
-
-void Selection::modifyAffinity(EAlter alter, EDirection dir, ETextGranularity granularity)
-{
-    switch (granularity) {
-        case CHARACTER:
-        case WORD:
-            m_affinity = DOWNSTREAM;
-            break;
-        case PARAGRAPH:
-        case LINE:
-        case PARAGRAPH_BOUNDARY:
-        case DOCUMENT_BOUNDARY:
-            // These granularities should not change affinity.
-            break;
-        case LINE_BOUNDARY: {
-            // When extending, leave affinity unchanged.
-            if (alter == MOVE) {
-                switch (dir) {
-                    case FORWARD:
-                    case RIGHT:
-                        m_affinity = UPSTREAM;
-                        break;
-                    case BACKWARD:
-                    case LEFT:
-                        m_affinity = DOWNSTREAM;
-                        break;
-                }
-            }
-            break;
-        }
-    }
-    setNeedsLayout();
+    // FIXME: use extentAffinity
+    m_affinity = pos.affinity();
+    m_base = pos.deepEquivalent();
+    m_extent = pos.deepEquivalent();
+    validate();
 }
 
-void Selection::moveTo(const Range &r)
+void Selection::moveTo(const VisiblePosition &base, const VisiblePosition &extent)
 {
-    m_affinity = UPSTREAM;
-    m_base = startPosition(r);
-    m_extent = endPosition(r);
+    // FIXME: use extentAffinity
+    m_affinity = base.affinity();
+    m_base = base.deepEquivalent();
+    m_extent = extent.deepEquivalent();
     validate();
 }
 
 void Selection::moveTo(const Selection &o)
 {
-    m_affinity = UPSTREAM;
+    // FIXME: copy extentAffinity
+    m_affinity = o.m_affinity;
     m_base = o.m_start;
     m_extent = o.m_end;
     validate();
 }
 
-void Selection::moveTo(const Position &pos)
+void Selection::moveTo(const Position &pos, EAffinity affinity)
 {
-    m_affinity = UPSTREAM;
+    // FIXME: use extentAffinity
+    m_affinity = affinity;
     m_base = pos;
     m_extent = pos;
     validate();
 }
 
-void Selection::moveTo(const Position &base, const Position &extent)
+void Selection::moveTo(const Range &r, EAffinity baseAffinity, EAffinity extentAffinity)
 {
-    m_affinity = UPSTREAM;
+    // FIXME: use extentAffinity
+    m_affinity = baseAffinity;
+    m_base = startPosition(r);
+    m_extent = endPosition(r);
+    validate();
+}
+
+void Selection::moveTo(const Position &base, EAffinity baseAffinity, const Position &extent, EAffinity extentAffinity)
+{
+    // FIXME: use extentAffinity
+    m_affinity = baseAffinity;
     m_base = base;
     m_extent = extent;
     validate();
@@ -256,7 +244,7 @@ void Selection::setModifyBias(EAlter alter, EDirection direction)
 
 VisiblePosition Selection::modifyExtendingRightForward(ETextGranularity granularity)
 {
-    VisiblePosition pos(m_extent);
+    VisiblePosition pos(m_extent, m_affinity);
     switch (granularity) {
         case CHARACTER:
             pos = pos.next();
@@ -271,15 +259,16 @@ VisiblePosition Selection::modifyExtendingRightForward(ETextGranularity granular
             pos = nextLinePosition(pos, m_affinity, xPosForVerticalArrowNavigation(EXTENT));
             break;
         case LINE_BOUNDARY:
-            pos = endOfLine(VisiblePosition(m_end), m_affinity);
+            pos = endOfLine(VisiblePosition(m_end, m_affinity), UPSTREAM);
             break;
         case PARAGRAPH_BOUNDARY:
-            pos = endOfParagraph(VisiblePosition(m_end));
+            pos = endOfParagraph(VisiblePosition(m_end, m_affinity));
             break;
         case DOCUMENT_BOUNDARY:
             pos = endOfDocument(pos);
             break;
     }
+    
     return pos;
 }
 
@@ -289,15 +278,15 @@ VisiblePosition Selection::modifyMovingRightForward(ETextGranularity granularity
     switch (granularity) {
         case CHARACTER:
             if (isRange()) 
-                pos = VisiblePosition(m_end);
+                pos = VisiblePosition(m_end, m_affinity);
             else
-                pos = VisiblePosition(m_extent).next();
+                pos = VisiblePosition(m_extent, m_affinity).next();
             break;
         case WORD:
-            pos = nextWordPosition(VisiblePosition(m_extent));
+            pos = nextWordPosition(VisiblePosition(m_extent, m_affinity));
             break;
         case PARAGRAPH:
-            pos = nextParagraphPosition(VisiblePosition(m_end), m_affinity, xPosForVerticalArrowNavigation(END, isRange()));
+            pos = nextParagraphPosition(VisiblePosition(m_end, m_affinity), m_affinity, xPosForVerticalArrowNavigation(END, isRange()));
             break;
         case LINE: {
             // This somewhat complicated code is needed to handle the case where there is a
@@ -309,26 +298,25 @@ VisiblePosition Selection::modifyMovingRightForward(ETextGranularity granularity
             // <rdar://problem/3875618> REGRESSION (Mail): Hitting down arrow with full line selected skips line (br case)
             // <rdar://problem/3875641> REGRESSION (Mail): Hitting down arrow with full line selected skips line (div case)
             if (isCaret()) {
-                pos = VisiblePosition(m_end);
-            }
-            else if (isRange()) {
+                pos = VisiblePosition(m_end, m_affinity);
+            } else if (isRange()) {
                 Position p(m_end.upstream());
                 if (p.node()->id() == ID_BR)
-                    pos = VisiblePosition(Position(p.node(), 0));
+                    pos = VisiblePosition(Position(p.node(), 0), UPSTREAM);
                 else
-                    pos = VisiblePosition(p);
+                    pos = VisiblePosition(p, UPSTREAM);
             }
             pos = nextLinePosition(pos, m_affinity, xPosForVerticalArrowNavigation(END, isRange()));
             break;
         }
         case LINE_BOUNDARY:
-            pos = endOfLine(VisiblePosition(m_end), m_affinity);
+            pos = endOfLine(VisiblePosition(m_end, m_affinity), UPSTREAM);
             break;
         case PARAGRAPH_BOUNDARY:
-            pos = endOfParagraph(VisiblePosition(m_end));
+            pos = endOfParagraph(VisiblePosition(m_end, m_affinity));
             break;
         case DOCUMENT_BOUNDARY:
-            pos = endOfDocument(VisiblePosition(m_end));
+            pos = endOfDocument(VisiblePosition(m_end, m_affinity));
             break;
     }
     return pos;
@@ -336,7 +324,7 @@ VisiblePosition Selection::modifyMovingRightForward(ETextGranularity granularity
 
 VisiblePosition Selection::modifyExtendingLeftBackward(ETextGranularity granularity)
 {
-    VisiblePosition pos(m_extent);
+    VisiblePosition pos(m_extent, m_affinity);
     switch (granularity) {
         case CHARACTER:
             pos = pos.previous();
@@ -351,10 +339,10 @@ VisiblePosition Selection::modifyExtendingLeftBackward(ETextGranularity granular
             pos = previousLinePosition(pos, m_affinity, xPosForVerticalArrowNavigation(EXTENT));
             break;
         case LINE_BOUNDARY:
-            pos = startOfLine(VisiblePosition(m_start), m_affinity);
+            pos = startOfLine(VisiblePosition(m_start, m_affinity), DOWNSTREAM);
             break;
         case PARAGRAPH_BOUNDARY:
-            pos = startOfParagraph(VisiblePosition(m_start));
+            pos = startOfParagraph(VisiblePosition(m_start, m_affinity));
             break;
         case DOCUMENT_BOUNDARY:
             pos = startOfDocument(pos);
@@ -369,27 +357,27 @@ VisiblePosition Selection::modifyMovingLeftBackward(ETextGranularity granularity
     switch (granularity) {
         case CHARACTER:
             if (isRange()) 
-                pos = VisiblePosition(m_start);
+                pos = VisiblePosition(m_start, m_affinity);
             else
-                pos = VisiblePosition(m_extent).previous();
+                pos = VisiblePosition(m_extent, m_affinity).previous();
             break;
         case WORD:
-            pos = previousWordPosition(VisiblePosition(m_extent));
+            pos = previousWordPosition(VisiblePosition(m_extent, m_affinity));
             break;
         case PARAGRAPH:
-            pos = previousParagraphPosition(VisiblePosition(m_start), m_affinity, xPosForVerticalArrowNavigation(START, isRange()));
+            pos = previousParagraphPosition(VisiblePosition(m_start, m_affinity), m_affinity, xPosForVerticalArrowNavigation(START, isRange()));
             break;
         case LINE:
-            pos = previousLinePosition(VisiblePosition(m_start), m_affinity, xPosForVerticalArrowNavigation(START, isRange()));
+            pos = previousLinePosition(VisiblePosition(m_start, m_affinity), m_affinity, xPosForVerticalArrowNavigation(START, isRange()));
             break;
         case LINE_BOUNDARY:
-            pos = startOfLine(VisiblePosition(m_start), m_affinity);
+            pos = startOfLine(VisiblePosition(m_start, m_affinity), DOWNSTREAM);
             break;
         case PARAGRAPH_BOUNDARY:
-            pos = startOfParagraph(VisiblePosition(m_start));
+            pos = startOfParagraph(VisiblePosition(m_start, m_affinity));
             break;
         case DOCUMENT_BOUNDARY:
-            pos = startOfDocument(VisiblePosition(m_start));
+            pos = startOfDocument(VisiblePosition(m_start, m_affinity));
             break;
     }
     return pos;
@@ -400,7 +388,6 @@ bool Selection::modify(EAlter alter, EDirection dir, ETextGranularity granularit
     setModifyBias(alter, dir);
 
     VisiblePosition pos;
-
     switch (dir) {
         // EDIT FIXME: These need to handle bidi
         case RIGHT:
@@ -422,20 +409,16 @@ bool Selection::modify(EAlter alter, EDirection dir, ETextGranularity granularit
     if (pos.isNull())
         return false;
 
-    // Save and restore affinity here before calling setAffinity. 
-    // The moveTo() and setExtent() calls reset affinity and this 
-    // is undesirable here.
-    EAffinity savedAffinity = m_affinity;
     switch (alter) {
         case MOVE:
-            moveTo(pos.deepEquivalent());
+            moveTo(pos);
             break;
         case EXTEND:
-            setExtent(pos.deepEquivalent());
+            setExtent(pos);
             break;
     }
-    m_affinity = savedAffinity;
-    modifyAffinity(alter, dir, granularity);
+
+    setNeedsLayout();
 
     return true;
 }
@@ -470,15 +453,14 @@ bool Selection::modify(EAlter alter, int verticalDistance)
     setModifyBias(alter, up ? BACKWARD : FORWARD);
 
     VisiblePosition pos;
-    int xPos = 0; /* initialized only to make compiler happy */
-
+    int xPos = 0;
     switch (alter) {
         case MOVE:
-            pos = VisiblePosition(up ? m_start : m_end);
+            pos = VisiblePosition(up ? m_start : m_end, m_affinity);
             xPos = xPosForVerticalArrowNavigation(up ? START : END, isRange());
             break;
         case EXTEND:
-            pos = VisiblePosition(m_extent);
+            pos = VisiblePosition(m_extent, m_affinity);
             xPos = xPosForVerticalArrowNavigation(EXTENT);
             break;
     }
@@ -491,7 +473,6 @@ bool Selection::modify(EAlter alter, int verticalDistance)
     int lastY = startY;
 
     VisiblePosition result;
-
     VisiblePosition next;
     for (VisiblePosition p = pos; ; p = next) {
         next = (up ? previousLinePosition : nextLinePosition)(p, m_affinity, xPos);
@@ -515,10 +496,10 @@ bool Selection::modify(EAlter alter, int verticalDistance)
 
     switch (alter) {
         case MOVE:
-            moveTo(result.deepEquivalent());
+            moveTo(result);
             break;
         case EXTEND:
-            setExtent(result.deepEquivalent());
+            setExtent(result);
             break;
     }
 
@@ -563,10 +544,10 @@ int Selection::xPosForVerticalArrowNavigation(EPositionType type, bool recalc) c
     if (recalc || part->xPosForVerticalArrowNavigation() == KHTMLPart::NoXPosForVerticalArrowNavigation) {
         switch (m_affinity) {
             case DOWNSTREAM:
-                pos = VisiblePosition(pos).downstreamDeepEquivalent();
+                pos = VisiblePosition(pos, m_affinity).downstreamDeepEquivalent();
                 break;
             case UPSTREAM:
-                pos = VisiblePosition(pos).deepEquivalent();
+                pos = VisiblePosition(pos, m_affinity).deepEquivalent();
                 break;
         }
         x = pos.node()->renderer()->caretRect(pos.offset(), m_affinity).x();
@@ -580,29 +561,55 @@ int Selection::xPosForVerticalArrowNavigation(EPositionType type, bool recalc) c
 
 void Selection::clear()
 {
-    m_affinity = UPSTREAM;
+    m_affinity = SEL_DEFAULT_AFFINITY;
     m_base.clear();
     m_extent.clear();
     validate();
 }
 
-void Selection::setBase(const Position &pos)
+void Selection::setBase(const VisiblePosition &pos)
 {
-    m_affinity = UPSTREAM;
+    m_affinity = pos.affinity();
+    m_base = pos.deepEquivalent();
+    validate();
+}
+
+void Selection::setExtent(const VisiblePosition &pos)
+{
+    // FIXME: Support extentAffinity
+    m_extent = pos.deepEquivalent();
+    validate();
+}
+
+void Selection::setBaseAndExtent(const VisiblePosition &base, const VisiblePosition &extent)
+{
+    // FIXME: Support extentAffinity
+    m_affinity = base.affinity();
+    m_base = base.deepEquivalent();
+    m_extent = extent.deepEquivalent();
+    validate();
+}
+
+
+void Selection::setBase(const Position &pos, EAffinity baseAffinity)
+{
+    m_affinity = baseAffinity;
     m_base = pos;
     validate();
 }
 
-void Selection::setExtent(const Position &pos)
+void Selection::setExtent(const Position &pos, EAffinity extentAffinity)
 {
-    m_affinity = UPSTREAM;
+    // FIXME: Support extentAffinity for real
+    m_affinity = extentAffinity;
     m_extent = pos;
     validate();
 }
 
-void Selection::setBaseAndExtent(const Position &base, const Position &extent)
+void Selection::setBaseAndExtent(const Position &base, EAffinity baseAffinity, const Position &extent, EAffinity extentAffinity)
 {
-    m_affinity = UPSTREAM;
+    // FIXME: extentAffinity
+    m_affinity = baseAffinity;
     m_base = base;
     m_extent = extent;
     validate();
@@ -691,10 +698,10 @@ void Selection::layout()
         Position pos = m_start;
         switch (m_affinity) {
             case DOWNSTREAM:
-                pos = VisiblePosition(m_start).downstreamDeepEquivalent();
+                pos = VisiblePosition(m_start, m_affinity).downstreamDeepEquivalent();
                 break;
             case UPSTREAM:
-                pos = VisiblePosition(m_start).deepEquivalent();
+                pos = VisiblePosition(m_start, m_affinity).deepEquivalent();
                 break;
         }
         if (pos.isNotNull()) {
@@ -808,14 +815,14 @@ void Selection::validate(ETextGranularity granularity)
     if (m_base.isNotNull()) {
         m_base.node()->getDocument()->updateLayout();
         updatedLayout = true;
-        m_base = VisiblePosition(m_base).deepEquivalent();
+        m_base = VisiblePosition(m_base, m_affinity).deepEquivalent();
         if (baseAndExtentEqual)
             m_extent = m_base;
     }
     if (m_extent.isNotNull() && !baseAndExtentEqual) {
         if (!updatedLayout)
             m_extent.node()->getDocument()->updateLayout();
-        m_extent = VisiblePosition(m_extent).deepEquivalent();
+        m_extent = VisiblePosition(m_extent, m_affinity).deepEquivalent();
     }
 
     // Make sure we do not have a dangling start or end
@@ -870,50 +877,50 @@ void Selection::validate(ETextGranularity granularity)
                 // Another exception is when double-clicking at the start of a line.
                 // However, the end of the document is an exception and always selects the previous word even though it could be
                 // both the start of a line and after a hard line break.
-                VisiblePosition pos(m_base);
+                VisiblePosition pos(m_base, m_affinity);
                 EWordSide side = LeftWordIfOnBoundary;
                 if ((isEndOfParagraph(pos) || isStartOfLine(pos, m_affinity)) && !isEndOfDocument(pos))
                     side = RightWordIfOnBoundary;
                 m_start = startOfWord(pos, side).deepEquivalent();
                 m_end = endOfWord(pos, side).deepEquivalent();
             } else if (m_baseIsStart) {
-                m_start = startOfWord(VisiblePosition(m_base)).deepEquivalent();
-                m_end = endOfWord(VisiblePosition(m_extent)).deepEquivalent();
+                m_start = startOfWord(VisiblePosition(m_base, m_affinity)).deepEquivalent();
+                m_end = endOfWord(VisiblePosition(m_extent, m_affinity)).deepEquivalent();
             } else {
-                m_start = startOfWord(VisiblePosition(m_extent)).deepEquivalent();
-                m_end = endOfWord(VisiblePosition(m_base)).deepEquivalent();
+                m_start = startOfWord(VisiblePosition(m_extent, m_affinity)).deepEquivalent();
+                m_end = endOfWord(VisiblePosition(m_base, m_affinity)).deepEquivalent();
             }
             break;
         case LINE:
         case LINE_BOUNDARY:
             if (m_baseIsStart) {
-                m_start = startOfLine(VisiblePosition(m_base), m_affinity).deepEquivalent();
-                m_end = endOfLine(VisiblePosition(m_extent), m_affinity, IncludeLineBreak).deepEquivalent();
+                m_start = startOfLine(VisiblePosition(m_base, m_affinity), m_affinity).deepEquivalent();
+                m_end = endOfLine(VisiblePosition(m_extent, m_affinity), m_affinity, IncludeLineBreak).deepEquivalent();
             } else {
-                m_start = startOfLine(VisiblePosition(m_extent), m_affinity).deepEquivalent();
-                m_end = endOfLine(VisiblePosition(m_base), m_affinity, IncludeLineBreak).deepEquivalent();
+                m_start = startOfLine(VisiblePosition(m_extent, m_affinity), m_affinity).deepEquivalent();
+                m_end = endOfLine(VisiblePosition(m_base, m_affinity), m_affinity, IncludeLineBreak).deepEquivalent();
             }
             break;
         case PARAGRAPH:
             if (m_baseIsStart) {
-                m_start = startOfParagraph(VisiblePosition(m_base)).deepEquivalent();
-                m_end = endOfParagraph(VisiblePosition(m_extent), IncludeLineBreak).deepEquivalent();
+                m_start = startOfParagraph(VisiblePosition(m_base, m_affinity)).deepEquivalent();
+                m_end = endOfParagraph(VisiblePosition(m_extent, m_affinity), IncludeLineBreak).deepEquivalent();
             } else {
-                m_start = startOfParagraph(VisiblePosition(m_extent)).deepEquivalent();
-                m_end = endOfParagraph(VisiblePosition(m_base), IncludeLineBreak).deepEquivalent();
+                m_start = startOfParagraph(VisiblePosition(m_extent, m_affinity)).deepEquivalent();
+                m_end = endOfParagraph(VisiblePosition(m_base, m_affinity), IncludeLineBreak).deepEquivalent();
             }
             break;
         case DOCUMENT_BOUNDARY:
-            m_start = startOfDocument(VisiblePosition(m_base)).deepEquivalent();
-            m_end = endOfDocument(VisiblePosition(m_base)).deepEquivalent();
+            m_start = startOfDocument(VisiblePosition(m_base, m_affinity)).deepEquivalent();
+            m_end = endOfDocument(VisiblePosition(m_base, m_affinity)).deepEquivalent();
             break;
         case PARAGRAPH_BOUNDARY:
             if (m_baseIsStart) {
-                m_start = startOfParagraph(VisiblePosition(m_base)).deepEquivalent();
-                m_end = endOfParagraph(VisiblePosition(m_extent)).deepEquivalent();
+                m_start = startOfParagraph(VisiblePosition(m_base, m_affinity)).deepEquivalent();
+                m_end = endOfParagraph(VisiblePosition(m_extent, m_affinity)).deepEquivalent();
             } else {
-                m_start = startOfParagraph(VisiblePosition(m_extent)).deepEquivalent();
-                m_end = endOfParagraph(VisiblePosition(m_base)).deepEquivalent();
+                m_start = startOfParagraph(VisiblePosition(m_extent, m_affinity)).deepEquivalent();
+                m_end = endOfParagraph(VisiblePosition(m_base, m_affinity)).deepEquivalent();
             }
             break;
     }
index b6c35827b3875681d58bc3460258fe0e23d45259..e14de864c3e809bf93feb7b6cdfabf71179dbad5 100644 (file)
@@ -44,33 +44,40 @@ public:
     enum EState { NONE, CARET, RANGE };
     enum EAlter { MOVE, EXTEND };
     enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT };
+#define SEL_DEFAULT_AFFINITY DOWNSTREAM
+
+// FIXME: Implement as "caller does not know whether it is OK to be upstream,
+// but that would be the desired affinity"
+#define SEL_PREFER_UPSTREAM_AFFINITY DOWNSTREAM
 
     typedef DOM::Range Range;
     typedef DOM::Position Position;
 
     Selection();
-    Selection(const Range &);
+    Selection(const Range &, EAffinity baseAffinity, EAffinity extentAffinity);
     Selection(const VisiblePosition &);
     Selection(const VisiblePosition &, const VisiblePosition &);
-    Selection(const Position &);
-    Selection(const Position &, const Position &);
+    Selection(const Position &, EAffinity affinity);
+    Selection(const Position &, EAffinity, const Position &, EAffinity);
     Selection(const Selection &);
 
     Selection &operator=(const Selection &o);
-    Selection &operator=(const Range &r) { moveTo(r); return *this; }
     Selection &operator=(const VisiblePosition &r) { moveTo(r); return *this; }
-    Selection &operator=(const Position &r) { moveTo(r); return *this; }
-    
-    void moveTo(const Range &);
+
+    void moveTo(const Range &, EAffinity baseAffinity, EAffinity extentAffinity);
     void moveTo(const VisiblePosition &);
     void moveTo(const VisiblePosition &, const VisiblePosition &);
-    void moveTo(const Position &);
-    void moveTo(const Position &, const Position &);
+    void moveTo(const Position &, EAffinity);
+    void moveTo(const Position &, EAffinity, const Position &, EAffinity);
     void moveTo(const Selection &);
 
     EState state() const { return m_state; }
-    EAffinity affinity() const { return m_affinity; }
-    void setAffinity(EAffinity);
+    
+    // FIXME: These should support separate baseAffinity and extentAffinity
+    EAffinity startAffinity() const { return m_affinity; }
+    EAffinity endAffinity() const { return m_affinity; }
+    EAffinity baseAffinity() const { return m_affinity; }
+    EAffinity extentAffinity() const { return m_affinity; }
 
     bool modify(EAlter, EDirection, ETextGranularity);
     bool modify(EAlter, int verticalDistance);
@@ -81,9 +88,9 @@ public:
     void setExtent(const VisiblePosition &);
     void setBaseAndExtent(const VisiblePosition &base, const VisiblePosition &extent);
 
-    void setBase(const Position &pos);
-    void setExtent(const Position &pos);
-    void setBaseAndExtent(const Position &base, const Position &extent);
+    void setBase(const Position &pos, EAffinity affinity);
+    void setExtent(const Position &pos, EAffinity affinity);
+    void setBaseAndExtent(const Position &base, EAffinity baseAffinity, const Position &extent, EAffinity extentAffinity);
 
     Position base() const { return m_base; }
     Position extent() const { return m_extent; }
@@ -116,7 +123,7 @@ public:
 private:
     enum EPositionType { START, END, BASE, EXTENT };
 
-    void init();
+    void init(EAffinity affinity);
     void validate(ETextGranularity granularity = CHARACTER);
 
     VisiblePosition modifyExtendingRightForward(ETextGranularity);
@@ -124,8 +131,6 @@ private:
     VisiblePosition modifyExtendingLeftBackward(ETextGranularity);
     VisiblePosition modifyMovingLeftBackward(ETextGranularity);
 
-    void modifyAffinity(EAlter, EDirection, ETextGranularity);
-
     void layout();
     void needsCaretRepaint();
     void paintCaret(QPainter *p, const QRect &rect);
@@ -152,7 +157,7 @@ private:
 
 inline bool operator==(const Selection &a, const Selection &b)
 {
-    return a.start() == b.start() && a.end() == b.end() && a.affinity() == b.affinity();
+    return a.start() == b.start() && a.end() == b.end() && a.startAffinity() == b.startAffinity();
 }
 
 inline bool operator!=(const Selection &a, const Selection &b)
index 2de15efa91bfedc641593af0b6f72f7185d507c8..ccee7e762fe1937d000bc75d5cdc58d220de6690 100644 (file)
@@ -32,7 +32,7 @@ namespace khtml {
 // From NSTextView.h:
 // NSSelectionAffinityUpstream = 0
 // NSSelectionAffinityDownstream = 1
-enum EAffinity { UPSTREAM = 0, DOWNSTREAM = 1 };
+typedef enum { UPSTREAM = 0, DOWNSTREAM = 1 } EAffinity;
 
 }
 
index 375dbd2e86b4dade2f38a0a03ac92fd3a25052f8..102497012114013b72747dd27713f992ef271455 100644 (file)
@@ -52,40 +52,30 @@ using DOM::TextImpl;
 
 namespace khtml {
 
-VisiblePosition::VisiblePosition(NodeImpl *node, long offset, EAffinity affinity)
+VisiblePosition::VisiblePosition(const Position &pos, EAffinity affinity, EInitHint initHint)
 {
-    Position pos = Position(node, offset);
-
-    // A first step toward eliminating the affinity parameter.
-    // For <br> 0, it's important not to move past the <br>.
-    if (node && node->id() == ID_BR && offset == 0)
-        affinity = UPSTREAM;
+    init(pos, initHint, affinity);
+}
 
-    switch (affinity) {
-        case UPSTREAM:
-            initUpstream(pos);
-            break;
-        case DOWNSTREAM:
-            initDownstream(pos);
-            break;
-        default:
-            ASSERT_NOT_REACHED();
-            break;
-    }
+VisiblePosition::VisiblePosition(NodeImpl *node, long offset, EAffinity affinity, EInitHint initHint)
+{
+    init(Position(node, offset), initHint, affinity);
 }
 
-VisiblePosition::VisiblePosition(const Position &pos, EAffinity affinity)
+void VisiblePosition::init(const Position &pos, EInitHint initHint, EAffinity affinity)
 {
-    // A first step toward eliminating the affinity parameter.
+    m_affinity = affinity;
+
+    // A first step toward eliminating the initHint parameter.
     // For <br> 0, it's important not to move past the <br>.
     if (pos.node() && pos.node()->id() == ID_BR && pos.offset() == 0)
-        affinity = UPSTREAM;
+        initHint = INIT_UP;
 
-    switch (affinity) {
-        case UPSTREAM:
+    switch (initHint) {
+        case INIT_UP:
             initUpstream(pos);
             break;
-        case DOWNSTREAM:
+        case INIT_DOWN:
             initDownstream(pos);
             break;
         default:
@@ -111,8 +101,7 @@ void VisiblePosition::initUpstream(const Position &pos)
         Position previous = previousVisiblePosition(deepPos);
         if (previous.isNotNull()) {
             m_deepPosition = previous;
-        }
-        else {
+        } else {
             Position next = nextVisiblePosition(deepPos);
             if (next.isNotNull())
                 m_deepPosition = next;
@@ -137,8 +126,7 @@ void VisiblePosition::initDownstream(const Position &pos)
         Position next = nextVisiblePosition(deepPos);
         if (next.isNotNull()) {
             m_deepPosition = next;
-        }
-        else {
+        } else {
             Position previous = previousVisiblePosition(deepPos);
             if (previous.isNotNull())
                 m_deepPosition = previous;
@@ -148,15 +136,34 @@ void VisiblePosition::initDownstream(const Position &pos)
 
 VisiblePosition VisiblePosition::next() const
 {
-    VisiblePosition result;
-    result.m_deepPosition = nextVisiblePosition(m_deepPosition);
+    VisiblePosition result = VisiblePosition(nextVisiblePosition(m_deepPosition), m_affinity);
+
+    // When moving across line wrap, make sure to end up with DOWNSTREAM affinity (i.e. at first
+    // character on next line).  Correct behavior regardless of whether the current position is
+    // at or after the last character on the current line.
+    if (result.isNotNull() && result.affinity() == UPSTREAM) {
+        VisiblePosition temp = result;
+        temp.setAffinity(DOWNSTREAM);
+        if (!visiblePositionsOnDifferentLines(temp, result))
+            result.setAffinity(DOWNSTREAM);
+    }
+
     return result;
 }
 
 VisiblePosition VisiblePosition::previous() const
 {
-    VisiblePosition result;
-    result.m_deepPosition = previousVisiblePosition(m_deepPosition);
+    VisiblePosition result =  VisiblePosition(previousVisiblePosition(m_deepPosition), DOWNSTREAM);
+
+#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 (result.isNotNull() && m_affinity == UPSTREAM) {
+        VisiblePosition temp = result;
+        temp.setAffinity(UPSTREAM);
+        ASSERT(!visiblePositionsOnDifferentLines(temp, result));
+    }
+#endif
     return result;
 }
 
@@ -425,14 +432,14 @@ Range makeRange(const VisiblePosition &start, const VisiblePosition &end)
     return Range(s.node(), s.offset(), e.node(), e.offset());
 }
 
-VisiblePosition startVisiblePosition(const Range &r)
+VisiblePosition startVisiblePosition(const Range &r, EAffinity affinity)
 {
-    return VisiblePosition(r.startContainer().handle(), r.startOffset());
+    return VisiblePosition(r.startContainer().handle(), r.startOffset(), affinity);
 }
 
-VisiblePosition endVisiblePosition(const Range &r)
+VisiblePosition endVisiblePosition(const Range &r, EAffinity affinity)
 {
-    return VisiblePosition(r.endContainer().handle(), r.endOffset());
+    return VisiblePosition(r.endContainer().handle(), r.endOffset(), affinity);
 }
 
 bool setStart(Range &r, const VisiblePosition &c)
index 54cb85289032a421c7d80d8af8e5739a511d4260..ea52578d7f729b04d04dd6eaf8dc421ceaf9db54 100644 (file)
@@ -39,15 +39,22 @@ namespace DOM {
 
 namespace khtml {
 
+#define VP_DEFAULT_AFFINITY DOWNSTREAM
+
 class VisiblePosition
 {
 public:
     typedef DOM::NodeImpl NodeImpl;
     typedef DOM::Position Position;
 
-    VisiblePosition() { }
-    VisiblePosition(NodeImpl *, long offset, EAffinity affinity=DOWNSTREAM);
-    explicit VisiblePosition(const Position &, EAffinity affinity=DOWNSTREAM);
+    enum EInitHint { 
+        INIT_UP, 
+        INIT_DOWN
+    };
+
+    VisiblePosition() { m_affinity = VP_DEFAULT_AFFINITY; };
+    VisiblePosition(NodeImpl *, long offset, EAffinity, EInitHint initHint=INIT_DOWN);
+    explicit VisiblePosition(const Position &, EAffinity, EInitHint initHint=INIT_DOWN);
 
     void clear() { m_deepPosition.clear(); }
 
@@ -56,6 +63,8 @@ public:
 
     Position position() const { return rangeCompliantEquivalent(m_deepPosition); }
     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; }
     
     Position downstreamDeepEquivalent() const;
 
@@ -76,6 +85,7 @@ public:
 #endif
     
 private:
+    void init(const Position &, EInitHint, EAffinity);
     void initUpstream(const Position &);
     void initDownstream(const Position &);
 
@@ -97,11 +107,12 @@ private:
     static bool isCandidate(const Position &);
     
     Position m_deepPosition;
+    EAffinity m_affinity;
 };
 
 inline bool operator==(const VisiblePosition &a, const VisiblePosition &b)
 {
-    return a.m_deepPosition == b.m_deepPosition;
+    return a.m_deepPosition == b.m_deepPosition && a.m_affinity == b.m_affinity;
 }
 
 inline bool operator!=(const VisiblePosition &a, const VisiblePosition &b)
@@ -114,10 +125,10 @@ bool setStart(DOM::Range &, const VisiblePosition &start);
 bool setStart(DOM::RangeImpl *, const VisiblePosition &start);
 bool setEnd(DOM::Range &, const VisiblePosition &start);
 bool setEnd(DOM::RangeImpl *, const VisiblePosition &start);
-VisiblePosition startVisiblePosition(const DOM::Range &);
-VisiblePosition startVisiblePosition(const DOM::RangeImpl *);
-VisiblePosition endVisiblePosition(const DOM::Range &);
-VisiblePosition endVisiblePosition(const DOM::RangeImpl *);
+VisiblePosition startVisiblePosition(const DOM::Range &, EAffinity);
+VisiblePosition startVisiblePosition(const DOM::RangeImpl *, EAffinity);
+VisiblePosition endVisiblePosition(const DOM::Range &, EAffinity);
+VisiblePosition endVisiblePosition(const DOM::RangeImpl *, EAffinity);
 
 bool visiblePositionsOnDifferentLines(const VisiblePosition &, const VisiblePosition &);
 bool visiblePositionsInDifferentBlocks(const VisiblePosition &, const VisiblePosition &);
index df97d6d9f8bd702f4db5bb39ac98880c6cf68b4a..3280491bffec3f77377d942cbc0556ccbf2212d9 100644 (file)
 #include "htmltags.h"
 #include "misc/helper.h"
 #include "rendering/render_text.h"
+#include "rendering/render_block.h"
 #include "visible_position.h"
 #include "visible_text.h"
 #include "xml/dom_docimpl.h"
+#include "xml/dom_elementimpl.h"
 
 using DOM::DocumentImpl;
+using DOM::ElementImpl;
 using DOM::NodeImpl;
 using DOM::Position;
 using DOM::Range;
@@ -114,7 +117,7 @@ static VisiblePosition previousBoundary(const VisiblePosition &c, unsigned (*sea
         }
     }
 
-    return VisiblePosition(pos, UPSTREAM);
+    return VisiblePosition(pos, DOWNSTREAM, VisiblePosition::INIT_UP);
 }
 
 static VisiblePosition nextBoundary(const VisiblePosition &c, unsigned (*searchFunction)(const QChar *, unsigned))
@@ -181,7 +184,7 @@ static VisiblePosition nextBoundary(const VisiblePosition &c, unsigned (*searchF
         charIt.advance(next - 1);
         pos = Position(charIt.range().endContainer().handle(), charIt.range().endOffset());
     }
-    return VisiblePosition(pos, UPSTREAM);
+    return VisiblePosition(pos, UPSTREAM, VisiblePosition::INIT_UP);
 }
 
 // ---------
@@ -285,7 +288,7 @@ VisiblePosition startOfLine(const VisiblePosition &c, EAffinity affinity)
         InlineTextBox *startTextBox = static_cast<InlineTextBox *>(startBox);
         startOffset = startTextBox->m_start;
     }
-    return VisiblePosition(startNode, startOffset);
+    return VisiblePosition(startNode, startOffset, affinity);
 }
 
 VisiblePosition endOfLine(const VisiblePosition &c, EAffinity affinity, EIncludeLineBreak includeLineBreak)
@@ -317,7 +320,7 @@ VisiblePosition endOfLine(const VisiblePosition &c, EAffinity affinity, EInclude
         InlineTextBox *endTextBox = static_cast<InlineTextBox *>(endBox);
         endOffset = endTextBox->m_start + endTextBox->m_len;
     }
-    return VisiblePosition(endNode, endOffset);
+    return VisiblePosition(endNode, endOffset, affinity);
 }
 
 bool inSameLine(const VisiblePosition &a, EAffinity aa, const VisiblePosition &b, EAffinity ab)
@@ -338,13 +341,128 @@ bool isEndOfLine(const VisiblePosition &p, EAffinity affinity)
 VisiblePosition previousLinePosition(const VisiblePosition &c, EAffinity affinity, int x)
 {
     Position p = affinity == UPSTREAM ? c.deepEquivalent() : c.downstreamDeepEquivalent();
-    return VisiblePosition(p.previousLinePosition(x, affinity));
+    NodeImpl *node = p.node();
+    if (!node)
+        return VisiblePosition();
+
+    RenderObject *renderer = node->renderer();
+    if (!renderer)
+        return VisiblePosition();
+
+    RenderBlock *containingBlock = 0;
+    RootInlineBox *root = 0;
+    InlineBox *box = renderer->inlineBox(p.offset(), affinity);
+    if (box) {
+        root = box->root()->prevRootBox();
+        if (root)
+            containingBlock = renderer->containingBlock();
+    }
+
+    if (!root) {
+        // 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 = node->enclosingBlockFlowElement();
+        NodeImpl *n = node->previousEditable();
+        while (n && startBlock == n->enclosingBlockFlowElement())
+            n = n->previousEditable();
+        while (n) {
+            if (!n->inSameRootEditableElement(node))
+                break;
+            Position pos(n, n->caretMinOffset());
+            if (pos.inRenderedContent()) {
+                assert(n->renderer());
+                box = n->renderer()->inlineBox(n->caretMaxOffset());
+                if (box) {
+                    // previous root line box found
+                    root = box->root();
+                    containingBlock = n->renderer()->containingBlock();
+                    break;
+                }
+
+                return VisiblePosition(pos, UPSTREAM);
+            }
+            n = n->previousEditable();
+        }
+    }
+    
+    if (root) {
+        int absx, absy;
+        containingBlock->absolutePosition(absx, absy);
+        RenderObject *renderer = root->closestLeafChildForXPos(x, absx)->object();
+        EAffinity posAffinity;
+        Position pos = renderer->positionForCoordinates(x, absy + root->topOverflow(), &posAffinity);
+        return VisiblePosition(pos, posAffinity);
+    }
+    
+    // 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.
+    return VisiblePosition(node->rootEditableElement(), 0, UPSTREAM);
 }
 
 VisiblePosition nextLinePosition(const VisiblePosition &c, EAffinity affinity, int x)
 {
     Position p = affinity == UPSTREAM ? c.deepEquivalent() : c.downstreamDeepEquivalent();
-    return VisiblePosition(p.nextLinePosition(x, affinity));
+    NodeImpl *node = p.node();
+    if (!node)
+        return VisiblePosition();
+
+    RenderObject *renderer = node->renderer();
+    if (!renderer)
+        return VisiblePosition();
+
+    RenderBlock *containingBlock = 0;
+    RootInlineBox *root = 0;
+    InlineBox *box = renderer->inlineBox(p.offset(), affinity);
+    if (box) {
+        root = box->root()->nextRootBox();
+        if (root)
+            containingBlock = renderer->containingBlock();
+    }
+
+    if (!root) {
+        // 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 = node->enclosingBlockFlowElement();
+        NodeImpl *n = node->nextEditable();
+        while (n && startBlock == n->enclosingBlockFlowElement())
+            n = n->nextEditable();
+        while (n) {
+            if (!n->inSameRootEditableElement(node))
+                break;
+            Position pos(n, n->caretMinOffset());
+            if (pos.inRenderedContent()) {
+                assert(n->renderer());
+                box = n->renderer()->inlineBox(n->caretMinOffset());
+                if (box) {
+                    // next root line box found
+                    root = box->root();
+                    containingBlock = n->renderer()->containingBlock();
+                    break;
+                }
+
+                return VisiblePosition(pos, UPSTREAM);
+            }
+            n = n->nextEditable();
+        }
+    }
+    
+    if (root) {
+        int absx, absy;
+        containingBlock->absolutePosition(absx, absy);
+        RenderObject *renderer = root->closestLeafChildForXPos(x, absx)->object();
+        EAffinity posAffinity;
+        Position pos = renderer->positionForCoordinates(x, absy + root->topOverflow(), &posAffinity);
+        return VisiblePosition(pos, posAffinity);
+    }    
+
+    // 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->rootEditableElement();
+    return VisiblePosition(rootElement, rootElement ? rootElement->childNodeCount() : 0, affinity);
 }
 
 // ---------
@@ -423,7 +541,7 @@ VisiblePosition startOfParagraph(const VisiblePosition &c)
                     i = kMax(0L, o);
                 while (--i >= 0)
                     if (text[i] == '\n')
-                        return VisiblePosition(n, i + 1);
+                        return VisiblePosition(n, i + 1, DOWNSTREAM);
             }
             node = n;
             offset = 0;
@@ -433,7 +551,7 @@ VisiblePosition startOfParagraph(const VisiblePosition &c)
         }
     }
 
-    return VisiblePosition(node, offset);
+    return VisiblePosition(node, offset, DOWNSTREAM);
 }
 
 VisiblePosition endOfParagraph(const VisiblePosition &c, EIncludeLineBreak includeLineBreak)
@@ -461,17 +579,17 @@ VisiblePosition endOfParagraph(const VisiblePosition &c, EIncludeLineBreak inclu
             continue;
         if (r->isBR()) {
             if (includeLineBreak)
-                return VisiblePosition(n, 1);
+                return VisiblePosition(n, 1, UPSTREAM);
             break;
         }
         if (r->isBlockFlow()) {
             if (includeLineBreak)
-                return VisiblePosition(n, 0);
+                return VisiblePosition(n, 0, UPSTREAM);
             break;
         }
         if (r->isText()) {
             if (includeLineBreak && !n->isAncestor(startBlock))
-                return VisiblePosition(n, 0);
+                return VisiblePosition(n, 0, UPSTREAM);
             long length = static_cast<RenderText *>(r)->length();
             if (style->whiteSpace() == PRE) {
                 QChar *text = static_cast<RenderText *>(r)->text();
@@ -480,7 +598,7 @@ VisiblePosition endOfParagraph(const VisiblePosition &c, EIncludeLineBreak inclu
                     o = offset;
                 for (long i = o; i < length; ++i)
                     if (text[i] == '\n')
-                        return VisiblePosition(n, i + includeLineBreak);
+                        return VisiblePosition(n, i + includeLineBreak, UPSTREAM);
             }
             node = n;
             offset = length;
@@ -492,7 +610,7 @@ VisiblePosition endOfParagraph(const VisiblePosition &c, EIncludeLineBreak inclu
         }
     }
 
-    return VisiblePosition(node, offset);
+    return VisiblePosition(node, offset, UPSTREAM);
 }
 
 bool inSameParagraph(const VisiblePosition &a, const VisiblePosition &b)
@@ -510,25 +628,27 @@ bool isEndOfParagraph(const VisiblePosition &pos)
     return pos.isNotNull() && pos == endOfParagraph(pos, DoNotIncludeLineBreak);
 }
 
-VisiblePosition previousParagraphPosition(const VisiblePosition &p, EAffinity affinity, int x)
+VisiblePosition previousParagraphPosition(const VisiblePosition &p, EAffinity a, int x)
 {
     VisiblePosition pos = p;
     do {
-        VisiblePosition n = previousLinePosition(pos, affinity, x);
-        if (n.isNull() || n == pos)
+        VisiblePosition n = previousLinePosition(pos, a, x);
+        if (n.isNull() || n == pos) {
             return p;
+        }
         pos = n;
     } while (inSameParagraph(p, pos));
     return pos;
 }
 
-VisiblePosition nextParagraphPosition(const VisiblePosition &p, EAffinity affinity, int x)
+VisiblePosition nextParagraphPosition(const VisiblePosition &p, EAffinity a, int x)
 {
     VisiblePosition pos = p;
     do {
-        VisiblePosition n = nextLinePosition(pos, affinity, x);
-        if (n.isNull() || n == pos)
+        VisiblePosition n = nextLinePosition(pos, a, x);
+        if (n.isNull() || n == pos) {
             return p;
+        }
         pos = n;
     } while (inSameParagraph(p, pos));
     return pos;
@@ -542,7 +662,7 @@ VisiblePosition startOfBlock(const VisiblePosition &c)
     NodeImpl *startNode = p.node();
     if (!startNode)
         return VisiblePosition();
-    return VisiblePosition(Position(startNode->enclosingBlockFlowElement(), 0));
+    return VisiblePosition(Position(startNode->enclosingBlockFlowElement(), 0), DOWNSTREAM);
 }
 
 // written, but not yet tested
@@ -569,12 +689,12 @@ VisiblePosition endOfBlock(const VisiblePosition &c, EIncludeLineBreak includeLi
             continue;
         if (r->isBlockFlow()) {
             if (includeLineBreak)
-                return VisiblePosition(n, 0);
+                return VisiblePosition(n, 0, DOWNSTREAM);
             break;
         }
         if (r->isText()) {
             if (includeLineBreak && !n->isAncestor(startBlock))
-                return VisiblePosition(n, 0);
+                return VisiblePosition(n, 0, DOWNSTREAM);
             node = n;
             offset = static_cast<RenderText *>(r)->length();
         } else if (r->isReplaced()) {
@@ -585,7 +705,7 @@ VisiblePosition endOfBlock(const VisiblePosition &c, EIncludeLineBreak includeLi
         }
     }
 
-    return VisiblePosition(node, offset);
+    return VisiblePosition(node, offset, DOWNSTREAM);
 }
 
 bool inSameBlock(const VisiblePosition &a, const VisiblePosition &b)
@@ -616,7 +736,7 @@ VisiblePosition startOfDocument(const VisiblePosition &c)
     if (!doc)
         return VisiblePosition();
 
-    return VisiblePosition(doc->documentElement(), 0);
+    return VisiblePosition(doc->documentElement(), 0, DOWNSTREAM);
 }
 
 VisiblePosition endOfDocument(const VisiblePosition &c)
@@ -634,7 +754,7 @@ VisiblePosition endOfDocument(const VisiblePosition &c)
     if (!node)
         return VisiblePosition();
 
-    return VisiblePosition(docElem, docElem->childNodeCount());
+    return VisiblePosition(docElem, docElem->childNodeCount(), DOWNSTREAM);
 }
 
 bool inSameDocument(const VisiblePosition &a, const VisiblePosition &b)
index 0e4f97803b8b885ef82c3efd110591cf02356179..e6ce51497737bff53b998460a526d60c861d1837 100644 (file)
@@ -53,8 +53,8 @@ bool isEndOfLine(const VisiblePosition &, EAffinity);
 // sentences
 VisiblePosition startOfSentence(const VisiblePosition &);
 VisiblePosition endOfSentence(const VisiblePosition &);
-VisiblePosition previousSentencePosition(const VisiblePosition &, EAffinity, int x);
-VisiblePosition nextSentencePosition(const VisiblePosition &, EAffinity, int x);
+VisiblePosition previousSentencePosition(const VisiblePosition &);
+VisiblePosition nextSentencePosition(const VisiblePosition &);
 
 // paragraphs (perhaps a misnomer, can be divided by line break elements)
 VisiblePosition startOfParagraph(const VisiblePosition &);
index 952fd395b2b16d6606483c019d64bd5367c5cef9..2f78235be4e4c96d4b548532df42a4564cc55924 100644 (file)
@@ -2300,7 +2300,7 @@ bool KHTMLPart::findTextNext( const QString &str, bool forward, bool caseSensiti
                 d->m_view->setContentsPos(x-50, y-50);
                 Position p1(d->m_findNode, d->m_findPos);
                 Position p2(d->m_findNode, d->m_findPos + matchLen);
-                setSelection(Selection(p1, p2));
+                setSelection(Selection(p1, khtml::DOWNSTREAM, p2, khtml::SEL_PREFER_UPSTREAM_AFFINITY));
                 return true;
             }
         }
@@ -4467,8 +4467,7 @@ void KHTMLPart::selectClosestWordFromMouseEvent(QMouseEvent *mouse, DOM::Node &i
         EAffinity affinity;
         Position pos(innerNode.handle()->renderer()->positionForCoordinates(x, y, &affinity));
         if (pos.isNotNull()) {
-            selection.moveTo(pos);
-            selection.setAffinity(affinity);
+            selection.moveTo(pos, affinity);
             selection.expandUsingGranularity(WORD);
         }
     }
@@ -4502,8 +4501,7 @@ void KHTMLPart::handleMousePressEventTripleClick(khtml::MousePressEvent *event)
         EAffinity affinity;
         Position pos(innerNode.handle()->renderer()->positionForCoordinates(event->x(), event->y(), &affinity));
         if (pos.isNotNull()) {
-            selection.moveTo(pos);
-            selection.setAffinity(affinity);
+            selection.moveTo(pos, affinity);
             selection.expandUsingGranularity(PARAGRAPH);
         }
     }
@@ -4549,10 +4547,9 @@ void KHTMLPart::handleMousePressEventSingleClick(khtml::MousePressEvent *event)
                 Position start = sel.start();
                 short before = RangeImpl::compareBoundaryPoints(pos.node(), pos.offset(), start.node(), start.offset());
                 if (before <= 0) {
-                    sel.setBaseAndExtent(pos, sel.end());
-                }
-                else {
-                    sel.setBaseAndExtent(start, pos);
+                    sel.setBaseAndExtent(pos, affinity, sel.end(), sel.endAffinity());
+                } else {
+                    sel.setBaseAndExtent(start, sel.startAffinity(), pos, affinity);
                 }
 
                 if (d->m_selectionGranularity != CHARACTER) {
@@ -4560,8 +4557,7 @@ void KHTMLPart::handleMousePressEventSingleClick(khtml::MousePressEvent *event)
                 }
                 d->m_beganSelectingText = true;
             } else {
-                sel = pos;
-                sel.setAffinity(affinity);
+                sel = Selection(pos, affinity);
                 d->m_selectionGranularity = CHARACTER;
             }
         }
@@ -4770,11 +4766,10 @@ void KHTMLPart::handleMouseMoveEventSelection(khtml::MouseMoveEvent *event)
     sel.clearModifyBias();
     if (!d->m_beganSelectingText) {
         d->m_beganSelectingText = true;
-        sel.moveTo(pos);
-        sel.setAffinity(affinity);
+        sel.moveTo(pos, affinity);
     }
 
-    sel.setExtent(pos);
+    sel.setExtent(pos, affinity);
     if (d->m_selectionGranularity != CHARACTER) {
         sel.expandUsingGranularity(d->m_selectionGranularity);
     }
@@ -4848,8 +4843,7 @@ void KHTMLPart::khtmlMouseReleaseEvent( khtml::MouseReleaseEvent *event )
         if (node->isContentEditable() && node->renderer()) {
             EAffinity affinity;
             Position pos = node->renderer()->positionForCoordinates(event->x(), event->y(), &affinity);
-            selection.moveTo(pos);
-            selection.setAffinity(affinity);
+            selection.moveTo(pos, affinity);
         }
         setSelection(selection);
     }
@@ -5015,7 +5009,7 @@ void KHTMLPart::selectAll()
         return;
     NodeImpl *de = d->m_doc->documentElement();
     int n = de ? de->childNodeCount() : 0;
-    setSelection(Selection(VisiblePosition(de, 0), VisiblePosition(de, n)));
+    setSelection(Selection(VisiblePosition(de, 0, khtml::DOWNSTREAM), VisiblePosition(de, n, khtml::DOWNSTREAM)));
 }
 
 bool KHTMLPart::shouldBeginEditing(const Range &range) const
@@ -5409,7 +5403,7 @@ void KHTMLPart::computeAndSetTypingStyle(CSSStyleDeclarationImpl *style, EditAct
         mutableStyle->ref();
     }
 
-    NodeImpl *node = VisiblePosition(selection().start()).deepEquivalent().node();
+    NodeImpl *node = VisiblePosition(selection().start(), selection().startAffinity()).deepEquivalent().node();
     CSSComputedStyleDeclarationImpl computedStyle(node);
     computedStyle.diff(mutableStyle);
     
@@ -5591,7 +5585,7 @@ CSSComputedStyleDeclarationImpl *KHTMLPart::selectionComputedStyle(NodeImpl *&no
     // If the position is in an empty block, which this test checks, then move the position
     // for the style check downstream. There may be a block placeholder in this block
     // which has been styled, and we want to use that for the style calculation.
-    VisiblePosition visiblePos(pos);
+    VisiblePosition visiblePos(pos, d->m_selection.startAffinity());
     if (isFirstVisiblePositionInBlock(visiblePos) && isLastVisiblePositionInBlock(visiblePos))
         pos = pos.downstream(StayInBlock);
 
index 3be8f9d461cdc17c5d299ae8e752b62c9b946053..23a91d03ccc5b8f2e73d5c7533955d75db5f43eb 100644 (file)
@@ -104,7 +104,7 @@ unsigned long RenderBR::caretMaxRenderedOffset() const
 Position RenderBR::positionForCoordinates(int _x, int _y, EAffinity *affinity)
 {
     if (affinity)
-        *affinity = UPSTREAM;
+        *affinity = DOWNSTREAM;
     return Position(element(), 0);
 }
 
index 0f1d2de7356266ae7fae6eaaed2fa6c18f81f24d..c517343a347a5d04e878a87b5860eda8d52055ea 100644 (file)
@@ -1267,8 +1267,8 @@ void DocumentImpl::updateSelection()
 #endif
     }
     else {
-        Position startPos = VisiblePosition(s.start(), UPSTREAM).deepEquivalent();
-        Position endPos = VisiblePosition(s.end(), DOWNSTREAM).deepEquivalent();
+        Position startPos = VisiblePosition(s.start(), s.startAffinity(), khtml::VisiblePosition::INIT_UP).deepEquivalent();
+        Position endPos = VisiblePosition(s.end(), s.endAffinity(), khtml::VisiblePosition::INIT_DOWN).deepEquivalent();
         if (startPos.isNotNull() && endPos.isNotNull()) {
             RenderObject *startRenderer = startPos.node()->renderer();
             RenderObject *endRenderer = endPos.node()->renderer();
index 31fa637b05a60e2ec4b2d957f78439e52605e3de..8c5e24667c4c5955c5a6e128138ea2637ebc831b 100644 (file)
@@ -2084,7 +2084,7 @@ void NodeBaseImpl::setFocus(bool received)
     NodeImpl::setFocus(received);
 
     if (received && isEditableBlock() && !hasChildNodes()) {
-        getDocument()->part()->setSelection(Position(this, 0));
+        getDocument()->part()->setSelection(Selection(Position(this, 0), DOWNSTREAM));
     }
 
     // note that we need to recalc the style
index 7f1b2fa9313170e2380d58b6fad05b79f0df9442..92c66f8474c0361101710454583ff81f911fde37 100644 (file)
@@ -190,7 +190,7 @@ Position Position::previousCharacterPosition() const
     NodeImpl *fromRootEditableElement = node()->rootEditableElement();
     PositionIterator it(*this);
 
-    bool atStartOfLine = isFirstVisiblePositionOnLine(VisiblePosition(*this));
+    bool atStartOfLine = isFirstVisiblePositionOnLine(VisiblePosition(*this, khtml::DOWNSTREAM));
     bool rendered = inRenderedContent();
     
     while (!it.atStart()) {
@@ -218,7 +218,7 @@ Position Position::nextCharacterPosition() const
     NodeImpl *fromRootEditableElement = node()->rootEditableElement();
     PositionIterator it(*this);
 
-    bool atEndOfLine = isLastVisiblePositionOnLine(VisiblePosition(*this));
+    bool atEndOfLine = isLastVisiblePositionOnLine(VisiblePosition(*this, khtml::UPSTREAM));
     bool rendered = inRenderedContent();
     
     while (!it.atEnd()) {
@@ -238,125 +238,6 @@ Position Position::nextCharacterPosition() const
     return *this;
 }
 
-Position Position::previousLinePosition(int x, EAffinity affinity) const
-{
-    if (!node())
-        return Position();
-
-    if (!node()->renderer())
-        return *this;
-
-    RenderBlock *containingBlock = 0;
-    RootInlineBox *root = 0;
-    InlineBox *box = node()->renderer()->inlineBox(offset(), affinity);
-    if (box) {
-        root = box->root()->prevRootBox();
-        if (root)
-            containingBlock = node()->renderer()->containingBlock();
-    }
-
-    if (!root) {
-        // 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 = node()->enclosingBlockFlowElement();
-        NodeImpl *n = node()->previousEditable();
-        while (n && startBlock == n->enclosingBlockFlowElement())
-            n = n->previousEditable();
-        while (n) {
-            if (!n->inSameRootEditableElement(node()))
-                break;
-            Position pos(n, n->caretMinOffset());
-            if (pos.inRenderedContent()) {
-                ASSERT(n->renderer());
-                box = n->renderer()->inlineBox(n->caretMaxOffset());
-                if (box) {
-                    // previous root line box found
-                    root = box->root();
-                    containingBlock = n->renderer()->containingBlock();
-                    break;
-                }
-                else {
-                    return pos;
-                }
-            }
-            n = n->previousEditable();
-        }
-    }
-    
-    if (root) {
-        int absx, absy;
-        containingBlock->absolutePosition(absx, absy);
-        RenderObject *renderer = root->closestLeafChildForXPos(x, absx)->object();
-        return renderer->positionForCoordinates(x, absy + 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.
-    return Position(node()->rootEditableElement(), 0);
-}
-
-Position Position::nextLinePosition(int x, EAffinity affinity) const
-{
-    if (!node())
-        return Position();
-
-    if (!node()->renderer())
-        return *this;
-
-    RenderBlock *containingBlock = 0;
-    RootInlineBox *root = 0;
-    InlineBox *box = node()->renderer()->inlineBox(offset(), affinity);
-    if (box) {
-        root = box->root()->nextRootBox();
-        if (root)
-            containingBlock = node()->renderer()->containingBlock();
-    }
-
-    if (!root) {
-        // 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 = node()->enclosingBlockFlowElement();
-        NodeImpl *n = node()->nextEditable();
-        while (n && startBlock == n->enclosingBlockFlowElement())
-            n = n->nextEditable();
-        while (n) {
-            if (!n->inSameRootEditableElement(node()))
-                break;
-            Position pos(n, n->caretMinOffset());
-            if (pos.inRenderedContent()) {
-                ASSERT(n->renderer());
-                box = n->renderer()->inlineBox(n->caretMinOffset());
-                if (box) {
-                    // next root line box found
-                    root = box->root();
-                    containingBlock = n->renderer()->containingBlock();
-                    break;
-                }
-                else {
-                    return pos;
-                }
-            }
-            n = n->nextEditable();
-        }
-    }
-    
-    if (root) {
-        int absx, absy;
-        containingBlock->absolutePosition(absx, absy);
-        RenderObject *renderer = root->closestLeafChildForXPos(x, absx)->object();
-        return renderer->positionForCoordinates(x, absy + 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()->rootEditableElement();
-    return Position(rootElement, rootElement ? rootElement->childNodeCount() : 0);
-}
-
 Position Position::upstream(EStayInBlock stayInBlock) const
 {
     Position start = equivalentDeepPosition();
index fedcb287436960fd9e60547b33da8d6acf975469..6a53f7870d68ab74605732268eea0039c707299b 100644 (file)
@@ -59,9 +59,6 @@ public:
     ElementImpl *element() const;
     CSSComputedStyleDeclarationImpl *computedStyle() const;
 
-    Position previousLinePosition(int x, khtml::EAffinity) const;
-    Position nextLinePosition(int x, khtml::EAffinity) const;
-
     Position leadingWhitespacePosition() const;
     Position trailingWhitespacePosition() const;
 
index 354b2a9157f49ab93e079ae51ed997289be448d3..951cb0123d732986bfc9bf5bacf4c84f110bfdda 100644 (file)
@@ -85,6 +85,7 @@ using DOM::NodeImpl;
 using DOM::Position;
 using DOM::Range;
 
+using khtml::EAffinity;
 using khtml::EVerticalAlign;
 using khtml::plainText;
 using khtml::RenderBlock;
@@ -499,8 +500,14 @@ extern "C" void NSAccessibilityUnregisterUniqueIdForUIElement(id element);
         if (!docPart)
             return nil;
         
-        VisiblePosition startVisiblePosition = VisiblePosition(m_renderer->positionForCoordinates (0, 0, nil));
-        VisiblePosition endVisiblePosition   = VisiblePosition(m_renderer->positionForCoordinates (LONG_MAX, LONG_MAX, nil));
+        // FIXME: should use startOfDocument and endOfDocument here
+        EAffinity startAffinity;
+        Position startPos = m_renderer->positionForCoordinates (0, 0, &startAffinity);
+        EAffinity endAffinity;
+        Position endPos = m_renderer->positionForCoordinates (LONG_MAX, LONG_MAX, &endAffinity);
+
+        VisiblePosition startVisiblePosition = VisiblePosition(startPos, startAffinity);
+        VisiblePosition endVisiblePosition   = VisiblePosition(endPos, endAffinity);
         QString qString   = plainText(makeRange(startVisiblePosition, endVisiblePosition));
         
         // transform it to a CFString and return that
@@ -811,11 +818,8 @@ static QRect boundingBoxRect(RenderObject* obj)
 
 - (VisiblePosition) visiblePositionForStartOfTextMarkerRange: (AXTextMarkerRangeRef)textMarkerRange
 {
-    AXTextMarkerRef textMarker;
-    VisiblePosition visiblePos;
-
-    textMarker = [self AXTextMarkerRangeCopyStartMarkerWrapper:textMarkerRange];
-    visiblePos = [self visiblePositionForTextMarker:textMarker];
+    AXTextMarkerRef textMarker = [self AXTextMarkerRangeCopyStartMarkerWrapper:textMarkerRange];
+    VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
     if (textMarker)
         CFRelease(textMarker);
     return visiblePos;
@@ -823,11 +827,8 @@ static QRect boundingBoxRect(RenderObject* obj)
 
 - (VisiblePosition) visiblePositionForEndOfTextMarkerRange: (AXTextMarkerRangeRef) textMarkerRange
 {
-    AXTextMarkerRef textMarker;
-    VisiblePosition visiblePos;
-    
-    textMarker = [self AXTextMarkerRangeCopyEndMarkerWrapper:textMarkerRange];
-    visiblePos = [self visiblePositionForTextMarker:textMarker];
+    AXTextMarkerRef textMarker = [self AXTextMarkerRangeCopyEndMarkerWrapper:textMarkerRange];
+    VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
     if (textMarker)
         CFRelease(textMarker);
     return visiblePos;
@@ -967,17 +968,23 @@ static QRect boundingBoxRect(RenderObject* obj)
         }
             
         // return a marker range for the selection start to end
-        VisiblePosition startPosition = VisiblePosition(sel.start());
-        VisiblePosition endPosition = VisiblePosition(sel.end());
+        VisiblePosition startPosition = VisiblePosition(sel.start(), sel.startAffinity());
+        VisiblePosition endPosition = VisiblePosition(sel.end(), sel.endAffinity());
         return (id) [self textMarkerRangeFromVisiblePositions:startPosition andEndPos:endPosition];
     }
     
     if ([attributeName isEqualToString: (NSString *) kAXStartTextMarkerAttribute]) {
-        return (id) [self textMarkerForVisiblePosition: VisiblePosition([self topRenderer]->positionForCoordinates (0, 0, nil))];
+        // FIXME: should use startOfDocument here
+        EAffinity startAffinity;
+        Position startPos = [self topRenderer]->positionForCoordinates (0, 0, &startAffinity);
+        return (id) [self textMarkerForVisiblePosition: VisiblePosition(startPos, startAffinity)];
     }
 
     if ([attributeName isEqualToString: (NSString *) kAXEndTextMarkerAttribute]) {
-        return (id) [self textMarkerForVisiblePosition: VisiblePosition([self topRenderer]->positionForCoordinates (LONG_MAX, LONG_MAX, nil))];
+        // FIXME: should use endOfDocument here
+        EAffinity endAffinity;
+        Position endPos = [self topRenderer]->positionForCoordinates (LONG_MAX, LONG_MAX, &endAffinity);
+        return (id) [self textMarkerForVisiblePosition: VisiblePosition(endPos, endAffinity)];
     }
 #endif
 
@@ -1052,7 +1059,6 @@ static QRect boundingBoxRect(RenderObject* obj)
     // previousLinePosition returns nil, so the count is accurate.
     // NOTE: BUG This only takes us to the top of the rootEditableElement, not the top of the
     // top document.
-    // NOTE: Can we use Selection::modify(EAlter alter, int verticalDistance)?
     while (visiblePos.isNotNull() && visiblePos != savedVisiblePos) {
         lineCount += 1;
         savedVisiblePos = visiblePos;
@@ -1070,11 +1076,13 @@ static QRect boundingBoxRect(RenderObject* obj)
     // iterate over the lines
     // NOTE: BUG this is wrong when lineNumber is lineCount+1,  because nextLinePosition takes you to the
     // last offset of the last line
-    VisiblePosition visiblePos = VisiblePosition([self topRenderer]->positionForCoordinates (0, 0, nil));
+    EAffinity affinity;
+    Position pos = [self topRenderer]->positionForCoordinates (0, 0, &affinity);
+    VisiblePosition visiblePos = VisiblePosition(pos, affinity);
     VisiblePosition savedVisiblePos;
     while (--lineCount != 0) {
         savedVisiblePos = visiblePos;
-        visiblePos = nextLinePosition(visiblePos, khtml::DOWNSTREAM, 0);
+        visiblePos = nextLinePosition(visiblePos, visiblePos.affinity(), 0);
         if (visiblePos.isNull() || visiblePos == savedVisiblePos)
             return nil;
     }
@@ -1087,8 +1095,8 @@ static QRect boundingBoxRect(RenderObject* obj)
     (void)sel.modify(Selection::EXTEND, Selection::RIGHT, khtml::LINE_BOUNDARY);
 
     // return a marker range for the selection start to end
-    VisiblePosition startPosition = VisiblePosition(sel.start());
-    VisiblePosition endPosition = VisiblePosition(sel.end());
+    VisiblePosition startPosition = VisiblePosition(sel.start(), sel.startAffinity());
+    VisiblePosition endPosition = VisiblePosition(sel.end(), sel.endAffinity());
     return (id) [self textMarkerRangeFromVisiblePositions:startPosition andEndPos:endPosition];
 }
 
@@ -1117,8 +1125,9 @@ static QRect boundingBoxRect(RenderObject* obj)
     NSPoint windowpoint = [[view window] convertScreenToBase: screenpoint];
     NSPoint ourpoint = [view convertPoint:windowpoint fromView:nil];
 
-    VisiblePosition visiblePos = VisiblePosition([self topRenderer]->positionForCoordinates ((int)ourpoint.x, (int)ourpoint.y, nil));
-    return (id) [self textMarkerForVisiblePosition:visiblePos];
+    EAffinity affinity;
+    Position pos = [self topRenderer]->positionForCoordinates ((int)ourpoint.x, (int)ourpoint.y, &affinity);
+    return (id) [self textMarkerForVisiblePosition:VisiblePosition(pos, affinity)];
 }
 
 - (id)doAXBoundsForTextMarkerRange: (AXTextMarkerRangeRef) textMarkerRange
@@ -1469,8 +1478,6 @@ static void AXAttributedStringAppendReplaced (NSMutableAttributedString *attrStr
 
 - (id)doAXLeftLineTextMarkerRangeForTextMarker: (AXTextMarkerRef) textMarker
 {
-    // use Selection class instead of visible_units because startOfLine and endOfLine
-    // are declared but not defined
     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
     if (visiblePos.isNull())
         return nil;
@@ -1481,24 +1488,13 @@ static void AXAttributedStringAppendReplaced (NSMutableAttributedString *attrStr
     if (prevVisiblePos.isNull())
         return nil;
     
-    // extend selection to the line
-    // NOTE: ignores results of sel.modify because it returns false when
-    // starting at an empty line.  The resulting selection in that case
-    // will be a caret at prevVisiblePos. 
-    Selection sel = Selection(prevVisiblePos, prevVisiblePos);
-    (void)sel.modify(Selection::MOVE, Selection::LEFT, khtml::LINE_BOUNDARY);
-    (void)sel.modify(Selection::EXTEND, Selection::RIGHT, khtml::LINE_BOUNDARY);
-
-    // return a marker range for the selection start to end
-    VisiblePosition startPosition = VisiblePosition(sel.start());
-    VisiblePosition endPosition = VisiblePosition(sel.end());
+    VisiblePosition startPosition = startOfLine(prevVisiblePos, prevVisiblePos.affinity());
+    VisiblePosition endPosition = endOfLine(prevVisiblePos, prevVisiblePos.affinity());
     return (id) [self textMarkerRangeFromVisiblePositions:startPosition andEndPos:endPosition];
 }
 
 - (id)doAXRightLineTextMarkerRangeForTextMarker: (AXTextMarkerRef) textMarker
 {
-    // use Selection class instead of visible_units because startOfLine and endOfLine
-    // are declared but not defined
     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
     if (visiblePos.isNull())
         return nil;
@@ -1508,17 +1504,8 @@ static void AXAttributedStringAppendReplaced (NSMutableAttributedString *attrStr
     if (nextVisiblePos.isNull())
         return nil;
         
-    // make a caret selection and extend it to the line
-    // NOTE: ignores results of sel.modify because it returns false when
-    // starting at an empty line.  The resulting selection in that case
-    // will be a caret at nextVisiblePos. 
-    Selection sel = Selection(nextVisiblePos, nextVisiblePos);
-    (void)sel.modify(Selection::MOVE, Selection::LEFT, khtml::LINE_BOUNDARY);
-    (void)sel.modify(Selection::EXTEND, Selection::RIGHT, khtml::LINE_BOUNDARY);
-
-    // return a marker range for the selection start to end
-    VisiblePosition startPosition = VisiblePosition(sel.start());
-    VisiblePosition endPosition = VisiblePosition(sel.end());
+    VisiblePosition startPosition = startOfLine(nextVisiblePos, nextVisiblePos.affinity());
+    VisiblePosition endPosition = endOfLine(nextVisiblePos, nextVisiblePos.affinity());
     return (id) [self textMarkerRangeFromVisiblePositions:startPosition andEndPos:endPosition];
 }
 
@@ -1554,7 +1541,7 @@ static void AXAttributedStringAppendReplaced (NSMutableAttributedString *attrStr
         return nil;
 
     VisiblePosition endPosition = endOfWord(visiblePos, khtml::RightWordIfOnBoundary);
-    return (id) [self textMarkerForVisiblePosition: endPosition];
+    return (id) [self textMarkerForVisiblePosition:endPosition];
 }
 
 - (id)doAXPreviousWordStartTextMarkerForTextMarker: (AXTextMarkerRef) textMarker
@@ -1569,13 +1556,11 @@ static void AXAttributedStringAppendReplaced (NSMutableAttributedString *attrStr
         return nil;
     
     VisiblePosition startPosition = startOfWord(visiblePos, khtml::LeftWordIfOnBoundary);
-    return (id) [self textMarkerForVisiblePosition: startPosition];
+    return (id) [self textMarkerForVisiblePosition:startPosition];
 }
 
 - (id)doAXNextLineEndTextMarkerForTextMarker: (AXTextMarkerRef) textMarker
 {
-    // use Selection class instead of visible_units because startOfLine and endOfLine
-    // are declared but not defined
     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
     if (visiblePos.isNull())
         return nil;
@@ -1585,22 +1570,12 @@ static void AXAttributedStringAppendReplaced (NSMutableAttributedString *attrStr
     if (nextVisiblePos.isNull())
         return nil;
         
-    // make caret selection and extend it to the line
-    // NOTE: ignores results of sel.modify because it returns false when
-    // starting at an empty line.  The resulting selection in that case
-    // will be a caret at nextVisiblePos. 
-    Selection sel = Selection(nextVisiblePos, nextVisiblePos);
-    (void)sel.modify(Selection::MOVE, Selection::RIGHT, khtml::LINE_BOUNDARY);
-
-    // return a marker for the selection end
-    VisiblePosition endPosition = VisiblePosition(sel.end());
+    VisiblePosition endPosition = endOfLine(nextVisiblePos, nextVisiblePos.affinity());
     return (id) [self textMarkerForVisiblePosition: endPosition];
 }
 
 - (id)doAXPreviousLineStartTextMarkerForTextMarker: (AXTextMarkerRef) textMarker
 {
-    // use Selection class instead of visible_units because startOfLine and endOfLine
-    // are declared but not defined
     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
     if (visiblePos.isNull())
         return nil;
@@ -1610,15 +1585,7 @@ static void AXAttributedStringAppendReplaced (NSMutableAttributedString *attrStr
     if (prevVisiblePos.isNull())
         return nil;
         
-    // make a caret selection and extend it to the line
-    // NOTE: ignores results of sel.modify because it returns false when
-    // starting at an empty line.  The resulting selection in that case
-    // will be a caret at prevVisiblePos. 
-    Selection sel = Selection(prevVisiblePos, prevVisiblePos);
-    (void)sel.modify(Selection::MOVE, Selection::LEFT, khtml::LINE_BOUNDARY);
-
-    // return a marker for the selection start
-    VisiblePosition startPosition = VisiblePosition(sel.start());
+    VisiblePosition startPosition = startOfLine(prevVisiblePos, prevVisiblePos.affinity());
     return (id) [self textMarkerForVisiblePosition: startPosition];
 }
 
@@ -1911,14 +1878,12 @@ static void AXAttributedStringAppendReplaced (NSMutableAttributedString *attrStr
 #else
 - (void)doSetAXSelectedTextMarkerRange: (AXTextMarkerRangeRef)textMarkerRange
 {
-    VisiblePosition startVisiblePosition, endVisiblePosition;
-    
     // extract the start and end VisiblePosition
-    startVisiblePosition = [self visiblePositionForStartOfTextMarkerRange: textMarkerRange];
+    VisiblePosition startVisiblePosition = [self visiblePositionForStartOfTextMarkerRange: textMarkerRange];
     if (startVisiblePosition.isNull())
         return;
     
-    endVisiblePosition = [self visiblePositionForEndOfTextMarkerRange: textMarkerRange];
+    VisiblePosition endVisiblePosition = [self visiblePositionForEndOfTextMarkerRange: textMarkerRange];
     if (endVisiblePosition.isNull())
         return;
     
index 27b1b3c5ba622ee89ac7aae26fb61e7d9ca55c43..9877b0faacc47db25a6805932dc884e1f1920722 100644 (file)
@@ -31,6 +31,7 @@
 #include <qstring.h>
 #include <render_object.h>
 
+using khtml::EAffinity;
 using khtml::RenderObject;
 using khtml::VisiblePosition;
 
@@ -42,6 +43,7 @@ typedef struct KWQTextMarkerData  {
     KWQAccObjectID  accObjectID;
     DOM::NodeImpl*  nodeImpl;
     int             offset;
+    EAffinity       affinity;
 };
 
 KWQAccObjectCache::KWQAccObjectCache()
@@ -160,7 +162,6 @@ AXTextMarkerRef   KWQAccObjectCache::textMarkerForVisiblePosition (const Visible
     KWQTextMarkerData   textMarkerData;
     AXTextMarkerRef     textMarker = NULL;    
 
-    // NOTE: always appropriate to use deepEquivalent?
     DOM::Position deepPos = visiblePos.deepEquivalent();
     DOM::NodeImpl* domNode = deepPos.node();
     if (domNode == NULL) {
@@ -179,6 +180,7 @@ AXTextMarkerRef   KWQAccObjectCache::textMarkerForVisiblePosition (const Visible
     textMarkerData.accObjectID = getAccObjectID(accObject);
     textMarkerData.nodeImpl = domNode;
     textMarkerData.offset = deepPos.offset();
+    textMarkerData.affinity = visiblePos.affinity();
     textMarker = AXTextMarkerCreate(NULL, (const UInt8*)&textMarkerData, sizeof(textMarkerData));
 
     // autorelease it because we will never see it again
@@ -210,7 +212,7 @@ VisiblePosition   KWQAccObjectCache::visiblePositionForTextMarker (AXTextMarkerR
         return VisiblePosition();
 
     // return the position from the data we stored earlier
-    return VisiblePosition(textMarkerData->nodeImpl, textMarkerData->offset);
+    return VisiblePosition(textMarkerData->nodeImpl, textMarkerData->offset, textMarkerData->affinity);
 }
 #endif
 
index 697eb5fce104e2e5a35a50c46e5e181e69b3c225..93acd4d9489229435c7fe47fe9aa014321e55d66 100644 (file)
@@ -144,6 +144,7 @@ using khtml::startOfWord;
 using khtml::startVisiblePosition;
 using khtml::StyleDashboardRegion;
 using khtml::TextIterator;
+using khtml::DOWNSTREAM;
 using khtml::UPSTREAM;
 using khtml::VISIBLE;
 using khtml::VisiblePosition;
@@ -603,9 +604,9 @@ bool KWQKHTMLPart::findString(NSString *string, bool forward, bool caseFlag, boo
     searchRange.selectNodeContents(xmlDocImpl());
     if (selectionStart()) {
         if (forward) {
-            setStart(searchRange, VisiblePosition(selection().end()));
+            setStart(searchRange, VisiblePosition(selection().end(), selection().endAffinity()));
         } else {
-            setEnd(searchRange, VisiblePosition(selection().start()));
+            setEnd(searchRange, VisiblePosition(selection().start(), selection().startAffinity()));
         }
     }
 
@@ -625,7 +626,7 @@ bool KWQKHTMLPart::findString(NSString *string, bool forward, bool caseFlag, boo
         return false;
     }
 
-    setSelection(resultRange);
+    setSelection(Selection(resultRange, DOWNSTREAM, khtml::SEL_PREFER_UPSTREAM_AFFINITY));
     jumpToSelection();
     return true;
 }
@@ -928,12 +929,12 @@ QString KWQKHTMLPart::advanceToNextMisspelling(bool startBeforeSelection)
     if (selectionStart()) {
         startedWithSelection = true;
         if (startBeforeSelection) {
-            VisiblePosition start(selection().start());
+            VisiblePosition start(selection().start(), selection().startAffinity());
             // We match AppKit's rule: Start 1 character before the selection.
             VisiblePosition oneBeforeStart = start.previous();
             setStart(searchRange, oneBeforeStart.isNotNull() ? oneBeforeStart : start);
         } else {
-            setStart(searchRange, VisiblePosition(selection().end()));
+            setStart(searchRange, VisiblePosition(selection().end(), selection().endAffinity()));
         }
     }
 
@@ -955,7 +956,7 @@ QString KWQKHTMLPart::advanceToNextMisspelling(bool startBeforeSelection)
     // Make sure start of searchRange is not in the middle of a word.  Jumping back a char and then
     // forward by a word happens to do the trick.
     if (startedWithSelection) {
-        VisiblePosition oneBeforeStart = startVisiblePosition(searchRange).previous();
+        VisiblePosition oneBeforeStart = startVisiblePosition(searchRange, DOWNSTREAM).previous();
         if (oneBeforeStart.isNotNull()) {
             setStart(searchRange, endOfWord(oneBeforeStart));
         } // else we were already at the start of the editable node
@@ -993,7 +994,7 @@ QString KWQKHTMLPart::advanceToNextMisspelling(bool startBeforeSelection)
                     QString result = chars.string(misspelling.length);
                     misspellingRange.setEnd(chars.range().startContainer(), chars.range().startOffset());
 
-                    setSelection(misspellingRange);
+                    setSelection(Selection(misspellingRange, DOWNSTREAM, khtml::SEL_PREFER_UPSTREAM_AFFINITY));
                     jumpToSelection();
                     // Mark misspelling in document.
                     xmlDocImpl()->addMarker(misspellingRange, DocumentMarker::Spelling);
@@ -3444,7 +3445,7 @@ RenderStyle *KWQKHTMLPart::styleForSelectionStart(NodeImpl *&nodeToRemove) const
     if (d->m_selection.isNone())
         return 0;
     
-    Position pos = VisiblePosition(d->m_selection.start(), UPSTREAM).deepEquivalent();
+    Position pos = VisiblePosition(d->m_selection.start(), d->m_selection.startAffinity(), khtml::VisiblePosition::INIT_UP).deepEquivalent();
     if (!pos.inRenderedContent())
         return 0;
     NodeImpl *node = pos.node();
@@ -3586,7 +3587,7 @@ NSWritingDirection KWQKHTMLPart::baseWritingDirectionForSelectionStart() const
 {
     NSWritingDirection result = NSWritingDirectionLeftToRight;
 
-    Position pos = VisiblePosition(d->m_selection.start()).deepEquivalent();
+    Position pos = VisiblePosition(d->m_selection.start(), d->m_selection.startAffinity()).deepEquivalent();
     NodeImpl *node = pos.node();
     if (!node || !node->renderer() || !node->renderer()->containingBlock())
         return result;
@@ -3679,7 +3680,7 @@ void KWQKHTMLPart::setSelectionFromNone()
             node = node->traverseNextNode();
         }
         if (node)
-            setSelection(Position(node, 0));
+            setSelection(Selection(Position(node, 0), DOWNSTREAM));
     }
 }
 
@@ -4013,10 +4014,10 @@ void KWQKHTMLPart::respondToChangedSelection(const Selection &oldSelection, bool
 {
     if (xmlDocImpl()) {
         if ([_bridge isContinuousSpellCheckingEnabled]) {
-            VisiblePosition oldStart(oldSelection.start());
+            VisiblePosition oldStart(oldSelection.start(), oldSelection.startAffinity());
             Selection oldAdjacentWords(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary));
 
-            VisiblePosition newStart(selection().start());
+            VisiblePosition newStart(selection().start(), selection().startAffinity());
             Selection newAdjacentWords(startOfWord(newStart, LeftWordIfOnBoundary), endOfWord(newStart, RightWordIfOnBoundary));
 
             if (oldAdjacentWords != newAdjacentWords) {
index 8cca6b55ce04d2f8936b4e80fb0264e0862ecb25..56805901e2f4a48b60af726e0be31215f87c11f8 100644 (file)
@@ -1548,14 +1548,16 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
     
     _part->xmlDocImpl()->updateLayout();
 
+    EAffinity affinity = static_cast<EAffinity>(selectionAffinity);
+
     // Work around bug where isRenderedContent returns false for <br> elements at the ends of lines.
     // If that bug wasn't an issue, we could just make the position from the range directly.
     Position start(startContainer, [range startOffset]);
     Position end(endContainer, [range endOffset]);
-    start = VisiblePosition(start, UPSTREAM).deepEquivalent();
+    start = VisiblePosition(start, affinity, khtml::VisiblePosition::INIT_UP).deepEquivalent();
 
-    Selection selection(start, end);
-    selection.setAffinity(static_cast<EAffinity>(selectionAffinity));
+    // FIXME: Can we provide extentAffinity?
+    Selection selection(start, affinity, end, khtml::SEL_DEFAULT_AFFINITY);
     _part->setSelection(selection);
 }
 
@@ -1566,12 +1568,12 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
 
 - (NSSelectionAffinity)selectionAffinity
 {
-    return static_cast<NSSelectionAffinity>(_part->selection().affinity());
+    return static_cast<NSSelectionAffinity>(_part->selection().startAffinity());
 }
 
 - (void)setMarkDOMRange:(DOMRange *)range
 {
-    _part->setMark(Selection([range _rangeImpl]));
+    _part->setMark(Selection([range _rangeImpl], khtml::SEL_DEFAULT_AFFINITY, khtml::SEL_DEFAULT_AFFINITY));
 }
 
 - (DOMRange *)markDOMRange
@@ -1680,24 +1682,27 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
     EditCommandPtr(new MoveSelectionCommand(_part->xmlDocImpl(), [selectionFragment _fragmentImpl], base, smartMove)).apply();
 }
 
-- (Position)_positionForPoint:(NSPoint)point
+- (VisiblePosition)_visiblePositionForPoint:(NSPoint)point
 {
     RenderObject *renderer = _part->renderer();
     if (!renderer) {
-        return Position();
+        return VisiblePosition();
     }
     
     RenderObject::NodeInfo nodeInfo(true, true);
     renderer->layer()->hitTest(nodeInfo, (int)point.x, (int)point.y);
     NodeImpl *node = nodeInfo.innerNode();
     if (!node->renderer())
-        return Position();
-    return node->renderer()->positionForCoordinates((int)point.x, (int)point.y);
+        return VisiblePosition();
+    
+    EAffinity affinity;
+    Position pos = node->renderer()->positionForCoordinates((int)point.x, (int)point.y, &affinity);
+    return VisiblePosition(pos, affinity);
 }
 
 - (void)moveDragCaretToPoint:(NSPoint)point
-{    
-    Selection dragCaret([self _positionForPoint:point]);
+{   
+    Selection dragCaret([self _visiblePositionForPoint:point]);
     _part->setDragCaret(dragCaret);
 }
 
@@ -1713,7 +1718,7 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
 
 - (DOMRange *)editableDOMRangeForPoint:(NSPoint)point
 {
-    Position position = [self _positionForPoint:point];
+    VisiblePosition position = [self _visiblePositionForPoint:point];
     return position.isNull() ? nil : [DOMRange _rangeWithImpl:Selection(position).toRange().handle()];
 }
 
@@ -1848,7 +1853,7 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
     if (!documentView)
         return;
     
-    QRect extentRect = renderer->caretRect(extent.offset(), _part->selection().affinity());
+    QRect extentRect = renderer->caretRect(extent.offset(), _part->selection().extentAffinity());
     if (!NSContainsRect([documentView visibleRect], NSRect(extentRect))) {
         v->ensureRectVisibleCentered(extentRect, true);
     }
@@ -2005,7 +2010,7 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
     if (!selection.isCaret())
         return nil;
 
-    VisiblePosition caret(selection.start());
+    VisiblePosition caret(selection.start(), selection.startAffinity());
     VisiblePosition next = caret.next();
     VisiblePosition previous = caret.previous();
     if (caret == next || caret == previous)