1 /*
2  * (C) 1999 Lars Knoll (knoll@kde.org)
3  * (C) 2000 Gunnstein Lye (gunnstein@netcom.no)
4  * (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
5  * (C) 2001 Peter Kelly (pmk@post.com)
6  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All
7  * rights reserved.
8  * Copyright (C) 2011 Motorola Mobility. All rights reserved.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25 
26 #include "third_party/blink/renderer/core/dom/range.h"
27 
28 #include "third_party/blink/renderer/core/dom/character_data.h"
29 #include "third_party/blink/renderer/core/dom/container_node.h"
30 #include "third_party/blink/renderer/core/dom/document_fragment.h"
31 #include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h"
32 #include "third_party/blink/renderer/core/dom/events/scoped_event_queue.h"
33 #include "third_party/blink/renderer/core/dom/node.h"
34 #include "third_party/blink/renderer/core/dom/node_traversal.h"
35 #include "third_party/blink/renderer/core/dom/node_with_index.h"
36 #include "third_party/blink/renderer/core/dom/processing_instruction.h"
37 #include "third_party/blink/renderer/core/dom/text.h"
38 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
39 #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
40 #include "third_party/blink/renderer/core/editing/frame_selection.h"
41 #include "third_party/blink/renderer/core/editing/iterators/text_iterator.h"
42 #include "third_party/blink/renderer/core/editing/selection_template.h"
43 #include "third_party/blink/renderer/core/editing/serializers/serialization.h"
44 #include "third_party/blink/renderer/core/editing/set_selection_options.h"
45 #include "third_party/blink/renderer/core/editing/visible_position.h"
46 #include "third_party/blink/renderer/core/editing/visible_units.h"
47 #include "third_party/blink/renderer/core/frame/local_frame.h"
48 #include "third_party/blink/renderer/core/frame/settings.h"
49 #include "third_party/blink/renderer/core/geometry/dom_rect.h"
50 #include "third_party/blink/renderer/core/geometry/dom_rect_list.h"
51 #include "third_party/blink/renderer/core/html/html_body_element.h"
52 #include "third_party/blink/renderer/core/html/html_element.h"
53 #include "third_party/blink/renderer/core/layout/layout_object.h"
54 #include "third_party/blink/renderer/core/layout/layout_text.h"
55 #include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
56 #include "third_party/blink/renderer/core/svg/svg_svg_element.h"
57 #include "third_party/blink/renderer/core/trustedtypes/trusted_types_util.h"
58 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
59 #include "third_party/blink/renderer/platform/geometry/float_quad.h"
60 #include "third_party/blink/renderer/platform/heap/heap.h"
61 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
62 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
63 
64 namespace blink {
65 
66 class RangeUpdateScope {
67   STACK_ALLOCATED();
68 
69  public:
RangeUpdateScope(Range * range)70   explicit RangeUpdateScope(Range* range) {
71     DCHECK(range);
72     if (++scope_count_ == 1) {
73       range_ = range;
74       old_document_ = &range->OwnerDocument();
75 #if DCHECK_IS_ON()
76       current_range_ = range;
77     } else {
78       DCHECK_EQ(current_range_, range);
79 #endif
80     }
81   }
82 
~RangeUpdateScope()83   ~RangeUpdateScope() {
84     DCHECK_GE(scope_count_, 1);
85     if (--scope_count_ > 0)
86       return;
87     Settings* settings = old_document_->GetFrame()
88                              ? old_document_->GetFrame()->GetSettings()
89                              : nullptr;
90     if (!settings ||
91         !settings->GetDoNotUpdateSelectionOnMutatingSelectionRange()) {
92       range_->RemoveFromSelectionIfInDifferentRoot(*old_document_);
93       range_->UpdateSelectionIfAddedToSelection();
94     }
95 #if DCHECK_IS_ON()
96     current_range_ = nullptr;
97 #endif
98   }
99 
100  private:
101   static int scope_count_;
102 #if DCHECK_IS_ON()
103   // This raw pointer is safe because
104   //  - s_currentRange has a valid pointer only if RangeUpdateScope instance is
105   //  live.
106   //  - RangeUpdateScope is used only in Range member functions.
107   static Range* current_range_;
108 #endif
109   Range* range_ = nullptr;
110   Document* old_document_ = nullptr;
111 
112   DISALLOW_COPY_AND_ASSIGN(RangeUpdateScope);
113 };
114 
115 int RangeUpdateScope::scope_count_ = 0;
116 #if DCHECK_IS_ON()
117 Range* RangeUpdateScope::current_range_;
118 #endif
119 
Range(Document & owner_document)120 Range::Range(Document& owner_document)
121     : owner_document_(&owner_document),
122       start_(*owner_document_),
123       end_(*owner_document_) {
124   owner_document_->AttachRange(this);
125 }
126 
Create(Document & owner_document)127 Range* Range::Create(Document& owner_document) {
128   return MakeGarbageCollected<Range>(owner_document);
129 }
130 
Range(Document & owner_document,Node * start_container,unsigned start_offset,Node * end_container,unsigned end_offset)131 Range::Range(Document& owner_document,
132              Node* start_container,
133              unsigned start_offset,
134              Node* end_container,
135              unsigned end_offset)
136     : owner_document_(&owner_document),
137       start_(*owner_document_),
138       end_(*owner_document_) {
139   owner_document_->AttachRange(this);
140 
141   // Simply setting the containers and offsets directly would not do any of the
142   // checking that setStart and setEnd do, so we call those functions.
143   setStart(start_container, start_offset);
144   setEnd(end_container, end_offset);
145 }
146 
Range(Document & owner_document,const Position & start,const Position & end)147 Range::Range(Document& owner_document,
148              const Position& start,
149              const Position& end)
150     : Range(owner_document,
151             start.ComputeContainerNode(),
152             start.ComputeOffsetInContainerNode(),
153             end.ComputeContainerNode(),
154             end.ComputeOffsetInContainerNode()) {}
155 
Dispose()156 void Range::Dispose() {
157   // A prompt detach from the owning Document helps avoid GC overhead.
158   owner_document_->DetachRange(this);
159 }
160 
IsConnected() const161 bool Range::IsConnected() const {
162   DCHECK_EQ(start_.IsConnected(), end_.IsConnected());
163   return start_.IsConnected();
164 }
165 
SetDocument(Document & document)166 void Range::SetDocument(Document& document) {
167   DCHECK_NE(owner_document_, document);
168   DCHECK(owner_document_);
169   owner_document_->DetachRange(this);
170   owner_document_ = &document;
171   start_.SetToStartOfNode(document);
172   end_.SetToStartOfNode(document);
173   owner_document_->AttachRange(this);
174 }
175 
commonAncestorContainer() const176 Node* Range::commonAncestorContainer() const {
177   return commonAncestorContainer(&start_.Container(), &end_.Container());
178 }
179 
commonAncestorContainer(const Node * container_a,const Node * container_b)180 Node* Range::commonAncestorContainer(const Node* container_a,
181                                      const Node* container_b) {
182   if (!container_a || !container_b)
183     return nullptr;
184   return container_a->CommonAncestor(*container_b, NodeTraversal::Parent);
185 }
186 
CheckForDifferentRootContainer(const RangeBoundaryPoint & start,const RangeBoundaryPoint & end)187 static inline bool CheckForDifferentRootContainer(
188     const RangeBoundaryPoint& start,
189     const RangeBoundaryPoint& end) {
190   Node* end_root_container = &end.Container();
191   while (end_root_container->parentNode())
192     end_root_container = end_root_container->parentNode();
193   Node* start_root_container = &start.Container();
194   while (start_root_container->parentNode())
195     start_root_container = start_root_container->parentNode();
196 
197   return start_root_container != end_root_container ||
198          (Range::compareBoundaryPoints(start, end, ASSERT_NO_EXCEPTION) > 0);
199 }
200 
setStart(Node * ref_node,unsigned offset,ExceptionState & exception_state)201 void Range::setStart(Node* ref_node,
202                      unsigned offset,
203                      ExceptionState& exception_state) {
204   if (!ref_node) {
205     // FIXME: Generated bindings code never calls with null, and neither should
206     // other callers!
207     exception_state.ThrowTypeError("The node provided is null.");
208     return;
209   }
210 
211   RangeUpdateScope scope(this);
212   bool did_move_document = false;
213   if (ref_node->GetDocument() != owner_document_) {
214     SetDocument(ref_node->GetDocument());
215     did_move_document = true;
216   }
217 
218   Node* child_node = CheckNodeWOffset(ref_node, offset, exception_state);
219   if (exception_state.HadException())
220     return;
221 
222   start_.Set(*ref_node, offset, child_node);
223 
224   if (did_move_document || CheckForDifferentRootContainer(start_, end_))
225     collapse(true);
226 }
227 
setEnd(Node * ref_node,unsigned offset,ExceptionState & exception_state)228 void Range::setEnd(Node* ref_node,
229                    unsigned offset,
230                    ExceptionState& exception_state) {
231   if (!ref_node) {
232     // FIXME: Generated bindings code never calls with null, and neither should
233     // other callers!
234     exception_state.ThrowTypeError("The node provided is null.");
235     return;
236   }
237 
238   RangeUpdateScope scope(this);
239   bool did_move_document = false;
240   if (ref_node->GetDocument() != owner_document_) {
241     SetDocument(ref_node->GetDocument());
242     did_move_document = true;
243   }
244 
245   Node* child_node = CheckNodeWOffset(ref_node, offset, exception_state);
246   if (exception_state.HadException())
247     return;
248 
249   end_.Set(*ref_node, offset, child_node);
250 
251   if (did_move_document || CheckForDifferentRootContainer(start_, end_))
252     collapse(false);
253 }
254 
setStart(const Position & start,ExceptionState & exception_state)255 void Range::setStart(const Position& start, ExceptionState& exception_state) {
256   Position parent_anchored = start.ParentAnchoredEquivalent();
257   setStart(parent_anchored.ComputeContainerNode(),
258            parent_anchored.OffsetInContainerNode(), exception_state);
259 }
260 
setEnd(const Position & end,ExceptionState & exception_state)261 void Range::setEnd(const Position& end, ExceptionState& exception_state) {
262   Position parent_anchored = end.ParentAnchoredEquivalent();
263   setEnd(parent_anchored.ComputeContainerNode(),
264          parent_anchored.OffsetInContainerNode(), exception_state);
265 }
266 
collapse(bool to_start)267 void Range::collapse(bool to_start) {
268   RangeUpdateScope scope(this);
269   if (to_start)
270     end_ = start_;
271   else
272     start_ = end_;
273 }
274 
HasSameRoot(const Node & node) const275 bool Range::HasSameRoot(const Node& node) const {
276   if (node.GetDocument() != owner_document_)
277     return false;
278   // commonAncestorContainer() is O(depth). We should avoid to call it in common
279   // cases.
280   if (node.IsInTreeScope() && start_.Container().IsInTreeScope() &&
281       &node.GetTreeScope() == &start_.Container().GetTreeScope())
282     return true;
283   return node.CommonAncestor(start_.Container(), NodeTraversal::Parent);
284 }
285 
isPointInRange(Node * ref_node,unsigned offset,ExceptionState & exception_state) const286 bool Range::isPointInRange(Node* ref_node,
287                            unsigned offset,
288                            ExceptionState& exception_state) const {
289   if (!ref_node) {
290     // FIXME: Generated bindings code never calls with null, and neither should
291     // other callers!
292     exception_state.ThrowTypeError("The node provided is null.");
293     return false;
294   }
295   if (!HasSameRoot(*ref_node))
296     return false;
297 
298   CheckNodeWOffset(ref_node, offset, exception_state);
299   if (exception_state.HadException())
300     return false;
301 
302   return compareBoundaryPoints(ref_node, offset, &start_.Container(),
303                                start_.Offset(), exception_state) >= 0 &&
304          !exception_state.HadException() &&
305          compareBoundaryPoints(ref_node, offset, &end_.Container(),
306                                end_.Offset(), exception_state) <= 0 &&
307          !exception_state.HadException();
308 }
309 
comparePoint(Node * ref_node,unsigned offset,ExceptionState & exception_state) const310 int16_t Range::comparePoint(Node* ref_node,
311                             unsigned offset,
312                             ExceptionState& exception_state) const {
313   // http://developer.mozilla.org/en/docs/DOM:range.comparePoint
314   // This method returns -1, 0 or 1 depending on if the point described by the
315   // refNode node and an offset within the node is before, same as, or after the
316   // range respectively.
317 
318   if (!HasSameRoot(*ref_node)) {
319     exception_state.ThrowDOMException(
320         DOMExceptionCode::kWrongDocumentError,
321         "The node provided and the Range are not in the same tree.");
322     return 0;
323   }
324 
325   CheckNodeWOffset(ref_node, offset, exception_state);
326   if (exception_state.HadException())
327     return 0;
328 
329   // compare to start, and point comes before
330   if (compareBoundaryPoints(ref_node, offset, &start_.Container(),
331                             start_.Offset(), exception_state) < 0)
332     return -1;
333 
334   if (exception_state.HadException())
335     return 0;
336 
337   // compare to end, and point comes after
338   if (compareBoundaryPoints(ref_node, offset, &end_.Container(), end_.Offset(),
339                             exception_state) > 0 &&
340       !exception_state.HadException())
341     return 1;
342 
343   // point is in the middle of this range, or on the boundary points
344   return 0;
345 }
346 
compareBoundaryPoints(unsigned how,const Range * source_range,ExceptionState & exception_state) const347 int16_t Range::compareBoundaryPoints(unsigned how,
348                                      const Range* source_range,
349                                      ExceptionState& exception_state) const {
350   if (!(how == kStartToStart || how == kStartToEnd || how == kEndToEnd ||
351         how == kEndToStart)) {
352     exception_state.ThrowDOMException(
353         DOMExceptionCode::kNotSupportedError,
354         "The comparison method provided must be "
355         "one of 'START_TO_START', 'START_TO_END', "
356         "'END_TO_END', or 'END_TO_START'.");
357     return 0;
358   }
359 
360   Node* this_cont = commonAncestorContainer();
361   Node* source_cont = source_range->commonAncestorContainer();
362   if (this_cont->GetDocument() != source_cont->GetDocument()) {
363     exception_state.ThrowDOMException(
364         DOMExceptionCode::kWrongDocumentError,
365         "The source range is in a different document than this range.");
366     return 0;
367   }
368 
369   Node* this_top = this_cont;
370   Node* source_top = source_cont;
371   while (this_top->parentNode())
372     this_top = this_top->parentNode();
373   while (source_top->parentNode())
374     source_top = source_top->parentNode();
375   if (this_top != source_top) {  // in different DocumentFragments
376     exception_state.ThrowDOMException(
377         DOMExceptionCode::kWrongDocumentError,
378         "The source range is in a different document than this range.");
379     return 0;
380   }
381 
382   switch (how) {
383     case kStartToStart:
384       return compareBoundaryPoints(start_, source_range->start_,
385                                    exception_state);
386     case kStartToEnd:
387       return compareBoundaryPoints(end_, source_range->start_, exception_state);
388     case kEndToEnd:
389       return compareBoundaryPoints(end_, source_range->end_, exception_state);
390     case kEndToStart:
391       return compareBoundaryPoints(start_, source_range->end_, exception_state);
392   }
393 
394   NOTREACHED();
395   return 0;
396 }
397 
compareBoundaryPoints(Node * container_a,unsigned offset_a,Node * container_b,unsigned offset_b,ExceptionState & exception_state)398 int16_t Range::compareBoundaryPoints(Node* container_a,
399                                      unsigned offset_a,
400                                      Node* container_b,
401                                      unsigned offset_b,
402                                      ExceptionState& exception_state) {
403   bool disconnected = false;
404   int16_t result = ComparePositionsInDOMTree(container_a, offset_a, container_b,
405                                              offset_b, &disconnected);
406   if (disconnected) {
407     exception_state.ThrowDOMException(
408         DOMExceptionCode::kWrongDocumentError,
409         "The two ranges are in separate documents.");
410     return 0;
411   }
412   return result;
413 }
414 
compareBoundaryPoints(const RangeBoundaryPoint & boundary_a,const RangeBoundaryPoint & boundary_b,ExceptionState & exception_state)415 int16_t Range::compareBoundaryPoints(const RangeBoundaryPoint& boundary_a,
416                                      const RangeBoundaryPoint& boundary_b,
417                                      ExceptionState& exception_state) {
418   return compareBoundaryPoints(&boundary_a.Container(), boundary_a.Offset(),
419                                &boundary_b.Container(), boundary_b.Offset(),
420                                exception_state);
421 }
422 
BoundaryPointsValid() const423 bool Range::BoundaryPointsValid() const {
424   DummyExceptionStateForTesting exception_state;
425   return compareBoundaryPoints(start_, end_, exception_state) <= 0 &&
426          !exception_state.HadException();
427 }
428 
deleteContents(ExceptionState & exception_state)429 void Range::deleteContents(ExceptionState& exception_state) {
430   DCHECK(BoundaryPointsValid());
431 
432   {
433     EventQueueScope event_queue_scope;
434     ProcessContents(DELETE_CONTENTS, exception_state);
435   }
436 }
437 
intersectsNode(Node * ref_node,ExceptionState & exception_state)438 bool Range::intersectsNode(Node* ref_node, ExceptionState& exception_state) {
439   // http://developer.mozilla.org/en/docs/DOM:range.intersectsNode
440   // Returns a bool if the node intersects the range.
441   if (!ref_node) {
442     // FIXME: Generated bindings code never calls with null, and neither should
443     // other callers!
444     exception_state.ThrowTypeError("The node provided is null.");
445     return false;
446   }
447   if (!HasSameRoot(*ref_node))
448     return false;
449 
450   ContainerNode* parent_node = ref_node->parentNode();
451   if (!parent_node)
452     return true;
453 
454   int node_index = ref_node->NodeIndex();
455   return Position(parent_node, node_index) < end_.ToPosition() &&
456          Position(parent_node, node_index + 1) > start_.ToPosition();
457 }
458 
HighestAncestorUnderCommonRoot(Node * node,Node * common_root)459 static inline Node* HighestAncestorUnderCommonRoot(Node* node,
460                                                    Node* common_root) {
461   if (node == common_root)
462     return nullptr;
463 
464   DCHECK(common_root->contains(node));
465 
466   while (node->parentNode() != common_root)
467     node = node->parentNode();
468 
469   return node;
470 }
471 
ChildOfCommonRootBeforeOffset(Node * container,unsigned offset,Node * common_root)472 static inline Node* ChildOfCommonRootBeforeOffset(Node* container,
473                                                   unsigned offset,
474                                                   Node* common_root) {
475   DCHECK(container);
476   DCHECK(common_root);
477 
478   if (!common_root->contains(container))
479     return nullptr;
480 
481   if (container == common_root) {
482     container = container->firstChild();
483     for (unsigned i = 0; container && i < offset; i++)
484       container = container->nextSibling();
485   } else {
486     while (container->parentNode() != common_root)
487       container = container->parentNode();
488   }
489 
490   return container;
491 }
492 
LengthOfContents(const Node * node)493 static unsigned LengthOfContents(const Node* node) {
494   // This switch statement must be consistent with that of
495   // Range::processContentsBetweenOffsets.
496   switch (node->getNodeType()) {
497     case Node::kTextNode:
498     case Node::kCdataSectionNode:
499     case Node::kCommentNode:
500     case Node::kProcessingInstructionNode:
501       return To<CharacterData>(node)->length();
502     case Node::kElementNode:
503     case Node::kDocumentNode:
504     case Node::kDocumentFragmentNode:
505       return To<ContainerNode>(node)->CountChildren();
506     case Node::kAttributeNode:
507     case Node::kDocumentTypeNode:
508       return 0;
509   }
510   NOTREACHED();
511   return 0;
512 }
513 
ProcessContents(ActionType action,ExceptionState & exception_state)514 DocumentFragment* Range::ProcessContents(ActionType action,
515                                          ExceptionState& exception_state) {
516   DocumentFragment* fragment = nullptr;
517   if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
518     fragment = DocumentFragment::Create(*owner_document_.Get());
519 
520   if (collapsed())
521     return fragment;
522 
523   Node* common_root = commonAncestorContainer();
524   DCHECK(common_root);
525 
526   if (start_.Container() == end_.Container()) {
527     ProcessContentsBetweenOffsets(action, fragment, &start_.Container(),
528                                   start_.Offset(), end_.Offset(),
529                                   exception_state);
530     return fragment;
531   }
532 
533   // Since mutation observers can modify the range during the process, the
534   // boundary points need to be saved.
535   const RangeBoundaryPoint original_start(start_);
536   const RangeBoundaryPoint original_end(end_);
537 
538   // what is the highest node that partially selects the start / end of the
539   // range?
540   Node* partial_start =
541       HighestAncestorUnderCommonRoot(&original_start.Container(), common_root);
542   Node* partial_end =
543       HighestAncestorUnderCommonRoot(&original_end.Container(), common_root);
544 
545   // Start and end containers are different.
546   // There are three possibilities here:
547   // 1. Start container == commonRoot (End container must be a descendant)
548   // 2. End container == commonRoot (Start container must be a descendant)
549   // 3. Neither is commonRoot, they are both descendants
550   //
551   // In case 3, we grab everything after the start (up until a direct child
552   // of commonRoot) into leftContents, and everything before the end (up until
553   // a direct child of commonRoot) into rightContents. Then we process all
554   // commonRoot children between leftContents and rightContents
555   //
556   // In case 1 or 2, we skip either processing of leftContents or rightContents,
557   // in which case the last lot of nodes either goes from the first or last
558   // child of commonRoot.
559   //
560   // These are deleted, cloned, or extracted (i.e. both) depending on action.
561 
562   // Note that we are verifying that our common root hierarchy is still intact
563   // after any DOM mutation event, at various stages below. See webkit bug
564   // 60350.
565 
566   Node* left_contents = nullptr;
567   if (original_start.Container() != common_root &&
568       common_root->contains(&original_start.Container())) {
569     left_contents = ProcessContentsBetweenOffsets(
570         action, nullptr, &original_start.Container(), original_start.Offset(),
571         LengthOfContents(&original_start.Container()), exception_state);
572     left_contents = ProcessAncestorsAndTheirSiblings(
573         action, &original_start.Container(), kProcessContentsForward,
574         left_contents, common_root, exception_state);
575   }
576 
577   Node* right_contents = nullptr;
578   if (end_.Container() != common_root &&
579       common_root->contains(&original_end.Container())) {
580     right_contents = ProcessContentsBetweenOffsets(
581         action, nullptr, &original_end.Container(), 0, original_end.Offset(),
582         exception_state);
583     right_contents = ProcessAncestorsAndTheirSiblings(
584         action, &original_end.Container(), kProcessContentsBackward,
585         right_contents, common_root, exception_state);
586   }
587 
588   // delete all children of commonRoot between the start and end container
589   Node* process_start = ChildOfCommonRootBeforeOffset(
590       &original_start.Container(), original_start.Offset(), common_root);
591   // process_start contains nodes before start_.
592   if (process_start && original_start.Container() != common_root)
593     process_start = process_start->nextSibling();
594   Node* process_end = ChildOfCommonRootBeforeOffset(
595       &original_end.Container(), original_end.Offset(), common_root);
596 
597   // Collapse the range, making sure that the result is not within a node that
598   // was partially selected.
599   if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
600     if (partial_start && common_root->contains(partial_start)) {
601       // FIXME: We should not continue if we have an earlier error.
602       exception_state.ClearException();
603       setStart(partial_start->parentNode(), partial_start->NodeIndex() + 1,
604                exception_state);
605     } else if (partial_end && common_root->contains(partial_end)) {
606       // FIXME: We should not continue if we have an earlier error.
607       exception_state.ClearException();
608       setStart(partial_end->parentNode(), partial_end->NodeIndex(),
609                exception_state);
610     }
611     if (exception_state.HadException())
612       return nullptr;
613     end_ = start_;
614   }
615 
616   // Now add leftContents, stuff in between, and rightContents to the fragment
617   // (or just delete the stuff in between)
618 
619   if ((action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) && left_contents)
620     fragment->AppendChild(left_contents, exception_state);
621 
622   if (process_start) {
623     NodeVector nodes;
624     for (Node* n = process_start; n && n != process_end; n = n->nextSibling())
625       nodes.push_back(n);
626     ProcessNodes(action, nodes, common_root, fragment, exception_state);
627   }
628 
629   if ((action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) &&
630       right_contents)
631     fragment->AppendChild(right_contents, exception_state);
632 
633   return fragment;
634 }
635 
DeleteCharacterData(CharacterData * data,unsigned start_offset,unsigned end_offset,ExceptionState & exception_state)636 static inline void DeleteCharacterData(CharacterData* data,
637                                        unsigned start_offset,
638                                        unsigned end_offset,
639                                        ExceptionState& exception_state) {
640   if (data->length() - end_offset)
641     data->deleteData(end_offset, data->length() - end_offset, exception_state);
642   if (start_offset)
643     data->deleteData(0, start_offset, exception_state);
644 }
645 
ProcessContentsBetweenOffsets(ActionType action,DocumentFragment * fragment,Node * container,unsigned start_offset,unsigned end_offset,ExceptionState & exception_state)646 Node* Range::ProcessContentsBetweenOffsets(ActionType action,
647                                            DocumentFragment* fragment,
648                                            Node* container,
649                                            unsigned start_offset,
650                                            unsigned end_offset,
651                                            ExceptionState& exception_state) {
652   DCHECK(container);
653   DCHECK_LE(start_offset, end_offset);
654 
655   // This switch statement must be consistent with that of
656   // lengthOfContents.
657   Node* result = nullptr;
658   switch (container->getNodeType()) {
659     case Node::kTextNode:
660     case Node::kCdataSectionNode:
661     case Node::kCommentNode:
662     case Node::kProcessingInstructionNode:
663       end_offset = std::min(end_offset, To<CharacterData>(container)->length());
664       if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
665         CharacterData* c =
666             static_cast<CharacterData*>(container->cloneNode(true));
667         DeleteCharacterData(c, start_offset, end_offset, exception_state);
668         if (fragment) {
669           result = fragment;
670           result->appendChild(c, exception_state);
671         } else {
672           result = c;
673         }
674       }
675       if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
676         To<CharacterData>(container)->deleteData(
677             start_offset, end_offset - start_offset, exception_state);
678       break;
679     case Node::kElementNode:
680     case Node::kAttributeNode:
681     case Node::kDocumentNode:
682     case Node::kDocumentTypeNode:
683     case Node::kDocumentFragmentNode:
684       // FIXME: Should we assert that some nodes never appear here?
685       if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
686         if (fragment)
687           result = fragment;
688         else
689           result = container->cloneNode(false);
690       }
691 
692       Node* n = container->firstChild();
693       NodeVector nodes;
694       for (unsigned i = start_offset; n && i; i--)
695         n = n->nextSibling();
696       for (unsigned i = start_offset; n && i < end_offset;
697            i++, n = n->nextSibling())
698         nodes.push_back(n);
699 
700       ProcessNodes(action, nodes, container, result, exception_state);
701       break;
702   }
703 
704   return result;
705 }
706 
ProcessNodes(ActionType action,NodeVector & nodes,Node * old_container,Node * new_container,ExceptionState & exception_state)707 void Range::ProcessNodes(ActionType action,
708                          NodeVector& nodes,
709                          Node* old_container,
710                          Node* new_container,
711                          ExceptionState& exception_state) {
712   for (auto& node : nodes) {
713     switch (action) {
714       case DELETE_CONTENTS:
715         old_container->removeChild(node.Get(), exception_state);
716         break;
717       case EXTRACT_CONTENTS:
718         new_container->appendChild(
719             node.Release(), exception_state);  // Will remove n from its parent.
720         break;
721       case CLONE_CONTENTS:
722         new_container->appendChild(node->cloneNode(true), exception_state);
723         break;
724     }
725   }
726 }
727 
ProcessAncestorsAndTheirSiblings(ActionType action,Node * container,ContentsProcessDirection direction,Node * cloned_container,Node * common_root,ExceptionState & exception_state)728 Node* Range::ProcessAncestorsAndTheirSiblings(
729     ActionType action,
730     Node* container,
731     ContentsProcessDirection direction,
732     Node* cloned_container,
733     Node* common_root,
734     ExceptionState& exception_state) {
735   NodeVector ancestors;
736   for (Node& runner : NodeTraversal::AncestorsOf(*container)) {
737     if (runner == common_root)
738       break;
739     ancestors.push_back(runner);
740   }
741 
742   Node* first_child_in_ancestor_to_process =
743       direction == kProcessContentsForward ? container->nextSibling()
744                                            : container->previousSibling();
745   for (const auto& ancestor : ancestors) {
746     if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
747       // Might have been removed already during mutation event.
748       if (Node* cloned_ancestor = ancestor->cloneNode(false)) {
749         cloned_ancestor->appendChild(cloned_container, exception_state);
750         cloned_container = cloned_ancestor;
751       }
752     }
753 
754     // Copy siblings of an ancestor of start/end containers
755     // FIXME: This assertion may fail if DOM is modified during mutation event
756     // FIXME: Share code with Range::processNodes
757     DCHECK(!first_child_in_ancestor_to_process ||
758            first_child_in_ancestor_to_process->parentNode() == ancestor);
759 
760     NodeVector nodes;
761     for (Node* child = first_child_in_ancestor_to_process; child;
762          child = (direction == kProcessContentsForward)
763                      ? child->nextSibling()
764                      : child->previousSibling())
765       nodes.push_back(child);
766 
767     for (const auto& node : nodes) {
768       Node* child = node.Get();
769       switch (action) {
770         case DELETE_CONTENTS:
771           // Prior call of ancestor->removeChild() may cause a tree change due
772           // to DOMSubtreeModified event.  Therefore, we need to make sure
773           // |ancestor| is still |child|'s parent.
774           if (ancestor == child->parentNode())
775             ancestor->removeChild(child, exception_state);
776           break;
777         case EXTRACT_CONTENTS:  // will remove child from ancestor
778           if (direction == kProcessContentsForward)
779             cloned_container->appendChild(child, exception_state);
780           else
781             cloned_container->insertBefore(
782                 child, cloned_container->firstChild(), exception_state);
783           break;
784         case CLONE_CONTENTS:
785           if (direction == kProcessContentsForward)
786             cloned_container->appendChild(child->cloneNode(true),
787                                           exception_state);
788           else
789             cloned_container->insertBefore(child->cloneNode(true),
790                                            cloned_container->firstChild(),
791                                            exception_state);
792           break;
793       }
794     }
795     first_child_in_ancestor_to_process = direction == kProcessContentsForward
796                                              ? ancestor->nextSibling()
797                                              : ancestor->previousSibling();
798   }
799 
800   return cloned_container;
801 }
802 
extractContents(ExceptionState & exception_state)803 DocumentFragment* Range::extractContents(ExceptionState& exception_state) {
804   CheckExtractPrecondition(exception_state);
805   if (exception_state.HadException())
806     return nullptr;
807 
808   EventQueueScope scope;
809   DocumentFragment* fragment = ProcessContents(EXTRACT_CONTENTS,
810                                                exception_state);
811   // |extractContents| has extended attributes [NewObject, DoNotTestNewObject],
812   // so it's better to have a test that exercises the following condition:
813   //
814   //   !fragment || DOMDataStore::GetWrapper(fragment, isolate).IsEmpty()
815   //
816   // however, there is no access to |isolate| so far.  So, we simply omit the
817   // test so far.
818   return fragment;
819 }
820 
cloneContents(ExceptionState & exception_state)821 DocumentFragment* Range::cloneContents(ExceptionState& exception_state) {
822   return ProcessContents(CLONE_CONTENTS, exception_state);
823 }
824 
825 // https://dom.spec.whatwg.org/#concept-range-insert
insertNode(Node * new_node,ExceptionState & exception_state)826 void Range::insertNode(Node* new_node, ExceptionState& exception_state) {
827   if (!new_node) {
828     // FIXME: Generated bindings code never calls with null, and neither should
829     // other callers!
830     exception_state.ThrowTypeError("The node provided is null.");
831     return;
832   }
833 
834   // 1. If range’s start node is a ProcessingInstruction or Comment node, is a
835   // Text node whose parent is null, or is node, then throw a
836   // HierarchyRequestError.
837   Node& start_node = start_.Container();
838   if (start_node.getNodeType() == Node::kProcessingInstructionNode ||
839       start_node.getNodeType() == Node::kCommentNode) {
840     exception_state.ThrowDOMException(
841         DOMExceptionCode::kHierarchyRequestError,
842         "Nodes of type '" + new_node->nodeName() +
843             "' may not be inserted inside nodes of type '" +
844             start_node.nodeName() + "'.");
845     return;
846   }
847   const bool start_is_text = start_node.IsTextNode();
848   if (start_is_text && !start_node.parentNode()) {
849     exception_state.ThrowDOMException(DOMExceptionCode::kHierarchyRequestError,
850                                       "This operation would split a text node, "
851                                       "but there's no parent into which to "
852                                       "insert.");
853     return;
854   }
855   if (start_node == new_node) {
856     exception_state.ThrowDOMException(
857         DOMExceptionCode::kHierarchyRequestError,
858         "Unable to insert a node into a Range starting from the node itself.");
859     return;
860   }
861 
862   // According to the specification, the following condition is checked in the
863   // step 6. However our EnsurePreInsertionValidity() supports only
864   // ContainerNode parent.
865   if (start_node.IsAttributeNode()) {
866     exception_state.ThrowDOMException(
867         DOMExceptionCode::kHierarchyRequestError,
868         "Nodes of type '" + new_node->nodeName() +
869             "' may not be inserted inside nodes of type 'Attr'.");
870     return;
871   }
872 
873   // 2. Let referenceNode be null.
874   Node* reference_node = nullptr;
875   // 3. If range’s start node is a Text node, set referenceNode to that Text
876   // node.
877   // 4. Otherwise, set referenceNode to the child of start node whose index is
878   // start offset, and null if there is no such child.
879   if (start_is_text)
880     reference_node = &start_node;
881   else
882     reference_node = NodeTraversal::ChildAt(start_node, start_.Offset());
883 
884   // 5. Let parent be range’s start node if referenceNode is null, and
885   // referenceNode’s parent otherwise.
886   ContainerNode& parent = reference_node ? *reference_node->parentNode()
887                                          : To<ContainerNode>(start_node);
888 
889   // 6. Ensure pre-insertion validity of node into parent before referenceNode.
890   if (!parent.EnsurePreInsertionValidity(*new_node, reference_node, nullptr,
891                                          exception_state))
892     return;
893 
894   EventQueueScope scope;
895   // 7. If range's start node is a Text node, set referenceNode to the result of
896   // splitting it with offset range’s start offset.
897   if (start_is_text) {
898     reference_node =
899         To<Text>(start_node).splitText(start_.Offset(), exception_state);
900     if (exception_state.HadException())
901       return;
902   }
903 
904   // 8. If node is referenceNode, set referenceNode to its next sibling.
905   if (new_node == reference_node)
906     reference_node = reference_node->nextSibling();
907 
908   // 9. If node's parent is not null, remove node from its parent.
909   if (new_node->parentNode()) {
910     new_node->remove(exception_state);
911     if (exception_state.HadException())
912       return;
913   }
914 
915   // 10. Let newOffset be parent's length if referenceNode is null, and
916   // referenceNode's index otherwise.
917   unsigned new_offset =
918       reference_node ? reference_node->NodeIndex() : LengthOfContents(&parent);
919 
920   // 11. Increase newOffset by node's length if node is a DocumentFragment node,
921   // and one otherwise.
922   new_offset += new_node->IsDocumentFragment() ? LengthOfContents(new_node) : 1;
923 
924   // 12. Pre-insert node into parent before referenceNode.
925   parent.insertBefore(new_node, reference_node, exception_state);
926   if (exception_state.HadException())
927     return;
928 
929   // 13. If range's start and end are the same, set range's end to (parent,
930   // newOffset).
931   if (start_ == end_)
932     setEnd(&parent, new_offset, exception_state);
933 }
934 
toString() const935 String Range::toString() const {
936   StringBuilder builder;
937 
938   Node* past_last = PastLastNode();
939   for (Node* n = FirstNode(); n != past_last; n = NodeTraversal::Next(*n)) {
940     Node::NodeType type = n->getNodeType();
941     if (type == Node::kTextNode || type == Node::kCdataSectionNode) {
942       String data = To<CharacterData>(n)->data();
943       unsigned length = data.length();
944       unsigned start =
945           (n == start_.Container()) ? std::min(start_.Offset(), length) : 0;
946       unsigned end = (n == end_.Container())
947                          ? std::min(std::max(start, end_.Offset()), length)
948                          : length;
949       builder.Append(data, start, end - start);
950     }
951   }
952 
953   return builder.ToString();
954 }
955 
GetText() const956 String Range::GetText() const {
957   DCHECK(!owner_document_->NeedsLayoutTreeUpdate());
958   return PlainText(EphemeralRange(this),
959                    TextIteratorBehavior::Builder()
960                        .SetEmitsObjectReplacementCharacter(true)
961                        .Build());
962 }
963 
createContextualFragment(const String & markup,ExceptionState & exception_state)964 DocumentFragment* Range::createContextualFragment(
965     const String& markup,
966     ExceptionState& exception_state) {
967   // Algorithm:
968   // http://domparsing.spec.whatwg.org/#extensions-to-the-range-interface
969 
970   DCHECK(!markup.IsNull());
971 
972   Node* node = &start_.Container();
973 
974   // Step 1.
975   Element* element;
976   if (!start_.Offset() &&
977       (node->IsDocumentNode() || node->IsDocumentFragment()))
978     element = nullptr;
979   else if (auto* node_element = DynamicTo<Element>(node))
980     element = node_element;
981   else
982     element = node->parentElement();
983 
984   // Step 2.
985   if (!element || IsA<HTMLHtmlElement>(element)) {
986     Document& document = node->GetDocument();
987 
988     if (document.IsSVGDocument()) {
989       element = document.documentElement();
990       if (!element)
991         element = MakeGarbageCollected<SVGSVGElement>(document);
992     } else {
993       // Optimization over spec: try to reuse the existing <body> element, if it
994       // is available.
995       element = document.body();
996       if (!element)
997         element = MakeGarbageCollected<HTMLBodyElement>(document);
998     }
999   }
1000 
1001   // Steps 3, 4, 5.
1002   return blink::CreateContextualFragment(
1003       markup, element, kAllowScriptingContentAndDoNotMarkAlreadyStarted,
1004       exception_state);
1005 }
1006 
detach()1007 void Range::detach() {
1008   // This is now a no-op as per the DOM specification.
1009 }
1010 
CheckNodeWOffset(Node * n,unsigned offset,ExceptionState & exception_state)1011 Node* Range::CheckNodeWOffset(Node* n,
1012                               unsigned offset,
1013                               ExceptionState& exception_state) {
1014   switch (n->getNodeType()) {
1015     case Node::kDocumentTypeNode:
1016       exception_state.ThrowDOMException(
1017           DOMExceptionCode::kInvalidNodeTypeError,
1018           "The node provided is of type '" + n->nodeName() + "'.");
1019       return nullptr;
1020     case Node::kCdataSectionNode:
1021     case Node::kCommentNode:
1022     case Node::kTextNode:
1023       if (offset > To<CharacterData>(n)->length()) {
1024         exception_state.ThrowDOMException(
1025             DOMExceptionCode::kIndexSizeError,
1026             "The offset " + String::Number(offset) +
1027                 " is larger than the node's length (" +
1028                 String::Number(To<CharacterData>(n)->length()) + ").");
1029       } else if (offset >
1030                  static_cast<unsigned>(std::numeric_limits<int>::max())) {
1031         exception_state.ThrowDOMException(
1032             DOMExceptionCode::kIndexSizeError,
1033             "The offset " + String::Number(offset) + " is invalid.");
1034       }
1035       return nullptr;
1036     case Node::kProcessingInstructionNode:
1037       if (offset > To<ProcessingInstruction>(n)->data().length()) {
1038         exception_state.ThrowDOMException(
1039             DOMExceptionCode::kIndexSizeError,
1040             "The offset " + String::Number(offset) +
1041                 " is larger than the node's length (" +
1042                 String::Number(To<ProcessingInstruction>(n)->data().length()) +
1043                 ").");
1044       } else if (offset >
1045                  static_cast<unsigned>(std::numeric_limits<int>::max())) {
1046         exception_state.ThrowDOMException(
1047             DOMExceptionCode::kIndexSizeError,
1048             "The offset " + String::Number(offset) + " is invalid.");
1049       }
1050       return nullptr;
1051     case Node::kAttributeNode:
1052     case Node::kDocumentFragmentNode:
1053     case Node::kDocumentNode:
1054     case Node::kElementNode: {
1055       if (!offset)
1056         return nullptr;
1057       if (offset > static_cast<unsigned>(std::numeric_limits<int>::max())) {
1058         exception_state.ThrowDOMException(
1059             DOMExceptionCode::kIndexSizeError,
1060             "The offset " + String::Number(offset) + " is invalid.");
1061         return nullptr;
1062       }
1063       Node* child_before = NodeTraversal::ChildAt(*n, offset - 1);
1064       if (!child_before) {
1065         exception_state.ThrowDOMException(
1066             DOMExceptionCode::kIndexSizeError,
1067             "There is no child at offset " + String::Number(offset) + ".");
1068       }
1069       return child_before;
1070     }
1071   }
1072   NOTREACHED();
1073   return nullptr;
1074 }
1075 
CheckNodeBA(Node * n,ExceptionState & exception_state) const1076 void Range::CheckNodeBA(Node* n, ExceptionState& exception_state) const {
1077   if (!n) {
1078     // FIXME: Generated bindings code never calls with null, and neither should
1079     // other callers!
1080     exception_state.ThrowTypeError("The node provided is null.");
1081     return;
1082   }
1083 
1084   // InvalidNodeTypeError: Raised if the root container of refNode is not an
1085   // Attr, Document, DocumentFragment or ShadowRoot node, or part of a SVG
1086   // shadow DOM tree, or if refNode is a Document, DocumentFragment, ShadowRoot,
1087   // Attr, Entity, or Notation node.
1088 
1089   if (!n->parentNode()) {
1090     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidNodeTypeError,
1091                                       "the given Node has no parent.");
1092     return;
1093   }
1094 
1095   switch (n->getNodeType()) {
1096     case Node::kAttributeNode:
1097     case Node::kDocumentFragmentNode:
1098     case Node::kDocumentNode:
1099       exception_state.ThrowDOMException(
1100           DOMExceptionCode::kInvalidNodeTypeError,
1101           "The node provided is of type '" + n->nodeName() + "'.");
1102       return;
1103     case Node::kCdataSectionNode:
1104     case Node::kCommentNode:
1105     case Node::kDocumentTypeNode:
1106     case Node::kElementNode:
1107     case Node::kProcessingInstructionNode:
1108     case Node::kTextNode:
1109       break;
1110   }
1111 
1112   Node* root = n;
1113   while (ContainerNode* parent = root->parentNode())
1114     root = parent;
1115 
1116   switch (root->getNodeType()) {
1117     case Node::kAttributeNode:
1118     case Node::kDocumentNode:
1119     case Node::kDocumentFragmentNode:
1120     case Node::kElementNode:
1121       break;
1122     case Node::kCdataSectionNode:
1123     case Node::kCommentNode:
1124     case Node::kDocumentTypeNode:
1125     case Node::kProcessingInstructionNode:
1126     case Node::kTextNode:
1127       exception_state.ThrowDOMException(
1128           DOMExceptionCode::kInvalidNodeTypeError,
1129           "The node provided is of type '" + n->nodeName() + "'.");
1130       return;
1131   }
1132 }
1133 
cloneRange() const1134 Range* Range::cloneRange() const {
1135   return MakeGarbageCollected<Range>(*owner_document_.Get(),
1136                                      &start_.Container(), start_.Offset(),
1137                                      &end_.Container(), end_.Offset());
1138 }
1139 
setStartAfter(Node * ref_node,ExceptionState & exception_state)1140 void Range::setStartAfter(Node* ref_node, ExceptionState& exception_state) {
1141   CheckNodeBA(ref_node, exception_state);
1142   if (exception_state.HadException())
1143     return;
1144 
1145   setStart(ref_node->parentNode(), ref_node->NodeIndex() + 1, exception_state);
1146 }
1147 
setEndBefore(Node * ref_node,ExceptionState & exception_state)1148 void Range::setEndBefore(Node* ref_node, ExceptionState& exception_state) {
1149   CheckNodeBA(ref_node, exception_state);
1150   if (exception_state.HadException())
1151     return;
1152 
1153   setEnd(ref_node->parentNode(), ref_node->NodeIndex(), exception_state);
1154 }
1155 
setEndAfter(Node * ref_node,ExceptionState & exception_state)1156 void Range::setEndAfter(Node* ref_node, ExceptionState& exception_state) {
1157   CheckNodeBA(ref_node, exception_state);
1158   if (exception_state.HadException())
1159     return;
1160 
1161   setEnd(ref_node->parentNode(), ref_node->NodeIndex() + 1, exception_state);
1162 }
1163 
selectNode(Node * ref_node,ExceptionState & exception_state)1164 void Range::selectNode(Node* ref_node, ExceptionState& exception_state) {
1165   if (!ref_node) {
1166     // FIXME: Generated bindings code never calls with null, and neither should
1167     // other callers!
1168     exception_state.ThrowTypeError("The node provided is null.");
1169     return;
1170   }
1171 
1172   if (!ref_node->parentNode()) {
1173     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidNodeTypeError,
1174                                       "the given Node has no parent.");
1175     return;
1176   }
1177 
1178   switch (ref_node->getNodeType()) {
1179     case Node::kCdataSectionNode:
1180     case Node::kCommentNode:
1181     case Node::kDocumentTypeNode:
1182     case Node::kElementNode:
1183     case Node::kProcessingInstructionNode:
1184     case Node::kTextNode:
1185       break;
1186     case Node::kAttributeNode:
1187     case Node::kDocumentFragmentNode:
1188     case Node::kDocumentNode:
1189       exception_state.ThrowDOMException(
1190           DOMExceptionCode::kInvalidNodeTypeError,
1191           "The node provided is of type '" + ref_node->nodeName() + "'.");
1192       return;
1193   }
1194 
1195   RangeUpdateScope scope(this);
1196   setStartBefore(ref_node);
1197   setEndAfter(ref_node);
1198 }
1199 
selectNodeContents(Node * ref_node,ExceptionState & exception_state)1200 void Range::selectNodeContents(Node* ref_node,
1201                                ExceptionState& exception_state) {
1202   if (!ref_node) {
1203     // FIXME: Generated bindings code never calls with null, and neither should
1204     // other callers!
1205     exception_state.ThrowTypeError("The node provided is null.");
1206     return;
1207   }
1208 
1209   // InvalidNodeTypeError: Raised if refNode or an ancestor of refNode is an
1210   // Entity, Notation
1211   // or DocumentType node.
1212   for (Node* n = ref_node; n; n = n->parentNode()) {
1213     switch (n->getNodeType()) {
1214       case Node::kAttributeNode:
1215       case Node::kCdataSectionNode:
1216       case Node::kCommentNode:
1217       case Node::kDocumentFragmentNode:
1218       case Node::kDocumentNode:
1219       case Node::kElementNode:
1220       case Node::kProcessingInstructionNode:
1221       case Node::kTextNode:
1222         break;
1223       case Node::kDocumentTypeNode:
1224         exception_state.ThrowDOMException(
1225             DOMExceptionCode::kInvalidNodeTypeError,
1226             "The node provided is of type '" + ref_node->nodeName() + "'.");
1227         return;
1228     }
1229   }
1230 
1231   RangeUpdateScope scope(this);
1232   if (owner_document_ != ref_node->GetDocument())
1233     SetDocument(ref_node->GetDocument());
1234 
1235   start_.SetToStartOfNode(*ref_node);
1236   end_.SetToEndOfNode(*ref_node);
1237 }
1238 
selectNodeContents(Node * ref_node,Position & start,Position & end)1239 bool Range::selectNodeContents(Node* ref_node, Position& start, Position& end) {
1240   if (!ref_node) {
1241     return false;
1242   }
1243 
1244   for (Node* n = ref_node; n; n = n->parentNode()) {
1245     switch (n->getNodeType()) {
1246       case Node::kAttributeNode:
1247       case Node::kCdataSectionNode:
1248       case Node::kCommentNode:
1249       case Node::kDocumentFragmentNode:
1250       case Node::kDocumentNode:
1251       case Node::kElementNode:
1252       case Node::kProcessingInstructionNode:
1253       case Node::kTextNode:
1254         break;
1255       case Node::kDocumentTypeNode:
1256         return false;
1257     }
1258   }
1259 
1260   RangeBoundaryPoint start_boundary_point(*ref_node);
1261   start_boundary_point.SetToStartOfNode(*ref_node);
1262   start = start_boundary_point.ToPosition();
1263   RangeBoundaryPoint end_boundary_point(*ref_node);
1264   end_boundary_point.SetToEndOfNode(*ref_node);
1265   end = end_boundary_point.ToPosition();
1266   return true;
1267 }
1268 
1269 // https://dom.spec.whatwg.org/#dom-range-surroundcontents
surroundContents(Node * new_parent,ExceptionState & exception_state)1270 void Range::surroundContents(Node* new_parent,
1271                              ExceptionState& exception_state) {
1272   if (!new_parent) {
1273     // FIXME: Generated bindings code never calls with null, and neither should
1274     // other callers!
1275     exception_state.ThrowTypeError("The node provided is null.");
1276     return;
1277   }
1278 
1279   // 1. If a non-Text node is partially contained in the context object, then
1280   // throw an InvalidStateError.
1281   Node* start_non_text_container = &start_.Container();
1282   if (start_non_text_container->getNodeType() == Node::kTextNode)
1283     start_non_text_container = start_non_text_container->parentNode();
1284   Node* end_non_text_container = &end_.Container();
1285   if (end_non_text_container->getNodeType() == Node::kTextNode)
1286     end_non_text_container = end_non_text_container->parentNode();
1287   if (start_non_text_container != end_non_text_container) {
1288     exception_state.ThrowDOMException(
1289         DOMExceptionCode::kInvalidStateError,
1290         "The Range has partially selected a non-Text node.");
1291     return;
1292   }
1293 
1294   // 2. If newParent is a Document, DocumentType, or DocumentFragment node, then
1295   // throw an InvalidNodeTypeError.
1296   switch (new_parent->getNodeType()) {
1297     case Node::kAttributeNode:
1298     case Node::kDocumentFragmentNode:
1299     case Node::kDocumentNode:
1300     case Node::kDocumentTypeNode:
1301       exception_state.ThrowDOMException(
1302           DOMExceptionCode::kInvalidNodeTypeError,
1303           "The node provided is of type '" + new_parent->nodeName() + "'.");
1304       return;
1305     case Node::kCdataSectionNode:
1306     case Node::kCommentNode:
1307     case Node::kElementNode:
1308     case Node::kProcessingInstructionNode:
1309     case Node::kTextNode:
1310       break;
1311   }
1312 
1313   EventQueueScope scope;
1314 
1315   // 3. Let fragment be the result of extracting context object.
1316   DocumentFragment* fragment = extractContents(exception_state);
1317   if (exception_state.HadException())
1318     return;
1319 
1320   // 4. If newParent has children, replace all with null within newParent.
1321   while (Node* n = new_parent->firstChild()) {
1322     To<ContainerNode>(new_parent)->RemoveChild(n, exception_state);
1323     if (exception_state.HadException())
1324       return;
1325   }
1326 
1327   // 5. If newParent has children, replace all with null within newParent.
1328   insertNode(new_parent, exception_state);
1329   if (exception_state.HadException())
1330     return;
1331 
1332   // 6. Append fragment to newParent.
1333   new_parent->appendChild(fragment, exception_state);
1334   if (exception_state.HadException())
1335     return;
1336 
1337   // 7. Select newParent within context object.
1338   selectNode(new_parent, exception_state);
1339 }
1340 
setStartBefore(Node * ref_node,ExceptionState & exception_state)1341 void Range::setStartBefore(Node* ref_node, ExceptionState& exception_state) {
1342   CheckNodeBA(ref_node, exception_state);
1343   if (exception_state.HadException())
1344     return;
1345 
1346   setStart(ref_node->parentNode(), ref_node->NodeIndex(), exception_state);
1347 }
1348 
CheckExtractPrecondition(ExceptionState & exception_state)1349 void Range::CheckExtractPrecondition(ExceptionState& exception_state) {
1350   DCHECK(BoundaryPointsValid());
1351 
1352   if (!commonAncestorContainer())
1353     return;
1354 
1355   Node* past_last = PastLastNode();
1356   for (Node* n = FirstNode(); n != past_last; n = NodeTraversal::Next(*n)) {
1357     if (n->IsDocumentTypeNode()) {
1358       exception_state.ThrowDOMException(
1359           DOMExceptionCode::kHierarchyRequestError,
1360           "The Range contains a doctype node.");
1361       return;
1362     }
1363   }
1364 }
1365 
FirstNode() const1366 Node* Range::FirstNode() const {
1367   return StartPosition().NodeAsRangeFirstNode();
1368 }
1369 
PastLastNode() const1370 Node* Range::PastLastNode() const {
1371   return EndPosition().NodeAsRangePastLastNode();
1372 }
1373 
BoundingBox() const1374 IntRect Range::BoundingBox() const {
1375   return ComputeTextRect(EphemeralRange(this));
1376 }
1377 
AreRangesEqual(const Range * a,const Range * b)1378 bool AreRangesEqual(const Range* a, const Range* b) {
1379   if (a == b)
1380     return true;
1381   if (!a || !b)
1382     return false;
1383   return a->StartPosition() == b->StartPosition() &&
1384          a->EndPosition() == b->EndPosition();
1385 }
1386 
BoundaryNodeChildrenWillBeRemoved(RangeBoundaryPoint & boundary,ContainerNode & container)1387 static inline void BoundaryNodeChildrenWillBeRemoved(
1388     RangeBoundaryPoint& boundary,
1389     ContainerNode& container) {
1390   for (Node* node_to_be_removed = container.firstChild(); node_to_be_removed;
1391        node_to_be_removed = node_to_be_removed->nextSibling()) {
1392     if (boundary.ChildBefore() == node_to_be_removed) {
1393       boundary.SetToStartOfNode(container);
1394       return;
1395     }
1396 
1397     for (Node* n = &boundary.Container(); n; n = n->parentNode()) {
1398       if (n == node_to_be_removed) {
1399         boundary.SetToStartOfNode(container);
1400         return;
1401       }
1402     }
1403   }
1404 }
1405 
BoundaryShadowNodeChildrenWillBeRemoved(RangeBoundaryPoint & boundary,ContainerNode & container)1406 static void BoundaryShadowNodeChildrenWillBeRemoved(
1407     RangeBoundaryPoint& boundary,
1408     ContainerNode& container) {
1409   for (Node* node_to_be_removed = container.firstChild(); node_to_be_removed;
1410        node_to_be_removed = node_to_be_removed->nextSibling()) {
1411     for (Node* n = &boundary.Container(); n;
1412          n = n->ParentOrShadowHostElement()) {
1413       if (n == node_to_be_removed) {
1414         boundary.SetToStartOfNode(container);
1415         return;
1416       }
1417     }
1418   }
1419 }
1420 
NodeChildrenWillBeRemoved(ContainerNode & container)1421 void Range::NodeChildrenWillBeRemoved(ContainerNode& container) {
1422   DCHECK_EQ(container.GetDocument(), owner_document_);
1423   BoundaryNodeChildrenWillBeRemoved(start_, container);
1424   BoundaryNodeChildrenWillBeRemoved(end_, container);
1425 }
1426 
FixupRemovedChildrenAcrossShadowBoundary(ContainerNode & container)1427 void Range::FixupRemovedChildrenAcrossShadowBoundary(ContainerNode& container) {
1428   DCHECK_EQ(container.GetDocument(), owner_document_);
1429   BoundaryShadowNodeChildrenWillBeRemoved(start_, container);
1430   BoundaryShadowNodeChildrenWillBeRemoved(end_, container);
1431 }
1432 
BoundaryNodeWillBeRemoved(RangeBoundaryPoint & boundary,Node & node_to_be_removed)1433 static inline void BoundaryNodeWillBeRemoved(RangeBoundaryPoint& boundary,
1434                                              Node& node_to_be_removed) {
1435   if (boundary.ChildBefore() == node_to_be_removed) {
1436     boundary.ChildBeforeWillBeRemoved();
1437     return;
1438   }
1439 
1440   for (Node* n = &boundary.Container(); n; n = n->parentNode()) {
1441     if (n == node_to_be_removed) {
1442       boundary.SetToBeforeChild(node_to_be_removed);
1443       return;
1444     }
1445   }
1446 }
1447 
BoundaryShadowNodeWillBeRemoved(RangeBoundaryPoint & boundary,Node & node_to_be_removed)1448 static inline void BoundaryShadowNodeWillBeRemoved(RangeBoundaryPoint& boundary,
1449                                                    Node& node_to_be_removed) {
1450   DCHECK_NE(boundary.ChildBefore(), node_to_be_removed);
1451 
1452   for (Node* node = &boundary.Container(); node;
1453        node = node->ParentOrShadowHostElement()) {
1454     if (node == node_to_be_removed) {
1455       boundary.SetToBeforeChild(node_to_be_removed);
1456       return;
1457     }
1458   }
1459 }
1460 
NodeWillBeRemoved(Node & node)1461 void Range::NodeWillBeRemoved(Node& node) {
1462   DCHECK_EQ(node.GetDocument(), owner_document_);
1463   DCHECK_NE(node, owner_document_.Get());
1464 
1465   // FIXME: Once DOMNodeRemovedFromDocument mutation event removed, we
1466   // should change following if-statement to DCHECK(!node->parentNode).
1467   if (!node.parentNode())
1468     return;
1469   BoundaryNodeWillBeRemoved(start_, node);
1470   BoundaryNodeWillBeRemoved(end_, node);
1471 }
1472 
FixupRemovedNodeAcrossShadowBoundary(Node & node)1473 void Range::FixupRemovedNodeAcrossShadowBoundary(Node& node) {
1474   BoundaryShadowNodeWillBeRemoved(start_, node);
1475   BoundaryShadowNodeWillBeRemoved(end_, node);
1476 }
1477 
BoundaryTextInserted(RangeBoundaryPoint & boundary,const CharacterData & text,unsigned offset,unsigned length)1478 static inline void BoundaryTextInserted(RangeBoundaryPoint& boundary,
1479                                         const CharacterData& text,
1480                                         unsigned offset,
1481                                         unsigned length) {
1482   if (boundary.Container() != &text)
1483     return;
1484   boundary.MarkValid();
1485   unsigned boundary_offset = boundary.Offset();
1486   if (offset >= boundary_offset)
1487     return;
1488   boundary.SetOffset(boundary_offset + length);
1489 }
1490 
DidInsertText(const CharacterData & text,unsigned offset,unsigned length)1491 void Range::DidInsertText(const CharacterData& text,
1492                           unsigned offset,
1493                           unsigned length) {
1494   DCHECK_EQ(text.GetDocument(), owner_document_);
1495   BoundaryTextInserted(start_, text, offset, length);
1496   BoundaryTextInserted(end_, text, offset, length);
1497 }
1498 
BoundaryTextRemoved(RangeBoundaryPoint & boundary,const CharacterData & text,unsigned offset,unsigned length)1499 static inline void BoundaryTextRemoved(RangeBoundaryPoint& boundary,
1500                                        const CharacterData& text,
1501                                        unsigned offset,
1502                                        unsigned length) {
1503   if (boundary.Container() != &text)
1504     return;
1505   boundary.MarkValid();
1506   unsigned boundary_offset = boundary.Offset();
1507   if (offset >= boundary_offset)
1508     return;
1509   if (offset + length >= boundary_offset)
1510     boundary.SetOffset(offset);
1511   else
1512     boundary.SetOffset(boundary_offset - length);
1513 }
1514 
DidRemoveText(const CharacterData & text,unsigned offset,unsigned length)1515 void Range::DidRemoveText(const CharacterData& text,
1516                           unsigned offset,
1517                           unsigned length) {
1518   DCHECK_EQ(text.GetDocument(), owner_document_);
1519   BoundaryTextRemoved(start_, text, offset, length);
1520   BoundaryTextRemoved(end_, text, offset, length);
1521 }
1522 
BoundaryTextNodesMerged(RangeBoundaryPoint & boundary,const NodeWithIndex & old_node,unsigned offset)1523 static inline void BoundaryTextNodesMerged(RangeBoundaryPoint& boundary,
1524                                            const NodeWithIndex& old_node,
1525                                            unsigned offset) {
1526   if (boundary.Container() == old_node.GetNode()) {
1527     Node* const previous_sibling = old_node.GetNode().previousSibling();
1528     DCHECK(previous_sibling);
1529     boundary.Set(*previous_sibling, boundary.Offset() + offset, nullptr);
1530   } else if (boundary.Container() == old_node.GetNode().parentNode() &&
1531              boundary.Offset() == static_cast<unsigned>(old_node.Index())) {
1532     Node* const previous_sibling = old_node.GetNode().previousSibling();
1533     DCHECK(previous_sibling);
1534     boundary.Set(*previous_sibling, offset, nullptr);
1535   }
1536 }
1537 
DidMergeTextNodes(const NodeWithIndex & old_node,unsigned offset)1538 void Range::DidMergeTextNodes(const NodeWithIndex& old_node, unsigned offset) {
1539   DCHECK_EQ(old_node.GetNode().GetDocument(), owner_document_);
1540   DCHECK(old_node.GetNode().parentNode());
1541   DCHECK(old_node.GetNode().IsTextNode());
1542   DCHECK(old_node.GetNode().previousSibling());
1543   DCHECK(old_node.GetNode().previousSibling()->IsTextNode());
1544   BoundaryTextNodesMerged(start_, old_node, offset);
1545   BoundaryTextNodesMerged(end_, old_node, offset);
1546 }
1547 
UpdateOwnerDocumentIfNeeded()1548 void Range::UpdateOwnerDocumentIfNeeded() {
1549   Document& new_document = start_.Container().GetDocument();
1550   DCHECK_EQ(new_document, end_.Container().GetDocument());
1551   if (new_document == owner_document_)
1552     return;
1553   owner_document_->DetachRange(this);
1554   owner_document_ = &new_document;
1555   owner_document_->AttachRange(this);
1556 }
1557 
BoundaryTextNodeSplit(RangeBoundaryPoint & boundary,const Text & old_node)1558 static inline void BoundaryTextNodeSplit(RangeBoundaryPoint& boundary,
1559                                          const Text& old_node) {
1560   unsigned boundary_offset = boundary.Offset();
1561   if (boundary.ChildBefore() == &old_node) {
1562     boundary.Set(boundary.Container(), boundary_offset + 1,
1563                  old_node.nextSibling());
1564   } else if (boundary.Container() == &old_node &&
1565              boundary_offset > old_node.length()) {
1566     Node* const next_sibling = old_node.nextSibling();
1567     DCHECK(next_sibling);
1568     boundary.Set(*next_sibling, boundary_offset - old_node.length(), nullptr);
1569   }
1570 }
1571 
DidSplitTextNode(const Text & old_node)1572 void Range::DidSplitTextNode(const Text& old_node) {
1573   DCHECK_EQ(old_node.GetDocument(), owner_document_);
1574   DCHECK(old_node.parentNode());
1575   DCHECK(old_node.nextSibling());
1576   DCHECK(old_node.nextSibling()->IsTextNode());
1577   BoundaryTextNodeSplit(start_, old_node);
1578   BoundaryTextNodeSplit(end_, old_node);
1579   DCHECK(BoundaryPointsValid());
1580 }
1581 
expand(const String & unit,ExceptionState & exception_state)1582 void Range::expand(const String& unit, ExceptionState& exception_state) {
1583   if (!StartPosition().IsConnected() || !EndPosition().IsConnected())
1584     return;
1585   owner_document_->UpdateStyleAndLayout(DocumentUpdateReason::kJavaScript);
1586   VisiblePosition start = CreateVisiblePosition(StartPosition());
1587   VisiblePosition end = CreateVisiblePosition(EndPosition());
1588   if (unit == "word") {
1589     start = CreateVisiblePosition(StartOfWordPosition(start.DeepEquivalent()));
1590     end = CreateVisiblePosition(EndOfWordPosition(end.DeepEquivalent()));
1591   } else if (unit == "sentence") {
1592     start =
1593         CreateVisiblePosition(StartOfSentencePosition(start.DeepEquivalent()));
1594     end = CreateVisiblePosition(EndOfSentence(end.DeepEquivalent()));
1595   } else if (unit == "block") {
1596     start = StartOfParagraph(start);
1597     end = EndOfParagraph(end);
1598   } else if (unit == "document") {
1599     start = StartOfDocument(start);
1600     end = EndOfDocument(end);
1601   } else {
1602     return;
1603   }
1604   setStart(start.DeepEquivalent().ComputeContainerNode(),
1605            start.DeepEquivalent().ComputeOffsetInContainerNode(),
1606            exception_state);
1607   setEnd(end.DeepEquivalent().ComputeContainerNode(),
1608          end.DeepEquivalent().ComputeOffsetInContainerNode(), exception_state);
1609 }
1610 
getClientRects() const1611 DOMRectList* Range::getClientRects() const {
1612   owner_document_->UpdateStyleAndLayout(DocumentUpdateReason::kJavaScript);
1613 
1614   Vector<FloatQuad> quads;
1615   GetBorderAndTextQuads(quads);
1616 
1617   return MakeGarbageCollected<DOMRectList>(quads);
1618 }
1619 
getBoundingClientRect() const1620 DOMRect* Range::getBoundingClientRect() const {
1621   return DOMRect::FromFloatRect(BoundingRect());
1622 }
1623 
1624 // TODO(editing-dev): We should make
1625 // |Document::AdjustFloatQuadsForScrollAndAbsoluteZoom()| as const function
1626 // and takes |const LayoutObject&|.
ComputeTextQuads(const Document & owner_document,const LayoutText & layout_text,unsigned start_offset,unsigned end_offset)1627 static Vector<FloatQuad> ComputeTextQuads(const Document& owner_document,
1628                                           const LayoutText& layout_text,
1629                                           unsigned start_offset,
1630                                           unsigned end_offset) {
1631   Vector<FloatQuad> text_quads;
1632   layout_text.AbsoluteQuadsForRange(text_quads, start_offset, end_offset);
1633   const_cast<Document&>(owner_document)
1634       .AdjustFloatQuadsForScrollAndAbsoluteZoom(
1635           text_quads, const_cast<LayoutText&>(layout_text));
1636   return text_quads;
1637 }
1638 
1639 // https://www.w3.org/TR/cssom-view-1/#dom-range-getclientrects
GetBorderAndTextQuads(Vector<FloatQuad> & quads) const1640 void Range::GetBorderAndTextQuads(Vector<FloatQuad>& quads) const {
1641   Node* start_container = &start_.Container();
1642   Node* end_container = &end_.Container();
1643   Node* stop_node = PastLastNode();
1644 
1645   // Stores the elements selected by the range.
1646   HeapHashSet<Member<const Node>> selected_elements;
1647   for (Node* node = FirstNode(); node != stop_node;
1648        node = NodeTraversal::Next(*node)) {
1649     if (!node->IsElementNode())
1650       continue;
1651     if (selected_elements.Contains(node->parentNode()) ||
1652         (!node->contains(start_container) && !node->contains(end_container))) {
1653       DCHECK_LE(StartPosition(), Position::BeforeNode(*node));
1654       DCHECK_GE(EndPosition(), Position::AfterNode(*node));
1655       selected_elements.insert(node);
1656     }
1657   }
1658 
1659   for (const Node* node = FirstNode(); node != stop_node;
1660        node = NodeTraversal::Next(*node)) {
1661     auto* element_node = DynamicTo<Element>(node);
1662     if (element_node) {
1663       if (!selected_elements.Contains(node) ||
1664           selected_elements.Contains(node->parentNode()))
1665         continue;
1666       LayoutObject* const layout_object = element_node->GetLayoutObject();
1667       if (!layout_object)
1668         continue;
1669       Vector<FloatQuad> element_quads;
1670       layout_object->AbsoluteQuads(element_quads);
1671       owner_document_->AdjustFloatQuadsForScrollAndAbsoluteZoom(element_quads,
1672                                                                 *layout_object);
1673 
1674       quads.AppendVector(element_quads);
1675       continue;
1676     }
1677 
1678     auto* const text_node = DynamicTo<Text>(node);
1679     if (!text_node)
1680       continue;
1681     LayoutText* const layout_text = text_node->GetLayoutObject();
1682     if (!layout_text)
1683       continue;
1684 
1685     // TODO(editing-dev): Offset in |LayoutText| doesn't match to DOM offset
1686     // when |text-transform| applied. We should map DOM offset to offset in
1687     // |LayouText| for |start_offset| and |end_offset|.
1688     const unsigned start_offset =
1689         (node == start_container) ? start_.Offset() : 0;
1690     const unsigned end_offset = (node == end_container)
1691                                     ? end_.Offset()
1692                                     : std::numeric_limits<unsigned>::max();
1693     if (!layout_text->IsTextFragment()) {
1694       quads.AppendVector(ComputeTextQuads(*owner_document_, *layout_text,
1695                                           start_offset, end_offset));
1696       continue;
1697     }
1698 
1699     // Handle ::first-letter
1700     const LayoutTextFragment& first_letter_part =
1701         *ToLayoutTextFragment(AssociatedLayoutObjectOf(*node, 0));
1702     const bool overlaps_with_first_letter =
1703         start_offset < first_letter_part.FragmentLength() ||
1704         (start_offset == first_letter_part.FragmentLength() &&
1705          end_offset == start_offset);
1706     if (overlaps_with_first_letter) {
1707       const unsigned start_in_first_letter = start_offset;
1708       const unsigned end_in_first_letter =
1709           std::min(end_offset, first_letter_part.FragmentLength());
1710       quads.AppendVector(ComputeTextQuads(*owner_document_, first_letter_part,
1711                                           start_in_first_letter,
1712                                           end_in_first_letter));
1713     }
1714     const LayoutTextFragment& remaining_part =
1715         *ToLayoutTextFragment(layout_text);
1716     if (end_offset > remaining_part.Start()) {
1717       const unsigned start_in_remaining_part =
1718           std::max(start_offset, remaining_part.Start()) -
1719           remaining_part.Start();
1720       // TODO(editing-dev): As we previously set |end_offset == UINT_MAX| as a
1721       // hacky support for |text-transform|, we need the same hack here.
1722       const unsigned end_in_remaining_part =
1723           end_offset == UINT_MAX ? end_offset
1724                                  : end_offset - remaining_part.Start();
1725       quads.AppendVector(ComputeTextQuads(*owner_document_, remaining_part,
1726                                           start_in_remaining_part,
1727                                           end_in_remaining_part));
1728     }
1729   }
1730 }
1731 
BoundingRect() const1732 FloatRect Range::BoundingRect() const {
1733   owner_document_->UpdateStyleAndLayout(DocumentUpdateReason::kJavaScript);
1734 
1735   Vector<FloatQuad> quads;
1736   GetBorderAndTextQuads(quads);
1737 
1738   FloatRect result;
1739   for (const FloatQuad& quad : quads)
1740     result.Unite(quad.BoundingBox());  // Skips empty rects.
1741 
1742   // If all rects are empty, return the first rect.
1743   if (result.IsEmpty() && !quads.IsEmpty())
1744     return quads.front().BoundingBox();
1745 
1746   return result;
1747 }
1748 
UpdateSelectionIfAddedToSelection()1749 void Range::UpdateSelectionIfAddedToSelection() {
1750   if (!OwnerDocument().GetFrame())
1751     return;
1752   FrameSelection& selection = OwnerDocument().GetFrame()->Selection();
1753   if (this != selection.DocumentCachedRange())
1754     return;
1755   DCHECK(startContainer()->isConnected());
1756   DCHECK(startContainer()->GetDocument() == OwnerDocument());
1757   DCHECK(endContainer()->isConnected());
1758   DCHECK(endContainer()->GetDocument() == OwnerDocument());
1759   EventDispatchForbiddenScope no_events;
1760   selection.SetSelection(SelectionInDOMTree::Builder()
1761                              .Collapse(StartPosition())
1762                              .Extend(EndPosition())
1763                              .Build(),
1764                          SetSelectionOptions::Builder()
1765                              .SetShouldCloseTyping(true)
1766                              .SetShouldClearTypingStyle(true)
1767                              .SetDoNotSetFocus(true)
1768                              .Build());
1769   selection.CacheRangeOfDocument(this);
1770 }
1771 
RemoveFromSelectionIfInDifferentRoot(Document & old_document)1772 void Range::RemoveFromSelectionIfInDifferentRoot(Document& old_document) {
1773   if (!old_document.GetFrame())
1774     return;
1775   FrameSelection& selection = old_document.GetFrame()->Selection();
1776   if (this != selection.DocumentCachedRange())
1777     return;
1778   if (OwnerDocument() == old_document && startContainer()->isConnected() &&
1779       endContainer()->isConnected())
1780     return;
1781   selection.Clear();
1782   selection.ClearDocumentCachedRange();
1783 }
1784 
Trace(Visitor * visitor)1785 void Range::Trace(Visitor* visitor) {
1786   visitor->Trace(owner_document_);
1787   visitor->Trace(start_);
1788   visitor->Trace(end_);
1789   ScriptWrappable::Trace(visitor);
1790 }
1791 
1792 }  // namespace blink
1793 
1794 #if DCHECK_IS_ON()
1795 
showTree(const blink::Range * range)1796 void showTree(const blink::Range* range) {
1797   if (range && range->BoundaryPointsValid()) {
1798     LOG(INFO) << "\n"
1799               << range->startContainer()
1800                      ->ToMarkedTreeString(range->startContainer(), "S",
1801                                           range->endContainer(), "E")
1802                      .Utf8()
1803               << "start offset: " << range->startOffset()
1804               << ", end offset: " << range->endOffset();
1805   } else {
1806     LOG(INFO) << "Cannot show tree if range is null, or if boundary points are "
1807                  "invalid.";
1808   }
1809 }
1810 
1811 #endif
1812