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