Changeset 266295 in webkit
- Timestamp:
- Aug 28, 2020, 2:37:08 PM (6 years ago)
- Location:
- trunk
- Files:
-
- 49 edited
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/accessibility/AXObjectCache.cpp (modified) (3 diffs)
-
Source/WebCore/accessibility/AccessibilityObject.cpp (modified) (3 diffs)
-
Source/WebCore/accessibility/AccessibilityRenderObject.cpp (modified) (4 diffs)
-
Source/WebCore/accessibility/atk/WebKitAccessibleUtil.cpp (modified) (1 diff)
-
Source/WebCore/dom/Document.h (modified) (1 diff)
-
Source/WebCore/dom/DocumentMarkerController.cpp (modified) (2 diffs)
-
Source/WebCore/dom/Element.h (modified) (1 diff)
-
Source/WebCore/dom/Node.cpp (modified) (8 diffs)
-
Source/WebCore/dom/Node.h (modified) (2 diffs)
-
Source/WebCore/dom/Range.cpp (modified) (29 diffs)
-
Source/WebCore/dom/Range.h (modified) (4 diffs)
-
Source/WebCore/dom/Range.idl (modified) (4 diffs)
-
Source/WebCore/dom/RangeBoundaryPoint.h (modified) (7 diffs)
-
Source/WebCore/dom/SimpleRange.cpp (modified) (4 diffs)
-
Source/WebCore/dom/SimpleRange.h (modified) (1 diff)
-
Source/WebCore/editing/Editing.cpp (modified) (2 diffs)
-
Source/WebCore/editing/Editor.cpp (modified) (2 diffs)
-
Source/WebCore/editing/EditorCommand.cpp (modified) (3 diffs)
-
Source/WebCore/editing/FrameSelection.cpp (modified) (2 diffs)
-
Source/WebCore/editing/ReplaceRangeWithTextCommand.cpp (modified) (1 diff)
-
Source/WebCore/editing/SpellingCorrectionCommand.cpp (modified) (1 diff)
-
Source/WebCore/editing/TextCheckingHelper.cpp (modified) (1 diff)
-
Source/WebCore/editing/mac/DictionaryLookupLegacy.mm (modified) (1 diff)
-
Source/WebCore/editing/markup.cpp (modified) (1 diff)
-
Source/WebCore/loader/archive/cf/LegacyWebArchive.cpp (modified) (1 diff)
-
Source/WebCore/page/DOMSelection.cpp (modified) (5 diffs)
-
Source/WebCore/page/DragController.cpp (modified) (3 diffs)
-
Source/WebCore/page/EventHandler.cpp (modified) (1 diff)
-
Source/WebCore/page/Page.cpp (modified) (3 diffs)
-
Source/WebCore/page/mac/ServicesOverlayController.mm (modified) (1 diff)
-
Source/WebCore/rendering/RenderObject.cpp (modified) (1 diff)
-
Source/WebCore/testing/Internals.cpp (modified) (1 diff)
-
Source/WebKit/ChangeLog (modified) (1 diff)
-
Source/WebKit/WebProcess/InjectedBundle/API/gtk/DOM/WebKitDOMRange.cpp (modified) (4 diffs)
-
Source/WebKit/WebProcess/InjectedBundle/API/mac/WKDOMRange.mm (modified) (4 diffs)
-
Source/WebKit/WebProcess/InjectedBundle/DOM/InjectedBundleRangeHandle.cpp (modified) (5 diffs)
-
Source/WebKit/WebProcess/WebPage/FindController.cpp (modified) (2 diffs)
-
Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp (modified) (1 diff)
-
Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm (modified) (3 diffs)
-
Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm (modified) (1 diff)
-
Source/WebKitLegacy/mac/ChangeLog (modified) (1 diff)
-
Source/WebKitLegacy/mac/DOM/DOM.mm (modified) (3 diffs)
-
Source/WebKitLegacy/mac/DOM/DOMRange.mm (modified) (4 diffs)
-
Source/WebKitLegacy/mac/DOM/DOMUIKitExtensions.mm (modified) (2 diffs)
-
Source/WebKitLegacy/mac/DOM/WebDOMOperations.mm (modified) (1 diff)
-
Source/WebKitLegacy/mac/WebView/WebPDFView.mm (modified) (1 diff)
-
Tools/ChangeLog (modified) (1 diff)
-
Tools/TestWebKitAPI/Tests/WebCore/DocumentOrder.cpp (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r266293 r266295 1 2020-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 1 185 2020-08-28 Chris Dumez <cdumez@apple.com> 2 186 -
trunk/Source/WebCore/accessibility/AXObjectCache.cpp
r266136 r266295 2037 2037 static bool characterOffsetsInOrder(const CharacterOffset& characterOffset1, const CharacterOffset& characterOffset2) 2038 2038 { 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 2039 2041 if (characterOffset1.isNull() || characterOffset2.isNull()) 2040 2042 return false; … … 2049 2051 if (!node2->isCharacterDataNode() && !isReplacedNodeOrBR(node2) && node2->hasChildNodes()) 2050 2052 node2 = node2->traverseToChildAt(characterOffset2.offset); 2051 2052 2053 if (!node1 || !node2) 2053 2054 return false; … … 2055 2056 auto range1 = AXObjectCache::rangeForNodeContents(*node1); 2056 2057 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)); 2061 2059 } 2062 2060 -
trunk/Source/WebCore/accessibility/AccessibilityObject.cpp
r266207 r266295 298 298 checkTextOfParagraph(*textChecker, stringValue(), TextCheckingType::Spelling, misspellings, frame->selection().selection()); 299 299 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. 304 301 if (direction == AccessibilitySearchDirection::Next) { 305 for ( constauto& misspelling : misspellings) {302 for (auto& misspelling : misspellings) { 306 303 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))) 311 305 return *misspellingRange; 312 306 } 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))) 320 311 return *misspellingRange; 321 312 } … … 566 557 static Optional<SimpleRange> rangeClosestToRange(const SimpleRange& referenceRange, Optional<SimpleRange>&& afterRange, Optional<SimpleRange>&& beforeRange) 567 558 { 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;581 559 if (!beforeRange) 582 560 return WTFMove(afterRange); 583 561 if (!afterRange) 584 562 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); 590 566 } 591 567 … … 604 580 for (auto& searchString : searchStrings) { 605 581 if (auto foundStringRange = frame->editor().rangeOfString(searchString, referenceRange, findOptions)) { 582 bool foundStringIsCloser; 606 583 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) 607 591 closestStringRange = *foundStringRange; 608 else {609 // If searching backward, use the trailing range edges to correctly determine which610 // 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 }623 592 } 624 593 } -
trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp
r266028 r266295 916 916 auto start = VisiblePosition { createLegacyEditingPosition(range->start) }; 917 917 auto end = nextVisiblePosition(start); 918 if ( !end.isNull() && createLiveRange(range)->contains(end))918 if (isPointInRange(*range, makeBoundaryPoint(end))) 919 919 return { boundsForRange(*makeSimpleRange(start, end)).center() }; 920 920 } … … 1562 1562 return PlainTextRange(); 1563 1563 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)) 1575 1567 return PlainTextRange(); 1576 1568 … … 1657 1649 auto elementRange = this->elementRange(); 1658 1650 auto start = visiblePositionForIndexUsingCharacterIterator(node, range.start); 1659 if (! createLiveRange(elementRange)->contains(start))1651 if (!isPointInRange(*elementRange, makeBoundaryPoint(start))) 1660 1652 start = createLegacyEditingPosition(elementRange->start); 1661 1653 auto end = visiblePositionForIndexUsingCharacterIterator(node, range.start + range.length); 1662 if (! createLiveRange(elementRange)->contains(end))1654 if (!isPointInRange(*elementRange, makeBoundaryPoint(end))) 1663 1655 end = createLegacyEditingPosition(elementRange->start); 1664 1656 m_renderer->frame().selection().setSelection(VisibleSelection(start, end), FrameSelection::defaultSetSelectionOptions(UserTriggered)); … … 2217 2209 auto start = range.start; 2218 2210 if (auto elementRange = this->elementRange()) { 2219 if (! createLiveRange(elementRange)->contains(start))2211 if (!isPointInRange(*elementRange, makeBoundaryPoint(start))) 2220 2212 start = createLegacyEditingPosition(elementRange->start); 2221 2213 } -
trunk/Source/WebCore/accessibility/atk/WebKitAccessibleUtil.cpp
r265176 r266295 156 156 return false; 157 157 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()); 177 160 } 178 161 -
trunk/Source/WebCore/dom/Document.h
r266026 r266295 906 906 // Returns the owning element in the parent document. 907 907 // Returns nullptr if this is the top level document. 908 HTMLFrameOwnerElement* ownerElement() const;908 WEBCORE_EXPORT HTMLFrameOwnerElement* ownerElement() const; 909 909 910 910 // Used by DOM bindings; no direction known. -
trunk/Source/WebCore/dom/DocumentMarkerController.cpp
r266028 r266295 650 650 void addMarker(const SimpleRange& range, DocumentMarker::MarkerType type, const DocumentMarker::Data& data) 651 651 { 652 range.start. container->document().markers().addMarker(range, type, data);652 range.start.document().markers().addMarker(range, type, data); 653 653 } 654 654 … … 660 660 void removeMarkers(const SimpleRange& range, OptionSet<DocumentMarker::MarkerType> types, RemovePartiallyOverlappingMarker policy) 661 661 { 662 range.start. container->document().markers().removeMarkers(range, types, policy);662 range.start.document().markers().removeMarkers(range, types, policy); 663 663 } 664 664 -
trunk/Source/WebCore/dom/Element.h
r266269 r266295 298 298 bool delegatesFocus { false }; 299 299 }; 300 ExceptionOr<ShadowRoot&> attachShadow(const ShadowRootInit&);300 WEBCORE_EXPORT ExceptionOr<ShadowRoot&> attachShadow(const ShadowRootInit&); 301 301 302 302 RefPtr<ShadowRoot> userAgentShadowRoot() const; -
trunk/Source/WebCore/dom/Node.cpp
r266281 r266295 1629 1629 } 1630 1630 1631 // FIXME: Refactor this so it calls documentOrder ing, 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. 1632 1632 unsigned short Node::compareDocumentPosition(Node& otherNode) 1633 1633 { … … 2628 2628 } 2629 2629 2630 static size_t depth (const Node& node)2630 static size_t depthInComposedTree(const Node& node) 2631 2631 { 2632 2632 size_t depth = 0; 2633 2633 auto ancestor = &node; 2634 while ((ancestor = ancestor->parent OrShadowHostNode()))2634 while ((ancestor = ancestor->parentInComposedTree())) 2635 2635 ++depth; 2636 2636 return depth; … … 2642 2642 const Node* distinctAncestorB; 2643 2643 }; 2644 2645 // FIXME: This function's name is not explicit about the fact that it's the common inclusive ancestor in the composed tree. 2644 2646 static AncestorAndChildren commonInclusiveAncestorAndChildren(const Node& a, const Node& b) 2645 2647 { 2646 // This firstcheck isn't needed for correctness, but it is cheap and likely to be2648 // This check isn't needed for correctness, but it is cheap and likely to be 2647 2649 // common enough to be worth optimizing so we don't have to walk to the root. 2648 2650 if (&a == &b) 2649 2651 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)); 2651 2656 auto [x, y, difference] = depthA >= depthB 2652 2657 ? std::make_tuple(&a, &b, depthA - depthB) … … 2655 2660 for (decltype(difference) i = 0; i < difference; ++i) { 2656 2661 distinctAncestorA = x; 2657 x = x->parent OrShadowHostNode();2662 x = x->parentInComposedTree(); 2658 2663 } 2659 2664 decltype(y) distinctAncestorB = nullptr; … … 2661 2666 distinctAncestorA = x; 2662 2667 distinctAncestorB = y; 2663 x = x->parent OrShadowHostNode();2664 y = y->parent OrShadowHostNode();2668 x = x->parentInComposedTree(); 2669 y = y->parentInComposedTree(); 2665 2670 } 2666 2671 if (depthA < depthB) … … 2669 2674 } 2670 2675 2676 // FIXME: This function's name is not explicit about the fact that it's the common inclusive ancestor in the composed tree. 2671 2677 RefPtr<Node> commonInclusiveAncestor(Node& a, Node& b) 2672 2678 { … … 2676 2682 static bool isSiblingSubsequent(const Node& siblingA, const Node& siblingB) 2677 2683 { 2684 ASSERT(siblingA.parentNode()); 2685 ASSERT(siblingA.parentNode() == siblingB.parentNode()); 2678 2686 ASSERT(&siblingA != &siblingB); 2679 2687 for (auto sibling = &siblingA; sibling; sibling = sibling->nextSibling()) { … … 2695 2703 if (!result.distinctAncestorB) 2696 2704 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 } 2697 2715 return isSiblingSubsequent(*result.distinctAncestorA, *result.distinctAncestorB) ? PartialOrdering::less : PartialOrdering::greater; 2698 2716 } -
trunk/Source/WebCore/dom/Node.h
r266212 r266295 694 694 Type m_type; 695 695 }; 696 constexpr bool is_eq(PartialOrdering); 697 constexpr bool is_lt(PartialOrdering); 698 constexpr bool is_gt(PartialOrdering); 699 constexpr bool is_neq(PartialOrdering); 700 constexpr bool is_lteq(PartialOrdering); 701 constexpr bool is_gteq(PartialOrdering); 696 702 697 703 WEBCORE_EXPORT PartialOrdering documentOrder(const Node&, const Node&); … … 830 836 } 831 837 838 constexpr bool is_neq(PartialOrdering ordering) 839 { 840 return is_lt(ordering) || is_gt(ordering); 841 } 842 843 constexpr bool is_lteq(PartialOrdering ordering) 844 { 845 return is_lt(ordering) || is_eq(ordering); 846 } 847 848 constexpr bool is_gteq(PartialOrdering ordering) 849 { 850 return is_gt(ordering) || is_eq(ordering); 851 } 852 832 853 WTF::TextStream& operator<<(WTF::TextStream&, const Node&); 833 854 -
trunk/Source/WebCore/dom/Range.cpp
r266123 r266295 67 67 68 68 enum ContentsProcessDirection { ProcessContentsForward, ProcessContentsBackward }; 69 enum class CoordinateSpace { Absolute, Client };70 69 71 70 static ExceptionOr<void> processNodes(Range::ActionType, Vector<Ref<Node>>&, Node* oldContainer, RefPtr<Node> newContainer); … … 75 74 inline Range::Range(Document& ownerDocument) 76 75 : m_ownerDocument(ownerDocument) 77 , m_start( &ownerDocument)78 , m_end( &ownerDocument)76 , m_start(ownerDocument) 77 , m_end(ownerDocument) 79 78 { 80 79 #ifndef NDEBUG … … 99 98 } 100 99 101 void Range::setDocument(Document& document) 102 { 103 ASSERT(m_ownerDocument.ptr() != &document); 100 void Range::updateDocument() 101 { 102 auto& document = startContainer().document(); 103 if (m_ownerDocument.ptr() == &document) 104 return; 104 105 m_ownerDocument->detachRange(*this); 105 106 m_ownerDocument = document; 106 m_start.setToStartOfNode(document);107 m_end.setToStartOfNode(document);108 107 m_ownerDocument->attachRange(*this); 109 108 } 110 109 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); 110 ExceptionOr<void> Range::setStart(Ref<Node>&& container, unsigned offset) 111 { 112 auto childNode = checkNodeOffsetPair(container, offset); 132 113 if (childNode.hasException()) 133 114 return childNode.releaseException(); 134 115 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(); 140 120 return { }; 141 121 } 142 122 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); 123 ExceptionOr<void> Range::setEnd(Ref<Node>&& container, unsigned offset) 124 { 125 auto childNode = checkNodeOffsetPair(container, offset); 152 126 if (childNode.hasException()) 153 127 return childNode.releaseException(); 154 128 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(); 160 133 return { }; 161 134 } … … 169 142 } 170 143 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())) 144 ExceptionOr<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()) 181 150 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 156 ExceptionOr<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()) 205 162 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)) 214 167 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)) 221 171 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 175 ExceptionOr<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 229 181 // http://developer.mozilla.org/en/docs/DOM:range.compareNode 230 182 // 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. 235 187 return NODE_BEFORE; 236 188 } 237 189 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)) 240 203 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 209 ExceptionOr<short> Range::compareBoundaryPoints(unsigned short how, const Range& sourceRange) const 210 { 211 const RangeBoundaryPoint* thisPoint; 212 const RangeBoundaryPoint* otherPoint; 281 213 switch (how) { 282 214 case START_TO_START: 283 return compareBoundaryPoints(m_start, sourceRange.m_start); 215 thisPoint = &m_start; 216 otherPoint = &sourceRange.m_start; 217 break; 284 218 case START_TO_END: 285 return compareBoundaryPoints(m_end, sourceRange.m_start); 219 thisPoint = &m_end; 220 otherPoint = &sourceRange.m_start; 221 break; 286 222 case END_TO_END: 287 return compareBoundaryPoints(m_end, sourceRange.m_end); 223 thisPoint = &m_end; 224 otherPoint = &sourceRange.m_end; 225 break; 288 226 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)) 313 235 return -1; 314 if (!containerB) 236 if (is_eq(ordering)) 237 return 0; 238 if (is_gt(ordering)) 315 239 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 }; 402 241 } 403 242 … … 410 249 } 411 250 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; 251 bool Range::intersectsNode(Node& node) const 252 { 253 return intersects(makeSimpleRange(*this), node); 432 254 } 433 255 … … 465 287 } 466 288 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 488 289 ExceptionOr<RefPtr<DocumentFragment>> Range::processContents(ActionType action) 489 290 { 490 291 RefPtr<DocumentFragment> fragment; 491 292 if (action == Extract || action == Clone) 492 fragment = DocumentFragment::create( ownerDocument());293 fragment = DocumentFragment::create(m_ownerDocument); 493 294 494 295 if (collapsed()) … … 510 311 511 312 // 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()); 514 315 515 316 // Start and end containers are different. … … 534 335 535 336 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()); 539 340 // 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. 540 341 if (!secondResult.hasException()) … … 543 344 544 345 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()); 548 349 // 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. 549 350 if (!secondResult.hasException()) … … 552 353 553 354 // 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. 556 357 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()); 558 359 559 360 // Collapse the range, making sure that the result is not within a node that was partially selected. … … 620 421 RefPtr<Node> result; 621 422 622 // This switch statement must be consistent with that of lengthOfContentsInNode.623 423 switch (container->nodeType()) { 624 424 case Node::TEXT_NODE: … … 869 669 String Range::toString() const 870 670 { 671 auto range = makeSimpleRange(*this); 871 672 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 } 883 679 return builder.toString(); 884 }885 886 String Range::text() const887 {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));893 680 } 894 681 … … 909 696 } 910 697 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 698 ExceptionOr<Node*> Range::checkNodeOffsetPair(Node& node, unsigned offset) const 917 699 { 918 700 switch (node.nodeType()) { … … 944 726 Ref<Range> Range::cloneRange() const 945 727 { 946 auto result = create( ownerDocument());728 auto result = create(m_ownerDocument); 947 729 result->setStart(startContainer(), m_start.offset()); 948 730 result->setEnd(endContainer(), m_end.offset()); … … 950 732 } 951 733 952 ExceptionOr<void> Range::setStartAfter(Node& refNode) 953 { 954 if (!refNode.parentNode()) 734 ExceptionOr<void> Range::setStartAfter(Node& node) 735 { 736 auto parent = node.parentNode(); 737 if (!parent) 955 738 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 742 ExceptionOr<void> Range::setEndBefore(Node& node) 743 { 744 auto parent = node.parentNode(); 745 if (!parent) 962 746 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 750 ExceptionOr<void> Range::setEndAfter(Node& node) 751 { 752 auto parent = node.parentNode(); 753 if (!parent) 969 754 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 758 ExceptionOr<void> Range::selectNode(Node& node) 759 { 760 auto parent = node.parentNode(); 761 if (!parent) 976 762 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); 983 765 if (result.hasException()) 984 766 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 770 ExceptionOr<void> Range::selectNodeContents(Node& node) 771 { 772 if (node.isDocumentTypeNode()) 991 773 return Exception { InvalidNodeTypeError }; 992 774 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); 999 777 return { }; 1000 778 } … … 1053 831 } 1054 832 1055 ExceptionOr<void> Range::setStartBefore(Node& refNode) 1056 { 1057 if (!refNode.parentNode()) 833 ExceptionOr<void> Range::setStartBefore(Node& node) 834 { 835 auto parent = node.parentNode(); 836 if (!parent) 1058 837 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()); 1080 839 } 1081 840 … … 1102 861 #endif 1103 862 1104 bool Range::contains(const Range& other) const1105 {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) const1118 {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 1163 863 static inline void boundaryNodeChildrenChanged(RangeBoundaryPoint& boundary, ContainerNode& container) 1164 864 { 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(); 1170 867 } 1171 868 1172 869 void Range::nodeChildrenChanged(ContainerNode& container) 1173 870 { 1174 ASSERT(&container.document() == &ownerDocument());871 ASSERT(&container.document() == m_ownerDocument.ptr()); 1175 872 boundaryNodeChildrenChanged(m_start, container); 1176 873 boundaryNodeChildrenChanged(m_end, container); 1177 874 } 1178 875 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 } 876 static inline void boundaryNodeChildrenWillBeRemoved(RangeBoundaryPoint& boundary, ContainerNode& containerOfNodesToBeRemoved) 877 { 878 if (containerOfNodesToBeRemoved.contains(&boundary.container())) 879 boundary.setToBeforeContents(containerOfNodesToBeRemoved); 1194 880 } 1195 881 1196 882 void Range::nodeChildrenWillBeRemoved(ContainerNode& container) 1197 883 { 1198 ASSERT(&container.document() == &ownerDocument());884 ASSERT(&container.document() == m_ownerDocument.ptr()); 1199 885 boundaryNodeChildrenWillBeRemoved(m_start, container); 1200 886 boundaryNodeChildrenWillBeRemoved(m_end, container); … … 1203 889 static inline void boundaryNodeWillBeRemoved(RangeBoundaryPoint& boundary, Node& nodeToBeRemoved) 1204 890 { 1205 if (boundary.childBefore() == &nodeToBeRemoved) {891 if (boundary.childBefore() == &nodeToBeRemoved) 1206 892 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); 1216 895 } 1217 896 1218 897 void Range::nodeWillBeRemoved(Node& node) 1219 898 { 1220 ASSERT(&node.document() == &ownerDocument());1221 ASSERT(&node != &ownerDocument());899 ASSERT(&node.document() == m_ownerDocument.ptr()); 900 ASSERT(&node != m_ownerDocument.ptr()); 1222 901 ASSERT(node.parentNode()); 1223 902 boundaryNodeWillBeRemoved(m_start, node); … … 1227 906 bool Range::parentlessNodeMovedToNewDocumentAffectsRange(Node& node) 1228 907 { 1229 return node.containsIncludingShadowDOM( m_start.container());908 return node.containsIncludingShadowDOM(&m_start.container()); 1230 909 } 1231 910 … … 1239 918 static inline void boundaryTextInserted(RangeBoundaryPoint& boundary, Node& text, unsigned offset, unsigned length) 1240 919 { 1241 if ( boundary.container() != &text)920 if (&boundary.container() != &text) 1242 921 return; 1243 922 unsigned boundaryOffset = boundary.offset(); … … 1249 928 void Range::textInserted(Node& text, unsigned offset, unsigned length) 1250 929 { 1251 ASSERT(&text.document() == &ownerDocument());930 ASSERT(&text.document() == m_ownerDocument.ptr()); 1252 931 boundaryTextInserted(m_start, text, offset, length); 1253 932 boundaryTextInserted(m_end, text, offset, length); … … 1256 935 static inline void boundaryTextRemoved(RangeBoundaryPoint& boundary, Node& text, unsigned offset, unsigned length) 1257 936 { 1258 if ( boundary.container() != &text)937 if (&boundary.container() != &text) 1259 938 return; 1260 939 unsigned boundaryOffset = boundary.offset(); … … 1269 948 void Range::textRemoved(Node& text, unsigned offset, unsigned length) 1270 949 { 1271 ASSERT(&text.document() == &ownerDocument());950 ASSERT(&text.document() == m_ownerDocument.ptr()); 1272 951 boundaryTextRemoved(m_start, text, offset, length); 1273 952 boundaryTextRemoved(m_end, text, offset, length); … … 1276 955 static inline void boundaryTextNodesMerged(RangeBoundaryPoint& boundary, NodeWithIndex& oldNode, unsigned offset) 1277 956 { 1278 if ( boundary.container() == oldNode.node())957 if (&boundary.container() == oldNode.node()) 1279 958 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())) 1281 960 boundary.set(*oldNode.node()->previousSibling(), offset, 0); 1282 961 } … … 1285 964 { 1286 965 ASSERT(oldNode.node()); 1287 ASSERT(&oldNode.node()->document() == &ownerDocument());966 ASSERT(&oldNode.node()->document() == m_ownerDocument.ptr()); 1288 967 ASSERT(oldNode.node()->parentNode()); 1289 968 ASSERT(oldNode.node()->isTextNode()); … … 1297 976 { 1298 977 auto* parent = oldNode.parentNode(); 1299 if ( boundary.container() == &oldNode) {978 if (&boundary.container() == &oldNode) { 1300 979 unsigned splitOffset = oldNode.length(); 1301 980 unsigned boundaryOffset = boundary.offset(); … … 1310 989 if (!parent) 1311 990 return; 1312 if ( boundary.container() == parent && boundary.childBefore() == &oldNode) {991 if (&boundary.container() == parent && boundary.childBefore() == &oldNode) { 1313 992 auto* newChild = oldNode.nextSibling(); 1314 993 ASSERT(newChild); 1315 boundary.setToAfter Child(*newChild);994 boundary.setToAfterNode(*newChild); 1316 995 } 1317 996 } … … 1319 998 void Range::textNodeSplit(Text& oldNode) 1320 999 { 1321 ASSERT(&oldNode.document() == &ownerDocument());1000 ASSERT(&oldNode.document() == m_ownerDocument.ptr()); 1322 1001 ASSERT(!oldNode.parentNode() || oldNode.nextSibling()); 1323 1002 ASSERT(!oldNode.parentNode() || oldNode.nextSibling()->isTextNode()); … … 1414 1093 void showTree(const WebCore::Range* range) 1415 1094 { 1416 if (range && range->boundaryPointsValid()) {1095 if (range) { 1417 1096 range->startContainer().showTreeAndMark(&range->startContainer(), "S", &range->endContainer(), "E"); 1418 1097 fprintf(stderr, "start offset: %d, end offset: %d\n", range->startOffset(), range->endOffset()); -
trunk/Source/WebCore/dom/Range.h
r266028 r266295 34 34 class NodeWithIndex; 35 35 class Text; 36 class VisiblePosition;37 36 38 37 struct SimpleRange; 39 38 40 // FIXME: Rename to LiveRange, while leaving the DOM-exposed name as Range.41 39 class Range : public RefCounted<Range> { 42 40 public: … … 44 42 WEBCORE_EXPORT ~Range(); 45 43 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(); } 49 45 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(); } 51 47 unsigned endOffset() const { return m_end.offset(); } 52 48 bool collapsed() const { return m_start == m_end; } 49 Node* commonAncestorContainer() const { return commonInclusiveAncestor(startContainer(), endContainer()).get(); } 53 50 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&); 57 57 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 69 64 WEBCORE_EXPORT ExceptionOr<void> deleteContents(); 70 65 WEBCORE_EXPORT ExceptionOr<Ref<DocumentFragment>> extractContents(); 71 66 WEBCORE_EXPORT ExceptionOr<Ref<DocumentFragment>> cloneContents(); 72 67 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 73 77 WEBCORE_EXPORT String toString() const; 74 78 75 WEBCORE_EXPORT String text() const; 79 Ref<DOMRectList> getClientRects() const; 80 Ref<DOMRect> getBoundingClientRect() const; 76 81 77 WEBCORE_EXPORT ExceptionOr<Ref<DocumentFragment>> createContextualFragment(const String& html);82 WEBCORE_EXPORT ExceptionOr<Ref<DocumentFragment>> createContextualFragment(const String& fragment); 78 83 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&); 81 87 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; 91 90 92 91 void nodeChildrenChanged(ContainerNode&); … … 101 100 void textNodeSplit(Text& oldNode); 102 101 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 #5105 // for details.106 WEBCORE_EXPORT ExceptionOr<void> expand(const String&);107 108 Ref<DOMRectList> getClientRects() const;109 Ref<DOMRect> getBoundingClientRect() const;110 111 102 #if ENABLE(TREE_DEBUGGING) 112 103 void formatForDebugger(char* buffer, unsigned length) const; 113 104 #endif 114 105 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 }; 119 107 120 108 private: 121 109 explicit Range(Document&); 122 110 123 void setDocument(Document&);124 ExceptionOr<Node*> checkNode WOffset(Node&, unsigned offset) const;111 void updateDocument(); 112 ExceptionOr<Node*> checkNodeOffsetPair(Node&, unsigned offset) const; 125 113 ExceptionOr<RefPtr<DocumentFragment>> processContents(ActionType); 126 127 Node* pastLastNode() const;128 114 129 115 Ref<Document> m_ownerDocument; … … 131 117 RangeBoundaryPoint m_end; 132 118 }; 133 134 WEBCORE_EXPORT bool areRangesEqual(const Range*, const Range*);135 WEBCORE_EXPORT bool rangesOverlap(const Range*, const Range*);136 119 137 120 WEBCORE_EXPORT SimpleRange makeSimpleRange(const Range&); -
trunk/Source/WebCore/dom/Range.idl
r263160 r266295 26 26 27 27 readonly attribute Node startContainer; 28 readonly attribute long startOffset; // FIXME: Should be unsigned long.28 readonly attribute unsigned long startOffset; 29 29 readonly attribute Node endContainer; 30 readonly attribute long endOffset; // FIXME: Should be unsigned long.30 readonly attribute unsigned long endOffset; 31 31 readonly attribute boolean collapsed; 32 32 readonly attribute Node commonAncestorContainer; … … 46 46 const unsigned short END_TO_END = 2; 47 47 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); 49 49 50 50 [CEReactions, MayThrowException] void deleteContents(); … … 60 60 [MayThrowException] short comparePoint(Node node, unsigned long offset); 61 61 62 [MayThrowException]boolean intersectsNode(Node node);62 boolean intersectsNode(Node node); 63 63 64 64 stringifier; … … 71 71 [CEReactions, MayThrowException, NewObject] DocumentFragment createContextualFragment(DOMString fragment); 72 72 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); 75 76 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. 77 78 [MayThrowException] short compareNode(Node node); 78 79 const unsigned short NODE_BEFORE = 0; -
trunk/Source/WebCore/dom/RangeBoundaryPoint.h
r266026 r266295 33 33 class RangeBoundaryPoint { 34 34 public: 35 explicit RangeBoundaryPoint(Node *container);35 explicit RangeBoundaryPoint(Node& container); 36 36 37 Node *container() const;37 Node& container() const; 38 38 unsigned offset() const; 39 39 Node* childBefore() const; 40 41 void clear();42 40 43 41 void set(Ref<Node>&& container, unsigned offset, Node* childBefore); 44 42 void setOffset(unsigned); 45 43 46 void setToBefore Child(Node&);47 void setToAfter Child(Node&);48 void setTo StartOfNode(Ref<Node>&&);49 void setTo EndOfNode(Ref<Node>&&);44 void setToBeforeNode(Node&); 45 void setToAfterNode(Node&); 46 void setToBeforeContents(Ref<Node>&&); 47 void setToAfterContents(Ref<Node>&&); 50 48 51 49 void childBeforeWillBeRemoved(); 52 50 void invalidateOffset() const; 53 void ensureOffsetIsValid() const;54 51 55 52 private: 56 Ref Ptr<Node> m_containerNode;53 Ref<Node> m_container; 57 54 mutable Optional<unsigned> m_offsetInContainer { 0 }; 58 55 RefPtr<Node> m_childBeforeBoundary; … … 61 58 BoundaryPoint makeBoundaryPoint(const RangeBoundaryPoint&); 62 59 63 inline RangeBoundaryPoint::RangeBoundaryPoint(Node *container)64 : m_container Node(container)60 inline RangeBoundaryPoint::RangeBoundaryPoint(Node& container) 61 : m_container(container) 65 62 { 66 ASSERT(m_containerNode);67 63 } 68 64 69 inline Node *RangeBoundaryPoint::container() const65 inline Node& RangeBoundaryPoint::container() const 70 66 { 71 return m_container Node.get();67 return m_container; 72 68 } 73 69 … … 77 73 } 78 74 79 inline void RangeBoundaryPoint::ensureOffsetIsValid() const80 {81 if (m_offsetInContainer)82 return;83 84 ASSERT(m_childBeforeBoundary);85 m_offsetInContainer = m_childBeforeBoundary->computeNodeIndex() + 1;86 }87 88 75 inline unsigned RangeBoundaryPoint::offset() const 89 76 { 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; 99 82 } 100 83 … … 102 85 { 103 86 ASSERT(childBefore == (offset ? container->traverseToChildAt(offset - 1) : 0)); 104 m_container Node= WTFMove(container);87 m_container = WTFMove(container); 105 88 m_offsetInContainer = offset; 106 89 m_childBeforeBoundary = childBefore; … … 109 92 inline void RangeBoundaryPoint::setOffset(unsigned offset) 110 93 { 111 ASSERT(m_containerNode); 112 ASSERT(m_containerNode->isCharacterDataNode()); 94 ASSERT(m_container->isCharacterDataNode()); 113 95 ASSERT(m_offsetInContainer); 114 96 ASSERT(!m_childBeforeBoundary); … … 116 98 } 117 99 118 inline void RangeBoundaryPoint::setToBefore Child(Node& child)100 inline void RangeBoundaryPoint::setToBeforeNode(Node& child) 119 101 { 120 102 ASSERT(child.parentNode()); 121 103 m_childBeforeBoundary = child.previousSibling(); 122 m_container Node =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); 124 106 } 125 107 126 inline void RangeBoundaryPoint::setToAfter Child(Node& child)108 inline void RangeBoundaryPoint::setToAfterNode(Node& child) 127 109 { 128 110 ASSERT(child.parentNode()); 129 111 m_childBeforeBoundary = &child; 130 m_container Node =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); 132 114 } 133 115 134 inline void RangeBoundaryPoint::setTo StartOfNode(Ref<Node>&& container)116 inline void RangeBoundaryPoint::setToBeforeContents(Ref<Node>&& container) 135 117 { 136 m_container Node= WTFMove(container);118 m_container = WTFMove(container); 137 119 m_offsetInContainer = 0; 138 120 m_childBeforeBoundary = nullptr; 139 121 } 140 122 141 inline void RangeBoundaryPoint::setTo EndOfNode(Ref<Node>&& container)123 inline void RangeBoundaryPoint::setToAfterContents(Ref<Node>&& container) 142 124 { 143 m_container Node= 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(); 146 128 m_childBeforeBoundary = nullptr; 147 129 } else { 148 m_childBeforeBoundary = m_container Node->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); 150 132 } 151 133 } … … 168 150 inline bool operator==(const RangeBoundaryPoint& a, const RangeBoundaryPoint& b) 169 151 { 170 if ( a.container() !=b.container())152 if (&a.container() != &b.container()) 171 153 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(); 180 157 } 181 158 182 159 inline BoundaryPoint makeBoundaryPoint(const RangeBoundaryPoint& point) 183 160 { 184 return { *point.container(), point.offset() };161 return { point.container(), point.offset() }; 185 162 } 186 163 -
trunk/Source/WebCore/dom/SimpleRange.cpp
r266123 r266295 73 73 if (!offset) 74 74 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; 75 78 unsigned currentOffset = 0; 76 79 for (auto currentChild = container.firstChild(); currentChild && currentChild != &child; currentChild = currentChild->nextSibling()) { … … 100 103 101 104 for (auto ancestor = b.container.ptr(); ancestor; ) { 102 auto nextAncestor = ancestor->parent OrShadowHostNode();105 auto nextAncestor = ancestor->parentInComposedTree(); 103 106 if (nextAncestor == a.container.ptr()) 104 107 return isOffsetBeforeChild(*nextAncestor, a.offset, *ancestor) ? PartialOrdering::less : PartialOrdering::greater; … … 107 110 108 111 for (auto ancestor = a.container.ptr(); ancestor; ) { 109 auto nextAncestor = ancestor->parent OrShadowHostNode();112 auto nextAncestor = ancestor->parentInComposedTree(); 110 113 if (nextAncestor == b.container.ptr()) 111 114 return isOffsetBeforeChild(*nextAncestor, b.offset, *ancestor) ? PartialOrdering::greater : PartialOrdering::less; … … 206 209 } 207 210 208 } 211 bool isPointInRange(const SimpleRange& range, const BoundaryPoint& point) 212 { 213 return is_lteq(documentOrder(range.start, point)) && is_lteq(documentOrder(point, range.end)); 214 } 215 216 bool isPointInRange(const SimpleRange& range, const Optional<BoundaryPoint>& point) 217 { 218 return point && isPointInRange(range, *point); 219 } 220 221 PartialOrdering 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 230 PartialOrdering 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 239 bool 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 244 bool 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 249 SimpleRange 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 256 bool 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 264 bool 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 65 65 66 66 bool operator==(const SimpleRange&, const SimpleRange&); 67 68 WEBCORE_EXPORT bool isPointInRange(const SimpleRange&, const BoundaryPoint&); 69 bool isPointInRange(const SimpleRange&, const Optional<BoundaryPoint>&); 70 71 WEBCORE_EXPORT bool contains(const SimpleRange& outerRange, const SimpleRange& innerRange); 72 WEBCORE_EXPORT bool intersects(const SimpleRange&, const SimpleRange&); 73 WEBCORE_EXPORT SimpleRange unionRange(const SimpleRange&, const SimpleRange&); 74 75 WEBCORE_EXPORT bool contains(const SimpleRange&, const Node&); 76 WEBCORE_EXPORT bool intersects(const SimpleRange&, const Node&); 77 78 // Returns equivalent if point is in range. 79 WEBCORE_EXPORT PartialOrdering documentOrder(const SimpleRange&, const BoundaryPoint&); 80 WEBCORE_EXPORT PartialOrdering documentOrder(const BoundaryPoint&, const SimpleRange&); 67 81 68 82 class IntersectingNodeRange; -
trunk/Source/WebCore/editing/Editing.cpp
r265199 r266295 80 80 } 81 81 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. 84 83 int comparePositions(const Position& a, const Position& b) 85 84 { 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. 116 94 int comparePositions(const VisiblePosition& a, const VisiblePosition& b) 117 95 { … … 1164 1142 bool isNodeVisiblyContainedWithin(Node& node, const SimpleRange& range) 1165 1143 { 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)) 1169 1145 return true; 1170 1146 -
trunk/Source/WebCore/editing/Editor.cpp
r266265 r266295 3551 3551 { 3552 3552 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); 3557 3555 } 3558 3556 return false; … … 3704 3702 auto& selection = m_document.selection(); 3705 3703 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); 3718 3714 } 3719 3715 } -
trunk/Source/WebCore/editing/EditorCommand.cpp
r265199 r266295 229 229 } 230 230 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 238 231 // Execute command functions 239 232 … … 354 347 static bool executeDeleteToMark(Frame& frame, Event*, EditorCommandSource, const String&) 355 348 { 356 auto mark = frame.editor().mark().toNormalizedRange();349 auto& editor = frame.editor(); 357 350 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)) 360 355 return false; 361 356 } 362 frame.editor().performDelete();363 frame.editor().setMark(selection.selection());357 editor.performDelete(); 358 editor.setMark(selection.selection()); 364 359 return true; 365 360 } … … 1051 1046 static bool executeSelectToMark(Frame& frame, Event*, EditorCommandSource, const String&) 1052 1047 { 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) { 1056 1053 PAL::systemBeep(); 1057 1054 return false; 1058 1055 } 1059 frame.selection().setSelectedRange(unionRanges(*mark, *selection), DOWNSTREAM, FrameSelection::ShouldCloseTyping::Yes);1056 selection.setSelectedRange(unionRange(*markRange, *selectionRange), DOWNSTREAM, FrameSelection::ShouldCloseTyping::Yes); 1060 1057 // FIXME: Why do we ignore the return value from setSelectedRange here? 1061 1058 return true; -
trunk/Source/WebCore/editing/FrameSelection.cpp
r266028 r266295 555 555 m_selection.setWithoutValidation(m_selection.end(), m_selection.start()); 556 556 } 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; 569 563 } 570 564 } … … 2035 2029 return false; 2036 2030 2037 if (&range->start. container->document() != &range->end.container->document())2031 if (&range->start.document() != &range->end.document()) 2038 2032 return false; 2039 2033 -
trunk/Source/WebCore/editing/ReplaceRangeWithTextCommand.cpp
r265176 r266295 42 42 43 43 ReplaceRangeWithTextCommand::ReplaceRangeWithTextCommand(const SimpleRange& rangeToBeReplaced, const String& text) 44 : CompositeEditCommand(rangeToBeReplaced.start. container->document(), EditAction::InsertReplacement)44 : CompositeEditCommand(rangeToBeReplaced.start.document(), EditAction::InsertReplacement) 45 45 , m_rangeToBeReplaced(rangeToBeReplaced) 46 46 , m_text(text) -
trunk/Source/WebCore/editing/SpellingCorrectionCommand.cpp
r265176 r266295 85 85 86 86 SpellingCorrectionCommand::SpellingCorrectionCommand(const SimpleRange& rangeToBeCorrected, const String& correction) 87 : CompositeEditCommand(rangeToBeCorrected.start. container->document(), EditAction::InsertReplacement)87 : CompositeEditCommand(rangeToBeCorrected.start.document(), EditAction::InsertReplacement) 88 88 , m_rangeToBeCorrected(rangeToBeCorrected) 89 89 , m_selectionToBeCorrected(m_rangeToBeCorrected) -
trunk/Source/WebCore/editing/TextCheckingHelper.cpp
r266248 r266295 338 338 checkingTypes.add(TextCheckingType::Grammar); 339 339 VisibleSelection currentSelection; 340 if (Frame* frame = paragraphRange.start. container->document().frame())340 if (Frame* frame = paragraphRange.start.document().frame()) 341 341 currentSelection = frame->selection().selection(); 342 342 checkTextOfParagraph(*m_client.textChecker(), paragraphString, checkingTypes, results, currentSelection); -
trunk/Source/WebCore/editing/mac/DictionaryLookupLegacy.mm
r265084 r266295 69 69 return false; 70 70 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)); 76 73 } 77 74 -
trunk/Source/WebCore/editing/markup.cpp
r266168 r266295 1121 1121 Ref<DocumentFragment> createFragmentFromText(const SimpleRange& context, const String& text) 1122 1122 { 1123 auto& document = context.start. container->document();1123 auto& document = context.start.document(); 1124 1124 auto fragment = document.createDocumentFragment(); 1125 1125 -
trunk/Source/WebCore/loader/archive/cf/LegacyWebArchive.cpp
r265084 r266295 456 456 RefPtr<LegacyWebArchive> LegacyWebArchive::create(const SimpleRange& range) 457 457 { 458 auto& document = range.start. container->document();458 auto& document = range.start.document(); 459 459 auto* frame = document.frame(); 460 460 if (!frame) -
trunk/Source/WebCore/page/DOMSelection.cpp
r266026 r266295 28 28 */ 29 29 30 31 30 #include "config.h" 32 31 #include "DOMSelection.h" … … 285 284 ExceptionOr<void> DOMSelection::extend(Node& node, unsigned offset) 286 285 { 287 auto * frame = this->frame();286 auto frame = makeRefPtr(this->frame()); 288 287 if (!frame) 289 288 return { }; 290 if (offset > (node.isCharacterDataNode() ? caretMaxOffset(node) : node.countChildNodes()))289 if (offset > node.length()) 291 290 return Exception { IndexSizeError }; 292 291 if (!isValidForPosition(&node)) 293 292 return { }; 294 295 Ref<Frame> protector(*frame);296 293 frame->selection().setExtent(createLegacyEditingPosition(&node, offset), DOWNSTREAM); 297 294 return { }; … … 302 299 if (index >= rangeCount()) 303 300 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 307 void DOMSelection::removeAllRanges() 308 { 309 auto* frame = this->frame(); 310 if (!frame) 311 return; 312 frame->selection().clear(); 313 } 314 315 void 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; 313 328 } 314 329 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); 374 331 } 375 332 … … 393 350 bool DOMSelection::containsNode(Node& node, bool allowPartial) const 394 351 { 352 // FIXME: This behavior does not match what the selection API standard specifies. 353 if (node.isTextNode()) 354 allowPartial = true; 355 395 356 auto* frame = this->frame(); 396 357 if (!frame) 397 358 return false; 398 359 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(); 405 361 if (!selectedRange || selectedRange->start.container->containingShadowRoot()) 406 362 return false; 407 363 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); 434 365 } 435 366 … … 484 415 { 485 416 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()); 491 418 } 492 419 -
trunk/Source/WebCore/page/DragController.cpp
r265228 r266295 155 155 String url = dragData.asURL(DragData::DoNotConvertFilenames, &title); 156 156 if (!url.isEmpty()) { 157 auto& document = context.start. container->document();157 auto& document = context.start.document(); 158 158 auto anchor = HTMLAnchorElement::create(document); 159 159 anchor->setHref(url); … … 775 775 if (!startElement) 776 776 return nullptr; 777 777 778 #if ENABLE(ATTACHMENT_ELEMENT) 778 779 if (auto attachment = enclosingAttachmentElement(*startElement)) { 779 auto selection = sourceFrame->selection().selection();780 auto& selection = sourceFrame->selection().selection(); 780 781 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)) { 788 784 state.type = DragSourceAction::Attachment; 789 785 return attachment.get(); … … 1472 1468 Vector<Ref<HTMLImageElement>> placeholders; 1473 1469 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)) 1476 1471 placeholders.append(placeholder); 1477 1472 } -
trunk/Source/WebCore/page/EventHandler.cpp
r266252 r266295 2742 2742 if (element && m_frame.selection().isRange()) { 2743 2743 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())) 2746 2745 return true; 2747 2746 } -
trunk/Source/WebCore/page/Page.cpp
r266026 r266295 731 731 if (frameWithSelection) { 732 732 result.indexForSelection = NoMatchAfterUserSelection; 733 auto selectedRange = frameWithSelection->selection().selection().firstRange();733 auto selectedRange = *frameWithSelection->selection().selection().firstRange(); 734 734 if (options.contains(Backwards)) { 735 735 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))) { 738 738 result.indexForSelection = i - 1; 739 739 break; … … 742 742 } else { 743 743 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))) { 746 746 result.indexForSelection = i; 747 747 break; … … 764 764 return WTF::nullopt; 765 765 766 if (referenceRange && referenceRange->start. container->document().page() != this)766 if (referenceRange && referenceRange->start.document().page() != this) 767 767 return WTF::nullopt; 768 768 769 769 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(); 771 771 Frame* startFrame = frame; 772 772 do { -
trunk/Source/WebCore/page/mac/ServicesOverlayController.mm
r260753 r266295 631 631 632 632 for (auto& highlight : m_potentialHighlights) { 633 if (highlight->type() == Highlight::TelephoneNumberType && c reateLiveRange(highlight->range())->contains(createLiveRange(*selectionRange)))633 if (highlight->type() == Highlight::TelephoneNumberType && contains(highlight->range(), *selectionRange)) 634 634 return highlight.get(); 635 635 } -
trunk/Source/WebCore/rendering/RenderObject.cpp
r266123 r266295 1976 1976 Vector<FloatRect> rects; 1977 1977 1978 range.start. container->document().updateLayoutIgnorePendingStylesheets();1978 range.start.document().updateLayoutIgnorePendingStylesheets(); 1979 1979 1980 1980 bool useVisibleBounds = behavior.contains(RenderObject::BoundingRectBehavior::UseVisibleBounds); -
trunk/Source/WebCore/testing/Internals.cpp
r266248 r266295 2162 2162 } 2163 2163 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)); 2164 String 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. 2172 static 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 2180 String 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 2191 Ref<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 2198 RefPtr<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)); 2185 2203 } 2186 2204 -
trunk/Source/WebKit/ChangeLog
r266287 r266295 1 2020-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 1 33 2020-08-28 Alex Christensen <achristensen@webkit.org> 2 34 -
trunk/Source/WebKit/WebProcess/InjectedBundle/API/gtk/DOM/WebKitDOMRange.cpp
r234586 r266295 26 26 #include <WebCore/Document.h> 27 27 #include <WebCore/JSExecState.h> 28 #include <WebCore/TextIterator.h> 28 29 #include "WebKitDOMDocumentFragmentPrivate.h" 29 30 #include "WebKitDOMNodePrivate.h" … … 356 357 g_return_val_if_fail(WEBKIT_DOM_IS_RANGE(sourceRange), 0); 357 358 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)); 361 360 if (result.hasException()) { 362 361 auto description = WebCore::DOMException::description(result.releaseException().code()); … … 509 508 g_return_val_if_fail(WEBKIT_DOM_IS_NODE(refNode), FALSE); 510 509 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)); 520 511 } 521 512 … … 633 624 WebCore::JSMainThreadNullState state; 634 625 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)); 638 629 } 639 630 -
trunk/Source/WebKit/WebProcess/InjectedBundle/API/mac/WKDOMRange.mm
r266026 r266295 31 31 #import "WKDOMInternals.h" 32 32 #import <WebCore/Document.h> 33 #import <WebCore/TextIterator.h> 33 34 #import <WebCore/VisibleUnits.h> 34 35 #import <wtf/cocoa/VectorCocoa.h> … … 50 51 - (id)initWithDocument:(WKDOMDocument *)document 51 52 { 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()]; 58 54 } 59 55 … … 119 115 - (NSString *)text 120 116 { 121 return _impl->text(); 117 auto range = makeSimpleRange(*_impl); 118 range.start.document().updateLayout(); 119 return plainText(range); 122 120 } 123 121 … … 129 127 - (NSArray *)textRects 130 128 { 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(); 133 132 } 134 133 -
trunk/Source/WebKit/WebProcess/InjectedBundle/DOM/InjectedBundleRangeHandle.cpp
r266028 r266295 45 45 #include <WebCore/RenderView.h> 46 46 #include <WebCore/SimpleRange.h> 47 #include <WebCore/TextIterator.h> 47 48 #include <WebCore/VisibleSelection.h> 48 49 #include <wtf/HashMap.h> … … 98 99 Ref<InjectedBundleNodeHandle> InjectedBundleRangeHandle::document() 99 100 { 100 return InjectedBundleNodeHandle::getOrCreate(m_range-> ownerDocument());101 return InjectedBundleNodeHandle::getOrCreate(m_range->startContainer().document()); 101 102 } 102 103 103 104 WebCore::IntRect InjectedBundleRangeHandle::boundingRectInWindowCoordinates() const 104 105 { 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)))); 107 114 } 108 115 109 116 RefPtr<WebImage> InjectedBundleRangeHandle::renderedImage(SnapshotOptions options) 110 117 { 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()); 113 123 if (!frame) 114 124 return nullptr; 115 125 116 FrameView*frameView = frame->view();126 auto frameView = frame->view(); 117 127 if (!frameView) 118 128 return nullptr; … … 122 132 #endif 123 133 124 Ref<Frame> protector(*frame);125 126 134 VisibleSelection oldSelection = frame->selection().selection(); 127 frame->selection().setSelection( makeSimpleRange(m_range));135 frame->selection().setSelection(range); 128 136 129 137 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))); 131 139 IntSize backingStoreSize = paintRect.size(); 132 140 backingStoreSize.scale(scaleFactor); … … 156 164 157 165 frameView->setPaintBehavior(paintBehavior); 158 ownerDocument.updateLayout();166 document->updateLayout(); 159 167 160 168 frameView->paint(*graphicsContext, paintRect); … … 168 176 String InjectedBundleRangeHandle::text() const 169 177 { 170 return m_range->text(); 178 auto range = makeSimpleRange(m_range); 179 range.start.document().updateLayout(); 180 return plainText(range); 171 181 } 172 182 -
trunk/Source/WebKit/WebProcess/WebPage/FindController.cpp
r265190 r266295 306 306 if (matchIndex >= m_findMatches.size()) 307 307 return; 308 Frame* frame = m_findMatches[matchIndex].start. container->document().frame();308 Frame* frame = m_findMatches[matchIndex].start.document().frame(); 309 309 if (!frame) 310 310 return; … … 337 337 if (matchIndex >= m_findMatches.size()) 338 338 return; 339 Frame* frame = m_findMatches[matchIndex].start. container->document().frame();339 Frame* frame = m_findMatches[matchIndex].start.document().frame(); 340 340 if (!frame) 341 341 return; -
trunk/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp
r265176 r266295 110 110 auto surroundingRange = makeSimpleRange(surroundingStart, endOfEditableContent(selectionStart)); 111 111 auto compositionRange = frame.editor().compositionRange(); 112 if (surroundingRange && compositionRange && c reateLiveRange(surroundingRange)->contains(createLiveRange(*compositionRange).get())) {112 if (surroundingRange && compositionRange && contains(*surroundingRange, *compositionRange)) { 113 113 auto beforeText = plainText({ surroundingRange->start, compositionRange->start }); 114 114 postLayoutData.surroundingContext = beforeText + plainText({ compositionRange->end, surroundingRange->end }); -
trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm
r266265 r266295 4201 4201 auto selectionRange = selection.toNormalizedRange(); 4202 4202 auto rangeOfInterest = *makeSimpleRange(rangeOfInterestStart, rangeOfInterestEnd); 4203 if (selectionRange && rangesOverlap(createLiveRange(rangeOfInterest).ptr(), createLiveRange(*selectionRange).ptr())) {4203 if (selectionRange && intersects(rangeOfInterest, *selectionRange)) { 4204 4204 startOfRangeOfInterestInSelection = std::max(rangeOfInterestStart, selectionStart); 4205 4205 endOfRangeOfInterestInSelection = std::min(rangeOfInterestEnd, selectionEnd); … … 4266 4266 context.selectedText = makeString(startOfRangeOfInterestInSelection, endOfRangeOfInterestInSelection); 4267 4267 context.contextAfter = makeString(endOfRangeOfInterestInSelection, contextAfterEnd); 4268 if (compositionRange && rangesOverlap(createLiveRange(rangeOfInterest).ptr(), createLiveRange(*compositionRange).ptr())) {4268 if (compositionRange && intersects(rangeOfInterest, *compositionRange)) { 4269 4269 VisiblePosition compositionStart(createLegacyEditingPosition(compositionRange->start)); 4270 4270 VisiblePosition compositionEnd(createLegacyEditingPosition(compositionRange->end)); … … 4282 4282 if (!iterator.text().isEmpty()) { 4283 4283 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 } }); 4285 4285 } 4286 4286 iterator.advance(stride); -
trunk/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm
r266051 r266295 878 878 continue; 879 879 880 auto view = actionContext->range.start. container->document().view();880 auto view = actionContext->range.start.document().view(); 881 881 if (!view) 882 882 continue; -
trunk/Source/WebKitLegacy/mac/ChangeLog
r266265 r266295 1 2020-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 1 22 2020-08-27 Devin Rousso <drousso@apple.com> 2 23 -
trunk/Source/WebKitLegacy/mac/DOM/DOM.mm
r266028 r266295 571 571 #endif 572 572 { 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)); 577 576 } 578 577 … … 584 583 { 585 584 auto range = makeSimpleRange(*core(self)); 586 auto frame = makeRefPtr(range.start. container->document().frame());585 auto frame = makeRefPtr(range.start.document().frame()); 587 586 if (!frame) 588 587 return nil; … … 603 602 { 604 603 auto range = makeSimpleRange(*core(self)); 605 range.start. container->document().updateLayoutIgnorePendingStylesheets();604 range.start.document().updateLayoutIgnorePendingStylesheets(); 606 605 return createNSArray(RenderObject::absoluteTextRects(range)).autorelease(); 607 606 } -
trunk/Source/WebKitLegacy/mac/DOM/DOMRange.mm
r265190 r266295 34 34 #import <WebCore/Range.h> 35 35 #import <WebCore/SimpleRange.h> 36 #import <WebCore/TextIterator.h> 36 37 #import <WebCore/ThreadCheck.h> 37 38 #import <WebCore/WebCoreObjCExtras.h> … … 93 94 { 94 95 WebCore::JSMainThreadNullState state; 95 return IMPL->text(); 96 auto range = makeSimpleRange(*IMPL); 97 range.start.document().updateLayout(); 98 return plainText(range); 96 99 } 97 100 … … 171 174 if (!sourceRange) 172 175 raiseTypeErrorException(); 173 return raiseOnDOMError(IMPL->compareBoundaryPoints ForBindings(how, *core(sourceRange)));176 return raiseOnDOMError(IMPL->compareBoundaryPoints(how, *core(sourceRange))); 174 177 } 175 178 … … 245 248 if (!refNode) 246 249 raiseTypeErrorException(); 247 return raiseOnDOMError(IMPL->intersectsNode(*core(refNode)));250 return IMPL->intersectsNode(*core(refNode)); 248 251 } 249 252 -
trunk/Source/WebKitLegacy/mac/DOM/DOMUIKitExtensions.mm
r265190 r266295 52 52 #import <WebCore/Image.h> 53 53 #import <WebCore/InlineBox.h> 54 #import <WebCore/Node .h>54 #import <WebCore/NodeTraversal.h> 55 55 #import <WebCore/Range.h> 56 56 #import <WebCore/RenderBlock.h> … … 125 125 } 126 126 127 // FIXME: Refactor to share code with intersectingNodesWithDeprecatedZeroOffsetStartQuirk. 128 static 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 127 139 - (DOMNode *)firstNode 128 140 { 129 return kit( core(self)->firstNode());141 return kit(firstNodeAfter(makeSimpleRange(*core(self)).start)); 130 142 } 131 143 -
trunk/Source/WebKitLegacy/mac/DOM/WebDOMOperations.mm
r265190 r266295 192 192 - (NSString *)markupString 193 193 { 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) }; 196 196 } 197 197 -
trunk/Source/WebKitLegacy/mac/WebView/WebPDFView.mm
r261210 r266295 637 637 } 638 638 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; 639 static 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; 649 646 } 650 647 651 648 - (NSUInteger)countMatchesForText:(NSString *)string inDOMRange:(DOMRange *)range options:(WebFindOptions)options limit:(NSUInteger)limit markMatches:(BOOL)markMatches 652 649 { 653 if (range && !isFrameInRange( [dataSource webFrame], range))650 if (range && !isFrameInRange(*core([dataSource webFrame]), makeSimpleRange(*core(range)))) 654 651 return 0; 655 652 -
trunk/Tools/ChangeLog
r266290 r266295 1 2020-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 1 14 2020-08-28 Myles C. Maxfield <mmaxfield@apple.com> 2 15 -
trunk/Tools/TestWebKitAPI/Tests/WebCore/DocumentOrder.cpp
r266026 r266295 26 26 #include "config.h" 27 27 28 #include <WebCore/BoundaryPoint.h>29 28 #include <WebCore/Document.h> 30 29 #include <WebCore/HTMLBodyElement.h> … … 33 32 #include <WebCore/HTMLTextAreaElement.h> 34 33 #include <WebCore/Position.h> 34 #include <WebCore/ShadowRoot.h> 35 #include <WebCore/SimpleRange.h> 35 36 #include <WebCore/TextControlInnerElements.h> 36 37 … … 39 40 #define EXPECT_LESS(a, b) EXPECT_BOTH(a, b, "less", "greater") 40 41 #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) 41 50 42 51 namespace TestWebKitAPI { … … 142 151 auto& h = *g->innerTextElement(); 143 152 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. 144 160 } 145 161 … … 189 205 c->appendChild(g); 190 206 EXPECT_LESS(makeBoundaryPoint(body, 0), makeBoundaryPoint(g, 0)); 207 208 // FIXME: Add tests that cover shadow trees. 191 209 } 192 210 … … 198 216 EXPECT_LESS(makeBoundaryPoint(document, 0), makeBoundaryPoint(document, 1)); 199 217 EXPECT_LESS(makeBoundaryPoint(body, 0), makeBoundaryPoint(document, 1)); 218 EXPECT_LESS(makeBoundaryPoint(body, 1), makeBoundaryPoint(document, 1)); 200 219 201 220 auto a = HTMLDivElement::create(document); … … 242 261 EXPECT_LESS(makeBoundaryPoint(h, 0), makeBoundaryPoint(c, 1)); 243 262 EXPECT_LESS(makeBoundaryPoint(h, 0), makeBoundaryPoint(c, 2)); 263 264 // FIXME: Add tests that cover shadow trees. 244 265 } 245 266 … … 451 472 TEST_ALL_POSITION_TYPES_B(makePositionAfter(document), body, 1, greater); 452 473 TEST_ALL_POSITION_TYPES_B(makePositionAfter(document), h, 0, greater); 474 475 // FIXME: Add tests that cover shadow trees. 476 } 477 478 TEST(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 527 TEST(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 582 TEST(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 637 TEST(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 681 TEST(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. 453 726 } 454 727
Note:
See TracChangeset
for help on using the changeset viewer.