Changeset 267220 in webkit
- Timestamp:
- Sep 17, 2020, 6:45:00 PM (4 years ago)
- Location:
- trunk
- Files:
-
- 23 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r267218 r267220 1 2020-09-16 Darin Adler <darin@apple.com> 2 3 Selection API: Introduce LiveRangeSelectionEnabled, off by default 4 https://bugs.webkit.org/show_bug.cgi?id=216656 5 6 Reviewed by Sam Weinig. 7 8 * editing/selection/move-to-line-boundary-clear-selection.html: Fix test that accidentally 9 relied on our non-standard behavior of clamping a too-high offset to a valid value. This 10 was not what we were trying to test. Without this change, the test fails in the new mode. 11 The offset was "5", which seems to be a character count, rather than "1", meaning "after 12 the text node". 13 * editing/selection/toString-1.html: Ditto. The offset here was 3, but the HTML element 14 has only 2 children, the head and the body. 15 * editing/selection/user-select-all-selection.html: Ditto. The code was passing the wrong 16 container by acccident, the parent of the text node rather than the text node. 17 1 18 2020-09-17 Chris Dumez <cdumez@apple.com> 2 19 -
trunk/LayoutTests/editing/selection/move-to-line-boundary-clear-selection.html
r197024 r267220 18 18 shouldBe('getSelection().toString()', "''"); 19 19 getSelection().empty(); 20 getSelection().setPosition(span, 5);20 getSelection().setPosition(span, 1); 21 21 getSelection().modify("extend", "backward", "line"); 22 22 if (window.testRunner) -
trunk/LayoutTests/editing/selection/toString-1.html
r120173 r267220 21 21 22 22 if (selection.setBaseAndExtent) 23 selection.setBaseAndExtent(bodyElement, 1, htmlElement, 3);23 selection.setBaseAndExtent(bodyElement, 1, htmlElement, 2); 24 24 else 25 25 throw("Couldn't set a selection."); -
trunk/LayoutTests/editing/selection/user-select-all-selection.html
r155276 r267220 50 50 function placeCaretBeforeUserSelectAllElement(){ 51 51 var userSelectAllElement = document.getElementById("allArea"); 52 execSetSelectionCommand(userSelectAllElement.previousSibling.firstChild, userSelectAllElement.previousSibling.textContent.length, userSelectAllElement.previousSibling , userSelectAllElement.previousSibling.textContent.length);52 execSetSelectionCommand(userSelectAllElement.previousSibling.firstChild, userSelectAllElement.previousSibling.textContent.length, userSelectAllElement.previousSibling.firstChild, userSelectAllElement.previousSibling.textContent.length); 53 53 } 54 54 -
trunk/Source/WebCore/ChangeLog
r267218 r267220 1 2020-09-16 Darin Adler <darin@apple.com> 2 3 Selection API: Introduce LiveRangeSelectionEnabled, off by default 4 https://bugs.webkit.org/show_bug.cgi?id=216656 5 6 Reviewed by Sam Weinig. 7 8 For interoperability, the Selection API requires behavior that is quite different 9 from how our Selection object has behaves historically. Specifically, the range 10 returned is a live range that update as the selection updates and the selection, 11 in turn, is updated if the returned range is modified. 12 13 This significant change will have compatibility impact on websites and other 14 content that assumes the legacy WebKit behavior, so we are developing it behind 15 a feature flag, LiveRangeSelectionEnabled. 16 17 This patch introduces the live range selection behind the flag, but leaves one 18 significant area unresolved, changing selection to keep track of the original 19 endpoints rather than only canonicalized endpoints, and a couple of loose ends, 20 lifetime of ride-along properties on the live range object, and updating test 21 expectations for the new behavior. 22 23 * dom/CharacterData.cpp: 24 (WebCore::CharacterData::setData): Fixed timing of call to Document::textRemoved 25 by letting setDataAndUpdate do it; otherwise it can be called after the selection 26 has been updated, and the range gets updated twice. 27 (WebCore::CharacterData::appendData): Pass UpdateLiveRanges::No to setDataAndUpdate, 28 to preserve the existing "don't update ranges" behavior for now at least. 29 (WebCore::CharacterData::insertData): Fixed timing of call to Document::textInserted 30 by letting setDataAndUpdate do it, for the same reason as above. 31 (WebCore::CharacterData::deleteData): Ditto, for textRemoved. 32 (WebCore::CharacterData::replaceData): Ditto, for textRemoved and textInserted. 33 (WebCore::CharacterData::setDataAndUpdate): Added UpdateLiveRanges argument and 34 calls to textRemoved and textInserted, after setting data, but before other updates. 35 36 * dom/CharacterData.h: Made setDataAndUpdate protected and added UpdateLiveRanges. 37 38 * dom/Document.h: Added optimized version of the Node::contains function. When the 39 node in question is the document we can just check treeScope and isConnected 40 rather than walking up the tree. 41 42 * dom/Node.cpp: 43 (WebCore::Node::isDescendantOf const): Moved special case for document to the top 44 of the function; seems a more important special case than disconnected nodes and 45 nodes with no children. 46 (WebCore::Node::isDescendantOrShadowDescendantOf const): Reworded the FIXME for clarity. 47 (WebCore::Node::contains const): Changed this to toke a reference instead of a pointer. 48 The pointer flavor is now inlined in the header. 49 50 * dom/Node.h: Added an overload of contains that takes a reference, analogous to what 51 we already have for isDescendantOf. 52 53 * dom/Position.cpp: 54 (WebCore::Position::Position): Removed too-strict assertions. When we start using 55 positions to represent arbitrary DOM positions for things outside editing we won't 56 want these assertions any more, and we hit them when we use Position in a more 57 straightforward way, like some cases in this patch. 58 (WebCore::Position::primaryDirection const): Added a missing null check. This case 59 is hit in some test cases in the new mode. 60 61 * dom/Range.cpp: Removed some, but probably not all, of the unneeded headers. 62 (WebCore::Range::~Range): Added an assertion. 63 (WebCore::Range::updateAssociatedSelection): Added. Tells FrameSelection to update 64 the selection when this is the live range associated with the selection. 65 (WebCore::Range::updateDocument): Added an assertion. 66 (WebCore::Range::setStart): Call updateAssociatedSelection. 67 (WebCore::Range::setEnd): Ditto. 68 (WebCore::Range::collapse): Ditto. 69 (WebCore::Range::processContents): Call collapse here to share slightly more 70 code so we don't have to call updateAssociatedSelection here. 71 (WebCore::Range::checkNodeOffsetPair): Made this a static function so it can 72 be used outside the Range class. Also fixed indentation of the switch statement. 73 (WebCore::Range::selectNodeContents): Call updateAssociatedSelection and 74 updateDocument. 75 (WebCore::setBothEndpoints): Added. 76 (WebCore::Range::updateFromSelection): Added. Uses setBothEndpoints. 77 (WebCore::createLiveRange): Refactored to call setBothEndpoints. 78 79 * dom/Range.h: Added didAssociateWithSelection, didDisassociateFromSelection, 80 updateFromSelection, updateAssociatedSelection, and m_isAssociatedWithSelection. 81 Also made checkNodeOffsetPair a public static member function instead of a 82 private non-static member function. 83 84 * dom/Text.cpp: 85 (WebCore::Text::setDataAndUpdate): Update to pass along UpdateLiveRanges argument. 86 * dom/Text.h: Ditto. Also made the override of setDataAndUpdate private. 87 88 * editing/FrameSelection.cpp: 89 (WebCore::FrameSelection::setSelectionWithoutUpdatingAppearance): Call 90 updateAssociatedLiveRange after updating the selection. 91 (WebCore::containsEndpoints): Added. Used to check if a live range still has the 92 document as its root node so it can remain associated this with the selection. 93 (WebCore::FrameSelection::associatedLiveRange): Added. 94 (WebCore::FrameSelection::disassociateLiveRange): Added. 95 (WebCore::FrameSelection::associateLiveRange): Added. 96 (WebCore::FrameSelection::updateFromAssociatedLiveRange): Added. 97 (WebCore::FrameSelection::updateAssociatedLiveRange): Added. 98 99 * editing/FrameSelection.h: Added associatedLiveRange, associateLiveRange, 100 disassociateLiveRange, updateFromAssociatedLiveRange, updateAssociatedLiveRange, 101 and m_associatedLiveRange. Also change m_document to a WeakPtr and do some 102 tidying up. 103 104 * page/DOMSelection.cpp: 105 (WebCore::selectionShadowAncestor): Assert the live range setting is false, 106 since this code is not used in that case. Changed the return type to RefPtr. 107 Address the FIXME here by getting the document in a simpler way. 108 (WebCore::DOMSelection::create): Moved here from the header. 109 (WebCore::DOMSelection::frame const): Added. Returns a RefPtr. This gets rid 110 of the need for various instances of the "protector" pattern in this file. 111 (WebCore::DOMSelection::range const): Added. Returns the selected range, but 112 checks for the shadow tree case and returns null in that case. 113 (WebCore::DOMSelection::anchorPosition const): Redid as a member function. 114 (WebCore::DOMSelection::focusPosition const): Ditto. 115 (WebCore::DOMSelection::basePosition const): Ditto. 116 (WebCore::DOMSelection::extentPosition const): Ditto. 117 (WebCore::DOMSelection::anchorNode const): Rewrote to be simpler using the 118 functions above. 119 (WebCore::DOMSelection::anchorOffset const): Ditto. 120 (WebCore::DOMSelection::focusNode const): Ditto. 121 (WebCore::DOMSelection::focusOffset const): Ditto. 122 (WebCore::DOMSelection::baseNode const): Ditto. 123 (WebCore::DOMSelection::baseOffset const): Ditto. 124 (WebCore::DOMSelection::extentNode const): Ditto. 125 (WebCore::DOMSelection::extentOffset const): Ditto. 126 (WebCore::DOMSelection::isCollapsed const): Rewrote using DOMSelection::range 127 and SimpleRange::collapsed. 128 (WebCore::DOMSelection::type const): Updated since frame returns RefPtr. 129 (WebCore::DOMSelection::rangeCount const): Ditto. 130 (WebCore::DOMSelection::collapse): Added new corrected checking for special 131 cases, guarded by the setting. 132 (WebCore::DOMSelection::collapseToEnd): Updated since frame returns RefPtr. 133 way to do protection. Added a call to disassociateLiveRange. No need to put 134 under a setting guard since it does nothing if feature is not enabled. 135 (WebCore::DOMSelection::collapseToStart): Ditto. 136 (WebCore::DOMSelection::empty): Call removeAllRanges so we don't have two 137 copies of the same function to maintain. 138 (WebCore::DOMSelection::setBaseAndExtent): Use makeRefPtr, added corrected 139 checking for special cases guarded by the setting. 140 (WebCore::DOMSelection::setPosition): Call collapse so we don't have two 141 copies of the same function to maintain. 142 (WebCore::DOMSelection::modify): Updated since frame returns RefPtr. 143 (WebCore::DOMSelection::extend): Ditto. Also added corrected checking for 144 special cases guarded by the setting. 145 (WebCore::DOMSelection::getRangeAt): Added a version of this function that 146 simply returns the associated live range, creating one if needed, guarded 147 by the setting. 148 (WebCore::DOMSelection::removeAllRanges): Updated since frame returns RefPtr. 149 (WebCore::DOMSelection::addRange): Added a version of this function that 150 matches the specification, guarded by the setting. 151 (WebCore::DOMSelection::removeRange): Added. 152 (WebCore::DOMSelection::deleteFromDocument): Added a version of this 153 function that simply calls deleteContents on the associated live range, 154 guarded by the setting. 155 (WebCore::DOMSelection::containsNode const): Put the text node workaround 156 inside a setting check. I also figured out why workaround was added: it 157 works around unwanted range canonicalization in various tests, but also 158 introduces incorrect behavior. Also rewrote to use DOMSelection::range. 159 (WebCore::DOMSelection::toString): Use DOMSelection::range, guarded by 160 the setting, so we return empty string when selection is in the shadow tree. 161 (WebCore::DOMSelection::shadowAdjustedNode const): When the live range 162 setting is enabled, adjust by changing the node to nullptr, not finding an 163 ancestor in the document. 164 (WebCore::DOMSelection::shadowAdjustedOffset const): Ditto, but offset 0. 165 (WebCore::DOMSelection::isValidForPosition const): Assert that the live range 166 selection setting is disabled, because this incorrect check should only be 167 used to preserve legacy behavior until we are ready to turn it on. 168 169 * page/DOMSelection.h: Updated since setBaseAndExtent, setPosition, and 170 collapse can raise exceptions, although they only do so when the live range 171 selection setting is on. Added removeRange. Moved the create function 172 out of the class definition into the .cpp file. Made return values of 173 baseNode, extentNode, anchorNode, focusNode, and shadowAdjustedNode RefPtr. 174 Made toString const. Added frame, range, anchorPosition, focusPosition, 175 basePosition, and extentPosition private functions. Removed visibleSelection. 176 177 * page/DOMSelection.idl: Updated file to match a recent draft of the 178 Selection standard, reordering things to match the order they appear there. 179 Added removeRange, guarded by the setting. Also got rid of the 180 unncecessary "undefined" string defaults for the arguments to the modify 181 method since they have no effect on observed behavior anyway. 182 183 * page/Settings.yaml: Added liveRangeSelectionEnabled. 184 1 185 2020-09-17 Chris Dumez <cdumez@apple.com> 2 186 -
trunk/Source/WebCore/dom/CharacterData.cpp
r259930 r267220 64 64 65 65 setDataAndUpdate(nonNullData, 0, oldLength, nonNullData.length()); 66 document().textRemoved(*this, 0, oldLength);67 66 } 68 67 … … 118 117 void CharacterData::appendData(const String& data) 119 118 { 120 String newStr = m_data; 121 newStr.append(data); 122 123 setDataAndUpdate(newStr, m_data.length(), 0, data.length()); 124 125 // FIXME: Should we call textInserted here? 119 setDataAndUpdate(m_data + data, m_data.length(), 0, data.length(), UpdateLiveRanges::No); 126 120 } 127 121 … … 131 125 return Exception { IndexSizeError }; 132 126 133 String newStr = m_data; 134 newStr.insert(data, offset); 135 136 setDataAndUpdate(newStr, offset, 0, data.length()); 137 138 document().textInserted(*this, offset, data.length()); 127 String newData = m_data; 128 newData.insert(data, offset); 129 setDataAndUpdate(newData, offset, 0, data.length()); 139 130 140 131 return { }; … … 148 139 count = std::min(count, length() - offset); 149 140 150 String newStr = m_data; 151 newStr.remove(offset, count); 152 153 setDataAndUpdate(newStr, offset, count, 0); 154 155 document().textRemoved(*this, offset, count); 141 String newData = m_data; 142 newData.remove(offset, count); 143 setDataAndUpdate(newData, offset, count, 0); 156 144 157 145 return { }; … … 165 153 count = std::min(count, length() - offset); 166 154 167 String newStr = m_data; 168 newStr.remove(offset, count); 169 newStr.insert(data, offset); 170 171 setDataAndUpdate(newStr, offset, count, data.length()); 172 173 // update the markers for spell checking and grammar checking 174 document().textRemoved(*this, offset, count); 175 document().textInserted(*this, offset, data.length()); 155 String newData = m_data; 156 newData.remove(offset, count); 157 newData.insert(data, offset); 158 setDataAndUpdate(newData, offset, count, data.length()); 176 159 177 160 return { }; … … 189 172 } 190 173 191 void CharacterData::setDataAndUpdate(const String& newData, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength )174 void CharacterData::setDataAndUpdate(const String& newData, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength, UpdateLiveRanges shouldUpdateLiveRanges) 192 175 { 193 176 String oldData = m_data; 194 177 m_data = newData; 178 179 if (oldLength && shouldUpdateLiveRanges != UpdateLiveRanges::No) 180 document().textRemoved(*this, offsetOfReplacedData, oldLength); 181 if (newLength && shouldUpdateLiveRanges != UpdateLiveRanges::No) 182 document().textInserted(*this, offsetOfReplacedData, newLength); 195 183 196 184 ASSERT(!renderer() || is<Text>(*this)); -
trunk/Source/WebCore/dom/CharacterData.h
r266776 r267220 34 34 35 35 WEBCORE_EXPORT void setData(const String&); 36 virtual void setDataAndUpdate(const String&, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength);37 36 unsigned length() const { return m_data.length(); } 38 37 WEBCORE_EXPORT ExceptionOr<String> substringData(unsigned offset, unsigned count); … … 61 60 void dispatchModifiedEvent(const String& oldValue); 62 61 62 enum class UpdateLiveRanges : bool { No, Yes }; 63 virtual void setDataAndUpdate(const String&, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength, UpdateLiveRanges = UpdateLiveRanges::Yes); 64 63 65 private: 64 66 String nodeValue() const final; -
trunk/Source/WebCore/dom/Document.h
r266295 r267220 1592 1592 void canvasDestroyed(CanvasBase&) final; 1593 1593 1594 bool contains(const Node& node) const { return this == &node.treeScope() && node.isConnected(); } 1595 bool contains(const Node* node) const { return node && contains(*node); } 1596 1594 1597 protected: 1595 1598 enum ConstructionFlags { Synthesized = 1, NonRenderedPlaceholder = 1 << 1 }; -
trunk/Source/WebCore/dom/Node.cpp
r267175 r267220 3 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 4 4 * (C) 2001 Dirk Mueller (mueller@kde.org) 5 * Copyright (C) 2004-20 17Apple Inc. All rights reserved.5 * Copyright (C) 2004-2020 Apple Inc. All rights reserved. 6 6 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 7 7 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) … … 1021 1021 bool Node::isDescendantOf(const Node& other) const 1022 1022 { 1023 // Return true if other is an ancestor of this, otherwise false 1023 // Return true if other is an ancestor of this. 1024 if (other.isDocumentNode()) 1025 return &treeScope().rootNode() == &other && !isDocumentNode() && isConnected(); 1024 1026 if (!other.hasChildNodes() || isConnected() != other.isConnected()) 1025 1027 return false; 1026 if (other.isDocumentNode()) 1027 return &document() == &other && !isDocumentNode() && isConnected(); 1028 for (const auto* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) { 1028 for (auto ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) { 1029 1029 if (ancestor == &other) 1030 1030 return true; … … 1035 1035 bool Node::isDescendantOrShadowDescendantOf(const Node* other) const 1036 1036 { 1037 // FIXME: This element's shadow tree's host could be inside another shadow tree. 1038 // This function doesn't handle that case correctly. Maybe share code with 1039 // the containsIncludingShadowDOM function? 1037 // FIXME: Correctly handle the case where the shadow host is itself in a shadow tree. 1040 1038 return other && (isDescendantOf(*other) || other->contains(shadowHost())); 1041 1039 } 1042 1040 1043 bool Node::contains(const Node *node) const1044 { 1045 return this == node || (node && node->isDescendantOf(*this));1041 bool Node::contains(const Node& node) const 1042 { 1043 return this == &node || node.isDescendantOf(*this); 1046 1044 } 1047 1045 -
trunk/Source/WebCore/dom/Node.h
r267175 r267220 3 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 4 4 * (C) 2001 Dirk Mueller (mueller@kde.org) 5 * Copyright (C) 2004-20 17Apple Inc. All rights reserved.5 * Copyright (C) 2004-2020 Apple Inc. All rights reserved. 6 6 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 7 7 * … … 372 372 WEBCORE_EXPORT bool isDescendantOf(const Node&) const; 373 373 bool isDescendantOf(const Node* other) const { return other && isDescendantOf(*other); } 374 WEBCORE_EXPORT bool contains(const Node&) const; 375 bool contains(const Node* other) const { return other && contains(*other); } 374 376 375 377 bool isDescendantOrShadowDescendantOf(const Node*) const; 376 WEBCORE_EXPORT bool contains(const Node*) const;377 378 WEBCORE_EXPORT bool containsIncludingShadowDOM(const Node*) const; 378 379 -
trunk/Source/WebCore/dom/Position.cpp
r266986 r267220 131 131 , m_isLegacyEditingPosition(false) 132 132 { 133 ASSERT(!m_anchorNode || !editingIgnoresContent(*m_anchorNode));134 ASSERT(!m_anchorNode || !m_anchorNode->isPseudoElement());135 133 ASSERT(anchorType == PositionIsOffsetInAnchor); 136 134 } … … 1363 1361 TextDirection Position::primaryDirection() const 1364 1362 { 1365 if (!m_anchorNode ->renderer())1363 if (!m_anchorNode || !m_anchorNode->renderer()) 1366 1364 return TextDirection::LTR; 1367 1365 if (auto* blockFlow = lineageOfType<RenderBlockFlow>(*m_anchorNode->renderer()).first()) -
trunk/Source/WebCore/dom/Range.cpp
r266986 r267220 4 4 * (C) 2000 Frederik Holljen (frederik.holljen@hig.no) 5 5 * (C) 2001 Peter Kelly (pmk@post.com) 6 * Copyright (C) 2004 , 2005, 2006, 2007, 2008, 2009, 2010, 2011Apple Inc. All rights reserved.6 * Copyright (C) 2004-2020 Apple Inc. All rights reserved. 7 7 * Copyright (C) 2011 Motorola Mobility. All rights reserved. 8 8 * … … 30 30 #include "DOMRectList.h" 31 31 #include "DocumentFragment.h" 32 #include "Editing.h"33 32 #include "Event.h" 34 33 #include "Frame.h" 34 #include "FrameSelection.h" 35 35 #include "FrameView.h" 36 36 #include "GeometryUtilities.h" 37 37 #include "HTMLBodyElement.h" 38 #include "HTMLElement.h"39 38 #include "HTMLHtmlElement.h" 40 39 #include "HTMLNames.h" … … 42 41 #include "NodeWithIndex.h" 43 42 #include "ProcessingInstruction.h" 44 #include "RenderBlock.h"45 #include "RenderBoxModelObject.h"46 #include "RenderText.h"47 #include "RenderView.h"48 43 #include "ScopedEventQueue.h" 49 44 #include "TextIterator.h" 50 #include "VisiblePosition.h"51 45 #include "VisibleUnits.h" 52 46 #include "markup.h" … … 56 50 #include <wtf/text/StringBuilder.h> 57 51 58 #if PLATFORM(IOS_FAMILY)59 #include "SelectionRect.h"60 #endif61 62 52 namespace WebCore { 63 53 … … 91 81 Range::~Range() 92 82 { 83 ASSERT(!m_isAssociatedWithSelection); 84 93 85 m_ownerDocument->detachRange(*this); 94 86 … … 98 90 } 99 91 92 void Range::updateAssociatedSelection() 93 { 94 if (m_isAssociatedWithSelection) 95 m_ownerDocument->selection().updateFromAssociatedLiveRange(); 96 } 97 100 98 void Range::updateDocument() 101 99 { … … 103 101 if (m_ownerDocument.ptr() == &document) 104 102 return; 103 ASSERT(!m_isAssociatedWithSelection); 105 104 m_ownerDocument->detachRange(*this); 106 105 m_ownerDocument = document; … … 117 116 if (!is_lteq(documentOrder(makeBoundaryPoint(m_start), makeBoundaryPoint(m_end)))) 118 117 m_end = m_start; 118 updateAssociatedSelection(); 119 119 updateDocument(); 120 120 return { }; … … 130 130 if (!is_lteq(documentOrder(makeBoundaryPoint(m_start), makeBoundaryPoint(m_end)))) 131 131 m_start = m_end; 132 updateAssociatedSelection(); 132 133 updateDocument(); 133 134 return { }; … … 140 141 else 141 142 m_start = m_end; 143 updateAssociatedSelection(); 142 144 } 143 145 … … 369 371 return result.releaseException(); 370 372 } 371 m_end = m_start;373 collapse(true); 372 374 } 373 375 … … 696 698 } 697 699 698 ExceptionOr<Node*> Range::checkNodeOffsetPair(Node& node, unsigned offset) const700 ExceptionOr<Node*> Range::checkNodeOffsetPair(Node& node, unsigned offset) 699 701 { 700 702 switch (node.nodeType()) { 701 case Node::DOCUMENT_TYPE_NODE: 702 return Exception { InvalidNodeTypeError }; 703 case Node::CDATA_SECTION_NODE: 704 case Node::COMMENT_NODE: 705 case Node::TEXT_NODE: 706 case Node::PROCESSING_INSTRUCTION_NODE: 707 if (offset > downcast<CharacterData>(node).length()) 708 return Exception { IndexSizeError }; 703 case Node::DOCUMENT_TYPE_NODE: 704 return Exception { InvalidNodeTypeError }; 705 case Node::CDATA_SECTION_NODE: 706 case Node::COMMENT_NODE: 707 case Node::TEXT_NODE: 708 case Node::PROCESSING_INSTRUCTION_NODE: 709 if (offset > downcast<CharacterData>(node).length()) 710 return Exception { IndexSizeError }; 711 return nullptr; 712 case Node::ATTRIBUTE_NODE: 713 case Node::DOCUMENT_FRAGMENT_NODE: 714 case Node::DOCUMENT_NODE: 715 case Node::ELEMENT_NODE: 716 if (!offset) 709 717 return nullptr; 710 case Node::ATTRIBUTE_NODE: 711 case Node::DOCUMENT_FRAGMENT_NODE: 712 case Node::DOCUMENT_NODE: 713 case Node::ELEMENT_NODE: { 714 if (!offset) 715 return nullptr; 716 Node* childBefore = node.traverseToChildAt(offset - 1); 717 if (!childBefore) 718 return Exception { IndexSizeError }; 719 return childBefore; 720 } 718 auto childBefore = node.traverseToChildAt(offset - 1); 719 if (!childBefore) 720 return Exception { IndexSizeError }; 721 return childBefore; 721 722 } 722 723 ASSERT_NOT_REACHED(); … … 772 773 if (node.isDocumentTypeNode()) 773 774 return Exception { InvalidNodeTypeError }; 774 775 775 m_start.setToBeforeContents(node); 776 776 m_end.setToAfterContents(node); 777 updateAssociatedSelection(); 778 updateDocument(); 777 779 return { }; 778 780 } … … 1033 1035 } 1034 1036 1037 static void setBothEndpoints(Range& range, const SimpleRange& value) 1038 { 1039 auto startContainer = value.start.container; 1040 range.setStart(WTFMove(startContainer), value.start.offset); 1041 auto endContainer = value.end.container; 1042 range.setEnd(WTFMove(endContainer), value.end.offset); 1043 } 1044 1045 void Range::updateFromSelection(const SimpleRange& value) 1046 { 1047 ASSERT(m_isAssociatedWithSelection); 1048 m_isAssociatedWithSelection = false; 1049 setBothEndpoints(*this, value); 1050 m_isAssociatedWithSelection = true; 1051 } 1052 1035 1053 SimpleRange makeSimpleRange(const Range& range) 1036 1054 { … … 1058 1076 { 1059 1077 auto result = Range::create(range.start.document()); 1060 auto startContainer = range.start.container; 1061 result->setStart(WTFMove(startContainer), range.start.offset); 1062 auto endContainer = range.end.container; 1063 result->setEnd(WTFMove(endContainer), range.end.offset); 1078 setBothEndpoints(result, range); 1064 1079 return result; 1065 1080 } -
trunk/Source/WebCore/dom/Range.h
r266986 r267220 100 100 void textNodeSplit(Text& oldNode); 101 101 102 void didAssociateWithSelection() { m_isAssociatedWithSelection = true; } 103 void didDisassociateFromSelection() { m_isAssociatedWithSelection = false; } 104 void updateFromSelection(const SimpleRange&); 105 106 static ExceptionOr<Node*> checkNodeOffsetPair(Node&, unsigned offset); 107 102 108 #if ENABLE(TREE_DEBUGGING) 103 109 String debugDescription() const; … … 110 116 111 117 void updateDocument(); 112 ExceptionOr<Node*> checkNodeOffsetPair(Node&, unsigned offset) const;118 void updateAssociatedSelection(); 113 119 ExceptionOr<RefPtr<DocumentFragment>> processContents(ActionType); 114 120 … … 116 122 RangeBoundaryPoint m_start; 117 123 RangeBoundaryPoint m_end; 124 bool m_isAssociatedWithSelection { false }; 118 125 }; 119 126 -
trunk/Source/WebCore/dom/Text.cpp
r266986 r267220 246 246 } 247 247 248 void Text::setDataAndUpdate(const String& newData, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength )248 void Text::setDataAndUpdate(const String& newData, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength, UpdateLiveRanges updateLiveRanges) 249 249 { 250 250 auto oldData = data(); 251 CharacterData::setDataAndUpdate(newData, offsetOfReplacedData, oldLength, newLength); 252 251 CharacterData::setDataAndUpdate(newData, offsetOfReplacedData, oldLength, newLength, updateLiveRanges); 252 253 // FIXME: Does not seem correct to do this for 0 offset only. 253 254 if (!offsetOfReplacedData) { 254 255 auto* textManipulationController = document().textManipulationControllerIfExists(); -
trunk/Source/WebCore/dom/Text.h
r266986 r267220 58 58 String debugDescription() const final; 59 59 60 void setDataAndUpdate(const String&, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength) final;61 62 60 protected: 63 61 Text(Document& document, const String& data, ConstructionType type) … … 71 69 Ref<Node> cloneNodeInternal(Document&, CloningOperation) override; 72 70 bool childTypeAllowed(NodeType) const override; 71 void setDataAndUpdate(const String&, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength, UpdateLiveRanges) final; 73 72 74 73 virtual Ref<Text> virtualCreate(const String&); -
trunk/Source/WebCore/editing/FrameSelection.cpp
r266986 r267220 1 1 /* 2 * Copyright (C) 2004 , 2008, 2009, 2010, 2014-2015Apple Inc. All rights reserved.2 * Copyright (C) 2004-2020 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 150 150 151 151 FrameSelection::FrameSelection(Document* document) 152 : m_document(document) 153 , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation()) 152 : m_document(makeWeakPtr(document)) 154 153 , m_granularity(TextGranularity::CharacterGranularity) 155 154 #if ENABLE(TEXT_CARET) … … 170 169 #endif 171 170 { 172 if (shouldAlwaysUseDirectionalSelection(m_document ))171 if (shouldAlwaysUseDirectionalSelection(m_document.get())) 173 172 m_selection.setIsDirectional(true); 174 173 … … 249 248 clearCaretRect(); 250 249 else 251 updateCaretRect( document, m_position);250 updateCaretRect(*document, m_position); 252 251 } 253 252 … … 293 292 { 294 293 VisibleSelection newSelection = passedNewSelection; 295 bool isDirectional = shouldAlwaysUseDirectionalSelection(m_document ) || newSelection.isDirectional();294 bool isDirectional = shouldAlwaysUseDirectionalSelection(m_document.get()) || newSelection.isDirectional(); 296 295 297 296 VisiblePosition base = m_originalBase.isNotNull() ? m_originalBase : newSelection.visibleBase(); … … 315 314 if (m_selection == newSelection || !shouldChangeSelection(newSelection)) 316 315 return; 317 318 316 319 317 AXTextStateChangeIntent intent; … … 331 329 332 330 VisibleSelection newSelection = newSelectionPossiblyWithoutDirection; 333 if (shouldAlwaysUseDirectionalSelection(m_document ))331 if (shouldAlwaysUseDirectionalSelection(m_document.get())) 334 332 newSelection.setIsDirectional(true); 335 333 336 334 if (!m_document || !m_document->frame()) { 337 335 m_selection = newSelection; 336 updateAssociatedLiveRange(); 338 337 return false; 339 338 } … … 369 368 370 369 m_selection = newSelection; 370 updateAssociatedLiveRange(); 371 371 372 372 // Selection offsets should increase when LF is inserted before the caret in InsertLineBreakCommand. See <https://webkit.org/b/56061>. … … 391 391 // Always clear the x position used for vertical arrow navigation. 392 392 // It will be restored by the vertical arrow navigation code if necessary. 393 m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation();393 m_xPosForVerticalArrowNavigation = WTF::nullopt; 394 394 selectFrameElementInParentIfFullySelected(); 395 395 m_document->editor().respondToChangedSelection(oldSelection, options); … … 405 405 LOG_WITH_STREAM(Selection, stream << "FrameSelection::setSelection " << selection); 406 406 407 RefPtr<Document> protector(m_document);407 auto protectedDocument = makeRefPtr(m_document.get()); 408 408 if (!setSelectionWithoutUpdatingAppearance(selection, options, align, granularity)) 409 409 return; … … 420 420 m_pendingSelectionUpdate = true; 421 421 422 if ( m_document->hasPendingStyleRecalc())423 return; 424 425 FrameView* frameView = m_document->view();422 if (protectedDocument->hasPendingStyleRecalc()) 423 return; 424 425 auto frameView = protectedDocument->view(); 426 426 if (frameView && frameView->layoutContext().isLayoutPending()) 427 427 return; … … 430 430 431 431 if (options & IsUserTriggered) { 432 if (auto* client = m_document->editor().client())432 if (auto* client = protectedDocument->editor().client()) 433 433 client->didEndUserTriggeredSelectionChanges(); 434 434 } … … 805 805 break; 806 806 case TextGranularity::LineGranularity: 807 pos = nextLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(E XTENT));807 pos = nextLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(Extent)); 808 808 break; 809 809 case TextGranularity::ParagraphGranularity: 810 pos = nextParagraphPosition(pos, lineDirectionPointForBlockDirectionNavigation(E XTENT));810 pos = nextParagraphPosition(pos, lineDirectionPointForBlockDirectionNavigation(Extent)); 811 811 break; 812 812 case TextGranularity::DocumentGranularity: … … 918 918 pos = currentPosition; 919 919 if (!isRange() || !isStartOfLine(pos)) 920 pos = nextLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(S TART));920 pos = nextLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(Start)); 921 921 break; 922 922 } 923 923 case TextGranularity::ParagraphGranularity: 924 pos = nextParagraphPosition(currentPosition, lineDirectionPointForBlockDirectionNavigation(S TART));924 pos = nextParagraphPosition(currentPosition, lineDirectionPointForBlockDirectionNavigation(Start)); 925 925 break; 926 926 case TextGranularity::DocumentGranularity: … … 1026 1026 break; 1027 1027 case TextGranularity::LineGranularity: 1028 pos = previousLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(E XTENT));1028 pos = previousLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(Extent)); 1029 1029 break; 1030 1030 case TextGranularity::ParagraphGranularity: 1031 pos = previousParagraphPosition(pos, lineDirectionPointForBlockDirectionNavigation(E XTENT));1031 pos = previousParagraphPosition(pos, lineDirectionPointForBlockDirectionNavigation(Extent)); 1032 1032 break; 1033 1033 case TextGranularity::SentenceBoundary: … … 1134 1134 break; 1135 1135 case TextGranularity::LineGranularity: 1136 pos = previousLinePosition(currentPosition, lineDirectionPointForBlockDirectionNavigation(S TART));1136 pos = previousLinePosition(currentPosition, lineDirectionPointForBlockDirectionNavigation(Start)); 1137 1137 break; 1138 1138 case TextGranularity::ParagraphGranularity: 1139 pos = previousParagraphPosition(currentPosition, lineDirectionPointForBlockDirectionNavigation(S TART));1139 pos = previousParagraphPosition(currentPosition, lineDirectionPointForBlockDirectionNavigation(Start)); 1140 1140 break; 1141 1141 case TextGranularity::SentenceBoundary: … … 1379 1379 // Some of the above operations set an xPosForVerticalArrowNavigation. 1380 1380 // Setting a selection will clear it, so save it to possibly restore later. 1381 // Note: the S TARTposition type is arbitrary because it is unused, it would be1381 // Note: the Start position type is arbitrary because it is unused, it would be 1382 1382 // the requested position type if there were no xPosForVerticalArrowNavigation set. 1383 LayoutUnit x = lineDirectionPointForBlockDirectionNavigation(S TART);1384 m_selection.setIsDirectional(shouldAlwaysUseDirectionalSelection(m_document ) || alter == AlterationExtend);1383 LayoutUnit x = lineDirectionPointForBlockDirectionNavigation(Start); 1384 m_selection.setIsDirectional(shouldAlwaysUseDirectionalSelection(m_document.get()) || alter == AlterationExtend); 1385 1385 1386 1386 switch (alter) { … … 1460 1460 case AlterationMove: 1461 1461 pos = VisiblePosition(direction == DirectionUp ? m_selection.start() : m_selection.end(), m_selection.affinity()); 1462 xPos = lineDirectionPointForBlockDirectionNavigation(direction == DirectionUp ? S TART : END);1462 xPos = lineDirectionPointForBlockDirectionNavigation(direction == DirectionUp ? Start : End); 1463 1463 m_selection.setAffinity(direction == DirectionUp ? Affinity::Upstream : Affinity::Downstream); 1464 1464 break; 1465 1465 case AlterationExtend: 1466 1466 pos = VisiblePosition(m_selection.extent(), m_selection.affinity()); 1467 xPos = lineDirectionPointForBlockDirectionNavigation(E XTENT);1467 xPos = lineDirectionPointForBlockDirectionNavigation(Extent); 1468 1468 m_selection.setAffinity(Affinity::Downstream); 1469 1469 break; … … 1515 1515 m_granularity = TextGranularity::CharacterGranularity; 1516 1516 1517 m_selection.setIsDirectional(shouldAlwaysUseDirectionalSelection(m_document ) || alter == AlterationExtend);1517 m_selection.setIsDirectional(shouldAlwaysUseDirectionalSelection(m_document.get()) || alter == AlterationExtend); 1518 1518 1519 1519 return true; 1520 1520 } 1521 1521 1522 LayoutUnit FrameSelection::lineDirectionPointForBlockDirectionNavigation(EPositionType type) 1523 { 1524 LayoutUnit x; 1525 1522 LayoutUnit FrameSelection::lineDirectionPointForBlockDirectionNavigation(PositionType type) 1523 { 1526 1524 if (isNone()) 1527 return x; 1528 1529 Position pos; 1525 return 0; 1526 1527 // FIXME: Can we use visibleStart/End/Extent? 1528 Position position; 1530 1529 switch (type) { 1531 case START: 1532 pos = m_selection.start(); 1533 break; 1534 case END: 1535 pos = m_selection.end(); 1536 break; 1537 case BASE: 1538 pos = m_selection.base(); 1539 break; 1540 case EXTENT: 1541 pos = m_selection.extent(); 1542 break; 1543 } 1544 1545 Frame* frame = pos.anchorNode()->document().frame(); 1546 if (!frame) 1547 return x; 1548 1549 if (m_xPosForVerticalArrowNavigation == NoXPosForVerticalArrowNavigation()) { 1550 VisiblePosition visiblePosition(pos, m_selection.affinity()); 1551 // VisiblePosition creation can fail here if a node containing the selection becomes visibility:hidden 1552 // after the selection is created and before this function is called. 1553 x = visiblePosition.isNotNull() ? visiblePosition.lineDirectionPointForBlockDirectionNavigation() : 0; 1554 m_xPosForVerticalArrowNavigation = x; 1555 } else 1556 x = m_xPosForVerticalArrowNavigation; 1557 1530 case Start: 1531 position = m_selection.start(); 1532 break; 1533 case End: 1534 position = m_selection.end(); 1535 break; 1536 case Extent: 1537 position = m_selection.extent(); 1538 break; 1539 } 1540 1541 // FIXME: Why is this check needed? What's the harm in doing a little more work without a frame? 1542 if (!position.anchorNode()->document().frame()) 1543 return 0; 1544 1545 // FIXME: Can we do this before getting the position from the selection? 1546 if (m_xPosForVerticalArrowNavigation) 1547 return *m_xPosForVerticalArrowNavigation; 1548 1549 // VisiblePosition creation can fail here if a node containing the selection becomes 1550 // visibility:hidden after the selection is created and before this function is called. 1551 VisiblePosition visiblePosition(position, m_selection.affinity()); 1552 auto x = visiblePosition.isNotNull() ? visiblePosition.lineDirectionPointForBlockDirectionNavigation() : 0; 1553 m_xPosForVerticalArrowNavigation = { x }; 1558 1554 return x; 1559 1555 } … … 1627 1623 } 1628 1624 1629 bool CaretBase::updateCaretRect(Document *document, const VisiblePosition& caretPosition)1630 { 1631 document ->updateLayoutIgnorePendingStylesheets();1625 bool CaretBase::updateCaretRect(Document& document, const VisiblePosition& caretPosition) 1626 { 1627 document.updateLayoutIgnorePendingStylesheets(); 1632 1628 m_caretRectNeedsUpdate = false; 1633 1629 RenderBlock* renderer; … … 1688 1684 else { 1689 1685 VisiblePosition visibleStart = m_selection.visibleStart(); 1690 if (updateCaretRect( m_document, visibleStart)) {1686 if (updateCaretRect(*m_document, visibleStart)) { 1691 1687 caretNode = visibleStart.deepEquivalent().deprecatedNode(); 1692 1688 m_absCaretBoundsDirty = true; … … 2127 2123 // If the caret moved, stop the blink timer so we can restart with a 2128 2124 // black caret in the new location. 2129 if (caretRectChangedOrCleared || !shouldBlink || shouldStopBlinkingDueToTypingCommand(m_document ))2125 if (caretRectChangedOrCleared || !shouldBlink || shouldStopBlinkingDueToTypingCommand(m_document.get())) 2130 2126 m_caretBlinkTimer.stop(); 2131 2127 … … 2777 2773 } 2778 2774 } 2775 2779 2776 #endif // PLATFORM(IOS_FAMILY) 2780 2777 2778 static bool containsEndpoints(const WeakPtr<Document>& document, const Optional<SimpleRange>& range) 2779 { 2780 return document && range && document->contains(range->start.container) && document->contains(range->end.container); 2781 } 2782 2783 static bool containsEndpoints(const WeakPtr<Document>& document, const Range& liveRange) 2784 { 2785 // Only need to check the start container because live ranges enforce the invariant that start and end have a common ancestor. 2786 return document && document->contains(liveRange.startContainer()); 2787 } 2788 2789 RefPtr<Range> FrameSelection::associatedLiveRange() 2790 { 2791 if (!m_associatedLiveRange) { 2792 if (auto range = m_selection.firstRange(); containsEndpoints(m_document, range)) { 2793 m_associatedLiveRange = createLiveRange(*range); 2794 m_associatedLiveRange->didAssociateWithSelection(); 2795 } 2796 } 2797 return m_associatedLiveRange; 2798 } 2799 2800 void FrameSelection::disassociateLiveRange() 2801 { 2802 if (auto previouslyAssociatedLiveRange = std::exchange(m_associatedLiveRange, nullptr)) 2803 previouslyAssociatedLiveRange->didDisassociateFromSelection(); 2804 // FIXME: Need additional code to keep the live range object's wrapper alive to preserve any JavaScript properties on it. 2805 } 2806 2807 void FrameSelection::associateLiveRange(Range& liveRange) 2808 { 2809 disassociateLiveRange(); 2810 m_associatedLiveRange = &liveRange; 2811 liveRange.didAssociateWithSelection(); 2812 updateFromAssociatedLiveRange(); 2813 } 2814 2815 void FrameSelection::updateFromAssociatedLiveRange() 2816 { 2817 ASSERT(m_associatedLiveRange); 2818 if (!containsEndpoints(m_document, *m_associatedLiveRange)) 2819 disassociateLiveRange(); 2820 else 2821 setSelection(makeSimpleRange(*m_associatedLiveRange)); 2822 // FIXME: Normalization done by setSelection will be visible next time updateAssociatedLiveRange is called. Instead the Selection API specification calls for allowing non-normalized selection ranges. 2823 } 2824 2825 void FrameSelection::updateAssociatedLiveRange() 2826 { 2827 auto range = m_selection.firstRange(); 2828 if (!containsEndpoints(m_document, range)) 2829 disassociateLiveRange(); 2830 else if (m_associatedLiveRange) 2831 m_associatedLiveRange->updateFromSelection(*range); 2832 } 2833 2781 2834 } 2782 2835 2783 2836 #if ENABLE(TREE_DEBUGGING) 2784 2837 2785 void showTree(const WebCore::FrameSelection& sel )2786 { 2787 sel .showTreeForThis();2788 } 2789 2790 void showTree(const WebCore::FrameSelection* sel )2791 { 2792 if (sel )2793 sel ->showTreeForThis();2794 } 2795 2796 #endif 2838 void showTree(const WebCore::FrameSelection& selection) 2839 { 2840 selection.showTreeForThis(); 2841 } 2842 2843 void showTree(const WebCore::FrameSelection* selection) 2844 { 2845 if (selection) 2846 selection->showTreeForThis(); 2847 } 2848 2849 #endif -
trunk/Source/WebCore/editing/FrameSelection.h
r266986 r267220 1 1 /* 2 * Copyright (C) 2004 , 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.2 * Copyright (C) 2004-2020 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 27 27 28 28 #include "AXTextStateChangeIntent.h" 29 #include "Color.h" 29 30 #include "EditingStyle.h" 30 31 #include "Element.h" … … 35 36 #include "VisibleSelection.h" 36 37 #include <wtf/Noncopyable.h> 37 38 #if PLATFORM(IOS_FAMILY)39 #include "Color.h"40 #endif41 38 42 39 namespace WebCore { … … 52 49 class VisiblePosition; 53 50 54 enum EUserTriggered { NotUserTriggered = 0, UserTriggered = 1 }; 55 56 enum RevealExtentOption { 57 RevealExtent, 58 DoNotRevealExtent 59 }; 51 enum EUserTriggered : bool { NotUserTriggered, UserTriggered }; 52 enum RevealExtentOption : bool { RevealExtent, DoNotRevealExtent }; 60 53 61 54 class CaretBase { … … 70 63 void invalidateCaretRect(Node*, bool caretRectChanged = false); 71 64 void clearCaretRect(); 72 bool updateCaretRect(Document *, const VisiblePosition& caretPosition);65 bool updateCaretRect(Document&, const VisiblePosition& caretPosition); 73 66 bool shouldRepaintCaret(const RenderView*, bool isContentEditable) const; 74 67 void paintCaret(const Node&, GraphicsContext&, const LayoutPoint&, const LayoutRect& clipRect) const; … … 119 112 public: 120 113 enum EAlteration { AlterationMove, AlterationExtend }; 121 enum CursorAlignOnScroll { AlignCursorOnScrollIfNeeded, 122 AlignCursorOnScrollAlways }; 114 enum CursorAlignOnScroll { AlignCursorOnScrollIfNeeded, AlignCursorOnScrollAlways }; 123 115 enum SetSelectionOption { 124 116 FireSelectEvent = 1 << 0, … … 132 124 RevealSelectionUpToMainFrame = 1 << 8, 133 125 }; 134 static constexpr OptionSet<SetSelectionOption> defaultSetSelectionOptions(EUserTriggered userTriggered = NotUserTriggered) 135 { 136 OptionSet<SetSelectionOption> options { CloseTyping, ClearTypingStyle }; 137 if (userTriggered == UserTriggered) 138 options.add({ RevealSelection, FireSelectEvent, IsUserTriggered }); 139 return options; 140 } 126 static constexpr OptionSet<SetSelectionOption> defaultSetSelectionOptions(EUserTriggered = NotUserTriggered); 141 127 142 128 WEBCORE_EXPORT explicit FrameSelection(Document* = nullptr); … … 181 167 void setExtent(const Position&, Affinity, EUserTriggered = NotUserTriggered); 182 168 183 // Return the renderer that is responsible for painting the caret (in the selection start node) 169 // Return the renderer that is responsible for painting the caret (in the selection start node). 184 170 RenderBlock* caretRendererWithoutUpdatingLayout() const; 185 171 186 // Bounds of (possibly transformed) caret in absolute coords172 // Bounds of possibly-transformed caret in absolute coordinates. 187 173 WEBCORE_EXPORT IntRect absoluteCaretBounds(bool* insideFixed = nullptr); 188 174 void setCaretRectNeedsUpdate() { CaretBase::setCaretRectNeedsUpdate(); } … … 208 194 bool isCaretBlinkingSuspended() const { return m_isCaretBlinkingSuspended; } 209 195 210 // Focus211 196 void setFocused(bool); 212 197 bool isFocused() const { return m_focused; } … … 214 199 void pageActivationChanged(); 215 200 216 // Painting.217 201 WEBCORE_EXPORT void updateAppearance(); 218 202 … … 240 224 void setUpdateAppearanceEnabled(bool enabled) { m_updateAppearanceEnabled = enabled; } 241 225 void suppressScrolling() { ++m_scrollingSuppressCount; } 242 void restoreScrolling() 243 { 244 ASSERT(m_scrollingSuppressCount); 245 --m_scrollingSuppressCount; 246 } 226 void restoreScrolling(); 247 227 #endif 248 228 … … 272 252 void setShouldShowBlockCursor(bool); 273 253 254 RefPtr<Range> associatedLiveRange(); 255 void associateLiveRange(Range&); 256 void disassociateLiveRange(); 257 void updateFromAssociatedLiveRange(); 258 274 259 private: 275 enum EPositionType { START, END, BASE, EXTENT };276 277 260 void updateAndRevealSelection(const AXTextStateChangeIntent&); 278 261 void updateDataDetectorsForSelection(); … … 298 281 VisiblePosition modifyMovingBackward(TextGranularity, bool* reachedBoundary = nullptr); 299 282 300 LayoutUnit lineDirectionPointForBlockDirectionNavigation(EPositionType); 283 enum PositionType : uint8_t { Start, End, Extent }; 284 LayoutUnit lineDirectionPointForBlockDirectionNavigation(PositionType); 301 285 302 286 AXTextStateChangeIntent textSelectionIntent(EAlteration, SelectionDirection, TextGranularity); 303 #if ENABLE(ACCESSIBILITY)304 287 void notifyAccessibilityForSelectionChange(const AXTextStateChangeIntent&); 305 #else306 void notifyAccessibilityForSelectionChange(const AXTextStateChangeIntent&) { }307 #endif308 288 309 289 void updateSelectionCachesIfSelectionIsInsideTextFormControl(EUserTriggered); … … 329 309 #endif 330 310 331 Document* m_document; 332 333 LayoutUnit m_xPosForVerticalArrowNavigation; 334 311 void updateAssociatedLiveRange(); 312 313 WeakPtr<Document> m_document; 314 RefPtr<Range> m_associatedLiveRange; 315 Optional<LayoutUnit> m_xPosForVerticalArrowNavigation; 335 316 VisibleSelection m_selection; 336 VisiblePosition m_originalBase; // Used to store base before the adjustment at bidi boundary 337 TextGranularity m_granularity ;317 VisiblePosition m_originalBase; // Used to store base before the adjustment at bidi boundary. 318 TextGranularity m_granularity { TextGranularity::CharacterGranularity }; 338 319 339 320 RefPtr<Node> m_previousCaretNode; // The last node which painted the caret. Retained for clearing the old caret when it moves. … … 368 349 }; 369 350 351 constexpr auto FrameSelection::defaultSetSelectionOptions(EUserTriggered userTriggered) -> OptionSet<SetSelectionOption> 352 { 353 OptionSet<SetSelectionOption> options { CloseTyping, ClearTypingStyle }; 354 if (userTriggered == UserTriggered) 355 options.add({ RevealSelection, FireSelectEvent, IsUserTriggered }); 356 return options; 357 } 358 370 359 inline EditingStyle* FrameSelection::typingStyle() const 371 360 { … … 378 367 } 379 368 380 #if !( PLATFORM(COCOA) || USE(ATK))381 #if ENABLE(ACCESSIBILITY) 369 #if !(ENABLE(ACCESSIBILITY) && (PLATFORM(COCOA) || USE(ATK))) 370 382 371 inline void FrameSelection::notifyAccessibilityForSelectionChange(const AXTextStateChangeIntent&) 383 372 { 384 373 } 385 #endif 374 375 #endif 376 377 #if PLATFORM(IOS_FAMILY) 378 379 inline void FrameSelection::restoreScrolling() 380 { 381 ASSERT(m_scrollingSuppressCount); 382 --m_scrollingSuppressCount; 383 } 384 386 385 #endif 387 386 … … 389 388 390 389 #if ENABLE(TREE_DEBUGGING) 390 391 391 // Outside the WebCore namespace for ease of invocation from the debugger. 392 392 void showTree(const WebCore::FrameSelection&); 393 393 void showTree(const WebCore::FrameSelection*); 394 #endif 394 395 #endif -
trunk/Source/WebCore/page/DOMSelection.cpp
r266618 r267220 1 1 /* 2 * Copyright (C) 2007 , 2009, 2016Apple Inc. All rights reserved.2 * Copyright (C) 2007-2020 Apple Inc. All rights reserved. 3 3 * Copyright (C) 2012 Google Inc. All rights reserved. 4 4 * … … 36 36 #include "FrameSelection.h" 37 37 #include "Range.h" 38 #include "Settings.h" 38 39 #include "TextIterator.h" 39 40 40 41 namespace WebCore { 41 42 42 static Node* selectionShadowAncestor(Frame& frame) 43 { 43 static RefPtr<Node> selectionShadowAncestor(Frame& frame) 44 { 45 ASSERT(!frame.settings().liveRangeSelectionEnabled()); 44 46 auto* node = frame.selection().selection().base().anchorNode(); 45 if (!node )47 if (!node || !node->isInShadowTree()) 46 48 return nullptr; 47 if (!node->isInShadowTree()) 48 return nullptr; 49 // FIXME: Unclear on why this needs to be the possibly null frame.document() instead of the never null node->document(). 50 return frame.document()->ancestorNodeInThisScope(node); 49 return node->document().ancestorNodeInThisScope(node); 51 50 } 52 51 … … 56 55 } 57 56 58 const VisibleSelection& DOMSelection::visibleSelection() const 59 { 60 ASSERT(frame()); 61 return frame()->selection().selection(); 62 } 63 64 static Position anchorPosition(const VisibleSelection& selection) 65 { 66 auto anchor = selection.isBaseFirst() ? selection.start() : selection.end(); 67 return anchor.parentAnchoredEquivalent(); 68 } 69 70 static Position focusPosition(const VisibleSelection& selection) 71 { 72 auto focus = selection.isBaseFirst() ? selection.end() : selection.start(); 73 return focus.parentAnchoredEquivalent(); 74 } 75 76 static Position basePosition(const VisibleSelection& selection) 77 { 78 return selection.base().parentAnchoredEquivalent(); 79 } 80 81 static Position extentPosition(const VisibleSelection& selection) 82 { 83 return selection.extent().parentAnchoredEquivalent(); 84 } 85 86 Node* DOMSelection::anchorNode() const 87 { 88 if (!frame()) 89 return nullptr; 90 return shadowAdjustedNode(anchorPosition(visibleSelection())); 57 Ref<DOMSelection> DOMSelection::create(DOMWindow& window) 58 { 59 return adoptRef(*new DOMSelection(window)); 60 } 61 62 RefPtr<Frame> DOMSelection::frame() const 63 { 64 return DOMWindowProperty::frame(); 65 } 66 67 Optional<SimpleRange> DOMSelection::range() const 68 { 69 auto frame = this->frame(); 70 if (!frame) 71 return WTF::nullopt; 72 auto range = frame->selection().selection().firstRange(); 73 if (!range || range->start.container->isInShadowTree()) 74 return WTF::nullopt; 75 return range; 76 } 77 78 Position DOMSelection::anchorPosition() const 79 { 80 auto frame = this->frame(); 81 if (!frame) 82 return { }; 83 auto& selection = frame->selection().selection(); 84 return (selection.isBaseFirst() ? selection.start() : selection.end()).parentAnchoredEquivalent(); 85 } 86 87 Position DOMSelection::focusPosition() const 88 { 89 auto frame = this->frame(); 90 if (!frame) 91 return { }; 92 auto& selection = frame->selection().selection(); 93 return (selection.isBaseFirst() ? selection.end() : selection.start()).parentAnchoredEquivalent(); 94 } 95 96 Position DOMSelection::basePosition() const 97 { 98 auto frame = this->frame(); 99 if (!frame) 100 return { }; 101 return frame->selection().selection().base().parentAnchoredEquivalent(); 102 } 103 104 Position DOMSelection::extentPosition() const 105 { 106 auto frame = this->frame(); 107 if (!frame) 108 return { }; 109 return frame->selection().selection().extent().parentAnchoredEquivalent(); 110 } 111 112 RefPtr<Node> DOMSelection::anchorNode() const 113 { 114 return shadowAdjustedNode(anchorPosition()); 91 115 } 92 116 93 117 unsigned DOMSelection::anchorOffset() const 94 118 { 95 if (!frame()) 96 return 0; 97 return shadowAdjustedOffset(anchorPosition(visibleSelection())); 98 } 99 100 Node* DOMSelection::focusNode() const 101 { 102 if (!frame()) 103 return nullptr; 104 return shadowAdjustedNode(focusPosition(visibleSelection())); 119 return shadowAdjustedOffset(anchorPosition()); 120 } 121 122 RefPtr<Node> DOMSelection::focusNode() const 123 { 124 return shadowAdjustedNode(focusPosition()); 105 125 } 106 126 107 127 unsigned DOMSelection::focusOffset() const 108 128 { 109 if (!frame()) 110 return 0; 111 return shadowAdjustedOffset(focusPosition(visibleSelection())); 112 } 113 114 Node* DOMSelection::baseNode() const 115 { 116 if (!frame()) 117 return nullptr; 118 return shadowAdjustedNode(basePosition(visibleSelection())); 129 return shadowAdjustedOffset(focusPosition()); 130 } 131 132 RefPtr<Node> DOMSelection::baseNode() const 133 { 134 return shadowAdjustedNode(basePosition()); 119 135 } 120 136 121 137 unsigned DOMSelection::baseOffset() const 122 138 { 123 if (!frame()) 124 return 0; 125 return shadowAdjustedOffset(basePosition(visibleSelection())); 126 } 127 128 Node* DOMSelection::extentNode() const 129 { 130 if (!frame()) 131 return nullptr; 132 return shadowAdjustedNode(extentPosition(visibleSelection())); 139 return shadowAdjustedOffset(basePosition()); 140 } 141 142 RefPtr<Node> DOMSelection::extentNode() const 143 { 144 return shadowAdjustedNode(extentPosition()); 133 145 } 134 146 135 147 unsigned DOMSelection::extentOffset() const 136 148 { 137 if (!frame()) 138 return 0; 139 return shadowAdjustedOffset(extentPosition(visibleSelection())); 149 return shadowAdjustedOffset(extentPosition()); 140 150 } 141 151 142 152 bool DOMSelection::isCollapsed() const 143 153 { 144 auto *frame = this->frame();145 if (!frame || selectionShadowAncestor(*frame))154 auto frame = this->frame(); 155 if (!frame) 146 156 return true; 147 return !frame->selection().isRange(); 157 auto range = this->range(); 158 return !range || range->collapsed(); 148 159 } 149 160 150 161 String DOMSelection::type() const 151 162 { 152 auto *frame = this->frame();163 auto frame = this->frame(); 153 164 if (!frame) 154 165 return "None"_s; … … 163 174 unsigned DOMSelection::rangeCount() const 164 175 { 165 auto *frame = this->frame();176 auto frame = this->frame(); 166 177 return !frame || frame->selection().isNone() ? 0 : 1; 167 178 } 168 179 169 void DOMSelection::collapse(Node* node, unsigned offset) 170 { 171 if (!isValidForPosition(node)) 172 return; 173 174 Ref<Frame> protectedFrame(*frame()); 175 protectedFrame->selection().moveTo(createLegacyEditingPosition(node, offset), Affinity::Downstream); 180 ExceptionOr<void> DOMSelection::collapse(Node* node, unsigned offset) 181 { 182 auto frame = this->frame(); 183 if (!frame) 184 return { }; 185 if (frame->settings().liveRangeSelectionEnabled()) { 186 if (!node) { 187 removeAllRanges(); 188 return { }; 189 } 190 auto& document = *frame->document(); 191 if (!document.contains(*node)) 192 return { }; 193 if (auto result = Range::checkNodeOffsetPair(*node, offset); result.hasException()) 194 return result.releaseException(); 195 } else { 196 if (!isValidForPosition(node)) 197 return { }; 198 } 199 auto& selection = frame->selection(); 200 selection.disassociateLiveRange(); 201 selection.moveTo(makeContainerOffsetPosition(node, offset), Affinity::Downstream); 202 return { }; 176 203 } 177 204 178 205 ExceptionOr<void> DOMSelection::collapseToEnd() 179 206 { 180 auto *frame = this->frame();207 auto frame = this->frame(); 181 208 if (!frame) 182 209 return { }; … … 184 211 if (selection.isNone()) 185 212 return Exception { InvalidStateError }; 186 187 Ref<Frame> protector(*frame); 213 selection.disassociateLiveRange(); 188 214 selection.moveTo(selection.selection().end(), Affinity::Downstream); 189 215 return { }; … … 192 218 ExceptionOr<void> DOMSelection::collapseToStart() 193 219 { 194 auto *frame = this->frame();220 auto frame = this->frame(); 195 221 if (!frame) 196 222 return { }; … … 198 224 if (selection.isNone()) 199 225 return Exception { InvalidStateError }; 200 201 Ref<Frame> protector(*frame); 226 selection.disassociateLiveRange(); 202 227 selection.moveTo(selection.selection().start(), Affinity::Downstream); 203 228 return { }; … … 206 231 void DOMSelection::empty() 207 232 { 208 auto* frame = this->frame(); 209 if (!frame) 210 return; 211 frame->selection().clear(); 212 } 213 214 void DOMSelection::setBaseAndExtent(Node* baseNode, unsigned baseOffset, Node* extentNode, unsigned extentOffset) 215 { 216 if (!isValidForPosition(baseNode) || !isValidForPosition(extentNode)) 217 return; 218 219 Ref<Frame> protectedFrame(*frame()); 220 protectedFrame->selection().moveTo(createLegacyEditingPosition(baseNode, baseOffset), createLegacyEditingPosition(extentNode, extentOffset), Affinity::Downstream); 221 } 222 223 void DOMSelection::setPosition(Node* node, unsigned offset) 224 { 225 if (!isValidForPosition(node)) 226 return; 227 228 Ref<Frame> protectedFrame(*frame()); 229 protectedFrame->selection().moveTo(createLegacyEditingPosition(node, offset), Affinity::Downstream); 233 removeAllRanges(); 234 } 235 236 ExceptionOr<void> DOMSelection::setBaseAndExtent(Node* baseNode, unsigned baseOffset, Node* extentNode, unsigned extentOffset) 237 { 238 auto frame = this->frame(); 239 if (!frame) 240 return { }; 241 if (frame->settings().liveRangeSelectionEnabled()) { 242 // FIXME: We should do this by making the arguments non-nullable in the IDL file, once liveRangeSelectionEnabled is always true. 243 if (!baseNode || !extentNode) 244 return Exception { TypeError }; 245 auto& document = *frame->document(); 246 if (!document.contains(*baseNode) || !document.contains(*extentNode)) 247 return { }; 248 if (auto result = Range::checkNodeOffsetPair(*baseNode, baseOffset); result.hasException()) 249 return result.releaseException(); 250 if (auto result = Range::checkNodeOffsetPair(*extentNode, extentOffset); result.hasException()) 251 return result.releaseException(); 252 } else { 253 if (!isValidForPosition(baseNode) || !isValidForPosition(extentNode)) 254 return { }; 255 } 256 auto& selection = frame->selection(); 257 selection.disassociateLiveRange(); 258 selection.moveTo(makeContainerOffsetPosition(baseNode, baseOffset), makeContainerOffsetPosition(extentNode, extentOffset), Affinity::Downstream); 259 return { }; 260 } 261 262 ExceptionOr<void> DOMSelection::setPosition(Node* node, unsigned offset) 263 { 264 return collapse(node, offset); 230 265 } 231 266 232 267 void DOMSelection::modify(const String& alterString, const String& directionString, const String& granularityString) 233 268 { 234 auto* frame = this->frame();235 if (!frame)236 return;237 238 269 FrameSelection::EAlteration alter; 239 270 if (equalLettersIgnoringASCIICase(alterString, "extend")) … … 278 309 return; 279 310 280 Ref<Frame> protector(*frame);281 frame->selection().modify(alter, direction, granularity);311 if (auto frame = this->frame()) 312 frame->selection().modify(alter, direction, granularity); 282 313 } 283 314 284 315 ExceptionOr<void> DOMSelection::extend(Node& node, unsigned offset) 285 316 { 286 auto frame = makeRefPtr(this->frame()); 287 if (!frame) 288 return { }; 289 if (offset > node.length()) 290 return Exception { IndexSizeError }; 291 if (!isValidForPosition(&node)) 292 return { }; 293 frame->selection().setExtent(createLegacyEditingPosition(&node, offset), Affinity::Downstream); 317 auto frame = this->frame(); 318 if (!frame) 319 return { }; 320 if (frame->settings().liveRangeSelectionEnabled()) { 321 if (!frame->document()->contains(node)) 322 return { }; 323 if (auto result = Range::checkNodeOffsetPair(node, offset); result.hasException()) 324 return result.releaseException(); 325 } else { 326 if (offset > node.length()) 327 return Exception { IndexSizeError }; 328 if (!isValidForPosition(&node)) 329 return { }; 330 } 331 auto& selection = frame->selection(); 332 selection.disassociateLiveRange(); 333 selection.setExtent(makeContainerOffsetPosition(&node, offset), Affinity::Downstream); 294 334 return { }; 295 335 } … … 299 339 if (index >= rangeCount()) 300 340 return Exception { IndexSizeError }; 301 auto& frame = *this->frame(); 341 auto frame = this->frame().releaseNonNull(); 342 if (frame->settings().liveRangeSelectionEnabled()) 343 return frame->selection().associatedLiveRange().releaseNonNull(); 302 344 if (auto shadowAncestor = selectionShadowAncestor(frame)) 303 345 return createLiveRange(makeSimpleRange(*makeBoundaryPointBeforeNode(*shadowAncestor))); 304 return createLiveRange(*frame .selection().selection().firstRange());346 return createLiveRange(*frame->selection().selection().firstRange()); 305 347 } 306 348 307 349 void DOMSelection::removeAllRanges() 308 350 { 309 auto *frame = this->frame();351 auto frame = this->frame(); 310 352 if (!frame) 311 353 return; … … 315 357 void DOMSelection::addRange(Range& liveRange) 316 358 { 317 auto frame = makeRefPtr(this->frame()); 318 if (!frame) 319 return; 320 359 auto frame = this->frame(); 360 if (!frame) 361 return; 362 auto& selection = frame->selection(); 363 if (frame->settings().liveRangeSelectionEnabled()) { 364 if (selection.isNone()) 365 selection.associateLiveRange(liveRange); 366 return; 367 } 321 368 auto range = makeSimpleRange(liveRange); 322 auto& selection = frame->selection();323 324 369 if (auto selectedRange = selection.selection().toNormalizedRange()) { 325 370 if (!selectedRange->start.container->containingShadowRoot() && intersects(*selectedRange, range)) … … 327 372 return; 328 373 } 329 330 374 selection.setSelection(range); 331 375 } 332 376 377 ExceptionOr<void> DOMSelection::removeRange(Range& liveRange) 378 { 379 auto frame = this->frame(); 380 if (!frame) 381 return { }; 382 ASSERT(frame->settings().liveRangeSelectionEnabled()); 383 if (&liveRange != frame->selection().associatedLiveRange()) 384 return Exception { NotFoundError }; 385 removeAllRanges(); 386 return { }; 387 } 388 333 389 void DOMSelection::deleteFromDocument() 334 390 { 335 auto frame = makeRefPtr(this->frame()); 336 if (!frame) 337 return; 338 391 auto frame = this->frame(); 392 if (!frame) 393 return; 394 if (frame->settings().liveRangeSelectionEnabled()) { 395 if (auto range = frame->selection().associatedLiveRange()) 396 range->deleteContents(); 397 return; 398 } 339 399 auto selectedRange = frame->selection().selection().toNormalizedRange(); 340 400 if (!selectedRange || selectedRange->start.container->containingShadowRoot()) 341 401 return; 342 343 402 createLiveRange(*selectedRange)->deleteContents(); 344 403 frame->selection().setSelectedRange(makeSimpleRange(selectedRange->start), Affinity::Downstream, FrameSelection::ShouldCloseTyping::No); … … 347 406 bool DOMSelection::containsNode(Node& node, bool allowPartial) const 348 407 { 349 // FIXME: This behavior does not match what the selection API standard specifies.350 if (node.isTextNode() )408 // FIXME: This is wrong, and was added to work around anomalies caused when we canonicalize selection endpoints. We should fix that and remove this. 409 if (node.isTextNode() && !node.document().settings().liveRangeSelectionEnabled()) 351 410 allowPartial = true; 352 353 auto* frame = this->frame(); 354 if (!frame) 355 return false; 356 357 auto selectedRange = frame->selection().selection().firstRange(); 358 if (!selectedRange || selectedRange->start.container->containingShadowRoot()) 359 return false; 360 361 return allowPartial ? intersects(*selectedRange, node) : contains(*selectedRange, node); 411 auto range = this->range(); 412 return range && (allowPartial ? intersects(*range, node) : contains(*range, node)); 362 413 } 363 414 … … 368 419 } 369 420 370 String DOMSelection::toString() 371 { 372 auto *frame = this->frame();421 String DOMSelection::toString() const 422 { 423 auto frame = this->frame(); 373 424 if (!frame) 374 425 return String(); 375 auto range = frame->selection().selection().toNormalizedRange(); 426 if (frame->settings().liveRangeSelectionEnabled()) { 427 auto range = this->range(); 428 return range ? plainText(*range) : emptyString(); 429 } 430 auto range = frame->selection().selection().firstRange(); 376 431 return range ? plainText(*range) : emptyString(); 377 432 } 378 433 379 Node*DOMSelection::shadowAdjustedNode(const Position& position) const434 RefPtr<Node> DOMSelection::shadowAdjustedNode(const Position& position) const 380 435 { 381 436 if (position.isNull()) 382 437 return nullptr; 438 439 if (frame()->settings().liveRangeSelectionEnabled()) { 440 auto node = position.containerNode(); 441 return !node || node->isInShadowTree() ? nullptr : node; 442 } 383 443 384 444 auto* containerNode = position.containerNode(); … … 398 458 return 0; 399 459 460 if (frame()->settings().liveRangeSelectionEnabled()) 461 return shadowAdjustedNode(position) ? position.computeOffsetInContainerNode() : 0; 462 400 463 auto* containerNode = position.containerNode(); 401 464 auto* adjustedNode = frame()->document()->ancestorNodeInThisScope(containerNode); … … 411 474 bool DOMSelection::isValidForPosition(Node* node) const 412 475 { 413 auto* frame = this->frame(); 476 auto frame = this->frame(); 477 ASSERT(!frame->settings().liveRangeSelectionEnabled()); 414 478 return frame && (!node || &node->document() == frame->document()); 415 479 } -
trunk/Source/WebCore/page/DOMSelection.h
r236917 r267220 1 1 /* 2 * Copyright (C) 2007 Apple Inc. All rights reserved.2 * Copyright (C) 2007-2020 Apple Inc. All rights reserved. 3 3 * Copyright (C) 2012 Google Inc. All rights reserved. 4 4 * … … 43 43 class VisibleSelection; 44 44 45 struct SimpleRange; 46 45 47 class DOMSelection : public RefCounted<DOMSelection>, public DOMWindowProperty { 46 48 public: 47 static Ref<DOMSelection> create(DOMWindow& window) { return adoptRef(*new DOMSelection(window)); }49 static Ref<DOMSelection> create(DOMWindow&); 48 50 49 Node*baseNode() const;50 Node*extentNode() const;51 RefPtr<Node> baseNode() const; 52 RefPtr<Node> extentNode() const; 51 53 unsigned baseOffset() const; 52 54 unsigned extentOffset() const; 53 55 String type() const; 54 voidsetBaseAndExtent(Node* baseNode, unsigned baseOffset, Node* extentNode, unsigned extentOffset);55 voidsetPosition(Node*, unsigned offset);56 ExceptionOr<void> setBaseAndExtent(Node* baseNode, unsigned baseOffset, Node* extentNode, unsigned extentOffset); 57 ExceptionOr<void> setPosition(Node*, unsigned offset); 56 58 void modify(const String& alter, const String& direction, const String& granularity); 57 59 … … 59 61 // reflect the direction in which the selection was made by the user. 60 62 // The base and extent are different, because they don't reflect expansion. 61 Node*anchorNode() const;63 RefPtr<Node> anchorNode() const; 62 64 unsigned anchorOffset() const; 63 Node*focusNode() const;65 RefPtr<Node> focusNode() const; 64 66 unsigned focusOffset() const; 65 67 bool isCollapsed() const; 66 68 unsigned rangeCount() const; 67 voidcollapse(Node*, unsigned offset);69 ExceptionOr<void> collapse(Node*, unsigned offset); 68 70 ExceptionOr<void> collapseToEnd(); 69 71 ExceptionOr<void> collapseToStart(); … … 72 74 void removeAllRanges(); 73 75 void addRange(Range&); 76 ExceptionOr<void> removeRange(Range&); 74 77 void deleteFromDocument(); 75 78 bool containsNode(Node&, bool partlyContained) const; 76 79 void selectAllChildren(Node&); 77 80 78 String toString() ;81 String toString() const; 79 82 80 83 void empty(); … … 83 86 explicit DOMSelection(DOMWindow&); 84 87 85 // Convenience method for accessors, caller must null-check frame(). 86 const VisibleSelection& visibleSelection() const; 88 // FIXME: Change DOMWindowProperty::frame to return RefPtr and then delete this. 89 RefPtr<Frame> frame() const; 90 Optional<SimpleRange> range() const; 87 91 88 Node* shadowAdjustedNode(const Position&) const; 92 Position anchorPosition() const; 93 Position focusPosition() const; 94 Position basePosition() const; 95 Position extentPosition() const; 96 97 RefPtr<Node> shadowAdjustedNode(const Position&) const; 89 98 unsigned shadowAdjustedOffset(const Position&) const; 90 99 -
trunk/Source/WebCore/page/DOMSelection.idl
r266311 r267220 42 42 readonly attribute unsigned long rangeCount; 43 43 44 undefined collapse(Node? node, optional unsigned long offset = 0); 44 readonly attribute DOMString type; 45 46 [MayThrowException] Range getRangeAt(unsigned long index); 47 undefined addRange(Range range); 48 [EnabledBySetting=LiveRangeSelection, MayThrowException] undefined removeRange(Range range); 49 undefined removeAllRanges(); 50 51 undefined empty(); 52 53 [MayThrowException] undefined collapse(Node? node, optional unsigned long offset = 0); 54 [MayThrowException] undefined setPosition(Node? node, optional unsigned long offset = 0); 55 56 [MayThrowException] undefined collapseToStart(); 45 57 [MayThrowException] undefined collapseToEnd(); 46 [MayThrowException] undefined collapseToStart();47 48 [CEReactions] undefined deleteFromDocument();49 boolean containsNode(Node node, optional boolean allowPartial = false);50 undefined selectAllChildren(Node node);51 58 52 59 [MayThrowException] undefined extend(Node node, optional unsigned long offset = 0); 53 60 54 [MayThrowException] Range getRangeAt(unsigned long index); 55 undefined removeAllRanges(); 56 undefined addRange(Range range); 61 [MayThrowException] undefined setBaseAndExtent(Node? baseNode, unsigned long baseOffset, Node? extentNode, unsigned long extentOffset); 62 undefined selectAllChildren(Node node); 63 64 [CEReactions] undefined deleteFromDocument(); 65 boolean containsNode(Node node, optional boolean allowPartialContainment = false); 57 66 58 67 [NotEnumerable] DOMString toString(); 59 68 60 readonly attribute DOMString type;69 // Non-standard methods and attributes. 61 70 62 undefined setBaseAndExtent(Node? baseNode, unsigned long baseOffset, Node? extentNode, unsigned long extentOffset); 63 undefined setPosition(Node? node, optional unsigned long offset = 0); 64 65 undefined empty(); 66 67 // FIXME: The following operation should be implemented. 68 // undefined removeRange(Range range); 69 70 // FIXME: Using "undefined" as default parameter value is wrong. 71 undefined modify(optional DOMString alter = "undefined", optional DOMString direction = "undefined", optional DOMString granularity = "undefined"); 71 undefined modify(optional DOMString alter, optional DOMString direction, optional DOMString granularity); 72 72 73 73 readonly attribute Node? baseNode; -
trunk/Source/WebCore/page/Settings.yaml
r267095 r267220 1073 1073 initial: false 1074 1074 1075 1076 1075 isPostLoadCPUUsageMeasurementEnabled: 1077 1076 initial: defaultPostLoadCPUUsageMeasurementEnabled … … 1088 1087 isPerActivityStateCPUUsageMeasurementEnabled: 1089 1088 initial: defaultPerActivityStateCPUUsageMeasurementEnabled 1089 1090 liveRangeSelectionEnabled: 1091 initial: false 1090 1092 1091 1093 # Deprecated -
trunk/Source/WebKit/ChangeLog
r267215 r267220 1 2020-09-16 Darin Adler <darin@apple.com> 2 3 Selection API: Introduce LiveRangeSelectionEnabled, off by default 4 https://bugs.webkit.org/show_bug.cgi?id=216656 5 6 Reviewed by Sam Weinig. 7 8 * Shared/WebPreferencesInternal.yaml: Added LiveRangeSelectionEnabled. 9 1 10 2020-09-17 Tim Horton <timothy_horton@apple.com> 2 11 -
trunk/Source/WebKit/Shared/WebPreferencesInternal.yaml
r267194 r267220 401 401 humanReadableDescription: "Do all media loading and playback in the GPU Process" 402 402 webcoreName: useGPUProcessForMedia 403 404 LiveRangeSelectionEnabled: 405 type: bool 406 defaultValue: false 407 humanReadableName: "Live Ranges in Selection" 408 humanReadableDescription: "Live range behavior for ranges in the Selection object" 409 category: internal
Note:
See TracChangeset
for help on using the changeset viewer.