Source/WebCore/ChangeLog

 12020-09-12 Darin Adler <darin@apple.com>
 2
 3 Make Selection throw same errors as other browsers and return same Range object from getRangeAt like other browsers
 4 https://bugs.webkit.org/show_bug.cgi?id=216325
 5
162020-09-13 Sam Weinig <weinig@apple.com>
27
38 [WebIDL] Remove need for [MayThrowException] on constructors and legacy factory functions

Source/WebCore/dom/Document.h

@@public:
15911591 void canvasResized(CanvasBase&) final { };
15921592 void canvasDestroyed(CanvasBase&) final;
15931593
 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
15941597protected:
15951598 enum ConstructionFlags { Synthesized = 1, NonRenderedPlaceholder = 1 << 1 };
15961599 WEBCORE_EXPORT Document(Frame*, const URL&, DocumentClassFlags = DefaultDocumentClass, unsigned constructionFlags = 0);

Source/WebCore/dom/Node.cpp

22 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
33 * (C) 1999 Antti Koivisto (koivisto@kde.org)
44 * (C) 2001 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
 5 * Copyright (C) 2004-2020 Apple Inc. All rights reserved.
66 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
77 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
88 *

@@ExceptionOr<void> Node::checkSetPrefix(const AtomString& prefix)
10211021
10221022bool Node::isDescendantOf(const Node& other) const
10231023{
1024  // Return true if other is an ancestor of this, otherwise false
 1024 // Return true if other is an ancestor of this.
 1025 if (other.isDocumentNode())
 1026 return &treeScope().rootNode() == &other && !isDocumentNode() && isConnected();
10251027 if (!other.hasChildNodes() || isConnected() != other.isConnected())
10261028 return false;
1027  if (other.isDocumentNode())
1028  return &document() == &other && !isDocumentNode() && isConnected();
1029  for (const auto* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
 1029 for (auto ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
10301030 if (ancestor == &other)
10311031 return true;
10321032 }

@@bool Node::isDescendantOf(const Node& other) const
10351035
10361036bool Node::isDescendantOrShadowDescendantOf(const Node* other) const
10371037{
1038  // FIXME: This element's shadow tree's host could be inside another shadow tree.
1039  // This function doesn't handle that case correctly. Maybe share code with
1040  // the containsIncludingShadowDOM function?
 1038 // FIXME: Correctly handle the case where the shadow host is itself in a shadow tree.
10411039 return other && (isDescendantOf(*other) || other->contains(shadowHost()));
10421040}
10431041
1044 bool Node::contains(const Node* node) const
 1042bool Node::contains(const Node& node) const
10451043{
1046  return this == node || (node && node->isDescendantOf(*this));
 1044 return this == &node || node.isDescendantOf(*this);
10471045}
10481046
10491047bool Node::containsIncludingShadowDOM(const Node* node) const

Source/WebCore/dom/Node.h

22 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
33 * (C) 1999 Antti Koivisto (koivisto@kde.org)
44 * (C) 2001 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
 5 * Copyright (C) 2004-2020 Apple Inc. All rights reserved.
66 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
77 *
88 * This library is free software; you can redistribute it and/or

@@public:
371371
372372 WEBCORE_EXPORT bool isDescendantOf(const Node&) const;
373373 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); }
374376
375377 bool isDescendantOrShadowDescendantOf(const Node*) const;
376  WEBCORE_EXPORT bool contains(const Node*) const;
377378 WEBCORE_EXPORT bool containsIncludingShadowDOM(const Node*) const;
378379
379380 // Whether or not a selection can be started in this object

Source/WebCore/dom/Range.cpp

33 * (C) 2000 Gunnstein Lye (gunnstein@netcom.no)
44 * (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
55 * (C) 2001 Peter Kelly (pmk@post.com)
6  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
 6 * Copyright (C) 2004-2020 Apple Inc. All rights reserved.
77 * Copyright (C) 2011 Motorola Mobility. All rights reserved.
88 *
99 * This library is free software; you can redistribute it and/or

2929#include "DOMRect.h"
3030#include "DOMRectList.h"
3131#include "DocumentFragment.h"
32 #include "Editing.h"
3332#include "Event.h"
3433#include "Frame.h"
 34#include "FrameSelection.h"
3535#include "FrameView.h"
3636#include "GeometryUtilities.h"
3737#include "HTMLBodyElement.h"
38 #include "HTMLElement.h"
3938#include "HTMLHtmlElement.h"
4039#include "HTMLNames.h"
4140#include "NodeTraversal.h"
4241#include "NodeWithIndex.h"
4342#include "ProcessingInstruction.h"
44 #include "RenderBlock.h"
45 #include "RenderBoxModelObject.h"
46 #include "RenderText.h"
47 #include "RenderView.h"
4843#include "ScopedEventQueue.h"
4944#include "TextIterator.h"
50 #include "VisiblePosition.h"
5145#include "VisibleUnits.h"
5246#include "markup.h"
5347#include <stdio.h>

5549#include <wtf/text/CString.h>
5650#include <wtf/text/StringBuilder.h>
5751
58 #if PLATFORM(IOS_FAMILY)
59 #include "SelectionRect.h"
60 #endif
61 
6252namespace WebCore {
6353
6454using namespace HTMLNames;

@@Ref<Range> Range::create(Document& ownerDocument)
9080
9181Range::~Range()
9282{
 83 ASSERT(!m_isAssociatedWithSelection);
 84
9385 m_ownerDocument->detachRange(*this);
9486
9587#ifndef NDEBUG

@@void Range::updateDocument()
10294 auto& document = startContainer().document();
10395 if (m_ownerDocument.ptr() == &document)
10496 return;
 97 if (m_isAssociatedWithSelection) {
 98 m_ownerDocument->selection().clear();
 99 m_isAssociatedWithSelection = false;
 100 }
105101 m_ownerDocument->detachRange(*this);
106102 m_ownerDocument = document;
107103 m_ownerDocument->attachRange(*this);
108104}
109105
 106void Range::updateAssociatedSelection()
 107{
 108 if (m_isAssociatedWithSelection)
 109 m_ownerDocument->selection().updateFromAssociatedLiveRange();
 110}
 111
110112ExceptionOr<void> Range::setStart(Ref<Node>&& container, unsigned offset)
111113{
112114 auto childNode = checkNodeOffsetPair(container, offset);

@@ExceptionOr<void> Range::setStart(Ref<Node>&& container, unsigned offset)
117119 if (!is_lteq(documentOrder(makeBoundaryPoint(m_start), makeBoundaryPoint(m_end))))
118120 m_end = m_start;
119121 updateDocument();
 122 updateAssociatedSelection();
120123 return { };
121124}
122125

@@ExceptionOr<void> Range::setEnd(Ref<Node>&& container, unsigned offset)
130133 if (!is_lteq(documentOrder(makeBoundaryPoint(m_start), makeBoundaryPoint(m_end))))
131134 m_start = m_end;
132135 updateDocument();
 136 updateAssociatedSelection();
133137 return { };
134138}
135139

@@void Range::collapse(bool toStart)
139143 m_end = m_start;
140144 else
141145 m_start = m_end;
 146 updateAssociatedSelection();
142147}
143148
144149ExceptionOr<bool> Range::isPointInRange(Node& container, unsigned offset)

@@ExceptionOr<RefPtr<DocumentFragment>> Range::processContents(ActionType action)
368373 if (result.hasException())
369374 return result.releaseException();
370375 }
371  m_end = m_start;
 376 collapse(true);
372377 }
373378
374379 // Now add leftContents, stuff in between, and rightContents to the fragment

@@ExceptionOr<void> Range::selectNodeContents(Node& node)
771776{
772777 if (node.isDocumentTypeNode())
773778 return Exception { InvalidNodeTypeError };
774 
775779 m_start.setToBeforeContents(node);
776780 m_end.setToAfterContents(node);
 781 updateDocument();
 782 updateAssociatedSelection();
777783 return { };
778784}
779785

@@Optional<SimpleRange> makeSimpleRange(const RefPtr<Range>& range)
10571063Ref<Range> createLiveRange(const SimpleRange& range)
10581064{
10591065 auto result = Range::create(range.start.document());
 1066 result.get() = range;
 1067 return result;
 1068}
 1069
 1070Range& Range::operator=(const SimpleRange& range)
 1071{
10601072 auto startContainer = range.start.container;
1061  result->setStart(WTFMove(startContainer), range.start.offset);
 1073 setStart(WTFMove(startContainer), range.start.offset);
10621074 auto endContainer = range.end.container;
1063  result->setEnd(WTFMove(endContainer), range.end.offset);
1064  return result;
 1075 setEnd(WTFMove(endContainer), range.end.offset);
 1076 return *this;
10651077}
10661078
10671079RefPtr<Range> createLiveRange(const Optional<SimpleRange>& range)

Source/WebCore/dom/Range.h

@@public:
9999 void textNodesMerged(NodeWithIndex& oldNode, unsigned offset);
100100 void textNodeSplit(Text& oldNode);
101101
 102 void wasAssociatedWithSelection() { m_isAssociatedWithSelection = true; }
 103 void wasDisassociatedFromSelection() { m_isAssociatedWithSelection = false; }
 104
102105#if ENABLE(TREE_DEBUGGING)
103106 String debugDescription() const;
104107#endif
105108
106109 enum ActionType : uint8_t { Delete, Extract, Clone };
107110
 111 Range& operator=(const SimpleRange&);
 112
108113private:
109114 explicit Range(Document&);
110115
111116 void updateDocument();
 117 void updateAssociatedSelection();
112118 ExceptionOr<Node*> checkNodeOffsetPair(Node&, unsigned offset) const;
113119 ExceptionOr<RefPtr<DocumentFragment>> processContents(ActionType);
114120
115121 Ref<Document> m_ownerDocument;
116122 RangeBoundaryPoint m_start;
117123 RangeBoundaryPoint m_end;
 124 bool m_isAssociatedWithSelection { false };
118125};
119126
120127WEBCORE_EXPORT SimpleRange makeSimpleRange(const Range&);

Source/WebCore/editing/FrameSelection.cpp

11/*
2  * Copyright (C) 2004, 2008, 2009, 2010, 2014-2015 Apple Inc. All rights reserved.
 2 * Copyright (C) 2004-2020 Apple Inc. All rights reserved.
33 *
44 * Redistribution and use in source and binary forms, with or without
55 * modification, are permitted provided that the following conditions

@@void FrameSelection::setSelectionByMouseIfDifferent(const VisibleSelection& pass
314314 newSelection.setIsDirectional(isDirectional); // Adjusting base and extent will make newSelection always directional
315315 if (m_selection == newSelection || !shouldChangeSelection(newSelection))
316316 return;
317 
318317
319318 AXTextStateChangeIntent intent;
320319 if (AXObjectCache::accessibilityEnabled() && newSelection.isCaret())

@@bool FrameSelection::setSelectionWithoutUpdatingAppearance(const VisibleSelectio
335334
336335 if (!m_document || !m_document->frame()) {
337336 m_selection = newSelection;
 337 updateAssociatedLiveRange();
338338 return false;
339339 }
340340

@@bool FrameSelection::setSelectionWithoutUpdatingAppearance(const VisibleSelectio
368368 m_document->editor().selectionWillChange();
369369
370370 m_selection = newSelection;
 371 updateAssociatedLiveRange();
371372
372373 // Selection offsets should increase when LF is inserted before the caret in InsertLineBreakCommand. See <https://webkit.org/b/56061>.
373374 if (HTMLTextFormControlElement* textControl = enclosingTextFormControl(newSelection.start()))

@@void FrameSelection::setCaretColor(const Color& caretColor)
27762777 invalidateCaretRect();
27772778 }
27782779}
 2780
27792781#endif // PLATFORM(IOS_FAMILY)
27802782
 2783static bool isRootNode(Document* document, const Optional<SimpleRange>& range)
 2784{
 2785 return document && range && document->contains(range->start.container) && document->contains(range->end.container);
 2786}
 2787
 2788static bool isRootNode(Document* document, const Range& liveRange)
 2789{
 2790 // Only need to check the start container because live ranges enforce the invariant that start and end have a common ancestor.
 2791 return document && document->contains(liveRange.startContainer());
 2792}
 2793
 2794RefPtr<Range> FrameSelection::associatedLiveRange()
 2795{
 2796 if (!m_associatedLiveRange) {
 2797 if (auto range = m_selection.firstRange(); isRootNode(m_document, range)) {
 2798 m_associatedLiveRange = createLiveRange(*range);
 2799 m_associatedLiveRange->wasAssociatedWithSelection();
 2800 }
 2801 }
 2802 return m_associatedLiveRange;
 2803}
 2804
 2805void FrameSelection::disassociateLiveRange()
 2806{
 2807 if (auto previouslyAssociatedLiveRange = std::exchange(m_associatedLiveRange, nullptr))
 2808 previouslyAssociatedLiveRange->wasDisassociatedFromSelection();
 2809}
 2810
 2811void FrameSelection::associateLiveRange(Range& liveRange)
 2812{
 2813 disassociateLiveRange();
 2814 m_associatedLiveRange = &liveRange;
 2815 liveRange.wasAssociatedWithSelection();
 2816 updateFromAssociatedLiveRange();
 2817}
 2818
 2819void FrameSelection::updateFromAssociatedLiveRange()
 2820{
 2821 ASSERT(m_associatedLiveRange);
 2822 if (!isRootNode(m_document, *m_associatedLiveRange))
 2823 disassociateLiveRange();
 2824 else
 2825 setSelection(makeSimpleRange(*m_associatedLiveRange));
 2826 // 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.
 2827}
 2828
 2829void FrameSelection::updateAssociatedLiveRange()
 2830{
 2831 auto range = m_selection.firstRange();
 2832 if (!isRootNode(m_document, range))
 2833 disassociateLiveRange();
 2834 else if (m_associatedLiveRange) {
 2835 // Tell the live range it's not associated while modifying it so it doesn't call updateFromAssociatedLiveRange.
 2836 m_associatedLiveRange->wasDisassociatedFromSelection();
 2837 *m_associatedLiveRange = *range;
 2838 m_associatedLiveRange->wasAssociatedWithSelection();
 2839 }
 2840}
 2841
27812842}
27822843
27832844#if ENABLE(TREE_DEBUGGING)
27842845
2785 void showTree(const WebCore::FrameSelection& sel)
 2846void showTree(const WebCore::FrameSelection& selection)
27862847{
2787  sel.showTreeForThis();
 2848 selection.showTreeForThis();
27882849}
27892850
2790 void showTree(const WebCore::FrameSelection* sel)
 2851void showTree(const WebCore::FrameSelection* selection)
27912852{
2792  if (sel)
2793  sel->showTreeForThis();
 2853 if (selection)
 2854 selection->showTreeForThis();
27942855}
27952856
27962857#endif

Source/WebCore/editing/FrameSelection.h

11/*
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.
33 *
44 * Redistribution and use in source and binary forms, with or without
55 * modification, are permitted provided that the following conditions

@@public:
271271 bool shouldShowBlockCursor() const { return m_shouldShowBlockCursor; }
272272 void setShouldShowBlockCursor(bool);
273273
 274 RefPtr<Range> associatedLiveRange();
 275 void associateLiveRange(Range&);
 276 void disassociateLiveRange();
 277 void updateFromAssociatedLiveRange();
 278
274279private:
275280 enum EPositionType { START, END, BASE, EXTENT };
276281

@@private:
328333 Optional<SimpleRange> rangeByAlteringCurrentSelection(EAlteration, int amount) const;
329334#endif
330335
331  Document* m_document;
 336 void updateAssociatedLiveRange();
 337
 338 Document* m_document { nullptr };
 339 RefPtr<Range> m_associatedLiveRange;
332340
333341 LayoutUnit m_xPosForVerticalArrowNavigation;
334342

Source/WebCore/page/DOMSelection.cpp

11/*
2  * Copyright (C) 2007, 2009, 2016 Apple Inc. All rights reserved.
 2 * Copyright (C) 2007-2020 Apple Inc. All rights reserved.
33 * Copyright (C) 2012 Google Inc. All rights reserved.
44 *
55 * Redistribution and use in source and binary forms, with or without

3939
4040namespace WebCore {
4141
 42static bool shouldUseSelectionAssociatedRange()
 43{
 44 // FIXME: This will be controlled by a feature flag during development, I guess.
 45 return false;
 46}
 47
4248static Node* selectionShadowAncestor(Frame& frame)
4349{
4450 auto* node = frame.selection().selection().base().anchorNode();

@@unsigned DOMSelection::rangeCount() const
166172 return !frame || frame->selection().isNone() ? 0 : 1;
167173}
168174
169 void DOMSelection::collapse(Node* node, unsigned offset)
 175ExceptionOr<void> DOMSelection::collapse(Node* node, unsigned offset)
170176{
171  if (!isValidForPosition(node))
172  return;
173 
174  Ref<Frame> protectedFrame(*frame());
175  protectedFrame->selection().moveTo(createLegacyEditingPosition(node, offset), Affinity::Downstream);
 177 auto frame = makeRefPtr(this->frame());
 178 if (!frame)
 179 return { };
 180 if (shouldUseSelectionAssociatedRange()) {
 181 if (!node) {
 182 removeAllRanges();
 183 return { };
 184 }
 185 // FIXME: The Selection API specification does not mention this, but Web Platform Tests results expect it.
 186 if (node->isDocumentTypeNode())
 187 return Exception { InvalidNodeTypeError };
 188 // FIXME: The Selection API specification requires this exception, but it may be incompatible in practice.
 189 if (offset > node->length())
 190 return Exception { IndexSizeError };
 191 if (!frame->document()->contains(*node))
 192 return { };
 193 } else {
 194 if (!isValidForPosition(node))
 195 return { };
 196 }
 197 auto& selection = frame->selection();
 198 selection.disassociateLiveRange();
 199 selection.moveTo(createLegacyEditingPosition(node, offset), Affinity::Downstream);
 200 return { };
176201}
177202
178203ExceptionOr<void> DOMSelection::collapseToEnd()
179204{
180  auto* frame = this->frame();
 205 auto frame = makeRefPtr(this->frame());
181206 if (!frame)
182207 return { };
183208 auto& selection = frame->selection();
184209 if (selection.isNone())
185210 return Exception { InvalidStateError };
186 
187  Ref<Frame> protector(*frame);
 211 selection.disassociateLiveRange();
188212 selection.moveTo(selection.selection().end(), Affinity::Downstream);
189213 return { };
190214}
191215
192216ExceptionOr<void> DOMSelection::collapseToStart()
193217{
194  auto* frame = this->frame();
 218 auto frame = makeRefPtr(this->frame());
195219 if (!frame)
196220 return { };
197221 auto& selection = frame->selection();
198222 if (selection.isNone())
199223 return Exception { InvalidStateError };
200 
201  Ref<Frame> protector(*frame);
 224 selection.disassociateLiveRange();
202225 selection.moveTo(selection.selection().start(), Affinity::Downstream);
203226 return { };
204227}
205228
206229void DOMSelection::empty()
207230{
208  auto* frame = this->frame();
209  if (!frame)
210  return;
211  frame->selection().clear();
 231 removeAllRanges();
212232}
213233
214 void DOMSelection::setBaseAndExtent(Node* baseNode, unsigned baseOffset, Node* extentNode, unsigned extentOffset)
 234ExceptionOr<void> DOMSelection::setBaseAndExtent(Node* baseNode, unsigned baseOffset, Node* extentNode, unsigned extentOffset)
215235{
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);
 236 auto frame = makeRefPtr(this->frame());
 237 if (!frame)
 238 return { };
 239 if (shouldUseSelectionAssociatedRange()) {
 240 // FIXME: The Selection API specification requires this exception, but it may be incompatible in practice.
 241 // FIXME: We should do this by making the arguments non-nullable in the IDL file, once shouldUseSelectionAssociatedRange is always true.
 242 if (!baseNode || !extentNode)
 243 return Exception { TypeError };
 244 // FIXME: The Selection API specification requires this exception, but it may be incompatible in practice.
 245 if (baseOffset > baseNode->length() || extentOffset > extentNode->length())
 246 return Exception { IndexSizeError };
 247 auto& document = *frame->document();
 248 if (!document.contains(*baseNode) || !document.contains(*extentNode))
 249 return { };
 250 } else {
 251 if (!isValidForPosition(baseNode) || !isValidForPosition(extentNode))
 252 return { };
 253 }
 254 auto& selection = frame->selection();
 255 selection.disassociateLiveRange();
 256 selection.moveTo(createLegacyEditingPosition(baseNode, baseOffset), createLegacyEditingPosition(extentNode, extentOffset), Affinity::Downstream);
 257 return { };
221258}
222259
223 void DOMSelection::setPosition(Node* node, unsigned offset)
 260ExceptionOr<void> DOMSelection::setPosition(Node* node, unsigned offset)
224261{
225  if (!isValidForPosition(node))
226  return;
227 
228  Ref<Frame> protectedFrame(*frame());
229  protectedFrame->selection().moveTo(createLegacyEditingPosition(node, offset), Affinity::Downstream);
 262 return collapse(node, offset);
230263}
231264
232265void DOMSelection::modify(const String& alterString, const String& directionString, const String& granularityString)
233266{
234  auto* frame = this->frame();
235  if (!frame)
236  return;
237 
238267 FrameSelection::EAlteration alter;
239268 if (equalLettersIgnoringASCIICase(alterString, "extend"))
240269 alter = FrameSelection::AlterationExtend;

@@void DOMSelection::modify(const String& alterString, const String& directionStri
277306 else
278307 return;
279308
280  Ref<Frame> protector(*frame);
281  frame->selection().modify(alter, direction, granularity);
 309 if (auto frame = makeRefPtr(this->frame()))
 310 frame->selection().modify(alter, direction, granularity);
282311}
283312
284313ExceptionOr<void> DOMSelection::extend(Node& node, unsigned offset)

@@ExceptionOr<void> DOMSelection::extend(Node& node, unsigned offset)
288317 return { };
289318 if (offset > node.length())
290319 return Exception { IndexSizeError };
291  if (!isValidForPosition(&node))
292  return { };
293  frame->selection().setExtent(createLegacyEditingPosition(&node, offset), Affinity::Downstream);
 320 if (shouldUseSelectionAssociatedRange()) {
 321 if (!frame->document()->contains(node))
 322 return { };
 323 } else {
 324 if (!isValidForPosition(&node))
 325 return { };
 326 }
 327 auto& selection = frame->selection();
 328 selection.disassociateLiveRange();
 329 selection.setExtent(createLegacyEditingPosition(&node, offset), Affinity::Downstream);
294330 return { };
295331}
296332

@@ExceptionOr<Ref<Range>> DOMSelection::getRangeAt(unsigned index)
299335 if (index >= rangeCount())
300336 return Exception { IndexSizeError };
301337 auto& frame = *this->frame();
 338 if (shouldUseSelectionAssociatedRange())
 339 return frame.selection().associatedLiveRange().releaseNonNull();
302340 if (auto shadowAncestor = selectionShadowAncestor(frame))
303341 return createLiveRange(makeSimpleRange(*makeBoundaryPointBeforeNode(*shadowAncestor)));
304342 return createLiveRange(*frame.selection().selection().firstRange());

@@void DOMSelection::addRange(Range& liveRange)
317355 auto frame = makeRefPtr(this->frame());
318356 if (!frame)
319357 return;
320 
321  auto range = makeSimpleRange(liveRange);
322358 auto& selection = frame->selection();
323 
 359 if (shouldUseSelectionAssociatedRange()) {
 360 if (selection.isNone())
 361 selection.associateLiveRange(liveRange);
 362 return;
 363 }
 364 auto range = makeSimpleRange(liveRange);
324365 if (auto selectedRange = selection.selection().toNormalizedRange()) {
325366 if (!selectedRange->start.container->containingShadowRoot() && intersects(*selectedRange, range))
326367 selection.setSelection(unionRange(*selectedRange, range));
327368 return;
328369 }
329 
330370 selection.setSelection(range);
331371}
332372
 373ExceptionOr<void> DOMSelection::removeRange(Range& liveRange)
 374{
 375 if (&liveRange != frame()->selection().associatedLiveRange())
 376 return Exception { NotFoundError };
 377 removeAllRanges();
 378 return { };
 379}
 380
333381void DOMSelection::deleteFromDocument()
334382{
335383 auto frame = makeRefPtr(this->frame());
336384 if (!frame)
337385 return;
338386
 387 if (shouldUseSelectionAssociatedRange()) {
 388 if (auto associatedRange = frame->selection().associatedLiveRange())
 389 associatedRange->deleteContents();
 390 return;
 391 }
 392
339393 auto selectedRange = frame->selection().selection().toNormalizedRange();
340394 if (!selectedRange || selectedRange->start.container->containingShadowRoot())
341395 return;

@@void DOMSelection::deleteFromDocument()
346400
347401bool DOMSelection::containsNode(Node& node, bool allowPartial) const
348402{
349  // FIXME: This behavior does not match what the selection API standard specifies.
350  if (node.isTextNode())
351  allowPartial = true;
 403 if (!shouldUseSelectionAssociatedRange()) {
 404 // FIXME: This does not match the Selection API specification.
 405 if (node.isTextNode())
 406 allowPartial = true;
 407 }
352408
353409 auto* frame = this->frame();
354410 if (!frame)

@@bool DOMSelection::containsNode(Node& node, bool allowPartial) const
363419
364420void DOMSelection::selectAllChildren(Node& node)
365421{
366  // This doesn't (and shouldn't) select text node characters.
367  setBaseAndExtent(&node, 0, &node, node.countChildNodes());
 422 if (shouldUseSelectionAssociatedRange())
 423 setBaseAndExtent(&node, 0, &node, node.length());
 424 else {
 425 // This doesn't select text node characters.
 426 setBaseAndExtent(&node, 0, &node, node.countChildNodes());
 427 }
368428}
369429
370430String DOMSelection::toString()

@@unsigned DOMSelection::shadowAdjustedOffset(const Position& position) const
410470
411471bool DOMSelection::isValidForPosition(Node* node) const
412472{
 473 ASSERT(!shouldUseSelectionAssociatedRange());
413474 auto* frame = this->frame();
414475 return frame && (!node || &node->document() == frame->document());
415476}

Source/WebCore/page/DOMSelection.h

11/*
2  * Copyright (C) 2007 Apple Inc. All rights reserved.
 2 * Copyright (C) 2007-2020 Apple Inc. All rights reserved.
33 * Copyright (C) 2012 Google Inc. All rights reserved.
44 *
55 * Redistribution and use in source and binary forms, with or without

@@public:
5151 unsigned baseOffset() const;
5252 unsigned extentOffset() const;
5353 String type() const;
54  void setBaseAndExtent(Node* baseNode, unsigned baseOffset, Node* extentNode, unsigned extentOffset);
55  void setPosition(Node*, unsigned offset);
 54 ExceptionOr<void> setBaseAndExtent(Node* baseNode, unsigned baseOffset, Node* extentNode, unsigned extentOffset);
 55 ExceptionOr<void> setPosition(Node*, unsigned offset);
5656 void modify(const String& alter, const String& direction, const String& granularity);
5757
5858 // The anchor and focus are the start and end of the selection, and

@@public:
6464 unsigned focusOffset() const;
6565 bool isCollapsed() const;
6666 unsigned rangeCount() const;
67  void collapse(Node*, unsigned offset);
 67 ExceptionOr<void> collapse(Node*, unsigned offset);
6868 ExceptionOr<void> collapseToEnd();
6969 ExceptionOr<void> collapseToStart();
7070 ExceptionOr<void> extend(Node&, unsigned offset);
7171 ExceptionOr<Ref<Range>> getRangeAt(unsigned);
7272 void removeAllRanges();
7373 void addRange(Range&);
 74 ExceptionOr<void> removeRange(Range&);
7475 void deleteFromDocument();
7576 bool containsNode(Node&, bool partlyContained) const;
7677 void selectAllChildren(Node&);

Source/WebCore/page/DOMSelection.idl

4141 readonly attribute boolean isCollapsed;
4242 readonly attribute unsigned long rangeCount;
4343
44  undefined collapse(Node? node, optional unsigned long offset = 0);
45  [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 
52  [MayThrowException] undefined extend(Node node, optional unsigned long offset = 0);
 44 readonly attribute DOMString type;
5345
5446 [MayThrowException] Range getRangeAt(unsigned long index);
55  undefined removeAllRanges();
5647 undefined addRange(Range range);
 48 [MayThrowException] undefined removeRange(Range range);
 49 undefined removeAllRanges();
5750
58  [NotEnumerable] DOMString toString();
 51 undefined empty();
5952
60  readonly attribute DOMString type;
 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();
 57 [MayThrowException] undefined collapseToEnd();
6158
62  undefined setBaseAndExtent(Node? baseNode, unsigned long baseOffset, Node? extentNode, unsigned long extentOffset);
63  undefined setPosition(Node? node, optional unsigned long offset = 0);
 59 [MayThrowException] undefined extend(Node node, optional unsigned long offset = 0);
6460
65  undefined empty();
 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);
 66
 67 [NotEnumerable] DOMString toString();
6668
67  // FIXME: The following operation should be implemented.
68  // undefined removeRange(Range range);
 69 // Non-standard methods and attributes.
6970
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);
7272
7373 readonly attribute Node? baseNode;
7474 readonly attribute unsigned long baseOffset;

LayoutTests/imported/w3c/web-platform-tests/selection/removeRange-expected.txt

@@Äb̈c̈d̈ëf̈g̈ḧ
33Qrstuvwx
44
55
6 FAIL removeRange() with Range 0 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
7 FAIL removeRange() with Range 1 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
8 FAIL removeRange() with Range 2 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
9 FAIL removeRange() with Range 3 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
10 FAIL removeRange() with Range 4 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
11 FAIL removeRange() with Range 5 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
12 FAIL removeRange() with Range 6 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
13 FAIL removeRange() with Range 7 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
14 FAIL removeRange() with Range 14 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
15 FAIL removeRange() with Range 15 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
16 FAIL removeRange() with Range 16 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
17 FAIL removeRange() with Range 17 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
18 FAIL removeRange() with Range 18 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
19 FAIL removeRange() with Range 22 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
20 FAIL removeRange() with Range 23 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
21 FAIL removeRange() with Range 26 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
22 FAIL removeRange() with Range 27 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
23 FAIL removeRange() with Range 28 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
24 FAIL removeRange() with Range 29 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
25 FAIL removeRange() with Range 30 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
26 FAIL removeRange() with Range 31 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
27 FAIL removeRange() with Range 32 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
28 FAIL removeRange() with Range 34 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
29 FAIL removeRange() with Range 35 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
30 FAIL removeRange() with Range 36 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
31 FAIL removeRange() with Range 37 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
32 FAIL removeRange() with Range 38 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
33 FAIL removeRange() with Range 39 selection.removeRange is not a function. (In 'selection.removeRange(range)', 'selection.removeRange' is undefined)
 6FAIL removeRange() with Range 0 The object can not be found here.
 7FAIL removeRange() with Range 1 The object can not be found here.
 8FAIL removeRange() with Range 2 The object can not be found here.
 9FAIL removeRange() with Range 3 The object can not be found here.
 10FAIL removeRange() with Range 4 The object can not be found here.
 11FAIL removeRange() with Range 5 The object can not be found here.
 12FAIL removeRange() with Range 6 The object can not be found here.
 13FAIL removeRange() with Range 7 The object can not be found here.
 14FAIL removeRange() with Range 14 The object can not be found here.
 15FAIL removeRange() with Range 15 The object can not be found here.
 16FAIL removeRange() with Range 16 The object can not be found here.
 17FAIL removeRange() with Range 17 The object can not be found here.
 18FAIL removeRange() with Range 18 The object can not be found here.
 19FAIL removeRange() with Range 22 The object can not be found here.
 20FAIL removeRange() with Range 23 The object can not be found here.
 21FAIL removeRange() with Range 26 The object can not be found here.
 22FAIL removeRange() with Range 27 The object can not be found here.
 23FAIL removeRange() with Range 28 The object can not be found here.
 24FAIL removeRange() with Range 29 The object can not be found here.
 25FAIL removeRange() with Range 30 The object can not be found here.
 26FAIL removeRange() with Range 31 The object can not be found here.
 27FAIL removeRange() with Range 32 The object can not be found here.
 28FAIL removeRange() with Range 34 The object can not be found here.
 29FAIL removeRange() with Range 35 The object can not be found here.
 30FAIL removeRange() with Range 36 The object can not be found here.
 31FAIL removeRange() with Range 37 The object can not be found here.
 32FAIL removeRange() with Range 38 The object can not be found here.
 33FAIL removeRange() with Range 39 The object can not be found here.
3434PASS removeRange() argument is non-optional Range
3535