| OLD | NEW |
| 1 /* | 1 /* |
| 2 * (C) 1999 Lars Knoll (knoll@kde.org) | 2 * (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 2000 Gunnstein Lye (gunnstein@netcom.no) | 3 * (C) 2000 Gunnstein Lye (gunnstein@netcom.no) |
| 4 * (C) 2000 Frederik Holljen (frederik.holljen@hig.no) | 4 * (C) 2000 Frederik Holljen (frederik.holljen@hig.no) |
| 5 * (C) 2001 Peter Kelly (pmk@post.com) | 5 * (C) 2001 Peter Kelly (pmk@post.com) |
| 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All | 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All |
| 7 * rights reserved. | 7 * rights reserved. |
| 8 * Copyright (C) 2011 Motorola Mobility. All rights reserved. | 8 * Copyright (C) 2011 Motorola Mobility. All rights reserved. |
| 9 * | 9 * |
| 10 * This library is free software; you can redistribute it and/or | 10 * This library is free software; you can redistribute it and/or |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 108 DISALLOW_COPY_AND_ASSIGN(RangeUpdateScope); | 108 DISALLOW_COPY_AND_ASSIGN(RangeUpdateScope); |
| 109 }; | 109 }; |
| 110 | 110 |
| 111 int RangeUpdateScope::scope_count_ = 0; | 111 int RangeUpdateScope::scope_count_ = 0; |
| 112 #if DCHECK_IS_ON() | 112 #if DCHECK_IS_ON() |
| 113 Range* RangeUpdateScope::current_range_; | 113 Range* RangeUpdateScope::current_range_; |
| 114 #endif | 114 #endif |
| 115 | 115 |
| 116 inline Range::Range(Document& owner_document) | 116 inline Range::Range(Document& owner_document) |
| 117 : owner_document_(&owner_document), | 117 : owner_document_(&owner_document), |
| 118 start_(owner_document_), | 118 start_(*owner_document_), |
| 119 end_(owner_document_) { | 119 end_(*owner_document_) { |
| 120 owner_document_->AttachRange(this); | 120 owner_document_->AttachRange(this); |
| 121 } | 121 } |
| 122 | 122 |
| 123 Range* Range::Create(Document& owner_document) { | 123 Range* Range::Create(Document& owner_document) { |
| 124 return new Range(owner_document); | 124 return new Range(owner_document); |
| 125 } | 125 } |
| 126 | 126 |
| 127 inline Range::Range(Document& owner_document, | 127 inline Range::Range(Document& owner_document, |
| 128 Node* start_container, | 128 Node* start_container, |
| 129 unsigned start_offset, | 129 unsigned start_offset, |
| 130 Node* end_container, | 130 Node* end_container, |
| 131 unsigned end_offset) | 131 unsigned end_offset) |
| 132 : owner_document_(&owner_document), | 132 : owner_document_(&owner_document), |
| 133 start_(owner_document_), | 133 start_(*owner_document_), |
| 134 end_(owner_document_) { | 134 end_(*owner_document_) { |
| 135 owner_document_->AttachRange(this); | 135 owner_document_->AttachRange(this); |
| 136 | 136 |
| 137 // Simply setting the containers and offsets directly would not do any of the | 137 // Simply setting the containers and offsets directly would not do any of the |
| 138 // checking that setStart and setEnd do, so we call those functions. | 138 // checking that setStart and setEnd do, so we call those functions. |
| 139 setStart(start_container, start_offset); | 139 setStart(start_container, start_offset); |
| 140 setEnd(end_container, end_offset); | 140 setEnd(end_container, end_offset); |
| 141 } | 141 } |
| 142 | 142 |
| 143 Range* Range::Create(Document& owner_document, | 143 Range* Range::Create(Document& owner_document, |
| 144 Node* start_container, | 144 Node* start_container, |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 DCHECK_NE(owner_document_, document); | 188 DCHECK_NE(owner_document_, document); |
| 189 DCHECK(owner_document_); | 189 DCHECK(owner_document_); |
| 190 owner_document_->DetachRange(this); | 190 owner_document_->DetachRange(this); |
| 191 owner_document_ = &document; | 191 owner_document_ = &document; |
| 192 start_.SetToStartOfNode(document); | 192 start_.SetToStartOfNode(document); |
| 193 end_.SetToStartOfNode(document); | 193 end_.SetToStartOfNode(document); |
| 194 owner_document_->AttachRange(this); | 194 owner_document_->AttachRange(this); |
| 195 } | 195 } |
| 196 | 196 |
| 197 Node* Range::commonAncestorContainer() const { | 197 Node* Range::commonAncestorContainer() const { |
| 198 return commonAncestorContainer(start_.Container(), end_.Container()); | 198 return commonAncestorContainer(&start_.Container(), &end_.Container()); |
| 199 } | 199 } |
| 200 | 200 |
| 201 Node* Range::commonAncestorContainer(const Node* container_a, | 201 Node* Range::commonAncestorContainer(const Node* container_a, |
| 202 const Node* container_b) { | 202 const Node* container_b) { |
| 203 if (!container_a || !container_b) | 203 if (!container_a || !container_b) |
| 204 return nullptr; | 204 return nullptr; |
| 205 return container_a->CommonAncestor(*container_b, NodeTraversal::Parent); | 205 return container_a->CommonAncestor(*container_b, NodeTraversal::Parent); |
| 206 } | 206 } |
| 207 | 207 |
| 208 static inline bool CheckForDifferentRootContainer( | 208 static inline bool CheckForDifferentRootContainer( |
| 209 const RangeBoundaryPoint& start, | 209 const RangeBoundaryPoint& start, |
| 210 const RangeBoundaryPoint& end) { | 210 const RangeBoundaryPoint& end) { |
| 211 Node* end_root_container = end.Container(); | 211 Node* end_root_container = &end.Container(); |
| 212 while (end_root_container->parentNode()) | 212 while (end_root_container->parentNode()) |
| 213 end_root_container = end_root_container->parentNode(); | 213 end_root_container = end_root_container->parentNode(); |
| 214 Node* start_root_container = start.Container(); | 214 Node* start_root_container = &start.Container(); |
| 215 while (start_root_container->parentNode()) | 215 while (start_root_container->parentNode()) |
| 216 start_root_container = start_root_container->parentNode(); | 216 start_root_container = start_root_container->parentNode(); |
| 217 | 217 |
| 218 return start_root_container != end_root_container || | 218 return start_root_container != end_root_container || |
| 219 (Range::compareBoundaryPoints(start, end, ASSERT_NO_EXCEPTION) > 0); | 219 (Range::compareBoundaryPoints(start, end, ASSERT_NO_EXCEPTION) > 0); |
| 220 } | 220 } |
| 221 | 221 |
| 222 void Range::setStart(Node* ref_node, | 222 void Range::setStart(Node* ref_node, |
| 223 unsigned offset, | 223 unsigned offset, |
| 224 ExceptionState& exception_state) { | 224 ExceptionState& exception_state) { |
| 225 if (!ref_node) { | 225 if (!ref_node) { |
| 226 // FIXME: Generated bindings code never calls with null, and neither should | 226 // FIXME: Generated bindings code never calls with null, and neither should |
| 227 // other callers! | 227 // other callers! |
| 228 exception_state.ThrowTypeError("The node provided is null."); | 228 exception_state.ThrowTypeError("The node provided is null."); |
| 229 return; | 229 return; |
| 230 } | 230 } |
| 231 | 231 |
| 232 RangeUpdateScope scope(this); | 232 RangeUpdateScope scope(this); |
| 233 bool did_move_document = false; | 233 bool did_move_document = false; |
| 234 if (ref_node->GetDocument() != owner_document_) { | 234 if (ref_node->GetDocument() != owner_document_) { |
| 235 SetDocument(ref_node->GetDocument()); | 235 SetDocument(ref_node->GetDocument()); |
| 236 did_move_document = true; | 236 did_move_document = true; |
| 237 } | 237 } |
| 238 | 238 |
| 239 Node* child_node = CheckNodeWOffset(ref_node, offset, exception_state); | 239 Node* child_node = CheckNodeWOffset(ref_node, offset, exception_state); |
| 240 if (exception_state.HadException()) | 240 if (exception_state.HadException()) |
| 241 return; | 241 return; |
| 242 | 242 |
| 243 start_.Set(ref_node, offset, child_node); | 243 start_.Set(*ref_node, offset, child_node); |
| 244 | 244 |
| 245 if (did_move_document || CheckForDifferentRootContainer(start_, end_)) | 245 if (did_move_document || CheckForDifferentRootContainer(start_, end_)) |
| 246 collapse(true); | 246 collapse(true); |
| 247 } | 247 } |
| 248 | 248 |
| 249 void Range::setEnd(Node* ref_node, | 249 void Range::setEnd(Node* ref_node, |
| 250 unsigned offset, | 250 unsigned offset, |
| 251 ExceptionState& exception_state) { | 251 ExceptionState& exception_state) { |
| 252 if (!ref_node) { | 252 if (!ref_node) { |
| 253 // FIXME: Generated bindings code never calls with null, and neither should | 253 // FIXME: Generated bindings code never calls with null, and neither should |
| 254 // other callers! | 254 // other callers! |
| 255 exception_state.ThrowTypeError("The node provided is null."); | 255 exception_state.ThrowTypeError("The node provided is null."); |
| 256 return; | 256 return; |
| 257 } | 257 } |
| 258 | 258 |
| 259 RangeUpdateScope scope(this); | 259 RangeUpdateScope scope(this); |
| 260 bool did_move_document = false; | 260 bool did_move_document = false; |
| 261 if (ref_node->GetDocument() != owner_document_) { | 261 if (ref_node->GetDocument() != owner_document_) { |
| 262 SetDocument(ref_node->GetDocument()); | 262 SetDocument(ref_node->GetDocument()); |
| 263 did_move_document = true; | 263 did_move_document = true; |
| 264 } | 264 } |
| 265 | 265 |
| 266 Node* child_node = CheckNodeWOffset(ref_node, offset, exception_state); | 266 Node* child_node = CheckNodeWOffset(ref_node, offset, exception_state); |
| 267 if (exception_state.HadException()) | 267 if (exception_state.HadException()) |
| 268 return; | 268 return; |
| 269 | 269 |
| 270 end_.Set(ref_node, offset, child_node); | 270 end_.Set(*ref_node, offset, child_node); |
| 271 | 271 |
| 272 if (did_move_document || CheckForDifferentRootContainer(start_, end_)) | 272 if (did_move_document || CheckForDifferentRootContainer(start_, end_)) |
| 273 collapse(false); | 273 collapse(false); |
| 274 } | 274 } |
| 275 | 275 |
| 276 void Range::setStart(const Position& start, ExceptionState& exception_state) { | 276 void Range::setStart(const Position& start, ExceptionState& exception_state) { |
| 277 Position parent_anchored = start.ParentAnchoredEquivalent(); | 277 Position parent_anchored = start.ParentAnchoredEquivalent(); |
| 278 setStart(parent_anchored.ComputeContainerNode(), | 278 setStart(parent_anchored.ComputeContainerNode(), |
| 279 parent_anchored.OffsetInContainerNode(), exception_state); | 279 parent_anchored.OffsetInContainerNode(), exception_state); |
| 280 } | 280 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 291 end_ = start_; | 291 end_ = start_; |
| 292 else | 292 else |
| 293 start_ = end_; | 293 start_ = end_; |
| 294 } | 294 } |
| 295 | 295 |
| 296 bool Range::HasSameRoot(const Node& node) const { | 296 bool Range::HasSameRoot(const Node& node) const { |
| 297 if (node.GetDocument() != owner_document_) | 297 if (node.GetDocument() != owner_document_) |
| 298 return false; | 298 return false; |
| 299 // commonAncestorContainer() is O(depth). We should avoid to call it in common | 299 // commonAncestorContainer() is O(depth). We should avoid to call it in common |
| 300 // cases. | 300 // cases. |
| 301 if (node.IsInTreeScope() && start_.Container()->IsInTreeScope() && | 301 if (node.IsInTreeScope() && start_.Container().IsInTreeScope() && |
| 302 &node.GetTreeScope() == &start_.Container()->GetTreeScope()) | 302 &node.GetTreeScope() == &start_.Container().GetTreeScope()) |
| 303 return true; | 303 return true; |
| 304 return node.CommonAncestor(*start_.Container(), NodeTraversal::Parent); | 304 return node.CommonAncestor(start_.Container(), NodeTraversal::Parent); |
| 305 } | 305 } |
| 306 | 306 |
| 307 bool Range::isPointInRange(Node* ref_node, | 307 bool Range::isPointInRange(Node* ref_node, |
| 308 unsigned offset, | 308 unsigned offset, |
| 309 ExceptionState& exception_state) const { | 309 ExceptionState& exception_state) const { |
| 310 if (!ref_node) { | 310 if (!ref_node) { |
| 311 // FIXME: Generated bindings code never calls with null, and neither should | 311 // FIXME: Generated bindings code never calls with null, and neither should |
| 312 // other callers! | 312 // other callers! |
| 313 exception_state.ThrowTypeError("The node provided is null."); | 313 exception_state.ThrowTypeError("The node provided is null."); |
| 314 return false; | 314 return false; |
| 315 } | 315 } |
| 316 if (!HasSameRoot(*ref_node)) | 316 if (!HasSameRoot(*ref_node)) |
| 317 return false; | 317 return false; |
| 318 | 318 |
| 319 CheckNodeWOffset(ref_node, offset, exception_state); | 319 CheckNodeWOffset(ref_node, offset, exception_state); |
| 320 if (exception_state.HadException()) | 320 if (exception_state.HadException()) |
| 321 return false; | 321 return false; |
| 322 | 322 |
| 323 return compareBoundaryPoints(ref_node, offset, start_.Container(), | 323 return compareBoundaryPoints(ref_node, offset, &start_.Container(), |
| 324 start_.Offset(), exception_state) >= 0 && | 324 start_.Offset(), exception_state) >= 0 && |
| 325 !exception_state.HadException() && | 325 !exception_state.HadException() && |
| 326 compareBoundaryPoints(ref_node, offset, end_.Container(), | 326 compareBoundaryPoints(ref_node, offset, &end_.Container(), |
| 327 end_.Offset(), exception_state) <= 0 && | 327 end_.Offset(), exception_state) <= 0 && |
| 328 !exception_state.HadException(); | 328 !exception_state.HadException(); |
| 329 } | 329 } |
| 330 | 330 |
| 331 short Range::comparePoint(Node* ref_node, | 331 short Range::comparePoint(Node* ref_node, |
| 332 unsigned offset, | 332 unsigned offset, |
| 333 ExceptionState& exception_state) const { | 333 ExceptionState& exception_state) const { |
| 334 // http://developer.mozilla.org/en/docs/DOM:range.comparePoint | 334 // http://developer.mozilla.org/en/docs/DOM:range.comparePoint |
| 335 // This method returns -1, 0 or 1 depending on if the point described by the | 335 // This method returns -1, 0 or 1 depending on if the point described by the |
| 336 // refNode node and an offset within the node is before, same as, or after the | 336 // refNode node and an offset within the node is before, same as, or after the |
| 337 // range respectively. | 337 // range respectively. |
| 338 | 338 |
| 339 if (!HasSameRoot(*ref_node)) { | 339 if (!HasSameRoot(*ref_node)) { |
| 340 exception_state.ThrowDOMException( | 340 exception_state.ThrowDOMException( |
| 341 kWrongDocumentError, | 341 kWrongDocumentError, |
| 342 "The node provided and the Range are not in the same tree."); | 342 "The node provided and the Range are not in the same tree."); |
| 343 return 0; | 343 return 0; |
| 344 } | 344 } |
| 345 | 345 |
| 346 CheckNodeWOffset(ref_node, offset, exception_state); | 346 CheckNodeWOffset(ref_node, offset, exception_state); |
| 347 if (exception_state.HadException()) | 347 if (exception_state.HadException()) |
| 348 return 0; | 348 return 0; |
| 349 | 349 |
| 350 // compare to start, and point comes before | 350 // compare to start, and point comes before |
| 351 if (compareBoundaryPoints(ref_node, offset, start_.Container(), | 351 if (compareBoundaryPoints(ref_node, offset, &start_.Container(), |
| 352 start_.Offset(), exception_state) < 0) | 352 start_.Offset(), exception_state) < 0) |
| 353 return -1; | 353 return -1; |
| 354 | 354 |
| 355 if (exception_state.HadException()) | 355 if (exception_state.HadException()) |
| 356 return 0; | 356 return 0; |
| 357 | 357 |
| 358 // compare to end, and point comes after | 358 // compare to end, and point comes after |
| 359 if (compareBoundaryPoints(ref_node, offset, end_.Container(), end_.Offset(), | 359 if (compareBoundaryPoints(ref_node, offset, &end_.Container(), end_.Offset(), |
| 360 exception_state) > 0 && | 360 exception_state) > 0 && |
| 361 !exception_state.HadException()) | 361 !exception_state.HadException()) |
| 362 return 1; | 362 return 1; |
| 363 | 363 |
| 364 // point is in the middle of this range, or on the boundary points | 364 // point is in the middle of this range, or on the boundary points |
| 365 return 0; | 365 return 0; |
| 366 } | 366 } |
| 367 | 367 |
| 368 short Range::compareBoundaryPoints(unsigned how, | 368 short Range::compareBoundaryPoints(unsigned how, |
| 369 const Range* source_range, | 369 const Range* source_range, |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 exception_state.ThrowDOMException( | 428 exception_state.ThrowDOMException( |
| 429 kWrongDocumentError, "The two ranges are in separate documents."); | 429 kWrongDocumentError, "The two ranges are in separate documents."); |
| 430 return 0; | 430 return 0; |
| 431 } | 431 } |
| 432 return result; | 432 return result; |
| 433 } | 433 } |
| 434 | 434 |
| 435 short Range::compareBoundaryPoints(const RangeBoundaryPoint& boundary_a, | 435 short Range::compareBoundaryPoints(const RangeBoundaryPoint& boundary_a, |
| 436 const RangeBoundaryPoint& boundary_b, | 436 const RangeBoundaryPoint& boundary_b, |
| 437 ExceptionState& exception_state) { | 437 ExceptionState& exception_state) { |
| 438 return compareBoundaryPoints(boundary_a.Container(), boundary_a.Offset(), | 438 return compareBoundaryPoints(&boundary_a.Container(), boundary_a.Offset(), |
| 439 boundary_b.Container(), boundary_b.Offset(), | 439 &boundary_b.Container(), boundary_b.Offset(), |
| 440 exception_state); | 440 exception_state); |
| 441 } | 441 } |
| 442 | 442 |
| 443 bool Range::BoundaryPointsValid() const { | 443 bool Range::BoundaryPointsValid() const { |
| 444 DummyExceptionStateForTesting exception_state; | 444 DummyExceptionStateForTesting exception_state; |
| 445 return compareBoundaryPoints(start_, end_, exception_state) <= 0 && | 445 return compareBoundaryPoints(start_, end_, exception_state) <= 0 && |
| 446 !exception_state.HadException(); | 446 !exception_state.HadException(); |
| 447 } | 447 } |
| 448 | 448 |
| 449 void Range::deleteContents(ExceptionState& exception_state) { | 449 void Range::deleteContents(ExceptionState& exception_state) { |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 553 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) | 553 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) |
| 554 fragment = DocumentFragment::Create(*owner_document_.Get()); | 554 fragment = DocumentFragment::Create(*owner_document_.Get()); |
| 555 | 555 |
| 556 if (collapsed()) | 556 if (collapsed()) |
| 557 return fragment; | 557 return fragment; |
| 558 | 558 |
| 559 Node* common_root = commonAncestorContainer(); | 559 Node* common_root = commonAncestorContainer(); |
| 560 DCHECK(common_root); | 560 DCHECK(common_root); |
| 561 | 561 |
| 562 if (start_.Container() == end_.Container()) { | 562 if (start_.Container() == end_.Container()) { |
| 563 ProcessContentsBetweenOffsets(action, fragment, start_.Container(), | 563 ProcessContentsBetweenOffsets(action, fragment, &start_.Container(), |
| 564 start_.Offset(), end_.Offset(), | 564 start_.Offset(), end_.Offset(), |
| 565 exception_state); | 565 exception_state); |
| 566 return fragment; | 566 return fragment; |
| 567 } | 567 } |
| 568 | 568 |
| 569 // Since mutation observers can modify the range during the process, the | 569 // Since mutation observers can modify the range during the process, the |
| 570 // boundary points need to be saved. | 570 // boundary points need to be saved. |
| 571 const RangeBoundaryPoint original_start(start_); | 571 const RangeBoundaryPoint original_start(start_); |
| 572 const RangeBoundaryPoint original_end(end_); | 572 const RangeBoundaryPoint original_end(end_); |
| 573 | 573 |
| 574 // what is the highest node that partially selects the start / end of the | 574 // what is the highest node that partially selects the start / end of the |
| 575 // range? | 575 // range? |
| 576 Node* partial_start = | 576 Node* partial_start = |
| 577 HighestAncestorUnderCommonRoot(original_start.Container(), common_root); | 577 HighestAncestorUnderCommonRoot(&original_start.Container(), common_root); |
| 578 Node* partial_end = | 578 Node* partial_end = |
| 579 HighestAncestorUnderCommonRoot(original_end.Container(), common_root); | 579 HighestAncestorUnderCommonRoot(&original_end.Container(), common_root); |
| 580 | 580 |
| 581 // Start and end containers are different. | 581 // Start and end containers are different. |
| 582 // There are three possibilities here: | 582 // There are three possibilities here: |
| 583 // 1. Start container == commonRoot (End container must be a descendant) | 583 // 1. Start container == commonRoot (End container must be a descendant) |
| 584 // 2. End container == commonRoot (Start container must be a descendant) | 584 // 2. End container == commonRoot (Start container must be a descendant) |
| 585 // 3. Neither is commonRoot, they are both descendants | 585 // 3. Neither is commonRoot, they are both descendants |
| 586 // | 586 // |
| 587 // In case 3, we grab everything after the start (up until a direct child | 587 // In case 3, we grab everything after the start (up until a direct child |
| 588 // of commonRoot) into leftContents, and everything before the end (up until | 588 // of commonRoot) into leftContents, and everything before the end (up until |
| 589 // a direct child of commonRoot) into rightContents. Then we process all | 589 // a direct child of commonRoot) into rightContents. Then we process all |
| 590 // commonRoot children between leftContents and rightContents | 590 // commonRoot children between leftContents and rightContents |
| 591 // | 591 // |
| 592 // In case 1 or 2, we skip either processing of leftContents or rightContents, | 592 // In case 1 or 2, we skip either processing of leftContents or rightContents, |
| 593 // in which case the last lot of nodes either goes from the first or last | 593 // in which case the last lot of nodes either goes from the first or last |
| 594 // child of commonRoot. | 594 // child of commonRoot. |
| 595 // | 595 // |
| 596 // These are deleted, cloned, or extracted (i.e. both) depending on action. | 596 // These are deleted, cloned, or extracted (i.e. both) depending on action. |
| 597 | 597 |
| 598 // Note that we are verifying that our common root hierarchy is still intact | 598 // Note that we are verifying that our common root hierarchy is still intact |
| 599 // after any DOM mutation event, at various stages below. See webkit bug | 599 // after any DOM mutation event, at various stages below. See webkit bug |
| 600 // 60350. | 600 // 60350. |
| 601 | 601 |
| 602 Node* left_contents = nullptr; | 602 Node* left_contents = nullptr; |
| 603 if (original_start.Container() != common_root && | 603 if (original_start.Container() != common_root && |
| 604 common_root->contains(original_start.Container())) { | 604 common_root->contains(&original_start.Container())) { |
| 605 left_contents = ProcessContentsBetweenOffsets( | 605 left_contents = ProcessContentsBetweenOffsets( |
| 606 action, nullptr, original_start.Container(), original_start.Offset(), | 606 action, nullptr, &original_start.Container(), original_start.Offset(), |
| 607 LengthOfContents(original_start.Container()), exception_state); | 607 LengthOfContents(&original_start.Container()), exception_state); |
| 608 left_contents = ProcessAncestorsAndTheirSiblings( | 608 left_contents = ProcessAncestorsAndTheirSiblings( |
| 609 action, original_start.Container(), kProcessContentsForward, | 609 action, &original_start.Container(), kProcessContentsForward, |
| 610 left_contents, common_root, exception_state); | 610 left_contents, common_root, exception_state); |
| 611 } | 611 } |
| 612 | 612 |
| 613 Node* right_contents = nullptr; | 613 Node* right_contents = nullptr; |
| 614 if (end_.Container() != common_root && | 614 if (end_.Container() != common_root && |
| 615 common_root->contains(original_end.Container())) { | 615 common_root->contains(&original_end.Container())) { |
| 616 right_contents = ProcessContentsBetweenOffsets( | 616 right_contents = ProcessContentsBetweenOffsets( |
| 617 action, nullptr, original_end.Container(), 0, original_end.Offset(), | 617 action, nullptr, &original_end.Container(), 0, original_end.Offset(), |
| 618 exception_state); | 618 exception_state); |
| 619 right_contents = ProcessAncestorsAndTheirSiblings( | 619 right_contents = ProcessAncestorsAndTheirSiblings( |
| 620 action, original_end.Container(), kProcessContentsBackward, | 620 action, &original_end.Container(), kProcessContentsBackward, |
| 621 right_contents, common_root, exception_state); | 621 right_contents, common_root, exception_state); |
| 622 } | 622 } |
| 623 | 623 |
| 624 // delete all children of commonRoot between the start and end container | 624 // delete all children of commonRoot between the start and end container |
| 625 Node* process_start = ChildOfCommonRootBeforeOffset( | 625 Node* process_start = ChildOfCommonRootBeforeOffset( |
| 626 original_start.Container(), original_start.Offset(), common_root); | 626 &original_start.Container(), original_start.Offset(), common_root); |
| 627 if (process_start && | 627 if (process_start && |
| 628 original_start.Container() != | 628 original_start.Container() != |
| 629 common_root) // processStart contains nodes before m_start. | 629 common_root) // processStart contains nodes before m_start. |
| 630 process_start = process_start->nextSibling(); | 630 process_start = process_start->nextSibling(); |
| 631 Node* process_end = ChildOfCommonRootBeforeOffset( | 631 Node* process_end = ChildOfCommonRootBeforeOffset( |
| 632 original_end.Container(), original_end.Offset(), common_root); | 632 &original_end.Container(), original_end.Offset(), common_root); |
| 633 | 633 |
| 634 // Collapse the range, making sure that the result is not within a node that | 634 // Collapse the range, making sure that the result is not within a node that |
| 635 // was partially selected. | 635 // was partially selected. |
| 636 if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) { | 636 if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) { |
| 637 if (partial_start && common_root->contains(partial_start)) { | 637 if (partial_start && common_root->contains(partial_start)) { |
| 638 // FIXME: We should not continue if we have an earlier error. | 638 // FIXME: We should not continue if we have an earlier error. |
| 639 exception_state.ClearException(); | 639 exception_state.ClearException(); |
| 640 setStart(partial_start->parentNode(), partial_start->NodeIndex() + 1, | 640 setStart(partial_start->parentNode(), partial_start->NodeIndex() + 1, |
| 641 exception_state); | 641 exception_state); |
| 642 } else if (partial_end && common_root->contains(partial_end)) { | 642 } else if (partial_end && common_root->contains(partial_end)) { |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 859 exception_state.ThrowTypeError("The node provided is null."); | 859 exception_state.ThrowTypeError("The node provided is null."); |
| 860 return; | 860 return; |
| 861 } | 861 } |
| 862 | 862 |
| 863 // HierarchyRequestError: Raised if the container of the start of the Range is | 863 // HierarchyRequestError: Raised if the container of the start of the Range is |
| 864 // of a type that does not allow children of the type of newNode or if newNode | 864 // of a type that does not allow children of the type of newNode or if newNode |
| 865 // is an ancestor of the container. | 865 // is an ancestor of the container. |
| 866 | 866 |
| 867 // an extra one here - if a text node is going to split, it must have a parent | 867 // an extra one here - if a text node is going to split, it must have a parent |
| 868 // to insert into | 868 // to insert into |
| 869 bool start_is_text = start_.Container()->IsTextNode(); | 869 bool start_is_text = start_.Container().IsTextNode(); |
| 870 if (start_is_text && !start_.Container()->parentNode()) { | 870 if (start_is_text && !start_.Container().parentNode()) { |
| 871 exception_state.ThrowDOMException(kHierarchyRequestError, | 871 exception_state.ThrowDOMException(kHierarchyRequestError, |
| 872 "This operation would split a text node, " | 872 "This operation would split a text node, " |
| 873 "but there's no parent into which to " | 873 "but there's no parent into which to " |
| 874 "insert."); | 874 "insert."); |
| 875 return; | 875 return; |
| 876 } | 876 } |
| 877 | 877 |
| 878 // In the case where the container is a text node, we check against the | 878 // In the case where the container is a text node, we check against the |
| 879 // container's parent, because text nodes get split up upon insertion. | 879 // container's parent, because text nodes get split up upon insertion. |
| 880 Node* check_against; | 880 Node* check_against; |
| 881 if (start_is_text) | 881 if (start_is_text) |
| 882 check_against = start_.Container()->parentNode(); | 882 check_against = start_.Container().parentNode(); |
| 883 else | 883 else |
| 884 check_against = start_.Container(); | 884 check_against = &start_.Container(); |
| 885 | 885 |
| 886 Node::NodeType new_node_type = new_node->getNodeType(); | 886 Node::NodeType new_node_type = new_node->getNodeType(); |
| 887 int num_new_children; | 887 int num_new_children; |
| 888 if (new_node_type == Node::kDocumentFragmentNode && | 888 if (new_node_type == Node::kDocumentFragmentNode && |
| 889 !new_node->IsShadowRoot()) { | 889 !new_node->IsShadowRoot()) { |
| 890 // check each child node, not the DocumentFragment itself | 890 // check each child node, not the DocumentFragment itself |
| 891 num_new_children = 0; | 891 num_new_children = 0; |
| 892 for (Node* c = ToDocumentFragment(new_node)->FirstChild(); c; | 892 for (Node* c = ToDocumentFragment(new_node)->FirstChild(); c; |
| 893 c = c->nextSibling()) { | 893 c = c->nextSibling()) { |
| 894 if (!check_against->ChildTypeAllowed(c->getNodeType())) { | 894 if (!check_against->ChildTypeAllowed(c->getNodeType())) { |
| 895 exception_state.ThrowDOMException( | 895 exception_state.ThrowDOMException( |
| 896 kHierarchyRequestError, | 896 kHierarchyRequestError, |
| 897 "The node to be inserted contains a '" + c->nodeName() + | 897 "The node to be inserted contains a '" + c->nodeName() + |
| 898 "' node, which may not be inserted here."); | 898 "' node, which may not be inserted here."); |
| 899 return; | 899 return; |
| 900 } | 900 } |
| 901 ++num_new_children; | 901 ++num_new_children; |
| 902 } | 902 } |
| 903 } else { | 903 } else { |
| 904 num_new_children = 1; | 904 num_new_children = 1; |
| 905 if (!check_against->ChildTypeAllowed(new_node_type)) { | 905 if (!check_against->ChildTypeAllowed(new_node_type)) { |
| 906 exception_state.ThrowDOMException( | 906 exception_state.ThrowDOMException( |
| 907 kHierarchyRequestError, | 907 kHierarchyRequestError, |
| 908 "The node to be inserted is a '" + new_node->nodeName() + | 908 "The node to be inserted is a '" + new_node->nodeName() + |
| 909 "' node, which may not be inserted here."); | 909 "' node, which may not be inserted here."); |
| 910 return; | 910 return; |
| 911 } | 911 } |
| 912 } | 912 } |
| 913 | 913 |
| 914 for (Node& node : NodeTraversal::InclusiveAncestorsOf(*start_.Container())) { | 914 for (Node& node : NodeTraversal::InclusiveAncestorsOf(start_.Container())) { |
| 915 if (node == new_node) { | 915 if (node == new_node) { |
| 916 exception_state.ThrowDOMException(kHierarchyRequestError, | 916 exception_state.ThrowDOMException(kHierarchyRequestError, |
| 917 "The node to be inserted contains the " | 917 "The node to be inserted contains the " |
| 918 "insertion point; it may not be " | 918 "insertion point; it may not be " |
| 919 "inserted into itself."); | 919 "inserted into itself."); |
| 920 return; | 920 return; |
| 921 } | 921 } |
| 922 } | 922 } |
| 923 | 923 |
| 924 // InvalidNodeTypeError: Raised if newNode is an Attr, Entity, Notation, | 924 // InvalidNodeTypeError: Raised if newNode is an Attr, Entity, Notation, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 939 "here."); | 939 "here."); |
| 940 return; | 940 return; |
| 941 } | 941 } |
| 942 break; | 942 break; |
| 943 } | 943 } |
| 944 | 944 |
| 945 EventQueueScope scope; | 945 EventQueueScope scope; |
| 946 bool collapsed = start_ == end_; | 946 bool collapsed = start_ == end_; |
| 947 Node* container = nullptr; | 947 Node* container = nullptr; |
| 948 if (start_is_text) { | 948 if (start_is_text) { |
| 949 container = start_.Container(); | 949 container = &start_.Container(); |
| 950 Text* new_text = | 950 Text* new_text = |
| 951 ToText(container)->splitText(start_.Offset(), exception_state); | 951 ToText(container)->splitText(start_.Offset(), exception_state); |
| 952 if (exception_state.HadException()) | 952 if (exception_state.HadException()) |
| 953 return; | 953 return; |
| 954 | 954 |
| 955 container = start_.Container(); | 955 container = &start_.Container(); |
| 956 container->parentNode()->InsertBefore(new_node, new_text, exception_state); | 956 container->parentNode()->InsertBefore(new_node, new_text, exception_state); |
| 957 if (exception_state.HadException()) | 957 if (exception_state.HadException()) |
| 958 return; | 958 return; |
| 959 | 959 |
| 960 if (collapsed) { | 960 if (collapsed) { |
| 961 // Some types of events don't support EventQueueScope. Given | 961 // Some types of events don't support EventQueueScope. Given |
| 962 // circumstance may mutate the tree so newText->parentNode() may | 962 // circumstance may mutate the tree so newText->parentNode() may |
| 963 // become null. | 963 // become null. |
| 964 if (!new_text->parentNode()) { | 964 if (!new_text->parentNode()) { |
| 965 exception_state.ThrowDOMException( | 965 exception_state.ThrowDOMException( |
| (...skipping 12 matching lines...) Expand all Loading... |
| 978 // The insertion will do nothing, but we need to extend the range to | 978 // The insertion will do nothing, but we need to extend the range to |
| 979 // include the inserted nodes. | 979 // include the inserted nodes. |
| 980 Node* first_child = (new_node_type == Node::kDocumentFragmentNode) | 980 Node* first_child = (new_node_type == Node::kDocumentFragmentNode) |
| 981 ? ToDocumentFragment(new_node)->FirstChild() | 981 ? ToDocumentFragment(new_node)->FirstChild() |
| 982 : new_node; | 982 : new_node; |
| 983 DCHECK(first_child); | 983 DCHECK(first_child); |
| 984 start_.SetToBeforeChild(*first_child); | 984 start_.SetToBeforeChild(*first_child); |
| 985 return; | 985 return; |
| 986 } | 986 } |
| 987 | 987 |
| 988 container = start_.Container(); | 988 container = &start_.Container(); |
| 989 Node* reference_node = NodeTraversal::ChildAt(*container, start_.Offset()); | 989 Node* reference_node = NodeTraversal::ChildAt(*container, start_.Offset()); |
| 990 // TODO(tkent): The following check must be unnecessary if we follow the | 990 // TODO(tkent): The following check must be unnecessary if we follow the |
| 991 // algorithm defined in the specification. | 991 // algorithm defined in the specification. |
| 992 // https://dom.spec.whatwg.org/#concept-range-insert | 992 // https://dom.spec.whatwg.org/#concept-range-insert |
| 993 if (new_node != reference_node) { | 993 if (new_node != reference_node) { |
| 994 container->insertBefore(new_node, reference_node, exception_state); | 994 container->insertBefore(new_node, reference_node, exception_state); |
| 995 if (exception_state.HadException()) | 995 if (exception_state.HadException()) |
| 996 return; | 996 return; |
| 997 } | 997 } |
| 998 | 998 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1033 .SetEmitsObjectReplacementCharacter(true) | 1033 .SetEmitsObjectReplacementCharacter(true) |
| 1034 .Build()); | 1034 .Build()); |
| 1035 } | 1035 } |
| 1036 | 1036 |
| 1037 DocumentFragment* Range::createContextualFragment( | 1037 DocumentFragment* Range::createContextualFragment( |
| 1038 const String& markup, | 1038 const String& markup, |
| 1039 ExceptionState& exception_state) { | 1039 ExceptionState& exception_state) { |
| 1040 // Algorithm: | 1040 // Algorithm: |
| 1041 // http://domparsing.spec.whatwg.org/#extensions-to-the-range-interface | 1041 // http://domparsing.spec.whatwg.org/#extensions-to-the-range-interface |
| 1042 | 1042 |
| 1043 Node* node = start_.Container(); | 1043 Node* node = &start_.Container(); |
| 1044 | 1044 |
| 1045 // Step 1. | 1045 // Step 1. |
| 1046 Element* element; | 1046 Element* element; |
| 1047 if (!start_.Offset() && | 1047 if (!start_.Offset() && |
| 1048 (node->IsDocumentNode() || node->IsDocumentFragment())) | 1048 (node->IsDocumentNode() || node->IsDocumentFragment())) |
| 1049 element = nullptr; | 1049 element = nullptr; |
| 1050 else if (node->IsElementNode()) | 1050 else if (node->IsElementNode()) |
| 1051 element = ToElement(node); | 1051 element = ToElement(node); |
| 1052 else | 1052 else |
| 1053 element = node->parentElement(); | 1053 element = node->parentElement(); |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1196 case Node::kProcessingInstructionNode: | 1196 case Node::kProcessingInstructionNode: |
| 1197 case Node::kTextNode: | 1197 case Node::kTextNode: |
| 1198 exception_state.ThrowDOMException( | 1198 exception_state.ThrowDOMException( |
| 1199 kInvalidNodeTypeError, | 1199 kInvalidNodeTypeError, |
| 1200 "The node provided is of type '" + n->nodeName() + "'."); | 1200 "The node provided is of type '" + n->nodeName() + "'."); |
| 1201 return; | 1201 return; |
| 1202 } | 1202 } |
| 1203 } | 1203 } |
| 1204 | 1204 |
| 1205 Range* Range::cloneRange() const { | 1205 Range* Range::cloneRange() const { |
| 1206 return Range::Create(*owner_document_.Get(), start_.Container(), | 1206 return Range::Create(*owner_document_.Get(), &start_.Container(), |
| 1207 start_.Offset(), end_.Container(), end_.Offset()); | 1207 start_.Offset(), &end_.Container(), end_.Offset()); |
| 1208 } | 1208 } |
| 1209 | 1209 |
| 1210 void Range::setStartAfter(Node* ref_node, ExceptionState& exception_state) { | 1210 void Range::setStartAfter(Node* ref_node, ExceptionState& exception_state) { |
| 1211 CheckNodeBA(ref_node, exception_state); | 1211 CheckNodeBA(ref_node, exception_state); |
| 1212 if (exception_state.HadException()) | 1212 if (exception_state.HadException()) |
| 1213 return; | 1213 return; |
| 1214 | 1214 |
| 1215 setStart(ref_node->parentNode(), ref_node->NodeIndex() + 1, exception_state); | 1215 setStart(ref_node->parentNode(), ref_node->NodeIndex() + 1, exception_state); |
| 1216 } | 1216 } |
| 1217 | 1217 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1320 case Node::kDocumentNode: | 1320 case Node::kDocumentNode: |
| 1321 case Node::kElementNode: | 1321 case Node::kElementNode: |
| 1322 case Node::kProcessingInstructionNode: | 1322 case Node::kProcessingInstructionNode: |
| 1323 case Node::kTextNode: | 1323 case Node::kTextNode: |
| 1324 break; | 1324 break; |
| 1325 case Node::kDocumentTypeNode: | 1325 case Node::kDocumentTypeNode: |
| 1326 return false; | 1326 return false; |
| 1327 } | 1327 } |
| 1328 } | 1328 } |
| 1329 | 1329 |
| 1330 RangeBoundaryPoint start_boundary_point(ref_node); | 1330 RangeBoundaryPoint start_boundary_point(*ref_node); |
| 1331 start_boundary_point.SetToStartOfNode(*ref_node); | 1331 start_boundary_point.SetToStartOfNode(*ref_node); |
| 1332 start = start_boundary_point.ToPosition(); | 1332 start = start_boundary_point.ToPosition(); |
| 1333 RangeBoundaryPoint end_boundary_point(ref_node); | 1333 RangeBoundaryPoint end_boundary_point(*ref_node); |
| 1334 end_boundary_point.SetToEndOfNode(*ref_node); | 1334 end_boundary_point.SetToEndOfNode(*ref_node); |
| 1335 end = end_boundary_point.ToPosition(); | 1335 end = end_boundary_point.ToPosition(); |
| 1336 return true; | 1336 return true; |
| 1337 } | 1337 } |
| 1338 | 1338 |
| 1339 // https://dom.spec.whatwg.org/#dom-range-surroundcontents | 1339 // https://dom.spec.whatwg.org/#dom-range-surroundcontents |
| 1340 void Range::surroundContents(Node* new_parent, | 1340 void Range::surroundContents(Node* new_parent, |
| 1341 ExceptionState& exception_state) { | 1341 ExceptionState& exception_state) { |
| 1342 if (!new_parent) { | 1342 if (!new_parent) { |
| 1343 // FIXME: Generated bindings code never calls with null, and neither should | 1343 // FIXME: Generated bindings code never calls with null, and neither should |
| 1344 // other callers! | 1344 // other callers! |
| 1345 exception_state.ThrowTypeError("The node provided is null."); | 1345 exception_state.ThrowTypeError("The node provided is null."); |
| 1346 return; | 1346 return; |
| 1347 } | 1347 } |
| 1348 | 1348 |
| 1349 // 1. If a non-Text node is partially contained in the context object, then | 1349 // 1. If a non-Text node is partially contained in the context object, then |
| 1350 // throw an InvalidStateError. | 1350 // throw an InvalidStateError. |
| 1351 Node* start_non_text_container = start_.Container(); | 1351 Node* start_non_text_container = &start_.Container(); |
| 1352 if (start_non_text_container->getNodeType() == Node::kTextNode) | 1352 if (start_non_text_container->getNodeType() == Node::kTextNode) |
| 1353 start_non_text_container = start_non_text_container->parentNode(); | 1353 start_non_text_container = start_non_text_container->parentNode(); |
| 1354 Node* end_non_text_container = end_.Container(); | 1354 Node* end_non_text_container = &end_.Container(); |
| 1355 if (end_non_text_container->getNodeType() == Node::kTextNode) | 1355 if (end_non_text_container->getNodeType() == Node::kTextNode) |
| 1356 end_non_text_container = end_non_text_container->parentNode(); | 1356 end_non_text_container = end_non_text_container->parentNode(); |
| 1357 if (start_non_text_container != end_non_text_container) { | 1357 if (start_non_text_container != end_non_text_container) { |
| 1358 exception_state.ThrowDOMException( | 1358 exception_state.ThrowDOMException( |
| 1359 kInvalidStateError, | 1359 kInvalidStateError, |
| 1360 "The Range has partially selected a non-Text node."); | 1360 "The Range has partially selected a non-Text node."); |
| 1361 return; | 1361 return; |
| 1362 } | 1362 } |
| 1363 | 1363 |
| 1364 // 2. If newParent is a Document, DocumentType, or DocumentFragment node, then | 1364 // 2. If newParent is a Document, DocumentType, or DocumentFragment node, then |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1426 for (Node* n = FirstNode(); n != past_last; n = NodeTraversal::Next(*n)) { | 1426 for (Node* n = FirstNode(); n != past_last; n = NodeTraversal::Next(*n)) { |
| 1427 if (n->IsDocumentTypeNode()) { | 1427 if (n->IsDocumentTypeNode()) { |
| 1428 exception_state.ThrowDOMException(kHierarchyRequestError, | 1428 exception_state.ThrowDOMException(kHierarchyRequestError, |
| 1429 "The Range contains a doctype node."); | 1429 "The Range contains a doctype node."); |
| 1430 return; | 1430 return; |
| 1431 } | 1431 } |
| 1432 } | 1432 } |
| 1433 } | 1433 } |
| 1434 | 1434 |
| 1435 Node* Range::FirstNode() const { | 1435 Node* Range::FirstNode() const { |
| 1436 if (start_.Container()->IsCharacterDataNode()) | 1436 if (start_.Container().IsCharacterDataNode()) |
| 1437 return start_.Container(); | 1437 return &start_.Container(); |
| 1438 if (Node* child = | 1438 if (Node* child = NodeTraversal::ChildAt(start_.Container(), start_.Offset())) |
| 1439 NodeTraversal::ChildAt(*start_.Container(), start_.Offset())) | |
| 1440 return child; | 1439 return child; |
| 1441 if (!start_.Offset()) | 1440 if (!start_.Offset()) |
| 1442 return start_.Container(); | 1441 return &start_.Container(); |
| 1443 return NodeTraversal::NextSkippingChildren(*start_.Container()); | 1442 return NodeTraversal::NextSkippingChildren(start_.Container()); |
| 1444 } | 1443 } |
| 1445 | 1444 |
| 1446 Node* Range::PastLastNode() const { | 1445 Node* Range::PastLastNode() const { |
| 1447 if (end_.Container()->IsCharacterDataNode()) | 1446 if (end_.Container().IsCharacterDataNode()) |
| 1448 return NodeTraversal::NextSkippingChildren(*end_.Container()); | 1447 return NodeTraversal::NextSkippingChildren(end_.Container()); |
| 1449 if (Node* child = NodeTraversal::ChildAt(*end_.Container(), end_.Offset())) | 1448 if (Node* child = NodeTraversal::ChildAt(end_.Container(), end_.Offset())) |
| 1450 return child; | 1449 return child; |
| 1451 return NodeTraversal::NextSkippingChildren(*end_.Container()); | 1450 return NodeTraversal::NextSkippingChildren(end_.Container()); |
| 1452 } | 1451 } |
| 1453 | 1452 |
| 1454 IntRect Range::BoundingBox() const { | 1453 IntRect Range::BoundingBox() const { |
| 1455 IntRect result; | 1454 IntRect result; |
| 1456 Vector<IntRect> rects; | 1455 Vector<IntRect> rects; |
| 1457 TextRects(rects); | 1456 TextRects(rects); |
| 1458 for (const IntRect& rect : rects) | 1457 for (const IntRect& rect : rects) |
| 1459 result.Unite(rect); | 1458 result.Unite(rect); |
| 1460 return result; | 1459 return result; |
| 1461 } | 1460 } |
| 1462 | 1461 |
| 1463 void Range::TextRects(Vector<IntRect>& rects, bool use_selection_height) const { | 1462 void Range::TextRects(Vector<IntRect>& rects, bool use_selection_height) const { |
| 1464 Node* start_container = start_.Container(); | 1463 Node* start_container = &start_.Container(); |
| 1465 DCHECK(start_container); | 1464 DCHECK(start_container); |
| 1466 Node* end_container = end_.Container(); | 1465 Node* end_container = &end_.Container(); |
| 1467 DCHECK(end_container); | 1466 DCHECK(end_container); |
| 1468 | 1467 |
| 1469 Node* stop_node = PastLastNode(); | 1468 Node* stop_node = PastLastNode(); |
| 1470 for (Node* node = FirstNode(); node != stop_node; | 1469 for (Node* node = FirstNode(); node != stop_node; |
| 1471 node = NodeTraversal::Next(*node)) { | 1470 node = NodeTraversal::Next(*node)) { |
| 1472 LayoutObject* r = node->GetLayoutObject(); | 1471 LayoutObject* r = node->GetLayoutObject(); |
| 1473 if (!r || !r->IsText()) | 1472 if (!r || !r->IsText()) |
| 1474 continue; | 1473 continue; |
| 1475 LayoutText* layout_text = ToLayoutText(r); | 1474 LayoutText* layout_text = ToLayoutText(r); |
| 1476 unsigned start_offset = node == start_container ? start_.Offset() : 0; | 1475 unsigned start_offset = node == start_container ? start_.Offset() : 0; |
| 1477 unsigned end_offset = node == end_container | 1476 unsigned end_offset = node == end_container |
| 1478 ? end_.Offset() | 1477 ? end_.Offset() |
| 1479 : std::numeric_limits<unsigned>::max(); | 1478 : std::numeric_limits<unsigned>::max(); |
| 1480 layout_text->AbsoluteRectsForRange(rects, start_offset, end_offset, | 1479 layout_text->AbsoluteRectsForRange(rects, start_offset, end_offset, |
| 1481 use_selection_height); | 1480 use_selection_height); |
| 1482 } | 1481 } |
| 1483 } | 1482 } |
| 1484 | 1483 |
| 1485 void Range::TextQuads(Vector<FloatQuad>& quads, | 1484 void Range::TextQuads(Vector<FloatQuad>& quads, |
| 1486 bool use_selection_height) const { | 1485 bool use_selection_height) const { |
| 1487 Node* start_container = start_.Container(); | 1486 Node* start_container = &start_.Container(); |
| 1488 DCHECK(start_container); | 1487 DCHECK(start_container); |
| 1489 Node* end_container = end_.Container(); | 1488 Node* end_container = &end_.Container(); |
| 1490 DCHECK(end_container); | 1489 DCHECK(end_container); |
| 1491 | 1490 |
| 1492 Node* stop_node = PastLastNode(); | 1491 Node* stop_node = PastLastNode(); |
| 1493 for (Node* node = FirstNode(); node != stop_node; | 1492 for (Node* node = FirstNode(); node != stop_node; |
| 1494 node = NodeTraversal::Next(*node)) { | 1493 node = NodeTraversal::Next(*node)) { |
| 1495 LayoutObject* r = node->GetLayoutObject(); | 1494 LayoutObject* r = node->GetLayoutObject(); |
| 1496 if (!r || !r->IsText()) | 1495 if (!r || !r->IsText()) |
| 1497 continue; | 1496 continue; |
| 1498 LayoutText* layout_text = ToLayoutText(r); | 1497 LayoutText* layout_text = ToLayoutText(r); |
| 1499 unsigned start_offset = node == start_container ? start_.Offset() : 0; | 1498 unsigned start_offset = node == start_container ? start_.Offset() : 0; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1517 static inline void BoundaryNodeChildrenWillBeRemoved( | 1516 static inline void BoundaryNodeChildrenWillBeRemoved( |
| 1518 RangeBoundaryPoint& boundary, | 1517 RangeBoundaryPoint& boundary, |
| 1519 ContainerNode& container) { | 1518 ContainerNode& container) { |
| 1520 for (Node* node_to_be_removed = container.FirstChild(); node_to_be_removed; | 1519 for (Node* node_to_be_removed = container.FirstChild(); node_to_be_removed; |
| 1521 node_to_be_removed = node_to_be_removed->nextSibling()) { | 1520 node_to_be_removed = node_to_be_removed->nextSibling()) { |
| 1522 if (boundary.ChildBefore() == node_to_be_removed) { | 1521 if (boundary.ChildBefore() == node_to_be_removed) { |
| 1523 boundary.SetToStartOfNode(container); | 1522 boundary.SetToStartOfNode(container); |
| 1524 return; | 1523 return; |
| 1525 } | 1524 } |
| 1526 | 1525 |
| 1527 for (Node* n = boundary.Container(); n; n = n->parentNode()) { | 1526 for (Node* n = &boundary.Container(); n; n = n->parentNode()) { |
| 1528 if (n == node_to_be_removed) { | 1527 if (n == node_to_be_removed) { |
| 1529 boundary.SetToStartOfNode(container); | 1528 boundary.SetToStartOfNode(container); |
| 1530 return; | 1529 return; |
| 1531 } | 1530 } |
| 1532 } | 1531 } |
| 1533 } | 1532 } |
| 1534 } | 1533 } |
| 1535 | 1534 |
| 1536 void Range::NodeChildrenWillBeRemoved(ContainerNode& container) { | 1535 void Range::NodeChildrenWillBeRemoved(ContainerNode& container) { |
| 1537 DCHECK_EQ(container.GetDocument(), owner_document_); | 1536 DCHECK_EQ(container.GetDocument(), owner_document_); |
| 1538 BoundaryNodeChildrenWillBeRemoved(start_, container); | 1537 BoundaryNodeChildrenWillBeRemoved(start_, container); |
| 1539 BoundaryNodeChildrenWillBeRemoved(end_, container); | 1538 BoundaryNodeChildrenWillBeRemoved(end_, container); |
| 1540 } | 1539 } |
| 1541 | 1540 |
| 1542 static inline void BoundaryNodeWillBeRemoved(RangeBoundaryPoint& boundary, | 1541 static inline void BoundaryNodeWillBeRemoved(RangeBoundaryPoint& boundary, |
| 1543 Node& node_to_be_removed) { | 1542 Node& node_to_be_removed) { |
| 1544 if (boundary.ChildBefore() == node_to_be_removed) { | 1543 if (boundary.ChildBefore() == node_to_be_removed) { |
| 1545 boundary.ChildBeforeWillBeRemoved(); | 1544 boundary.ChildBeforeWillBeRemoved(); |
| 1546 return; | 1545 return; |
| 1547 } | 1546 } |
| 1548 | 1547 |
| 1549 for (Node* n = boundary.Container(); n; n = n->parentNode()) { | 1548 for (Node* n = &boundary.Container(); n; n = n->parentNode()) { |
| 1550 if (n == node_to_be_removed) { | 1549 if (n == node_to_be_removed) { |
| 1551 boundary.SetToBeforeChild(node_to_be_removed); | 1550 boundary.SetToBeforeChild(node_to_be_removed); |
| 1552 return; | 1551 return; |
| 1553 } | 1552 } |
| 1554 } | 1553 } |
| 1555 } | 1554 } |
| 1556 | 1555 |
| 1557 void Range::NodeWillBeRemoved(Node& node) { | 1556 void Range::NodeWillBeRemoved(Node& node) { |
| 1558 DCHECK_EQ(node.GetDocument(), owner_document_); | 1557 DCHECK_EQ(node.GetDocument(), owner_document_); |
| 1559 DCHECK_NE(node, owner_document_.Get()); | 1558 DCHECK_NE(node, owner_document_.Get()); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1605 void Range::DidRemoveText(Node* text, unsigned offset, unsigned length) { | 1604 void Range::DidRemoveText(Node* text, unsigned offset, unsigned length) { |
| 1606 DCHECK(text); | 1605 DCHECK(text); |
| 1607 DCHECK_EQ(text->GetDocument(), owner_document_); | 1606 DCHECK_EQ(text->GetDocument(), owner_document_); |
| 1608 BoundaryTextRemoved(start_, text, offset, length); | 1607 BoundaryTextRemoved(start_, text, offset, length); |
| 1609 BoundaryTextRemoved(end_, text, offset, length); | 1608 BoundaryTextRemoved(end_, text, offset, length); |
| 1610 } | 1609 } |
| 1611 | 1610 |
| 1612 static inline void BoundaryTextNodesMerged(RangeBoundaryPoint& boundary, | 1611 static inline void BoundaryTextNodesMerged(RangeBoundaryPoint& boundary, |
| 1613 const NodeWithIndex& old_node, | 1612 const NodeWithIndex& old_node, |
| 1614 unsigned offset) { | 1613 unsigned offset) { |
| 1615 if (boundary.Container() == old_node.GetNode()) | 1614 if (boundary.Container() == old_node.GetNode()) { |
| 1616 boundary.Set(old_node.GetNode().previousSibling(), | 1615 Node* const previous_sibling = old_node.GetNode().previousSibling(); |
| 1617 boundary.Offset() + offset, 0); | 1616 DCHECK(previous_sibling); |
| 1618 else if (boundary.Container() == old_node.GetNode().parentNode() && | 1617 boundary.Set(*previous_sibling, boundary.Offset() + offset, 0); |
| 1619 boundary.Offset() == static_cast<unsigned>(old_node.Index())) | 1618 } else if (boundary.Container() == old_node.GetNode().parentNode() && |
| 1620 boundary.Set(old_node.GetNode().previousSibling(), offset, 0); | 1619 boundary.Offset() == static_cast<unsigned>(old_node.Index())) { |
| 1620 Node* const previous_sibling = old_node.GetNode().previousSibling(); |
| 1621 DCHECK(previous_sibling); |
| 1622 boundary.Set(*previous_sibling, offset, 0); |
| 1623 } |
| 1621 } | 1624 } |
| 1622 | 1625 |
| 1623 void Range::DidMergeTextNodes(const NodeWithIndex& old_node, unsigned offset) { | 1626 void Range::DidMergeTextNodes(const NodeWithIndex& old_node, unsigned offset) { |
| 1624 DCHECK_EQ(old_node.GetNode().GetDocument(), owner_document_); | 1627 DCHECK_EQ(old_node.GetNode().GetDocument(), owner_document_); |
| 1625 DCHECK(old_node.GetNode().parentNode()); | 1628 DCHECK(old_node.GetNode().parentNode()); |
| 1626 DCHECK(old_node.GetNode().IsTextNode()); | 1629 DCHECK(old_node.GetNode().IsTextNode()); |
| 1627 DCHECK(old_node.GetNode().previousSibling()); | 1630 DCHECK(old_node.GetNode().previousSibling()); |
| 1628 DCHECK(old_node.GetNode().previousSibling()->IsTextNode()); | 1631 DCHECK(old_node.GetNode().previousSibling()->IsTextNode()); |
| 1629 BoundaryTextNodesMerged(start_, old_node, offset); | 1632 BoundaryTextNodesMerged(start_, old_node, offset); |
| 1630 BoundaryTextNodesMerged(end_, old_node, offset); | 1633 BoundaryTextNodesMerged(end_, old_node, offset); |
| 1631 } | 1634 } |
| 1632 | 1635 |
| 1633 void Range::UpdateOwnerDocumentIfNeeded() { | 1636 void Range::UpdateOwnerDocumentIfNeeded() { |
| 1634 DCHECK(start_.Container()); | 1637 Document& new_document = start_.Container().GetDocument(); |
| 1635 DCHECK(end_.Container()); | 1638 DCHECK_EQ(new_document, end_.Container().GetDocument()); |
| 1636 Document& new_document = start_.Container()->GetDocument(); | |
| 1637 DCHECK_EQ(new_document, end_.Container()->GetDocument()); | |
| 1638 if (new_document == owner_document_) | 1639 if (new_document == owner_document_) |
| 1639 return; | 1640 return; |
| 1640 owner_document_->DetachRange(this); | 1641 owner_document_->DetachRange(this); |
| 1641 owner_document_ = &new_document; | 1642 owner_document_ = &new_document; |
| 1642 owner_document_->AttachRange(this); | 1643 owner_document_->AttachRange(this); |
| 1643 } | 1644 } |
| 1644 | 1645 |
| 1645 static inline void BoundaryTextNodeSplit(RangeBoundaryPoint& boundary, | 1646 static inline void BoundaryTextNodeSplit(RangeBoundaryPoint& boundary, |
| 1646 const Text& old_node) { | 1647 const Text& old_node) { |
| 1647 Node* boundary_container = boundary.Container(); | |
| 1648 unsigned boundary_offset = boundary.Offset(); | 1648 unsigned boundary_offset = boundary.Offset(); |
| 1649 if (boundary.ChildBefore() == &old_node) | 1649 if (boundary.ChildBefore() == &old_node) { |
| 1650 boundary.Set(boundary_container, boundary_offset + 1, | 1650 boundary.Set(boundary.Container(), boundary_offset + 1, |
| 1651 old_node.nextSibling()); | 1651 old_node.nextSibling()); |
| 1652 else if (boundary.Container() == &old_node && | 1652 } else if (boundary.Container() == &old_node && |
| 1653 boundary_offset > old_node.length()) | 1653 boundary_offset > old_node.length()) { |
| 1654 boundary.Set(old_node.nextSibling(), boundary_offset - old_node.length(), | 1654 Node* const next_sibling = old_node.nextSibling(); |
| 1655 0); | 1655 DCHECK(next_sibling); |
| 1656 boundary.Set(*next_sibling, boundary_offset - old_node.length(), 0); |
| 1657 } |
| 1656 } | 1658 } |
| 1657 | 1659 |
| 1658 void Range::DidSplitTextNode(const Text& old_node) { | 1660 void Range::DidSplitTextNode(const Text& old_node) { |
| 1659 DCHECK_EQ(old_node.GetDocument(), owner_document_); | 1661 DCHECK_EQ(old_node.GetDocument(), owner_document_); |
| 1660 DCHECK(old_node.parentNode()); | 1662 DCHECK(old_node.parentNode()); |
| 1661 DCHECK(old_node.nextSibling()); | 1663 DCHECK(old_node.nextSibling()); |
| 1662 DCHECK(old_node.nextSibling()->IsTextNode()); | 1664 DCHECK(old_node.nextSibling()->IsTextNode()); |
| 1663 BoundaryTextNodeSplit(start_, old_node); | 1665 BoundaryTextNodeSplit(start_, old_node); |
| 1664 BoundaryTextNodeSplit(end_, old_node); | 1666 BoundaryTextNodeSplit(end_, old_node); |
| 1665 DCHECK(BoundaryPointsValid()); | 1667 DCHECK(BoundaryPointsValid()); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1700 GetBorderAndTextQuads(quads); | 1702 GetBorderAndTextQuads(quads); |
| 1701 | 1703 |
| 1702 return ClientRectList::Create(quads); | 1704 return ClientRectList::Create(quads); |
| 1703 } | 1705 } |
| 1704 | 1706 |
| 1705 ClientRect* Range::getBoundingClientRect() const { | 1707 ClientRect* Range::getBoundingClientRect() const { |
| 1706 return ClientRect::Create(BoundingRect()); | 1708 return ClientRect::Create(BoundingRect()); |
| 1707 } | 1709 } |
| 1708 | 1710 |
| 1709 void Range::GetBorderAndTextQuads(Vector<FloatQuad>& quads) const { | 1711 void Range::GetBorderAndTextQuads(Vector<FloatQuad>& quads) const { |
| 1710 Node* start_container = start_.Container(); | 1712 Node* start_container = &start_.Container(); |
| 1711 Node* end_container = end_.Container(); | 1713 Node* end_container = &end_.Container(); |
| 1712 Node* stop_node = PastLastNode(); | 1714 Node* stop_node = PastLastNode(); |
| 1713 | 1715 |
| 1714 HeapHashSet<Member<Node>> node_set; | 1716 HeapHashSet<Member<Node>> node_set; |
| 1715 for (Node* node = FirstNode(); node != stop_node; | 1717 for (Node* node = FirstNode(); node != stop_node; |
| 1716 node = NodeTraversal::Next(*node)) { | 1718 node = NodeTraversal::Next(*node)) { |
| 1717 if (node->IsElementNode()) | 1719 if (node->IsElementNode()) |
| 1718 node_set.insert(node); | 1720 node_set.insert(node); |
| 1719 } | 1721 } |
| 1720 | 1722 |
| 1721 for (Node* node = FirstNode(); node != stop_node; | 1723 for (Node* node = FirstNode(); node != stop_node; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1826 .Data() | 1828 .Data() |
| 1827 << "start offset: " << range->startOffset() | 1829 << "start offset: " << range->startOffset() |
| 1828 << ", end offset: " << range->endOffset(); | 1830 << ", end offset: " << range->endOffset(); |
| 1829 } else { | 1831 } else { |
| 1830 LOG(INFO) << "Cannot show tree if range is null, or if boundary points are " | 1832 LOG(INFO) << "Cannot show tree if range is null, or if boundary points are " |
| 1831 "invalid."; | 1833 "invalid."; |
| 1832 } | 1834 } |
| 1833 } | 1835 } |
| 1834 | 1836 |
| 1835 #endif | 1837 #endif |
| OLD | NEW |