| 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 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 void DeleteSelectionCommand::initializeStartEnd(Position& start, Position& end) | 103 void DeleteSelectionCommand::initializeStartEnd(Position& start, Position& end) |
| 104 { | 104 { |
| 105 HTMLElement* startSpecialContainer = nullptr; | 105 HTMLElement* startSpecialContainer = nullptr; |
| 106 HTMLElement* endSpecialContainer = nullptr; | 106 HTMLElement* endSpecialContainer = nullptr; |
| 107 | 107 |
| 108 start = m_selectionToDelete.start(); | 108 start = m_selectionToDelete.start(); |
| 109 end = m_selectionToDelete.end(); | 109 end = m_selectionToDelete.end(); |
| 110 | 110 |
| 111 // For HRs, we'll get a position at (HR,1) when hitting delete from the begi
nning of the previous line, or (HR,0) when forward deleting, | 111 // For HRs, we'll get a position at (HR,1) when hitting delete from the begi
nning of the previous line, or (HR,0) when forward deleting, |
| 112 // but in these cases, we want to delete it, so manually expand the selectio
n | 112 // but in these cases, we want to delete it, so manually expand the selectio
n |
| 113 if (isHTMLHRElement(*start.deprecatedNode())) | 113 if (isHTMLHRElement(*start.anchorNode())) |
| 114 start = positionBeforeNode(start.deprecatedNode()); | 114 start = positionBeforeNode(start.anchorNode()); |
| 115 else if (isHTMLHRElement(*end.deprecatedNode())) | 115 else if (isHTMLHRElement(*end.anchorNode())) |
| 116 end = positionAfterNode(end.deprecatedNode()); | 116 end = positionAfterNode(end.anchorNode()); |
| 117 | 117 |
| 118 // FIXME: This is only used so that moveParagraphs can avoid the bugs in spe
cial element expansion. | 118 // FIXME: This is only used so that moveParagraphs can avoid the bugs in spe
cial element expansion. |
| 119 if (!m_expandForSpecialElements) | 119 if (!m_expandForSpecialElements) |
| 120 return; | 120 return; |
| 121 | 121 |
| 122 while (1) { | 122 while (1) { |
| 123 startSpecialContainer = 0; | 123 startSpecialContainer = 0; |
| 124 endSpecialContainer = 0; | 124 endSpecialContainer = 0; |
| 125 | 125 |
| 126 Position s = positionBeforeContainingSpecialElement(start, &startSpecial
Container); | 126 Position s = positionBeforeContainingSpecialElement(start, &startSpecial
Container); |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 272 | 272 |
| 273 void DeleteSelectionCommand::saveTypingStyleState() | 273 void DeleteSelectionCommand::saveTypingStyleState() |
| 274 { | 274 { |
| 275 // A common case is deleting characters that are all from the same text node
. In | 275 // A common case is deleting characters that are all from the same text node
. In |
| 276 // that case, the style at the start of the selection before deletion will b
e the | 276 // that case, the style at the start of the selection before deletion will b
e the |
| 277 // same as the style at the start of the selection after deletion (since tho
se | 277 // same as the style at the start of the selection after deletion (since tho
se |
| 278 // two positions will be identical). Therefore there is no need to save the | 278 // two positions will be identical). Therefore there is no need to save the |
| 279 // typing style at the start of the selection, nor is there a reason to | 279 // typing style at the start of the selection, nor is there a reason to |
| 280 // compute the style at the start of the selection after deletion (see the | 280 // compute the style at the start of the selection after deletion (see the |
| 281 // early return in calculateTypingStyleAfterDelete). | 281 // early return in calculateTypingStyleAfterDelete). |
| 282 if (m_upstreamStart.deprecatedNode() == m_downstreamEnd.deprecatedNode() &&
m_upstreamStart.deprecatedNode()->isTextNode()) | 282 if (m_upstreamStart.anchorNode() == m_downstreamEnd.anchorNode() && m_upstre
amStart.anchorNode()->isTextNode()) |
| 283 return; | 283 return; |
| 284 | 284 |
| 285 if (shouldNotInheritStyleFrom(*m_selectionToDelete.start().anchorNode())) | 285 if (shouldNotInheritStyleFrom(*m_selectionToDelete.start().anchorNode())) |
| 286 return; | 286 return; |
| 287 | 287 |
| 288 // Figure out the typing style in effect before the delete is done. | 288 // Figure out the typing style in effect before the delete is done. |
| 289 m_typingStyle = EditingStyle::create(m_selectionToDelete.start(), EditingSty
le::EditingPropertiesInEffect); | 289 m_typingStyle = EditingStyle::create(m_selectionToDelete.start(), EditingSty
le::EditingPropertiesInEffect); |
| 290 m_typingStyle->removeStyleAddedByElement(enclosingAnchorElement(m_selectionT
oDelete.start())); | 290 m_typingStyle->removeStyleAddedByElement(enclosingAnchorElement(m_selectionT
oDelete.start())); |
| 291 | 291 |
| 292 // If we're deleting into a Mail blockquote, save the style at end() instead
of start() | 292 // If we're deleting into a Mail blockquote, save the style at end() instead
of start() |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 441 node = nextNode; | 441 node = nextNode; |
| 442 } | 442 } |
| 443 } | 443 } |
| 444 | 444 |
| 445 void DeleteSelectionCommand::handleGeneralDelete() | 445 void DeleteSelectionCommand::handleGeneralDelete() |
| 446 { | 446 { |
| 447 if (m_upstreamStart.isNull()) | 447 if (m_upstreamStart.isNull()) |
| 448 return; | 448 return; |
| 449 | 449 |
| 450 int startOffset = m_upstreamStart.deprecatedEditingOffset(); | 450 int startOffset = m_upstreamStart.deprecatedEditingOffset(); |
| 451 Node* startNode = m_upstreamStart.deprecatedNode(); | 451 Node* startNode = m_upstreamStart.anchorNode(); |
| 452 ASSERT(startNode); | 452 ASSERT(startNode); |
| 453 | 453 |
| 454 makeStylingElementsDirectChildrenOfEditableRootToPreventStyleLoss(); | 454 makeStylingElementsDirectChildrenOfEditableRootToPreventStyleLoss(); |
| 455 | 455 |
| 456 // Never remove the start block unless it's a table, in which case we won't
merge content in. | 456 // Never remove the start block unless it's a table, in which case we won't
merge content in. |
| 457 if (startNode->isSameNode(m_startBlock.get()) && !startOffset && canHaveChil
drenForEditing(startNode) && !isHTMLTableElement(*startNode)) { | 457 if (startNode->isSameNode(m_startBlock.get()) && !startOffset && canHaveChil
drenForEditing(startNode) && !isHTMLTableElement(*startNode)) { |
| 458 startOffset = 0; | 458 startOffset = 0; |
| 459 startNode = NodeTraversal::next(*startNode); | 459 startNode = NodeTraversal::next(*startNode); |
| 460 if (!startNode) | 460 if (!startNode) |
| 461 return; | 461 return; |
| 462 } | 462 } |
| 463 | 463 |
| 464 if (startOffset >= caretMaxOffset(startNode) && startNode->isTextNode()) { | 464 if (startOffset >= caretMaxOffset(startNode) && startNode->isTextNode()) { |
| 465 Text* text = toText(startNode); | 465 Text* text = toText(startNode); |
| 466 if (text->length() > (unsigned)caretMaxOffset(startNode)) | 466 if (text->length() > (unsigned)caretMaxOffset(startNode)) |
| 467 deleteTextFromNode(text, caretMaxOffset(startNode), text->length() -
caretMaxOffset(startNode)); | 467 deleteTextFromNode(text, caretMaxOffset(startNode), text->length() -
caretMaxOffset(startNode)); |
| 468 } | 468 } |
| 469 | 469 |
| 470 if (startOffset >= lastOffsetForEditing(startNode)) { | 470 if (startOffset >= lastOffsetForEditing(startNode)) { |
| 471 startNode = NodeTraversal::nextSkippingChildren(*startNode); | 471 startNode = NodeTraversal::nextSkippingChildren(*startNode); |
| 472 startOffset = 0; | 472 startOffset = 0; |
| 473 } | 473 } |
| 474 | 474 |
| 475 // Done adjusting the start. See if we're all done. | 475 // Done adjusting the start. See if we're all done. |
| 476 if (!startNode) | 476 if (!startNode) |
| 477 return; | 477 return; |
| 478 | 478 |
| 479 if (startNode == m_downstreamEnd.deprecatedNode()) { | 479 if (startNode == m_downstreamEnd.anchorNode()) { |
| 480 if (m_downstreamEnd.deprecatedEditingOffset() - startOffset > 0) { | 480 if (m_downstreamEnd.deprecatedEditingOffset() - startOffset > 0) { |
| 481 if (startNode->isTextNode()) { | 481 if (startNode->isTextNode()) { |
| 482 // in a text node that needs to be trimmed | 482 // in a text node that needs to be trimmed |
| 483 Text* text = toText(startNode); | 483 Text* text = toText(startNode); |
| 484 deleteTextFromNode(text, startOffset, m_downstreamEnd.deprecated
EditingOffset() - startOffset); | 484 deleteTextFromNode(text, startOffset, m_downstreamEnd.deprecated
EditingOffset() - startOffset); |
| 485 } else { | 485 } else { |
| 486 removeChildrenInRange(startNode, startOffset, m_downstreamEnd.de
precatedEditingOffset()); | 486 removeChildrenInRange(startNode, startOffset, m_downstreamEnd.de
precatedEditingOffset()); |
| 487 m_endingPosition = m_upstreamStart; | 487 m_endingPosition = m_upstreamStart; |
| 488 } | 488 } |
| 489 } | 489 } |
| 490 | 490 |
| 491 // The selection to delete is all in one node. | 491 // The selection to delete is all in one node. |
| 492 if (!startNode->layoutObject() || (!startOffset && m_downstreamEnd.atLas
tEditingPositionForNode())) | 492 if (!startNode->layoutObject() || (!startOffset && m_downstreamEnd.atLas
tEditingPositionForNode())) |
| 493 removeNode(startNode); | 493 removeNode(startNode); |
| 494 } | 494 } |
| 495 else { | 495 else { |
| 496 bool startNodeWasDescendantOfEndNode = m_upstreamStart.deprecatedNode()-
>isDescendantOf(m_downstreamEnd.deprecatedNode()); | 496 bool startNodeWasDescendantOfEndNode = m_upstreamStart.anchorNode()->isD
escendantOf(m_downstreamEnd.anchorNode()); |
| 497 // The selection to delete spans more than one node. | 497 // The selection to delete spans more than one node. |
| 498 RefPtrWillBeRawPtr<Node> node(startNode); | 498 RefPtrWillBeRawPtr<Node> node(startNode); |
| 499 | 499 |
| 500 if (startOffset > 0) { | 500 if (startOffset > 0) { |
| 501 if (startNode->isTextNode()) { | 501 if (startNode->isTextNode()) { |
| 502 // in a text node that needs to be trimmed | 502 // in a text node that needs to be trimmed |
| 503 Text* text = toText(node); | 503 Text* text = toText(node); |
| 504 deleteTextFromNode(text, startOffset, text->length() - startOffs
et); | 504 deleteTextFromNode(text, startOffset, text->length() - startOffs
et); |
| 505 node = NodeTraversal::next(*node); | 505 node = NodeTraversal::next(*node); |
| 506 } else { | 506 } else { |
| 507 node = NodeTraversal::childAt(*startNode, startOffset); | 507 node = NodeTraversal::childAt(*startNode, startOffset); |
| 508 } | 508 } |
| 509 } else if (startNode == m_upstreamEnd.deprecatedNode() && startNode->isT
extNode()) { | 509 } else if (startNode == m_upstreamEnd.anchorNode() && startNode->isTextN
ode()) { |
| 510 Text* text = toText(m_upstreamEnd.deprecatedNode()); | 510 Text* text = toText(m_upstreamEnd.anchorNode()); |
| 511 deleteTextFromNode(text, 0, m_upstreamEnd.deprecatedEditingOffset())
; | 511 deleteTextFromNode(text, 0, m_upstreamEnd.deprecatedEditingOffset())
; |
| 512 } | 512 } |
| 513 | 513 |
| 514 // handle deleting all nodes that are completely selected | 514 // handle deleting all nodes that are completely selected |
| 515 while (node && node != m_downstreamEnd.deprecatedNode()) { | 515 while (node && node != m_downstreamEnd.anchorNode()) { |
| 516 if (comparePositions(firstPositionInOrBeforeNode(node.get()), m_down
streamEnd) >= 0) { | 516 if (comparePositions(firstPositionInOrBeforeNode(node.get()), m_down
streamEnd) >= 0) { |
| 517 // NodeTraversal::nextSkippingChildren just blew past the end po
sition, so stop deleting | 517 // NodeTraversal::nextSkippingChildren just blew past the end po
sition, so stop deleting |
| 518 node = nullptr; | 518 node = nullptr; |
| 519 } else if (!m_downstreamEnd.deprecatedNode()->isDescendantOf(node.ge
t())) { | 519 } else if (!m_downstreamEnd.anchorNode()->isDescendantOf(node.get())
) { |
| 520 RefPtrWillBeRawPtr<Node> nextNode = NodeTraversal::nextSkippingC
hildren(*node); | 520 RefPtrWillBeRawPtr<Node> nextNode = NodeTraversal::nextSkippingC
hildren(*node); |
| 521 // if we just removed a node from the end container, update end
position so the | 521 // if we just removed a node from the end container, update end
position so the |
| 522 // check above will work | 522 // check above will work |
| 523 updatePositionForNodeRemoval(m_downstreamEnd, *node); | 523 updatePositionForNodeRemoval(m_downstreamEnd, *node); |
| 524 removeNode(node.get()); | 524 removeNode(node.get()); |
| 525 node = nextNode.get(); | 525 node = nextNode.get(); |
| 526 } else { | 526 } else { |
| 527 Node& n = NodeTraversal::lastWithinOrSelf(*node); | 527 Node& n = NodeTraversal::lastWithinOrSelf(*node); |
| 528 if (m_downstreamEnd.deprecatedNode() == n && m_downstreamEnd.dep
recatedEditingOffset() >= caretMaxOffset(&n)) { | 528 if (m_downstreamEnd.anchorNode() == n && m_downstreamEnd.depreca
tedEditingOffset() >= caretMaxOffset(&n)) { |
| 529 removeNode(node.get()); | 529 removeNode(node.get()); |
| 530 node = nullptr; | 530 node = nullptr; |
| 531 } else { | 531 } else { |
| 532 node = NodeTraversal::next(*node); | 532 node = NodeTraversal::next(*node); |
| 533 } | 533 } |
| 534 } | 534 } |
| 535 } | 535 } |
| 536 | 536 |
| 537 if (m_downstreamEnd.deprecatedNode() != startNode && !m_upstreamStart.de
precatedNode()->isDescendantOf(m_downstreamEnd.deprecatedNode()) && m_downstream
End.inDocument() && m_downstreamEnd.deprecatedEditingOffset() >= caretMinOffset(
m_downstreamEnd.deprecatedNode())) { | 537 if (m_downstreamEnd.anchorNode() != startNode && !m_upstreamStart.anchor
Node()->isDescendantOf(m_downstreamEnd.anchorNode()) && m_downstreamEnd.inDocume
nt() && m_downstreamEnd.deprecatedEditingOffset() >= caretMinOffset(m_downstream
End.anchorNode())) { |
| 538 if (m_downstreamEnd.atLastEditingPositionForNode() && !canHaveChildr
enForEditing(m_downstreamEnd.deprecatedNode())) { | 538 if (m_downstreamEnd.atLastEditingPositionForNode() && !canHaveChildr
enForEditing(m_downstreamEnd.anchorNode())) { |
| 539 // The node itself is fully selected, not just its contents. De
lete it. | 539 // The node itself is fully selected, not just its contents. De
lete it. |
| 540 removeNode(m_downstreamEnd.deprecatedNode()); | 540 removeNode(m_downstreamEnd.anchorNode()); |
| 541 } else { | 541 } else { |
| 542 if (m_downstreamEnd.deprecatedNode()->isTextNode()) { | 542 if (m_downstreamEnd.anchorNode()->isTextNode()) { |
| 543 // in a text node that needs to be trimmed | 543 // in a text node that needs to be trimmed |
| 544 Text* text = toText(m_downstreamEnd.deprecatedNode()); | 544 Text* text = toText(m_downstreamEnd.anchorNode()); |
| 545 if (m_downstreamEnd.deprecatedEditingOffset() > 0) { | 545 if (m_downstreamEnd.deprecatedEditingOffset() > 0) { |
| 546 deleteTextFromNode(text, 0, m_downstreamEnd.deprecatedEd
itingOffset()); | 546 deleteTextFromNode(text, 0, m_downstreamEnd.deprecatedEd
itingOffset()); |
| 547 } | 547 } |
| 548 // Remove children of m_downstreamEnd.deprecatedNode() that come
after m_upstreamStart. | 548 // Remove children of m_downstreamEnd.anchorNode() that come aft
er m_upstreamStart. |
| 549 // Don't try to remove children if m_upstreamStart was inside m_
downstreamEnd.deprecatedNode() | 549 // Don't try to remove children if m_upstreamStart was inside m_
downstreamEnd.anchorNode() |
| 550 // and m_upstreamStart has been removed from the document, becau
se then we don't | 550 // and m_upstreamStart has been removed from the document, becau
se then we don't |
| 551 // know how many children to remove. | 551 // know how many children to remove. |
| 552 // FIXME: Make m_upstreamStart a position we update as we remove
content, then we can | 552 // FIXME: Make m_upstreamStart a position we update as we remove
content, then we can |
| 553 // always know which children to remove. | 553 // always know which children to remove. |
| 554 } else if (!(startNodeWasDescendantOfEndNode && !m_upstreamStart
.inDocument())) { | 554 } else if (!(startNodeWasDescendantOfEndNode && !m_upstreamStart
.inDocument())) { |
| 555 int offset = 0; | 555 int offset = 0; |
| 556 if (m_upstreamStart.deprecatedNode()->isDescendantOf(m_downs
treamEnd.deprecatedNode())) { | 556 if (m_upstreamStart.anchorNode()->isDescendantOf(m_downstrea
mEnd.anchorNode())) { |
| 557 Node* n = m_upstreamStart.deprecatedNode(); | 557 Node* n = m_upstreamStart.anchorNode(); |
| 558 while (n && n->parentNode() != m_downstreamEnd.deprecate
dNode()) | 558 while (n && n->parentNode() != m_downstreamEnd.anchorNod
e()) |
| 559 n = n->parentNode(); | 559 n = n->parentNode(); |
| 560 if (n) | 560 if (n) |
| 561 offset = n->nodeIndex() + 1; | 561 offset = n->nodeIndex() + 1; |
| 562 } | 562 } |
| 563 removeChildrenInRange(m_downstreamEnd.deprecatedNode(), offs
et, m_downstreamEnd.deprecatedEditingOffset()); | 563 removeChildrenInRange(m_downstreamEnd.anchorNode(), offset,
m_downstreamEnd.deprecatedEditingOffset()); |
| 564 m_downstreamEnd = createLegacyEditingPosition(m_downstreamEn
d.deprecatedNode(), offset); | 564 m_downstreamEnd = createLegacyEditingPosition(m_downstreamEn
d.anchorNode(), offset); |
| 565 } | 565 } |
| 566 } | 566 } |
| 567 } | 567 } |
| 568 } | 568 } |
| 569 } | 569 } |
| 570 | 570 |
| 571 void DeleteSelectionCommand::fixupWhitespace() | 571 void DeleteSelectionCommand::fixupWhitespace() |
| 572 { | 572 { |
| 573 document().updateLayoutIgnorePendingStylesheets(); | 573 document().updateLayoutIgnorePendingStylesheets(); |
| 574 // FIXME: isRenderedCharacter should be removed, and we should use VisiblePo
sition::characterAfter and VisiblePosition::characterBefore | 574 // FIXME: isRenderedCharacter should be removed, and we should use VisiblePo
sition::characterAfter and VisiblePosition::characterBefore |
| 575 if (m_leadingWhitespace.isNotNull() && !m_leadingWhitespace.isRenderedCharac
ter() && m_leadingWhitespace.deprecatedNode()->isTextNode()) { | 575 if (m_leadingWhitespace.isNotNull() && !m_leadingWhitespace.isRenderedCharac
ter() && m_leadingWhitespace.anchorNode()->isTextNode()) { |
| 576 Text* textNode = toText(m_leadingWhitespace.deprecatedNode()); | 576 Text* textNode = toText(m_leadingWhitespace.anchorNode()); |
| 577 ASSERT(!textNode->layoutObject() || textNode->layoutObject()->style()->c
ollapseWhiteSpace()); | 577 ASSERT(!textNode->layoutObject() || textNode->layoutObject()->style()->c
ollapseWhiteSpace()); |
| 578 replaceTextInNodePreservingMarkers(textNode, m_leadingWhitespace.depreca
tedEditingOffset(), 1, nonBreakingSpaceString()); | 578 replaceTextInNodePreservingMarkers(textNode, m_leadingWhitespace.depreca
tedEditingOffset(), 1, nonBreakingSpaceString()); |
| 579 } | 579 } |
| 580 if (m_trailingWhitespace.isNotNull() && !m_trailingWhitespace.isRenderedChar
acter() && m_trailingWhitespace.deprecatedNode()->isTextNode()) { | 580 if (m_trailingWhitespace.isNotNull() && !m_trailingWhitespace.isRenderedChar
acter() && m_trailingWhitespace.anchorNode()->isTextNode()) { |
| 581 Text* textNode = toText(m_trailingWhitespace.deprecatedNode()); | 581 Text* textNode = toText(m_trailingWhitespace.anchorNode()); |
| 582 ASSERT(!textNode->layoutObject() || textNode->layoutObject()->style()->c
ollapseWhiteSpace()); | 582 ASSERT(!textNode->layoutObject() || textNode->layoutObject()->style()->c
ollapseWhiteSpace()); |
| 583 replaceTextInNodePreservingMarkers(textNode, m_trailingWhitespace.deprec
atedEditingOffset(), 1, nonBreakingSpaceString()); | 583 replaceTextInNodePreservingMarkers(textNode, m_trailingWhitespace.deprec
atedEditingOffset(), 1, nonBreakingSpaceString()); |
| 584 } | 584 } |
| 585 } | 585 } |
| 586 | 586 |
| 587 // If a selection starts in one block and ends in another, we have to merge to b
ring content before the | 587 // If a selection starts in one block and ends in another, we have to merge to b
ring content before the |
| 588 // start together with content after the end. | 588 // start together with content after the end. |
| 589 void DeleteSelectionCommand::mergeParagraphs() | 589 void DeleteSelectionCommand::mergeParagraphs() |
| 590 { | 590 { |
| 591 if (!m_mergeBlocksAfterDelete) { | 591 if (!m_mergeBlocksAfterDelete) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 612 | 612 |
| 613 // There's nothing to merge. | 613 // There's nothing to merge. |
| 614 if (m_upstreamStart == m_downstreamEnd) | 614 if (m_upstreamStart == m_downstreamEnd) |
| 615 return; | 615 return; |
| 616 | 616 |
| 617 VisiblePosition startOfParagraphToMove(m_downstreamEnd); | 617 VisiblePosition startOfParagraphToMove(m_downstreamEnd); |
| 618 VisiblePosition mergeDestination(m_upstreamStart); | 618 VisiblePosition mergeDestination(m_upstreamStart); |
| 619 | 619 |
| 620 // m_downstreamEnd's block has been emptied out by deletion. There is no co
ntent inside of it to | 620 // m_downstreamEnd's block has been emptied out by deletion. There is no co
ntent inside of it to |
| 621 // move, so just remove it. | 621 // move, so just remove it. |
| 622 Element* endBlock = enclosingBlock(m_downstreamEnd.deprecatedNode()); | 622 Element* endBlock = enclosingBlock(m_downstreamEnd.anchorNode()); |
| 623 if (!endBlock || !endBlock->contains(startOfParagraphToMove.deepEquivalent()
.deprecatedNode()) || !startOfParagraphToMove.deepEquivalent().deprecatedNode())
{ | 623 if (!endBlock || !endBlock->contains(startOfParagraphToMove.deepEquivalent()
.anchorNode()) || !startOfParagraphToMove.deepEquivalent().anchorNode()) { |
| 624 removeNode(enclosingBlock(m_downstreamEnd.deprecatedNode())); | 624 removeNode(enclosingBlock(m_downstreamEnd.anchorNode())); |
| 625 return; | 625 return; |
| 626 } | 626 } |
| 627 | 627 |
| 628 // We need to merge into m_upstreamStart's block, but it's been emptied out
and collapsed by deletion. | 628 // We need to merge into m_upstreamStart's block, but it's been emptied out
and collapsed by deletion. |
| 629 if (!mergeDestination.deepEquivalent().deprecatedNode() || (!mergeDestinatio
n.deepEquivalent().deprecatedNode()->isDescendantOf(enclosingBlock(m_upstreamSta
rt.containerNode())) && (!mergeDestination.deepEquivalent().anchorNode()->hasChi
ldren() || !m_upstreamStart.containerNode()->hasChildren())) || (m_startsAtEmpty
Line && mergeDestination != startOfParagraphToMove)) { | 629 if (!mergeDestination.deepEquivalent().anchorNode() || (!mergeDestination.de
epEquivalent().anchorNode()->isDescendantOf(enclosingBlock(m_upstreamStart.conta
inerNode())) && (!mergeDestination.deepEquivalent().anchorNode()->hasChildren()
|| !m_upstreamStart.containerNode()->hasChildren())) || (m_startsAtEmptyLine &&
mergeDestination != startOfParagraphToMove)) { |
| 630 insertNodeAt(createBreakElement(document()).get(), m_upstreamStart); | 630 insertNodeAt(createBreakElement(document()).get(), m_upstreamStart); |
| 631 mergeDestination = VisiblePosition(m_upstreamStart); | 631 mergeDestination = VisiblePosition(m_upstreamStart); |
| 632 } | 632 } |
| 633 | 633 |
| 634 if (mergeDestination == startOfParagraphToMove) | 634 if (mergeDestination == startOfParagraphToMove) |
| 635 return; | 635 return; |
| 636 | 636 |
| 637 VisiblePosition endOfParagraphToMove = endOfParagraph(startOfParagraphToMove
, CanSkipOverEditingBoundary); | 637 VisiblePosition endOfParagraphToMove = endOfParagraph(startOfParagraphToMove
, CanSkipOverEditingBoundary); |
| 638 | 638 |
| 639 if (mergeDestination == endOfParagraphToMove) | 639 if (mergeDestination == endOfParagraphToMove) |
| 640 return; | 640 return; |
| 641 | 641 |
| 642 // If the merge destination and source to be moved are both list items of di
fferent lists, merge them into single list. | 642 // If the merge destination and source to be moved are both list items of di
fferent lists, merge them into single list. |
| 643 Node* listItemInFirstParagraph = enclosingNodeOfType(m_upstreamStart, isList
Item); | 643 Node* listItemInFirstParagraph = enclosingNodeOfType(m_upstreamStart, isList
Item); |
| 644 Node* listItemInSecondParagraph = enclosingNodeOfType(m_downstreamEnd, isLis
tItem); | 644 Node* listItemInSecondParagraph = enclosingNodeOfType(m_downstreamEnd, isLis
tItem); |
| 645 if (listItemInFirstParagraph && listItemInSecondParagraph | 645 if (listItemInFirstParagraph && listItemInSecondParagraph |
| 646 && listItemInFirstParagraph->parentElement() != listItemInSecondParagrap
h->parentElement() | 646 && listItemInFirstParagraph->parentElement() != listItemInSecondParagrap
h->parentElement() |
| 647 && canMergeLists(listItemInFirstParagraph->parentElement(), listItemInSe
condParagraph->parentElement())) { | 647 && canMergeLists(listItemInFirstParagraph->parentElement(), listItemInSe
condParagraph->parentElement())) { |
| 648 mergeIdenticalElements(listItemInFirstParagraph->parentElement(), listIt
emInSecondParagraph->parentElement()); | 648 mergeIdenticalElements(listItemInFirstParagraph->parentElement(), listIt
emInSecondParagraph->parentElement()); |
| 649 m_endingPosition = mergeDestination.deepEquivalent(); | 649 m_endingPosition = mergeDestination.deepEquivalent(); |
| 650 return; | 650 return; |
| 651 } | 651 } |
| 652 | 652 |
| 653 // The rule for merging into an empty block is: only do so if its farther to
the right. | 653 // The rule for merging into an empty block is: only do so if its farther to
the right. |
| 654 // FIXME: Consider RTL. | 654 // FIXME: Consider RTL. |
| 655 if (!m_startsAtEmptyLine && isStartOfParagraph(mergeDestination) && startOfP
aragraphToMove.absoluteCaretBounds().x() > mergeDestination.absoluteCaretBounds(
).x()) { | 655 if (!m_startsAtEmptyLine && isStartOfParagraph(mergeDestination) && startOfP
aragraphToMove.absoluteCaretBounds().x() > mergeDestination.absoluteCaretBounds(
).x()) { |
| 656 if (isHTMLBRElement(*mergeDestination.deepEquivalent().downstream().depr
ecatedNode())) { | 656 if (isHTMLBRElement(*mergeDestination.deepEquivalent().downstream().anch
orNode())) { |
| 657 removeNodeAndPruneAncestors(mergeDestination.deepEquivalent().downst
ream().deprecatedNode()); | 657 removeNodeAndPruneAncestors(mergeDestination.deepEquivalent().downst
ream().anchorNode()); |
| 658 m_endingPosition = startOfParagraphToMove.deepEquivalent(); | 658 m_endingPosition = startOfParagraphToMove.deepEquivalent(); |
| 659 return; | 659 return; |
| 660 } | 660 } |
| 661 } | 661 } |
| 662 | 662 |
| 663 // Block images, tables and horizontal rules cannot be made inline with cont
ent at mergeDestination. If there is | 663 // Block images, tables and horizontal rules cannot be made inline with cont
ent at mergeDestination. If there is |
| 664 // any (!isStartOfParagraph(mergeDestination)), don't merge, just move the c
aret to just before the selection we deleted. | 664 // any (!isStartOfParagraph(mergeDestination)), don't merge, just move the c
aret to just before the selection we deleted. |
| 665 // See https://bugs.webkit.org/show_bug.cgi?id=25439 | 665 // See https://bugs.webkit.org/show_bug.cgi?id=25439 |
| 666 if (isRenderedAsNonInlineTableImageOrHR(startOfParagraphToMove.deepEquivalen
t().deprecatedNode()) && !isStartOfParagraph(mergeDestination)) { | 666 if (isRenderedAsNonInlineTableImageOrHR(startOfParagraphToMove.deepEquivalen
t().anchorNode()) && !isStartOfParagraph(mergeDestination)) { |
| 667 m_endingPosition = m_upstreamStart; | 667 m_endingPosition = m_upstreamStart; |
| 668 return; | 668 return; |
| 669 } | 669 } |
| 670 | 670 |
| 671 // moveParagraphs will insert placeholders if it removes blocks that would r
equire their use, don't let block | 671 // moveParagraphs will insert placeholders if it removes blocks that would r
equire their use, don't let block |
| 672 // removals that it does cause the insertion of *another* placeholder. | 672 // removals that it does cause the insertion of *another* placeholder. |
| 673 bool needPlaceholder = m_needPlaceholder; | 673 bool needPlaceholder = m_needPlaceholder; |
| 674 bool paragraphToMergeIsEmpty = (startOfParagraphToMove == endOfParagraphToMo
ve); | 674 bool paragraphToMergeIsEmpty = (startOfParagraphToMove == endOfParagraphToMo
ve); |
| 675 moveParagraph(startOfParagraphToMove, endOfParagraphToMove, mergeDestination
, false, !paragraphToMergeIsEmpty); | 675 moveParagraph(startOfParagraphToMove, endOfParagraphToMove, mergeDestination
, false, !paragraphToMergeIsEmpty); |
| 676 m_needPlaceholder = needPlaceholder; | 676 m_needPlaceholder = needPlaceholder; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 699 RefPtrWillBeRawPtr<Node> nextRow = row->nextSibling(); | 699 RefPtrWillBeRawPtr<Node> nextRow = row->nextSibling(); |
| 700 if (isTableRowEmpty(row)) | 700 if (isTableRowEmpty(row)) |
| 701 CompositeEditCommand::removeNode(row); | 701 CompositeEditCommand::removeNode(row); |
| 702 row = nextRow.get(); | 702 row = nextRow.get(); |
| 703 } | 703 } |
| 704 } | 704 } |
| 705 | 705 |
| 706 if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_start
TableRow) | 706 if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_start
TableRow) |
| 707 if (isTableRowEmpty(m_endTableRow.get())) { | 707 if (isTableRowEmpty(m_endTableRow.get())) { |
| 708 // Don't remove m_endTableRow if it's where we're putting the ending
selection. | 708 // Don't remove m_endTableRow if it's where we're putting the ending
selection. |
| 709 if (!m_endingPosition.deprecatedNode()->isDescendantOf(m_endTableRow
.get())) { | 709 if (!m_endingPosition.anchorNode()->isDescendantOf(m_endTableRow.get
())) { |
| 710 // FIXME: We probably shouldn't remove m_endTableRow unless it's
fully selected, even if it is empty. | 710 // FIXME: We probably shouldn't remove m_endTableRow unless it's
fully selected, even if it is empty. |
| 711 // We'll need to start adjusting the selection endpoints during
deletion to know whether or not m_endTableRow | 711 // We'll need to start adjusting the selection endpoints during
deletion to know whether or not m_endTableRow |
| 712 // was fully selected here. | 712 // was fully selected here. |
| 713 CompositeEditCommand::removeNode(m_endTableRow.get()); | 713 CompositeEditCommand::removeNode(m_endTableRow.get()); |
| 714 } | 714 } |
| 715 } | 715 } |
| 716 } | 716 } |
| 717 | 717 |
| 718 void DeleteSelectionCommand::calculateTypingStyleAfterDelete() | 718 void DeleteSelectionCommand::calculateTypingStyleAfterDelete() |
| 719 { | 719 { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 793 bool lineBreakAtEndOfSelectionToDelete = lineBreakExistsAtVisiblePosition(m_
selectionToDelete.visibleEnd()); | 793 bool lineBreakAtEndOfSelectionToDelete = lineBreakExistsAtVisiblePosition(m_
selectionToDelete.visibleEnd()); |
| 794 m_needPlaceholder = !rootWillStayOpenWithoutPlaceholder | 794 m_needPlaceholder = !rootWillStayOpenWithoutPlaceholder |
| 795 && isStartOfParagraph(m_selectionToDelete.visibleStart(), CanCrossEditin
gBoundary) | 795 && isStartOfParagraph(m_selectionToDelete.visibleStart(), CanCrossEditin
gBoundary) |
| 796 && isEndOfParagraph(m_selectionToDelete.visibleEnd(), CanCrossEditingBou
ndary) | 796 && isEndOfParagraph(m_selectionToDelete.visibleEnd(), CanCrossEditingBou
ndary) |
| 797 && !lineBreakAtEndOfSelectionToDelete; | 797 && !lineBreakAtEndOfSelectionToDelete; |
| 798 if (m_needPlaceholder) { | 798 if (m_needPlaceholder) { |
| 799 // Don't need a placeholder when deleting a selection that starts just b
efore a table | 799 // Don't need a placeholder when deleting a selection that starts just b
efore a table |
| 800 // and ends inside it (we do need placeholders to hold open empty cells,
but that's | 800 // and ends inside it (we do need placeholders to hold open empty cells,
but that's |
| 801 // handled elsewhere). | 801 // handled elsewhere). |
| 802 if (Element* table = isLastPositionBeforeTable(m_selectionToDelete.visib
leStart())) | 802 if (Element* table = isLastPositionBeforeTable(m_selectionToDelete.visib
leStart())) |
| 803 if (m_selectionToDelete.end().deprecatedNode()->isDescendantOf(table
)) | 803 if (m_selectionToDelete.end().anchorNode()->isDescendantOf(table)) |
| 804 m_needPlaceholder = false; | 804 m_needPlaceholder = false; |
| 805 } | 805 } |
| 806 | 806 |
| 807 | 807 |
| 808 // set up our state | 808 // set up our state |
| 809 initializePositionData(); | 809 initializePositionData(); |
| 810 | 810 |
| 811 bool lineBreakBeforeStart = lineBreakExistsAtVisiblePosition(VisiblePosition
(m_upstreamStart).previous()); | 811 bool lineBreakBeforeStart = lineBreakExistsAtVisiblePosition(VisiblePosition
(m_upstreamStart).previous()); |
| 812 | 812 |
| 813 // Delete any text that may hinder our ability to fixup whitespace after the
delete | 813 // Delete any text that may hinder our ability to fixup whitespace after the
delete |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 891 visitor->trace(m_deleteIntoBlockquoteStyle); | 891 visitor->trace(m_deleteIntoBlockquoteStyle); |
| 892 visitor->trace(m_startRoot); | 892 visitor->trace(m_startRoot); |
| 893 visitor->trace(m_endRoot); | 893 visitor->trace(m_endRoot); |
| 894 visitor->trace(m_startTableRow); | 894 visitor->trace(m_startTableRow); |
| 895 visitor->trace(m_endTableRow); | 895 visitor->trace(m_endTableRow); |
| 896 visitor->trace(m_temporaryPlaceholder); | 896 visitor->trace(m_temporaryPlaceholder); |
| 897 CompositeEditCommand::trace(visitor); | 897 CompositeEditCommand::trace(visitor); |
| 898 } | 898 } |
| 899 | 899 |
| 900 } // namespace blink | 900 } // namespace blink |
| OLD | NEW |