Changeset 84265 in webkit
- Timestamp:
- Apr 19, 2011 11:05:52 AM (13 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r84264 r84265 1 2011-04-19 Ryosuke Niwa <rniwa@webkit.org> 2 3 Reviewed by Dimitri Glazkov. 4 5 REGRESSION(r74228-75294): removing nodes is 200+ times slower when selection is inside a shadow DOM 6 https://bugs.webkit.org/show_bug.cgi?id=57061 7 8 The bug was caused by Range::compareNode's incorrectly returning NODE_INSIDE when the selection is inside 9 a shadow DOM and the node is outside of the shadow DOM. This caused respondToNodeModification to call 10 RenderView::clearSelection every time a node is removed when selection is in a shadow DOM and resulted in 11 a significant performance regression. 12 13 Fixed Ranged::compareNode by making Range::compareBoundaryPoints throw a WRONG_DOCUMENT_ERR when there are 14 no common ancestors between containerA and containerB. This will force compareNode to also throw an exception 15 and prevents respondToNodeModification from clearing selection. 16 17 No new tests because this is a performance improvement and the fix in Range cannot be tested since shadow DOM 18 isn't exposed to JavaScript. 19 20 * dom/Range.cpp: 21 (WebCore::Range::setStart): Calls compareBoundaryPoints; since we ensures that the root container noes of 22 start and end nodes are same, we should never get an exception from compareBoundaryPoints. 23 (WebCore::Range::setEnd): Ditto. 24 (WebCore::Range::isPointInRange): Calls compareBoundaryPoints; returns false when compareBoundaryPoints 25 throws an exception. 26 (WebCore::Range::comparePoint): Calls compareBoundaryPoints; exit early when an exception is thrown by 27 compareBoundaryPoints. 28 (WebCore::Range::compareBoundaryPoints): Throws an exception when two containers do not have a common ancestor. 29 (WebCore::Range::boundaryPointsValid): Calls compareBoundaryPoints and checks that it didn't throw an exception. 30 * dom/Range.h: 31 * editing/SelectionController.cpp: 32 (WebCore::SelectionController::respondToNodeModification): 33 * editing/htmlediting.cpp: 34 (WebCore::comparePositions): Calls compareBoundaryPoints. 35 * editing/markup.cpp: 36 (WebCore::createMarkup): Calls compareBoundaryPoints; since startNode and pastEnd are both in the same document 37 and neither are in a shadow DOM, it should never throw an exception. 38 * page/DOMSelection.cpp: 39 (WebCore::DOMSelection::containsNode): Calls compareBoundaryPoints; node is fully selected only if no exception 40 was thrown. 41 1 42 2011-04-19 Jungshik Shin <jshin@chromium.org> 2 43 -
trunk/Source/WebCore/dom/Range.cpp
r82778 r84265 225 225 collapse(true, ec); 226 226 // check if new start after end 227 else if (compareBoundaryPoints(m_start, m_end) > 0) 227 else if (compareBoundaryPoints(m_start, m_end, ec) > 0) { 228 ASSERT(!ec); 228 229 collapse(true, ec); 230 } 229 231 } 230 232 … … 263 265 collapse(false, ec); 264 266 // check if new end before start 265 if (compareBoundaryPoints(m_start, m_end) > 0) 267 if (compareBoundaryPoints(m_start, m_end, ec) > 0) { 268 ASSERT(!ec); 266 269 collapse(false, ec); 270 } 267 271 } 268 272 … … 307 311 return false; 308 312 309 return compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset() ) >= 0310 && compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset() ) <= 0;313 return compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset(), ec) >= 0 && !ec 314 && compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset(), ec) <= 0 && !ec; 311 315 } 312 316 … … 338 342 339 343 // compare to start, and point comes before 340 if (compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset() ) < 0)344 if (compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset(), ec) < 0) 341 345 return -1; 342 346 347 if (ec) 348 return 0; 349 343 350 // compare to end, and point comes after 344 if (compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset() ) > 0)351 if (compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset(), ec) > 0 && !ec) 345 352 return 1; 346 353 … … 434 441 switch (how) { 435 442 case START_TO_START: 436 return compareBoundaryPoints(m_start, sourceRange->m_start );443 return compareBoundaryPoints(m_start, sourceRange->m_start, ec); 437 444 case START_TO_END: 438 return compareBoundaryPoints(m_end, sourceRange->m_start );445 return compareBoundaryPoints(m_end, sourceRange->m_start, ec); 439 446 case END_TO_END: 440 return compareBoundaryPoints(m_end, sourceRange->m_end );447 return compareBoundaryPoints(m_end, sourceRange->m_end, ec); 441 448 case END_TO_START: 442 return compareBoundaryPoints(m_start, sourceRange->m_end );449 return compareBoundaryPoints(m_start, sourceRange->m_end, ec); 443 450 } 444 451 … … 447 454 } 448 455 449 short Range::compareBoundaryPoints(Node* containerA, int offsetA, Node* containerB, int offsetB )456 short Range::compareBoundaryPoints(Node* containerA, int offsetA, Node* containerB, int offsetB, ExceptionCode& ec) 450 457 { 451 458 ASSERT(containerA); … … 508 515 // ### we need to do a traversal here instead 509 516 Node* commonAncestor = commonAncestorContainer(containerA, containerB); 510 if (!commonAncestor) 511 return 0; 517 if (!commonAncestor) { 518 ec = WRONG_DOCUMENT_ERR; 519 return 0; 520 } 512 521 Node* childA = containerA; 513 522 while (childA && childA->parentNode() != commonAncestor) … … 538 547 } 539 548 540 short Range::compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB )541 { 542 return compareBoundaryPoints(boundaryA.container(), boundaryA.offset(), boundaryB.container(), boundaryB.offset() );549 short Range::compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB, ExceptionCode& ec) 550 { 551 return compareBoundaryPoints(boundaryA.container(), boundaryA.offset(), boundaryB.container(), boundaryB.offset(), ec); 543 552 } 544 553 545 554 bool Range::boundaryPointsValid() const 546 555 { 547 return m_start.container() && compareBoundaryPoints(m_start, m_end) <= 0; 556 ExceptionCode ec = 0; 557 return m_start.container() && compareBoundaryPoints(m_start, m_end, ec) <= 0 && !ec; 548 558 } 549 559 -
trunk/Source/WebCore/dom/Range.h
r82533 r84265 70 70 enum CompareHow { START_TO_START, START_TO_END, END_TO_END, END_TO_START }; 71 71 short compareBoundaryPoints(CompareHow, const Range* sourceRange, ExceptionCode&) const; 72 static short compareBoundaryPoints(Node* containerA, int offsetA, Node* containerB, int offsetB );73 static short compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB );72 static short compareBoundaryPoints(Node* containerA, int offsetA, Node* containerB, int offsetB, ExceptionCode&); 73 static short compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB, ExceptionCode&); 74 74 bool boundaryPointsValid() const; 75 75 bool intersectsNode(Node* refNode, ExceptionCode&); -
trunk/Source/WebCore/editing/SelectionController.cpp
r82593 r84265 252 252 else 253 253 m_selection.setWithoutValidation(m_selection.end(), m_selection.start()); 254 } else if ( m_selection.firstRange()) {254 } else if (RefPtr<Range> range = m_selection.firstRange()) { 255 255 ExceptionCode ec = 0; 256 Range::CompareResults compareResult = m_selection.firstRange()->compareNode(node, ec);256 Range::CompareResults compareResult = range->compareNode(node, ec); 257 257 if (!ec && (compareResult == Range::NODE_BEFORE_AND_AFTER || compareResult == Range::NODE_INSIDE)) { 258 258 // If we did nothing here, when this node's renderer was destroyed, the rect that it -
trunk/Source/WebCore/editing/htmlediting.cpp
r83322 r84265 123 123 } 124 124 125 int result = Range::compareBoundaryPoints(nodeA, offsetA, nodeB, offsetB); 125 ExceptionCode ec; 126 int result = Range::compareBoundaryPoints(nodeA, offsetA, nodeB, offsetB, ec); 126 127 return result ? result : bias; 127 128 } -
trunk/Source/WebCore/editing/markup.cpp
r81295 r84265 572 572 startNode = visibleStart.next().deepEquivalent().deprecatedNode(); 573 573 574 if (pastEnd && Range::compareBoundaryPoints(startNode, 0, pastEnd, 0) >= 0) { 574 ExceptionCode ec = 0; 575 if (pastEnd && Range::compareBoundaryPoints(startNode, 0, pastEnd, 0, ec) >= 0) { 576 ASSERT(!ec); 575 577 if (deleteButton) 576 578 deleteButton->enable(); 577 579 return interchangeNewlineString; 578 580 } 581 ASSERT(!ec); 579 582 } 580 583 -
trunk/Source/WebCore/page/DOMSelection.cpp
r82588 r84265 475 475 476 476 ExceptionCode ec = 0; 477 bool nodeFullySelected = Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->startContainer(ec), selectedRange->startOffset(ec) ) >= 0478 && Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->endContainer(ec), selectedRange->endOffset(ec) ) <= 0;477 bool nodeFullySelected = Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->startContainer(ec), selectedRange->startOffset(ec), ec) >= 0 && !ec 478 && Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->endContainer(ec), selectedRange->endOffset(ec), ec) <= 0 && !ec; 479 479 ASSERT(!ec); 480 480 if (nodeFullySelected) 481 481 return true; 482 482 483 bool nodeFullyUnselected = Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->endContainer(ec), selectedRange->endOffset(ec)) > 0484 || Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->startContainer(ec), selectedRange->startOffset(ec)) < 0;483 bool nodeFullyUnselected = (Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->endContainer(ec), selectedRange->endOffset(ec), ec) > 0 && !ec) 484 || (Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->startContainer(ec), selectedRange->startOffset(ec), ec) < 0 && !ec); 485 485 ASSERT(!ec); 486 486 if (nodeFullyUnselected)
Note: See TracChangeset
for help on using the changeset viewer.