Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(297)

Side by Side Diff: third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp

Issue 1690513002: Editing: Pass failure information of RemoveNodeCommand to ReplaceSelectionCommand. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: add a comment Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698