Changeset 267329 in webkit
- Timestamp:
- Sep 20, 2020, 12:37:43 PM (6 years ago)
- Location:
- trunk
- Files:
-
- 8 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/editing/execCommand/insert-list-nested-with-orphaned-expected.txt (modified) (1 diff)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/editing/FrameSelection.cpp (modified) (2 diffs)
-
Source/WebCore/editing/FrameSelection.h (modified) (1 diff)
-
Source/WebCore/editing/VisibleSelection.cpp (modified) (16 diffs)
-
Source/WebCore/editing/VisibleSelection.h (modified) (6 diffs)
-
Source/WebCore/page/DOMSelection.cpp (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r267325 r267329 1 2020-09-20 Darin Adler <darin@apple.com> 2 3 Selection API: Further improvements to VisibleSelection, FrameSelection, and DOMSelection to preserve anchor and focus 4 https://bugs.webkit.org/show_bug.cgi?id=216739 5 6 Reviewed by Ryosuke Niwa. 7 8 * editing/execCommand/insert-list-nested-with-orphaned-expected.txt: This test 9 result reflected incorrrect behavior where the selection changed from a range 10 to a caret in a certain unusual case. The new behavior of leaving the text 11 selected is consistent with how the command works in normal cases, and was an 12 accidental progression from the improvements to the selection code. Was able 13 to reproduce this all in Safari and after experimenting with different 14 selections, it's clear this is an improvement. 15 1 16 2020-09-20 Zalan Bujtas <zalan@apple.com> 2 17 -
trunk/LayoutTests/editing/execCommand/insert-list-nested-with-orphaned-expected.txt
r66048 r267329 18 18 | <ol> 19 19 | <li> 20 | " <#selection-caret>because of you"20 | "because of you" 21 21 | " 22 22 " -
trunk/Source/WebCore/ChangeLog
r267328 r267329 1 2020-09-20 Darin Adler <darin@apple.com> 2 3 Selection API: Further improvements to VisibleSelection, FrameSelection, and DOMSelection to preserve anchor and focus 4 https://bugs.webkit.org/show_bug.cgi?id=216739 5 6 Reviewed by Ryosuke Niwa. 7 8 If done correctly, these changes should have almost no effect unless live range selection 9 is enabled. This adds a feature where VisibleSelection tracks the original points, 10 before the VisiblePosition-style canonicalization. It also starts a transition from 11 the base/extent terminology to the slightly-easier-to-understand anchor/focus terminology 12 that is used in the selection specification. New functions name them anchor and focus, 13 even though we still have some old ones that call them base and extent. In addition, 14 made some other small related improvements to live range selection mode, without changing 15 behavior when not in that mode. Have been testing these locally by turning on that mode 16 and running various tests. 17 18 * editing/FrameSelection.cpp: 19 (WebCore::FrameSelection::isInDocumentTree const): Added. Used by DOMSelection to 20 correctly handle cases where the selection is in a shadow tree without requiring it 21 actually create the associated live range just to query. 22 (WebCore::FrameSelection::associatedLiveRange): Use the new VisibleSelection::range, 23 which gives us non-canonicalized points, rather than the deprecated 24 VisibleSelection::firstRange, which we will eventually be renaming or deleting. 25 (WebCore::FrameSelection::updateFromAssociatedLiveRange): Use 26 makeContainerOffsetPosition instead of implicitly using makeDeprecatedLegacyPosition. 27 Also removed the FIXME about normalization of endpoints, which is what this patch 28 mostly addresses; no need to track with a comment now. 29 (WebCore::FrameSelection::updateAssociatedLiveRange): Use VisibleSelection::range 30 for the same reason as above. 31 32 * editing/FrameSelection.h: Added isInDocumentTree. 33 34 * editing/VisibleSelection.cpp: 35 (WebCore::VisibleSelection::VisibleSelection): Updated the primary constructor to set 36 m_anchor/focus and let the validate function set m_base/extent/start/end/baseIsFirst. 37 Changed most other constructors to call that primary one. 38 (WebCore::VisibleSelection::anchor const): Added. This is a non-canonicalized position. 39 (WebCore::VisibleSelection::focus const): Ditto. 40 (WebCore::VisibleSelection::uncanonicalizedStart const): Added. This non-canonicalized 41 version of start is used by new DOMSelection code, but eventually should be used 42 elsewhere as well, and we may eventually eliminate the canonicalized version. 43 (WebCore::VisibleSelection::uncanonicalizedEnd const): Ditto. 44 (WebCore::VisibleSelection::range const): Added. This non-canonicalized version of 45 firstRange has many of the same considerations as the other four functions above. 46 (WebCore::VisibleSelection::setBase): Set m_anchor instead of m_base. Eventually we 47 will want to rename this function, too, but there is no need to do that now. 48 (WebCore::VisibleSelection::setExtent): Ditto. 49 (WebCore::VisibleSelection::setBaseAndExtentToDeepEquivalents): Rewrote to take 50 m_anchor and m_focus as inputs and now m_base and m_extent are pure outputs. 51 May want to rename this later, because "deep equivalents" is a funny way to say 52 that this function sets base and extent to canonicalized values. 53 (WebCore::VisibleSelection::adjustSelectionRespectingGranularity): Renamed from 54 setStartAndEndFromBaseAndExtentRespectingGranularity. This now takes m_start/end 55 as input as well as output, because the validate function needs to check 56 if the function changes m_start/end so it can update m_anchor/focus. Also did a tiny 57 bit of refactoring to use std::swap. 58 (WebCore::VisibleSelection::validate): Refined the code to handle canonicalization 59 differently from expanding due to granularity. Canonicalization is done preserving 60 the original m_anchor/focus as it mostly always has been. But expansion due to 61 granularity now changes m_anchor/focus/base/extent rather than just m_start/end. 62 This makes sense because granularity changes actually affect what is selected, 63 while canonicalization just changes how the selection is expressed and tracked. 64 (WebCore::VisibleSelection::setWithoutValidation): Set m_anchor/focus. In the future, 65 we can probably get rid of this eventually, because the "validation" talked about 66 here is the unwanted canonicalization. But that's a refinement for the future. 67 (WebCore::VisibleSelection::adjustSelectionToAvoidCrossingShadowBoundaries): 68 Update m_focus, not just m_extent, if we have to adjust. Also removed an unnnecessary 69 null check from the start of the function. 70 (WebCore::VisibleSelection::adjustSelectionToAvoidCrossingEditingBoundaries): Ditto. 71 Also removed the assertions because these situations can indeed arise and it's not 72 necessarily an indication of a bug in editing code. 73 74 * editing/VisibleSelection.h: Rearranged constructors to make it slightly more clear 75 which is the main one and that the others are simply convenience shorthands. Might 76 want to come back later and remove some unused ones. Added uncanonicalizedStart, 77 uncanonicalizedEnd, anchor, focus, and range. Renamed the private function called 78 setStartAndEndFromBaseAndExtentRespectingGranularity to the new name 79 adjustSelectionRespectingGranularity. Added m_anchor and m_focus and refined the 80 comments about the position data members. We should eventually be able to cut down 81 on the number of these again, but it's fine to have two more for now. 82 83 * page/DOMSelection.cpp: 84 (WebCore::DOMSelection::range const): Use range rather than firstRange when live 85 range selection is enabled, for proper round-tripping of selection endpoints, 86 unaffected by canonicalization. The other changes below are for the same reason. 87 (WebCore::DOMSelection::anchorPosition const): Use anchor. 88 (WebCore::DOMSelection::focusPosition const): Use focus. 89 (WebCore::DOMSelection::basePosition const): Use anchor. 90 (WebCore::DOMSelection::extentPosition const): Use focus. 91 (WebCore::DOMSelection::type const): Use isInDocumentTree and range rather than 92 isNone/isCaret/isRange when live range selection is enabled, because this needs 93 to report "Caret" when the range is not collapsed, even if the canonicalized 94 range is collapsed and "None" when the selection is in a shadow tree. 95 (WebCore::DOMSelection::rangeCount const): Use isInDocumentTree to check if 96 there is a selection rather than isNone to correctly handle the shadow tree case. 97 (WebCore::DOMSelection::collapseToEnd): Use uncanonicalizedEnd. 98 (WebCore::DOMSelection::collapseToStart): Use uncanonicalizedStart. 99 (WebCore::DOMSelection::containsNode const): Updated the comment for clarity. 100 1 101 2020-09-20 Simon Fraser <simon.fraser@apple.com> 2 102 -
trunk/Source/WebCore/editing/FrameSelection.cpp
r267313 r267329 2787 2787 } 2788 2788 2789 bool FrameSelection::isInDocumentTree() const 2790 { 2791 return containsEndpoints(m_document, m_selection.range()); 2792 } 2793 2789 2794 RefPtr<Range> FrameSelection::associatedLiveRange() 2790 2795 { 2791 2796 if (!m_associatedLiveRange) { 2792 if (auto range = m_selection. firstRange(); containsEndpoints(m_document, range)) {2797 if (auto range = m_selection.range(); containsEndpoints(m_document, range)) { 2793 2798 m_associatedLiveRange = createLiveRange(*range); 2794 2799 m_associatedLiveRange->didAssociateWithSelection(); … … 2817 2822 if (!containsEndpoints(m_document, *m_associatedLiveRange)) 2818 2823 disassociateLiveRange(); 2819 else 2820 setSelection(makeSimpleRange(*m_associatedLiveRange)); 2821 // 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. 2824 else { 2825 // Don't use VisibleSelection's constructor that takes a SimpleRange, because it uses makeDeprecatedLegacyPosition instead of makeContainerOffsetPosition. 2826 auto start = makeContainerOffsetPosition(&m_associatedLiveRange->startContainer(), m_associatedLiveRange->startOffset()); 2827 auto end = makeContainerOffsetPosition(&m_associatedLiveRange->endContainer(), m_associatedLiveRange->endOffset()); 2828 setSelection({ start, end }); 2829 } 2822 2830 } 2823 2831 2824 2832 void FrameSelection::updateAssociatedLiveRange() 2825 2833 { 2826 auto range = m_selection. firstRange();2834 auto range = m_selection.range(); 2827 2835 if (!containsEndpoints(m_document, range)) { 2828 2836 // The selection was cleared or is now within a shadow tree. -
trunk/Source/WebCore/editing/FrameSelection.h
r267220 r267329 252 252 void setShouldShowBlockCursor(bool); 253 253 254 bool isInDocumentTree() const; 254 255 RefPtr<Range> associatedLiveRange(); 255 256 void associateLiveRange(Range&); -
trunk/Source/WebCore/editing/VisibleSelection.cpp
r266986 r267329 50 50 } 51 51 52 VisibleSelection::VisibleSelection(const Position& position, Affinity affinity, bool isDirectional)53 : m_ base(position)54 , m_ extent(position)52 VisibleSelection::VisibleSelection(const Position& anchor, const Position& focus, Affinity affinity, bool isDirectional) 53 : m_anchor(anchor) 54 , m_focus(focus) 55 55 , m_affinity(affinity) 56 56 , m_isDirectional(isDirectional) … … 59 59 } 60 60 61 VisibleSelection::VisibleSelection(const Position& base, const Position& extent, Affinity affinity, bool isDirectional) 62 : m_base(base) 63 , m_extent(extent) 64 , m_affinity(affinity) 65 , m_isDirectional(isDirectional) 66 { 67 validate(); 61 VisibleSelection::VisibleSelection(const Position& position, Affinity affinity, bool isDirectional) 62 : VisibleSelection(position, position, affinity, isDirectional) 63 { 68 64 } 69 65 70 66 VisibleSelection::VisibleSelection(const VisiblePosition& position, bool isDirectional) 71 : m_base(position.deepEquivalent()) 72 , m_extent(position.deepEquivalent()) 73 , m_affinity(position.affinity()) 74 , m_isDirectional(isDirectional) 75 { 76 validate(); 77 } 78 79 VisibleSelection::VisibleSelection(const VisiblePosition& base, const VisiblePosition& extent, bool isDirectional) 80 : m_base(base.deepEquivalent()) 81 , m_extent(extent.deepEquivalent()) 82 , m_affinity(base.affinity()) 83 , m_isDirectional(isDirectional) 84 { 85 validate(); 67 : VisibleSelection(position.deepEquivalent(), position.affinity(), isDirectional) 68 { 69 // FIXME: Wasteful that this re-canonicalizes, but risky to change since the VisiblePosition object could be from before a mutation and its position may no longer be canonical. 70 } 71 72 VisibleSelection::VisibleSelection(const VisiblePosition& anchor, const VisiblePosition& focus, bool isDirectional) 73 : VisibleSelection(anchor.deepEquivalent(), focus.deepEquivalent(), anchor.affinity(), isDirectional) 74 { 75 // FIXME: Wasteful that this re-canonicalizes, but risky to change since the VisiblePosition objects could be from before a mutation and their positions may no longer be canonical. 86 76 } 87 77 88 78 VisibleSelection::VisibleSelection(const SimpleRange& range, Affinity affinity, bool isDirectional) 89 : m_base(createLegacyEditingPosition(&range.startContainer(), range.startOffset())) 90 , m_extent(createLegacyEditingPosition(&range.endContainer(), range.endOffset())) 91 , m_affinity(affinity) 92 , m_isDirectional(isDirectional) 93 { 94 ASSERT(&range.startContainer().treeScope() == &range.endContainer().treeScope()); 95 validate(); 79 : VisibleSelection(makeDeprecatedLegacyPosition(range.start), makeDeprecatedLegacyPosition(range.end), affinity, isDirectional) 80 { 96 81 } 97 82 … … 102 87 } 103 88 89 Position VisibleSelection::anchor() const 90 { 91 return m_anchor; 92 } 93 94 Position VisibleSelection::focus() const 95 { 96 return m_focus; 97 } 98 99 Position VisibleSelection::uncanonicalizedStart() const 100 { 101 return m_baseIsFirst ? m_anchor : m_focus; 102 } 103 104 Position VisibleSelection::uncanonicalizedEnd() const 105 { 106 return m_baseIsFirst ? m_focus : m_anchor; 107 } 108 109 Optional<SimpleRange> VisibleSelection::range() const 110 { 111 return makeSimpleRange(uncanonicalizedStart().parentAnchoredEquivalent(), uncanonicalizedEnd().parentAnchoredEquivalent()); 112 } 113 104 114 void VisibleSelection::setBase(const Position& position) 105 115 { 106 m_ base= position;116 m_anchor = position; 107 117 validate(); 108 118 } … … 110 120 void VisibleSelection::setBase(const VisiblePosition& visiblePosition) 111 121 { 112 m_base = visiblePosition.deepEquivalent(); 122 setBase(visiblePosition.deepEquivalent()); 123 } 124 125 void VisibleSelection::setExtent(const Position& position) 126 { 127 m_focus = position; 113 128 validate(); 114 129 } 115 130 116 void VisibleSelection::setExtent(const Position& position)117 {118 m_extent = position;119 validate();120 }121 122 131 void VisibleSelection::setExtent(const VisiblePosition& visiblePosition) 123 132 { 124 m_extent = visiblePosition.deepEquivalent(); 125 validate(); 133 setExtent(visiblePosition.deepEquivalent()); 126 134 } 127 135 … … 211 219 void VisibleSelection::setBaseAndExtentToDeepEquivalents() 212 220 { 213 // Move the selection to rendered positions, if possible. 214 bool baseAndExtentEqual = m_base == m_extent; 215 if (m_base.isNotNull()) { 216 m_base = VisiblePosition(m_base, m_affinity).deepEquivalent(); 217 if (baseAndExtentEqual) 218 m_extent = m_base; 219 } 220 if (m_extent.isNotNull() && !baseAndExtentEqual) 221 m_extent = VisiblePosition(m_extent, m_affinity).deepEquivalent(); 222 223 // Make sure we do not have a dangling base or extent. 224 if (m_base.isNull() && m_extent.isNull()) 225 m_baseIsFirst = true; 226 else if (m_base.isNull()) { 227 m_base = m_extent; 228 m_baseIsFirst = true; 229 } else if (m_extent.isNull()) { 221 // If only one of anchor and focus is null, convert to a caret selection. 222 // FIXME: Seems like a better rule would be to convert to no selection. 223 if (m_anchor.isNull()) 224 m_anchor = m_focus; 225 if (m_focus.isNull()) 226 m_focus = m_anchor; 227 228 m_base = VisiblePosition(m_anchor, m_affinity).deepEquivalent(); 229 if (m_anchor == m_focus) 230 230 m_extent = m_base; 231 m_baseIsFirst = true; 232 } else 233 m_baseIsFirst = m_base <= m_extent; 234 } 235 236 void VisibleSelection::setStartAndEndFromBaseAndExtentRespectingGranularity(TextGranularity granularity) 237 { 238 if (m_baseIsFirst) { 239 m_start = m_base; 240 m_end = m_extent; 241 } else { 242 m_start = m_extent; 243 m_end = m_base; 244 } 245 231 else 232 m_extent = VisiblePosition(m_focus, m_affinity).deepEquivalent(); 233 234 m_baseIsFirst = m_base <= m_extent; 235 } 236 237 void VisibleSelection::adjustSelectionRespectingGranularity(TextGranularity granularity) 238 { 246 239 switch (granularity) { 247 240 case TextGranularity::CharacterGranularity: … … 287 280 288 281 m_end = end.deepEquivalent(); 282 289 283 // End must not be before start. 290 if (m_start.deprecatedNode() == m_end.deprecatedNode() && m_start.deprecatedEditingOffset() > m_end.deprecatedEditingOffset()) { 291 Position swap(m_start); 292 m_start = m_end; 293 m_end = swap; 294 } 284 if (m_start.deprecatedNode() == m_end.deprecatedNode() && m_start.deprecatedEditingOffset() > m_end.deprecatedEditingOffset()) 285 std::swap(m_start, m_end); 295 286 break; 296 287 } 297 case TextGranularity::SentenceGranularity: {288 case TextGranularity::SentenceGranularity: 298 289 m_start = startOfSentence(VisiblePosition(m_start, m_affinity)).deepEquivalent(); 299 290 m_end = endOfSentence(VisiblePosition(m_end, m_affinity)).deepEquivalent(); 300 291 break; 301 }302 292 case TextGranularity::LineGranularity: { 303 293 m_start = startOfLine(VisiblePosition(m_start, m_affinity)).deepEquivalent(); … … 385 375 { 386 376 setBaseAndExtentToDeepEquivalents(); 387 setStartAndEndFromBaseAndExtentRespectingGranularity(granularity); 377 378 m_start = m_baseIsFirst ? m_base : m_extent; 379 m_end = m_baseIsFirst ? m_extent : m_base; 380 381 auto startBeforeAdjustments = m_start; 382 auto endBeforeAdjustments = m_end; 383 384 adjustSelectionRespectingGranularity(granularity); 388 385 adjustSelectionToAvoidCrossingShadowBoundaries(); 389 386 adjustSelectionToAvoidCrossingEditingBoundaries(); 390 387 updateSelectionType(); 388 389 bool shouldUpdateAnchor = m_start != startBeforeAdjustments; 390 bool shouldUpdateFocus = m_end != endBeforeAdjustments; 391 391 392 392 if (isRange()) { … … 395 395 // useful to make to make the selection "canonical" (if only for 396 396 // purposes of comparing selections). This is an ideal point of the code 397 // to do this operation, since all selection changes that result in a RANGE 397 // to do this operation, since all selection changes that result in a RANGE 398 398 // come through here before anyone uses it. 399 399 // FIXME: Canonicalizing is good, but haven't we already done it (when we … … 402 402 m_end = m_end.upstream(); 403 403 404 // FIXME: Position::downstream() or Position::upStream() might violate editing boundaries 405 // if an anchor node has a Shadow DOM. So we adjust selection to avoid crossing editing 406 // boundaries again. See https://bugs.webkit.org/show_bug.cgi?id=87463 404 // Position::downstream() or Position::upstream() might violate editing boundaries 405 // if an anchor node has a Shadow DOM even though they should not. But because this 406 // happens in practice, adjust selection to avoid crossing editing boundaries again. 407 // See https://bugs.webkit.org/show_bug.cgi?id=87463. 407 408 adjustSelectionToAvoidCrossingEditingBoundaries(); 409 } 410 411 if (shouldUpdateAnchor) { 412 m_anchor = m_baseIsFirst ? m_start : m_end; 413 m_base = m_anchor; 414 } 415 if (shouldUpdateFocus) { 416 m_focus = m_baseIsFirst ? m_end : m_start; 417 m_extent = m_focus; 408 418 } 409 419 } … … 417 427 void VisibleSelection::setWithoutValidation(const Position& base, const Position& extent) 418 428 { 419 ASSERT(!base.isNull()); 420 ASSERT(!extent.isNull()); 429 ASSERT(base.isNull() == extent.isNull()); 421 430 ASSERT(m_affinity == Affinity::Downstream); 431 m_anchor = base; 432 m_focus = extent; 422 433 m_base = base; 423 434 m_extent = extent; … … 487 498 void VisibleSelection::adjustSelectionToAvoidCrossingShadowBoundaries() 488 499 { 489 if (m_ base.isNull() || m_start.isNull() || m_end.isNull())500 if (m_start.isNull() || m_end.isNull()) 490 501 return; 491 502 … … 501 512 } 502 513 514 // Correct the focus if necessary. 503 515 if (m_baseIsFirst) { 504 516 m_extent = adjustPositionForEnd(m_end, m_start.containerNode()); … … 508 520 m_start = m_extent; 509 521 } 522 m_focus = m_extent; 510 523 } 511 524 512 525 void VisibleSelection::adjustSelectionToAvoidCrossingEditingBoundaries() 513 526 { 514 if (m_ base.isNull() || m_start.isNull() || m_end.isNull())527 if (m_start.isNull() || m_end.isNull()) 515 528 return; 516 529 … … 576 589 577 590 if (previous.isNull()) { 578 // The selection crosses an Editing boundary. This is a 579 // programmer error in the editing code. Happy debugging! 580 ASSERT_NOT_REACHED(); 581 m_base = Position(); 582 m_extent = Position(); 583 validate(); 591 *this = { }; 584 592 return; 585 593 } … … 605 613 606 614 if (next.isNull()) { 607 // The selection crosses an Editing boundary. This is a 608 // programmer error in the editing code. Happy debugging! 609 ASSERT_NOT_REACHED(); 610 m_base = Position(); 611 m_extent = Position(); 612 validate(); 615 *this = { }; 613 616 return; 614 617 } … … 617 620 } 618 621 619 // Correct the extentif necessary.620 if (baseEditableAncestor != lowestEditableAncestor(m_extent.containerNode())) 622 // Correct the focus if necessary. 623 if (baseEditableAncestor != lowestEditableAncestor(m_extent.containerNode())) { 621 624 m_extent = m_baseIsFirst ? m_end : m_start; 625 m_focus = m_extent; 626 } 622 627 } 623 628 -
trunk/Source/WebCore/editing/VisibleSelection.h
r266986 r267329 40 40 static constexpr auto defaultAffinity = VisiblePosition::defaultAffinity; 41 41 42 VisibleSelection(const Position& anchor, const Position& focus, Affinity = defaultAffinity, bool isDirectional = false); 43 42 44 VisibleSelection(const Position&, Affinity, bool isDirectional = false); 43 VisibleSelection(const Position&, const Position&, Affinity = defaultAffinity, bool isDirectional = false);44 45 WEBCORE_EXPORT VisibleSelection(const SimpleRange&, Affinity = defaultAffinity, bool isDirectional = false); 45 46 WEBCORE_EXPORT VisibleSelection(const VisiblePosition&, bool isDirectional = false); 46 WEBCORE_EXPORT VisibleSelection(const VisiblePosition& , const VisiblePosition&, bool isDirectional = false);47 WEBCORE_EXPORT VisibleSelection(const VisiblePosition& anchor, const VisiblePosition& focus, bool isDirectional = false); 47 48 48 49 WEBCORE_EXPORT static VisibleSelection selectionFromContentsOfNode(Node*); … … 51 52 Affinity affinity() const { return m_affinity; } 52 53 54 // FIXME: Move to the terms "focus" and "anchor" instead of "base" and "extent". 55 53 56 void setBase(const Position&); 54 57 void setBase(const VisiblePosition&); … … 56 59 void setExtent(const VisiblePosition&); 57 60 61 // These functions return the values that were passed in, without the canonicalization done by VisiblePosition. 62 // FIXME: When we expand granularity, we canonicalize as a side effect, so expanded values have been made canonical. 63 // FIXME: Replace start/range/base/end/firstRange with these, renaming these to the shorter names. 64 Position uncanonicalizedStart() const; 65 Position uncanonicalizedEnd() const; 66 Position anchor() const; 67 Position focus() const; 68 WEBCORE_EXPORT Optional<SimpleRange> range() const; 69 70 // FIXME: Rename these to include the word "canonical" or remove. 58 71 Position base() const { return m_base; } 59 72 Position extent() const { return m_extent; } 60 73 Position start() const { return m_start; } 61 74 Position end() const { return m_end; } 62 75 63 76 VisiblePosition visibleStart() const { return VisiblePosition(m_start, isRange() ? Affinity::Downstream : affinity()); } 64 77 VisiblePosition visibleEnd() const { return VisiblePosition(m_end, isRange() ? Affinity::Upstream : affinity()); } … … 85 98 WEBCORE_EXPORT bool expandUsingGranularity(TextGranularity granularity); 86 99 100 // FIXME: Rename to include the word "canonical" and remove the word "first" or remove. 87 101 // We don't yet support multi-range selections, so we only ever have one range to return. 88 102 WEBCORE_EXPORT Optional<SimpleRange> firstRange() const; 89 103 90 // FIXME: Most callers probably don't want this function, and should use firstRange instead.91 // toNormalizedRange is like firstRange, butcontracts the range around text and moves the caret upstream before returning the range.104 // FIXME: Most callers probably don't want this function, and should use range instead. 105 // This function contracts the range around text and moves the caret upstream before returning the range. 92 106 WEBCORE_EXPORT Optional<SimpleRange> toNormalizedRange() const; 93 107 … … 96 110 WEBCORE_EXPORT bool hasEditableStyle() const; 97 111 WEBCORE_EXPORT bool isContentRichlyEditable() const; 112 98 113 // Returns a shadow tree node for legacy shadow trees, a child of the 99 114 // ShadowRoot node for new shadow trees, or 0 for non-shadow trees. … … 118 133 // Support methods for validate() 119 134 void setBaseAndExtentToDeepEquivalents(); 120 void setStartAndEndFromBaseAndExtentRespectingGranularity(TextGranularity);135 void adjustSelectionRespectingGranularity(TextGranularity); 121 136 void adjustSelectionToAvoidCrossingShadowBoundaries(); 122 137 void adjustSelectionToAvoidCrossingEditingBoundaries(); 123 138 void updateSelectionType(); 124 139 125 // We store these asPositions because VisibleSelection is used to store values in140 // We store only Positions because VisibleSelection is used to store values in 126 141 // editing commands for use when undoing the command. We need to be able to store 127 142 // a selection that, while currently invalid, will be valid once the changes are undone. 128 143 129 Position m_base; // Where the first click happened. 130 Position m_extent; // Where the end click happened. 131 132 Position m_start; // Leftmost position when expanded to respect granularity. 133 Position m_end; // Rightmost position when expanded to respect granularity. 144 // FIXME: Consider doing canonicalization only as part of editing operations, and keeping all selection endpoints non-canonical outside of that code. 145 // FIXME: Rename m_base to m_canonicalAnchor. 146 // FIXME: Rename m_extent to m_canonicalFocus. 147 Position m_anchor; // Where the first click happened. 148 Position m_focus; // Where the end click/release happened. 149 Position m_base; // Anchor, canonical, not yet expended to respect granularity. 150 Position m_extent; // Focus, canonical, but not expended to respect granularity. 151 Position m_start; // First of anchor and focus, caonicalized and expanded to respect granularity. 152 Position m_end; // Last of anchor and focus, caonicalized and expanded to respect granularity. 134 153 135 154 Affinity m_affinity { defaultAffinity }; -
trunk/Source/WebCore/page/DOMSelection.cpp
r267327 r267329 70 70 if (!frame) 71 71 return WTF::nullopt; 72 auto range = frame->selection().selection().firstRange(); 72 auto range = frame->settings().liveRangeSelectionEnabled() 73 ? frame->selection().selection().range() 74 : frame->selection().selection().firstRange(); 73 75 if (!range || range->start.container->isInShadowTree()) 74 76 return WTF::nullopt; … … 81 83 if (!frame) 82 84 return { }; 85 if (frame->settings().liveRangeSelectionEnabled()) 86 return frame->selection().selection().anchor().parentAnchoredEquivalent(); 83 87 auto& selection = frame->selection().selection(); 84 88 return (selection.isBaseFirst() ? selection.start() : selection.end()).parentAnchoredEquivalent(); … … 90 94 if (!frame) 91 95 return { }; 96 if (frame->settings().liveRangeSelectionEnabled()) 97 return frame->selection().selection().focus().parentAnchoredEquivalent(); 92 98 auto& selection = frame->selection().selection(); 93 99 return (selection.isBaseFirst() ? selection.end() : selection.start()).parentAnchoredEquivalent(); … … 96 102 Position DOMSelection::basePosition() const 97 103 { 98 auto frame = this->frame(); 99 if (!frame) 100 return { }; 104 // FIXME: Remove this once liveRangeSelectionEnabled is always on, since base and anchor should be the same thing. 105 auto frame = this->frame(); 106 if (!frame) 107 return { }; 108 if (frame->settings().liveRangeSelectionEnabled()) 109 return frame->selection().selection().anchor().parentAnchoredEquivalent(); 101 110 return frame->selection().selection().base().parentAnchoredEquivalent(); 102 111 } … … 104 113 Position DOMSelection::extentPosition() const 105 114 { 106 auto frame = this->frame(); 107 if (!frame) 108 return { }; 115 // FIXME: Remove this once liveRangeSelectionEnabled is always on, since extent and focus should be the same thing. 116 auto frame = this->frame(); 117 if (!frame) 118 return { }; 119 if (frame->settings().liveRangeSelectionEnabled()) 120 return frame->selection().selection().focus().parentAnchoredEquivalent(); 109 121 return frame->selection().selection().extent().parentAnchoredEquivalent(); 110 122 } … … 165 177 return "None"_s; 166 178 auto& selection = frame->selection(); 179 if (frame->settings().liveRangeSelectionEnabled()) 180 return !selection.isInDocumentTree() ? "None"_s : range()->collapsed() ? "Caret"_s : "Range"_s; 167 181 if (selection.isNone()) 168 182 return "None"_s; … … 175 189 { 176 190 auto frame = this->frame(); 191 if (frame->settings().liveRangeSelectionEnabled()) 192 return frame && frame->selection().isInDocumentTree(); 177 193 return !frame || frame->selection().isNone() ? 0 : 1; 178 194 } … … 211 227 if (selection.isNone()) 212 228 return Exception { InvalidStateError }; 213 selection.disassociateLiveRange(); 214 selection.moveTo(selection.selection().end(), Affinity::Downstream); 229 if (frame->settings().liveRangeSelectionEnabled()) { 230 selection.disassociateLiveRange(); 231 selection.moveTo(selection.selection().uncanonicalizedEnd(), Affinity::Downstream); 232 } else 233 selection.moveTo(selection.selection().end(), Affinity::Downstream); 215 234 return { }; 216 235 } … … 224 243 if (selection.isNone()) 225 244 return Exception { InvalidStateError }; 226 selection.disassociateLiveRange(); 227 selection.moveTo(selection.selection().start(), Affinity::Downstream); 245 if (frame->settings().liveRangeSelectionEnabled()) { 246 selection.disassociateLiveRange(); 247 selection.moveTo(selection.selection().uncanonicalizedStart(), Affinity::Downstream); 248 } else 249 selection.moveTo(selection.selection().start(), Affinity::Downstream); 228 250 return { }; 229 251 } … … 406 428 bool DOMSelection::containsNode(Node& node, bool allowPartial) const 407 429 { 408 // FIXME: Th is is wrong, and was added to work around anomalies caused when we canonicalize selection endpoints. We should fix that and remove this.430 // FIXME: The rule implemented here for text nodes is wrong, and was added to work around anomalies caused when we canonicalize selection endpoints. 409 431 if (node.isTextNode() && !node.document().settings().liveRangeSelectionEnabled()) 410 432 allowPartial = true;
Note:
See TracChangeset
for help on using the changeset viewer.