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

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

Issue 2397963002: Reflow comments in //third_party/WebKit/Source/core/editing/commands (Closed)
Patch Set: . Created 4 years, 2 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, 2006, 2008 Apple Inc. All rights reserved. 2 * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2009, 2010, 2011 Google Inc. All rights reserved. 3 * Copyright (C) 2009, 2010, 2011 Google Inc. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 (AppleConvertedSpace)); 124 (AppleConvertedSpace));
125 if (!node->isHTMLElement() || 125 if (!node->isHTMLElement() ||
126 toHTMLElement(node)->getAttribute(classAttr) != 126 toHTMLElement(node)->getAttribute(classAttr) !=
127 convertedSpaceSpanClassString) 127 convertedSpaceSpanClassString)
128 return false; 128 return false;
129 UseCounter::count(node->document(), UseCounter::EditingAppleConvertedSpace); 129 UseCounter::count(node->document(), UseCounter::EditingAppleConvertedSpace);
130 return true; 130 return true;
131 } 131 }
132 132
133 static Position positionAvoidingPrecedingNodes(Position pos) { 133 static Position positionAvoidingPrecedingNodes(Position pos) {
134 // If we're already on a break, it's probably a placeholder and we shouldn't c hange our position. 134 // If we're already on a break, it's probably a placeholder and we shouldn't
135 // change our position.
135 if (editingIgnoresContent(pos.anchorNode())) 136 if (editingIgnoresContent(pos.anchorNode()))
136 return pos; 137 return pos;
137 138
138 // We also stop when changing block flow elements because even though the visu al position is the 139 // We also stop when changing block flow elements because even though the
139 // same. E.g., 140 // visual position is the same. E.g.,
140 // <div>foo^</div>^ 141 // <div>foo^</div>^
141 // The two positions above are the same visual position, but we want to stay i n the same block. 142 // The two positions above are the same visual position, but we want to stay
143 // in the same block.
142 Element* enclosingBlockElement = enclosingBlock(pos.computeContainerNode()); 144 Element* enclosingBlockElement = enclosingBlock(pos.computeContainerNode());
143 for (Position nextPosition = pos; 145 for (Position nextPosition = pos;
144 nextPosition.computeContainerNode() != enclosingBlockElement; 146 nextPosition.computeContainerNode() != enclosingBlockElement;
145 pos = nextPosition) { 147 pos = nextPosition) {
146 if (lineBreakExistsAtPosition(pos)) 148 if (lineBreakExistsAtPosition(pos))
147 break; 149 break;
148 150
149 if (pos.computeContainerNode()->nonShadowBoundaryParentNode()) 151 if (pos.computeContainerNode()->nonShadowBoundaryParentNode())
150 nextPosition = Position::inParentAfterNode(*pos.computeContainerNode()); 152 nextPosition = Position::inParentAfterNode(*pos.computeContainerNode());
151 153
(...skipping 26 matching lines...) Expand all
178 return; 180 return;
179 181
180 Element* shadowAncestorElement; 182 Element* shadowAncestorElement;
181 if (editableRoot->isInShadowTree()) 183 if (editableRoot->isInShadowTree())
182 shadowAncestorElement = editableRoot->ownerShadowHost(); 184 shadowAncestorElement = editableRoot->ownerShadowHost();
183 else 185 else
184 shadowAncestorElement = editableRoot; 186 shadowAncestorElement = editableRoot;
185 187
186 if (!editableRoot->getAttributeEventListener( 188 if (!editableRoot->getAttributeEventListener(
187 EventTypeNames::webkitBeforeTextInserted) 189 EventTypeNames::webkitBeforeTextInserted)
188 // FIXME: Remove these checks once textareas and textfields actually regis ter an event handler. 190 // FIXME: Remove these checks once textareas and textfields actually
191 // register an event handler.
189 && 192 &&
190 !(shadowAncestorElement && shadowAncestorElement->layoutObject() && 193 !(shadowAncestorElement && shadowAncestorElement->layoutObject() &&
191 shadowAncestorElement->layoutObject()->isTextControl()) && 194 shadowAncestorElement->layoutObject()->isTextControl()) &&
192 hasRichlyEditableStyle(*editableRoot)) { 195 hasRichlyEditableStyle(*editableRoot)) {
193 removeInterchangeNodes(m_fragment.get()); 196 removeInterchangeNodes(m_fragment.get());
194 return; 197 return;
195 } 198 }
196 199
197 if (!hasRichlyEditableStyle(*editableRoot)) { 200 if (!hasRichlyEditableStyle(*editableRoot)) {
198 bool isPlainText = true; 201 bool isPlainText = true;
199 for (Node& node : NodeTraversal::childrenOf(*m_fragment)) { 202 for (Node& node : NodeTraversal::childrenOf(*m_fragment)) {
200 if (isInterchangeHTMLBRElement(&node) && &node == m_fragment->lastChild()) 203 if (isInterchangeHTMLBRElement(&node) && &node == m_fragment->lastChild())
201 continue; 204 continue;
202 if (!node.isTextNode()) { 205 if (!node.isTextNode()) {
203 isPlainText = false; 206 isPlainText = false;
204 break; 207 break;
205 } 208 }
206 } 209 }
207 // We don't need TestRendering for plain-text editing + plain-text insertion . 210 // We don't need TestRendering for plain-text editing + plain-text
211 // insertion.
208 if (isPlainText) { 212 if (isPlainText) {
209 removeInterchangeNodes(m_fragment.get()); 213 removeInterchangeNodes(m_fragment.get());
210 String originalText = m_fragment->textContent(); 214 String originalText = m_fragment->textContent();
211 BeforeTextInsertedEvent* event = 215 BeforeTextInsertedEvent* event =
212 BeforeTextInsertedEvent::create(originalText); 216 BeforeTextInsertedEvent::create(originalText);
213 editableRoot->dispatchEvent(event); 217 editableRoot->dispatchEvent(event);
214 if (originalText != event->text()) { 218 if (originalText != event->text()) {
215 m_fragment = createFragmentFromText( 219 m_fragment = createFragmentFromText(
216 selection.toNormalizedEphemeralRange(), event->text()); 220 selection.toNormalizedEphemeralRange(), event->text());
217 removeInterchangeNodes(m_fragment.get()); 221 removeInterchangeNodes(m_fragment.get());
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after
454 if (m_movingParagraph) 458 if (m_movingParagraph)
455 return false; 459 return false;
456 460
457 VisiblePosition startOfInsertedContent = positionAtStartOfInsertedContent(); 461 VisiblePosition startOfInsertedContent = positionAtStartOfInsertedContent();
458 VisiblePosition prev = 462 VisiblePosition prev =
459 previousPositionOf(startOfInsertedContent, CannotCrossEditingBoundary); 463 previousPositionOf(startOfInsertedContent, CannotCrossEditingBoundary);
460 if (prev.isNull()) 464 if (prev.isNull())
461 return false; 465 return false;
462 466
463 // When we have matching quote levels, its ok to merge more frequently. 467 // When we have matching quote levels, its ok to merge more frequently.
464 // For a successful merge, we still need to make sure that the inserted conten t starts with the beginning of a paragraph. 468 // For a successful merge, we still need to make sure that the inserted
465 // And we should only merge here if the selection start was inside a mail bloc kquote. This prevents against removing a 469 // content starts with the beginning of a paragraph. And we should only merge
466 // blockquote from newly pasted quoted content that was pasted into an unquote d position. If that unquoted position happens 470 // here if the selection start was inside a mail blockquote. This prevents
467 // to be right after another blockquote, we don't want to merge and risk strip ping a valid block (and newline) from the pasted content. 471 // against removing a blockquote from newly pasted quoted content that was
472 // pasted into an unquoted position. If that unquoted position happens to be
473 // right after another blockquote, we don't want to merge and risk stripping a
474 // valid block (and newline) from the pasted content.
468 if (isStartOfParagraphDeprecated(startOfInsertedContent) && 475 if (isStartOfParagraphDeprecated(startOfInsertedContent) &&
469 selectionStartWasInsideMailBlockquote && 476 selectionStartWasInsideMailBlockquote &&
470 hasMatchingQuoteLevel(prev, positionAtEndOfInsertedContent())) 477 hasMatchingQuoteLevel(prev, positionAtEndOfInsertedContent()))
471 return true; 478 return true;
472 479
473 return !selectionStartWasStartOfParagraph && 480 return !selectionStartWasStartOfParagraph &&
474 !fragmentHasInterchangeNewlineAtStart && 481 !fragmentHasInterchangeNewlineAtStart &&
475 isStartOfParagraphDeprecated(startOfInsertedContent) && 482 isStartOfParagraphDeprecated(startOfInsertedContent) &&
476 !isHTMLBRElement( 483 !isHTMLBRElement(
477 *startOfInsertedContent.deepEquivalent().anchorNode()) && 484 *startOfInsertedContent.deepEquivalent().anchorNode()) &&
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
530 return !enclosingNodeOfType(source.deepEquivalent(), 537 return !enclosingNodeOfType(source.deepEquivalent(),
531 &isMailPasteAsQuotationHTMLBlockQuoteElement) && 538 &isMailPasteAsQuotationHTMLBlockQuoteElement) &&
532 sourceBlock && (!sourceBlock->hasTagName(blockquoteTag) || 539 sourceBlock && (!sourceBlock->hasTagName(blockquoteTag) ||
533 isMailHTMLBlockquoteElement(sourceBlock)) && 540 isMailHTMLBlockquoteElement(sourceBlock)) &&
534 enclosingListChild(sourceBlock) == 541 enclosingListChild(sourceBlock) ==
535 enclosingListChild(destinationNode) && 542 enclosingListChild(destinationNode) &&
536 enclosingTableCell(source.deepEquivalent()) == 543 enclosingTableCell(source.deepEquivalent()) ==
537 enclosingTableCell(destination.deepEquivalent()) && 544 enclosingTableCell(destination.deepEquivalent()) &&
538 (!isHTMLHeaderElement(sourceBlock) || 545 (!isHTMLHeaderElement(sourceBlock) ||
539 haveSameTagName(sourceBlock, destinationBlock)) 546 haveSameTagName(sourceBlock, destinationBlock))
540 // Don't merge to or from a position before or after a block because it would 547 // Don't merge to or from a position before or after a block because it
541 // be a no-op and cause infinite recursion. 548 // would be a no-op and cause infinite recursion.
542 && !isEnclosingBlock(sourceNode) && !isEnclosingBlock(destinationNode); 549 && !isEnclosingBlock(sourceNode) && !isEnclosingBlock(destinationNode);
543 } 550 }
544 551
545 // Style rules that match just inserted elements could change their appearance, like 552 // Style rules that match just inserted elements could change their appearance,
546 // a div inserted into a document with div { display:inline; }. 553 // like a div inserted into a document with div { display:inline; }.
547 void ReplaceSelectionCommand::removeRedundantStylesAndKeepStyleSpanInline( 554 void ReplaceSelectionCommand::removeRedundantStylesAndKeepStyleSpanInline(
548 InsertedNodes& insertedNodes, 555 InsertedNodes& insertedNodes,
549 EditingState* editingState) { 556 EditingState* editingState) {
550 Node* pastEndNode = insertedNodes.pastLastLeaf(); 557 Node* pastEndNode = insertedNodes.pastLastLeaf();
551 Node* next = nullptr; 558 Node* next = nullptr;
552 for (Node* node = insertedNodes.firstNodeInserted(); 559 for (Node* node = insertedNodes.firstNodeInserted();
553 node && node != pastEndNode; node = next) { 560 node && node != pastEndNode; node = next) {
554 // FIXME: <rdar://problem/5371536> Style rules that match pasted content can change it's appearance 561 // FIXME: <rdar://problem/5371536> Style rules that match pasted content can
562 // change it's appearance
555 563
556 next = NodeTraversal::next(*node); 564 next = NodeTraversal::next(*node);
557 if (!node->isStyledElement()) 565 if (!node->isStyledElement())
558 continue; 566 continue;
559 567
560 Element* element = toElement(node); 568 Element* element = toElement(node);
561 569
562 const StylePropertySet* inlineStyle = element->inlineStyle(); 570 const StylePropertySet* inlineStyle = element->inlineStyle();
563 EditingStyle* newInlineStyle = EditingStyle::create(inlineStyle); 571 EditingStyle* newInlineStyle = EditingStyle::create(inlineStyle);
564 if (inlineStyle) { 572 if (inlineStyle) {
565 if (element->isHTMLElement()) { 573 if (element->isHTMLElement()) {
566 Vector<QualifiedName> attributes; 574 Vector<QualifiedName> attributes;
567 HTMLElement* htmlElement = toHTMLElement(element); 575 HTMLElement* htmlElement = toHTMLElement(element);
568 DCHECK(htmlElement); 576 DCHECK(htmlElement);
569 577
570 if (newInlineStyle->conflictsWithImplicitStyleOfElement(htmlElement)) { 578 if (newInlineStyle->conflictsWithImplicitStyleOfElement(htmlElement)) {
571 // e.g. <b style="font-weight: normal;"> is converted to <span style=" font-weight: normal;"> 579 // e.g. <b style="font-weight: normal;"> is converted to <span
580 // style="font-weight: normal;">
572 element = replaceElementWithSpanPreservingChildrenAndAttributes( 581 element = replaceElementWithSpanPreservingChildrenAndAttributes(
573 htmlElement); 582 htmlElement);
574 inlineStyle = element->inlineStyle(); 583 inlineStyle = element->inlineStyle();
575 insertedNodes.didReplaceNode(*htmlElement, *element); 584 insertedNodes.didReplaceNode(*htmlElement, *element);
576 } else if (newInlineStyle->extractConflictingImplicitStyleOfAttributes( 585 } else if (newInlineStyle->extractConflictingImplicitStyleOfAttributes(
577 htmlElement, EditingStyle::PreserveWritingDirection, 0, 586 htmlElement, EditingStyle::PreserveWritingDirection, 0,
578 attributes, EditingStyle::DoNotExtractMatchingStyle)) { 587 attributes, EditingStyle::DoNotExtractMatchingStyle)) {
579 // e.g. <font size="3" style="font-size: 20px;"> is converted to <font style="font-size: 20px;"> 588 // e.g. <font size="3" style="font-size: 20px;"> is converted to <font
589 // style="font-size: 20px;">
580 for (size_t i = 0; i < attributes.size(); i++) 590 for (size_t i = 0; i < attributes.size(); i++)
581 removeElementAttribute(htmlElement, attributes[i]); 591 removeElementAttribute(htmlElement, attributes[i]);
582 } 592 }
583 } 593 }
584 594
585 ContainerNode* context = element->parentNode(); 595 ContainerNode* context = element->parentNode();
586 596
587 // If Mail wraps the fragment with a Paste as Quotation blockquote, or if you're pasting into a quoted region, 597 // If Mail wraps the fragment with a Paste as Quotation blockquote, or if
588 // styles from blockquoteNode are allowed to override those from the sourc e document, see <rdar://problem/4930986> and <rdar://problem/5089327>. 598 // you're pasting into a quoted region, styles from blockquoteNode are
599 // allowed to override those from the source document, see
600 // <rdar://problem/4930986> and <rdar://problem/5089327>.
589 HTMLQuoteElement* blockquoteElement = 601 HTMLQuoteElement* blockquoteElement =
590 !context || isMailPasteAsQuotationHTMLBlockQuoteElement(context) 602 !context || isMailPasteAsQuotationHTMLBlockQuoteElement(context)
591 ? toHTMLQuoteElement(context) 603 ? toHTMLQuoteElement(context)
592 : toHTMLQuoteElement(enclosingNodeOfType( 604 : toHTMLQuoteElement(enclosingNodeOfType(
593 Position::firstPositionInNode(context), 605 Position::firstPositionInNode(context),
594 isMailHTMLBlockquoteElement, CanCrossEditingBoundary)); 606 isMailHTMLBlockquoteElement, CanCrossEditingBoundary));
595 if (blockquoteElement) 607 if (blockquoteElement)
596 newInlineStyle->removeStyleFromRulesAndContext( 608 newInlineStyle->removeStyleFromRulesAndContext(
597 element, document().documentElement()); 609 element, document().documentElement());
598 610
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
637 // WebKit used to not add display: inline and float: none on copy. 649 // WebKit used to not add display: inline and float: none on copy.
638 // Keep this code around for backward compatibility 650 // Keep this code around for backward compatibility
639 if (isLegacyAppleHTMLSpanElement(element)) { 651 if (isLegacyAppleHTMLSpanElement(element)) {
640 if (!element->hasChildren()) { 652 if (!element->hasChildren()) {
641 insertedNodes.willRemoveNodePreservingChildren(*element); 653 insertedNodes.willRemoveNodePreservingChildren(*element);
642 removeNodePreservingChildren(element, editingState); 654 removeNodePreservingChildren(element, editingState);
643 if (editingState->isAborted()) 655 if (editingState->isAborted())
644 return; 656 return;
645 continue; 657 continue;
646 } 658 }
647 // There are other styles that style rules can give to style spans, 659 // There are other styles that style rules can give to style spans, but
648 // but these are the two important ones because they'll prevent 660 // these are the two important ones because they'll prevent inserted
649 // inserted content from appearing in the right paragraph. 661 // content from appearing in the right paragraph.
650 // FIXME: Hyatt is concerned that selectively using display:inline will gi ve inconsistent 662 // FIXME: Hyatt is concerned that selectively using display:inline will
651 // results. We already know one issue because td elements ignore their dis play property 663 // give inconsistent results. We already know one issue because td
652 // in quirks mode (which Mail.app is always in). We should look for an alt ernative. 664 // elements ignore their display property in quirks mode (which Mail.app
665 // is always in). We should look for an alternative.
653 666
654 // Mutate using the CSSOM wrapper so we get the same event behavior as a s cript. 667 // Mutate using the CSSOM wrapper so we get the same event behavior as a
668 // script.
655 if (isEnclosingBlock(element)) 669 if (isEnclosingBlock(element))
656 element->style()->setPropertyInternal( 670 element->style()->setPropertyInternal(
657 CSSPropertyDisplay, String(), "inline", false, IGNORE_EXCEPTION); 671 CSSPropertyDisplay, String(), "inline", false, IGNORE_EXCEPTION);
658 if (element->layoutObject() && 672 if (element->layoutObject() &&
659 element->layoutObject()->style()->isFloating()) 673 element->layoutObject()->style()->isFloating())
660 element->style()->setPropertyInternal(CSSPropertyFloat, String(), 674 element->style()->setPropertyInternal(CSSPropertyFloat, String(),
661 "none", false, IGNORE_EXCEPTION); 675 "none", false, IGNORE_EXCEPTION);
662 } 676 }
663 } 677 }
664 } 678 }
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
782 !nodeHasVisibleLayoutText(toText(*lastLeafInserted)) && 796 !nodeHasVisibleLayoutText(toText(*lastLeafInserted)) &&
783 !enclosingElementWithTag(firstPositionInOrBeforeNode(lastLeafInserted), 797 !enclosingElementWithTag(firstPositionInOrBeforeNode(lastLeafInserted),
784 selectTag) && 798 selectTag) &&
785 !enclosingElementWithTag(firstPositionInOrBeforeNode(lastLeafInserted), 799 !enclosingElementWithTag(firstPositionInOrBeforeNode(lastLeafInserted),
786 scriptTag)) { 800 scriptTag)) {
787 insertedNodes.willRemoveNode(*lastLeafInserted); 801 insertedNodes.willRemoveNode(*lastLeafInserted);
788 // Removing a Text node won't dispatch synchronous events. 802 // Removing a Text node won't dispatch synchronous events.
789 removeNode(lastLeafInserted, ASSERT_NO_EDITING_ABORT); 803 removeNode(lastLeafInserted, ASSERT_NO_EDITING_ABORT);
790 } 804 }
791 805
792 // We don't have to make sure that firstNodeInserted isn't inside a select or script element, because 806 // We don't have to make sure that firstNodeInserted isn't inside a select or
793 // it is a top level node in the fragment and the user can't insert into those elements. 807 // script element, because it is a top level node in the fragment and the user
808 // can't insert into those elements.
794 Node* firstNodeInserted = insertedNodes.firstNodeInserted(); 809 Node* firstNodeInserted = insertedNodes.firstNodeInserted();
795 if (firstNodeInserted && firstNodeInserted->isTextNode() && 810 if (firstNodeInserted && firstNodeInserted->isTextNode() &&
796 !nodeHasVisibleLayoutText(toText(*firstNodeInserted))) { 811 !nodeHasVisibleLayoutText(toText(*firstNodeInserted))) {
797 insertedNodes.willRemoveNode(*firstNodeInserted); 812 insertedNodes.willRemoveNode(*firstNodeInserted);
798 // Removing a Text node won't dispatch synchronous events. 813 // Removing a Text node won't dispatch synchronous events.
799 removeNode(firstNodeInserted, ASSERT_NO_EDITING_ABORT); 814 removeNode(firstNodeInserted, ASSERT_NO_EDITING_ABORT);
800 } 815 }
801 } 816 }
802 817
803 VisiblePosition ReplaceSelectionCommand::positionAtEndOfInsertedContent() 818 VisiblePosition ReplaceSelectionCommand::positionAtEndOfInsertedContent()
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
839 if (!node->isHTMLElement()) 854 if (!node->isHTMLElement())
840 return false; 855 return false;
841 856
842 const HTMLElement& element = toHTMLElement(*node); 857 const HTMLElement& element = toHTMLElement(*node);
843 return isListItem(node) || isTableCell(node) || element.hasTagName(preTag) || 858 return isListItem(node) || isTableCell(node) || element.hasTagName(preTag) ||
844 element.hasTagName(h1Tag) || element.hasTagName(h2Tag) || 859 element.hasTagName(h1Tag) || element.hasTagName(h2Tag) ||
845 element.hasTagName(h3Tag) || element.hasTagName(h4Tag) || 860 element.hasTagName(h3Tag) || element.hasTagName(h4Tag) ||
846 element.hasTagName(h5Tag) || element.hasTagName(h6Tag); 861 element.hasTagName(h5Tag) || element.hasTagName(h6Tag);
847 } 862 }
848 863
849 // Remove style spans before insertion if they are unnecessary. It's faster bec ause we'll 864 // Remove style spans before insertion if they are unnecessary. It's faster
850 // avoid doing a layout. 865 // because we'll avoid doing a layout.
851 static bool handleStyleSpansBeforeInsertion(ReplacementFragment& fragment, 866 static bool handleStyleSpansBeforeInsertion(ReplacementFragment& fragment,
852 const Position& insertionPos) { 867 const Position& insertionPos) {
853 Node* topNode = fragment.firstChild(); 868 Node* topNode = fragment.firstChild();
854 if (!isHTMLSpanElement(topNode)) 869 if (!isHTMLSpanElement(topNode))
855 return false; 870 return false;
856 871
857 // Handling the case where we are doing Paste as Quotation or pasting into quo ted content is more complicated (see handleStyleSpans) 872 // Handling the case where we are doing Paste as Quotation or pasting into
858 // and doesn't receive the optimization. 873 // quoted content is more complicated (see handleStyleSpans) and doesn't
874 // receive the optimization.
859 if (isMailPasteAsQuotationHTMLBlockQuoteElement(topNode) || 875 if (isMailPasteAsQuotationHTMLBlockQuoteElement(topNode) ||
860 enclosingNodeOfType(firstPositionInOrBeforeNode(topNode), 876 enclosingNodeOfType(firstPositionInOrBeforeNode(topNode),
861 isMailHTMLBlockquoteElement, CanCrossEditingBoundary)) 877 isMailHTMLBlockquoteElement, CanCrossEditingBoundary))
862 return false; 878 return false;
863 879
864 // Remove style spans to follow the styles of parent block element when |fragm ent| becomes a part of it. 880 // Remove style spans to follow the styles of parent block element when
865 // See bugs http://crbug.com/226941 and http://crbug.com/335955. 881 // |fragment| becomes a part of it. See bugs http://crbug.com/226941 and
882 // http://crbug.com/335955.
866 HTMLSpanElement* wrappingStyleSpan = toHTMLSpanElement(topNode); 883 HTMLSpanElement* wrappingStyleSpan = toHTMLSpanElement(topNode);
867 const Node* node = insertionPos.anchorNode(); 884 const Node* node = insertionPos.anchorNode();
868 // |node| can be an inline element like <br> under <li> 885 // |node| can be an inline element like <br> under <li>
869 // e.g.) editing/execCommand/switch-list-type.html 886 // e.g.) editing/execCommand/switch-list-type.html
870 // editing/deleting/backspace-merge-into-block.html 887 // editing/deleting/backspace-merge-into-block.html
871 if (isInline(node)) { 888 if (isInline(node)) {
872 node = enclosingBlock(insertionPos.anchorNode()); 889 node = enclosingBlock(insertionPos.anchorNode());
873 if (!node) 890 if (!node)
874 return false; 891 return false;
875 } 892 }
876 893
877 if (followBlockElementStyle(node)) { 894 if (followBlockElementStyle(node)) {
878 fragment.removeNodePreservingChildren(wrappingStyleSpan); 895 fragment.removeNodePreservingChildren(wrappingStyleSpan);
879 return true; 896 return true;
880 } 897 }
881 898
882 // Either there are no style spans in the fragment or a WebKit client has adde d content to the fragment 899 // Either there are no style spans in the fragment or a WebKit client has
883 // before inserting it. Look for and handle style spans after insertion. 900 // added content to the fragment before inserting it. Look for and handle
901 // style spans after insertion.
884 if (!isLegacyAppleHTMLSpanElement(topNode)) 902 if (!isLegacyAppleHTMLSpanElement(topNode))
885 return false; 903 return false;
886 904
887 EditingStyle* styleAtInsertionPos = 905 EditingStyle* styleAtInsertionPos =
888 EditingStyle::create(insertionPos.parentAnchoredEquivalent()); 906 EditingStyle::create(insertionPos.parentAnchoredEquivalent());
889 String styleText = styleAtInsertionPos->style()->asText(); 907 String styleText = styleAtInsertionPos->style()->asText();
890 908
891 // FIXME: This string comparison is a naive way of comparing two styles. 909 // FIXME: This string comparison is a naive way of comparing two styles.
892 // We should be taking the diff and check that the diff is empty. 910 // We should be taking the diff and check that the diff is empty.
893 if (styleText != wrappingStyleSpan->getAttribute(styleAttr)) 911 if (styleText != wrappingStyleSpan->getAttribute(styleAttr))
894 return false; 912 return false;
895 913
896 fragment.removeNodePreservingChildren(wrappingStyleSpan); 914 fragment.removeNodePreservingChildren(wrappingStyleSpan);
897 return true; 915 return true;
898 } 916 }
899 917
900 // At copy time, WebKit wraps copied content in a span that contains the source document's 918 // At copy time, WebKit wraps copied content in a span that contains the source
901 // default styles. If the copied Range inherits any other styles from its ances tors, we put 919 // document's default styles. If the copied Range inherits any other styles
902 // those styles on a second span. 920 // from its ancestors, we put those styles on a second span. This function
903 // This function removes redundant styles from those spans, and removes the span s if all their 921 // removes redundant styles from those spans, and removes the
904 // styles are redundant. 922 // spans if all their styles are redundant.
905 // We should remove the Apple-style-span class when we're done, see <rdar://prob lem/5685600>. 923 // We should remove the Apple-style-span class when we're done, see
906 // We should remove styles from spans that are overridden by all of their childr en, either here 924 // <rdar://problem/5685600>.
907 // or at copy time. 925 // We should remove styles from spans that are overridden by all of their
926 // children, either here or at copy time.
908 void ReplaceSelectionCommand::handleStyleSpans(InsertedNodes& insertedNodes, 927 void ReplaceSelectionCommand::handleStyleSpans(InsertedNodes& insertedNodes,
909 EditingState* editingState) { 928 EditingState* editingState) {
910 if (!insertedNodes.firstNodeInserted()) 929 if (!insertedNodes.firstNodeInserted())
911 return; 930 return;
912 931
913 HTMLSpanElement* wrappingStyleSpan = nullptr; 932 HTMLSpanElement* wrappingStyleSpan = nullptr;
914 // The style span that contains the source document's default style should be at 933 // The style span that contains the source document's default style should be
915 // the top of the fragment, but Mail sometimes adds a wrapper (for Paste As Qu otation), 934 // at the top of the fragment, but Mail sometimes adds a wrapper (for Paste As
916 // so search for the top level style span instead of assuming it's at the top. 935 // Quotation), so search for the top level style span instead of assuming it's
936 // at the top.
917 937
918 for (Node& node : 938 for (Node& node :
919 NodeTraversal::startsAt(*insertedNodes.firstNodeInserted())) { 939 NodeTraversal::startsAt(*insertedNodes.firstNodeInserted())) {
920 if (isLegacyAppleHTMLSpanElement(&node)) { 940 if (isLegacyAppleHTMLSpanElement(&node)) {
921 wrappingStyleSpan = toHTMLSpanElement(&node); 941 wrappingStyleSpan = toHTMLSpanElement(&node);
922 break; 942 break;
923 } 943 }
924 } 944 }
925 945
926 // There might not be any style spans if we're pasting from another applicatio n or if 946 // There might not be any style spans if we're pasting from another
927 // we are here because of a document.execCommand("InsertHTML", ...) call. 947 // application or if we are here because of a
948 // document.execCommand("InsertHTML", ...) call.
928 if (!wrappingStyleSpan) 949 if (!wrappingStyleSpan)
929 return; 950 return;
930 951
931 EditingStyle* style = EditingStyle::create(wrappingStyleSpan->inlineStyle()); 952 EditingStyle* style = EditingStyle::create(wrappingStyleSpan->inlineStyle());
932 ContainerNode* context = wrappingStyleSpan->parentNode(); 953 ContainerNode* context = wrappingStyleSpan->parentNode();
933 954
934 // If Mail wraps the fragment with a Paste as Quotation blockquote, or if you' re pasting into a quoted region, 955 // If Mail wraps the fragment with a Paste as Quotation blockquote, or if
935 // styles from blockquoteElement are allowed to override those from the source document, see <rdar://problem/4930986> and <rdar://problem/5089327>. 956 // you're pasting into a quoted region, styles from blockquoteElement are
957 // allowed to override those from the source document, see
958 // <rdar://problem/4930986> and <rdar://problem/5089327>.
936 HTMLQuoteElement* blockquoteElement = 959 HTMLQuoteElement* blockquoteElement =
937 isMailPasteAsQuotationHTMLBlockQuoteElement(context) 960 isMailPasteAsQuotationHTMLBlockQuoteElement(context)
938 ? toHTMLQuoteElement(context) 961 ? toHTMLQuoteElement(context)
939 : toHTMLQuoteElement(enclosingNodeOfType( 962 : toHTMLQuoteElement(enclosingNodeOfType(
940 Position::firstPositionInNode(context), 963 Position::firstPositionInNode(context),
941 isMailHTMLBlockquoteElement, CanCrossEditingBoundary)); 964 isMailHTMLBlockquoteElement, CanCrossEditingBoundary));
942 if (blockquoteElement) 965 if (blockquoteElement)
943 context = document().documentElement(); 966 context = document().documentElement();
944 967
945 // This operation requires that only editing styles to be removed from sourceD ocumentStyle. 968 // This operation requires that only editing styles to be removed from
969 // sourceDocumentStyle.
946 style->prepareToApplyAt(Position::firstPositionInNode(context)); 970 style->prepareToApplyAt(Position::firstPositionInNode(context));
947 971
948 // Remove block properties in the span's style. This prevents properties that probably have no effect 972 // Remove block properties in the span's style. This prevents properties that
949 // currently from affecting blocks later if the style is cloned for a new bloc k element during a future 973 // probably have no effect currently from affecting blocks later if the style
974 // is cloned for a new block element during a future
950 // editing operation. 975 // editing operation.
951 // FIXME: They *can* have an effect currently if blocks beneath the style span aren't individually marked 976 // FIXME: They *can* have an effect currently if blocks beneath the style span
952 // with block styles by the editing engine used to style them. WebKit doesn't do this, but others might. 977 // aren't individually marked with block styles by the editing engine used to
978 // style them. WebKit doesn't do this, but others might.
953 style->removeBlockProperties(); 979 style->removeBlockProperties();
954 980
955 if (style->isEmpty() || !wrappingStyleSpan->hasChildren()) { 981 if (style->isEmpty() || !wrappingStyleSpan->hasChildren()) {
956 insertedNodes.willRemoveNodePreservingChildren(*wrappingStyleSpan); 982 insertedNodes.willRemoveNodePreservingChildren(*wrappingStyleSpan);
957 removeNodePreservingChildren(wrappingStyleSpan, editingState); 983 removeNodePreservingChildren(wrappingStyleSpan, editingState);
958 } else { 984 } else {
959 setNodeAttribute(wrappingStyleSpan, styleAttr, 985 setNodeAttribute(wrappingStyleSpan, styleAttr,
960 AtomicString(style->style()->asText())); 986 AtomicString(style->style()->asText()));
961 } 987 }
962 } 988 }
963 989
964 void ReplaceSelectionCommand::mergeEndIfNeeded(EditingState* editingState) { 990 void ReplaceSelectionCommand::mergeEndIfNeeded(EditingState* editingState) {
965 if (!m_shouldMergeEnd) 991 if (!m_shouldMergeEnd)
966 return; 992 return;
967 993
968 VisiblePosition startOfInsertedContent(positionAtStartOfInsertedContent()); 994 VisiblePosition startOfInsertedContent(positionAtStartOfInsertedContent());
969 VisiblePosition endOfInsertedContent(positionAtEndOfInsertedContent()); 995 VisiblePosition endOfInsertedContent(positionAtEndOfInsertedContent());
970 996
971 // Bail to avoid infinite recursion. 997 // Bail to avoid infinite recursion.
972 if (m_movingParagraph) { 998 if (m_movingParagraph) {
973 NOTREACHED(); 999 NOTREACHED();
974 return; 1000 return;
975 } 1001 }
976 1002
977 // Merging two paragraphs will destroy the moved one's block styles. Always m ove the end of inserted forward 1003 // Merging two paragraphs will destroy the moved one's block styles. Always
978 // to preserve the block style of the paragraph already in the document, unles s the paragraph to move would 1004 // move the end of inserted forward to preserve the block style of the
979 // include the what was the start of the selection that was pasted into, so th at we preserve that paragraph's 1005 // paragraph already in the document, unless the paragraph to move would
980 // block styles. 1006 // include the what was the start of the selection that was pasted into, so
1007 // that we preserve that paragraph's block styles.
981 bool mergeForward = !( 1008 bool mergeForward = !(
982 inSameParagraphDeprecated(startOfInsertedContent, endOfInsertedContent) && 1009 inSameParagraphDeprecated(startOfInsertedContent, endOfInsertedContent) &&
983 !isStartOfParagraphDeprecated(startOfInsertedContent)); 1010 !isStartOfParagraphDeprecated(startOfInsertedContent));
984 1011
985 VisiblePosition destination = mergeForward 1012 VisiblePosition destination = mergeForward
986 ? nextPositionOf(endOfInsertedContent) 1013 ? nextPositionOf(endOfInsertedContent)
987 : endOfInsertedContent; 1014 : endOfInsertedContent;
988 VisiblePosition startOfParagraphToMove = 1015 VisiblePosition startOfParagraphToMove =
989 mergeForward ? startOfParagraphDeprecated(endOfInsertedContent) 1016 mergeForward ? startOfParagraphDeprecated(endOfInsertedContent)
990 : nextPositionOf(endOfInsertedContent); 1017 : nextPositionOf(endOfInsertedContent);
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
1128 Element* currentRoot = selection.rootEditableElement(); 1155 Element* currentRoot = selection.rootEditableElement();
1129 1156
1130 if ((selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph && 1157 if ((selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph &&
1131 !startIsInsideMailBlockquote) || 1158 !startIsInsideMailBlockquote) ||
1132 enclosingBlockOfVisibleStart == currentRoot || 1159 enclosingBlockOfVisibleStart == currentRoot ||
1133 isListItem(enclosingBlockOfVisibleStart) || selectionIsPlainText) { 1160 isListItem(enclosingBlockOfVisibleStart) || selectionIsPlainText) {
1134 m_preventNesting = false; 1161 m_preventNesting = false;
1135 } 1162 }
1136 1163
1137 if (selection.isRange()) { 1164 if (selection.isRange()) {
1138 // When the end of the selection being pasted into is at the end of a paragr aph, and that selection 1165 // When the end of the selection being pasted into is at the end of a
1139 // spans multiple blocks, not merging may leave an empty line. 1166 // paragraph, and that selection spans multiple blocks, not merging may
1140 // When the start of the selection being pasted into is at the start of a bl ock, not merging 1167 // leave an empty line.
1141 // will leave hanging block(s). 1168 // When the start of the selection being pasted into is at the start of a
1142 // Merge blocks if the start of the selection was in a Mail blockquote, sinc e we handle 1169 // block, not merging will leave hanging block(s).
1143 // that case specially to prevent nesting. 1170 // Merge blocks if the start of the selection was in a Mail blockquote,
1171 // since we handle that case specially to prevent nesting.
1144 bool mergeBlocksAfterDelete = startIsInsideMailBlockquote || 1172 bool mergeBlocksAfterDelete = startIsInsideMailBlockquote ||
1145 isEndOfParagraphDeprecated(visibleEnd) || 1173 isEndOfParagraphDeprecated(visibleEnd) ||
1146 isStartOfBlock(visibleStart); 1174 isStartOfBlock(visibleStart);
1147 // FIXME: We should only expand to include fully selected special elements i f we are copying a 1175 // FIXME: We should only expand to include fully selected special elements
1148 // selection and pasting it on top of itself. 1176 // if we are copying a selection and pasting it on top of itself.
1149 deleteSelection(editingState, false, mergeBlocksAfterDelete, false); 1177 deleteSelection(editingState, false, mergeBlocksAfterDelete, false);
1150 if (editingState->isAborted()) 1178 if (editingState->isAborted())
1151 return; 1179 return;
1152 if (fragment.hasInterchangeNewlineAtStart()) { 1180 if (fragment.hasInterchangeNewlineAtStart()) {
1153 VisiblePosition startAfterDelete = 1181 VisiblePosition startAfterDelete =
1154 endingSelection().visibleStartDeprecated(); 1182 endingSelection().visibleStartDeprecated();
1155 if (isEndOfParagraphDeprecated(startAfterDelete) && 1183 if (isEndOfParagraphDeprecated(startAfterDelete) &&
1156 !isStartOfParagraphDeprecated(startAfterDelete) && 1184 !isStartOfParagraphDeprecated(startAfterDelete) &&
1157 !isEndOfEditableOrNonEditableContent(startAfterDelete)) 1185 !isEndOfEditableOrNonEditableContent(startAfterDelete))
1158 setEndingSelection(nextPositionOf(startAfterDelete)); 1186 setEndingSelection(nextPositionOf(startAfterDelete));
1159 else 1187 else
1160 insertParagraphSeparator(editingState); 1188 insertParagraphSeparator(editingState);
1161 if (editingState->isAborted()) 1189 if (editingState->isAborted())
1162 return; 1190 return;
1163 } 1191 }
1164 } else { 1192 } else {
1165 DCHECK(selection.isCaret()); 1193 DCHECK(selection.isCaret());
1166 if (fragment.hasInterchangeNewlineAtStart()) { 1194 if (fragment.hasInterchangeNewlineAtStart()) {
1167 const VisiblePosition next = 1195 const VisiblePosition next =
1168 nextPositionOf(visibleStart, CannotCrossEditingBoundary); 1196 nextPositionOf(visibleStart, CannotCrossEditingBoundary);
1169 if (isEndOfParagraphDeprecated(visibleStart) && 1197 if (isEndOfParagraphDeprecated(visibleStart) &&
1170 !isStartOfParagraphDeprecated(visibleStart) && next.isNotNull()) 1198 !isStartOfParagraphDeprecated(visibleStart) && next.isNotNull())
1171 setEndingSelection(next); 1199 setEndingSelection(next);
1172 else 1200 else
1173 insertParagraphSeparator(editingState); 1201 insertParagraphSeparator(editingState);
1174 if (editingState->isAborted()) 1202 if (editingState->isAborted())
1175 return; 1203 return;
1176 } 1204 }
1177 // We split the current paragraph in two to avoid nesting the blocks from th e fragment inside the current block. 1205 // We split the current paragraph in two to avoid nesting the blocks from
1178 // For example paste <div>foo</div><div>bar</div><div>baz</div> into <div>x^ x</div>, where ^ is the caret. 1206 // the fragment inside the current block.
1179 // As long as the div styles are the same, visually you'd expect: <div>xbar </div><div>bar</div><div>bazx</div>, 1207 //
1180 // not <div>xbar<div>bar</div><div>bazx</div></div>. 1208 // For example, paste
1209 // <div>foo</div><div>bar</div><div>baz</div>
1210 // into
1211 // <div>x^x</div>
1212 // where ^ is the caret.
1213 //
1214 // As long as the div styles are the same, visually you'd expect:
1215 // <div>xbar</div><div>bar</div><div>bazx</div>
1216 // not
1217 // <div>xbar<div>bar</div><div>bazx</div></div>
1181 // Don't do this if the selection started in a Mail blockquote. 1218 // Don't do this if the selection started in a Mail blockquote.
1182 if (m_preventNesting && !startIsInsideMailBlockquote && 1219 if (m_preventNesting && !startIsInsideMailBlockquote &&
1183 !isEndOfParagraphDeprecated( 1220 !isEndOfParagraphDeprecated(
1184 endingSelection().visibleStartDeprecated()) && 1221 endingSelection().visibleStartDeprecated()) &&
1185 !isStartOfParagraphDeprecated( 1222 !isStartOfParagraphDeprecated(
1186 endingSelection().visibleStartDeprecated())) { 1223 endingSelection().visibleStartDeprecated())) {
1187 insertParagraphSeparator(editingState); 1224 insertParagraphSeparator(editingState);
1188 if (editingState->isAborted()) 1225 if (editingState->isAborted())
1189 return; 1226 return;
1190 setEndingSelection( 1227 setEndingSelection(
1191 previousPositionOf(endingSelection().visibleStartDeprecated())); 1228 previousPositionOf(endingSelection().visibleStartDeprecated()));
1192 } 1229 }
1193 } 1230 }
1194 1231
1195 Position insertionPos = endingSelection().start(); 1232 Position insertionPos = endingSelection().start();
1196 // We don't want any of the pasted content to end up nested in a Mail blockquo te, so first break 1233 // We don't want any of the pasted content to end up nested in a Mail
1197 // out of any surrounding Mail blockquotes. Unless we're inserting in a table, in which case 1234 // blockquote, so first break out of any surrounding Mail blockquotes. Unless
1198 // breaking the blockquote will prevent the content from actually being insert ed in the table. 1235 // we're inserting in a table, in which case breaking the blockquote will
1236 // prevent the content from actually being inserted in the table.
1199 if (enclosingNodeOfType(insertionPos, isMailHTMLBlockquoteElement, 1237 if (enclosingNodeOfType(insertionPos, isMailHTMLBlockquoteElement,
1200 CanCrossEditingBoundary) && 1238 CanCrossEditingBoundary) &&
1201 m_preventNesting && 1239 m_preventNesting &&
1202 !(enclosingNodeOfType(insertionPos, &isTableStructureNode))) { 1240 !(enclosingNodeOfType(insertionPos, &isTableStructureNode))) {
1203 applyCommandToComposite(BreakBlockquoteCommand::create(document()), 1241 applyCommandToComposite(BreakBlockquoteCommand::create(document()),
1204 editingState); 1242 editingState);
1205 if (editingState->isAborted()) 1243 if (editingState->isAborted())
1206 return; 1244 return;
1207 // This will leave a br between the split. 1245 // This will leave a br between the split.
1208 Node* br = endingSelection().start().anchorNode(); 1246 Node* br = endingSelection().start().anchorNode();
1209 DCHECK(isHTMLBRElement(br)) << br; 1247 DCHECK(isHTMLBRElement(br)) << br;
1210 // Insert content between the two blockquotes, but remove the br (since it w as just a placeholder). 1248 // Insert content between the two blockquotes, but remove the br (since it
1249 // was just a placeholder).
1211 insertionPos = Position::inParentBeforeNode(*br); 1250 insertionPos = Position::inParentBeforeNode(*br);
1212 removeNode(br, editingState); 1251 removeNode(br, editingState);
1213 if (editingState->isAborted()) 1252 if (editingState->isAborted())
1214 return; 1253 return;
1215 } 1254 }
1216 1255
1217 // Inserting content could cause whitespace to collapse, e.g. inserting <div>f oo</div> into hello^ world. 1256 // Inserting content could cause whitespace to collapse, e.g. inserting
1257 // <div>foo</div> into hello^ world.
1218 prepareWhitespaceAtPositionForSplit(insertionPos); 1258 prepareWhitespaceAtPositionForSplit(insertionPos);
1219 1259
1220 // If the downstream node has been removed there's no point in continuing. 1260 // If the downstream node has been removed there's no point in continuing.
1221 if (!mostForwardCaretPosition(insertionPos).anchorNode()) 1261 if (!mostForwardCaretPosition(insertionPos).anchorNode())
1222 return; 1262 return;
1223 1263
1224 // NOTE: This would be an incorrect usage of downstream() if downstream() were changed to mean the last position after 1264 // NOTE: This would be an incorrect usage of downstream() if downstream() were
1225 // p that maps to the same visible position as p (since in the case where a br is at the end of a block and collapsed 1265 // changed to mean the last position after p that maps to the same visible
1226 // away, there are positions after the br which map to the same visible positi on as [br, 0]). 1266 // position as p (since in the case where a br is at the end of a block and
1267 // collapsed away, there are positions after the br which map to the same
1268 // visible position as [br, 0]).
1227 HTMLBRElement* endBR = 1269 HTMLBRElement* endBR =
1228 isHTMLBRElement(*mostForwardCaretPosition(insertionPos).anchorNode()) 1270 isHTMLBRElement(*mostForwardCaretPosition(insertionPos).anchorNode())
1229 ? toHTMLBRElement(mostForwardCaretPosition(insertionPos).anchorNode()) 1271 ? toHTMLBRElement(mostForwardCaretPosition(insertionPos).anchorNode())
1230 : 0; 1272 : 0;
1231 VisiblePosition originalVisPosBeforeEndBR; 1273 VisiblePosition originalVisPosBeforeEndBR;
1232 if (endBR) 1274 if (endBR)
1233 originalVisPosBeforeEndBR = 1275 originalVisPosBeforeEndBR =
1234 previousPositionOf(VisiblePosition::beforeNode(endBR)); 1276 previousPositionOf(VisiblePosition::beforeNode(endBR));
1235 1277
1236 Element* enclosingBlockOfInsertionPos = 1278 Element* enclosingBlockOfInsertionPos =
(...skipping 16 matching lines...) Expand all
1253 insertionPos = 1295 insertionPos =
1254 Position::inParentBeforeNode(*enclosingBlockOfInsertionPos); 1296 Position::inParentBeforeNode(*enclosingBlockOfInsertionPos);
1255 } 1297 }
1256 1298
1257 // Paste at start or end of link goes outside of link. 1299 // Paste at start or end of link goes outside of link.
1258 insertionPos = 1300 insertionPos =
1259 positionAvoidingSpecialElementBoundary(insertionPos, editingState); 1301 positionAvoidingSpecialElementBoundary(insertionPos, editingState);
1260 if (editingState->isAborted()) 1302 if (editingState->isAborted())
1261 return; 1303 return;
1262 1304
1263 // FIXME: Can this wait until after the operation has been performed? There d oesn't seem to be 1305 // FIXME: Can this wait until after the operation has been performed? There
1264 // any work performed after this that queries or uses the typing style. 1306 // doesn't seem to be any work performed after this that queries or uses the
1307 // typing style.
1265 if (LocalFrame* frame = document().frame()) 1308 if (LocalFrame* frame = document().frame())
1266 frame->selection().clearTypingStyle(); 1309 frame->selection().clearTypingStyle();
1267 1310
1268 removeHeadContents(fragment); 1311 removeHeadContents(fragment);
1269 1312
1270 // We don't want the destination to end up inside nodes that weren't selected. To avoid that, we move the 1313 // We don't want the destination to end up inside nodes that weren't selected.
1271 // position forward without changing the visible position so we're still at th e same visible location, but 1314 // To avoid that, we move the position forward without changing the visible
1272 // outside of preceding tags. 1315 // position so we're still at the same visible location, but outside of
1316 // preceding tags.
1273 insertionPos = positionAvoidingPrecedingNodes(insertionPos); 1317 insertionPos = positionAvoidingPrecedingNodes(insertionPos);
1274 1318
1275 // Paste into run of tabs splits the tab span. 1319 // Paste into run of tabs splits the tab span.
1276 insertionPos = positionOutsideTabSpan(insertionPos); 1320 insertionPos = positionOutsideTabSpan(insertionPos);
1277 1321
1278 bool handledStyleSpans = 1322 bool handledStyleSpans =
1279 handleStyleSpansBeforeInsertion(fragment, insertionPos); 1323 handleStyleSpansBeforeInsertion(fragment, insertionPos);
1280 1324
1281 // We're finished if there is nothing to add. 1325 // We're finished if there is nothing to add.
1282 if (fragment.isEmpty() || !fragment.firstChild()) 1326 if (fragment.isEmpty() || !fragment.firstChild())
(...skipping 23 matching lines...) Expand all
1306 Node* splitStart = insertionPos.computeNodeAfterPosition(); 1350 Node* splitStart = insertionPos.computeNodeAfterPosition();
1307 if (!splitStart) 1351 if (!splitStart)
1308 splitStart = insertionPos.computeContainerNode(); 1352 splitStart = insertionPos.computeContainerNode();
1309 Node* nodeToSplitTo = 1353 Node* nodeToSplitTo =
1310 splitTreeToNode(splitStart, elementToSplitTo->parentNode()); 1354 splitTreeToNode(splitStart, elementToSplitTo->parentNode());
1311 insertionPos = Position::inParentBeforeNode(*nodeToSplitTo); 1355 insertionPos = Position::inParentBeforeNode(*nodeToSplitTo);
1312 } 1356 }
1313 } 1357 }
1314 } 1358 }
1315 1359
1316 // FIXME: When pasting rich content we're often prevented from heading down th e fast path by style spans. Try 1360 // FIXME: When pasting rich content we're often prevented from heading down
1317 // again here if they've been removed. 1361 // the fast path by style spans. Try again here if they've been removed.
1318 1362
1319 // 1) Insert the content. 1363 // 1) Insert the content.
1320 // 2) Remove redundant styles and style tags, this inner <b> for example: <b>f oo <b>bar</b> baz</b>. 1364 // 2) Remove redundant styles and style tags, this inner <b> for example:
1321 // 3) Merge the start of the added content with the content before the positio n being pasted into. 1365 // <b>foo <b>bar</b> baz</b>.
1322 // 4) Do one of the following: a) expand the last br if the fragment ends with one and it collapsed, 1366 // 3) Merge the start of the added content with the content before the
1323 // b) merge the last paragraph of the incoming fragment with the paragraph tha t contained the 1367 // position being pasted into.
1324 // end of the selection that was pasted into, or c) handle an interchange newl ine at the end of the 1368 // 4) Do one of the following:
1325 // incoming fragment. 1369 // a) expand the last br if the fragment ends with one and it collapsed,
1370 // b) merge the last paragraph of the incoming fragment with the paragraph
1371 // that contained the end of the selection that was pasted into, or
1372 // c) handle an interchange newline at the end of the incoming fragment.
1326 // 5) Add spaces for smart replace. 1373 // 5) Add spaces for smart replace.
1327 // 6) Select the replacement if requested, and match style if requested. 1374 // 6) Select the replacement if requested, and match style if requested.
1328 1375
1329 InsertedNodes insertedNodes; 1376 InsertedNodes insertedNodes;
1330 Node* refNode = fragment.firstChild(); 1377 Node* refNode = fragment.firstChild();
1331 DCHECK(refNode); 1378 DCHECK(refNode);
1332 Node* node = refNode->nextSibling(); 1379 Node* node = refNode->nextSibling();
1333 1380
1334 fragment.removeNode(refNode); 1381 fragment.removeNode(refNode);
1335 1382
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1381 handleStyleSpans(insertedNodes, editingState); 1428 handleStyleSpans(insertedNodes, editingState);
1382 if (editingState->isAborted()) 1429 if (editingState->isAborted())
1383 return; 1430 return;
1384 } 1431 }
1385 1432
1386 // Mutation events (bug 20161) may have already removed the inserted content 1433 // Mutation events (bug 20161) may have already removed the inserted content
1387 if (!insertedNodes.firstNodeInserted() || 1434 if (!insertedNodes.firstNodeInserted() ||
1388 !insertedNodes.firstNodeInserted()->isConnected()) 1435 !insertedNodes.firstNodeInserted()->isConnected())
1389 return; 1436 return;
1390 1437
1391 // Scripts specified in javascript protocol may remove |enclosingBlockOfInsert ionPos| 1438 // Scripts specified in javascript protocol may remove
1392 // during insertion, e.g. <iframe src="javascript:..."> 1439 // |enclosingBlockOfInsertionPos| during insertion, e.g. <iframe
1440 // src="javascript:...">
1393 if (enclosingBlockOfInsertionPos && 1441 if (enclosingBlockOfInsertionPos &&
1394 !enclosingBlockOfInsertionPos->isConnected()) 1442 !enclosingBlockOfInsertionPos->isConnected())
1395 enclosingBlockOfInsertionPos = nullptr; 1443 enclosingBlockOfInsertionPos = nullptr;
1396 1444
1397 VisiblePosition startOfInsertedContent = createVisiblePositionDeprecated( 1445 VisiblePosition startOfInsertedContent = createVisiblePositionDeprecated(
1398 firstPositionInOrBeforeNode(insertedNodes.firstNodeInserted())); 1446 firstPositionInOrBeforeNode(insertedNodes.firstNodeInserted()));
1399 1447
1400 // We inserted before the enclosingBlockOfInsertionPos to prevent nesting, and the content before the enclosingBlockOfInsertionPos wasn't in its own block and 1448 // We inserted before the enclosingBlockOfInsertionPos to prevent nesting, and
1401 // didn't have a br after it, so the inserted content ended up in the same par agraph. 1449 // the content before the enclosingBlockOfInsertionPos wasn't in its own block
1450 // and didn't have a br after it, so the inserted content ended up in the same
1451 // paragraph.
1402 if (!startOfInsertedContent.isNull() && enclosingBlockOfInsertionPos && 1452 if (!startOfInsertedContent.isNull() && enclosingBlockOfInsertionPos &&
1403 insertionPos.anchorNode() == enclosingBlockOfInsertionPos->parentNode() && 1453 insertionPos.anchorNode() == enclosingBlockOfInsertionPos->parentNode() &&
1404 (unsigned)insertionPos.computeEditingOffset() < 1454 (unsigned)insertionPos.computeEditingOffset() <
1405 enclosingBlockOfInsertionPos->nodeIndex() && 1455 enclosingBlockOfInsertionPos->nodeIndex() &&
1406 !isStartOfParagraphDeprecated(startOfInsertedContent)) { 1456 !isStartOfParagraphDeprecated(startOfInsertedContent)) {
1407 insertNodeAt(HTMLBRElement::create(document()), 1457 insertNodeAt(HTMLBRElement::create(document()),
1408 startOfInsertedContent.deepEquivalent(), editingState); 1458 startOfInsertedContent.deepEquivalent(), editingState);
1409 if (editingState->isAborted()) 1459 if (editingState->isAborted())
1410 return; 1460 return;
1411 } 1461 }
(...skipping 26 matching lines...) Expand all
1438 1488
1439 if (m_sanitizeFragment && insertedNodes.firstNodeInserted()) { 1489 if (m_sanitizeFragment && insertedNodes.firstNodeInserted()) {
1440 applyCommandToComposite(SimplifyMarkupCommand::create( 1490 applyCommandToComposite(SimplifyMarkupCommand::create(
1441 document(), insertedNodes.firstNodeInserted(), 1491 document(), insertedNodes.firstNodeInserted(),
1442 insertedNodes.pastLastLeaf()), 1492 insertedNodes.pastLastLeaf()),
1443 editingState); 1493 editingState);
1444 if (editingState->isAborted()) 1494 if (editingState->isAborted())
1445 return; 1495 return;
1446 } 1496 }
1447 1497
1448 // Setup m_startOfInsertedContent and m_endOfInsertedContent. This should be t he last two lines of code that access insertedNodes. 1498 // Setup m_startOfInsertedContent and m_endOfInsertedContent. This should be
1499 // the last two lines of code that access insertedNodes.
1449 m_startOfInsertedContent = 1500 m_startOfInsertedContent =
1450 firstPositionInOrBeforeNode(insertedNodes.firstNodeInserted()); 1501 firstPositionInOrBeforeNode(insertedNodes.firstNodeInserted());
1451 m_endOfInsertedContent = 1502 m_endOfInsertedContent =
1452 lastPositionInOrAfterNode(insertedNodes.lastLeafInserted()); 1503 lastPositionInOrAfterNode(insertedNodes.lastLeafInserted());
1453 1504
1454 // Determine whether or not we should merge the end of inserted content with w hat's after it before we do 1505 // Determine whether or not we should merge the end of inserted content with
1455 // the start merge so that the start merge doesn't effect our decision. 1506 // what's after it before we do the start merge so that the start merge
1507 // doesn't effect our decision.
1456 m_shouldMergeEnd = shouldMergeEnd(selectionEndWasEndOfParagraph); 1508 m_shouldMergeEnd = shouldMergeEnd(selectionEndWasEndOfParagraph);
1457 1509
1458 if (shouldMergeStart(selectionStartWasStartOfParagraph, 1510 if (shouldMergeStart(selectionStartWasStartOfParagraph,
1459 fragment.hasInterchangeNewlineAtStart(), 1511 fragment.hasInterchangeNewlineAtStart(),
1460 startIsInsideMailBlockquote)) { 1512 startIsInsideMailBlockquote)) {
1461 VisiblePosition startOfParagraphToMove = positionAtStartOfInsertedContent(); 1513 VisiblePosition startOfParagraphToMove = positionAtStartOfInsertedContent();
1462 VisiblePosition destination = previousPositionOf(startOfParagraphToMove); 1514 VisiblePosition destination = previousPositionOf(startOfParagraphToMove);
1463 // We need to handle the case where we need to merge the end 1515 // We need to handle the case where we need to merge the end
1464 // but our destination node is inside an inline that is the last in the bloc k. 1516 // but our destination node is inside an inline that is the last in the
1465 // We insert a placeholder before the newly inserted content to avoid being merged into the inline. 1517 // block.
1518 // We insert a placeholder before the newly inserted content to avoid being
1519 // merged into the inline.
1466 Node* destinationNode = destination.deepEquivalent().anchorNode(); 1520 Node* destinationNode = destination.deepEquivalent().anchorNode();
1467 if (m_shouldMergeEnd && 1521 if (m_shouldMergeEnd &&
1468 destinationNode != enclosingInline(destinationNode) && 1522 destinationNode != enclosingInline(destinationNode) &&
1469 enclosingInline(destinationNode)->nextSibling()) { 1523 enclosingInline(destinationNode)->nextSibling()) {
1470 insertNodeBefore(HTMLBRElement::create(document()), refNode, 1524 insertNodeBefore(HTMLBRElement::create(document()), refNode,
1471 editingState); 1525 editingState);
1472 if (editingState->isAborted()) 1526 if (editingState->isAborted())
1473 return; 1527 return;
1474 } 1528 }
1475 1529
1476 // Merging the the first paragraph of inserted content with the content that came 1530 // Merging the the first paragraph of inserted content with the content that
1477 // before the selection that was pasted into would also move content after 1531 // came before the selection that was pasted into would also move content
1478 // the selection that was pasted into if: only one paragraph was being paste d, 1532 // after the selection that was pasted into if: only one paragraph was being
1479 // and it was not wrapped in a block, the selection that was pasted into end ed 1533 // pasted, and it was not wrapped in a block, the selection that was pasted
1480 // at the end of a block and the next paragraph didn't start at the start of a block. 1534 // into ended at the end of a block and the next paragraph didn't start at
1481 // Insert a line break just after the inserted content to separate it from w hat 1535 // the start of a block.
1482 // comes after and prevent that from happening. 1536 // Insert a line break just after the inserted content to separate it from
1537 // what comes after and prevent that from happening.
1483 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent(); 1538 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent();
1484 if (startOfParagraphDeprecated(endOfInsertedContent).deepEquivalent() == 1539 if (startOfParagraphDeprecated(endOfInsertedContent).deepEquivalent() ==
1485 startOfParagraphToMove.deepEquivalent()) { 1540 startOfParagraphToMove.deepEquivalent()) {
1486 insertNodeAt(HTMLBRElement::create(document()), 1541 insertNodeAt(HTMLBRElement::create(document()),
1487 endOfInsertedContent.deepEquivalent(), editingState); 1542 endOfInsertedContent.deepEquivalent(), editingState);
1488 if (editingState->isAborted()) 1543 if (editingState->isAborted())
1489 return; 1544 return;
1490 // Mutation events (bug 22634) triggered by inserting the <br> might have removed the content we're about to move 1545 // Mutation events (bug 22634) triggered by inserting the <br> might have
1546 // removed the content we're about to move
1491 if (!startOfParagraphToMove.deepEquivalent().isConnected()) 1547 if (!startOfParagraphToMove.deepEquivalent().isConnected())
1492 return; 1548 return;
1493 } 1549 }
1494 1550
1495 // FIXME: Maintain positions for the start and end of inserted content inste ad of keeping nodes. The nodes are 1551 // FIXME: Maintain positions for the start and end of inserted content
1496 // only ever used to create positions where inserted content starts/ends. 1552 // instead of keeping nodes. The nodes are only ever used to create
1553 // positions where inserted content starts/ends.
1497 moveParagraph(startOfParagraphToMove, 1554 moveParagraph(startOfParagraphToMove,
1498 endOfParagraphDeprecated(startOfParagraphToMove), destination, 1555 endOfParagraphDeprecated(startOfParagraphToMove), destination,
1499 editingState); 1556 editingState);
1500 if (editingState->isAborted()) 1557 if (editingState->isAborted())
1501 return; 1558 return;
1502 m_startOfInsertedContent = mostForwardCaretPosition( 1559 m_startOfInsertedContent = mostForwardCaretPosition(
1503 endingSelection().visibleStartDeprecated().deepEquivalent()); 1560 endingSelection().visibleStartDeprecated().deepEquivalent());
1504 if (m_endOfInsertedContent.isOrphan()) 1561 if (m_endOfInsertedContent.isOrphan())
1505 m_endOfInsertedContent = mostBackwardCaretPosition( 1562 m_endOfInsertedContent = mostBackwardCaretPosition(
1506 endingSelection().visibleEndDeprecated().deepEquivalent()); 1563 endingSelection().visibleEndDeprecated().deepEquivalent());
(...skipping 24 matching lines...) Expand all
1531 setEndingSelection(endOfInsertedContent); 1588 setEndingSelection(endOfInsertedContent);
1532 Element* enclosingBlockElement = 1589 Element* enclosingBlockElement =
1533 enclosingBlock(endOfInsertedContent.deepEquivalent().anchorNode()); 1590 enclosingBlock(endOfInsertedContent.deepEquivalent().anchorNode());
1534 if (isListItem(enclosingBlockElement)) { 1591 if (isListItem(enclosingBlockElement)) {
1535 HTMLLIElement* newListItem = HTMLLIElement::create(document()); 1592 HTMLLIElement* newListItem = HTMLLIElement::create(document());
1536 insertNodeAfter(newListItem, enclosingBlockElement, editingState); 1593 insertNodeAfter(newListItem, enclosingBlockElement, editingState);
1537 if (editingState->isAborted()) 1594 if (editingState->isAborted())
1538 return; 1595 return;
1539 setEndingSelection(VisiblePosition::firstPositionInNode(newListItem)); 1596 setEndingSelection(VisiblePosition::firstPositionInNode(newListItem));
1540 } else { 1597 } else {
1541 // Use a default paragraph element (a plain div) for the empty paragra ph, using the last paragraph 1598 // Use a default paragraph element (a plain div) for the empty
1542 // block's style seems to annoy users. 1599 // paragraph, using the last paragraph block's style seems to annoy
1600 // users.
1543 insertParagraphSeparator( 1601 insertParagraphSeparator(
1544 editingState, true, 1602 editingState, true,
1545 !startIsInsideMailBlockquote && 1603 !startIsInsideMailBlockquote &&
1546 highestEnclosingNodeOfType( 1604 highestEnclosingNodeOfType(
1547 endOfInsertedContent.deepEquivalent(), 1605 endOfInsertedContent.deepEquivalent(),
1548 isMailHTMLBlockquoteElement, CannotCrossEditingBoundary, 1606 isMailHTMLBlockquoteElement, CannotCrossEditingBoundary,
1549 insertedNodes.firstNodeInserted()->parentNode())); 1607 insertedNodes.firstNodeInserted()->parentNode()));
1550 if (editingState->isAborted()) 1608 if (editingState->isAborted())
1551 return; 1609 return;
1552 } 1610 }
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1596 // Don't remove the br if nothing was inserted. 1654 // Don't remove the br if nothing was inserted.
1597 if (previousPositionOf(visiblePos).deepEquivalent() == 1655 if (previousPositionOf(visiblePos).deepEquivalent() ==
1598 originalVisPosBeforeEndBR.deepEquivalent()) 1656 originalVisPosBeforeEndBR.deepEquivalent())
1599 return false; 1657 return false;
1600 1658
1601 // Remove the br if it is collapsed away and so is unnecessary. 1659 // Remove the br if it is collapsed away and so is unnecessary.
1602 if (!document().inNoQuirksMode() && isEndOfBlock(visiblePos) && 1660 if (!document().inNoQuirksMode() && isEndOfBlock(visiblePos) &&
1603 !isStartOfParagraphDeprecated(visiblePos)) 1661 !isStartOfParagraphDeprecated(visiblePos))
1604 return true; 1662 return true;
1605 1663
1606 // A br that was originally holding a line open should be displaced by inserte d content or turned into a line break. 1664 // A br that was originally holding a line open should be displaced by
1607 // A br that was originally acting as a line break should still be acting as a line break, not as a placeholder. 1665 // inserted content or turned into a line break.
1666 // A br that was originally acting as a line break should still be acting as a
1667 // line break, not as a placeholder.
1608 return isStartOfParagraphDeprecated(visiblePos) && 1668 return isStartOfParagraphDeprecated(visiblePos) &&
1609 isEndOfParagraphDeprecated(visiblePos); 1669 isEndOfParagraphDeprecated(visiblePos);
1610 } 1670 }
1611 1671
1612 bool ReplaceSelectionCommand::shouldPerformSmartReplace() const { 1672 bool ReplaceSelectionCommand::shouldPerformSmartReplace() const {
1613 if (!m_smartReplace) 1673 if (!m_smartReplace)
1614 return false; 1674 return false;
1615 1675
1616 HTMLTextFormControlElement* textControl = enclosingTextFormControl( 1676 HTMLTextFormControlElement* textControl = enclosingTextFormControl(
1617 positionAtStartOfInsertedContent().deepEquivalent()); 1677 positionAtStartOfInsertedContent().deepEquivalent());
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
1692 if (startNode->isTextNode()) { 1752 if (startNode->isTextNode()) {
1693 insertTextIntoNode(toText(startNode), startOffset, 1753 insertTextIntoNode(toText(startNode), startOffset,
1694 collapseWhiteSpace ? nonBreakingSpaceString() : " "); 1754 collapseWhiteSpace ? nonBreakingSpaceString() : " ");
1695 if (m_endOfInsertedContent.computeContainerNode() == startNode && 1755 if (m_endOfInsertedContent.computeContainerNode() == startNode &&
1696 m_endOfInsertedContent.offsetInContainerNode()) 1756 m_endOfInsertedContent.offsetInContainerNode())
1697 m_endOfInsertedContent = Position( 1757 m_endOfInsertedContent = Position(
1698 startNode, m_endOfInsertedContent.offsetInContainerNode() + 1); 1758 startNode, m_endOfInsertedContent.offsetInContainerNode() + 1);
1699 } else { 1759 } else {
1700 Text* node = document().createEditingTextNode( 1760 Text* node = document().createEditingTextNode(
1701 collapseWhiteSpace ? nonBreakingSpaceString() : " "); 1761 collapseWhiteSpace ? nonBreakingSpaceString() : " ");
1702 // Don't updateNodesInserted. Doing so would set m_endOfInsertedContent to be the node containing the leading space, 1762 // Don't updateNodesInserted. Doing so would set m_endOfInsertedContent to
1703 // but m_endOfInsertedContent is supposed to mark the end of pasted conten t. 1763 // be the node containing the leading space, but m_endOfInsertedContent is
1764 // supposed to mark the end of pasted content.
1704 insertNodeBefore(node, startNode, editingState); 1765 insertNodeBefore(node, startNode, editingState);
1705 if (editingState->isAborted()) 1766 if (editingState->isAborted())
1706 return; 1767 return;
1707 m_startOfInsertedContent = Position::firstPositionInNode(node); 1768 m_startOfInsertedContent = Position::firstPositionInNode(node);
1708 } 1769 }
1709 } 1770 }
1710 } 1771 }
1711 1772
1712 void ReplaceSelectionCommand::completeHTMLReplacement( 1773 void ReplaceSelectionCommand::completeHTMLReplacement(
1713 const Position& lastPositionToSelect, 1774 const Position& lastPositionToSelect,
1714 EditingState* editingState) { 1775 EditingState* editingState) {
1715 Position start = positionAtStartOfInsertedContent().deepEquivalent(); 1776 Position start = positionAtStartOfInsertedContent().deepEquivalent();
1716 Position end = positionAtEndOfInsertedContent().deepEquivalent(); 1777 Position end = positionAtEndOfInsertedContent().deepEquivalent();
1717 1778
1718 // Mutation events may have deleted start or end 1779 // Mutation events may have deleted start or end
1719 if (start.isNotNull() && !start.isOrphan() && end.isNotNull() && 1780 if (start.isNotNull() && !start.isOrphan() && end.isNotNull() &&
1720 !end.isOrphan()) { 1781 !end.isOrphan()) {
1721 // FIXME (11475): Remove this and require that the creator of the fragment t o use nbsps. 1782 // FIXME (11475): Remove this and require that the creator of the fragment
1783 // to use nbsps.
1722 rebalanceWhitespaceAt(start); 1784 rebalanceWhitespaceAt(start);
1723 rebalanceWhitespaceAt(end); 1785 rebalanceWhitespaceAt(end);
1724 1786
1725 if (m_matchStyle) { 1787 if (m_matchStyle) {
1726 DCHECK(m_insertionStyle); 1788 DCHECK(m_insertionStyle);
1727 applyStyle(m_insertionStyle.get(), start, end, editingState); 1789 applyStyle(m_insertionStyle.get(), start, end, editingState);
1728 if (editingState->isAborted()) 1790 if (editingState->isAborted())
1729 return; 1791 return;
1730 } 1792 }
1731 1793
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
1834 else 1896 else
1835 updatePositionForNodeRemoval(positionOnlyToBeUpdated, *next); 1897 updatePositionForNodeRemoval(positionOnlyToBeUpdated, *next);
1836 1898
1837 removeNode(next, editingState); 1899 removeNode(next, editingState);
1838 if (editingState->isAborted()) 1900 if (editingState->isAborted())
1839 return; 1901 return;
1840 } 1902 }
1841 } 1903 }
1842 1904
1843 InputEvent::InputType ReplaceSelectionCommand::inputType() const { 1905 InputEvent::InputType ReplaceSelectionCommand::inputType() const {
1844 // |ReplaceSelectionCommand| could be used with Paste, Drag&Drop, InsertFragme nt and |TypingCommand|. 1906 // |ReplaceSelectionCommand| could be used with Paste, Drag&Drop,
1907 // InsertFragment and |TypingCommand|.
1845 // 1. Paste, Drag&Drop, InsertFragment should rely on correct |m_inputType|. 1908 // 1. Paste, Drag&Drop, InsertFragment should rely on correct |m_inputType|.
1846 // 2. |TypingCommand| will supply the |inputType()|, so |m_inputType| could de fault to |InputType::None|. 1909 // 2. |TypingCommand| will supply the |inputType()|, so |m_inputType| could
1910 // default to |InputType::None|.
1847 return m_inputType; 1911 return m_inputType;
1848 } 1912 }
1849 1913
1850 // If the user is inserting a list into an existing list, instead of nesting the list, 1914 // If the user is inserting a list into an existing list, instead of nesting the
1851 // we put the list items into the existing list. 1915 // list, we put the list items into the existing list.
1852 Node* ReplaceSelectionCommand::insertAsListItems(HTMLElement* listElement, 1916 Node* ReplaceSelectionCommand::insertAsListItems(HTMLElement* listElement,
1853 Element* insertionBlock, 1917 Element* insertionBlock,
1854 const Position& insertPos, 1918 const Position& insertPos,
1855 InsertedNodes& insertedNodes, 1919 InsertedNodes& insertedNodes,
1856 EditingState* editingState) { 1920 EditingState* editingState) {
1857 while (listElement->hasOneChild() && 1921 while (listElement->hasOneChild() &&
1858 isHTMLListElement(listElement->firstChild())) 1922 isHTMLListElement(listElement->firstChild()))
1859 listElement = toHTMLElement(listElement->firstChild()); 1923 listElement = toHTMLElement(listElement->firstChild());
1860 1924
1861 bool isStart = 1925 bool isStart =
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1902 if (!node) 1966 if (!node)
1903 return; 1967 return;
1904 1968
1905 if (m_startOfInsertedContent.isNull()) 1969 if (m_startOfInsertedContent.isNull())
1906 m_startOfInsertedContent = firstPositionInOrBeforeNode(node); 1970 m_startOfInsertedContent = firstPositionInOrBeforeNode(node);
1907 1971
1908 m_endOfInsertedContent = 1972 m_endOfInsertedContent =
1909 lastPositionInOrAfterNode(&NodeTraversal::lastWithinOrSelf(*node)); 1973 lastPositionInOrAfterNode(&NodeTraversal::lastWithinOrSelf(*node));
1910 } 1974 }
1911 1975
1912 // During simple pastes, where we're just pasting a text node into a run of text , we insert the text node 1976 // During simple pastes, where we're just pasting a text node into a run of
1913 // directly into the text node that holds the selection. This is much faster th an the generalized code in 1977 // text, we insert the text node directly into the text node that holds the
1914 // ReplaceSelectionCommand, and works around <https://bugs.webkit.org/show_bug.c gi?id=6148> since we don't 1978 // selection. This is much faster than the generalized code in
1915 // split text nodes. 1979 // ReplaceSelectionCommand, and works around
1980 // <https://bugs.webkit.org/show_bug.cgi?id=6148> since we don't split text
1981 // nodes.
1916 bool ReplaceSelectionCommand::performTrivialReplace( 1982 bool ReplaceSelectionCommand::performTrivialReplace(
1917 const ReplacementFragment& fragment, 1983 const ReplacementFragment& fragment,
1918 EditingState* editingState) { 1984 EditingState* editingState) {
1919 if (!fragment.firstChild() || fragment.firstChild() != fragment.lastChild() || 1985 if (!fragment.firstChild() || fragment.firstChild() != fragment.lastChild() ||
1920 !fragment.firstChild()->isTextNode()) 1986 !fragment.firstChild()->isTextNode())
1921 return false; 1987 return false;
1922 1988
1923 // FIXME: Would be nice to handle smart replace in the fast path. 1989 // FIXME: Would be nice to handle smart replace in the fast path.
1924 if (m_smartReplace || fragment.hasInterchangeNewlineAtStart() || 1990 if (m_smartReplace || fragment.hasInterchangeNewlineAtStart() ||
1925 fragment.hasInterchangeNewlineAtEnd()) 1991 fragment.hasInterchangeNewlineAtEnd())
1926 return false; 1992 return false;
1927 1993
1928 // e.g. when "bar" is inserted after "foo" in <div><u>foo</u></div>, "bar" sho uld not be underlined. 1994 // e.g. when "bar" is inserted after "foo" in <div><u>foo</u></div>, "bar"
1995 // should not be underlined.
1929 if (elementToSplitToAvoidPastingIntoInlineElementsWithStyle( 1996 if (elementToSplitToAvoidPastingIntoInlineElementsWithStyle(
1930 endingSelection().start())) 1997 endingSelection().start()))
1931 return false; 1998 return false;
1932 1999
1933 Node* nodeAfterInsertionPos = 2000 Node* nodeAfterInsertionPos =
1934 mostForwardCaretPosition(endingSelection().end()).anchorNode(); 2001 mostForwardCaretPosition(endingSelection().end()).anchorNode();
1935 Text* textNode = toText(fragment.firstChild()); 2002 Text* textNode = toText(fragment.firstChild());
1936 // Our fragment creation code handles tabs, spaces, and newlines, so we don't have to worry about those here. 2003 // Our fragment creation code handles tabs, spaces, and newlines, so we don't
2004 // have to worry about those here.
1937 2005
1938 Position start = endingSelection().start(); 2006 Position start = endingSelection().start();
1939 Position end = replaceSelectedTextInNode(textNode->data()); 2007 Position end = replaceSelectedTextInNode(textNode->data());
1940 if (end.isNull()) 2008 if (end.isNull())
1941 return false; 2009 return false;
1942 2010
1943 if (nodeAfterInsertionPos && nodeAfterInsertionPos->parentNode() && 2011 if (nodeAfterInsertionPos && nodeAfterInsertionPos->parentNode() &&
1944 isHTMLBRElement(*nodeAfterInsertionPos) && 2012 isHTMLBRElement(*nodeAfterInsertionPos) &&
1945 shouldRemoveEndBR(toHTMLBRElement(nodeAfterInsertionPos), 2013 shouldRemoveEndBR(toHTMLBRElement(nodeAfterInsertionPos),
1946 VisiblePosition::beforeNode(nodeAfterInsertionPos))) { 2014 VisiblePosition::beforeNode(nodeAfterInsertionPos))) {
(...skipping 25 matching lines...) Expand all
1972 visitor->trace(m_startOfInsertedContent); 2040 visitor->trace(m_startOfInsertedContent);
1973 visitor->trace(m_endOfInsertedContent); 2041 visitor->trace(m_endOfInsertedContent);
1974 visitor->trace(m_insertionStyle); 2042 visitor->trace(m_insertionStyle);
1975 visitor->trace(m_documentFragment); 2043 visitor->trace(m_documentFragment);
1976 visitor->trace(m_startOfInsertedRange); 2044 visitor->trace(m_startOfInsertedRange);
1977 visitor->trace(m_endOfInsertedRange); 2045 visitor->trace(m_endOfInsertedRange);
1978 CompositeEditCommand::trace(visitor); 2046 CompositeEditCommand::trace(visitor);
1979 } 2047 }
1980 2048
1981 } // namespace blink 2049 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698