⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 266295 in webkit


Ignore:
Timestamp:
Aug 28, 2020, 2:37:08 PM (6 years ago)
Author:
Darin Adler
Message:

Remove almost all the remaining uses of live ranges
https://bugs.webkit.org/show_bug.cgi?id=215755

Reviewed by Sam Weinig.

Source/WebCore:

  • accessibility/AXObjectCache.cpp:

(WebCore::characterOffsetsInOrder): Use documentOrder.

  • accessibility/AccessibilityObject.cpp:

(WebCore::AccessibilityObject::misspellingRange const): Ditto.
(WebCore::rangeClosestToRange): Use characterCount. Also removed unnnecessary assertions
and special cases.
(WebCore::AccessibilityObject::rangeOfStringClosestToRangeInDirection const): Use documentOrder.

  • accessibility/AccessibilityRenderObject.cpp:

(WebCore::AccessibilityRenderObject::documentBasedSelectedTextRange const): Use intersects.
Also use firstRange instead of toNormalizedRange.

  • dom/Element.h: Export attachShadow so it can be used in unit tests.
  • dom/Node.cpp:

(WebCore::depthInComposedTree): Renamed and changed to use parentInComposedTree
instead of parentOrShadowHostNode to handle cases involving assigned slots correctly.
(WebCore::commonInclusiveAncestorAndChildren): Ditto.
(WebCore::isSiblingSubsequent): Added assertions.
(WebCore::documentOrder): Add logic so shadow roots are ordered before the
other children of their hosts in cases that don't involve assigned slots.
Without this the results would be inconsistent based on the order of the
arguments passed to documentOrder.

  • dom/Node.h: Added is_neq, is_lteq, and is_gteq for use with PartialOrdering,

matching the names and behavior from C++20.

  • dom/Range.cpp: Removed unused CoordinateSpace.

(WebCore::Range::Range): Updated since RangeBoundaryPoint now uses references.
(WebCore::Range::updateDocument): Renamed from setDocument and changed so that
it maintains the invariants without requiring the caller pass any arguments.
Also updated for RangeBoundaryPoint anme changes.
(WebCore::Range::compareBoundaryPoints): Deleted.
(WebCore::checkForDifferentRootContainer): Deleted.
(WebCore::Range::setStart): Updated for checkNodeOffsetPair name change.
Removed too-complex code for moving between documents. Use documentOrder
instead of checkForDifferentRootContainer to check for start/end that have
incorrect order or no common ancestor. Use updateDocument.
(WebCore::Range::setEnd): Ditto.
(WebCore::Range::isPointInRange): Use isPointInRange that takes a SimpleRange.
Also updated for checkNodeOffsetPair name change.
(WebCore::Range::comparePoint const): Use documentOrder. Ditto.
(WebCore::Range::compareNode const): Use documentOrder.
(WebCore::top): Deleted.
(WebCore::Range::compareBoundaryPoints const): Deleted more overloads.
Kept only the one needed for bindings, and renamed it from
compareBoundaryPointsForBindings. Also fixed the implementatin to be simpler,
use documentOrder, and match the DOM specification more closely (without a
behavior change).
(WebCore::Range::boundaryPointsValid const): Deleted.
(WebCore::Range::intersectsNode const): Use intersects from SimpleRange.
Also don't raise exceptions.
(WebCore::lengthOfContentsInNode): Deleted. This gives the same result as
Node::length, but less efficiently.
(WebCore::Range::processContents): Updated since RangeBoundaryPoint now
uses references.
(WebCore::processContentsBetweenOffsets): Removed obsolete comment.
(WebCore::Range::toString const): Use intersectingNodes and
characterDataOffsetRange.
(WebCore::Range::text const): Deleted.
(WebCore::Range::detach): Moved to the header.
(WebCore::Range::checkNodeOffsetPair const): Rneamed from checkNodeWOffset.
(WebCore::Range::cloneRange): Use m_ownerDocument.
(WebCore::Range::setStartAfter): Tweaked coding style.
(WebCore::Range::setEndBefore): Ditto.
(WebCore::Range::setEndAfter): Ditto.
(WebCore::Range::selectNode): Ditto. Also removed unnecessary code to
call setDocument, since setStart takes care of that.
(WebCore::Range::selectNodeContents): Ditto.
(WebCore::Range::setStartBefore): Ditto.
(WebCore::Range::firstNode const): Deleted.
(WebCore::Range::pastLastNode const): Deleted.
(WebCore::Range::contains const): Deleted.
(WebCore::areRangesEqual): Deleted.
(WebCore::rangesOverlap): Deleted.
(WebCore::boundaryNodeChildrenChanged): Tweaked coding style and updated
since RangeBoundaryPoint uses a reference.
(WebCore::Range::nodeChildrenChanged): Use m_ownerDocument.
(WebCore::boundaryNodeChildrenWillBeRemoved): Removed unneeded code
to handle case where one of the children is the childBefore but the
node is not inside the container -- that case doesn't exist. Use
Node::contains.
(WebCore::Range::nodeChildrenWillBeRemoved): Use m_ownerDocument.
(WebCore::boundaryNodeWillBeRemoved): Simplify logic using
Range::contains.
(WebCore::Range::nodeWillBeRemoved): Use m_ownerDocument.
(WebCore::Range::parentlessNodeMovedToNewDocumentAffectsRange):
Updated since RangeBoundaryPoint uses a reference.
(WebCore::boundaryTextInserted): Ditto.
(WebCore::boundaryTextRemoved): Ditto.
(WebCore::boundaryTextNodesMerged): Ditto.
(WebCore::boundaryTextNodesSplit): Ditto.
(showTree): Removed call to boundaryPointsValid. That's checking something
the class already treats as an invariant, so it's obsolete code left from
long ago when we didn't have that implemented correctly.

  • dom/Range.h: Reorganized the header to match the IDL file.

Removed ownerDocument, compareBoundaryPoints overloads other than the one
used from bindings, firstNode, pastLastNode, text, contains, areRangesEqual,
and rangesOverlap. Also updated since RangeBoundaryPoint::container is now
a reference. Moved detach function here to the header as an empty inline.

  • dom/Range.idl: Changed start/endOffset to unsigned. Stopped using the

name compareBoundaryPointersForBindings. Updated intersectsNode to not
throw exceptions as called for in the DOM specification. Tweaked comments.

  • dom/RangeBoundaryPoint.h: Changed constructor argument to a reference.

Renamed setToBeforeChild, setToAfterChild, setToStartOfNode, and setToEndOfNode
to setToBeforeNode, setToAfterNode, setToBeforeContents, setToAfterContents.
Merged ensureOffsetIsValid into the offset function. Changed m_containerNode
into a Ref<> and renamed it m_container. Removed clear.

  • dom/SimpleRange.cpp:

(WebCore::isOffsetBeforeChild): Add logic so shadow roots are ordered after offset
0 but before offset 1 in their hosts in cases that don't involve assigned slots.
This is an arbitrary choice, but is consistent with how we order shadow roots before
other child nodes.
(WebCore::documentOrder): Use parentInComposedTree instead of parentOrShadowHostNode
to handle cases involving assigned slots correctly.
(WebCore::isPointInRange): Added.
(WebCore::documentOrder): Added.
(WebCore::contains): Added.
(WebCore::intersects): Added.
(WebCore::unionRange): Added.

  • dom/SimpleRange.h: Updated for above.
  • editing/Editing.cpp:

(WebCore::comparePositions): Use documentOrder.
(WebCore::isNodeVisiblyContainedWithin): Use contains.

  • editing/Editor.cpp:

(WebCore::isFrameInRange): Use intersects.
(WebCore::Editor::scanSelectionForTelephoneNumbers): Use intersects.

  • editing/EditorCommand.cpp:

(WebCore::unionRanges): Moved to SimpleRange.cpp, where it's now
implemented using documentOrder.
(WebCore::executeDeleteToMark): Updated name to unionRange.
(WebCore::executeSelectToMark): Ditto.

  • editing/FrameSelection.cpp:

(WebCore::FrameSelection::respondToNodeModification): Use intersects.

  • editing/mac/DictionaryLookupLegacy.mm:

(WebCore::selectionContainsPosition): Use isPointInRange.

  • page/DOMSelection.cpp:

(WebCore::DOMSelection::extend): Use makeRefPtr and Node::length
to streamline the implementation.
(WebCore::DOMSelection::getRangeAt): Use makeBoundaryPointBeforeNode
and remove unneeded null check that's already covered above.
(WebCore::DOMSelection::addRange): Use intersects and unionRange.
(WebCore::DOMSelection::containsNode const): Use intersects and contains.
(WebCore::DOMSelection::isValidForPosition const): Use boolean logic.

  • page/DragController.cpp:

(WebCore::DragController::draggableElement const): Use contains.
(WebCore::DragController::insertDroppedImagePlaceholdersAtCaret): Use intersects.

  • page/EventHandler.cpp:

(WebCore::EventHandler::dispatchMouseEvent): Use contains.

  • page/Page.cpp:

(WebCore::Page::findTextMatches): Use documentOrder.

  • page/mac/ServicesOverlayController.mm:

(WebCore::ServicesOverlayController::findTelephoneNumberHighlightContainingSelectionHighlight):
Use contains.

  • testing/Internals.cpp:

(WebCore::Internals::rangeAsText): Use plainText.
(WebCore::join): Added.
(WebCore::Internals::rangeAsTextUsingBackwardsTextIterator): Use a vector
that we reverse and join rather than inserting at the start of a string.
(WebCore::Internals::subrange): Added a call to updateLayout since text iterator
functions depend on the state of the render tree. Realized this was theoretically
needed because of Internals::rangeAsText.
(WebCore::Internals::rangeOfStringNearLocation): Ditto.

Source/WebKit:

  • WebProcess/InjectedBundle/API/gtk/DOM/WebKitDOMRange.cpp:

(webkit_dom_range_compare_boundary_points): Update for rename of
compareBoundaryPointsForBindings.
(webkit_dom_range_intersects_node): Removed exception handling.
(webkit_dom_range_get_text): Use plainText.

  • WebProcess/InjectedBundle/API/mac/WKDOMRange.mm:

(-[WKDOMRange initWithDocument:]): Tightened up into a one-liner.
(-[WKDOMRange text]): Use plainText.
(-[WKDOMRange textRects]): Stopped using Range::ownerDocument.

  • WebProcess/InjectedBundle/DOM/InjectedBundleRangeHandle.cpp:

(WebKit::InjectedBundleRangeHandle::document): Stopped using
Range::ownerDocument.
(WebKit::InjectedBundleRangeHandle::boundingRectInWindowCoordinates const):
Ditto.
(WebKit::InjectedBundleRangeHandle::renderedImage): Ditto.
(WebKit::InjectedBundleRangeHandle::text const): Use plainText.

  • WebProcess/WebPage/glib/WebPageGLib.cpp:

(WebKit::WebPage::getPlatformEditorState const): Use contains.

  • WebProcess/WebPage/ios/WebPageIOS.mm:

(WebKit::WebPage::requestDocumentEditingContext): Use intersects.

Source/WebKitLegacy/mac:

  • DOM/DOMRange.mm:

(-[DOMRange text]): Use plainText.
(-[DOMRange compareBoundaryPoints:sourceRange:]): Update for rename of
compareBoundaryPointsForBindings.
(-[DOMRange intersectsNode:]): Removed raiseOnDOMError.

  • DOM/DOMUIKitExtensions.mm:

(firstNodeAfter): Moved Range::firstNode here since it's the only remaining caller;
might need to keep legacy behavior depending on how this is used by UIKit.
(-[DOMRange firstNode]): Call firstNodeAfter.

  • DOM/WebDOMOperations.mm:

(-[DOMRange markupString]): Stop using Range::ownerDocument.

Tools:

  • TestWebKitAPI/Tests/WebCore/DocumentOrder.cpp:

(TestWebKitAPI::TEST): Added test cases for node ordering involving non-user-agent
shadow tree. Added test case that showed the old "use node order if offsets are equal"
rule for boundary point ordering was wrong. Added tests for isPointInRange,
intersects, and contains functions.

Location:
trunk
Files:
49 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r266293 r266295  
     12020-08-28  Darin Adler  <darin@apple.com>
     2
     3        Remove almost all the remaining uses of live ranges
     4        https://bugs.webkit.org/show_bug.cgi?id=215755
     5
     6        Reviewed by Sam Weinig.
     7
     8        * accessibility/AXObjectCache.cpp:
     9        (WebCore::characterOffsetsInOrder): Use documentOrder.
     10        * accessibility/AccessibilityObject.cpp:
     11        (WebCore::AccessibilityObject::misspellingRange const): Ditto.
     12        (WebCore::rangeClosestToRange): Use characterCount. Also removed unnnecessary assertions
     13        and special cases.
     14        (WebCore::AccessibilityObject::rangeOfStringClosestToRangeInDirection const): Use documentOrder.
     15        * accessibility/AccessibilityRenderObject.cpp:
     16        (WebCore::AccessibilityRenderObject::documentBasedSelectedTextRange const): Use intersects.
     17        Also use firstRange instead of toNormalizedRange.
     18
     19        * dom/Element.h: Export attachShadow so it can be used in unit tests.
     20
     21        * dom/Node.cpp:
     22        (WebCore::depthInComposedTree): Renamed and changed to use parentInComposedTree
     23        instead of parentOrShadowHostNode to handle cases involving assigned slots correctly.
     24        (WebCore::commonInclusiveAncestorAndChildren): Ditto.
     25        (WebCore::isSiblingSubsequent): Added assertions.
     26        (WebCore::documentOrder): Add logic so shadow roots are ordered before the
     27        other children of their hosts in cases that don't involve assigned slots.
     28        Without this the results would be inconsistent based on the order of the
     29        arguments passed to documentOrder.
     30
     31        * dom/Node.h: Added is_neq, is_lteq, and is_gteq for use with PartialOrdering,
     32        matching the names and behavior from C++20.
     33
     34        * dom/Range.cpp: Removed unused CoordinateSpace.
     35        (WebCore::Range::Range): Updated since RangeBoundaryPoint now uses references.
     36        (WebCore::Range::updateDocument): Renamed from setDocument and changed so that
     37        it maintains the invariants without requiring the caller pass any arguments.
     38        Also updated for RangeBoundaryPoint anme changes.
     39        (WebCore::Range::compareBoundaryPoints): Deleted.
     40        (WebCore::checkForDifferentRootContainer): Deleted.
     41        (WebCore::Range::setStart): Updated for checkNodeOffsetPair name change.
     42        Removed too-complex code for moving between documents. Use documentOrder
     43        instead of checkForDifferentRootContainer to check for start/end that have
     44        incorrect order or no common ancestor. Use updateDocument.
     45        (WebCore::Range::setEnd): Ditto.
     46        (WebCore::Range::isPointInRange): Use isPointInRange that takes a SimpleRange.
     47        Also updated for checkNodeOffsetPair name change.
     48        (WebCore::Range::comparePoint const): Use documentOrder. Ditto.
     49        (WebCore::Range::compareNode const): Use documentOrder.
     50        (WebCore::top): Deleted.
     51        (WebCore::Range::compareBoundaryPoints const): Deleted more overloads.
     52        Kept only the one needed for bindings, and renamed it from
     53        compareBoundaryPointsForBindings. Also fixed the implementatin to be simpler,
     54        use documentOrder, and match the DOM specification more closely (without a
     55        behavior change).
     56        (WebCore::Range::boundaryPointsValid const): Deleted.
     57        (WebCore::Range::intersectsNode const): Use intersects from SimpleRange.
     58        Also don't raise exceptions.
     59        (WebCore::lengthOfContentsInNode): Deleted. This gives the same result as
     60        Node::length, but less efficiently.
     61        (WebCore::Range::processContents): Updated since RangeBoundaryPoint now
     62        uses references.
     63        (WebCore::processContentsBetweenOffsets): Removed obsolete comment.
     64        (WebCore::Range::toString const): Use intersectingNodes and
     65        characterDataOffsetRange.
     66        (WebCore::Range::text const): Deleted.
     67        (WebCore::Range::detach): Moved to the header.
     68        (WebCore::Range::checkNodeOffsetPair const): Rneamed from checkNodeWOffset.
     69        (WebCore::Range::cloneRange): Use m_ownerDocument.
     70        (WebCore::Range::setStartAfter): Tweaked coding style.
     71        (WebCore::Range::setEndBefore): Ditto.
     72        (WebCore::Range::setEndAfter): Ditto.
     73        (WebCore::Range::selectNode): Ditto. Also removed unnecessary code to
     74        call setDocument, since setStart takes care of that.
     75        (WebCore::Range::selectNodeContents): Ditto.
     76        (WebCore::Range::setStartBefore): Ditto.
     77        (WebCore::Range::firstNode const): Deleted.
     78        (WebCore::Range::pastLastNode const): Deleted.
     79        (WebCore::Range::contains const): Deleted.
     80        (WebCore::areRangesEqual): Deleted.
     81        (WebCore::rangesOverlap): Deleted.
     82        (WebCore::boundaryNodeChildrenChanged): Tweaked coding style and updated
     83        since RangeBoundaryPoint uses a reference.
     84        (WebCore::Range::nodeChildrenChanged): Use m_ownerDocument.
     85        (WebCore::boundaryNodeChildrenWillBeRemoved): Removed unneeded code
     86        to handle case where one of the children is the childBefore but the
     87        node is not inside the container -- that case doesn't exist. Use
     88        Node::contains.
     89        (WebCore::Range::nodeChildrenWillBeRemoved): Use m_ownerDocument.
     90        (WebCore::boundaryNodeWillBeRemoved): Simplify logic using
     91        Range::contains.
     92        (WebCore::Range::nodeWillBeRemoved): Use m_ownerDocument.
     93        (WebCore::Range::parentlessNodeMovedToNewDocumentAffectsRange):
     94        Updated since RangeBoundaryPoint uses a reference.
     95        (WebCore::boundaryTextInserted): Ditto.
     96        (WebCore::boundaryTextRemoved): Ditto.
     97        (WebCore::boundaryTextNodesMerged): Ditto.
     98        (WebCore::boundaryTextNodesSplit): Ditto.
     99        (showTree): Removed call to boundaryPointsValid. That's checking something
     100        the class already treats as an invariant, so it's obsolete code left from
     101        long ago when we didn't have that implemented correctly.
     102
     103        * dom/Range.h: Reorganized the header to match the IDL file.
     104        Removed ownerDocument, compareBoundaryPoints overloads other than the one
     105        used from bindings, firstNode, pastLastNode, text, contains, areRangesEqual,
     106        and rangesOverlap. Also updated since RangeBoundaryPoint::container is now
     107        a reference. Moved detach function here to the header as an empty inline.
     108
     109        * dom/Range.idl: Changed start/endOffset to unsigned. Stopped using the
     110        name compareBoundaryPointersForBindings. Updated intersectsNode to not
     111        throw exceptions as called for in the DOM specification. Tweaked comments.
     112
     113        * dom/RangeBoundaryPoint.h: Changed constructor argument to a reference.
     114        Renamed setToBeforeChild, setToAfterChild, setToStartOfNode, and setToEndOfNode
     115        to setToBeforeNode, setToAfterNode, setToBeforeContents, setToAfterContents.
     116        Merged ensureOffsetIsValid into the offset function. Changed m_containerNode
     117        into a Ref<> and renamed it m_container. Removed clear.
     118
     119        * dom/SimpleRange.cpp:
     120        (WebCore::isOffsetBeforeChild): Add logic so shadow roots are ordered after offset
     121        0 but before offset 1 in their hosts in cases that don't involve assigned slots.
     122        This is an arbitrary choice, but is consistent with how we order shadow roots before
     123        other child nodes.
     124        (WebCore::documentOrder): Use parentInComposedTree instead of parentOrShadowHostNode
     125        to handle cases involving assigned slots correctly.
     126        (WebCore::isPointInRange): Added.
     127        (WebCore::documentOrder): Added.
     128        (WebCore::contains): Added.
     129        (WebCore::intersects): Added.
     130        (WebCore::unionRange): Added.
     131        * dom/SimpleRange.h: Updated for above.
     132
     133        * editing/Editing.cpp:
     134        (WebCore::comparePositions): Use documentOrder.
     135        (WebCore::isNodeVisiblyContainedWithin): Use contains.
     136        * editing/Editor.cpp:
     137        (WebCore::isFrameInRange): Use intersects.
     138        (WebCore::Editor::scanSelectionForTelephoneNumbers): Use intersects.
     139
     140        * editing/EditorCommand.cpp:
     141        (WebCore::unionRanges): Moved to SimpleRange.cpp, where it's now
     142        implemented using documentOrder.
     143        (WebCore::executeDeleteToMark): Updated name to unionRange.
     144        (WebCore::executeSelectToMark): Ditto.
     145
     146        * editing/FrameSelection.cpp:
     147        (WebCore::FrameSelection::respondToNodeModification): Use intersects.
     148
     149        * editing/mac/DictionaryLookupLegacy.mm:
     150        (WebCore::selectionContainsPosition): Use isPointInRange.
     151
     152        * page/DOMSelection.cpp:
     153        (WebCore::DOMSelection::extend): Use makeRefPtr and Node::length
     154        to streamline the implementation.
     155        (WebCore::DOMSelection::getRangeAt): Use makeBoundaryPointBeforeNode
     156        and remove unneeded null check that's already covered above.
     157        (WebCore::DOMSelection::addRange): Use intersects and unionRange.
     158        (WebCore::DOMSelection::containsNode const): Use intersects and contains.
     159        (WebCore::DOMSelection::isValidForPosition const): Use boolean logic.
     160
     161        * page/DragController.cpp:
     162        (WebCore::DragController::draggableElement const): Use contains.
     163        (WebCore::DragController::insertDroppedImagePlaceholdersAtCaret): Use intersects.
     164
     165        * page/EventHandler.cpp:
     166        (WebCore::EventHandler::dispatchMouseEvent): Use contains.
     167
     168        * page/Page.cpp:
     169        (WebCore::Page::findTextMatches): Use documentOrder.
     170
     171        * page/mac/ServicesOverlayController.mm:
     172        (WebCore::ServicesOverlayController::findTelephoneNumberHighlightContainingSelectionHighlight):
     173        Use contains.
     174
     175        * testing/Internals.cpp:
     176        (WebCore::Internals::rangeAsText): Use plainText.
     177        (WebCore::join): Added.
     178        (WebCore::Internals::rangeAsTextUsingBackwardsTextIterator): Use a vector
     179        that we reverse and join rather than inserting at the start of a string.
     180        (WebCore::Internals::subrange): Added a call to updateLayout since text iterator
     181        functions depend on the state of the render tree. Realized this was theoretically
     182        needed because of Internals::rangeAsText.
     183        (WebCore::Internals::rangeOfStringNearLocation): Ditto.
     184
    11852020-08-28  Chris Dumez  <cdumez@apple.com>
    2186
  • trunk/Source/WebCore/accessibility/AXObjectCache.cpp

    r266136 r266295  
    20372037static bool characterOffsetsInOrder(const CharacterOffset& characterOffset1, const CharacterOffset& characterOffset2)
    20382038{
     2039    // FIXME: Should just be able to call documentOrder without accessibility-specific logic. Not clear why we need CharacterOffset instead of Position or BoundaryPoint.
     2040
    20392041    if (characterOffset1.isNull() || characterOffset2.isNull())
    20402042        return false;
     
    20492051    if (!node2->isCharacterDataNode() && !isReplacedNodeOrBR(node2) && node2->hasChildNodes())
    20502052        node2 = node2->traverseToChildAt(characterOffset2.offset);
    2051    
    20522053    if (!node1 || !node2)
    20532054        return false;
     
    20552056    auto range1 = AXObjectCache::rangeForNodeContents(*node1);
    20562057    auto range2 = AXObjectCache::rangeForNodeContents(*node2);
    2057     auto result = createLiveRange(range1)->compareBoundaryPoints(Range::START_TO_START, createLiveRange(range2));
    2058     if (result.hasException())
    2059         return true;
    2060     return result.releaseReturnValue() <= 0;
     2058    return is_lteq(documentOrder(range1.start, range2.start));
    20612059}
    20622060
  • trunk/Source/WebCore/accessibility/AccessibilityObject.cpp

    r266207 r266295  
    298298    checkTextOfParagraph(*textChecker, stringValue(), TextCheckingType::Spelling, misspellings, frame->selection().selection());
    299299
    300     // The returned misspellings are assumed to be ordered in the document
    301     // logical order, which should be matched by Range::compareBoundaryPoints.
    302     // So iterate forward or backwards depending on the desired search
    303     // direction to find the closest misspelling in that direction.
     300    // Find the first misspelling past the start.
    304301    if (direction == AccessibilitySearchDirection::Next) {
    305         for (const auto& misspelling : misspellings) {
     302        for (auto& misspelling : misspellings) {
    306303            auto misspellingRange = editor.rangeForTextCheckingResult(misspelling);
    307             if (!misspellingRange)
    308                 continue;
    309 
    310             if (createLiveRange(*misspellingRange)->compareBoundaryPoints(Range::END_TO_END, createLiveRange(start)).releaseReturnValue() > 0)
     304            if (misspellingRange && is_gt(documentOrder(misspellingRange->end, start.end)))
    311305                return *misspellingRange;
    312306        }
    313     } else if (direction == AccessibilitySearchDirection::Previous) {
    314         for (auto rit = misspellings.rbegin(); rit != misspellings.rend(); ++rit) {
    315             auto misspellingRange = editor.rangeForTextCheckingResult(*rit);
    316             if (!misspellingRange)
    317                 continue;
    318 
    319             if (createLiveRange(*misspellingRange)->compareBoundaryPoints(Range::START_TO_START, createLiveRange(start)).releaseReturnValue() < 0)
     307    } else {
     308        for (auto& misspelling : makeReversedRange(misspellings)) {
     309            auto misspellingRange = editor.rangeForTextCheckingResult(misspelling);
     310            if (misspellingRange && is_lt(documentOrder(misspellingRange->start, start.start)))
    320311                return *misspellingRange;
    321312        }
     
    566557static Optional<SimpleRange> rangeClosestToRange(const SimpleRange& referenceRange, Optional<SimpleRange>&& afterRange, Optional<SimpleRange>&& beforeRange)
    567558{
    568     // The treeScope for shadow nodes may not be the same scope as another element in a document.
    569     // Comparisons may fail in that case, which are expected behavior and should not assert.
    570 
    571     if (afterRange && (afterRange->start.container->compareDocumentPosition(referenceRange.end.container) & Node::DOCUMENT_POSITION_DISCONNECTED))
    572         return WTF::nullopt;
    573     ASSERT(!afterRange || createLiveRange(afterRange)->compareBoundaryPoints(Range::START_TO_START, createLiveRange(referenceRange)).releaseReturnValue() >= 0);
    574 
    575     if (beforeRange && (beforeRange->end.container->compareDocumentPosition(referenceRange.start.container) & Node::DOCUMENT_POSITION_DISCONNECTED))
    576         return WTF::nullopt;
    577     ASSERT(!beforeRange || createLiveRange(beforeRange)->compareBoundaryPoints(Range::START_TO_START, createLiveRange(referenceRange)).releaseReturnValue() <= 0);
    578 
    579     if (!afterRange && !beforeRange)
    580         return WTF::nullopt;
    581559    if (!beforeRange)
    582560        return WTFMove(afterRange);
    583561    if (!afterRange)
    584562        return WTFMove(beforeRange);
    585 
    586     auto positionsToAfterRange = Position::positionCountBetweenPositions(createLegacyEditingPosition(afterRange->start), createLegacyEditingPosition(referenceRange.end));
    587     auto positionsToBeforeRange = Position::positionCountBetweenPositions(createLegacyEditingPosition(beforeRange->end), createLegacyEditingPosition(referenceRange.start));
    588 
    589     return WTFMove(positionsToAfterRange < positionsToBeforeRange ? afterRange : beforeRange);
     563    auto distanceBefore = characterCount({ beforeRange->end, referenceRange.start });
     564    auto distanceAfter = characterCount({ afterRange->start, referenceRange.end });
     565    return WTFMove(distanceBefore <= distanceAfter ? beforeRange : afterRange);
    590566}
    591567
     
    604580    for (auto& searchString : searchStrings) {
    605581        if (auto foundStringRange = frame->editor().rangeOfString(searchString, referenceRange, findOptions)) {
     582            bool foundStringIsCloser;
    606583            if (!closestStringRange)
     584                foundStringIsCloser = true;
     585            else {
     586                foundStringIsCloser = isBackwardSearch
     587                    ? is_gt(documentOrder(foundStringRange->end, closestStringRange->end))
     588                    : is_lt(documentOrder(foundStringRange->start, closestStringRange->start));
     589            }
     590            if (foundStringIsCloser)
    607591                closestStringRange = *foundStringRange;
    608             else {
    609                 // If searching backward, use the trailing range edges to correctly determine which
    610                 // range is closest. Similarly, if searching forward, use the leading range edges.
    611                 auto& closestStringPosition = isBackwardSearch ? closestStringRange->end : closestStringRange->start;
    612                 auto& foundStringPosition = isBackwardSearch ? foundStringRange->end : foundStringRange->start;
    613                
    614                 auto closestPositionOffset = closestStringPosition.offset;
    615                 auto searchPositionOffset = foundStringPosition.offset;
    616                 auto closestContainerNode = closestStringPosition.container.ptr();
    617                 auto searchContainerNode = foundStringPosition.container.ptr();
    618                
    619                 auto result = Range::compareBoundaryPoints(closestContainerNode, closestPositionOffset, searchContainerNode, searchPositionOffset).releaseReturnValue();
    620                 if ((!isBackwardSearch && result > 0) || (isBackwardSearch && result < 0))
    621                     closestStringRange = *foundStringRange;
    622             }
    623592        }
    624593    }
  • trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp

    r266028 r266295  
    916916        auto start = VisiblePosition { createLegacyEditingPosition(range->start) };
    917917        auto end = nextVisiblePosition(start);
    918         if (!end.isNull() && createLiveRange(range)->contains(end))
     918        if (isPointInRange(*range, makeBoundaryPoint(end)))
    919919            return { boundsForRange(*makeSimpleRange(start, end)).center() };
    920920    }
     
    15621562        return PlainTextRange();
    15631563
    1564     VisibleSelection visibleSelection = selection();
    1565     auto selectionRange = visibleSelection.toNormalizedRange();
    1566     if (!selectionRange)
    1567         return PlainTextRange();
    1568 
    1569     // FIXME: The reason this does the correct thing when the selection is in the
    1570     // shadow tree of an input element is that we get an exception below, and we
    1571     // choose to interpret all exceptions as "does not intersect". Seems likely
    1572     // that does not handle all cases correctly.
    1573     auto intersectsResult = createLiveRange(*selectionRange)->intersectsNode(*node);
    1574     if (!intersectsResult.hasException() && !intersectsResult.releaseReturnValue())
     1564    auto visibleSelection = selection();
     1565    auto selectionRange = visibleSelection.firstRange();
     1566    if (!selectionRange || !intersects(*selectionRange, *node))
    15751567        return PlainTextRange();
    15761568
     
    16571649        auto elementRange = this->elementRange();
    16581650        auto start = visiblePositionForIndexUsingCharacterIterator(node, range.start);
    1659         if (!createLiveRange(elementRange)->contains(start))
     1651        if (!isPointInRange(*elementRange, makeBoundaryPoint(start)))
    16601652            start = createLegacyEditingPosition(elementRange->start);
    16611653        auto end = visiblePositionForIndexUsingCharacterIterator(node, range.start + range.length);
    1662         if (!createLiveRange(elementRange)->contains(end))
     1654        if (!isPointInRange(*elementRange, makeBoundaryPoint(end)))
    16631655            end = createLegacyEditingPosition(elementRange->start);
    16641656        m_renderer->frame().selection().setSelection(VisibleSelection(start, end), FrameSelection::defaultSetSelectionOptions(UserTriggered));
     
    22172209        auto start = range.start;
    22182210        if (auto elementRange = this->elementRange()) {
    2219             if (!createLiveRange(elementRange)->contains(start))
     2211            if (!isPointInRange(*elementRange, makeBoundaryPoint(start)))
    22202212                start = createLegacyEditingPosition(elementRange->start);
    22212213        }
  • trunk/Source/WebCore/accessibility/atk/WebKitAccessibleUtil.cpp

    r265176 r266295  
    156156        return false;
    157157
    158     if (selection.isNone())
    159         return false;
    160 
    161     auto range = selection.toNormalizedRange();
    162     if (!range)
    163         return false;
    164 
    165     // We want to check that both the selection intersects the node
    166     // AND that the selection is not just "touching" one of the
    167     // boundaries for the selected node. We want to check whether the
    168     // node is actually inside the region, at least partially.
    169     auto& node = *coreObject->node();
    170     auto* lastDescendant = node.lastDescendant();
    171     unsigned lastOffset = lastDescendant->length();
    172     auto intersectsResult = createLiveRange(*range)->intersectsNode(node);
    173     return !intersectsResult.hasException()
    174         && intersectsResult.releaseReturnValue()
    175         && (range->end.container.ptr() != &node || range->end.offset)
    176         && (range->start.container.ptr() != lastDescendant || range->start.offset != lastOffset);
     158    auto range = selection.firstRange();
     159    return range && intersects(*range, *coreObject->node());
    177160}
    178161
  • trunk/Source/WebCore/dom/Document.h

    r266026 r266295  
    906906    // Returns the owning element in the parent document.
    907907    // Returns nullptr if this is the top level document.
    908     HTMLFrameOwnerElement* ownerElement() const;
     908    WEBCORE_EXPORT HTMLFrameOwnerElement* ownerElement() const;
    909909
    910910    // Used by DOM bindings; no direction known.
  • trunk/Source/WebCore/dom/DocumentMarkerController.cpp

    r266028 r266295  
    650650void addMarker(const SimpleRange& range, DocumentMarker::MarkerType type, const DocumentMarker::Data& data)
    651651{
    652     range.start.container->document().markers().addMarker(range, type, data);
     652    range.start.document().markers().addMarker(range, type, data);
    653653}
    654654
     
    660660void removeMarkers(const SimpleRange& range, OptionSet<DocumentMarker::MarkerType> types, RemovePartiallyOverlappingMarker policy)
    661661{
    662     range.start.container->document().markers().removeMarkers(range, types, policy);
     662    range.start.document().markers().removeMarkers(range, types, policy);
    663663}
    664664
  • trunk/Source/WebCore/dom/Element.h

    r266269 r266295  
    298298        bool delegatesFocus { false };
    299299    };
    300     ExceptionOr<ShadowRoot&> attachShadow(const ShadowRootInit&);
     300    WEBCORE_EXPORT ExceptionOr<ShadowRoot&> attachShadow(const ShadowRootInit&);
    301301
    302302    RefPtr<ShadowRoot> userAgentShadowRoot() const;
  • trunk/Source/WebCore/dom/Node.cpp

    r266281 r266295  
    16291629}
    16301630
    1631 // FIXME: Refactor this so it calls documentOrdering, except for any exotic inefficient things that are needed only here.
     1631// FIXME: Refactor this so it calls documentOrder, except for any exotic inefficient things that are needed only here.
    16321632unsigned short Node::compareDocumentPosition(Node& otherNode)
    16331633{
     
    26282628}
    26292629
    2630 static size_t depth(const Node& node)
     2630static size_t depthInComposedTree(const Node& node)
    26312631{
    26322632    size_t depth = 0;
    26332633    auto ancestor = &node;
    2634     while ((ancestor = ancestor->parentOrShadowHostNode()))
     2634    while ((ancestor = ancestor->parentInComposedTree()))
    26352635        ++depth;
    26362636    return depth;
     
    26422642    const Node* distinctAncestorB;
    26432643};
     2644
     2645// FIXME: This function's name is not explicit about the fact that it's the common inclusive ancestor in the composed tree.
    26442646static AncestorAndChildren commonInclusiveAncestorAndChildren(const Node& a, const Node& b)
    26452647{
    2646     // This first check isn't needed for correctness, but it is cheap and likely to be
     2648    // This check isn't needed for correctness, but it is cheap and likely to be
    26472649    // common enough to be worth optimizing so we don't have to walk to the root.
    26482650    if (&a == &b)
    26492651        return { &a, nullptr, nullptr };
    2650     auto [depthA, depthB] = std::make_tuple(depth(a), depth(b));
     2652    // FIXME: Could optimize cases where nodes are both in the same shadow tree.
     2653    // FIXME: Could optimize cases where nodes are in different documents to quickly return false.
     2654    // FIXME: Could optimize cases where one node is connected and the other is not to quickly return false.
     2655    auto [depthA, depthB] = std::make_tuple(depthInComposedTree(a), depthInComposedTree(b));
    26512656    auto [x, y, difference] = depthA >= depthB
    26522657        ? std::make_tuple(&a, &b, depthA - depthB)
     
    26552660    for (decltype(difference) i = 0; i < difference; ++i) {
    26562661        distinctAncestorA = x;
    2657         x = x->parentOrShadowHostNode();
     2662        x = x->parentInComposedTree();
    26582663    }
    26592664    decltype(y) distinctAncestorB = nullptr;
     
    26612666        distinctAncestorA = x;
    26622667        distinctAncestorB = y;
    2663         x = x->parentOrShadowHostNode();
    2664         y = y->parentOrShadowHostNode();
     2668        x = x->parentInComposedTree();
     2669        y = y->parentInComposedTree();
    26652670    }
    26662671    if (depthA < depthB)
     
    26692674}
    26702675
     2676// FIXME: This function's name is not explicit about the fact that it's the common inclusive ancestor in the composed tree.
    26712677RefPtr<Node> commonInclusiveAncestor(Node& a, Node& b)
    26722678{
     
    26762682static bool isSiblingSubsequent(const Node& siblingA, const Node& siblingB)
    26772683{
     2684    ASSERT(siblingA.parentNode());
     2685    ASSERT(siblingA.parentNode() == siblingB.parentNode());
    26782686    ASSERT(&siblingA != &siblingB);
    26792687    for (auto sibling = &siblingA; sibling; sibling = sibling->nextSibling()) {
     
    26952703    if (!result.distinctAncestorB)
    26962704        return PartialOrdering::greater;
     2705    bool isShadowRootA = result.distinctAncestorA->isShadowRoot();
     2706    bool isShadowRootB = result.distinctAncestorB->isShadowRoot();
     2707    if (isShadowRootA || isShadowRootB) {
     2708        if (!isShadowRootB)
     2709            return PartialOrdering::less;
     2710        if (!isShadowRootA)
     2711            return PartialOrdering::greater;
     2712        ASSERT_NOT_REACHED();
     2713        return PartialOrdering::unordered;
     2714    }
    26972715    return isSiblingSubsequent(*result.distinctAncestorA, *result.distinctAncestorB) ? PartialOrdering::less : PartialOrdering::greater;
    26982716}
  • trunk/Source/WebCore/dom/Node.h

    r266212 r266295  
    694694    Type m_type;
    695695};
     696constexpr bool is_eq(PartialOrdering);
     697constexpr bool is_lt(PartialOrdering);
     698constexpr bool is_gt(PartialOrdering);
     699constexpr bool is_neq(PartialOrdering);
     700constexpr bool is_lteq(PartialOrdering);
     701constexpr bool is_gteq(PartialOrdering);
    696702
    697703WEBCORE_EXPORT PartialOrdering documentOrder(const Node&, const Node&);
     
    830836}
    831837
     838constexpr bool is_neq(PartialOrdering ordering)
     839{
     840    return is_lt(ordering) || is_gt(ordering);
     841}
     842
     843constexpr bool is_lteq(PartialOrdering ordering)
     844{
     845    return is_lt(ordering) || is_eq(ordering);
     846}
     847
     848constexpr bool is_gteq(PartialOrdering ordering)
     849{
     850    return is_gt(ordering) || is_eq(ordering);
     851}
     852
    832853WTF::TextStream& operator<<(WTF::TextStream&, const Node&);
    833854
  • trunk/Source/WebCore/dom/Range.cpp

    r266123 r266295  
    6767
    6868enum ContentsProcessDirection { ProcessContentsForward, ProcessContentsBackward };
    69 enum class CoordinateSpace { Absolute, Client };
    7069
    7170static ExceptionOr<void> processNodes(Range::ActionType, Vector<Ref<Node>>&, Node* oldContainer, RefPtr<Node> newContainer);
     
    7574inline Range::Range(Document& ownerDocument)
    7675    : m_ownerDocument(ownerDocument)
    77     , m_start(&ownerDocument)
    78     , m_end(&ownerDocument)
     76    , m_start(ownerDocument)
     77    , m_end(ownerDocument)
    7978{
    8079#ifndef NDEBUG
     
    9998}
    10099
    101 void Range::setDocument(Document& document)
    102 {
    103     ASSERT(m_ownerDocument.ptr() != &document);
     100void Range::updateDocument()
     101{
     102    auto& document = startContainer().document();
     103    if (m_ownerDocument.ptr() == &document)
     104        return;
    104105    m_ownerDocument->detachRange(*this);
    105106    m_ownerDocument = document;
    106     m_start.setToStartOfNode(document);
    107     m_end.setToStartOfNode(document);
    108107    m_ownerDocument->attachRange(*this);
    109108}
    110109
    111 static inline bool checkForDifferentRootContainer(const RangeBoundaryPoint& start, const RangeBoundaryPoint& end)
    112 {
    113     Node* endRootContainer = end.container();
    114     while (endRootContainer->parentNode())
    115         endRootContainer = endRootContainer->parentNode();
    116     Node* startRootContainer = start.container();
    117     while (startRootContainer->parentNode())
    118         startRootContainer = startRootContainer->parentNode();
    119 
    120     return startRootContainer != endRootContainer || Range::compareBoundaryPoints(start, end).releaseReturnValue() > 0;
    121 }
    122 
    123 ExceptionOr<void> Range::setStart(Ref<Node>&& refNode, unsigned offset)
    124 {
    125     bool didMoveDocument = false;
    126     if (&refNode->document() != &ownerDocument()) {
    127         setDocument(refNode->document());
    128         didMoveDocument = true;
    129     }
    130 
    131     auto childNode = checkNodeWOffset(refNode, offset);
     110ExceptionOr<void> Range::setStart(Ref<Node>&& container, unsigned offset)
     111{
     112    auto childNode = checkNodeOffsetPair(container, offset);
    132113    if (childNode.hasException())
    133114        return childNode.releaseException();
    134115
    135     m_start.set(WTFMove(refNode), offset, childNode.releaseReturnValue());
    136 
    137     if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end))
    138         collapse(true);
    139 
     116    m_start.set(WTFMove(container), offset, childNode.releaseReturnValue());
     117    if (!is_lteq(documentOrder(makeBoundaryPoint(m_start), makeBoundaryPoint(m_end))))
     118        m_end = m_start;
     119    updateDocument();
    140120    return { };
    141121}
    142122
    143 ExceptionOr<void> Range::setEnd(Ref<Node>&& refNode, unsigned offset)
    144 {
    145     bool didMoveDocument = false;
    146     if (&refNode->document() != &ownerDocument()) {
    147         setDocument(refNode->document());
    148         didMoveDocument = true;
    149     }
    150 
    151     auto childNode = checkNodeWOffset(refNode, offset);
     123ExceptionOr<void> Range::setEnd(Ref<Node>&& container, unsigned offset)
     124{
     125    auto childNode = checkNodeOffsetPair(container, offset);
    152126    if (childNode.hasException())
    153127        return childNode.releaseException();
    154128
    155     m_end.set(WTFMove(refNode), offset, childNode.releaseReturnValue());
    156 
    157     if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end))
    158         collapse(false);
    159 
     129    m_end.set(WTFMove(container), offset, childNode.releaseReturnValue());
     130    if (!is_lteq(documentOrder(makeBoundaryPoint(m_start), makeBoundaryPoint(m_end))))
     131        m_start = m_end;
     132    updateDocument();
    160133    return { };
    161134}
     
    169142}
    170143
    171 ExceptionOr<bool> Range::isPointInRange(Node& refNode, unsigned offset)
    172 {
    173     if (&refNode.document() != &ownerDocument())
    174         return false;
    175 
    176     auto checkNodeResult = checkNodeWOffset(refNode, offset);
    177     if (checkNodeResult.hasException()) {
    178         // DOM4 spec requires us to check whether refNode and start container have the same root first
    179         // but we do it in the reverse order to avoid O(n) operation here in common case.
    180         if (!commonInclusiveAncestor(refNode, startContainer()))
     144ExceptionOr<bool> Range::isPointInRange(Node& container, unsigned offset)
     145{
     146    if (auto checkResult = checkNodeOffsetPair(container, offset); checkResult.hasException()) {
     147        // DOM specification requires this check be done first but since there are no side effects,
     148        // we can do it in reverse order to avoid an extra root node check in the common case.
     149        if (&container.rootNode() != &startContainer().rootNode())
    181150            return false;
    182         return checkNodeResult.releaseException();
    183     }
    184 
    185     auto startCompareResult = compareBoundaryPoints(&refNode, offset, &startContainer(), m_start.offset());
    186     if (!(!startCompareResult.hasException() && startCompareResult.releaseReturnValue() >= 0))
    187         return false;
    188     auto endCompareResult = compareBoundaryPoints(&refNode, offset, &endContainer(), m_end.offset());
    189     return !endCompareResult.hasException() && endCompareResult.releaseReturnValue() <= 0;
    190 }
    191 
    192 ExceptionOr<short> Range::comparePoint(Node& refNode, unsigned offset) const
    193 {
    194     // http://developer.mozilla.org/en/docs/DOM:range.comparePoint
    195     // This method returns -1, 0 or 1 depending on if the point described by the
    196     // refNode node and an offset within the node is before, same as, or after the range respectively.
    197     if (&refNode.document() != &ownerDocument())
    198         return Exception { WrongDocumentError };
    199 
    200     auto checkNodeResult = checkNodeWOffset(refNode, offset);
    201     if (checkNodeResult.hasException()) {
    202         // DOM4 spec requires us to check whether refNode and start container have the same root first
    203         // but we do it in the reverse order to avoid O(n) operation here in common case.
    204         if (!refNode.isConnected() && !commonInclusiveAncestor(refNode, startContainer()))
     151        return checkResult.releaseException();
     152    }
     153    return WebCore::isPointInRange(makeSimpleRange(*this), { container, offset });
     154}
     155
     156ExceptionOr<short> Range::comparePoint(Node& container, unsigned offset) const
     157{
     158    if (auto checkResult = checkNodeOffsetPair(container, offset); checkResult.hasException()) {
     159        // DOM specification requires this check be done first but since there are no side effects,
     160        // we can do it in reverse order to avoid an extra root node check in the common case.
     161        if (&container.rootNode() != &startContainer().rootNode())
    205162            return Exception { WrongDocumentError };
    206         return checkNodeResult.releaseException();
    207     }
    208 
    209     // compare to start, and point comes before
    210     auto startCompareResult = compareBoundaryPoints(&refNode, offset, &startContainer(), m_start.offset());
    211     if (startCompareResult.hasException())
    212         return startCompareResult.releaseException();
    213     if (startCompareResult.releaseReturnValue() < 0)
     163        return checkResult.releaseException();
     164    }
     165    auto ordering = documentOrder({ container, offset }, makeSimpleRange(*this));
     166    if (is_lt(ordering))
    214167        return -1;
    215 
    216     // compare to end, and point comes after
    217     auto endCompareResult = compareBoundaryPoints(&refNode, offset, &endContainer(), m_end.offset());
    218     if (endCompareResult.hasException())
    219         return endCompareResult.releaseException();
    220     if (endCompareResult.releaseReturnValue() > 0)
     168    if (is_eq(ordering))
     169        return 0;
     170    if (is_gt(ordering))
    221171        return 1;
    222 
    223     // point is in the middle of this range, or on the boundary points
    224     return 0;
    225 }
    226 
    227 ExceptionOr<Range::CompareResults> Range::compareNode(Node& refNode) const
    228 {
     172    return Exception { WrongDocumentError };
     173}
     174
     175ExceptionOr<Range::CompareResults> Range::compareNode(Node& node) const
     176{
     177    // FIXME: This deprecated function should be removed.
     178    // We originally added it for interoperability with Firefox.
     179    // Recent versions of Firefox have removed it.
     180
    229181    // http://developer.mozilla.org/en/docs/DOM:range.compareNode
    230182    // This method returns 0, 1, 2, or 3 based on if the node is before, after,
    231     // before and after(surrounds), or inside the range, respectively
    232 
    233     if (!refNode.isConnected()) {
    234         // Firefox doesn't throw an exception for this case; it returns 0.
     183    // before and after(surrounds), or inside the range, respectively.
     184
     185    if (!node.isConnected() || &node.document() != m_ownerDocument.ptr()) {
     186        // Match historical Firefox behavior.
    235187        return NODE_BEFORE;
    236188    }
    237189
    238     if (&refNode.document() != &ownerDocument()) {
    239         // Firefox doesn't throw an exception for this case; it returns 0.
     190    auto nodeRange = makeRangeSelectingNode(node);
     191    if (!nodeRange) {
     192        // Match historical Firefox behavior.
     193        return Exception { NotFoundError };
     194    }
     195
     196    auto startOrdering = documentOrder(nodeRange->start, makeBoundaryPoint(m_start));
     197    auto endOrdering = documentOrder(nodeRange->end, makeBoundaryPoint(m_end));
     198    if (is_gteq(startOrdering) && is_lteq(endOrdering))
     199        return NODE_INSIDE;
     200    if (is_lteq(startOrdering) && is_gteq(endOrdering))
     201        return NODE_BEFORE_AND_AFTER;
     202    if (is_lteq(startOrdering))
    240203        return NODE_BEFORE;
    241     }
    242 
    243     auto* parentNode = refNode.parentNode();
    244     if (!parentNode) {
    245         // If the node is the top of the tree we should return NODE_BEFORE_AND_AFTER,
    246         // but we throw to match firefox behavior.
    247         return Exception { NotFoundError };
    248     }
    249     auto nodeIndex = refNode.computeNodeIndex();
    250 
    251     auto nodeStartCompareResult = comparePoint(*parentNode, nodeIndex);
    252     if (nodeStartCompareResult.hasException())
    253         return nodeStartCompareResult.releaseException();
    254     auto nodeEndCompareResult = comparePoint(*parentNode, nodeIndex + 1);
    255     if (nodeEndCompareResult.hasException())
    256         return nodeEndCompareResult.releaseException();
    257 
    258     bool nodeStartsBeforeRange = nodeStartCompareResult.releaseReturnValue() < 0;
    259     bool nodeEndsAfterRange = nodeEndCompareResult.releaseReturnValue() > 0;
    260 
    261     return nodeStartsBeforeRange
    262         ? (nodeEndsAfterRange ? NODE_BEFORE_AND_AFTER : NODE_BEFORE)
    263         : (nodeEndsAfterRange ? NODE_AFTER : NODE_INSIDE);
    264 }
    265 
    266 static inline Node* top(Node& node)
    267 {
    268     auto* top = &node;
    269     while (auto* parent = top->parentNode())
    270         top = parent;
    271     return top;
    272 }
    273 
    274 ExceptionOr<short> Range::compareBoundaryPoints(CompareHow how, const Range& sourceRange) const
    275 {
    276     auto* thisContainer = commonAncestorContainer();
    277     auto* sourceContainer = sourceRange.commonAncestorContainer();
    278     if (!thisContainer || !sourceContainer || &thisContainer->document() != &sourceContainer->document() || top(*thisContainer) != top(*sourceContainer))
    279         return Exception { WrongDocumentError };
    280 
     204    if (is_gteq(endOrdering))
     205        return NODE_AFTER;
     206    return Exception { WrongDocumentError };
     207}
     208
     209ExceptionOr<short> Range::compareBoundaryPoints(unsigned short how, const Range& sourceRange) const
     210{
     211    const RangeBoundaryPoint* thisPoint;
     212    const RangeBoundaryPoint* otherPoint;
    281213    switch (how) {
    282214    case START_TO_START:
    283         return compareBoundaryPoints(m_start, sourceRange.m_start);
     215        thisPoint = &m_start;
     216        otherPoint = &sourceRange.m_start;
     217        break;
    284218    case START_TO_END:
    285         return compareBoundaryPoints(m_end, sourceRange.m_start);
     219        thisPoint = &m_end;
     220        otherPoint = &sourceRange.m_start;
     221        break;
    286222    case END_TO_END:
    287         return compareBoundaryPoints(m_end, sourceRange.m_end);
     223        thisPoint = &m_end;
     224        otherPoint = &sourceRange.m_end;
     225        break;
    288226    case END_TO_START:
    289         return compareBoundaryPoints(m_start, sourceRange.m_end);
    290     }
    291 
    292     return Exception { SyntaxError };
    293 }
    294 
    295 ExceptionOr<short> Range::compareBoundaryPointsForBindings(unsigned short how, const Range& sourceRange) const
    296 {
    297     switch (how) {
    298     case START_TO_START:
    299     case START_TO_END:
    300     case END_TO_END:
    301     case END_TO_START:
    302         return compareBoundaryPoints(static_cast<CompareHow>(how), sourceRange);
    303     }
    304     return Exception { NotSupportedError };
    305 }
    306 
    307 ExceptionOr<short> Range::compareBoundaryPoints(Node* containerA, unsigned offsetA, Node* containerB, unsigned offsetB)
    308 {
    309     ASSERT(containerA);
    310     ASSERT(containerB);
    311 
    312     if (!containerA)
     227        thisPoint = &m_start;
     228        otherPoint = &sourceRange.m_end;
     229        break;
     230    default:
     231        return Exception { NotSupportedError };
     232    }
     233    auto ordering = documentOrder(makeBoundaryPoint(*thisPoint), makeBoundaryPoint(*otherPoint));
     234    if (is_lt(ordering))
    313235        return -1;
    314     if (!containerB)
     236    if (is_eq(ordering))
     237        return 0;
     238    if (is_gt(ordering))
    315239        return 1;
    316 
    317     // see DOM2 traversal & range section 2.5
    318 
    319     // case 1: both points have the same container
    320     if (containerA == containerB) {
    321         if (offsetA == offsetB)
    322             return 0; // A is equal to B
    323         if (offsetA < offsetB)
    324             return -1; // A is before B
    325         return 1; // A is after B
    326     }
    327 
    328     // case 2: node C (container B or an ancestor) is a child node of A
    329     Node* c = containerB;
    330     while (c && c->parentNode() != containerA)
    331         c = c->parentNode();
    332     if (c) {
    333         unsigned offsetC = 0;
    334         Node* n = containerA->firstChild();
    335         while (n != c && offsetC < offsetA) {
    336             offsetC++;
    337             n = n->nextSibling();
    338         }
    339         if (offsetA <= offsetC)
    340             return -1; // A is before B
    341         return 1; // A is after B
    342     }
    343 
    344     // case 3: node C (container A or an ancestor) is a child node of B
    345     c = containerA;
    346     while (c && c->parentNode() != containerB)
    347         c = c->parentNode();
    348     if (c) {
    349         unsigned offsetC = 0;
    350         Node* n = containerB->firstChild();
    351         while (n != c && offsetC < offsetB) {
    352             offsetC++;
    353             n = n->nextSibling();
    354         }
    355         if (offsetC < offsetB)
    356             return -1; // A is before B
    357         return 1; // A is after B
    358     }
    359 
    360     // case 4: containers A & B are siblings, or children of siblings
    361     // ### we need to do a traversal here instead
    362     auto commonAncestor = commonInclusiveAncestor(*containerA, *containerB);
    363     if (!commonAncestor)
    364         return Exception { WrongDocumentError };
    365     Node* childA = containerA;
    366     while (childA && childA->parentNode() != commonAncestor)
    367         childA = childA->parentNode();
    368     if (!childA)
    369         childA = commonAncestor.get();
    370     Node* childB = containerB;
    371     while (childB && childB->parentNode() != commonAncestor)
    372         childB = childB->parentNode();
    373     if (!childB)
    374         childB = commonAncestor.get();
    375 
    376     if (childA == childB)
    377         return 0; // A is equal to B
    378 
    379     Node* n = commonAncestor->firstChild();
    380     while (n) {
    381         if (n == childA)
    382             return -1; // A is before B
    383         if (n == childB)
    384             return 1; // A is after B
    385         n = n->nextSibling();
    386     }
    387 
    388     // Should never reach this point.
    389     ASSERT_NOT_REACHED();
    390     return 0;
    391 }
    392 
    393 ExceptionOr<short> Range::compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB)
    394 {
    395     return compareBoundaryPoints(boundaryA.container(), boundaryA.offset(), boundaryB.container(), boundaryB.offset());
    396 }
    397 
    398 bool Range::boundaryPointsValid() const
    399 {
    400     auto result = compareBoundaryPoints(m_start, m_end);
    401     return !result.hasException() && result.releaseReturnValue() <= 0;
     240    return Exception { WrongDocumentError };
    402241}
    403242
     
    410249}
    411250
    412 ExceptionOr<bool> Range::intersectsNode(Node& refNode) const
    413 {
    414     if (!refNode.isConnected() || &refNode.document() != &ownerDocument())
    415         return false;
    416 
    417     auto* parentNode = refNode.parentNode();
    418     if (!parentNode)
    419         return true;
    420 
    421     unsigned nodeIndex = refNode.computeNodeIndex();
    422 
    423     // If (parentNode, nodeIndex) is before end and (parentNode, nodeIndex + 1) is after start, return true.
    424     // Otherwise, return false.
    425     auto compareEndResult = compareBoundaryPoints(parentNode, nodeIndex, m_end.container(), m_end.offset());
    426     if (compareEndResult.hasException())
    427         return compareEndResult.releaseException();
    428     auto compareStartResult = compareBoundaryPoints(parentNode, nodeIndex + 1, m_start.container(), m_start.offset());
    429     if (compareStartResult.hasException())
    430         return compareStartResult.releaseException();
    431     return compareEndResult.returnValue() == -1 && compareStartResult.returnValue() == 1;
     251bool Range::intersectsNode(Node& node) const
     252{
     253    return intersects(makeSimpleRange(*this), node);
    432254}
    433255
     
    465287}
    466288
    467 static inline unsigned lengthOfContentsInNode(Node& node)
    468 {
    469     // This switch statement must be consistent with that of Range::processContentsBetweenOffsets.
    470     switch (node.nodeType()) {
    471     case Node::DOCUMENT_TYPE_NODE:
    472     case Node::ATTRIBUTE_NODE:
    473         return 0;
    474     case Node::TEXT_NODE:
    475     case Node::CDATA_SECTION_NODE:
    476     case Node::COMMENT_NODE:
    477     case Node::PROCESSING_INSTRUCTION_NODE:
    478         return downcast<CharacterData>(node).length();
    479     case Node::ELEMENT_NODE:
    480     case Node::DOCUMENT_NODE:
    481     case Node::DOCUMENT_FRAGMENT_NODE:
    482         return downcast<ContainerNode>(node).countChildNodes();
    483     }
    484     ASSERT_NOT_REACHED();
    485     return 0;
    486 }
    487 
    488289ExceptionOr<RefPtr<DocumentFragment>> Range::processContents(ActionType action)
    489290{
    490291    RefPtr<DocumentFragment> fragment;
    491292    if (action == Extract || action == Clone)
    492         fragment = DocumentFragment::create(ownerDocument());
     293        fragment = DocumentFragment::create(m_ownerDocument);
    493294
    494295    if (collapsed())
     
    510311
    511312    // what is the highest node that partially selects the start / end of the range?
    512     RefPtr<Node> partialStart = highestAncestorUnderCommonRoot(originalStart.container(), commonRoot.get());
    513     RefPtr<Node> partialEnd = highestAncestorUnderCommonRoot(originalEnd.container(), commonRoot.get());
     313    RefPtr<Node> partialStart = highestAncestorUnderCommonRoot(&originalStart.container(), commonRoot.get());
     314    RefPtr<Node> partialEnd = highestAncestorUnderCommonRoot(&originalEnd.container(), commonRoot.get());
    514315
    515316    // Start and end containers are different.
     
    534335
    535336    RefPtr<Node> leftContents;
    536     if (originalStart.container() != commonRoot && commonRoot->contains(originalStart.container())) {
    537         auto firstResult = processContentsBetweenOffsets(action, nullptr, originalStart.container(), originalStart.offset(), lengthOfContentsInNode(*originalStart.container()));
    538         auto secondResult = processAncestorsAndTheirSiblings(action, originalStart.container(), ProcessContentsForward, WTFMove(firstResult), commonRoot.get());
     337    if (&originalStart.container() != commonRoot && commonRoot->contains(&originalStart.container())) {
     338        auto firstResult = processContentsBetweenOffsets(action, nullptr, &originalStart.container(), originalStart.offset(), originalStart.container().length());
     339        auto secondResult = processAncestorsAndTheirSiblings(action, &originalStart.container(), ProcessContentsForward, WTFMove(firstResult), commonRoot.get());
    539340        // FIXME: A bit peculiar that we silently ignore the exception here, but we do have at least some regression tests that rely on this behavior.
    540341        if (!secondResult.hasException())
     
    543344
    544345    RefPtr<Node> rightContents;
    545     if (&endContainer() != commonRoot && commonRoot->contains(originalEnd.container())) {
    546         auto firstResult = processContentsBetweenOffsets(action, nullptr, originalEnd.container(), 0, originalEnd.offset());
    547         auto secondResult = processAncestorsAndTheirSiblings(action, originalEnd.container(), ProcessContentsBackward, WTFMove(firstResult), commonRoot.get());
     346    if (&endContainer() != commonRoot && commonRoot->contains(&originalEnd.container())) {
     347        auto firstResult = processContentsBetweenOffsets(action, nullptr, &originalEnd.container(), 0, originalEnd.offset());
     348        auto secondResult = processAncestorsAndTheirSiblings(action, &originalEnd.container(), ProcessContentsBackward, WTFMove(firstResult), commonRoot.get());
    548349        // FIXME: A bit peculiar that we silently ignore the exception here, but we do have at least some regression tests that rely on this behavior.
    549350        if (!secondResult.hasException())
     
    552353
    553354    // delete all children of commonRoot between the start and end container
    554     RefPtr<Node> processStart = childOfCommonRootBeforeOffset(originalStart.container(), originalStart.offset(), commonRoot.get());
    555     if (processStart && originalStart.container() != commonRoot) // processStart contains nodes before m_start.
     355    RefPtr<Node> processStart = childOfCommonRootBeforeOffset(&originalStart.container(), originalStart.offset(), commonRoot.get());
     356    if (processStart && &originalStart.container() != commonRoot) // processStart contains nodes before m_start.
    556357        processStart = processStart->nextSibling();
    557     RefPtr<Node> processEnd = childOfCommonRootBeforeOffset(originalEnd.container(), originalEnd.offset(), commonRoot.get());
     358    RefPtr<Node> processEnd = childOfCommonRootBeforeOffset(&originalEnd.container(), originalEnd.offset(), commonRoot.get());
    558359
    559360    // Collapse the range, making sure that the result is not within a node that was partially selected.
     
    620421    RefPtr<Node> result;
    621422
    622     // This switch statement must be consistent with that of lengthOfContentsInNode.
    623423    switch (container->nodeType()) {
    624424    case Node::TEXT_NODE:
     
    869669String Range::toString() const
    870670{
     671    auto range = makeSimpleRange(*this);
    871672    StringBuilder builder;
    872 
    873     Node* pastLast = pastLastNode();
    874     for (Node* node = firstNode(); node != pastLast; node = NodeTraversal::next(*node)) {
    875         auto type = node->nodeType();
    876         if (type == Node::TEXT_NODE || type == Node::CDATA_SECTION_NODE) {
    877             unsigned start = node == &startContainer() ? m_start.offset() : 0U;
    878             unsigned end = node == &endContainer() ? std::max(start, m_end.offset()) : std::numeric_limits<unsigned>::max();
    879             builder.appendSubstring(downcast<CharacterData>(*node).data(), start, end - start);
    880         }
    881     }
    882 
     673    for (auto& node : intersectingNodes(range)) {
     674        if (is<Text>(node)) {
     675            auto offsetRange = characterDataOffsetRange(range, node);
     676            builder.appendSubstring(downcast<Text>(node).data(), offsetRange.start, offsetRange.end - offsetRange.start);
     677        }
     678    }
    883679    return builder.toString();
    884 }
    885 
    886 String Range::text() const
    887 {
    888     // We need to update layout, since plainText uses line boxes in the render tree.
    889     // FIXME: As with innerText, we'd like this to work even if there are no render objects.
    890     startContainer().document().updateLayout();
    891 
    892     return plainText(makeSimpleRange(*this));
    893680}
    894681
     
    909696}
    910697
    911 void Range::detach()
    912 {
    913     // This is now a no-op as per the DOM specification.
    914 }
    915 
    916 ExceptionOr<Node*> Range::checkNodeWOffset(Node& node, unsigned offset) const
     698ExceptionOr<Node*> Range::checkNodeOffsetPair(Node& node, unsigned offset) const
    917699{
    918700    switch (node.nodeType()) {
     
    944726Ref<Range> Range::cloneRange() const
    945727{
    946     auto result = create(ownerDocument());
     728    auto result = create(m_ownerDocument);
    947729    result->setStart(startContainer(), m_start.offset());
    948730    result->setEnd(endContainer(), m_end.offset());
     
    950732}
    951733
    952 ExceptionOr<void> Range::setStartAfter(Node& refNode)
    953 {
    954     if (!refNode.parentNode())
     734ExceptionOr<void> Range::setStartAfter(Node& node)
     735{
     736    auto parent = node.parentNode();
     737    if (!parent)
    955738        return Exception { InvalidNodeTypeError };
    956     return setStart(*refNode.parentNode(), refNode.computeNodeIndex() + 1);
    957 }
    958 
    959 ExceptionOr<void> Range::setEndBefore(Node& refNode)
    960 {
    961     if (!refNode.parentNode())
     739    return setStart(*parent, node.computeNodeIndex() + 1);
     740}
     741
     742ExceptionOr<void> Range::setEndBefore(Node& node)
     743{
     744    auto parent = node.parentNode();
     745    if (!parent)
    962746        return Exception { InvalidNodeTypeError };
    963     return setEnd(*refNode.parentNode(), refNode.computeNodeIndex());
    964 }
    965 
    966 ExceptionOr<void> Range::setEndAfter(Node& refNode)
    967 {
    968     if (!refNode.parentNode())
     747    return setEnd(*parent, node.computeNodeIndex());
     748}
     749
     750ExceptionOr<void> Range::setEndAfter(Node& node)
     751{
     752    auto parent = node.parentNode();
     753    if (!parent)
    969754        return Exception { InvalidNodeTypeError };
    970     return setEnd(*refNode.parentNode(), refNode.computeNodeIndex() + 1);
    971 }
    972 
    973 ExceptionOr<void> Range::selectNode(Node& refNode)
    974 {
    975     if (!refNode.parentNode())
     755    return setEnd(*parent, node.computeNodeIndex() + 1);
     756}
     757
     758ExceptionOr<void> Range::selectNode(Node& node)
     759{
     760    auto parent = node.parentNode();
     761    if (!parent)
    976762        return Exception { InvalidNodeTypeError };
    977 
    978     if (&ownerDocument() != &refNode.document())
    979         setDocument(refNode.document());
    980 
    981     unsigned index = refNode.computeNodeIndex();
    982     auto result = setStart(*refNode.parentNode(), index);
     763    unsigned index = node.computeNodeIndex();
     764    auto result = setStart(*parent, index);
    983765    if (result.hasException())
    984766        return result.releaseException();
    985     return setEnd(*refNode.parentNode(), index + 1);
    986 }
    987 
    988 ExceptionOr<void> Range::selectNodeContents(Node& refNode)
    989 {
    990     if (refNode.isDocumentTypeNode())
     767    return setEnd(*parent, index + 1);
     768}
     769
     770ExceptionOr<void> Range::selectNodeContents(Node& node)
     771{
     772    if (node.isDocumentTypeNode())
    991773        return Exception { InvalidNodeTypeError };
    992774
    993     if (&ownerDocument() != &refNode.document())
    994         setDocument(refNode.document());
    995 
    996     m_start.setToStartOfNode(refNode);
    997     m_end.setToEndOfNode(refNode);
    998 
     775    m_start.setToBeforeContents(node);
     776    m_end.setToAfterContents(node);
    999777    return { };
    1000778}
     
    1053831}
    1054832
    1055 ExceptionOr<void> Range::setStartBefore(Node& refNode)
    1056 {
    1057     if (!refNode.parentNode())
     833ExceptionOr<void> Range::setStartBefore(Node& node)
     834{
     835    auto parent = node.parentNode();
     836    if (!parent)
    1058837        return Exception { InvalidNodeTypeError };
    1059     return setStart(*refNode.parentNode(), refNode.computeNodeIndex());
    1060 }
    1061 
    1062 Node* Range::firstNode() const
    1063 {
    1064     if (startContainer().isCharacterDataNode())
    1065         return &startContainer();
    1066     if (Node* child = startContainer().traverseToChildAt(m_start.offset()))
    1067         return child;
    1068     if (!m_start.offset())
    1069         return &startContainer();
    1070     return NodeTraversal::nextSkippingChildren(startContainer());
    1071 }
    1072 
    1073 Node* Range::pastLastNode() const
    1074 {
    1075     if (endContainer().isCharacterDataNode())
    1076         return NodeTraversal::nextSkippingChildren(endContainer());
    1077     if (Node* child = endContainer().traverseToChildAt(m_end.offset()))
    1078         return child;
    1079     return NodeTraversal::nextSkippingChildren(endContainer());
     838    return setStart(*parent, node.computeNodeIndex());
    1080839}
    1081840
     
    1102861#endif
    1103862
    1104 bool Range::contains(const Range& other) const
    1105 {
    1106     if (commonAncestorContainer()->document() != other.commonAncestorContainer()->document())
    1107         return false;
    1108 
    1109     auto startToStart = compareBoundaryPoints(Range::START_TO_START, other);
    1110     if (startToStart.hasException() || startToStart.releaseReturnValue() > 0)
    1111         return false;
    1112 
    1113     auto endToEnd = compareBoundaryPoints(Range::END_TO_END, other);
    1114     return !endToEnd.hasException() && endToEnd.releaseReturnValue() >= 0;
    1115 }
    1116 
    1117 bool Range::contains(const VisiblePosition& position) const
    1118 {
    1119     auto positionRange = makeSimpleRange(position);
    1120     if (!positionRange)
    1121         return false;
    1122     return contains(createLiveRange(*positionRange));
    1123 }
    1124 
    1125 bool areRangesEqual(const Range* a, const Range* b)
    1126 {
    1127     if (a == b)
    1128         return true;
    1129     if (!a || !b)
    1130         return false;
    1131     return &a->startContainer() == &b->startContainer() && a->startOffset() == b->startOffset() && &a->endContainer() == &b->endContainer() && a->endOffset() == b->endOffset();
    1132 }
    1133 
    1134 bool rangesOverlap(const Range* a, const Range* b)
    1135 {
    1136     if (!a || !b)
    1137         return false;
    1138 
    1139     if (a == b)
    1140         return true;
    1141 
    1142     if (!connectedInSameTreeScope(a->commonAncestorContainer(), b->commonAncestorContainer()))
    1143         return false;
    1144 
    1145     short startToStart = a->compareBoundaryPoints(Range::START_TO_START, *b).releaseReturnValue();
    1146     short endToEnd = a->compareBoundaryPoints(Range::END_TO_END, *b).releaseReturnValue();
    1147 
    1148     // First range contains the second range.
    1149     if (startToStart <= 0 && endToEnd >= 0)
    1150         return true;
    1151 
    1152     // End of first range is inside second range.
    1153     if (a->compareBoundaryPoints(Range::START_TO_END, *b).releaseReturnValue() >= 0 && endToEnd <= 0)
    1154         return true;
    1155 
    1156     // Start of first range is inside second range.
    1157     if (startToStart >= 0 && a->compareBoundaryPoints(Range::END_TO_START, *b).releaseReturnValue() <= 0)
    1158         return true;
    1159 
    1160     return false;
    1161 }
    1162 
    1163863static inline void boundaryNodeChildrenChanged(RangeBoundaryPoint& boundary, ContainerNode& container)
    1164864{
    1165     if (!boundary.childBefore())
    1166         return;
    1167     if (boundary.container() != &container)
    1168         return;
    1169     boundary.invalidateOffset();
     865    if (boundary.childBefore() && &boundary.container() == &container)
     866        boundary.invalidateOffset();
    1170867}
    1171868
    1172869void Range::nodeChildrenChanged(ContainerNode& container)
    1173870{
    1174     ASSERT(&container.document() == &ownerDocument());
     871    ASSERT(&container.document() == m_ownerDocument.ptr());
    1175872    boundaryNodeChildrenChanged(m_start, container);
    1176873    boundaryNodeChildrenChanged(m_end, container);
    1177874}
    1178875
    1179 static inline void boundaryNodeChildrenWillBeRemoved(RangeBoundaryPoint& boundary, ContainerNode& container)
    1180 {
    1181     for (Node* nodeToBeRemoved = container.firstChild(); nodeToBeRemoved; nodeToBeRemoved = nodeToBeRemoved->nextSibling()) {
    1182         if (boundary.childBefore() == nodeToBeRemoved) {
    1183             boundary.setToStartOfNode(container);
    1184             return;
    1185         }
    1186 
    1187         for (Node* n = boundary.container(); n; n = n->parentNode()) {
    1188             if (n == nodeToBeRemoved) {
    1189                 boundary.setToStartOfNode(container);
    1190                 return;
    1191             }
    1192         }
    1193     }
     876static inline void boundaryNodeChildrenWillBeRemoved(RangeBoundaryPoint& boundary, ContainerNode& containerOfNodesToBeRemoved)
     877{
     878    if (containerOfNodesToBeRemoved.contains(&boundary.container()))
     879        boundary.setToBeforeContents(containerOfNodesToBeRemoved);
    1194880}
    1195881
    1196882void Range::nodeChildrenWillBeRemoved(ContainerNode& container)
    1197883{
    1198     ASSERT(&container.document() == &ownerDocument());
     884    ASSERT(&container.document() == m_ownerDocument.ptr());
    1199885    boundaryNodeChildrenWillBeRemoved(m_start, container);
    1200886    boundaryNodeChildrenWillBeRemoved(m_end, container);
     
    1203889static inline void boundaryNodeWillBeRemoved(RangeBoundaryPoint& boundary, Node& nodeToBeRemoved)
    1204890{
    1205     if (boundary.childBefore() == &nodeToBeRemoved) {
     891    if (boundary.childBefore() == &nodeToBeRemoved)
    1206892        boundary.childBeforeWillBeRemoved();
    1207         return;
    1208     }
    1209 
    1210     for (Node* n = boundary.container(); n; n = n->parentNode()) {
    1211         if (n == &nodeToBeRemoved) {
    1212             boundary.setToBeforeChild(nodeToBeRemoved);
    1213             return;
    1214         }
    1215     }
     893    else if (nodeToBeRemoved.contains(&boundary.container()))
     894        boundary.setToBeforeNode(nodeToBeRemoved);
    1216895}
    1217896
    1218897void Range::nodeWillBeRemoved(Node& node)
    1219898{
    1220     ASSERT(&node.document() == &ownerDocument());
    1221     ASSERT(&node != &ownerDocument());
     899    ASSERT(&node.document() == m_ownerDocument.ptr());
     900    ASSERT(&node != m_ownerDocument.ptr());
    1222901    ASSERT(node.parentNode());
    1223902    boundaryNodeWillBeRemoved(m_start, node);
     
    1227906bool Range::parentlessNodeMovedToNewDocumentAffectsRange(Node& node)
    1228907{
    1229     return node.containsIncludingShadowDOM(m_start.container());
     908    return node.containsIncludingShadowDOM(&m_start.container());
    1230909}
    1231910
     
    1239918static inline void boundaryTextInserted(RangeBoundaryPoint& boundary, Node& text, unsigned offset, unsigned length)
    1240919{
    1241     if (boundary.container() != &text)
     920    if (&boundary.container() != &text)
    1242921        return;
    1243922    unsigned boundaryOffset = boundary.offset();
     
    1249928void Range::textInserted(Node& text, unsigned offset, unsigned length)
    1250929{
    1251     ASSERT(&text.document() == &ownerDocument());
     930    ASSERT(&text.document() == m_ownerDocument.ptr());
    1252931    boundaryTextInserted(m_start, text, offset, length);
    1253932    boundaryTextInserted(m_end, text, offset, length);
     
    1256935static inline void boundaryTextRemoved(RangeBoundaryPoint& boundary, Node& text, unsigned offset, unsigned length)
    1257936{
    1258     if (boundary.container() != &text)
     937    if (&boundary.container() != &text)
    1259938        return;
    1260939    unsigned boundaryOffset = boundary.offset();
     
    1269948void Range::textRemoved(Node& text, unsigned offset, unsigned length)
    1270949{
    1271     ASSERT(&text.document() == &ownerDocument());
     950    ASSERT(&text.document() == m_ownerDocument.ptr());
    1272951    boundaryTextRemoved(m_start, text, offset, length);
    1273952    boundaryTextRemoved(m_end, text, offset, length);
     
    1276955static inline void boundaryTextNodesMerged(RangeBoundaryPoint& boundary, NodeWithIndex& oldNode, unsigned offset)
    1277956{
    1278     if (boundary.container() == oldNode.node())
     957    if (&boundary.container() == oldNode.node())
    1279958        boundary.set(*oldNode.node()->previousSibling(), boundary.offset() + offset, 0);
    1280     else if (boundary.container() == oldNode.node()->parentNode() && static_cast<int>(boundary.offset()) == oldNode.index())
     959    else if (&boundary.container() == oldNode.node()->parentNode() && boundary.offset() == static_cast<unsigned>(oldNode.index()))
    1281960        boundary.set(*oldNode.node()->previousSibling(), offset, 0);
    1282961}
     
    1285964{
    1286965    ASSERT(oldNode.node());
    1287     ASSERT(&oldNode.node()->document() == &ownerDocument());
     966    ASSERT(&oldNode.node()->document() == m_ownerDocument.ptr());
    1288967    ASSERT(oldNode.node()->parentNode());
    1289968    ASSERT(oldNode.node()->isTextNode());
     
    1297976{
    1298977    auto* parent = oldNode.parentNode();
    1299     if (boundary.container() == &oldNode) {
     978    if (&boundary.container() == &oldNode) {
    1300979        unsigned splitOffset = oldNode.length();
    1301980        unsigned boundaryOffset = boundary.offset();
     
    1310989    if (!parent)
    1311990        return;
    1312     if (boundary.container() == parent && boundary.childBefore() == &oldNode) {
     991    if (&boundary.container() == parent && boundary.childBefore() == &oldNode) {
    1313992        auto* newChild = oldNode.nextSibling();
    1314993        ASSERT(newChild);
    1315         boundary.setToAfterChild(*newChild);
     994        boundary.setToAfterNode(*newChild);
    1316995    }
    1317996}
     
    1319998void Range::textNodeSplit(Text& oldNode)
    1320999{
    1321     ASSERT(&oldNode.document() == &ownerDocument());
     1000    ASSERT(&oldNode.document() == m_ownerDocument.ptr());
    13221001    ASSERT(!oldNode.parentNode() || oldNode.nextSibling());
    13231002    ASSERT(!oldNode.parentNode() || oldNode.nextSibling()->isTextNode());
     
    14141093void showTree(const WebCore::Range* range)
    14151094{
    1416     if (range && range->boundaryPointsValid()) {
     1095    if (range) {
    14171096        range->startContainer().showTreeAndMark(&range->startContainer(), "S", &range->endContainer(), "E");
    14181097        fprintf(stderr, "start offset: %d, end offset: %d\n", range->startOffset(), range->endOffset());
  • trunk/Source/WebCore/dom/Range.h

    r266028 r266295  
    3434class NodeWithIndex;
    3535class Text;
    36 class VisiblePosition;
    3736
    3837struct SimpleRange;
    3938
    40 // FIXME: Rename to LiveRange, while leaving the DOM-exposed name as Range.
    4139class Range : public RefCounted<Range> {
    4240public:
     
    4442    WEBCORE_EXPORT ~Range();
    4543
    46     Document& ownerDocument() const { return m_ownerDocument; }
    47 
    48     Node& startContainer() const { ASSERT(m_start.container()); return *m_start.container(); }
     44    Node& startContainer() const { return m_start.container(); }
    4945    unsigned startOffset() const { return m_start.offset(); }
    50     Node& endContainer() const { ASSERT(m_end.container()); return *m_end.container(); }
     46    Node& endContainer() const { return m_end.container(); }
    5147    unsigned endOffset() const { return m_end.offset(); }
    5248    bool collapsed() const { return m_start == m_end; }
     49    Node* commonAncestorContainer() const { return commonInclusiveAncestor(startContainer(), endContainer()).get(); }
    5350
    54     Node* commonAncestorContainer() const { return commonInclusiveAncestor(startContainer(), endContainer()).get(); }
    55     WEBCORE_EXPORT ExceptionOr<void> setStart(Ref<Node>&& container, unsigned offset);
    56     WEBCORE_EXPORT ExceptionOr<void> setEnd(Ref<Node>&& container, unsigned offset);
     51    WEBCORE_EXPORT ExceptionOr<void> setStart(Ref<Node>&&, unsigned offset);
     52    WEBCORE_EXPORT ExceptionOr<void> setEnd(Ref<Node>&&, unsigned offset);
     53    WEBCORE_EXPORT ExceptionOr<void> setStartBefore(Node&);
     54    WEBCORE_EXPORT ExceptionOr<void> setStartAfter(Node&);
     55    WEBCORE_EXPORT ExceptionOr<void> setEndBefore(Node&);
     56    WEBCORE_EXPORT ExceptionOr<void> setEndAfter(Node&);
    5757    WEBCORE_EXPORT void collapse(bool toStart);
    58     WEBCORE_EXPORT ExceptionOr<bool> isPointInRange(Node& refNode, unsigned offset);
    59     WEBCORE_EXPORT ExceptionOr<short> comparePoint(Node& refNode, unsigned offset) const;
    60     enum CompareResults { NODE_BEFORE, NODE_AFTER, NODE_BEFORE_AND_AFTER, NODE_INSIDE };
    61     WEBCORE_EXPORT ExceptionOr<CompareResults> compareNode(Node& refNode) const;
    62     enum CompareHow { START_TO_START, START_TO_END, END_TO_END, END_TO_START };
    63     WEBCORE_EXPORT ExceptionOr<short> compareBoundaryPoints(CompareHow, const Range& sourceRange) const;
    64     WEBCORE_EXPORT ExceptionOr<short> compareBoundaryPointsForBindings(unsigned short compareHow, const Range& sourceRange) const;
    65     static ExceptionOr<short> compareBoundaryPoints(Node* containerA, unsigned offsetA, Node* containerB, unsigned offsetB);
    66     static ExceptionOr<short> compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB);
    67     WEBCORE_EXPORT bool boundaryPointsValid() const;
    68     WEBCORE_EXPORT ExceptionOr<bool> intersectsNode(Node& refNode) const;
     58    WEBCORE_EXPORT ExceptionOr<void> selectNode(Node&);
     59    WEBCORE_EXPORT ExceptionOr<void> selectNodeContents(Node&);
     60
     61    enum CompareHow : unsigned short { START_TO_START, START_TO_END, END_TO_END, END_TO_START };
     62    WEBCORE_EXPORT ExceptionOr<short> compareBoundaryPoints(unsigned short compareHow, const Range& sourceRange) const;
     63
    6964    WEBCORE_EXPORT ExceptionOr<void> deleteContents();
    7065    WEBCORE_EXPORT ExceptionOr<Ref<DocumentFragment>> extractContents();
    7166    WEBCORE_EXPORT ExceptionOr<Ref<DocumentFragment>> cloneContents();
    7267    WEBCORE_EXPORT ExceptionOr<void> insertNode(Ref<Node>&&);
     68    WEBCORE_EXPORT ExceptionOr<void> surroundContents(Node&);
     69
     70    WEBCORE_EXPORT Ref<Range> cloneRange() const;
     71    static void detach() { }
     72
     73    WEBCORE_EXPORT ExceptionOr<bool> isPointInRange(Node&, unsigned offset);
     74    WEBCORE_EXPORT ExceptionOr<short> comparePoint(Node&, unsigned offset) const;
     75    WEBCORE_EXPORT bool intersectsNode(Node&) const;
     76
    7377    WEBCORE_EXPORT String toString() const;
    7478
    75     WEBCORE_EXPORT String text() const;
     79    Ref<DOMRectList> getClientRects() const;
     80    Ref<DOMRect> getBoundingClientRect() const;
    7681
    77     WEBCORE_EXPORT ExceptionOr<Ref<DocumentFragment>> createContextualFragment(const String& html);
     82    WEBCORE_EXPORT ExceptionOr<Ref<DocumentFragment>> createContextualFragment(const String& fragment);
    7883
    79     WEBCORE_EXPORT void detach();
    80     WEBCORE_EXPORT Ref<Range> cloneRange() const;
     84    // Expand range to a unit (word or sentence or block or document) boundary.
     85    // Please refer to https://bugs.webkit.org/show_bug.cgi?id=27632 comment #5 for details.
     86    WEBCORE_EXPORT ExceptionOr<void> expand(const String&);
    8187
    82     WEBCORE_EXPORT ExceptionOr<void> setStartAfter(Node&);
    83     WEBCORE_EXPORT ExceptionOr<void> setEndBefore(Node&);
    84     WEBCORE_EXPORT ExceptionOr<void> setEndAfter(Node&);
    85     WEBCORE_EXPORT ExceptionOr<void> selectNode(Node&);
    86     WEBCORE_EXPORT ExceptionOr<void> selectNodeContents(Node&);
    87     WEBCORE_EXPORT ExceptionOr<void> surroundContents(Node&);
    88     WEBCORE_EXPORT ExceptionOr<void> setStartBefore(Node&);
    89 
    90     WEBCORE_EXPORT Node* firstNode() const;
     88    enum CompareResults : uint8_t { NODE_BEFORE, NODE_AFTER, NODE_BEFORE_AND_AFTER, NODE_INSIDE };
     89    WEBCORE_EXPORT ExceptionOr<CompareResults> compareNode(Node&) const;
    9190
    9291    void nodeChildrenChanged(ContainerNode&);
     
    101100    void textNodeSplit(Text& oldNode);
    102101
    103     // Expand range to a unit (word or sentence or block or document) boundary.
    104     // Please refer to https://bugs.webkit.org/show_bug.cgi?id=27632 comment #5
    105     // for details.
    106     WEBCORE_EXPORT ExceptionOr<void> expand(const String&);
    107 
    108     Ref<DOMRectList> getClientRects() const;
    109     Ref<DOMRect> getBoundingClientRect() const;
    110 
    111102#if ENABLE(TREE_DEBUGGING)
    112103    void formatForDebugger(char* buffer, unsigned length) const;
    113104#endif
    114105
    115     WEBCORE_EXPORT bool contains(const Range&) const;
    116     bool contains(const VisiblePosition&) const;
    117 
    118     enum ActionType { Delete, Extract, Clone };
     106    enum ActionType : uint8_t { Delete, Extract, Clone };
    119107
    120108private:
    121109    explicit Range(Document&);
    122110
    123     void setDocument(Document&);
    124     ExceptionOr<Node*> checkNodeWOffset(Node&, unsigned offset) const;
     111    void updateDocument();
     112    ExceptionOr<Node*> checkNodeOffsetPair(Node&, unsigned offset) const;
    125113    ExceptionOr<RefPtr<DocumentFragment>> processContents(ActionType);
    126 
    127     Node* pastLastNode() const;
    128114
    129115    Ref<Document> m_ownerDocument;
     
    131117    RangeBoundaryPoint m_end;
    132118};
    133 
    134 WEBCORE_EXPORT bool areRangesEqual(const Range*, const Range*);
    135 WEBCORE_EXPORT bool rangesOverlap(const Range*, const Range*);
    136119
    137120WEBCORE_EXPORT SimpleRange makeSimpleRange(const Range&);
  • trunk/Source/WebCore/dom/Range.idl

    r263160 r266295  
    2626
    2727    readonly attribute Node startContainer;
    28     readonly attribute long startOffset; // FIXME: Should be unsigned long.
     28    readonly attribute unsigned long startOffset;
    2929    readonly attribute Node endContainer;
    30     readonly attribute long endOffset; // FIXME: Should be unsigned long.
     30    readonly attribute unsigned long endOffset;
    3131    readonly attribute boolean collapsed;
    3232    readonly attribute Node commonAncestorContainer;
     
    4646    const unsigned short END_TO_END = 2;
    4747    const unsigned short END_TO_START = 3;
    48     [MayThrowException, ImplementedAs=compareBoundaryPointsForBindings] short compareBoundaryPoints(unsigned short how, Range sourceRange);
     48    [MayThrowException] short compareBoundaryPoints(unsigned short how, Range sourceRange);
    4949
    5050    [CEReactions, MayThrowException] void deleteContents();
     
    6060    [MayThrowException] short comparePoint(Node node, unsigned long offset);
    6161
    62     [MayThrowException] boolean intersectsNode(Node node);
     62    boolean intersectsNode(Node node);
    6363
    6464    stringifier;
     
    7171    [CEReactions, MayThrowException, NewObject] DocumentFragment createContextualFragment(DOMString fragment);
    7272
    73     // Non standard.
    74     [MayThrowException] void expand(optional DOMString unit = "");
     73    // Non-standard extension.
     74    // FIXME: We should eventually drop this since no other browser supports it.
     75    [MayThrowException] void expand(optional DOMString unit);
    7576
    76     // FIXME: We should likely drop this since no other browser supports it.
     77    // FIXME: We should likely drop this since we added it for Firefox interoperability, but now no other browser supports it.
    7778    [MayThrowException] short compareNode(Node node);
    7879    const unsigned short NODE_BEFORE = 0;
  • trunk/Source/WebCore/dom/RangeBoundaryPoint.h

    r266026 r266295  
    3333class RangeBoundaryPoint {
    3434public:
    35     explicit RangeBoundaryPoint(Node* container);
     35    explicit RangeBoundaryPoint(Node& container);
    3636
    37     Node* container() const;
     37    Node& container() const;
    3838    unsigned offset() const;
    3939    Node* childBefore() const;
    40 
    41     void clear();
    4240
    4341    void set(Ref<Node>&& container, unsigned offset, Node* childBefore);
    4442    void setOffset(unsigned);
    4543
    46     void setToBeforeChild(Node&);
    47     void setToAfterChild(Node&);
    48     void setToStartOfNode(Ref<Node>&&);
    49     void setToEndOfNode(Ref<Node>&&);
     44    void setToBeforeNode(Node&);
     45    void setToAfterNode(Node&);
     46    void setToBeforeContents(Ref<Node>&&);
     47    void setToAfterContents(Ref<Node>&&);
    5048
    5149    void childBeforeWillBeRemoved();
    5250    void invalidateOffset() const;
    53     void ensureOffsetIsValid() const;
    5451
    5552private:
    56     RefPtr<Node> m_containerNode;
     53    Ref<Node> m_container;
    5754    mutable Optional<unsigned> m_offsetInContainer { 0 };
    5855    RefPtr<Node> m_childBeforeBoundary;
     
    6158BoundaryPoint makeBoundaryPoint(const RangeBoundaryPoint&);
    6259
    63 inline RangeBoundaryPoint::RangeBoundaryPoint(Node* container)
    64     : m_containerNode(container)
     60inline RangeBoundaryPoint::RangeBoundaryPoint(Node& container)
     61    : m_container(container)
    6562{
    66     ASSERT(m_containerNode);
    6763}
    6864
    69 inline Node* RangeBoundaryPoint::container() const
     65inline Node& RangeBoundaryPoint::container() const
    7066{
    71     return m_containerNode.get();
     67    return m_container;
    7268}
    7369
     
    7773}
    7874
    79 inline void RangeBoundaryPoint::ensureOffsetIsValid() const
    80 {
    81     if (m_offsetInContainer)
    82         return;
    83 
    84     ASSERT(m_childBeforeBoundary);
    85     m_offsetInContainer = m_childBeforeBoundary->computeNodeIndex() + 1;
    86 }
    87 
    8875inline unsigned RangeBoundaryPoint::offset() const
    8976{
    90     ensureOffsetIsValid();
    91     return m_offsetInContainer.value();
    92 }
    93 
    94 inline void RangeBoundaryPoint::clear()
    95 {
    96     m_containerNode = nullptr;
    97     m_offsetInContainer = 0;
    98     m_childBeforeBoundary = nullptr;
     77    if (!m_offsetInContainer) {
     78        ASSERT(m_childBeforeBoundary);
     79        m_offsetInContainer = m_childBeforeBoundary->computeNodeIndex() + 1;
     80    }
     81    return *m_offsetInContainer;
    9982}
    10083
     
    10285{
    10386    ASSERT(childBefore == (offset ? container->traverseToChildAt(offset - 1) : 0));
    104     m_containerNode = WTFMove(container);
     87    m_container = WTFMove(container);
    10588    m_offsetInContainer = offset;
    10689    m_childBeforeBoundary = childBefore;
     
    10992inline void RangeBoundaryPoint::setOffset(unsigned offset)
    11093{
    111     ASSERT(m_containerNode);
    112     ASSERT(m_containerNode->isCharacterDataNode());
     94    ASSERT(m_container->isCharacterDataNode());
    11395    ASSERT(m_offsetInContainer);
    11496    ASSERT(!m_childBeforeBoundary);
     
    11698}
    11799
    118 inline void RangeBoundaryPoint::setToBeforeChild(Node& child)
     100inline void RangeBoundaryPoint::setToBeforeNode(Node& child)
    119101{
    120102    ASSERT(child.parentNode());
    121103    m_childBeforeBoundary = child.previousSibling();
    122     m_containerNode = child.parentNode();
    123     m_offsetInContainer = m_childBeforeBoundary ? WTF::nullopt : Optional<unsigned>(0);
     104    m_container = *child.parentNode();
     105    m_offsetInContainer = m_childBeforeBoundary ? WTF::nullopt : makeOptional(0U);
    124106}
    125107
    126 inline void RangeBoundaryPoint::setToAfterChild(Node& child)
     108inline void RangeBoundaryPoint::setToAfterNode(Node& child)
    127109{
    128110    ASSERT(child.parentNode());
    129111    m_childBeforeBoundary = &child;
    130     m_containerNode = child.parentNode();
    131     m_offsetInContainer = m_childBeforeBoundary ? WTF::nullopt : Optional<unsigned>(0);
     112    m_container = *child.parentNode();
     113    m_offsetInContainer = m_childBeforeBoundary ? WTF::nullopt : makeOptional(0U);
    132114}
    133115
    134 inline void RangeBoundaryPoint::setToStartOfNode(Ref<Node>&& container)
     116inline void RangeBoundaryPoint::setToBeforeContents(Ref<Node>&& container)
    135117{
    136     m_containerNode = WTFMove(container);
     118    m_container = WTFMove(container);
    137119    m_offsetInContainer = 0;
    138120    m_childBeforeBoundary = nullptr;
    139121}
    140122
    141 inline void RangeBoundaryPoint::setToEndOfNode(Ref<Node>&& container)
     123inline void RangeBoundaryPoint::setToAfterContents(Ref<Node>&& container)
    142124{
    143     m_containerNode = WTFMove(container);
    144     if (is<CharacterData>(*m_containerNode)) {
    145         m_offsetInContainer = downcast<CharacterData>(*m_containerNode).length();
     125    m_container = WTFMove(container);
     126    if (is<CharacterData>(m_container)) {
     127        m_offsetInContainer = downcast<CharacterData>(m_container.get()).length();
    146128        m_childBeforeBoundary = nullptr;
    147129    } else {
    148         m_childBeforeBoundary = m_containerNode->lastChild();
    149         m_offsetInContainer = m_childBeforeBoundary ? WTF::nullopt : Optional<unsigned>(0);
     130        m_childBeforeBoundary = m_container->lastChild();
     131        m_offsetInContainer = m_childBeforeBoundary ? WTF::nullopt : makeOptional(0U);
    150132    }
    151133}
     
    168150inline bool operator==(const RangeBoundaryPoint& a, const RangeBoundaryPoint& b)
    169151{
    170     if (a.container() != b.container())
     152    if (&a.container() != &b.container())
    171153        return false;
    172     if (a.childBefore() || b.childBefore()) {
    173         if (a.childBefore() != b.childBefore())
    174             return false;
    175     } else {
    176         if (a.offset() != b.offset())
    177             return false;
    178     }
    179     return true;
     154    if (a.childBefore() || b.childBefore())
     155        return a.childBefore() == b.childBefore();
     156    return a.offset() == b.offset();
    180157}
    181158
    182159inline BoundaryPoint makeBoundaryPoint(const RangeBoundaryPoint& point)
    183160{
    184     return { *point.container(), point.offset() };
     161    return { point.container(), point.offset() };
    185162}
    186163
  • trunk/Source/WebCore/dom/SimpleRange.cpp

    r266123 r266295  
    7373    if (!offset)
    7474        return true;
     75    // If the container is not the parent, the child is part of a shadow tree, which we sort between offset 0 and offset 1.
     76    if (child.parentNode() != &container)
     77        return false;
    7578    unsigned currentOffset = 0;
    7679    for (auto currentChild = container.firstChild(); currentChild && currentChild != &child; currentChild = currentChild->nextSibling()) {
     
    100103
    101104    for (auto ancestor = b.container.ptr(); ancestor; ) {
    102         auto nextAncestor = ancestor->parentOrShadowHostNode();
     105        auto nextAncestor = ancestor->parentInComposedTree();
    103106        if (nextAncestor == a.container.ptr())
    104107            return isOffsetBeforeChild(*nextAncestor, a.offset, *ancestor) ? PartialOrdering::less : PartialOrdering::greater;
     
    107110
    108111    for (auto ancestor = a.container.ptr(); ancestor; ) {
    109         auto nextAncestor = ancestor->parentOrShadowHostNode();
     112        auto nextAncestor = ancestor->parentInComposedTree();
    110113        if (nextAncestor == b.container.ptr())
    111114            return isOffsetBeforeChild(*nextAncestor, b.offset, *ancestor) ? PartialOrdering::greater : PartialOrdering::less;
     
    206209}
    207210
    208 }
     211bool isPointInRange(const SimpleRange& range, const BoundaryPoint& point)
     212{
     213    return is_lteq(documentOrder(range.start, point)) && is_lteq(documentOrder(point, range.end));
     214}
     215
     216bool isPointInRange(const SimpleRange& range, const Optional<BoundaryPoint>& point)
     217{
     218    return point && isPointInRange(range, *point);
     219}
     220
     221PartialOrdering documentOrder(const SimpleRange& range, const BoundaryPoint& point)
     222{
     223    if (auto order = documentOrder(range.start, point); !is_lt(order))
     224        return order;
     225    if (auto order = documentOrder(range.end, point); !is_gt(order))
     226        return order;
     227    return PartialOrdering::equivalent;
     228}
     229
     230PartialOrdering documentOrder(const BoundaryPoint& point, const SimpleRange& range)
     231{
     232    if (auto order = documentOrder(point, range.start); !is_gt(order))
     233        return order;
     234    if (auto order = documentOrder(point, range.end); !is_lt(order))
     235        return order;
     236    return PartialOrdering::equivalent;
     237}
     238
     239bool contains(const SimpleRange& outerRange, const SimpleRange& innerRange)
     240{
     241    return is_lteq(documentOrder(outerRange.start, innerRange.start)) && is_gteq(documentOrder(outerRange.end, innerRange.end));
     242}
     243
     244bool intersects(const SimpleRange& a, const SimpleRange& b)
     245{
     246    return is_lteq(documentOrder(a.start, b.end)) && is_lteq(documentOrder(b.start, a.end));
     247}
     248
     249SimpleRange unionRange(const SimpleRange& a, const SimpleRange& b)
     250{
     251    auto& start = is_lteq(documentOrder(a.start, b.start)) ? a : b;
     252    auto& end = is_lteq(documentOrder(a.end, b.end)) ? b : a;
     253    return { start.start, end.end };
     254}
     255
     256bool contains(const SimpleRange& range, const Node& node)
     257{
     258    // FIXME: Consider a more efficient algorithm that avoids always computing the node index.
     259    // FIXME: Does this const_cast point to a design problem?
     260    auto nodeRange = makeRangeSelectingNode(const_cast<Node&>(node));
     261    return nodeRange && contains(range, *nodeRange);
     262}
     263
     264bool intersects(const SimpleRange& range, const Node& node)
     265{
     266    // FIXME: Consider a more efficient algorithm that avoids always computing the node index.
     267    // FIXME: Does this const_cast point to a design problem?
     268    auto nodeRange = makeRangeSelectingNode(const_cast<Node&>(node));
     269    if (!nodeRange)
     270        return node.contains(range.start.container.ptr());
     271    return is_lt(documentOrder(nodeRange->start, range.end)) && is_lt(documentOrder(range.start, nodeRange->end));
     272
     273}
     274
     275}
  • trunk/Source/WebCore/dom/SimpleRange.h

    r266123 r266295  
    6565
    6666bool operator==(const SimpleRange&, const SimpleRange&);
     67
     68WEBCORE_EXPORT bool isPointInRange(const SimpleRange&, const BoundaryPoint&);
     69bool isPointInRange(const SimpleRange&, const Optional<BoundaryPoint>&);
     70
     71WEBCORE_EXPORT bool contains(const SimpleRange& outerRange, const SimpleRange& innerRange);
     72WEBCORE_EXPORT bool intersects(const SimpleRange&, const SimpleRange&);
     73WEBCORE_EXPORT SimpleRange unionRange(const SimpleRange&, const SimpleRange&);
     74
     75WEBCORE_EXPORT bool contains(const SimpleRange&, const Node&);
     76WEBCORE_EXPORT bool intersects(const SimpleRange&, const Node&);
     77
     78// Returns equivalent if point is in range.
     79WEBCORE_EXPORT PartialOrdering documentOrder(const SimpleRange&, const BoundaryPoint&);
     80WEBCORE_EXPORT PartialOrdering documentOrder(const BoundaryPoint&, const SimpleRange&);
    6781
    6882class IntersectingNodeRange;
  • trunk/Source/WebCore/editing/Editing.cpp

    r265199 r266295  
    8080}
    8181
    82 // Compare two positions, taking into account the possibility that one or both
    83 // could be inside a shadow tree. Only works for non-null values.
     82// FIXME: Change callers to use documentOrder and delete this.
    8483int comparePositions(const Position& a, const Position& b)
    8584{
    86     TreeScope* commonScope = commonTreeScope(a.containerNode(), b.containerNode());
    87 
    88     if (!commonScope)
    89         return 0;
    90 
    91     Node* nodeA = commonScope->ancestorNodeInThisScope(a.containerNode());
    92     ASSERT(nodeA);
    93     bool hasDescendentA = nodeA != a.containerNode();
    94     int offsetA = hasDescendentA ? 0 : a.computeOffsetInContainerNode();
    95 
    96     Node* nodeB = commonScope->ancestorNodeInThisScope(b.containerNode());
    97     ASSERT(nodeB);
    98     bool hasDescendentB = nodeB != b.containerNode();
    99     int offsetB = hasDescendentB ? 0 : b.computeOffsetInContainerNode();
    100 
    101     int bias = 0;
    102     if (nodeA == nodeB) {
    103         if (hasDescendentA)
    104             bias = -1;
    105         else if (hasDescendentB)
    106             bias = 1;
    107     }
    108 
    109     auto comparisonResult = Range::compareBoundaryPoints(nodeA, offsetA, nodeB, offsetB);
    110     if (comparisonResult.hasException())
    111         return bias;
    112     auto result = comparisonResult.releaseReturnValue();
    113     return result ? result : bias;
    114 }
    115 
     85    auto ordering = documentOrder(a, b);
     86    if (is_lt(ordering))
     87        return -1;
     88    if (is_gt(ordering))
     89        return 1;
     90    return 0;
     91}
     92
     93// FIXME: Change callers to use documentOrder and delete this.
    11694int comparePositions(const VisiblePosition& a, const VisiblePosition& b)
    11795{
     
    11641142bool isNodeVisiblyContainedWithin(Node& node, const SimpleRange& range)
    11651143{
    1166     // If the node is inside the range, then it surely is contained within.
    1167     auto comparisonResult = createLiveRange(range)->compareNode(node);
    1168     if (!comparisonResult.hasException() && comparisonResult.releaseReturnValue() == Range::NODE_INSIDE)
     1144    if (contains(range, node))
    11691145        return true;
    11701146
  • trunk/Source/WebCore/editing/Editor.cpp

    r266265 r266295  
    35513551{
    35523552    for (auto* ownerElement = frame.ownerElement(); ownerElement; ownerElement = ownerElement->document().ownerElement()) {
    3553         if (&ownerElement->document() == &range.start.document()) {
    3554             auto result = createLiveRange(range)->intersectsNode(*ownerElement);
    3555             return !result.hasException() && result.releaseReturnValue();
    3556         }
     3553        if (&ownerElement->document() == &range.start.document())
     3554            return intersects(range, *ownerElement);
    35573555    }
    35583556    return false;
     
    37043702    auto& selection = m_document.selection();
    37053703    if (selection.isRange()) {
    3706         if (auto selectedRange = selection.selection().firstRange()) {
    3707             // Extend the range a few characters in each direction to detect incompletely selected phone numbers.
    3708             constexpr unsigned charactersToExtend = 15;
    3709             auto selectedLiveRange = createLiveRange(*selectedRange);
    3710             for (auto& range : scanForTelephoneNumbers(extendSelection(*selectedRange, charactersToExtend))) {
    3711                 // FIXME: Why do we do this unconditionally and the code below this only when it overlaps the selection?
    3712                 addMarker(range, DocumentMarker::TelephoneNumber);
    3713 
    3714                 // Only consider ranges with a detected telephone number if they overlap with the actual selection range.
    3715                 if (rangesOverlap(createLiveRange(range).ptr(), selectedLiveRange.ptr()))
    3716                     m_detectedTelephoneNumberRanges.append(range);
    3717             }
     3704        auto selectedRange = *selection.selection().firstRange();
     3705        // Extend the range a few characters in each direction to detect incompletely selected phone numbers.
     3706        constexpr unsigned charactersToExtend = 15;
     3707        for (auto& range : scanForTelephoneNumbers(extendSelection(selectedRange, charactersToExtend))) {
     3708            // FIXME: Why do we do this unconditionally instead of when only when it overlaps the selection?
     3709            addMarker(range, DocumentMarker::TelephoneNumber);
     3710
     3711            // Only consider ranges with a detected telephone number if they overlap with the selection.
     3712            if (intersects(range, selectedRange))
     3713                m_detectedTelephoneNumberRanges.append(range);
    37183714        }
    37193715    }
  • trunk/Source/WebCore/editing/EditorCommand.cpp

    r265199 r266295  
    229229}
    230230
    231 static SimpleRange unionRanges(const SimpleRange& a, const SimpleRange& b)
    232 {
    233     auto& start = createLiveRange(a)->compareBoundaryPoints(Range::START_TO_START, createLiveRange(b)).releaseReturnValue() <= 0 ? a : b;
    234     auto& end = createLiveRange(a)->compareBoundaryPoints(Range::END_TO_END, createLiveRange(b)).releaseReturnValue() <= 0 ? b : a;
    235     return { start.start, end.end };
    236 }
    237 
    238231// Execute command functions
    239232
     
    354347static bool executeDeleteToMark(Frame& frame, Event*, EditorCommandSource, const String&)
    355348{
    356     auto mark = frame.editor().mark().toNormalizedRange();
     349    auto& editor = frame.editor();
    357350    auto& selection = frame.selection();
    358     if (mark && frame.editor().selectedRange()) {
    359         if (!selection.setSelectedRange(unionRanges(*mark, *frame.editor().selectedRange()), DOWNSTREAM, FrameSelection::ShouldCloseTyping::Yes))
     351    auto markRange = editor.mark().toNormalizedRange();
     352    auto selectionRange = selection.selection().toNormalizedRange();
     353    if (markRange && selectionRange) {
     354        if (!selection.setSelectedRange(unionRange(*markRange, *selectionRange), DOWNSTREAM, FrameSelection::ShouldCloseTyping::Yes))
    360355            return false;
    361356    }
    362     frame.editor().performDelete();
    363     frame.editor().setMark(selection.selection());
     357    editor.performDelete();
     358    editor.setMark(selection.selection());
    364359    return true;
    365360}
     
    10511046static bool executeSelectToMark(Frame& frame, Event*, EditorCommandSource, const String&)
    10521047{
    1053     auto mark = frame.editor().mark().toNormalizedRange();
    1054     auto selection = frame.editor().selectedRange();
    1055     if (!mark || !selection) {
     1048    auto& editor = frame.editor();
     1049    auto& selection = frame.selection();
     1050    auto markRange = editor.mark().toNormalizedRange();
     1051    auto selectionRange = selection.selection().toNormalizedRange();
     1052    if (!markRange || !selectionRange) {
    10561053        PAL::systemBeep();
    10571054        return false;
    10581055    }
    1059     frame.selection().setSelectedRange(unionRanges(*mark, *selection), DOWNSTREAM, FrameSelection::ShouldCloseTyping::Yes);
     1056    selection.setSelectedRange(unionRange(*markRange, *selectionRange), DOWNSTREAM, FrameSelection::ShouldCloseTyping::Yes);
    10601057    // FIXME: Why do we ignore the return value from setSelectedRange here?
    10611058    return true;
  • trunk/Source/WebCore/editing/FrameSelection.cpp

    r266028 r266295  
    555555            m_selection.setWithoutValidation(m_selection.end(), m_selection.start());
    556556    } else if (isRange()) {
    557         if (auto range = m_selection.firstRange()) {
    558             auto compareNodeResult = createLiveRange(*range)->compareNode(node);
    559             if (!compareNodeResult.hasException()) {
    560                 auto compareResult = compareNodeResult.releaseReturnValue();
    561                 if (compareResult == Range::NODE_BEFORE_AND_AFTER || compareResult == Range::NODE_INSIDE) {
    562                     // If we did nothing here, when this node's renderer was destroyed, the rect that it
    563                     // occupied would be invalidated, but, selection gaps that change as a result of
    564                     // the removal wouldn't be invalidated.
    565                     // FIXME: Don't do so much unnecessary invalidation.
    566                     clearRenderTreeSelection = true;
    567                 }
    568             }
     557        if (auto range = m_selection.firstRange(); range && intersects(*range, node)) {
     558            // If we did nothing here, when this node's renderer was destroyed, the rect that it
     559            // occupied would be invalidated, but, selection gaps that change as a result of
     560            // the removal wouldn't be invalidated.
     561            // FIXME: Don't do so much unnecessary invalidation.
     562            clearRenderTreeSelection = true;
    569563        }
    570564    }
     
    20352029        return false;
    20362030
    2037     if (&range->start.container->document() != &range->end.container->document())
     2031    if (&range->start.document() != &range->end.document())
    20382032        return false;
    20392033
  • trunk/Source/WebCore/editing/ReplaceRangeWithTextCommand.cpp

    r265176 r266295  
    4242
    4343ReplaceRangeWithTextCommand::ReplaceRangeWithTextCommand(const SimpleRange& rangeToBeReplaced, const String& text)
    44     : CompositeEditCommand(rangeToBeReplaced.start.container->document(), EditAction::InsertReplacement)
     44    : CompositeEditCommand(rangeToBeReplaced.start.document(), EditAction::InsertReplacement)
    4545    , m_rangeToBeReplaced(rangeToBeReplaced)
    4646    , m_text(text)
  • trunk/Source/WebCore/editing/SpellingCorrectionCommand.cpp

    r265176 r266295  
    8585
    8686SpellingCorrectionCommand::SpellingCorrectionCommand(const SimpleRange& rangeToBeCorrected, const String& correction)
    87     : CompositeEditCommand(rangeToBeCorrected.start.container->document(), EditAction::InsertReplacement)
     87    : CompositeEditCommand(rangeToBeCorrected.start.document(), EditAction::InsertReplacement)
    8888    , m_rangeToBeCorrected(rangeToBeCorrected)
    8989    , m_selectionToBeCorrected(m_rangeToBeCorrected)
  • trunk/Source/WebCore/editing/TextCheckingHelper.cpp

    r266248 r266295  
    338338                    checkingTypes.add(TextCheckingType::Grammar);
    339339                VisibleSelection currentSelection;
    340                 if (Frame* frame = paragraphRange.start.container->document().frame())
     340                if (Frame* frame = paragraphRange.start.document().frame())
    341341                    currentSelection = frame->selection().selection();
    342342                checkTextOfParagraph(*m_client.textChecker(), paragraphString, checkingTypes, results, currentSelection);
  • trunk/Source/WebCore/editing/mac/DictionaryLookupLegacy.mm

    r265084 r266295  
    6969        return false;
    7070
    71     auto selectedRange = selection.toNormalizedRange();
    72     if (!selectedRange)
    73         return false;
    74 
    75     return createLiveRange(*selectedRange)->contains(position);
     71    auto selectedRange = selection.firstRange();
     72    return selectedRange && isPointInRange(*selectedRange, makeBoundaryPoint(position));
    7673}
    7774
  • trunk/Source/WebCore/editing/markup.cpp

    r266168 r266295  
    11211121Ref<DocumentFragment> createFragmentFromText(const SimpleRange& context, const String& text)
    11221122{
    1123     auto& document = context.start.container->document();
     1123    auto& document = context.start.document();
    11241124    auto fragment = document.createDocumentFragment();
    11251125   
  • trunk/Source/WebCore/loader/archive/cf/LegacyWebArchive.cpp

    r265084 r266295  
    456456RefPtr<LegacyWebArchive> LegacyWebArchive::create(const SimpleRange& range)
    457457{
    458     auto& document = range.start.container->document();
     458    auto& document = range.start.document();
    459459    auto* frame = document.frame();
    460460    if (!frame)
  • trunk/Source/WebCore/page/DOMSelection.cpp

    r266026 r266295  
    2828 */
    2929
    30 
    3130#include "config.h"
    3231#include "DOMSelection.h"
     
    285284ExceptionOr<void> DOMSelection::extend(Node& node, unsigned offset)
    286285{
    287     auto* frame = this->frame();
     286    auto frame = makeRefPtr(this->frame());
    288287    if (!frame)
    289288        return { };
    290     if (offset > (node.isCharacterDataNode() ? caretMaxOffset(node) : node.countChildNodes()))
     289    if (offset > node.length())
    291290        return Exception { IndexSizeError };
    292291    if (!isValidForPosition(&node))
    293292        return { };
    294 
    295     Ref<Frame> protector(*frame);
    296293    frame->selection().setExtent(createLegacyEditingPosition(&node, offset), DOWNSTREAM);
    297294    return { };
     
    302299    if (index >= rangeCount())
    303300        return Exception { IndexSizeError };
    304 
    305     // If you're hitting this, you've added broken multi-range selection support.
    306     ASSERT(rangeCount() == 1);
    307 
    308     auto* frame = this->frame();
    309     if (auto* shadowAncestor = selectionShadowAncestor(*frame)) {
    310         auto* container = shadowAncestor->parentNodeGuaranteedHostFree();
    311         unsigned offset = shadowAncestor->computeNodeIndex();
    312         return createLiveRange(makeSimpleRange(BoundaryPoint { *container, offset }));
     301    auto& frame = *this->frame();
     302    if (auto shadowAncestor = selectionShadowAncestor(frame))
     303        return createLiveRange(makeSimpleRange(*makeBoundaryPointBeforeNode(*shadowAncestor)));
     304    return createLiveRange(*frame.selection().selection().firstRange());
     305}
     306
     307void DOMSelection::removeAllRanges()
     308{
     309    auto* frame = this->frame();
     310    if (!frame)
     311        return;
     312    frame->selection().clear();
     313}
     314
     315void DOMSelection::addRange(Range& liveRange)
     316{
     317    auto frame = makeRefPtr(this->frame());
     318    if (!frame)
     319        return;
     320
     321    auto range = makeSimpleRange(liveRange);
     322    auto& selection = frame->selection();
     323
     324    if (auto selectedRange = selection.selection().toNormalizedRange()) {
     325        if (!selectedRange->start.container->containingShadowRoot() && intersects(*selectedRange, range))
     326            selection.setSelection(unionRange(*selectedRange, range));
     327        return;
    313328    }
    314329
    315     auto firstRange = frame->selection().selection().firstRange();
    316     ASSERT(firstRange);
    317     if (!firstRange)
    318         return Exception { IndexSizeError };
    319     return createLiveRange(*firstRange);
    320 }
    321 
    322 void DOMSelection::removeAllRanges()
    323 {
    324     auto* frame = this->frame();
    325     if (!frame)
    326         return;
    327     frame->selection().clear();
    328 }
    329 
    330 void DOMSelection::addRange(Range& range)
    331 {
    332     auto* frame = this->frame();
    333     if (!frame)
    334         return;
    335 
    336     Ref<Frame> protector(*frame);
    337 
    338     auto& selection = frame->selection();
    339     auto selectedRange = selection.selection().toNormalizedRange();
    340     if (!selectedRange || selectedRange->start.container->containingShadowRoot()) {
    341         selection.setSelection(makeSimpleRange(range));
    342         return;
    343     }
    344 
    345     auto normalizedRange = createLiveRange(selectedRange);
    346     auto result = range.compareBoundaryPoints(Range::START_TO_START, *normalizedRange);
    347     if (!result.hasException() && result.releaseReturnValue() == -1) {
    348         // We don't support discontiguous selection. We don't do anything if the two ranges don't intersect.
    349         result = range.compareBoundaryPoints(Range::START_TO_END, *normalizedRange);
    350         if (!result.hasException() && result.releaseReturnValue() > -1) {
    351             result = range.compareBoundaryPoints(Range::END_TO_END, *normalizedRange);
    352             if (!result.hasException() && result.releaseReturnValue() == -1) {
    353                 // The ranges intersect.
    354                 selection.moveTo(makeDeprecatedLegacyPosition(&range.startContainer(), range.startOffset()), makeDeprecatedLegacyPosition(&normalizedRange->endContainer(), normalizedRange->endOffset()), DOWNSTREAM);
    355             } else {
    356                 // The new range contains the original range.
    357                 selection.setSelection(makeSimpleRange(range));
    358             }
    359         }
    360     } else {
    361         // We don't support discontiguous selection. We don't do anything if the two ranges don't intersect.
    362         result = range.compareBoundaryPoints(Range::END_TO_START, *normalizedRange);
    363         if (!result.hasException() && result.releaseReturnValue() < 1) {
    364             result = range.compareBoundaryPoints(Range::END_TO_END, *normalizedRange);
    365             if (!result.hasException() && result.releaseReturnValue() == -1) {
    366                 // The original range contains the new range.
    367                 selection.setSelection(makeSimpleRange(*normalizedRange));
    368             } else {
    369                 // The ranges intersect.
    370                 selection.moveTo(makeDeprecatedLegacyPosition(&normalizedRange->startContainer(), normalizedRange->startOffset()), makeDeprecatedLegacyPosition(&range.endContainer(), range.endOffset()), DOWNSTREAM);
    371             }
    372         }
    373     }
     330    selection.setSelection(range);
    374331}
    375332
     
    393350bool DOMSelection::containsNode(Node& node, bool allowPartial) const
    394351{
     352    // FIXME: This behavior does not match what the selection API standard specifies.
     353    if (node.isTextNode())
     354        allowPartial = true;
     355
    395356    auto* frame = this->frame();
    396357    if (!frame)
    397358        return false;
    398359
    399     auto& selection = frame->selection();
    400     if (frame->document() != &node.document() || selection.isNone())
    401         return false;
    402 
    403     Ref<Node> protectedNode(node);
    404     auto selectedRange = selection.selection().toNormalizedRange();
     360    auto selectedRange = frame->selection().selection().firstRange();
    405361    if (!selectedRange || selectedRange->start.container->containingShadowRoot())
    406362        return false;
    407363
    408     ContainerNode* parentNode = node.parentNode();
    409     if (!parentNode || !parentNode->isConnected())
    410         return false;
    411     unsigned nodeIndex = node.computeNodeIndex();
    412 
    413     auto startsResult = Range::compareBoundaryPoints(parentNode, nodeIndex, &selectedRange->startContainer(), selectedRange->startOffset());
    414     if (startsResult.hasException())
    415         return false;
    416 
    417     auto endsResult = Range::compareBoundaryPoints(parentNode, nodeIndex + 1, &selectedRange->endContainer(), selectedRange->endOffset());
    418     ASSERT(!endsResult.hasException());
    419     bool isNodeFullySelected = !startsResult.hasException() && startsResult.releaseReturnValue() >= 0
    420         && !endsResult.hasException() && endsResult.releaseReturnValue() <= 0;
    421     if (isNodeFullySelected)
    422         return true;
    423 
    424     auto startEndResult = Range::compareBoundaryPoints(parentNode, nodeIndex, &selectedRange->endContainer(), selectedRange->endOffset());
    425     ASSERT(!startEndResult.hasException());
    426     auto endStartResult = Range::compareBoundaryPoints(parentNode, nodeIndex + 1, &selectedRange->startContainer(), selectedRange->startOffset());
    427     ASSERT(!endStartResult.hasException());
    428     bool isNodeFullyUnselected = (!startEndResult.hasException() && startEndResult.releaseReturnValue() > 0)
    429         || (!endStartResult.hasException() && endStartResult.releaseReturnValue() < 0);
    430     if (isNodeFullyUnselected)
    431         return false;
    432 
    433     return allowPartial || node.isTextNode();
     364    return allowPartial ? intersects(*selectedRange, node) : contains(*selectedRange, node);
    434365}
    435366
     
    484415{
    485416    auto* frame = this->frame();
    486     if (!frame)
    487         return false;
    488     if (!node)
    489         return true;
    490     return &node->document() == frame->document();
     417    return frame && (!node || &node->document() == frame->document());
    491418}
    492419
  • trunk/Source/WebCore/page/DragController.cpp

    r265228 r266295  
    155155            String url = dragData.asURL(DragData::DoNotConvertFilenames, &title);
    156156            if (!url.isEmpty()) {
    157                 auto& document = context.start.container->document();
     157                auto& document = context.start.document();
    158158                auto anchor = HTMLAnchorElement::create(document);
    159159                anchor->setHref(url);
     
    775775    if (!startElement)
    776776        return nullptr;
     777
    777778#if ENABLE(ATTACHMENT_ELEMENT)
    778779    if (auto attachment = enclosingAttachmentElement(*startElement)) {
    779         auto selection = sourceFrame->selection().selection();
     780        auto& selection = sourceFrame->selection().selection();
    780781        bool isSingleAttachmentSelection = selection.start() == Position(attachment.get(), Position::PositionIsBeforeAnchor) && selection.end() == Position(attachment.get(), Position::PositionIsAfterAnchor);
    781         bool isAttachmentElementInCurrentSelection = false;
    782         if (auto selectedRange = selection.toNormalizedRange()) {
    783             auto compareResult = createLiveRange(*selectedRange)->compareNode(*attachment);
    784             isAttachmentElementInCurrentSelection = !compareResult.hasException() && compareResult.releaseReturnValue() == Range::NODE_INSIDE;
    785         }
    786 
    787         if (!isAttachmentElementInCurrentSelection || isSingleAttachmentSelection) {
     782        auto selectedRange = selection.firstRange();
     783        if (isSingleAttachmentSelection || !selectedRange || !contains(*selectedRange, *attachment)) {
    788784            state.type = DragSourceAction::Attachment;
    789785            return attachment.get();
     
    14721468    Vector<Ref<HTMLImageElement>> placeholders;
    14731469    for (auto& placeholder : descendantsOfType<HTMLImageElement>(downcast<ContainerNode>(*container))) {
    1474         auto intersectsNode = createLiveRange(*insertedContentRange)->intersectsNode(placeholder);
    1475         if (!intersectsNode.hasException() && intersectsNode.returnValue())
     1470        if (intersects(*insertedContentRange, placeholder))
    14761471            placeholders.append(placeholder);
    14771472    }
  • trunk/Source/WebCore/page/EventHandler.cpp

    r266252 r266295  
    27422742    if (element && m_frame.selection().isRange()) {
    27432743        if (auto range = m_frame.selection().selection().toNormalizedRange()) {
    2744             auto result = createLiveRange(*range)->compareNode(*element);
    2745             if (!result.hasException() && result.releaseReturnValue() == Range::NODE_INSIDE && element->isDescendantOf(m_frame.document()->focusedElement()))
     2744            if (contains(*range, *element) && element->isDescendantOf(m_frame.document()->focusedElement()))
    27462745                return true;
    27472746        }
  • trunk/Source/WebCore/page/Page.cpp

    r266026 r266295  
    731731    if (frameWithSelection) {
    732732        result.indexForSelection = NoMatchAfterUserSelection;
    733         auto selectedRange = frameWithSelection->selection().selection().firstRange();
     733        auto selectedRange = *frameWithSelection->selection().selection().firstRange();
    734734        if (options.contains(Backwards)) {
    735735            for (size_t i = result.ranges.size(); i > 0; --i) {
    736                 auto comparisonResult = createLiveRange(selectedRange)->compareBoundaryPoints(Range::END_TO_START, createLiveRange(result.ranges[i - 1]));
    737                 if (!comparisonResult.hasException() && comparisonResult.returnValue() > 0) {
     736                // FIXME: Seems like this should be is_gteq to correctly handle the same string found twice in a row.
     737                if (is_gt(documentOrder(selectedRange.start, result.ranges[i - 1].end))) {
    738738                    result.indexForSelection = i - 1;
    739739                    break;
     
    742742        } else {
    743743            for (size_t i = 0, size = result.ranges.size(); i < size; ++i) {
    744                 auto comparisonResult = createLiveRange(selectedRange)->compareBoundaryPoints(Range::START_TO_END, createLiveRange(result.ranges[i]));
    745                 if (!comparisonResult.hasException() && comparisonResult.returnValue() < 0) {
     744                // FIXME: Seems like this should be is_lteq to correctly handle the same string found twice in a row.
     745                if (is_lt(documentOrder(selectedRange.end, result.ranges[i].start))) {
    746746                    result.indexForSelection = i;
    747747                    break;
     
    764764        return WTF::nullopt;
    765765
    766     if (referenceRange && referenceRange->start.container->document().page() != this)
     766    if (referenceRange && referenceRange->start.document().page() != this)
    767767        return WTF::nullopt;
    768768
    769769    CanWrap canWrap = options.contains(WrapAround) ? CanWrap::Yes : CanWrap::No;
    770     Frame* frame = referenceRange ? referenceRange->start.container->document().frame() : &mainFrame();
     770    Frame* frame = referenceRange ? referenceRange->start.document().frame() : &mainFrame();
    771771    Frame* startFrame = frame;
    772772    do {
  • trunk/Source/WebCore/page/mac/ServicesOverlayController.mm

    r260753 r266295  
    631631
    632632    for (auto& highlight : m_potentialHighlights) {
    633         if (highlight->type() == Highlight::TelephoneNumberType && createLiveRange(highlight->range())->contains(createLiveRange(*selectionRange)))
     633        if (highlight->type() == Highlight::TelephoneNumberType && contains(highlight->range(), *selectionRange))
    634634            return highlight.get();
    635635    }
  • trunk/Source/WebCore/rendering/RenderObject.cpp

    r266123 r266295  
    19761976    Vector<FloatRect> rects;
    19771977
    1978     range.start.container->document().updateLayoutIgnorePendingStylesheets();
     1978    range.start.document().updateLayoutIgnorePendingStylesheets();
    19791979
    19801980    bool useVisibleBounds = behavior.contains(RenderObject::BoundingRectBehavior::UseVisibleBounds);
  • trunk/Source/WebCore/testing/Internals.cpp

    r266248 r266295  
    21622162}
    21632163
    2164 String Internals::rangeAsText(const Range& range)
    2165 {
    2166     return range.text();
    2167 }
    2168 
    2169 String Internals::rangeAsTextUsingBackwardsTextIterator(const Range& range)
    2170 {
    2171     String result;
    2172     for (SimplifiedBackwardsTextIterator backwardsIterator(makeSimpleRange(range)); !backwardsIterator.atEnd(); backwardsIterator.advance())
    2173         result.insert(backwardsIterator.text().toString(), 0);
    2174     return result;
    2175 }
    2176 
    2177 Ref<Range> Internals::subrange(Range& range, unsigned rangeLocation, unsigned rangeLength)
    2178 {
    2179     return createLiveRange(resolveCharacterRange(makeSimpleRange(range), { rangeLocation, rangeLength }));
    2180 }
    2181 
    2182 RefPtr<Range> Internals::rangeOfStringNearLocation(const Range& range, const String& text, unsigned targetOffset)
    2183 {
    2184     return createLiveRange(findClosestPlainText(makeSimpleRange(range), text, { }, targetOffset));
     2164String Internals::rangeAsText(const Range& liveRange)
     2165{
     2166    auto range = makeSimpleRange(liveRange);
     2167    range.start.document().updateLayout();
     2168    return plainText(range);
     2169}
     2170
     2171// FIXME: Move this to StringConcatenate.h.
     2172static String join(Vector<String>&& strings)
     2173{
     2174    StringBuilder result;
     2175    for (auto& string : strings)
     2176        result.append(WTFMove(string));
     2177    return result.toString();
     2178}
     2179
     2180String Internals::rangeAsTextUsingBackwardsTextIterator(const Range& liveRange)
     2181{
     2182    auto range = makeSimpleRange(liveRange);
     2183    range.start.document().updateLayout();
     2184    Vector<String> strings;
     2185    for (SimplifiedBackwardsTextIterator backwardsIterator(range); !backwardsIterator.atEnd(); backwardsIterator.advance())
     2186        strings.append(backwardsIterator.text().toString());
     2187    strings.reverse();
     2188    return join(WTFMove(strings));
     2189}
     2190
     2191Ref<Range> Internals::subrange(Range& liveRange, unsigned rangeLocation, unsigned rangeLength)
     2192{
     2193    auto range = makeSimpleRange(liveRange);
     2194    range.start.document().updateLayout();
     2195    return createLiveRange(resolveCharacterRange(range, { rangeLocation, rangeLength }));
     2196}
     2197
     2198RefPtr<Range> Internals::rangeOfStringNearLocation(const Range& liveRange, const String& text, unsigned targetOffset)
     2199{
     2200    auto range = makeSimpleRange(liveRange);
     2201    range.start.document().updateLayout();
     2202    return createLiveRange(findClosestPlainText(range, text, { }, targetOffset));
    21852203}
    21862204
  • trunk/Source/WebKit/ChangeLog

    r266287 r266295  
     12020-08-28  Darin Adler  <darin@apple.com>
     2
     3        Remove almost all the remaining uses of live ranges
     4        https://bugs.webkit.org/show_bug.cgi?id=215755
     5
     6        Reviewed by Sam Weinig.
     7
     8        * WebProcess/InjectedBundle/API/gtk/DOM/WebKitDOMRange.cpp:
     9        (webkit_dom_range_compare_boundary_points): Update for rename of
     10        compareBoundaryPointsForBindings.
     11        (webkit_dom_range_intersects_node): Removed exception handling.
     12        (webkit_dom_range_get_text): Use plainText.
     13
     14        * WebProcess/InjectedBundle/API/mac/WKDOMRange.mm:
     15        (-[WKDOMRange initWithDocument:]): Tightened up into a one-liner.
     16        (-[WKDOMRange text]): Use plainText.
     17        (-[WKDOMRange textRects]): Stopped using Range::ownerDocument.
     18
     19        * WebProcess/InjectedBundle/DOM/InjectedBundleRangeHandle.cpp:
     20        (WebKit::InjectedBundleRangeHandle::document): Stopped using
     21        Range::ownerDocument.
     22        (WebKit::InjectedBundleRangeHandle::boundingRectInWindowCoordinates const):
     23        Ditto.
     24        (WebKit::InjectedBundleRangeHandle::renderedImage): Ditto.
     25        (WebKit::InjectedBundleRangeHandle::text const): Use plainText.
     26
     27        * WebProcess/WebPage/glib/WebPageGLib.cpp:
     28        (WebKit::WebPage::getPlatformEditorState const): Use contains.
     29
     30        * WebProcess/WebPage/ios/WebPageIOS.mm:
     31        (WebKit::WebPage::requestDocumentEditingContext): Use intersects.
     32
    1332020-08-28  Alex Christensen  <achristensen@webkit.org>
    234
  • trunk/Source/WebKit/WebProcess/InjectedBundle/API/gtk/DOM/WebKitDOMRange.cpp

    r234586 r266295  
    2626#include <WebCore/Document.h>
    2727#include <WebCore/JSExecState.h>
     28#include <WebCore/TextIterator.h>
    2829#include "WebKitDOMDocumentFragmentPrivate.h"
    2930#include "WebKitDOMNodePrivate.h"
     
    356357    g_return_val_if_fail(WEBKIT_DOM_IS_RANGE(sourceRange), 0);
    357358    g_return_val_if_fail(!error || !*error, 0);
    358     WebCore::Range* item = WebKit::core(self);
    359     WebCore::Range* convertedSourceRange = WebKit::core(sourceRange);
    360     auto result = item->compareBoundaryPointsForBindings(how, *convertedSourceRange);
     359    auto result = WebKit::core(self)->compareBoundaryPoints(how, *WebKit::core(sourceRange));
    361360    if (result.hasException()) {
    362361        auto description = WebCore::DOMException::description(result.releaseException().code());
     
    509508    g_return_val_if_fail(WEBKIT_DOM_IS_NODE(refNode), FALSE);
    510509    g_return_val_if_fail(!error || !*error, FALSE);
    511     WebCore::Range* item = WebKit::core(self);
    512     WebCore::Node* convertedRefNode = WebKit::core(refNode);
    513     auto result = item->intersectsNode(*convertedRefNode);
    514     if (result.hasException()) {
    515         auto description = WebCore::DOMException::description(result.releaseException().code());
    516         g_set_error_literal(error, g_quark_from_string("WEBKIT_DOM"), description.legacyCode, description.name);
    517         return false;
    518     }
    519     return result.releaseReturnValue();
     510    return WebKit::core(self)->intersectsNode(*WebKit::core(refNode));
    520511}
    521512
     
    633624    WebCore::JSMainThreadNullState state;
    634625    g_return_val_if_fail(WEBKIT_DOM_IS_RANGE(self), 0);
    635     WebCore::Range* item = WebKit::core(self);
    636     gchar* result = convertToUTF8String(item->text());
    637     return result;
     626    auto range = makeSimpleRange(*WebKit::core(self));
     627    range.start.document().updateLayout();
     628    return convertToUTF8String(plainText(range));
    638629}
    639630
  • trunk/Source/WebKit/WebProcess/InjectedBundle/API/mac/WKDOMRange.mm

    r266026 r266295  
    3131#import "WKDOMInternals.h"
    3232#import <WebCore/Document.h>
     33#import <WebCore/TextIterator.h>
    3334#import <WebCore/VisibleUnits.h>
    3435#import <wtf/cocoa/VectorCocoa.h>
     
    5051- (id)initWithDocument:(WKDOMDocument *)document
    5152{
    52     auto range = WebCore::Range::create(*WebKit::toWebCoreDocument(document));
    53     self = [self _initWithImpl:range.ptr()];
    54     if (!self)
    55         return nil;
    56 
    57     return self;
     53    return [self _initWithImpl:WebCore::Range::create(*WebKit::toWebCoreDocument(document)).ptr()];
    5854}
    5955
     
    119115- (NSString *)text
    120116{
    121     return _impl->text();
     117    auto range = makeSimpleRange(*_impl);
     118    range.start.document().updateLayout();
     119    return plainText(range);
    122120}
    123121
     
    129127- (NSArray *)textRects
    130128{
    131     _impl->ownerDocument().updateLayoutIgnorePendingStylesheets();
    132     return createNSArray(WebCore::RenderObject::absoluteTextRects(makeSimpleRange(*_impl))).autorelease();
     129    auto range = makeSimpleRange(*_impl);
     130    range.start.document().updateLayoutIgnorePendingStylesheets();
     131    return createNSArray(WebCore::RenderObject::absoluteTextRects(range)).autorelease();
    133132}
    134133
  • trunk/Source/WebKit/WebProcess/InjectedBundle/DOM/InjectedBundleRangeHandle.cpp

    r266028 r266295  
    4545#include <WebCore/RenderView.h>
    4646#include <WebCore/SimpleRange.h>
     47#include <WebCore/TextIterator.h>
    4748#include <WebCore/VisibleSelection.h>
    4849#include <wtf/HashMap.h>
     
    9899Ref<InjectedBundleNodeHandle> InjectedBundleRangeHandle::document()
    99100{
    100     return InjectedBundleNodeHandle::getOrCreate(m_range->ownerDocument());
     101    return InjectedBundleNodeHandle::getOrCreate(m_range->startContainer().document());
    101102}
    102103
    103104WebCore::IntRect InjectedBundleRangeHandle::boundingRectInWindowCoordinates() const
    104105{
    105     Frame* frame = m_range->ownerDocument().frame();
    106     return frame->view()->contentsToWindow(enclosingIntRect(unionRectIgnoringZeroRects(RenderObject::absoluteBorderAndTextRects(makeSimpleRange(m_range)))));
     106    auto range = makeSimpleRange(m_range);
     107    auto frame = range.start.document().frame();
     108    if (!frame)
     109        return { };
     110    auto view = frame->view();
     111    if (!view)
     112        return { };
     113    return view->contentsToWindow(enclosingIntRect(unionRectIgnoringZeroRects(RenderObject::absoluteBorderAndTextRects(range))));
    107114}
    108115
    109116RefPtr<WebImage> InjectedBundleRangeHandle::renderedImage(SnapshotOptions options)
    110117{
    111     Document& ownerDocument = m_range->ownerDocument();
    112     Frame* frame = ownerDocument.frame();
     118    auto range = makeSimpleRange(m_range);
     119
     120    auto document = makeRef(range.start.document());
     121
     122    auto frame = makeRefPtr(document->frame());
    113123    if (!frame)
    114124        return nullptr;
    115125
    116     FrameView* frameView = frame->view();
     126    auto frameView = frame->view();
    117127    if (!frameView)
    118128        return nullptr;
     
    122132#endif
    123133
    124     Ref<Frame> protector(*frame);
    125 
    126134    VisibleSelection oldSelection = frame->selection().selection();
    127     frame->selection().setSelection(makeSimpleRange(m_range));
     135    frame->selection().setSelection(range);
    128136
    129137    float scaleFactor = (options & SnapshotOptionsExcludeDeviceScaleFactor) ? 1 : frame->page()->deviceScaleFactor();
    130     IntRect paintRect = enclosingIntRect(unionRectIgnoringZeroRects(RenderObject::absoluteBorderAndTextRects(makeSimpleRange(m_range))));
     138    IntRect paintRect = enclosingIntRect(unionRectIgnoringZeroRects(RenderObject::absoluteBorderAndTextRects(range)));
    131139    IntSize backingStoreSize = paintRect.size();
    132140    backingStoreSize.scale(scaleFactor);
     
    156164
    157165    frameView->setPaintBehavior(paintBehavior);
    158     ownerDocument.updateLayout();
     166    document->updateLayout();
    159167
    160168    frameView->paint(*graphicsContext, paintRect);
     
    168176String InjectedBundleRangeHandle::text() const
    169177{
    170     return m_range->text();
     178    auto range = makeSimpleRange(m_range);
     179    range.start.document().updateLayout();
     180    return plainText(range);
    171181}
    172182
  • trunk/Source/WebKit/WebProcess/WebPage/FindController.cpp

    r265190 r266295  
    306306    if (matchIndex >= m_findMatches.size())
    307307        return;
    308     Frame* frame = m_findMatches[matchIndex].start.container->document().frame();
     308    Frame* frame = m_findMatches[matchIndex].start.document().frame();
    309309    if (!frame)
    310310        return;
     
    337337    if (matchIndex >= m_findMatches.size())
    338338        return;
    339     Frame* frame = m_findMatches[matchIndex].start.container->document().frame();
     339    Frame* frame = m_findMatches[matchIndex].start.document().frame();
    340340    if (!frame)
    341341        return;
  • trunk/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp

    r265176 r266295  
    110110        auto surroundingRange = makeSimpleRange(surroundingStart, endOfEditableContent(selectionStart));
    111111        auto compositionRange = frame.editor().compositionRange();
    112         if (surroundingRange && compositionRange && createLiveRange(surroundingRange)->contains(createLiveRange(*compositionRange).get())) {
     112        if (surroundingRange && compositionRange && contains(*surroundingRange, *compositionRange)) {
    113113            auto beforeText = plainText({ surroundingRange->start, compositionRange->start });
    114114            postLayoutData.surroundingContext = beforeText + plainText({ compositionRange->end, surroundingRange->end });
  • trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm

    r266265 r266295  
    42014201    auto selectionRange = selection.toNormalizedRange();
    42024202    auto rangeOfInterest = *makeSimpleRange(rangeOfInterestStart, rangeOfInterestEnd);
    4203     if (selectionRange && rangesOverlap(createLiveRange(rangeOfInterest).ptr(), createLiveRange(*selectionRange).ptr())) {
     4203    if (selectionRange && intersects(rangeOfInterest, *selectionRange)) {
    42044204        startOfRangeOfInterestInSelection = std::max(rangeOfInterestStart, selectionStart);
    42054205        endOfRangeOfInterestInSelection = std::min(rangeOfInterestEnd, selectionEnd);
     
    42664266    context.selectedText = makeString(startOfRangeOfInterestInSelection, endOfRangeOfInterestInSelection);
    42674267    context.contextAfter = makeString(endOfRangeOfInterestInSelection, contextAfterEnd);
    4268     if (compositionRange && rangesOverlap(createLiveRange(rangeOfInterest).ptr(), createLiveRange(*compositionRange).ptr())) {
     4268    if (compositionRange && intersects(rangeOfInterest, *compositionRange)) {
    42694269        VisiblePosition compositionStart(createLegacyEditingPosition(compositionRange->start));
    42704270        VisiblePosition compositionEnd(createLegacyEditingPosition(compositionRange->end));
     
    42824282            if (!iterator.text().isEmpty()) {
    42834283                auto absoluteBoundingBox = unionRect(RenderObject::absoluteTextRects(iterator.range(), RenderObject::BoundingRectBehavior::IgnoreEmptyTextSelections));
    4284                 rects.append({ iterator.range().start.container->document().view()->contentsToRootView(absoluteBoundingBox), { offsetSoFar++, stride } });
     4284                rects.append({ iterator.range().start.document().view()->contentsToRootView(absoluteBoundingBox), { offsetSoFar++, stride } });
    42854285            }
    42864286            iterator.advance(stride);
  • trunk/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm

    r266051 r266295  
    878878            continue;
    879879
    880         auto view = actionContext->range.start.container->document().view();
     880        auto view = actionContext->range.start.document().view();
    881881        if (!view)
    882882            continue;
  • trunk/Source/WebKitLegacy/mac/ChangeLog

    r266265 r266295  
     12020-08-28  Darin Adler  <darin@apple.com>
     2
     3        Remove almost all the remaining uses of live ranges
     4        https://bugs.webkit.org/show_bug.cgi?id=215755
     5
     6        Reviewed by Sam Weinig.
     7
     8        * DOM/DOMRange.mm:
     9        (-[DOMRange text]): Use plainText.
     10        (-[DOMRange compareBoundaryPoints:sourceRange:]): Update for rename of
     11        compareBoundaryPointsForBindings.
     12        (-[DOMRange intersectsNode:]): Removed raiseOnDOMError.
     13
     14        * DOM/DOMUIKitExtensions.mm:
     15        (firstNodeAfter): Moved Range::firstNode here since it's the only remaining caller;
     16        might need to keep legacy behavior depending on how this is used by UIKit.
     17        (-[DOMRange firstNode]): Call firstNodeAfter.
     18
     19        * DOM/WebDOMOperations.mm:
     20        (-[DOMRange markupString]): Stop using Range::ownerDocument.
     21
    1222020-08-27  Devin Rousso  <drousso@apple.com>
    223
  • trunk/Source/WebKitLegacy/mac/DOM/DOM.mm

    r266028 r266295  
    571571#endif
    572572{
    573     // FIXME: The call to updateLayoutIgnorePendingStylesheets should be moved into WebCore::Range.
    574     auto& range = *core(self);
    575     range.ownerDocument().updateLayoutIgnorePendingStylesheets();
    576     return unionRect(RenderObject::absoluteTextRects(makeSimpleRange(range)));
     573    auto range = makeSimpleRange(*core(self));
     574    range.start.document().updateLayoutIgnorePendingStylesheets();
     575    return unionRect(RenderObject::absoluteTextRects(range));
    577576}
    578577
     
    584583{
    585584    auto range = makeSimpleRange(*core(self));
    586     auto frame = makeRefPtr(range.start.container->document().frame());
     585    auto frame = makeRefPtr(range.start.document().frame());
    587586    if (!frame)
    588587        return nil;
     
    603602{
    604603    auto range = makeSimpleRange(*core(self));
    605     range.start.container->document().updateLayoutIgnorePendingStylesheets();
     604    range.start.document().updateLayoutIgnorePendingStylesheets();
    606605    return createNSArray(RenderObject::absoluteTextRects(range)).autorelease();
    607606}
  • trunk/Source/WebKitLegacy/mac/DOM/DOMRange.mm

    r265190 r266295  
    3434#import <WebCore/Range.h>
    3535#import <WebCore/SimpleRange.h>
     36#import <WebCore/TextIterator.h>
    3637#import <WebCore/ThreadCheck.h>
    3738#import <WebCore/WebCoreObjCExtras.h>
     
    9394{
    9495    WebCore::JSMainThreadNullState state;
    95     return IMPL->text();
     96    auto range = makeSimpleRange(*IMPL);
     97    range.start.document().updateLayout();
     98    return plainText(range);
    9699}
    97100
     
    171174    if (!sourceRange)
    172175        raiseTypeErrorException();
    173     return raiseOnDOMError(IMPL->compareBoundaryPointsForBindings(how, *core(sourceRange)));
     176    return raiseOnDOMError(IMPL->compareBoundaryPoints(how, *core(sourceRange)));
    174177}
    175178
     
    245248    if (!refNode)
    246249        raiseTypeErrorException();
    247     return raiseOnDOMError(IMPL->intersectsNode(*core(refNode)));
     250    return IMPL->intersectsNode(*core(refNode));
    248251}
    249252
  • trunk/Source/WebKitLegacy/mac/DOM/DOMUIKitExtensions.mm

    r265190 r266295  
    5252#import <WebCore/Image.h>
    5353#import <WebCore/InlineBox.h>
    54 #import <WebCore/Node.h>
     54#import <WebCore/NodeTraversal.h>
    5555#import <WebCore/Range.h>
    5656#import <WebCore/RenderBlock.h>
     
    125125}
    126126
     127// FIXME: Refactor to share code with intersectingNodesWithDeprecatedZeroOffsetStartQuirk.
     128static WebCore::Node* firstNodeAfter(const WebCore::BoundaryPoint& point)
     129{
     130    if (point.container->isCharacterDataNode())
     131        return point.container.ptr();
     132    if (auto child = point.container->traverseToChildAt(point.offset))
     133        return child;
     134    if (!point.offset)
     135        return point.container.ptr();
     136    return WebCore::NodeTraversal::nextSkippingChildren(point.container);
     137}
     138
    127139- (DOMNode *)firstNode
    128140{
    129     return kit(core(self)->firstNode());
     141    return kit(firstNodeAfter(makeSimpleRange(*core(self)).start));
    130142}
    131143
  • trunk/Source/WebKitLegacy/mac/DOM/WebDOMOperations.mm

    r265190 r266295  
    192192- (NSString *)markupString
    193193{
    194     auto& range = *core(self);
    195     return String { documentTypeString(range.ownerDocument()) + serializePreservingVisualAppearance(makeSimpleRange(range), nullptr, AnnotateForInterchange::Yes) };
     194    auto range = makeSimpleRange(*core(self));
     195    return String { documentTypeString(range.start.document()) + serializePreservingVisualAppearance(range, nullptr, AnnotateForInterchange::Yes) };
    196196}
    197197
  • trunk/Source/WebKitLegacy/mac/WebView/WebPDFView.mm

    r261210 r266295  
    637637}
    638638
    639 static BOOL isFrameInRange(WebFrame *frame, DOMRange *range)
    640 {
    641     BOOL inRange = NO;
    642     for (auto* ownerElement = core(frame)->ownerElement(); ownerElement; ownerElement = ownerElement->document().frame()->ownerElement()) {
    643         if (&ownerElement->document() == &core(range)->ownerDocument()) {
    644             inRange = [range intersectsNode:kit(ownerElement)];
    645             break;
    646         }
    647     }
    648     return inRange;
     639static bool isFrameInRange(WebCore::Frame& frame, const WebCore::SimpleRange& range)
     640{
     641    for (auto* ownerElement = frame.ownerElement(); ownerElement; ownerElement = ownerElement->document().ownerElement()) {
     642        if (&ownerElement->document() == &range.start.document())
     643            return intersects(range, *ownerElement);
     644    }
     645    return false;
    649646}
    650647
    651648- (NSUInteger)countMatchesForText:(NSString *)string inDOMRange:(DOMRange *)range options:(WebFindOptions)options limit:(NSUInteger)limit markMatches:(BOOL)markMatches
    652649{
    653     if (range && !isFrameInRange([dataSource webFrame], range))
     650    if (range && !isFrameInRange(*core([dataSource webFrame]), makeSimpleRange(*core(range))))
    654651        return 0;
    655652
  • trunk/Tools/ChangeLog

    r266290 r266295  
     12020-08-28  Darin Adler  <darin@apple.com>
     2
     3        Remove almost all the remaining uses of live ranges
     4        https://bugs.webkit.org/show_bug.cgi?id=215755
     5
     6        Reviewed by Sam Weinig.
     7
     8        * TestWebKitAPI/Tests/WebCore/DocumentOrder.cpp:
     9        (TestWebKitAPI::TEST): Added test cases for node ordering involving non-user-agent
     10        shadow tree. Added test case that showed the old "use node order if offsets are equal"
     11        rule for boundary point ordering was wrong. Added tests for isPointInRange,
     12        intersects, and contains functions.
     13
    1142020-08-28  Myles C. Maxfield  <mmaxfield@apple.com>
    215
  • trunk/Tools/TestWebKitAPI/Tests/WebCore/DocumentOrder.cpp

    r266026 r266295  
    2626#include "config.h"
    2727
    28 #include <WebCore/BoundaryPoint.h>
    2928#include <WebCore/Document.h>
    3029#include <WebCore/HTMLBodyElement.h>
     
    3332#include <WebCore/HTMLTextAreaElement.h>
    3433#include <WebCore/Position.h>
     34#include <WebCore/ShadowRoot.h>
     35#include <WebCore/SimpleRange.h>
    3536#include <WebCore/TextControlInnerElements.h>
    3637
     
    3940#define EXPECT_LESS(a, b) EXPECT_BOTH(a, b, "less", "greater")
    4041#define EXPECT_UNORDERED(a, b) EXPECT_BOTH(a, b, "unordered", "unordered")
     42
     43#define EXPECT_CONTAINS_SELF(a) EXPECT_TRUE(contains(a, a))
     44#define EXPECT_NESTED(a, b) do { EXPECT_TRUE(contains(a, b)); EXPECT_FALSE(contains(b, a)); } while (0)
     45#define EXPECT_NOT_CONTAINED(a, b) do { EXPECT_FALSE(contains(a, b)); EXPECT_FALSE(contains(b, a)); } while (0)
     46
     47#define EXPECT_INTERSECTS_SELF(a) EXPECT_TRUE(intersects(a, a))
     48#define EXPECT_INTERSECTS_BOTH_WAYS(a, b) do { EXPECT_TRUE(intersects(a, b)); EXPECT_TRUE(intersects(b, a)); } while (0)
     49#define EXPECT_NOT_INTERSECTING_BOTH_WAYS(a, b) do { EXPECT_FALSE(intersects(a, b)); EXPECT_FALSE(intersects(b, a)); } while (0)
    4150
    4251namespace TestWebKitAPI {
     
    142151    auto& h = *g->innerTextElement();
    143152    EXPECT_LESS(body, h);
     153
     154    auto& i = a->attachShadow({ ShadowRootMode::Closed }).releaseReturnValue();
     155    EXPECT_LESS(body, i);
     156    EXPECT_LESS(i, d);
     157    EXPECT_LESS(i, b);
     158
     159    // FIXME: Add tests that cover slots and assignment.
    144160}
    145161
     
    189205    c->appendChild(g);
    190206    EXPECT_LESS(makeBoundaryPoint(body, 0), makeBoundaryPoint(g, 0));
     207
     208    // FIXME: Add tests that cover shadow trees.
    191209}
    192210
     
    198216    EXPECT_LESS(makeBoundaryPoint(document, 0), makeBoundaryPoint(document, 1));
    199217    EXPECT_LESS(makeBoundaryPoint(body, 0), makeBoundaryPoint(document, 1));
     218    EXPECT_LESS(makeBoundaryPoint(body, 1), makeBoundaryPoint(document, 1));
    200219
    201220    auto a = HTMLDivElement::create(document);
     
    242261    EXPECT_LESS(makeBoundaryPoint(h, 0), makeBoundaryPoint(c, 1));
    243262    EXPECT_LESS(makeBoundaryPoint(h, 0), makeBoundaryPoint(c, 2));
     263
     264    // FIXME: Add tests that cover shadow trees.
    244265}
    245266
     
    451472    TEST_ALL_POSITION_TYPES_B(makePositionAfter(document), body, 1, greater);
    452473    TEST_ALL_POSITION_TYPES_B(makePositionAfter(document), h, 0, greater);
     474
     475    // FIXME: Add tests that cover shadow trees.
     476}
     477
     478TEST(DocumentOrder, IsPointInRange)
     479{
     480    auto document = createDocument();
     481    auto& documentElement = *document->documentElement();
     482    auto& body = *document->body();
     483
     484    EXPECT_TRUE(isPointInRange(makeRangeSelectingNodeContents(document), makeBoundaryPoint(document, 0)));
     485    EXPECT_TRUE(isPointInRange(makeRangeSelectingNodeContents(document), makeBoundaryPoint(document, 1)));
     486    EXPECT_FALSE(isPointInRange(makeRangeSelectingNodeContents(document), makeBoundaryPoint(document, 2)));
     487    EXPECT_TRUE(isPointInRange(makeRangeSelectingNodeContents(document), makeBoundaryPoint(body, 0)));
     488    EXPECT_TRUE(isPointInRange(makeRangeSelectingNodeContents(document), makeBoundaryPoint(body, 1)));
     489    EXPECT_TRUE(isPointInRange(makeRangeSelectingNodeContents(document), makeBoundaryPoint(body, 2)));
     490    EXPECT_FALSE(isPointInRange(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(documentElement, 0)), makeBoundaryPoint(body, 0)));
     491    EXPECT_TRUE(isPointInRange(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(body, 0)), makeBoundaryPoint(body, 0)));
     492
     493    auto a = HTMLDivElement::create(document);
     494    EXPECT_FALSE(isPointInRange(makeRangeSelectingNodeContents(document), makeBoundaryPoint(a, 0)));
     495    EXPECT_FALSE(isPointInRange(makeRangeSelectingNodeContents(body), makeBoundaryPoint(a, 0)));
     496
     497    body.appendChild(a);
     498    EXPECT_TRUE(isPointInRange(makeRangeSelectingNodeContents(document), makeBoundaryPoint(a, 0)));
     499    EXPECT_TRUE(isPointInRange(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(a, 0)), makeBoundaryPoint(a, 0)));
     500    EXPECT_FALSE(isPointInRange(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(body, 0)), makeBoundaryPoint(a, 0)));
     501    EXPECT_TRUE(isPointInRange(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(body, 1)), makeBoundaryPoint(a, 0)));
     502    EXPECT_FALSE(isPointInRange(makeSimpleRange(makeBoundaryPoint(body, 1), makeBoundaryPoint(document, 1)), makeBoundaryPoint(a, 0)));
     503    EXPECT_TRUE(isPointInRange(makeSimpleRange(makeBoundaryPoint(body, 0), makeBoundaryPoint(document, 1)), makeBoundaryPoint(a, 0)));
     504
     505    auto b = HTMLDivElement::create(document);
     506    body.appendChild(b);
     507
     508    auto c = HTMLDivElement::create(document);
     509    b->appendChild(c);
     510
     511    auto d = HTMLDivElement::create(document);
     512    a->appendChild(d);
     513
     514    auto e = HTMLDivElement::create(document);
     515    auto f = HTMLDivElement::create(document);
     516    e->appendChild(f);
     517    EXPECT_FALSE(isPointInRange(makeRangeSelectingNodeContents(body), makeBoundaryPoint(f, 0)));
     518
     519    auto g = HTMLTextAreaElement::create(document);
     520    auto& h = *g->innerTextElement();
     521    c->appendChild(g);
     522    EXPECT_TRUE(isPointInRange(makeRangeSelectingNodeContents(body), makeBoundaryPoint(h, 0)));
     523
     524    // FIXME: Add tests that cover shadow trees.
     525}
     526
     527TEST(DocumentOrder, RangeContainsRange)
     528{
     529    auto document = createDocument();
     530    auto& documentElement = *document->documentElement();
     531    auto& body = *document->body();
     532
     533    EXPECT_CONTAINS_SELF(makeRangeSelectingNodeContents(document));
     534    EXPECT_CONTAINS_SELF(makeRangeSelectingNodeContents(documentElement));
     535    EXPECT_CONTAINS_SELF(makeRangeSelectingNodeContents(body));
     536
     537    EXPECT_NESTED(makeRangeSelectingNodeContents(document), makeRangeSelectingNodeContents(documentElement));
     538    EXPECT_NESTED(makeRangeSelectingNodeContents(document), makeRangeSelectingNodeContents(body));
     539    EXPECT_NESTED(makeRangeSelectingNodeContents(documentElement), makeRangeSelectingNodeContents(body));
     540
     541    EXPECT_NESTED(makeRangeSelectingNodeContents(document), makeRangeSelectingNodeContents(documentElement));
     542
     543    EXPECT_NESTED(makeRangeSelectingNodeContents(documentElement), makeRangeSelectingNodeContents(body));
     544
     545    EXPECT_NESTED(makeRangeSelectingNodeContents(document), makeSimpleRange(makeBoundaryPoint(document, 0)));
     546    EXPECT_NESTED(makeRangeSelectingNodeContents(document), makeSimpleRange(makeBoundaryPoint(document, 1)));
     547    EXPECT_NOT_CONTAINED(makeRangeSelectingNodeContents(document), makeSimpleRange(makeBoundaryPoint(document, 2)));
     548
     549    EXPECT_NESTED(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(document, 2)), makeRangeSelectingNodeContents(document));
     550    EXPECT_NOT_CONTAINED(makeRangeSelectingNodeContents(document), makeSimpleRange(makeBoundaryPoint(document, 1), makeBoundaryPoint(document, 2)));
     551
     552    EXPECT_NOT_CONTAINED(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(documentElement, 0)), makeRangeSelectingNodeContents(body));
     553    EXPECT_NESTED(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(body, 0)), makeSimpleRange(makeBoundaryPoint(body, 0)));
     554
     555    auto a = HTMLDivElement::create(document);
     556    EXPECT_NOT_CONTAINED(makeRangeSelectingNodeContents(document), makeRangeSelectingNodeContents(a));
     557
     558    body.appendChild(a);
     559
     560    auto b = HTMLDivElement::create(document);
     561    body.appendChild(b);
     562
     563    auto c = HTMLDivElement::create(document);
     564    b->appendChild(c);
     565
     566    auto d = HTMLDivElement::create(document);
     567    a->appendChild(d);
     568
     569    auto e = HTMLDivElement::create(document);
     570    auto f = HTMLDivElement::create(document);
     571    e->appendChild(f);
     572    EXPECT_NOT_CONTAINED(makeRangeSelectingNodeContents(body), makeRangeSelectingNodeContents(f));
     573
     574    auto g = HTMLTextAreaElement::create(document);
     575    auto& h = *g->innerTextElement();
     576    c->appendChild(g);
     577    EXPECT_NESTED(makeRangeSelectingNodeContents(body), makeRangeSelectingNodeContents(h));
     578
     579    // FIXME: Add tests that cover shadow trees.
     580}
     581
     582TEST(DocumentOrder, RangeIntersectsRange)
     583{
     584    auto document = createDocument();
     585    auto& documentElement = *document->documentElement();
     586    auto& body = *document->body();
     587
     588    EXPECT_INTERSECTS_SELF(makeRangeSelectingNodeContents(document));
     589    EXPECT_INTERSECTS_SELF(makeRangeSelectingNodeContents(documentElement));
     590    EXPECT_INTERSECTS_SELF(makeRangeSelectingNodeContents(body));
     591
     592    EXPECT_INTERSECTS_BOTH_WAYS(makeRangeSelectingNodeContents(document), makeRangeSelectingNodeContents(documentElement));
     593    EXPECT_INTERSECTS_BOTH_WAYS(makeRangeSelectingNodeContents(document), makeRangeSelectingNodeContents(body));
     594    EXPECT_INTERSECTS_BOTH_WAYS(makeRangeSelectingNodeContents(documentElement), makeRangeSelectingNodeContents(body));
     595
     596    EXPECT_INTERSECTS_BOTH_WAYS(makeRangeSelectingNodeContents(document), makeRangeSelectingNodeContents(documentElement));
     597
     598    EXPECT_INTERSECTS_BOTH_WAYS(makeRangeSelectingNodeContents(documentElement), makeRangeSelectingNodeContents(body));
     599
     600    EXPECT_INTERSECTS_BOTH_WAYS(makeRangeSelectingNodeContents(document), makeSimpleRange(makeBoundaryPoint(document, 0)));
     601    EXPECT_INTERSECTS_BOTH_WAYS(makeRangeSelectingNodeContents(document), makeSimpleRange(makeBoundaryPoint(document, 1)));
     602    EXPECT_NOT_INTERSECTING_BOTH_WAYS(makeRangeSelectingNodeContents(document), makeSimpleRange(makeBoundaryPoint(document, 2)));
     603
     604    EXPECT_INTERSECTS_BOTH_WAYS(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(document, 2)), makeRangeSelectingNodeContents(document));
     605    EXPECT_INTERSECTS_BOTH_WAYS(makeRangeSelectingNodeContents(document), makeSimpleRange(makeBoundaryPoint(document, 1), makeBoundaryPoint(document, 2)));
     606
     607    EXPECT_NOT_INTERSECTING_BOTH_WAYS(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(documentElement, 0)), makeRangeSelectingNodeContents(body));
     608    EXPECT_INTERSECTS_BOTH_WAYS(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(body, 0)), makeSimpleRange(makeBoundaryPoint(body, 0)));
     609
     610    auto a = HTMLDivElement::create(document);
     611    EXPECT_NOT_INTERSECTING_BOTH_WAYS(makeRangeSelectingNodeContents(document), makeRangeSelectingNodeContents(a));
     612
     613    body.appendChild(a);
     614
     615    auto b = HTMLDivElement::create(document);
     616    body.appendChild(b);
     617
     618    auto c = HTMLDivElement::create(document);
     619    b->appendChild(c);
     620
     621    auto d = HTMLDivElement::create(document);
     622    a->appendChild(d);
     623
     624    auto e = HTMLDivElement::create(document);
     625    auto f = HTMLDivElement::create(document);
     626    e->appendChild(f);
     627    EXPECT_NOT_INTERSECTING_BOTH_WAYS(makeRangeSelectingNodeContents(body), makeRangeSelectingNodeContents(f));
     628
     629    auto g = HTMLTextAreaElement::create(document);
     630    auto& h = *g->innerTextElement();
     631    c->appendChild(g);
     632    EXPECT_INTERSECTS_BOTH_WAYS(makeRangeSelectingNodeContents(body), makeRangeSelectingNodeContents(h));
     633
     634    // FIXME: Add tests that cover shadow trees.
     635}
     636
     637TEST(DocumentOrder, RangeContainsNode)
     638{
     639    auto document = createDocument();
     640    auto& documentElement = *document->documentElement();
     641    auto& body = *document->body();
     642
     643    EXPECT_TRUE(contains(makeRangeSelectingNodeContents(document), documentElement));
     644    EXPECT_TRUE(contains(makeRangeSelectingNodeContents(document), body));
     645    EXPECT_TRUE(contains(makeRangeSelectingNodeContents(documentElement), body));
     646
     647    EXPECT_FALSE(contains(makeRangeSelectingNodeContents(document), document));
     648    EXPECT_FALSE(contains(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(document, 2)), document));
     649    EXPECT_FALSE(contains(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(documentElement, 0)), body));
     650    EXPECT_FALSE(contains(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(body, 0)), body));
     651    EXPECT_FALSE(contains(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(body, 1)), body));
     652    EXPECT_TRUE(contains(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(documentElement, 1)), body));
     653
     654    auto a = HTMLDivElement::create(document);
     655    EXPECT_FALSE(contains(makeRangeSelectingNodeContents(document), a));
     656
     657    body.appendChild(a);
     658
     659    auto b = HTMLDivElement::create(document);
     660    body.appendChild(b);
     661
     662    auto c = HTMLDivElement::create(document);
     663    b->appendChild(c);
     664
     665    auto d = HTMLDivElement::create(document);
     666    a->appendChild(d);
     667
     668    auto e = HTMLDivElement::create(document);
     669    auto f = HTMLDivElement::create(document);
     670    e->appendChild(f);
     671    EXPECT_FALSE(contains(makeRangeSelectingNodeContents(body), f));
     672
     673    auto g = HTMLTextAreaElement::create(document);
     674    auto& h = *g->innerTextElement();
     675    c->appendChild(g);
     676    EXPECT_TRUE(contains(makeRangeSelectingNodeContents(body), h));
     677
     678    // FIXME: Add tests that cover shadow trees.
     679}
     680
     681TEST(DocumentOrder, RangeIntersectsNode)
     682{
     683    auto document = createDocument();
     684    auto& documentElement = *document->documentElement();
     685    auto& body = *document->body();
     686
     687    EXPECT_TRUE(intersects(makeRangeSelectingNodeContents(document), documentElement));
     688    EXPECT_TRUE(intersects(makeRangeSelectingNodeContents(document), body));
     689    EXPECT_TRUE(intersects(makeRangeSelectingNodeContents(documentElement), body));
     690
     691    EXPECT_TRUE(intersects(makeRangeSelectingNodeContents(document), document));
     692    EXPECT_TRUE(intersects(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(document, 2)), document));
     693    EXPECT_FALSE(intersects(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(documentElement, 0)), body));
     694    EXPECT_FALSE(intersects(makeSimpleRange(makeBoundaryPoint(documentElement, 1), makeBoundaryPoint(document, 1)), body));
     695    EXPECT_TRUE(intersects(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(body, 0)), body));
     696    EXPECT_TRUE(intersects(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(body, 1)), body));
     697    EXPECT_TRUE(intersects(makeSimpleRange(makeBoundaryPoint(document, 0), makeBoundaryPoint(documentElement, 1)), body));
     698
     699    auto a = HTMLDivElement::create(document);
     700    EXPECT_FALSE(intersects(makeRangeSelectingNodeContents(document), a));
     701
     702    body.appendChild(a);
     703
     704    auto b = HTMLDivElement::create(document);
     705    body.appendChild(b);
     706
     707    auto c = HTMLDivElement::create(document);
     708    b->appendChild(c);
     709
     710    auto d = HTMLDivElement::create(document);
     711    a->appendChild(d);
     712
     713    auto e = HTMLDivElement::create(document);
     714    auto f = HTMLDivElement::create(document);
     715    e->appendChild(f);
     716    EXPECT_FALSE(intersects(makeRangeSelectingNodeContents(body), e));
     717    EXPECT_TRUE(intersects(makeRangeSelectingNodeContents(f), e));
     718    EXPECT_FALSE(intersects(makeRangeSelectingNodeContents(body), f));
     719
     720    auto g = HTMLTextAreaElement::create(document);
     721    auto& h = *g->innerTextElement();
     722    c->appendChild(g);
     723    EXPECT_TRUE(intersects(makeRangeSelectingNodeContents(body), h));
     724
     725    // FIXME: Add tests that cover shadow trees.
    453726}
    454727
Note: See TracChangeset for help on using the changeset viewer.