OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. | 2 * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
293 m_typingStyle->removeStyleAddedByElement(enclosingAnchorElement(m_selectionT
oDelete.start())); | 293 m_typingStyle->removeStyleAddedByElement(enclosingAnchorElement(m_selectionT
oDelete.start())); |
294 | 294 |
295 // If we're deleting into a Mail blockquote, save the style at end() instead
of start() | 295 // If we're deleting into a Mail blockquote, save the style at end() instead
of start() |
296 // We'll use this later in computeTypingStyleAfterDelete if we end up outsid
e of a Mail blockquote | 296 // We'll use this later in computeTypingStyleAfterDelete if we end up outsid
e of a Mail blockquote |
297 if (enclosingNodeOfType(m_selectionToDelete.start(), isMailHTMLBlockquoteEle
ment)) | 297 if (enclosingNodeOfType(m_selectionToDelete.start(), isMailHTMLBlockquoteEle
ment)) |
298 m_deleteIntoBlockquoteStyle = EditingStyle::create(m_selectionToDelete.e
nd()); | 298 m_deleteIntoBlockquoteStyle = EditingStyle::create(m_selectionToDelete.e
nd()); |
299 else | 299 else |
300 m_deleteIntoBlockquoteStyle = nullptr; | 300 m_deleteIntoBlockquoteStyle = nullptr; |
301 } | 301 } |
302 | 302 |
303 bool DeleteSelectionCommand::handleSpecialCaseBRDelete() | 303 bool DeleteSelectionCommand::handleSpecialCaseBRDelete(EditingState* editingStat
e) |
304 { | 304 { |
305 Node* nodeAfterUpstreamStart = m_upstreamStart.computeNodeAfterPosition(); | 305 Node* nodeAfterUpstreamStart = m_upstreamStart.computeNodeAfterPosition(); |
306 Node* nodeAfterDownstreamStart = m_downstreamStart.computeNodeAfterPosition(
); | 306 Node* nodeAfterDownstreamStart = m_downstreamStart.computeNodeAfterPosition(
); |
307 // Upstream end will appear before BR due to canonicalization | 307 // Upstream end will appear before BR due to canonicalization |
308 Node* nodeAfterUpstreamEnd = m_upstreamEnd.computeNodeAfterPosition(); | 308 Node* nodeAfterUpstreamEnd = m_upstreamEnd.computeNodeAfterPosition(); |
309 | 309 |
310 if (!nodeAfterUpstreamStart || !nodeAfterDownstreamStart) | 310 if (!nodeAfterUpstreamStart || !nodeAfterDownstreamStart) |
311 return false; | 311 return false; |
312 | 312 |
313 // Check for special-case where the selection contains only a BR on a line b
y itself after another BR. | 313 // Check for special-case where the selection contains only a BR on a line b
y itself after another BR. |
314 bool upstreamStartIsBR = isHTMLBRElement(*nodeAfterUpstreamStart); | 314 bool upstreamStartIsBR = isHTMLBRElement(*nodeAfterUpstreamStart); |
315 bool downstreamStartIsBR = isHTMLBRElement(*nodeAfterDownstreamStart); | 315 bool downstreamStartIsBR = isHTMLBRElement(*nodeAfterDownstreamStart); |
316 bool isBROnLineByItself = upstreamStartIsBR && downstreamStartIsBR && nodeAf
terDownstreamStart == nodeAfterUpstreamEnd; | 316 bool isBROnLineByItself = upstreamStartIsBR && downstreamStartIsBR && nodeAf
terDownstreamStart == nodeAfterUpstreamEnd; |
317 if (isBROnLineByItself) { | 317 if (isBROnLineByItself) { |
318 removeNode(nodeAfterDownstreamStart); | 318 removeNode(nodeAfterDownstreamStart, editingState); |
319 return true; | 319 return true; |
320 } | 320 } |
321 | 321 |
322 // FIXME: This code doesn't belong in here. | 322 // FIXME: This code doesn't belong in here. |
323 // We detect the case where the start is an empty line consisting of BR not
wrapped in a block element. | 323 // We detect the case where the start is an empty line consisting of BR not
wrapped in a block element. |
324 if (upstreamStartIsBR && downstreamStartIsBR && !(isStartOfBlock(createVisib
lePosition(positionBeforeNode(nodeAfterUpstreamStart))) && isEndOfBlock(createVi
siblePosition(positionAfterNode(nodeAfterUpstreamStart))))) { | 324 if (upstreamStartIsBR && downstreamStartIsBR && !(isStartOfBlock(createVisib
lePosition(positionBeforeNode(nodeAfterUpstreamStart))) && isEndOfBlock(createVi
siblePosition(positionAfterNode(nodeAfterUpstreamStart))))) { |
325 m_startsAtEmptyLine = true; | 325 m_startsAtEmptyLine = true; |
326 m_endingPosition = m_downstreamEnd; | 326 m_endingPosition = m_downstreamEnd; |
327 } | 327 } |
328 | 328 |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
424 { | 424 { |
425 // FIXME: Update the endpoints of the range being deleted. | 425 // FIXME: Update the endpoints of the range being deleted. |
426 updatePositionForTextRemoval(node.get(), offset, count, m_endingPosition); | 426 updatePositionForTextRemoval(node.get(), offset, count, m_endingPosition); |
427 updatePositionForTextRemoval(node.get(), offset, count, m_leadingWhitespace)
; | 427 updatePositionForTextRemoval(node.get(), offset, count, m_leadingWhitespace)
; |
428 updatePositionForTextRemoval(node.get(), offset, count, m_trailingWhitespace
); | 428 updatePositionForTextRemoval(node.get(), offset, count, m_trailingWhitespace
); |
429 updatePositionForTextRemoval(node.get(), offset, count, m_downstreamEnd); | 429 updatePositionForTextRemoval(node.get(), offset, count, m_downstreamEnd); |
430 | 430 |
431 CompositeEditCommand::deleteTextFromNode(node, offset, count); | 431 CompositeEditCommand::deleteTextFromNode(node, offset, count); |
432 } | 432 } |
433 | 433 |
434 void DeleteSelectionCommand::makeStylingElementsDirectChildrenOfEditableRootToPr
eventStyleLoss() | 434 void DeleteSelectionCommand::makeStylingElementsDirectChildrenOfEditableRootToPr
eventStyleLoss(EditingState* editingState) |
435 { | 435 { |
436 RefPtrWillBeRawPtr<Range> range = createRange(m_selectionToDelete.toNormaliz
edEphemeralRange()); | 436 RefPtrWillBeRawPtr<Range> range = createRange(m_selectionToDelete.toNormaliz
edEphemeralRange()); |
437 RefPtrWillBeRawPtr<Node> node = range->firstNode(); | 437 RefPtrWillBeRawPtr<Node> node = range->firstNode(); |
438 while (node && node != range->pastLastNode()) { | 438 while (node && node != range->pastLastNode()) { |
439 RefPtrWillBeRawPtr<Node> nextNode = NodeTraversal::next(*node); | 439 RefPtrWillBeRawPtr<Node> nextNode = NodeTraversal::next(*node); |
440 if (isHTMLStyleElement(*node) || isHTMLLinkElement(*node)) { | 440 if (isHTMLStyleElement(*node) || isHTMLLinkElement(*node)) { |
441 nextNode = NodeTraversal::nextSkippingChildren(*node); | 441 nextNode = NodeTraversal::nextSkippingChildren(*node); |
442 RefPtrWillBeRawPtr<Element> rootEditableElement = node->rootEditable
Element(); | 442 RefPtrWillBeRawPtr<Element> rootEditableElement = node->rootEditable
Element(); |
443 if (rootEditableElement.get()) { | 443 if (rootEditableElement.get()) { |
444 removeNode(node); | 444 removeNode(node, editingState); |
445 appendNode(node, rootEditableElement); | 445 if (editingState->isAborted()) |
| 446 return; |
| 447 appendNode(node, rootEditableElement, editingState); |
| 448 if (editingState->isAborted()) |
| 449 return; |
446 } | 450 } |
447 } | 451 } |
448 node = nextNode; | 452 node = nextNode; |
449 } | 453 } |
450 } | 454 } |
451 | 455 |
452 void DeleteSelectionCommand::handleGeneralDelete(EditingState* editingState) | 456 void DeleteSelectionCommand::handleGeneralDelete(EditingState* editingState) |
453 { | 457 { |
454 if (m_upstreamStart.isNull()) | 458 if (m_upstreamStart.isNull()) |
455 return; | 459 return; |
456 | 460 |
457 int startOffset = m_upstreamStart.computeEditingOffset(); | 461 int startOffset = m_upstreamStart.computeEditingOffset(); |
458 Node* startNode = m_upstreamStart.anchorNode(); | 462 Node* startNode = m_upstreamStart.anchorNode(); |
459 ASSERT(startNode); | 463 ASSERT(startNode); |
460 | 464 |
461 makeStylingElementsDirectChildrenOfEditableRootToPreventStyleLoss(); | 465 makeStylingElementsDirectChildrenOfEditableRootToPreventStyleLoss(editingSta
te); |
| 466 if (editingState->isAborted()) |
| 467 return; |
462 | 468 |
463 // Never remove the start block unless it's a table, in which case we won't
merge content in. | 469 // Never remove the start block unless it's a table, in which case we won't
merge content in. |
464 if (startNode->isSameNode(m_startBlock.get()) && !startOffset && canHaveChil
drenForEditing(startNode) && !isHTMLTableElement(*startNode)) { | 470 if (startNode->isSameNode(m_startBlock.get()) && !startOffset && canHaveChil
drenForEditing(startNode) && !isHTMLTableElement(*startNode)) { |
465 startOffset = 0; | 471 startOffset = 0; |
466 startNode = NodeTraversal::next(*startNode); | 472 startNode = NodeTraversal::next(*startNode); |
467 if (!startNode) | 473 if (!startNode) |
468 return; | 474 return; |
469 } | 475 } |
470 | 476 |
471 if (startOffset >= caretMaxOffset(startNode) && startNode->isTextNode()) { | 477 if (startOffset >= caretMaxOffset(startNode) && startNode->isTextNode()) { |
(...skipping 11 matching lines...) Expand all Loading... |
483 if (!startNode) | 489 if (!startNode) |
484 return; | 490 return; |
485 | 491 |
486 if (startNode == m_downstreamEnd.anchorNode()) { | 492 if (startNode == m_downstreamEnd.anchorNode()) { |
487 if (m_downstreamEnd.computeEditingOffset() - startOffset > 0) { | 493 if (m_downstreamEnd.computeEditingOffset() - startOffset > 0) { |
488 if (startNode->isTextNode()) { | 494 if (startNode->isTextNode()) { |
489 // in a text node that needs to be trimmed | 495 // in a text node that needs to be trimmed |
490 Text* text = toText(startNode); | 496 Text* text = toText(startNode); |
491 deleteTextFromNode(text, startOffset, m_downstreamEnd.computeOff
setInContainerNode() - startOffset); | 497 deleteTextFromNode(text, startOffset, m_downstreamEnd.computeOff
setInContainerNode() - startOffset); |
492 } else { | 498 } else { |
493 removeChildrenInRange(startNode, startOffset, m_downstreamEnd.co
mputeEditingOffset()); | 499 removeChildrenInRange(startNode, startOffset, m_downstreamEnd.co
mputeEditingOffset(), editingState); |
| 500 if (editingState->isAborted()) |
| 501 return; |
494 m_endingPosition = m_upstreamStart; | 502 m_endingPosition = m_upstreamStart; |
495 } | 503 } |
496 } | 504 } |
497 | 505 |
498 // The selection to delete is all in one node. | 506 // The selection to delete is all in one node. |
499 if (!startNode->layoutObject() || (!startOffset && m_downstreamEnd.atLas
tEditingPositionForNode())) { | 507 if (!startNode->layoutObject() || (!startOffset && m_downstreamEnd.atLas
tEditingPositionForNode())) { |
500 removeNode(startNode, editingState); | 508 removeNode(startNode, editingState); |
501 if (editingState->isAborted()) | 509 if (editingState->isAborted()) |
502 return; | 510 return; |
503 } | 511 } |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
566 // always know which children to remove. | 574 // always know which children to remove. |
567 } else if (!(startNodeWasDescendantOfEndNode && !m_upstreamStart
.inDocument())) { | 575 } else if (!(startNodeWasDescendantOfEndNode && !m_upstreamStart
.inDocument())) { |
568 int offset = 0; | 576 int offset = 0; |
569 if (m_upstreamStart.anchorNode()->isDescendantOf(m_downstrea
mEnd.anchorNode())) { | 577 if (m_upstreamStart.anchorNode()->isDescendantOf(m_downstrea
mEnd.anchorNode())) { |
570 Node* n = m_upstreamStart.anchorNode(); | 578 Node* n = m_upstreamStart.anchorNode(); |
571 while (n && n->parentNode() != m_downstreamEnd.anchorNod
e()) | 579 while (n && n->parentNode() != m_downstreamEnd.anchorNod
e()) |
572 n = n->parentNode(); | 580 n = n->parentNode(); |
573 if (n) | 581 if (n) |
574 offset = n->nodeIndex() + 1; | 582 offset = n->nodeIndex() + 1; |
575 } | 583 } |
576 removeChildrenInRange(m_downstreamEnd.anchorNode(), offset,
m_downstreamEnd.computeEditingOffset()); | 584 removeChildrenInRange(m_downstreamEnd.anchorNode(), offset,
m_downstreamEnd.computeEditingOffset(), editingState); |
| 585 if (editingState->isAborted()) |
| 586 return; |
577 m_downstreamEnd = Position::editingPositionOf(m_downstreamEn
d.anchorNode(), offset); | 587 m_downstreamEnd = Position::editingPositionOf(m_downstreamEn
d.anchorNode(), offset); |
578 } | 588 } |
579 } | 589 } |
580 } | 590 } |
581 } | 591 } |
582 } | 592 } |
583 | 593 |
584 void DeleteSelectionCommand::fixupWhitespace() | 594 void DeleteSelectionCommand::fixupWhitespace() |
585 { | 595 { |
586 document().updateLayoutIgnorePendingStylesheets(); | 596 document().updateLayoutIgnorePendingStylesheets(); |
587 // TODO(yosin) |isRenderedCharacter()| should be removed, and we should use | 597 // TODO(yosin) |isRenderedCharacter()| should be removed, and we should use |
588 // |VisiblePosition::characterAfter()| and | 598 // |VisiblePosition::characterAfter()| and |
589 // |VisiblePosition::characterBefore()| | 599 // |VisiblePosition::characterBefore()| |
590 if (m_leadingWhitespace.isNotNull() && !isRenderedCharacter(m_leadingWhitesp
ace) && m_leadingWhitespace.anchorNode()->isTextNode()) { | 600 if (m_leadingWhitespace.isNotNull() && !isRenderedCharacter(m_leadingWhitesp
ace) && m_leadingWhitespace.anchorNode()->isTextNode()) { |
591 Text* textNode = toText(m_leadingWhitespace.anchorNode()); | 601 Text* textNode = toText(m_leadingWhitespace.anchorNode()); |
592 ASSERT(!textNode->layoutObject() || textNode->layoutObject()->style()->c
ollapseWhiteSpace()); | 602 ASSERT(!textNode->layoutObject() || textNode->layoutObject()->style()->c
ollapseWhiteSpace()); |
593 replaceTextInNodePreservingMarkers(textNode, m_leadingWhitespace.compute
OffsetInContainerNode(), 1, nonBreakingSpaceString()); | 603 replaceTextInNodePreservingMarkers(textNode, m_leadingWhitespace.compute
OffsetInContainerNode(), 1, nonBreakingSpaceString()); |
594 } | 604 } |
595 if (m_trailingWhitespace.isNotNull() && !isRenderedCharacter(m_trailingWhite
space) && m_trailingWhitespace.anchorNode()->isTextNode()) { | 605 if (m_trailingWhitespace.isNotNull() && !isRenderedCharacter(m_trailingWhite
space) && m_trailingWhitespace.anchorNode()->isTextNode()) { |
596 Text* textNode = toText(m_trailingWhitespace.anchorNode()); | 606 Text* textNode = toText(m_trailingWhitespace.anchorNode()); |
597 ASSERT(!textNode->layoutObject() || textNode->layoutObject()->style()->c
ollapseWhiteSpace()); | 607 ASSERT(!textNode->layoutObject() || textNode->layoutObject()->style()->c
ollapseWhiteSpace()); |
598 replaceTextInNodePreservingMarkers(textNode, m_trailingWhitespace.comput
eOffsetInContainerNode(), 1, nonBreakingSpaceString()); | 608 replaceTextInNodePreservingMarkers(textNode, m_trailingWhitespace.comput
eOffsetInContainerNode(), 1, nonBreakingSpaceString()); |
599 } | 609 } |
600 } | 610 } |
601 | 611 |
602 // If a selection starts in one block and ends in another, we have to merge to b
ring content before the | 612 // If a selection starts in one block and ends in another, we have to merge to b
ring content before the |
603 // start together with content after the end. | 613 // start together with content after the end. |
604 void DeleteSelectionCommand::mergeParagraphs() | 614 void DeleteSelectionCommand::mergeParagraphs(EditingState* editingState) |
605 { | 615 { |
606 if (!m_mergeBlocksAfterDelete) { | 616 if (!m_mergeBlocksAfterDelete) { |
607 if (m_pruneStartBlockIfNecessary) { | 617 if (m_pruneStartBlockIfNecessary) { |
608 // We aren't going to merge into the start block, so remove it if it
's empty. | 618 // We aren't going to merge into the start block, so remove it if it
's empty. |
609 prune(m_startBlock); | 619 prune(m_startBlock, editingState); |
| 620 if (editingState->isAborted()) |
| 621 return; |
610 // Removing the start block during a deletion is usually an indicati
on that we need | 622 // Removing the start block during a deletion is usually an indicati
on that we need |
611 // a placeholder, but not in this case. | 623 // a placeholder, but not in this case. |
612 m_needPlaceholder = false; | 624 m_needPlaceholder = false; |
613 } | 625 } |
614 return; | 626 return; |
615 } | 627 } |
616 | 628 |
617 // It shouldn't have been asked to both try and merge content into the start
block and prune it. | 629 // It shouldn't have been asked to both try and merge content into the start
block and prune it. |
618 ASSERT(!m_pruneStartBlockIfNecessary); | 630 ASSERT(!m_pruneStartBlockIfNecessary); |
619 | 631 |
620 // FIXME: Deletion should adjust selection endpoints as it removes nodes so
that we never get into this state (4099839). | 632 // FIXME: Deletion should adjust selection endpoints as it removes nodes so
that we never get into this state (4099839). |
621 if (!m_downstreamEnd.inDocument() || !m_upstreamStart.inDocument()) | 633 if (!m_downstreamEnd.inDocument() || !m_upstreamStart.inDocument()) |
622 return; | 634 return; |
623 | 635 |
624 // FIXME: The deletion algorithm shouldn't let this happen. | 636 // FIXME: The deletion algorithm shouldn't let this happen. |
625 if (comparePositions(m_upstreamStart, m_downstreamEnd) > 0) | 637 if (comparePositions(m_upstreamStart, m_downstreamEnd) > 0) |
626 return; | 638 return; |
627 | 639 |
628 // There's nothing to merge. | 640 // There's nothing to merge. |
629 if (m_upstreamStart == m_downstreamEnd) | 641 if (m_upstreamStart == m_downstreamEnd) |
630 return; | 642 return; |
631 | 643 |
632 VisiblePosition startOfParagraphToMove = createVisiblePosition(m_downstreamE
nd); | 644 VisiblePosition startOfParagraphToMove = createVisiblePosition(m_downstreamE
nd); |
633 VisiblePosition mergeDestination = createVisiblePosition(m_upstreamStart); | 645 VisiblePosition mergeDestination = createVisiblePosition(m_upstreamStart); |
634 | 646 |
635 // m_downstreamEnd's block has been emptied out by deletion. There is no co
ntent inside of it to | 647 // m_downstreamEnd's block has been emptied out by deletion. There is no co
ntent inside of it to |
636 // move, so just remove it. | 648 // move, so just remove it. |
637 Element* endBlock = enclosingBlock(m_downstreamEnd.anchorNode()); | 649 Element* endBlock = enclosingBlock(m_downstreamEnd.anchorNode()); |
638 if (!endBlock || !endBlock->contains(startOfParagraphToMove.deepEquivalent()
.anchorNode()) || !startOfParagraphToMove.deepEquivalent().anchorNode()) { | 650 if (!endBlock || !endBlock->contains(startOfParagraphToMove.deepEquivalent()
.anchorNode()) || !startOfParagraphToMove.deepEquivalent().anchorNode()) { |
639 removeNode(enclosingBlock(m_downstreamEnd.anchorNode())); | 651 removeNode(enclosingBlock(m_downstreamEnd.anchorNode()), editingState); |
640 return; | 652 return; |
641 } | 653 } |
642 | 654 |
643 // We need to merge into m_upstreamStart's block, but it's been emptied out
and collapsed by deletion. | 655 // We need to merge into m_upstreamStart's block, but it's been emptied out
and collapsed by deletion. |
644 if (!mergeDestination.deepEquivalent().anchorNode() || (!mergeDestination.de
epEquivalent().anchorNode()->isDescendantOf(enclosingBlock(m_upstreamStart.compu
teContainerNode())) && (!mergeDestination.deepEquivalent().anchorNode()->hasChil
dren() || !m_upstreamStart.computeContainerNode()->hasChildren())) || (m_startsA
tEmptyLine && mergeDestination.deepEquivalent() != startOfParagraphToMove.deepEq
uivalent())) { | 656 if (!mergeDestination.deepEquivalent().anchorNode() || (!mergeDestination.de
epEquivalent().anchorNode()->isDescendantOf(enclosingBlock(m_upstreamStart.compu
teContainerNode())) && (!mergeDestination.deepEquivalent().anchorNode()->hasChil
dren() || !m_upstreamStart.computeContainerNode()->hasChildren())) || (m_startsA
tEmptyLine && mergeDestination.deepEquivalent() != startOfParagraphToMove.deepEq
uivalent())) { |
645 insertNodeAt(HTMLBRElement::create(document()).get(), m_upstreamStart); | 657 insertNodeAt(HTMLBRElement::create(document()).get(), m_upstreamStart, e
ditingState); |
| 658 if (editingState->isAborted()) |
| 659 return; |
646 mergeDestination = createVisiblePosition(m_upstreamStart); | 660 mergeDestination = createVisiblePosition(m_upstreamStart); |
647 } | 661 } |
648 | 662 |
649 if (mergeDestination.deepEquivalent() == startOfParagraphToMove.deepEquivale
nt()) | 663 if (mergeDestination.deepEquivalent() == startOfParagraphToMove.deepEquivale
nt()) |
650 return; | 664 return; |
651 | 665 |
652 VisiblePosition endOfParagraphToMove = endOfParagraph(startOfParagraphToMove
, CanSkipOverEditingBoundary); | 666 VisiblePosition endOfParagraphToMove = endOfParagraph(startOfParagraphToMove
, CanSkipOverEditingBoundary); |
653 | 667 |
654 if (mergeDestination.deepEquivalent() == endOfParagraphToMove.deepEquivalent
()) | 668 if (mergeDestination.deepEquivalent() == endOfParagraphToMove.deepEquivalent
()) |
655 return; | 669 return; |
656 | 670 |
657 // If the merge destination and source to be moved are both list items of di
fferent lists, merge them into single list. | 671 // If the merge destination and source to be moved are both list items of di
fferent lists, merge them into single list. |
658 Node* listItemInFirstParagraph = enclosingNodeOfType(m_upstreamStart, isList
Item); | 672 Node* listItemInFirstParagraph = enclosingNodeOfType(m_upstreamStart, isList
Item); |
659 Node* listItemInSecondParagraph = enclosingNodeOfType(m_downstreamEnd, isLis
tItem); | 673 Node* listItemInSecondParagraph = enclosingNodeOfType(m_downstreamEnd, isLis
tItem); |
660 if (listItemInFirstParagraph && listItemInSecondParagraph | 674 if (listItemInFirstParagraph && listItemInSecondParagraph |
661 && listItemInFirstParagraph->parentElement() != listItemInSecondParagrap
h->parentElement() | 675 && listItemInFirstParagraph->parentElement() != listItemInSecondParagrap
h->parentElement() |
662 && canMergeLists(listItemInFirstParagraph->parentElement(), listItemInSe
condParagraph->parentElement())) { | 676 && canMergeLists(listItemInFirstParagraph->parentElement(), listItemInSe
condParagraph->parentElement())) { |
663 mergeIdenticalElements(listItemInFirstParagraph->parentElement(), listIt
emInSecondParagraph->parentElement()); | 677 mergeIdenticalElements(listItemInFirstParagraph->parentElement(), listIt
emInSecondParagraph->parentElement(), editingState); |
| 678 if (editingState->isAborted()) |
| 679 return; |
664 m_endingPosition = mergeDestination.deepEquivalent(); | 680 m_endingPosition = mergeDestination.deepEquivalent(); |
665 return; | 681 return; |
666 } | 682 } |
667 | 683 |
668 // The rule for merging into an empty block is: only do so if its farther to
the right. | 684 // The rule for merging into an empty block is: only do so if its farther to
the right. |
669 // FIXME: Consider RTL. | 685 // FIXME: Consider RTL. |
670 if (!m_startsAtEmptyLine && isStartOfParagraph(mergeDestination) && absolute
CaretBoundsOf(startOfParagraphToMove).x() > absoluteCaretBoundsOf(mergeDestinati
on).x()) { | 686 if (!m_startsAtEmptyLine && isStartOfParagraph(mergeDestination) && absolute
CaretBoundsOf(startOfParagraphToMove).x() > absoluteCaretBoundsOf(mergeDestinati
on).x()) { |
671 if (isHTMLBRElement(*mostForwardCaretPosition(mergeDestination.deepEquiv
alent()).anchorNode())) { | 687 if (isHTMLBRElement(*mostForwardCaretPosition(mergeDestination.deepEquiv
alent()).anchorNode())) { |
672 removeNodeAndPruneAncestors(mostForwardCaretPosition(mergeDestinatio
n.deepEquivalent()).anchorNode()); | 688 removeNodeAndPruneAncestors(mostForwardCaretPosition(mergeDestinatio
n.deepEquivalent()).anchorNode(), editingState); |
| 689 if (editingState->isAborted()) |
| 690 return; |
673 m_endingPosition = startOfParagraphToMove.deepEquivalent(); | 691 m_endingPosition = startOfParagraphToMove.deepEquivalent(); |
674 return; | 692 return; |
675 } | 693 } |
676 } | 694 } |
677 | 695 |
678 // Block images, tables and horizontal rules cannot be made inline with cont
ent at mergeDestination. If there is | 696 // Block images, tables and horizontal rules cannot be made inline with cont
ent at mergeDestination. If there is |
679 // any (!isStartOfParagraph(mergeDestination)), don't merge, just move the c
aret to just before the selection we deleted. | 697 // any (!isStartOfParagraph(mergeDestination)), don't merge, just move the c
aret to just before the selection we deleted. |
680 // See https://bugs.webkit.org/show_bug.cgi?id=25439 | 698 // See https://bugs.webkit.org/show_bug.cgi?id=25439 |
681 if (isRenderedAsNonInlineTableImageOrHR(startOfParagraphToMove.deepEquivalen
t().anchorNode()) && !isStartOfParagraph(mergeDestination)) { | 699 if (isRenderedAsNonInlineTableImageOrHR(startOfParagraphToMove.deepEquivalen
t().anchorNode()) && !isStartOfParagraph(mergeDestination)) { |
682 m_endingPosition = m_upstreamStart; | 700 m_endingPosition = m_upstreamStart; |
683 return; | 701 return; |
684 } | 702 } |
685 | 703 |
686 // moveParagraphs will insert placeholders if it removes blocks that would r
equire their use, don't let block | 704 // moveParagraphs will insert placeholders if it removes blocks that would r
equire their use, don't let block |
687 // removals that it does cause the insertion of *another* placeholder. | 705 // removals that it does cause the insertion of *another* placeholder. |
688 bool needPlaceholder = m_needPlaceholder; | 706 bool needPlaceholder = m_needPlaceholder; |
689 bool paragraphToMergeIsEmpty = startOfParagraphToMove.deepEquivalent() == en
dOfParagraphToMove.deepEquivalent(); | 707 bool paragraphToMergeIsEmpty = startOfParagraphToMove.deepEquivalent() == en
dOfParagraphToMove.deepEquivalent(); |
690 moveParagraph(startOfParagraphToMove, endOfParagraphToMove, mergeDestination
, ASSERT_NO_EDITING_ABORT, false, !paragraphToMergeIsEmpty); | 708 moveParagraph(startOfParagraphToMove, endOfParagraphToMove, mergeDestination
, editingState, false, !paragraphToMergeIsEmpty); |
| 709 if (editingState->isAborted()) |
| 710 return; |
691 m_needPlaceholder = needPlaceholder; | 711 m_needPlaceholder = needPlaceholder; |
692 // The endingPosition was likely clobbered by the move, so recompute it (mov
eParagraph selects the moved paragraph). | 712 // The endingPosition was likely clobbered by the move, so recompute it (mov
eParagraph selects the moved paragraph). |
693 m_endingPosition = endingSelection().start(); | 713 m_endingPosition = endingSelection().start(); |
694 } | 714 } |
695 | 715 |
696 void DeleteSelectionCommand::removePreviouslySelectedEmptyTableRows() | 716 void DeleteSelectionCommand::removePreviouslySelectedEmptyTableRows(EditingState
* editingState) |
697 { | 717 { |
698 if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_start
TableRow) { | 718 if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_start
TableRow) { |
699 Node* row = m_endTableRow->previousSibling(); | 719 Node* row = m_endTableRow->previousSibling(); |
700 while (row && row != m_startTableRow) { | 720 while (row && row != m_startTableRow) { |
701 RefPtrWillBeRawPtr<Node> previousRow = row->previousSibling(); | 721 RefPtrWillBeRawPtr<Node> previousRow = row->previousSibling(); |
702 if (isTableRowEmpty(row)) { | 722 if (isTableRowEmpty(row)) { |
703 // Use a raw removeNode, instead of DeleteSelectionCommand's, | 723 // Use a raw removeNode, instead of DeleteSelectionCommand's, |
704 // because that won't remove rows, it only empties them in | 724 // because that won't remove rows, it only empties them in |
705 // preparation for this function. | 725 // preparation for this function. |
706 CompositeEditCommand::removeNode(row); | 726 CompositeEditCommand::removeNode(row, editingState); |
| 727 if (editingState->isAborted()) |
| 728 return; |
707 } | 729 } |
708 row = previousRow.get(); | 730 row = previousRow.get(); |
709 } | 731 } |
710 } | 732 } |
711 | 733 |
712 // Remove empty rows after the start row. | 734 // Remove empty rows after the start row. |
713 if (m_startTableRow && m_startTableRow->inDocument() && m_startTableRow != m
_endTableRow) { | 735 if (m_startTableRow && m_startTableRow->inDocument() && m_startTableRow != m
_endTableRow) { |
714 Node* row = m_startTableRow->nextSibling(); | 736 Node* row = m_startTableRow->nextSibling(); |
715 while (row && row != m_endTableRow) { | 737 while (row && row != m_endTableRow) { |
716 RefPtrWillBeRawPtr<Node> nextRow = row->nextSibling(); | 738 RefPtrWillBeRawPtr<Node> nextRow = row->nextSibling(); |
717 if (isTableRowEmpty(row)) | 739 if (isTableRowEmpty(row)) { |
718 CompositeEditCommand::removeNode(row); | 740 CompositeEditCommand::removeNode(row, editingState); |
| 741 if (editingState->isAborted()) |
| 742 return; |
| 743 } |
719 row = nextRow.get(); | 744 row = nextRow.get(); |
720 } | 745 } |
721 } | 746 } |
722 | 747 |
723 if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_start
TableRow) { | 748 if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_start
TableRow) { |
724 if (isTableRowEmpty(m_endTableRow.get())) { | 749 if (isTableRowEmpty(m_endTableRow.get())) { |
725 // Don't remove m_endTableRow if it's where we're putting the ending | 750 // Don't remove m_endTableRow if it's where we're putting the ending |
726 // selection. | 751 // selection. |
727 if (!m_endingPosition.anchorNode()->isDescendantOf(m_endTableRow.get
())) { | 752 if (!m_endingPosition.anchorNode()->isDescendantOf(m_endTableRow.get
())) { |
728 // FIXME: We probably shouldn't remove m_endTableRow unless it's | 753 // FIXME: We probably shouldn't remove m_endTableRow unless it's |
729 // fully selected, even if it is empty. We'll need to start | 754 // fully selected, even if it is empty. We'll need to start |
730 // adjusting the selection endpoints during deletion to know | 755 // adjusting the selection endpoints during deletion to know |
731 // whether or not m_endTableRow was fully selected here. | 756 // whether or not m_endTableRow was fully selected here. |
732 CompositeEditCommand::removeNode(m_endTableRow.get()); | 757 CompositeEditCommand::removeNode(m_endTableRow.get(), editingSta
te); |
| 758 if (editingState->isAborted()) |
| 759 return; |
733 } | 760 } |
734 } | 761 } |
735 } | 762 } |
736 } | 763 } |
737 | 764 |
738 void DeleteSelectionCommand::calculateTypingStyleAfterDelete() | 765 void DeleteSelectionCommand::calculateTypingStyleAfterDelete() |
739 { | 766 { |
740 // Clearing any previously set typing style and doing an early return. | 767 // Clearing any previously set typing style and doing an early return. |
741 if (!m_typingStyle) { | 768 if (!m_typingStyle) { |
742 document().frame()->selection().clearTypingStyle(); | 769 document().frame()->selection().clearTypingStyle(); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
835 bool lineBreakBeforeStart = lineBreakExistsAtVisiblePosition(previousPositio
nOf(createVisiblePosition(m_upstreamStart))); | 862 bool lineBreakBeforeStart = lineBreakExistsAtVisiblePosition(previousPositio
nOf(createVisiblePosition(m_upstreamStart))); |
836 | 863 |
837 // Delete any text that may hinder our ability to fixup whitespace after the | 864 // Delete any text that may hinder our ability to fixup whitespace after the |
838 // delete | 865 // delete |
839 deleteInsignificantTextDownstream(m_trailingWhitespace); | 866 deleteInsignificantTextDownstream(m_trailingWhitespace); |
840 | 867 |
841 saveTypingStyleState(); | 868 saveTypingStyleState(); |
842 | 869 |
843 // deleting just a BR is handled specially, at least because we do not | 870 // deleting just a BR is handled specially, at least because we do not |
844 // want to replace it with a placeholder BR! | 871 // want to replace it with a placeholder BR! |
845 if (handleSpecialCaseBRDelete()) { | 872 bool brResult = handleSpecialCaseBRDelete(editingState); |
| 873 if (editingState->isAborted()) |
| 874 return; |
| 875 if (brResult) { |
846 calculateTypingStyleAfterDelete(); | 876 calculateTypingStyleAfterDelete(); |
847 setEndingSelection(VisibleSelection(m_endingPosition, affinity, endingSe
lection().isDirectional())); | 877 setEndingSelection(VisibleSelection(m_endingPosition, affinity, endingSe
lection().isDirectional())); |
848 clearTransientState(); | 878 clearTransientState(); |
849 rebalanceWhitespace(); | 879 rebalanceWhitespace(); |
850 return; | 880 return; |
851 } | 881 } |
852 | 882 |
853 handleGeneralDelete(editingState); | 883 handleGeneralDelete(editingState); |
854 if (editingState->isAborted()) | 884 if (editingState->isAborted()) |
855 return; | 885 return; |
856 | 886 |
857 fixupWhitespace(); | 887 fixupWhitespace(); |
858 | 888 |
859 mergeParagraphs(); | 889 mergeParagraphs(editingState); |
| 890 if (editingState->isAborted()) |
| 891 return; |
860 | 892 |
861 removePreviouslySelectedEmptyTableRows(); | 893 removePreviouslySelectedEmptyTableRows(editingState); |
| 894 if (editingState->isAborted()) |
| 895 return; |
862 | 896 |
863 if (!m_needPlaceholder && rootWillStayOpenWithoutPlaceholder) { | 897 if (!m_needPlaceholder && rootWillStayOpenWithoutPlaceholder) { |
864 VisiblePosition visualEnding = createVisiblePosition(m_endingPosition); | 898 VisiblePosition visualEnding = createVisiblePosition(m_endingPosition); |
865 bool hasPlaceholder = lineBreakExistsAtVisiblePosition(visualEnding) | 899 bool hasPlaceholder = lineBreakExistsAtVisiblePosition(visualEnding) |
866 && nextPositionOf(visualEnding, CannotCrossEditingBoundary).isNull()
; | 900 && nextPositionOf(visualEnding, CannotCrossEditingBoundary).isNull()
; |
867 m_needPlaceholder = hasPlaceholder && lineBreakBeforeStart && !lineBreak
AtEndOfSelectionToDelete; | 901 m_needPlaceholder = hasPlaceholder && lineBreakBeforeStart && !lineBreak
AtEndOfSelectionToDelete; |
868 } | 902 } |
869 | 903 |
870 RefPtrWillBeRawPtr<HTMLBRElement> placeholder = m_needPlaceholder ? HTMLBREl
ement::create(document()) : nullptr; | 904 RefPtrWillBeRawPtr<HTMLBRElement> placeholder = m_needPlaceholder ? HTMLBREl
ement::create(document()) : nullptr; |
871 | 905 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
921 visitor->trace(m_deleteIntoBlockquoteStyle); | 955 visitor->trace(m_deleteIntoBlockquoteStyle); |
922 visitor->trace(m_startRoot); | 956 visitor->trace(m_startRoot); |
923 visitor->trace(m_endRoot); | 957 visitor->trace(m_endRoot); |
924 visitor->trace(m_startTableRow); | 958 visitor->trace(m_startTableRow); |
925 visitor->trace(m_endTableRow); | 959 visitor->trace(m_endTableRow); |
926 visitor->trace(m_temporaryPlaceholder); | 960 visitor->trace(m_temporaryPlaceholder); |
927 CompositeEditCommand::trace(visitor); | 961 CompositeEditCommand::trace(visitor); |
928 } | 962 } |
929 | 963 |
930 } // namespace blink | 964 } // namespace blink |
OLD | NEW |