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 |