| 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 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 331 | 331 |
| 332 static Position firstEditablePositionInNode(Node* node) | 332 static Position firstEditablePositionInNode(Node* node) |
| 333 { | 333 { |
| 334 ASSERT(node); | 334 ASSERT(node); |
| 335 Node* next = node; | 335 Node* next = node; |
| 336 while (next && !next->hasEditableStyle()) | 336 while (next && !next->hasEditableStyle()) |
| 337 next = NodeTraversal::next(*next, node); | 337 next = NodeTraversal::next(*next, node); |
| 338 return next ? firstPositionInOrBeforeNode(next) : Position(); | 338 return next ? firstPositionInOrBeforeNode(next) : Position(); |
| 339 } | 339 } |
| 340 | 340 |
| 341 void DeleteSelectionCommand::removeNode(PassRefPtrWillBeRawPtr<Node> node, Shoul
dAssumeContentIsAlwaysEditable shouldAssumeContentIsAlwaysEditable) | 341 void DeleteSelectionCommand::removeNode(PassRefPtrWillBeRawPtr<Node> node, Editi
ngState* editingState, ShouldAssumeContentIsAlwaysEditable shouldAssumeContentIs
AlwaysEditable) |
| 342 { | 342 { |
| 343 if (!node) | 343 if (!node) |
| 344 return; | 344 return; |
| 345 | 345 |
| 346 if (m_startRoot != m_endRoot && !(node->isDescendantOf(m_startRoot.get()) &&
node->isDescendantOf(m_endRoot.get()))) { | 346 if (m_startRoot != m_endRoot && !(node->isDescendantOf(m_startRoot.get()) &&
node->isDescendantOf(m_endRoot.get()))) { |
| 347 // If a node is not in both the start and end editable roots, remove it
only if its inside an editable region. | 347 // If a node is not in both the start and end editable roots, remove it
only if its inside an editable region. |
| 348 if (!node->parentNode()->hasEditableStyle()) { | 348 if (!node->parentNode()->hasEditableStyle()) { |
| 349 // Don't remove non-editable atomic nodes. | 349 // Don't remove non-editable atomic nodes. |
| 350 if (!node->hasChildren()) | 350 if (!node->hasChildren()) |
| 351 return; | 351 return; |
| 352 // Search this non-editable region for editable regions to empty. | 352 // Search this non-editable region for editable regions to empty. |
| 353 RefPtrWillBeRawPtr<Node> child = node->firstChild(); | 353 RefPtrWillBeRawPtr<Node> child = node->firstChild(); |
| 354 while (child) { | 354 while (child) { |
| 355 RefPtrWillBeRawPtr<Node> nextChild = child->nextSibling(); | 355 RefPtrWillBeRawPtr<Node> nextChild = child->nextSibling(); |
| 356 removeNode(child.get(), shouldAssumeContentIsAlwaysEditable); | 356 removeNode(child.get(), editingState, shouldAssumeContentIsAlway
sEditable); |
| 357 if (editingState->isAborted()) |
| 358 return; |
| 357 // Bail if nextChild is no longer node's child. | 359 // Bail if nextChild is no longer node's child. |
| 358 if (nextChild && nextChild->parentNode() != node) | 360 if (nextChild && nextChild->parentNode() != node) |
| 359 return; | 361 return; |
| 360 child = nextChild; | 362 child = nextChild; |
| 361 } | 363 } |
| 362 | 364 |
| 363 // Don't remove editable regions that are inside non-editable ones,
just clear them. | 365 // Don't remove editable regions that are inside non-editable ones,
just clear them. |
| 364 return; | 366 return; |
| 365 } | 367 } |
| 366 } | 368 } |
| 367 | 369 |
| 368 if (isTableStructureNode(node.get()) || node->isRootEditableElement()) { | 370 if (isTableStructureNode(node.get()) || node->isRootEditableElement()) { |
| 369 // Do not remove an element of table structure; remove its contents. | 371 // Do not remove an element of table structure; remove its contents. |
| 370 // Likewise for the root editable element. | 372 // Likewise for the root editable element. |
| 371 Node* child = node->firstChild(); | 373 Node* child = node->firstChild(); |
| 372 while (child) { | 374 while (child) { |
| 373 Node* remove = child; | 375 Node* remove = child; |
| 374 child = child->nextSibling(); | 376 child = child->nextSibling(); |
| 375 removeNode(remove, shouldAssumeContentIsAlwaysEditable); | 377 removeNode(remove, editingState, shouldAssumeContentIsAlwaysEditable
); |
| 378 if (editingState->isAborted()) |
| 379 return; |
| 376 } | 380 } |
| 377 | 381 |
| 378 // Make sure empty cell has some height, if a placeholder can be inserte
d. | 382 // Make sure empty cell has some height, if a placeholder can be inserte
d. |
| 379 document().updateLayoutIgnorePendingStylesheets(); | 383 document().updateLayoutIgnorePendingStylesheets(); |
| 380 LayoutObject* r = node->layoutObject(); | 384 LayoutObject* r = node->layoutObject(); |
| 381 if (r && r->isTableCell() && toLayoutTableCell(r)->contentHeight() <= 0)
{ | 385 if (r && r->isTableCell() && toLayoutTableCell(r)->contentHeight() <= 0)
{ |
| 382 Position firstEditablePosition = firstEditablePositionInNode(node.ge
t()); | 386 Position firstEditablePosition = firstEditablePositionInNode(node.ge
t()); |
| 383 if (firstEditablePosition.isNotNull()) | 387 if (firstEditablePosition.isNotNull()) |
| 384 insertBlockPlaceholder(firstEditablePosition); | 388 insertBlockPlaceholder(firstEditablePosition); |
| 385 } | 389 } |
| 386 return; | 390 return; |
| 387 } | 391 } |
| 388 | 392 |
| 389 if (node == m_startBlock) { | 393 if (node == m_startBlock) { |
| 390 VisiblePosition previous = previousPositionOf(createVisiblePosition(firs
tPositionInNode(m_startBlock.get()))); | 394 VisiblePosition previous = previousPositionOf(createVisiblePosition(firs
tPositionInNode(m_startBlock.get()))); |
| 391 if (previous.isNotNull() && !isEndOfBlock(previous)) | 395 if (previous.isNotNull() && !isEndOfBlock(previous)) |
| 392 m_needPlaceholder = true; | 396 m_needPlaceholder = true; |
| 393 } | 397 } |
| 394 if (node == m_endBlock) { | 398 if (node == m_endBlock) { |
| 395 VisiblePosition next = nextPositionOf(createVisiblePosition(lastPosition
InNode(m_endBlock.get()))); | 399 VisiblePosition next = nextPositionOf(createVisiblePosition(lastPosition
InNode(m_endBlock.get()))); |
| 396 if (next.isNotNull() && !isStartOfBlock(next)) | 400 if (next.isNotNull() && !isStartOfBlock(next)) |
| 397 m_needPlaceholder = true; | 401 m_needPlaceholder = true; |
| 398 } | 402 } |
| 399 | 403 |
| 400 // FIXME: Update the endpoints of the range being deleted. | 404 // FIXME: Update the endpoints of the range being deleted. |
| 401 updatePositionForNodeRemoval(m_endingPosition, *node); | 405 updatePositionForNodeRemoval(m_endingPosition, *node); |
| 402 updatePositionForNodeRemoval(m_leadingWhitespace, *node); | 406 updatePositionForNodeRemoval(m_leadingWhitespace, *node); |
| 403 updatePositionForNodeRemoval(m_trailingWhitespace, *node); | 407 updatePositionForNodeRemoval(m_trailingWhitespace, *node); |
| 404 | 408 |
| 405 CompositeEditCommand::removeNode(node, shouldAssumeContentIsAlwaysEditable); | 409 CompositeEditCommand::removeNode(node, editingState, shouldAssumeContentIsAl
waysEditable); |
| 406 } | 410 } |
| 407 | 411 |
| 408 static void updatePositionForTextRemoval(Text* node, int offset, int count, Posi
tion& position) | 412 static void updatePositionForTextRemoval(Text* node, int offset, int count, Posi
tion& position) |
| 409 { | 413 { |
| 410 if (!position.isOffsetInAnchor() || position.computeContainerNode() != node) | 414 if (!position.isOffsetInAnchor() || position.computeContainerNode() != node) |
| 411 return; | 415 return; |
| 412 | 416 |
| 413 if (position.offsetInContainerNode() > offset + count) | 417 if (position.offsetInContainerNode() > offset + count) |
| 414 position = Position(position.computeContainerNode(), position.offsetInCo
ntainerNode() - count); | 418 position = Position(position.computeContainerNode(), position.offsetInCo
ntainerNode() - count); |
| 415 else if (position.offsetInContainerNode() > offset) | 419 else if (position.offsetInContainerNode() > offset) |
| (...skipping 22 matching lines...) Expand all Loading... |
| 438 RefPtrWillBeRawPtr<Element> rootEditableElement = node->rootEditable
Element(); | 442 RefPtrWillBeRawPtr<Element> rootEditableElement = node->rootEditable
Element(); |
| 439 if (rootEditableElement.get()) { | 443 if (rootEditableElement.get()) { |
| 440 removeNode(node); | 444 removeNode(node); |
| 441 appendNode(node, rootEditableElement); | 445 appendNode(node, rootEditableElement); |
| 442 } | 446 } |
| 443 } | 447 } |
| 444 node = nextNode; | 448 node = nextNode; |
| 445 } | 449 } |
| 446 } | 450 } |
| 447 | 451 |
| 448 void DeleteSelectionCommand::handleGeneralDelete() | 452 void DeleteSelectionCommand::handleGeneralDelete(EditingState* editingState) |
| 449 { | 453 { |
| 450 if (m_upstreamStart.isNull()) | 454 if (m_upstreamStart.isNull()) |
| 451 return; | 455 return; |
| 452 | 456 |
| 453 int startOffset = m_upstreamStart.computeEditingOffset(); | 457 int startOffset = m_upstreamStart.computeEditingOffset(); |
| 454 Node* startNode = m_upstreamStart.anchorNode(); | 458 Node* startNode = m_upstreamStart.anchorNode(); |
| 455 ASSERT(startNode); | 459 ASSERT(startNode); |
| 456 | 460 |
| 457 makeStylingElementsDirectChildrenOfEditableRootToPreventStyleLoss(); | 461 makeStylingElementsDirectChildrenOfEditableRootToPreventStyleLoss(); |
| 458 | 462 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 485 // in a text node that needs to be trimmed | 489 // in a text node that needs to be trimmed |
| 486 Text* text = toText(startNode); | 490 Text* text = toText(startNode); |
| 487 deleteTextFromNode(text, startOffset, m_downstreamEnd.computeOff
setInContainerNode() - startOffset); | 491 deleteTextFromNode(text, startOffset, m_downstreamEnd.computeOff
setInContainerNode() - startOffset); |
| 488 } else { | 492 } else { |
| 489 removeChildrenInRange(startNode, startOffset, m_downstreamEnd.co
mputeEditingOffset()); | 493 removeChildrenInRange(startNode, startOffset, m_downstreamEnd.co
mputeEditingOffset()); |
| 490 m_endingPosition = m_upstreamStart; | 494 m_endingPosition = m_upstreamStart; |
| 491 } | 495 } |
| 492 } | 496 } |
| 493 | 497 |
| 494 // The selection to delete is all in one node. | 498 // The selection to delete is all in one node. |
| 495 if (!startNode->layoutObject() || (!startOffset && m_downstreamEnd.atLas
tEditingPositionForNode())) | 499 if (!startNode->layoutObject() || (!startOffset && m_downstreamEnd.atLas
tEditingPositionForNode())) { |
| 496 removeNode(startNode); | 500 removeNode(startNode, editingState); |
| 501 if (editingState->isAborted()) |
| 502 return; |
| 503 } |
| 497 } else { | 504 } else { |
| 498 bool startNodeWasDescendantOfEndNode = m_upstreamStart.anchorNode()->isD
escendantOf(m_downstreamEnd.anchorNode()); | 505 bool startNodeWasDescendantOfEndNode = m_upstreamStart.anchorNode()->isD
escendantOf(m_downstreamEnd.anchorNode()); |
| 499 // The selection to delete spans more than one node. | 506 // The selection to delete spans more than one node. |
| 500 RefPtrWillBeRawPtr<Node> node(startNode); | 507 RefPtrWillBeRawPtr<Node> node(startNode); |
| 501 | 508 |
| 502 if (startOffset > 0) { | 509 if (startOffset > 0) { |
| 503 if (startNode->isTextNode()) { | 510 if (startNode->isTextNode()) { |
| 504 // in a text node that needs to be trimmed | 511 // in a text node that needs to be trimmed |
| 505 Text* text = toText(node); | 512 Text* text = toText(node); |
| 506 deleteTextFromNode(text, startOffset, text->length() - startOffs
et); | 513 deleteTextFromNode(text, startOffset, text->length() - startOffs
et); |
| 507 node = NodeTraversal::next(*node); | 514 node = NodeTraversal::next(*node); |
| 508 } else { | 515 } else { |
| 509 node = NodeTraversal::childAt(*startNode, startOffset); | 516 node = NodeTraversal::childAt(*startNode, startOffset); |
| 510 } | 517 } |
| 511 } else if (startNode == m_upstreamEnd.anchorNode() && startNode->isTextN
ode()) { | 518 } else if (startNode == m_upstreamEnd.anchorNode() && startNode->isTextN
ode()) { |
| 512 Text* text = toText(m_upstreamEnd.anchorNode()); | 519 Text* text = toText(m_upstreamEnd.anchorNode()); |
| 513 deleteTextFromNode(text, 0, m_upstreamEnd.computeOffsetInContainerNo
de()); | 520 deleteTextFromNode(text, 0, m_upstreamEnd.computeOffsetInContainerNo
de()); |
| 514 } | 521 } |
| 515 | 522 |
| 516 // handle deleting all nodes that are completely selected | 523 // handle deleting all nodes that are completely selected |
| 517 while (node && node != m_downstreamEnd.anchorNode()) { | 524 while (node && node != m_downstreamEnd.anchorNode()) { |
| 518 if (comparePositions(firstPositionInOrBeforeNode(node.get()), m_down
streamEnd) >= 0) { | 525 if (comparePositions(firstPositionInOrBeforeNode(node.get()), m_down
streamEnd) >= 0) { |
| 519 // NodeTraversal::nextSkippingChildren just blew past the end po
sition, so stop deleting | 526 // NodeTraversal::nextSkippingChildren just blew past the end po
sition, so stop deleting |
| 520 node = nullptr; | 527 node = nullptr; |
| 521 } else if (!m_downstreamEnd.anchorNode()->isDescendantOf(node.get())
) { | 528 } else if (!m_downstreamEnd.anchorNode()->isDescendantOf(node.get())
) { |
| 522 RefPtrWillBeRawPtr<Node> nextNode = NodeTraversal::nextSkippingC
hildren(*node); | 529 RefPtrWillBeRawPtr<Node> nextNode = NodeTraversal::nextSkippingC
hildren(*node); |
| 523 // if we just removed a node from the end container, update end
position so the | 530 // if we just removed a node from the end container, update end
position so the |
| 524 // check above will work | 531 // check above will work |
| 525 updatePositionForNodeRemoval(m_downstreamEnd, *node); | 532 updatePositionForNodeRemoval(m_downstreamEnd, *node); |
| 526 removeNode(node.get()); | 533 removeNode(node.get(), editingState); |
| 534 if (editingState->isAborted()) |
| 535 return; |
| 527 node = nextNode.get(); | 536 node = nextNode.get(); |
| 528 } else { | 537 } else { |
| 529 Node& n = NodeTraversal::lastWithinOrSelf(*node); | 538 Node& n = NodeTraversal::lastWithinOrSelf(*node); |
| 530 if (m_downstreamEnd.anchorNode() == n && m_downstreamEnd.compute
EditingOffset() >= caretMaxOffset(&n)) { | 539 if (m_downstreamEnd.anchorNode() == n && m_downstreamEnd.compute
EditingOffset() >= caretMaxOffset(&n)) { |
| 531 removeNode(node.get()); | 540 removeNode(node.get(), editingState); |
| 541 if (editingState->isAborted()) |
| 542 return; |
| 532 node = nullptr; | 543 node = nullptr; |
| 533 } else { | 544 } else { |
| 534 node = NodeTraversal::next(*node); | 545 node = NodeTraversal::next(*node); |
| 535 } | 546 } |
| 536 } | 547 } |
| 537 } | 548 } |
| 538 | 549 |
| 539 if (m_downstreamEnd.anchorNode() != startNode && !m_upstreamStart.anchor
Node()->isDescendantOf(m_downstreamEnd.anchorNode()) && m_downstreamEnd.inDocume
nt() && m_downstreamEnd.computeEditingOffset() >= caretMinOffset(m_downstreamEnd
.anchorNode())) { | 550 if (m_downstreamEnd.anchorNode() != startNode && !m_upstreamStart.anchor
Node()->isDescendantOf(m_downstreamEnd.anchorNode()) && m_downstreamEnd.inDocume
nt() && m_downstreamEnd.computeEditingOffset() >= caretMinOffset(m_downstreamEnd
.anchorNode())) { |
| 540 if (m_downstreamEnd.atLastEditingPositionForNode() && !canHaveChildr
enForEditing(m_downstreamEnd.anchorNode())) { | 551 if (m_downstreamEnd.atLastEditingPositionForNode() && !canHaveChildr
enForEditing(m_downstreamEnd.anchorNode())) { |
| 541 // The node itself is fully selected, not just its contents. De
lete it. | 552 // The node itself is fully selected, not just its contents. De
lete it. |
| 542 removeNode(m_downstreamEnd.anchorNode()); | 553 removeNode(m_downstreamEnd.anchorNode(), editingState); |
| 543 } else { | 554 } else { |
| 544 if (m_downstreamEnd.anchorNode()->isTextNode()) { | 555 if (m_downstreamEnd.anchorNode()->isTextNode()) { |
| 545 // in a text node that needs to be trimmed | 556 // in a text node that needs to be trimmed |
| 546 Text* text = toText(m_downstreamEnd.anchorNode()); | 557 Text* text = toText(m_downstreamEnd.anchorNode()); |
| 547 if (m_downstreamEnd.computeEditingOffset() > 0) { | 558 if (m_downstreamEnd.computeEditingOffset() > 0) { |
| 548 deleteTextFromNode(text, 0, m_downstreamEnd.computeEditi
ngOffset()); | 559 deleteTextFromNode(text, 0, m_downstreamEnd.computeEditi
ngOffset()); |
| 549 } | 560 } |
| 550 // Remove children of m_downstreamEnd.anchorNode() that come aft
er m_upstreamStart. | 561 // Remove children of m_downstreamEnd.anchorNode() that come aft
er m_upstreamStart. |
| 551 // Don't try to remove children if m_upstreamStart was inside m_
downstreamEnd.anchorNode() | 562 // Don't try to remove children if m_upstreamStart was inside m_
downstreamEnd.anchorNode() |
| 552 // and m_upstreamStart has been removed from the document, becau
se then we don't | 563 // and m_upstreamStart has been removed from the document, becau
se then we don't |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 832 // deleting just a BR is handled specially, at least because we do not | 843 // deleting just a BR is handled specially, at least because we do not |
| 833 // want to replace it with a placeholder BR! | 844 // want to replace it with a placeholder BR! |
| 834 if (handleSpecialCaseBRDelete()) { | 845 if (handleSpecialCaseBRDelete()) { |
| 835 calculateTypingStyleAfterDelete(); | 846 calculateTypingStyleAfterDelete(); |
| 836 setEndingSelection(VisibleSelection(m_endingPosition, affinity, endingSe
lection().isDirectional())); | 847 setEndingSelection(VisibleSelection(m_endingPosition, affinity, endingSe
lection().isDirectional())); |
| 837 clearTransientState(); | 848 clearTransientState(); |
| 838 rebalanceWhitespace(); | 849 rebalanceWhitespace(); |
| 839 return; | 850 return; |
| 840 } | 851 } |
| 841 | 852 |
| 842 handleGeneralDelete(); | 853 handleGeneralDelete(editingState); |
| 854 if (editingState->isAborted()) |
| 855 return; |
| 843 | 856 |
| 844 fixupWhitespace(); | 857 fixupWhitespace(); |
| 845 | 858 |
| 846 mergeParagraphs(); | 859 mergeParagraphs(); |
| 847 | 860 |
| 848 removePreviouslySelectedEmptyTableRows(); | 861 removePreviouslySelectedEmptyTableRows(); |
| 849 | 862 |
| 850 if (!m_needPlaceholder && rootWillStayOpenWithoutPlaceholder) { | 863 if (!m_needPlaceholder && rootWillStayOpenWithoutPlaceholder) { |
| 851 VisiblePosition visualEnding = createVisiblePosition(m_endingPosition); | 864 VisiblePosition visualEnding = createVisiblePosition(m_endingPosition); |
| 852 bool hasPlaceholder = lineBreakExistsAtVisiblePosition(visualEnding) | 865 bool hasPlaceholder = lineBreakExistsAtVisiblePosition(visualEnding) |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 908 visitor->trace(m_deleteIntoBlockquoteStyle); | 921 visitor->trace(m_deleteIntoBlockquoteStyle); |
| 909 visitor->trace(m_startRoot); | 922 visitor->trace(m_startRoot); |
| 910 visitor->trace(m_endRoot); | 923 visitor->trace(m_endRoot); |
| 911 visitor->trace(m_startTableRow); | 924 visitor->trace(m_startTableRow); |
| 912 visitor->trace(m_endTableRow); | 925 visitor->trace(m_endTableRow); |
| 913 visitor->trace(m_temporaryPlaceholder); | 926 visitor->trace(m_temporaryPlaceholder); |
| 914 CompositeEditCommand::trace(visitor); | 927 CompositeEditCommand::trace(visitor); |
| 915 } | 928 } |
| 916 | 929 |
| 917 } // namespace blink | 930 } // namespace blink |
| OLD | NEW |