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

Side by Side Diff: Source/core/editing/ReplaceSelectionCommand.cpp

Issue 24278008: [oilpan] Handlify Nodes in htmlediting (Closed) Base URL: svn://svn.chromium.org/blink/branches/oilpan
Patch Set: Created 7 years, 3 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 | Annotate | Revision Log
« no previous file with comments | « Source/core/editing/ModifySelectionListLevel.cpp ('k') | Source/core/editing/TextIterator.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 static bool isInterchangeConvertedSpaceSpan(const Node *node) 109 static bool isInterchangeConvertedSpaceSpan(const Node *node)
110 { 110 {
111 DEFINE_STATIC_LOCAL(String, convertedSpaceSpanClassString, (AppleConvertedSp ace)); 111 DEFINE_STATIC_LOCAL(String, convertedSpaceSpanClassString, (AppleConvertedSp ace));
112 return node->isHTMLElement() && 112 return node->isHTMLElement() &&
113 static_cast<const HTMLElement *>(node)->getAttribute(classAttr) == co nvertedSpaceSpanClassString; 113 static_cast<const HTMLElement *>(node)->getAttribute(classAttr) == co nvertedSpaceSpanClassString;
114 } 114 }
115 115
116 static Position positionAvoidingPrecedingNodes(Position pos) 116 static Position positionAvoidingPrecedingNodes(Position pos)
117 { 117 {
118 // If we're already on a break, it's probably a placeholder and we shouldn't change our position. 118 // If we're already on a break, it's probably a placeholder and we shouldn't change our position.
119 if (editingIgnoresContent(pos.deprecatedNode().handle().raw())) 119 if (editingIgnoresContent(pos.deprecatedNode()))
120 return pos; 120 return pos;
121 121
122 // We also stop when changing block flow elements because even though the vi sual position is the 122 // We also stop when changing block flow elements because even though the vi sual position is the
123 // same. E.g., 123 // same. E.g.,
124 // <div>foo^</div>^ 124 // <div>foo^</div>^
125 // The two positions above are the same visual position, but we want to stay in the same block. 125 // The two positions above are the same visual position, but we want to stay in the same block.
126 Handle<Node> enclosingBlockNode = enclosingBlock(pos.containerNode().handle( ).raw()); 126 Handle<Node> enclosingBlockNode = enclosingBlock(pos.containerNode());
127 for (Position nextPosition = pos; nextPosition.containerNode() != enclosingB lockNode; pos = nextPosition) { 127 for (Position nextPosition = pos; nextPosition.containerNode() != enclosingB lockNode; pos = nextPosition) {
128 HandleScope scope; 128 HandleScope scope;
129 if (lineBreakExistsAtPosition(pos)) 129 if (lineBreakExistsAtPosition(pos))
130 break; 130 break;
131 131
132 if (pos.containerNode()->nonShadowBoundaryParentNode()) 132 if (pos.containerNode()->nonShadowBoundaryParentNode())
133 nextPosition = positionInParentAfterNode(pos.containerNode()); 133 nextPosition = positionInParentAfterNode(pos.containerNode());
134 134
135 if (nextPosition == pos 135 if (nextPosition == pos
136 || enclosingBlock(nextPosition.containerNode().handle().raw()) != en closingBlockNode 136 || enclosingBlock(nextPosition.containerNode()) != enclosingBlockNod e
137 || VisiblePosition(pos) != VisiblePosition(nextPosition)) 137 || VisiblePosition(pos) != VisiblePosition(nextPosition))
138 break; 138 break;
139 } 139 }
140 return pos; 140 return pos;
141 } 141 }
142 142
143 ReplacementFragment::ReplacementFragment(const Handle<Document>& document, Docum entFragment* fragment, bool, const VisibleSelection& selection) 143 ReplacementFragment::ReplacementFragment(const Handle<Document>& document, Docum entFragment* fragment, bool, const VisibleSelection& selection)
144 : m_document(document), 144 : m_document(document),
145 m_fragment(fragment), 145 m_fragment(fragment),
146 m_hasInterchangeNewlineAtStart(false), 146 m_hasInterchangeNewlineAtStart(false),
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 274
275 removeNode(holder.raw()); 275 removeNode(holder.raw());
276 } 276 }
277 277
278 void ReplacementFragment::removeUnrenderedNodes(Node* holder) 278 void ReplacementFragment::removeUnrenderedNodes(Node* holder)
279 { 279 {
280 Vector<RefPtr<Node> > unrendered; 280 Vector<RefPtr<Node> > unrendered;
281 281
282 for (Handle<Node> node = holder->firstChild(); node; node = NodeTraversal::n ext(node, adoptRawResult(holder))) { 282 for (Handle<Node> node = holder->firstChild(); node; node = NodeTraversal::n ext(node, adoptRawResult(holder))) {
283 HandleScope scope; 283 HandleScope scope;
284 if (!isNodeRendered(node.raw()) && !isTableStructureNode(node.raw())) 284 if (!isNodeRendered(node) && !isTableStructureNode(node))
285 unrendered.append(node.raw()); 285 unrendered.append(node.raw());
286 } 286 }
287 287
288 size_t n = unrendered.size(); 288 size_t n = unrendered.size();
289 for (size_t i = 0; i < n; ++i) { 289 for (size_t i = 0; i < n; ++i) {
290 HandleScope scope; 290 HandleScope scope;
291 removeNode(unrendered[i]); 291 removeNode(unrendered[i]);
292 } 292 }
293 } 293 }
294 294
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
425 VisiblePosition next = endOfInsertedContent.next(CannotCrossEditingBoundary) ; 425 VisiblePosition next = endOfInsertedContent.next(CannotCrossEditingBoundary) ;
426 if (next.isNull()) 426 if (next.isNull())
427 return false; 427 return false;
428 428
429 return !selectionEndWasEndOfParagraph 429 return !selectionEndWasEndOfParagraph
430 && isEndOfParagraph(endOfInsertedContent) 430 && isEndOfParagraph(endOfInsertedContent)
431 && !endOfInsertedContent.deepEquivalent().deprecatedNode()->hasTagName(b rTag) 431 && !endOfInsertedContent.deepEquivalent().deprecatedNode()->hasTagName(b rTag)
432 && shouldMerge(endOfInsertedContent, next); 432 && shouldMerge(endOfInsertedContent, next);
433 } 433 }
434 434
435 static bool isMailPasteAsQuotationNode(const Node* node) 435 static bool isMailPasteAsQuotationNode(const Handle<const Node>& node)
436 { 436 {
437 return node && node->hasTagName(blockquoteTag) && node->isElementNode() && t oElement(node)->getAttribute(classAttr) == ApplePasteAsQuotation; 437 return node && node->hasTagName(blockquoteTag) && node->isElementNode() && t oConstElement(node)->getAttribute(classAttr) == ApplePasteAsQuotation;
438 } 438 }
439 439
440 static bool isHeaderElement(const Node* a) 440 static bool isHeaderElement(const Handle<const Node>& a)
441 { 441 {
442 if (!a) 442 if (!a)
443 return false; 443 return false;
444 444
445 return a->hasTagName(h1Tag) 445 return a->hasTagName(h1Tag)
446 || a->hasTagName(h2Tag) 446 || a->hasTagName(h2Tag)
447 || a->hasTagName(h3Tag) 447 || a->hasTagName(h3Tag)
448 || a->hasTagName(h4Tag) 448 || a->hasTagName(h4Tag)
449 || a->hasTagName(h5Tag) 449 || a->hasTagName(h5Tag)
450 || a->hasTagName(h6Tag); 450 || a->hasTagName(h6Tag);
451 } 451 }
452 452
453 static bool haveSameTagName(Node* a, Node* b) 453 static bool haveSameTagName(Node* a, Node* b)
454 { 454 {
455 return a && b && a->isElementNode() && b->isElementNode() && toElement(a)->t agName() == toElement(b)->tagName(); 455 return a && b && a->isElementNode() && b->isElementNode() && toElement(a)->t agName() == toElement(b)->tagName();
456 } 456 }
457 457
458 bool ReplaceSelectionCommand::shouldMerge(const VisiblePosition& source, const V isiblePosition& destination) 458 bool ReplaceSelectionCommand::shouldMerge(const VisiblePosition& source, const V isiblePosition& destination)
459 { 459 {
460 if (source.isNull() || destination.isNull()) 460 if (source.isNull() || destination.isNull())
461 return false; 461 return false;
462 462
463 Handle<Node> sourceNode = source.deepEquivalent().deprecatedNode(); 463 Handle<Node> sourceNode = source.deepEquivalent().deprecatedNode();
464 Handle<Node> destinationNode = destination.deepEquivalent().deprecatedNode() ; 464 Handle<Node> destinationNode = destination.deepEquivalent().deprecatedNode() ;
465 Handle<Node> sourceBlock = enclosingBlock(sourceNode.raw()); 465 Handle<Node> sourceBlock = enclosingBlock(sourceNode);
466 Handle<Node> destinationBlock = enclosingBlock(destinationNode.raw()); 466 Handle<Node> destinationBlock = enclosingBlock(destinationNode);
467 return !enclosingNodeOfType(source.deepEquivalent(), &isMailPasteAsQuotation Node) 467 return !enclosingNodeOfType(source.deepEquivalent(), &isMailPasteAsQuotation Node)
468 && sourceBlock && (!sourceBlock->hasTagName(blockquoteTag) || isMailBloc kquote(sourceBlock.raw())) 468 && sourceBlock && (!sourceBlock->hasTagName(blockquoteTag) || isMailBloc kquote(sourceBlock))
469 && enclosingListChild(sourceBlock.raw()) == enclosingListChild(destinati onNode.raw()) 469 && enclosingListChild(sourceBlock) == enclosingListChild(destinationNode )
470 && enclosingTableCell(source.deepEquivalent()) == enclosingTableCell(des tination.deepEquivalent()) 470 && enclosingTableCell(source.deepEquivalent()) == enclosingTableCell(des tination.deepEquivalent())
471 && (!isHeaderElement(sourceBlock.raw()) || haveSameTagName(sourceBlock.r aw(), destinationBlock.raw())) 471 && (!isHeaderElement(sourceBlock) || haveSameTagName(sourceBlock.raw(), destinationBlock.raw()))
472 // Don't merge to or from a position before or after a block because it would 472 // Don't merge to or from a position before or after a block because it would
473 // be a no-op and cause infinite recursion. 473 // be a no-op and cause infinite recursion.
474 && !isBlock(sourceNode.raw()) && !isBlock(destinationNode.raw()); 474 && !isBlock(sourceNode) && !isBlock(destinationNode);
475 } 475 }
476 476
477 // Style rules that match just inserted elements could change their appearance, like 477 // Style rules that match just inserted elements could change their appearance, like
478 // a div inserted into a document with div { display:inline; }. 478 // a div inserted into a document with div { display:inline; }.
479 void ReplaceSelectionCommand::removeRedundantStylesAndKeepStyleSpanInline(Insert edNodes& insertedNodes) 479 void ReplaceSelectionCommand::removeRedundantStylesAndKeepStyleSpanInline(Insert edNodes& insertedNodes)
480 { 480 {
481 Handle<Node> pastEndNode = adoptRawResult(insertedNodes.pastLastLeaf()); 481 Handle<Node> pastEndNode = adoptRawResult(insertedNodes.pastLastLeaf());
482 Handle<Node> next; 482 Handle<Node> next;
483 for (Handle<Node> node = adoptRawResult(insertedNodes.firstNodeInserted()); node && node != pastEndNode; node = next) { 483 for (Handle<Node> node = adoptRawResult(insertedNodes.firstNodeInserted()); node && node != pastEndNode; node = next) {
484 // FIXME: <rdar://problem/5371536> Style rules that match pasted content can change it's appearance 484 // FIXME: <rdar://problem/5371536> Style rules that match pasted content can change it's appearance
(...skipping 21 matching lines...) Expand all
506 // e.g. <font size="3" style="font-size: 20px;"> is converte d to <font style="font-size: 20px;"> 506 // e.g. <font size="3" style="font-size: 20px;"> is converte d to <font style="font-size: 20px;">
507 for (size_t i = 0; i < attributes.size(); i++) 507 for (size_t i = 0; i < attributes.size(); i++)
508 removeNodeAttribute(element, attributes[i]); 508 removeNodeAttribute(element, attributes[i]);
509 } 509 }
510 } 510 }
511 511
512 Handle<ContainerNode> context = element->parentNode(); 512 Handle<ContainerNode> context = element->parentNode();
513 513
514 // If Mail wraps the fragment with a Paste as Quotation blockquote, or if you're pasting into a quoted region, 514 // If Mail wraps the fragment with a Paste as Quotation blockquote, or if you're pasting into a quoted region,
515 // styles from blockquoteNode are allowed to override those from the source document, see <rdar://problem/4930986> and <rdar://problem/5089327>. 515 // styles from blockquoteNode are allowed to override those from the source document, see <rdar://problem/4930986> and <rdar://problem/5089327>.
516 Node* blockquoteNode = isMailPasteAsQuotationNode(context.raw()) ? c ontext.raw() : enclosingNodeOfType(firstPositionInNode(context), isMailBlockquot e, CanCrossEditingBoundary); 516 Handle<Node> blockquoteNode = isMailPasteAsQuotationNode(context) ? Handle<Node>(context) : Handle<Node>(enclosingNodeOfType(firstPositionInNode(con text), isMailBlockquote, CanCrossEditingBoundary));
517 if (blockquoteNode) 517 if (blockquoteNode)
518 newInlineStyle->removeStyleFromRulesAndContext(element, document ()->documentElement()); 518 newInlineStyle->removeStyleFromRulesAndContext(element, document ()->documentElement());
519 519
520 newInlineStyle->removeStyleFromRulesAndContext(element, context); 520 newInlineStyle->removeStyleFromRulesAndContext(element, context);
521 } 521 }
522 522
523 if (!inlineStyle || newInlineStyle->isEmpty()) { 523 if (!inlineStyle || newInlineStyle->isEmpty()) {
524 if (isStyleSpanOrSpanWithOnlyStyleAttribute(element) || isEmptyFontT ag(element, AllowNonEmptyStyleAttribute)) { 524 if (isStyleSpanOrSpanWithOnlyStyleAttribute(element) || isEmptyFontT ag(element, AllowNonEmptyStyleAttribute)) {
525 insertedNodes.willRemoveNodePreservingChildren(element.raw()); 525 insertedNodes.willRemoveNodePreservingChildren(element.raw());
526 removeNodePreservingChildren(element); 526 removeNodePreservingChildren(element);
527 continue; 527 continue;
528 } 528 }
529 removeNodeAttribute(element, styleAttr); 529 removeNodeAttribute(element, styleAttr);
530 } else if (newInlineStyle->style()->propertyCount() != inlineStyle->prop ertyCount()) 530 } else if (newInlineStyle->style()->propertyCount() != inlineStyle->prop ertyCount())
531 setNodeAttribute(element, styleAttr, newInlineStyle->style()->asText ()); 531 setNodeAttribute(element, styleAttr, newInlineStyle->style()->asText ());
532 532
533 // FIXME: Tolerate differences in id, class, and style attributes. 533 // FIXME: Tolerate differences in id, class, and style attributes.
534 if (isNonTableCellHTMLBlockElement(element.raw()) && areIdenticalElement s(element.raw(), element->parentNode().handle().raw()) 534 if (isNonTableCellHTMLBlockElement(element) && areIdenticalElements(elem ent, element->parentNode())
535 && VisiblePosition(firstPositionInNode(element->parentNode())) == Vi siblePosition(firstPositionInNode(element)) 535 && VisiblePosition(firstPositionInNode(element->parentNode())) == Vi siblePosition(firstPositionInNode(element))
536 && VisiblePosition(lastPositionInNode(element->parentNode())) == Vis iblePosition(lastPositionInNode(element))) { 536 && VisiblePosition(lastPositionInNode(element->parentNode())) == Vis iblePosition(lastPositionInNode(element))) {
537 insertedNodes.willRemoveNodePreservingChildren(element.raw()); 537 insertedNodes.willRemoveNodePreservingChildren(element.raw());
538 removeNodePreservingChildren(element); 538 removeNodePreservingChildren(element);
539 continue; 539 continue;
540 } 540 }
541 541
542 if (element->parentNode()->rendererIsRichlyEditable()) 542 if (element->parentNode()->rendererIsRichlyEditable())
543 removeNodeAttribute(element, contenteditableAttr); 543 removeNodeAttribute(element, contenteditableAttr);
544 544
545 // WebKit used to not add display: inline and float: none on copy. 545 // WebKit used to not add display: inline and float: none on copy.
546 // Keep this code around for backward compatibility 546 // Keep this code around for backward compatibility
547 if (isLegacyAppleStyleSpan(element)) { 547 if (isLegacyAppleStyleSpan(element)) {
548 if (!element->firstChild()) { 548 if (!element->firstChild()) {
549 insertedNodes.willRemoveNodePreservingChildren(element.raw()); 549 insertedNodes.willRemoveNodePreservingChildren(element.raw());
550 removeNodePreservingChildren(element); 550 removeNodePreservingChildren(element);
551 continue; 551 continue;
552 } 552 }
553 // There are other styles that style rules can give to style spans, 553 // There are other styles that style rules can give to style spans,
554 // but these are the two important ones because they'll prevent 554 // but these are the two important ones because they'll prevent
555 // inserted content from appearing in the right paragraph. 555 // inserted content from appearing in the right paragraph.
556 // FIXME: Hyatt is concerned that selectively using display:inline w ill give inconsistent 556 // FIXME: Hyatt is concerned that selectively using display:inline w ill give inconsistent
557 // results. We already know one issue because td elements ignore the ir display property 557 // results. We already know one issue because td elements ignore the ir display property
558 // in quirks mode (which Mail.app is always in). We should look for an alternative. 558 // in quirks mode (which Mail.app is always in). We should look for an alternative.
559 559
560 // Mutate using the CSSOM wrapper so we get the same event behavior as a script. 560 // Mutate using the CSSOM wrapper so we get the same event behavior as a script.
561 if (isBlock(element.raw())) 561 if (isBlock(element))
562 element->style()->setPropertyInternal(CSSPropertyDisplay, "inlin e", false, IGNORE_EXCEPTION); 562 element->style()->setPropertyInternal(CSSPropertyDisplay, "inlin e", false, IGNORE_EXCEPTION);
563 if (element->renderer() && element->renderer()->style()->isFloating( )) 563 if (element->renderer() && element->renderer()->style()->isFloating( ))
564 element->style()->setPropertyInternal(CSSPropertyFloat, "none", false, IGNORE_EXCEPTION); 564 element->style()->setPropertyInternal(CSSPropertyFloat, "none", false, IGNORE_EXCEPTION);
565 } 565 }
566 } 566 }
567 } 567 }
568 568
569 static bool isProhibitedParagraphChild(const AtomicString& name) 569 static bool isProhibitedParagraphChild(const AtomicString& name)
570 { 570 {
571 // https://dvcs.w3.org/hg/editing/raw-file/57abe6d3cb60/editing.html#prohibi ted-paragraph-child 571 // https://dvcs.w3.org/hg/editing/raw-file/57abe6d3cb60/editing.html#prohibi ted-paragraph-child
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
627 { 627 {
628 RefPtr<Node> pastEndNode = insertedNodes.pastLastLeaf(); 628 RefPtr<Node> pastEndNode = insertedNodes.pastLastLeaf();
629 Handle<Node> next; 629 Handle<Node> next;
630 for (RefPtr<Node> node = insertedNodes.firstNodeInserted(); node && node != pastEndNode; node = next.passRefPtr()) { 630 for (RefPtr<Node> node = insertedNodes.firstNodeInserted(); node && node != pastEndNode; node = next.passRefPtr()) {
631 next = NodeTraversal::next(adoptRawResult(node.get())); 631 next = NodeTraversal::next(adoptRawResult(node.get()));
632 632
633 if (!node->isHTMLElement()) 633 if (!node->isHTMLElement())
634 continue; 634 continue;
635 635
636 if (isProhibitedParagraphChild(toHTMLElement(adoptRawResult(node.get())) ->localName())) { 636 if (isProhibitedParagraphChild(toHTMLElement(adoptRawResult(node.get())) ->localName())) {
637 if (Handle<HTMLElement> paragraphElement = toHTMLElement(adoptRawRes ult(enclosingNodeWithTag(positionInParentBeforeNode(adoptRawResult(node.get())), pTag)))) 637 if (Handle<HTMLElement> paragraphElement = toHTMLElement(enclosingNo deWithTag(positionInParentBeforeNode(adoptRawResult(node.get())), pTag)))
638 moveNodeOutOfAncestor(node, paragraphElement.passRefPtr()); 638 moveNodeOutOfAncestor(node, paragraphElement.passRefPtr());
639 } 639 }
640 640
641 if (isHeaderElement(node.get())) { 641 if (isHeaderElement(adoptRawResult(node.get()))) {
642 if (Handle<HTMLElement> headerElement = toHTMLElement(adoptRawResult (highestEnclosingNodeOfType(positionInParentBeforeNode(adoptRawResult(node.get() )), isHeaderElement)))) 642 if (Handle<HTMLElement> headerElement = toHTMLElement(highestEnclosi ngNodeOfType(positionInParentBeforeNode(adoptRawResult(node.get())), isHeaderEle ment)))
643 moveNodeOutOfAncestor(node, headerElement.passRefPtr()); 643 moveNodeOutOfAncestor(node, headerElement.passRefPtr());
644 } 644 }
645 } 645 }
646 } 646 }
647 647
648 void ReplaceSelectionCommand::moveNodeOutOfAncestor(PassRefPtr<Node> prpNode, Pa ssRefPtr<Node> prpAncestor) 648 void ReplaceSelectionCommand::moveNodeOutOfAncestor(PassRefPtr<Node> prpNode, Pa ssRefPtr<Node> prpAncestor)
649 { 649 {
650 Handle<Node> node = adoptRawResult(prpNode.get()); 650 Handle<Node> node = adoptRawResult(prpNode.get());
651 Handle<Node> ancestor = adoptRawResult(prpAncestor.get()); 651 Handle<Node> ancestor = adoptRawResult(prpAncestor.get());
652 652
653 VisiblePosition positionAtEndOfNode = lastPositionInOrAfterNode(node.raw()); 653 VisiblePosition positionAtEndOfNode = lastPositionInOrAfterNode(node);
654 VisiblePosition lastPositionInParagraph = lastPositionInNode(ancestor); 654 VisiblePosition lastPositionInParagraph = lastPositionInNode(ancestor);
655 if (positionAtEndOfNode == lastPositionInParagraph) { 655 if (positionAtEndOfNode == lastPositionInParagraph) {
656 removeNode(node); 656 removeNode(node);
657 if (ancestor->nextSibling()) 657 if (ancestor->nextSibling())
658 insertNodeBefore(node, ancestor->nextSibling()); 658 insertNodeBefore(node, ancestor->nextSibling());
659 else 659 else
660 appendNode(node, ancestor->parentNode()); 660 appendNode(node, ancestor->parentNode());
661 } else { 661 } else {
662 Handle<Node> nodeToSplitTo = splitTreeToNode(node, ancestor, true); 662 Handle<Node> nodeToSplitTo = splitTreeToNode(node, ancestor, true);
663 removeNode(node); 663 removeNode(node);
664 insertNodeBefore(node, nodeToSplitTo); 664 insertNodeBefore(node, nodeToSplitTo);
665 } 665 }
666 if (!ancestor->firstChild()) 666 if (!ancestor->firstChild())
667 removeNode(ancestor); 667 removeNode(ancestor);
668 } 668 }
669 669
670 static inline bool nodeHasVisibleRenderText(const Handle<Text>& text) 670 static inline bool nodeHasVisibleRenderText(const Handle<Text>& text)
671 { 671 {
672 return text->renderer() && toRenderText(text->renderer())->renderedTextLengt h() > 0; 672 return text->renderer() && toRenderText(text->renderer())->renderedTextLengt h() > 0;
673 } 673 }
674 674
675 void ReplaceSelectionCommand::removeUnrenderedTextNodesAtEnds(InsertedNodes& ins ertedNodes) 675 void ReplaceSelectionCommand::removeUnrenderedTextNodesAtEnds(InsertedNodes& ins ertedNodes)
676 { 676 {
677 document()->updateLayoutIgnorePendingStylesheets(); 677 document()->updateLayoutIgnorePendingStylesheets();
678 678
679 Handle<Node> lastLeafInserted = adoptRawResult(insertedNodes.lastLeafInserte d()); 679 Handle<Node> lastLeafInserted = adoptRawResult(insertedNodes.lastLeafInserte d());
680 if (lastLeafInserted && lastLeafInserted->isTextNode() && !nodeHasVisibleRen derText(toText(lastLeafInserted)) 680 if (lastLeafInserted && lastLeafInserted->isTextNode() && !nodeHasVisibleRen derText(toText(lastLeafInserted))
681 && !enclosingNodeWithTag(firstPositionInOrBeforeNode(lastLeafInserted.ra w()), selectTag) 681 && !enclosingNodeWithTag(firstPositionInOrBeforeNode(lastLeafInserted), selectTag)
682 && !enclosingNodeWithTag(firstPositionInOrBeforeNode(lastLeafInserted.ra w()), scriptTag)) { 682 && !enclosingNodeWithTag(firstPositionInOrBeforeNode(lastLeafInserted), scriptTag)) {
683 insertedNodes.willRemoveNode(lastLeafInserted.raw()); 683 insertedNodes.willRemoveNode(lastLeafInserted.raw());
684 removeNode(lastLeafInserted); 684 removeNode(lastLeafInserted);
685 } 685 }
686 686
687 // We don't have to make sure that firstNodeInserted isn't inside a select o r script element, because 687 // We don't have to make sure that firstNodeInserted isn't inside a select o r script element, because
688 // it is a top level node in the fragment and the user can't insert into tho se elements. 688 // it is a top level node in the fragment and the user can't insert into tho se elements.
689 Handle<Node> firstNodeInserted = adoptRawResult(insertedNodes.firstNodeInser ted()); 689 Handle<Node> firstNodeInserted = adoptRawResult(insertedNodes.firstNodeInser ted());
690 lastLeafInserted = adoptRawResult(insertedNodes.lastLeafInserted()); 690 lastLeafInserted = adoptRawResult(insertedNodes.lastLeafInserted());
691 if (firstNodeInserted && firstNodeInserted->isTextNode() && !nodeHasVisibleR enderText(toText(firstNodeInserted.raw()))) { 691 if (firstNodeInserted && firstNodeInserted->isTextNode() && !nodeHasVisibleR enderText(toText(firstNodeInserted.raw()))) {
692 insertedNodes.willRemoveNode(firstNodeInserted.raw()); 692 insertedNodes.willRemoveNode(firstNodeInserted.raw());
693 removeNode(firstNodeInserted); 693 removeNode(firstNodeInserted);
694 } 694 }
695 } 695 }
696 696
697 VisiblePosition ReplaceSelectionCommand::positionAtEndOfInsertedContent() const 697 VisiblePosition ReplaceSelectionCommand::positionAtEndOfInsertedContent() const
698 { 698 {
699 // FIXME: Why is this hack here? What's special about <select> tags? 699 // FIXME: Why is this hack here? What's special about <select> tags?
700 Node* enclosingSelect = enclosingNodeWithTag(m_endOfInsertedContent, selectT ag); 700 Handle<Node> enclosingSelect = enclosingNodeWithTag(m_endOfInsertedContent, selectTag);
701 return enclosingSelect ? lastPositionInOrAfterNode(enclosingSelect) : m_endO fInsertedContent; 701 return enclosingSelect ? lastPositionInOrAfterNode(enclosingSelect) : m_endO fInsertedContent;
702 } 702 }
703 703
704 VisiblePosition ReplaceSelectionCommand::positionAtStartOfInsertedContent() cons t 704 VisiblePosition ReplaceSelectionCommand::positionAtStartOfInsertedContent() cons t
705 { 705 {
706 return m_startOfInsertedContent; 706 return m_startOfInsertedContent;
707 } 707 }
708 708
709 static void removeHeadContents(ReplacementFragment& fragment) 709 static void removeHeadContents(ReplacementFragment& fragment)
710 { 710 {
(...skipping 13 matching lines...) Expand all
724 } 724 }
725 725
726 // Remove style spans before insertion if they are unnecessary. It's faster bec ause we'll 726 // Remove style spans before insertion if they are unnecessary. It's faster bec ause we'll
727 // avoid doing a layout. 727 // avoid doing a layout.
728 static bool handleStyleSpansBeforeInsertion(ReplacementFragment& fragment, const Position& insertionPos) 728 static bool handleStyleSpansBeforeInsertion(ReplacementFragment& fragment, const Position& insertionPos)
729 { 729 {
730 Handle<Node> topNode = adoptRawResult(fragment.firstChild()); 730 Handle<Node> topNode = adoptRawResult(fragment.firstChild());
731 731
732 // Handling the case where we are doing Paste as Quotation or pasting into q uoted content is more complicated (see handleStyleSpans) 732 // Handling the case where we are doing Paste as Quotation or pasting into q uoted content is more complicated (see handleStyleSpans)
733 // and doesn't receive the optimization. 733 // and doesn't receive the optimization.
734 if (isMailPasteAsQuotationNode(topNode.raw()) || enclosingNodeOfType(firstPo sitionInOrBeforeNode(topNode.raw()), isMailBlockquote, CanCrossEditingBoundary)) 734 if (isMailPasteAsQuotationNode(topNode) || enclosingNodeOfType(firstPosition InOrBeforeNode(topNode), isMailBlockquote, CanCrossEditingBoundary))
735 return false; 735 return false;
736 736
737 // Either there are no style spans in the fragment or a WebKit client has ad ded content to the fragment 737 // Either there are no style spans in the fragment or a WebKit client has ad ded content to the fragment
738 // before inserting it. Look for and handle style spans after insertion. 738 // before inserting it. Look for and handle style spans after insertion.
739 if (!isLegacyAppleStyleSpan(topNode)) 739 if (!isLegacyAppleStyleSpan(topNode))
740 return false; 740 return false;
741 741
742 Handle<Node> wrappingStyleSpan = topNode; 742 Handle<Node> wrappingStyleSpan = topNode;
743 RefPtr<EditingStyle> styleAtInsertionPos = EditingStyle::create(insertionPos .parentAnchoredEquivalent()); 743 RefPtr<EditingStyle> styleAtInsertionPos = EditingStyle::create(insertionPos .parentAnchoredEquivalent());
744 String styleText = styleAtInsertionPos->style()->asText(); 744 String styleText = styleAtInsertionPos->style()->asText();
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
777 // There might not be any style spans if we're pasting from another applicat ion or if 777 // There might not be any style spans if we're pasting from another applicat ion or if
778 // we are here because of a document.execCommand("InsertHTML", ...) call. 778 // we are here because of a document.execCommand("InsertHTML", ...) call.
779 if (!wrappingStyleSpan) 779 if (!wrappingStyleSpan)
780 return; 780 return;
781 781
782 RefPtr<EditingStyle> style = EditingStyle::createFromPropertySet(wrappingSty leSpan->inlineStyle()); 782 RefPtr<EditingStyle> style = EditingStyle::createFromPropertySet(wrappingSty leSpan->inlineStyle());
783 Handle<ContainerNode> context = wrappingStyleSpan->parentNode(); 783 Handle<ContainerNode> context = wrappingStyleSpan->parentNode();
784 784
785 // If Mail wraps the fragment with a Paste as Quotation blockquote, or if yo u're pasting into a quoted region, 785 // If Mail wraps the fragment with a Paste as Quotation blockquote, or if yo u're pasting into a quoted region,
786 // styles from blockquoteNode are allowed to override those from the source document, see <rdar://problem/4930986> and <rdar://problem/5089327>. 786 // styles from blockquoteNode are allowed to override those from the source document, see <rdar://problem/4930986> and <rdar://problem/5089327>.
787 Node* blockquoteNode = isMailPasteAsQuotationNode(context.raw()) ? context.r aw() : enclosingNodeOfType(firstPositionInNode(context), isMailBlockquote, CanCr ossEditingBoundary); 787 Handle<Node> blockquoteNode = isMailPasteAsQuotationNode(context) ? Handle<N ode>(context) : Handle<Node>(enclosingNodeOfType(firstPositionInNode(context), i sMailBlockquote, CanCrossEditingBoundary));
788 if (blockquoteNode) 788 if (blockquoteNode)
789 context = document()->documentElement(); 789 context = document()->documentElement();
790 790
791 // This operation requires that only editing styles to be removed from sourc eDocumentStyle. 791 // This operation requires that only editing styles to be removed from sourc eDocumentStyle.
792 style->prepareToApplyAt(firstPositionInNode(context)); 792 style->prepareToApplyAt(firstPositionInNode(context));
793 793
794 // Remove block properties in the span's style. This prevents properties tha t probably have no effect 794 // Remove block properties in the span's style. This prevents properties tha t probably have no effect
795 // currently from affecting blocks later if the style is cloned for a new bl ock element during a future 795 // currently from affecting blocks later if the style is cloned for a new bl ock element during a future
796 // editing operation. 796 // editing operation.
797 // FIXME: They *can* have an effect currently if blocks beneath the style sp an aren't individually marked 797 // FIXME: They *can* have an effect currently if blocks beneath the style sp an aren't individually marked
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
858 // Stop if any previous sibling is a block. 858 // Stop if any previous sibling is a block.
859 for (Handle<Node> sibling = node->previousSibling(); sibling; sibling = sibling->previousSibling()) { 859 for (Handle<Node> sibling = node->previousSibling(); sibling; sibling = sibling->previousSibling()) {
860 if (sibling->isBlockFlowElement()) 860 if (sibling->isBlockFlowElement())
861 return node; 861 return node;
862 } 862 }
863 node = parent.raw(); 863 node = parent.raw();
864 } 864 }
865 return node; 865 return node;
866 } 866 }
867 867
868 static bool isInlineNodeWithStyle(const Node* node) 868 static bool isInlineNodeWithStyle(const Handle<const Node>& node)
869 { 869 {
870 // We don't want to skip over any block elements. 870 // We don't want to skip over any block elements.
871 if (isBlock(node)) 871 if (isBlock(node))
872 return false; 872 return false;
873 873
874 if (!node->isHTMLElement()) 874 if (!node->isHTMLElement())
875 return false; 875 return false;
876 876
877 // We can skip over elements whose class attribute is 877 // We can skip over elements whose class attribute is
878 // one of our internal classes. 878 // one of our internal classes.
879 Handle<const HTMLElement> element = toConstHTMLElement(adoptRawResult(node)) ; 879 Handle<const HTMLElement> element = toConstHTMLElement(node);
880 const AtomicString& classAttributeValue = element->getAttribute(classAttr); 880 const AtomicString& classAttributeValue = element->getAttribute(classAttr);
881 if (classAttributeValue == AppleTabSpanClass 881 if (classAttributeValue == AppleTabSpanClass
882 || classAttributeValue == AppleConvertedSpace 882 || classAttributeValue == AppleConvertedSpace
883 || classAttributeValue == ApplePasteAsQuotation) 883 || classAttributeValue == ApplePasteAsQuotation)
884 return true; 884 return true;
885 885
886 return EditingStyle::elementIsStyledSpanOrHTMLEquivalent(element); 886 return EditingStyle::elementIsStyledSpanOrHTMLEquivalent(element);
887 } 887 }
888 888
889 inline Node* nodeToSplitToAvoidPastingIntoInlineNodesWithStyle(const Position& i nsertionPos) 889 inline Node* nodeToSplitToAvoidPastingIntoInlineNodesWithStyle(const Position& i nsertionPos)
Mads Ager (chromium) 2013/09/24 06:36:20 I believe this is only used in a couple of places
890 { 890 {
891 Handle<Node> containgBlock = enclosingBlock(insertionPos.containerNode().han dle().raw()); 891 Handle<Node> containgBlock = enclosingBlock(insertionPos.containerNode());
892 return highestEnclosingNodeOfType(insertionPos, isInlineNodeWithStyle, Canno tCrossEditingBoundary, containgBlock.raw()); 892 return highestEnclosingNodeOfType(insertionPos, isInlineNodeWithStyle, Canno tCrossEditingBoundary, containgBlock).handle().raw();
893 } 893 }
894 894
895 void ReplaceSelectionCommand::doApply() 895 void ReplaceSelectionCommand::doApply()
896 { 896 {
897 VisibleSelection selection = endingSelection(); 897 VisibleSelection selection = endingSelection();
898 ASSERT(selection.isCaretOrRange()); 898 ASSERT(selection.isCaretOrRange());
899 ASSERT(selection.start().deprecatedNode()); 899 ASSERT(selection.start().deprecatedNode());
900 if (!selection.isNonOrphanedCaretOrRange() || !selection.start().deprecatedN ode()) 900 if (!selection.isNonOrphanedCaretOrRange() || !selection.start().deprecatedN ode())
901 return; 901 return;
902 902
(...skipping 13 matching lines...) Expand all
916 m_insertionStyle = EditingStyle::create(selection.start()); 916 m_insertionStyle = EditingStyle::create(selection.start());
917 m_insertionStyle->mergeTypingStyle(document()); 917 m_insertionStyle->mergeTypingStyle(document());
918 } 918 }
919 919
920 VisiblePosition visibleStart = selection.visibleStart(); 920 VisiblePosition visibleStart = selection.visibleStart();
921 VisiblePosition visibleEnd = selection.visibleEnd(); 921 VisiblePosition visibleEnd = selection.visibleEnd();
922 922
923 bool selectionEndWasEndOfParagraph = isEndOfParagraph(visibleEnd); 923 bool selectionEndWasEndOfParagraph = isEndOfParagraph(visibleEnd);
924 bool selectionStartWasStartOfParagraph = isStartOfParagraph(visibleStart); 924 bool selectionStartWasStartOfParagraph = isStartOfParagraph(visibleStart);
925 925
926 Handle<Node> startBlock = enclosingBlock(visibleStart.deepEquivalent().depre catedNode().handle().raw()); 926 Handle<Node> startBlock = enclosingBlock(visibleStart.deepEquivalent().depre catedNode());
927 927
928 Position insertionPos = selection.start(); 928 Position insertionPos = selection.start();
929 bool startIsInsideMailBlockquote = enclosingNodeOfType(insertionPos, isMailB lockquote, CanCrossEditingBoundary); 929 bool startIsInsideMailBlockquote = enclosingNodeOfType(insertionPos, isMailB lockquote, CanCrossEditingBoundary);
930 bool selectionIsPlainText = !selection.isContentRichlyEditable(); 930 bool selectionIsPlainText = !selection.isContentRichlyEditable();
931 Handle<Element> currentRoot = selection.rootEditableElement(); 931 Handle<Element> currentRoot = selection.rootEditableElement();
932 932
933 if ((selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph && ! startIsInsideMailBlockquote) || 933 if ((selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph && ! startIsInsideMailBlockquote) ||
934 startBlock == currentRoot || isListItem(startBlock.raw()) || selectionIs PlainText) 934 startBlock == currentRoot || isListItem(startBlock) || selectionIsPlainT ext)
935 m_preventNesting = false; 935 m_preventNesting = false;
936 936
937 if (selection.isRange()) { 937 if (selection.isRange()) {
938 // When the end of the selection being pasted into is at the end of a pa ragraph, and that selection 938 // When the end of the selection being pasted into is at the end of a pa ragraph, and that selection
939 // spans multiple blocks, not merging may leave an empty line. 939 // spans multiple blocks, not merging may leave an empty line.
940 // When the start of the selection being pasted into is at the start of a block, not merging 940 // When the start of the selection being pasted into is at the start of a block, not merging
941 // will leave hanging block(s). 941 // will leave hanging block(s).
942 // Merge blocks if the start of the selection was in a Mail blockquote, since we handle 942 // Merge blocks if the start of the selection was in a Mail blockquote, since we handle
943 // that case specially to prevent nesting. 943 // that case specially to prevent nesting.
944 bool mergeBlocksAfterDelete = startIsInsideMailBlockquote || isEndOfPara graph(visibleEnd) || isStartOfBlock(visibleStart); 944 bool mergeBlocksAfterDelete = startIsInsideMailBlockquote || isEndOfPara graph(visibleEnd) || isStartOfBlock(visibleStart);
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
998 return; 998 return;
999 999
1000 // NOTE: This would be an incorrect usage of downstream() if downstream() we re changed to mean the last position after 1000 // NOTE: This would be an incorrect usage of downstream() if downstream() we re changed to mean the last position after
1001 // 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 1001 // 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
1002 // away, there are positions after the br which map to the same visible posi tion as [br, 0]). 1002 // away, there are positions after the br which map to the same visible posi tion as [br, 0]).
1003 Handle<Node> endBR = insertionPos.downstream().deprecatedNode()->hasTagName( brTag) ? insertionPos.downstream().deprecatedNode() : nullptr; 1003 Handle<Node> endBR = insertionPos.downstream().deprecatedNode()->hasTagName( brTag) ? insertionPos.downstream().deprecatedNode() : nullptr;
1004 VisiblePosition originalVisPosBeforeEndBR; 1004 VisiblePosition originalVisPosBeforeEndBR;
1005 if (endBR) 1005 if (endBR)
1006 originalVisPosBeforeEndBR = VisiblePosition(positionBeforeNode(endBR), D OWNSTREAM).previous(); 1006 originalVisPosBeforeEndBR = VisiblePosition(positionBeforeNode(endBR), D OWNSTREAM).previous();
1007 1007
1008 startBlock = enclosingBlock(insertionPos.deprecatedNode().handle().raw()); 1008 startBlock = enclosingBlock(insertionPos.deprecatedNode());
1009 1009
1010 // Adjust insertionPos to prevent nesting. 1010 // Adjust insertionPos to prevent nesting.
1011 // If the start was in a Mail blockquote, we will have already handled adjus ting insertionPos above. 1011 // If the start was in a Mail blockquote, we will have already handled adjus ting insertionPos above.
1012 if (m_preventNesting && startBlock && !isTableCell(startBlock.raw()) && !sta rtIsInsideMailBlockquote) { 1012 if (m_preventNesting && startBlock && !isTableCell(startBlock) && !startIsIn sideMailBlockquote) {
1013 ASSERT(startBlock != currentRoot); 1013 ASSERT(startBlock != currentRoot);
1014 VisiblePosition visibleInsertionPos(insertionPos); 1014 VisiblePosition visibleInsertionPos(insertionPos);
1015 if (isEndOfBlock(visibleInsertionPos) && !(isStartOfBlock(visibleInserti onPos) && fragment.hasInterchangeNewlineAtEnd())) 1015 if (isEndOfBlock(visibleInsertionPos) && !(isStartOfBlock(visibleInserti onPos) && fragment.hasInterchangeNewlineAtEnd()))
1016 insertionPos = positionInParentAfterNode(startBlock); 1016 insertionPos = positionInParentAfterNode(startBlock);
1017 else if (isStartOfBlock(visibleInsertionPos)) 1017 else if (isStartOfBlock(visibleInsertionPos))
1018 insertionPos = positionInParentBeforeNode(startBlock); 1018 insertionPos = positionInParentBeforeNode(startBlock);
1019 } 1019 }
1020 1020
1021 // Paste at start or end of link goes outside of link. 1021 // Paste at start or end of link goes outside of link.
1022 insertionPos = positionAvoidingSpecialElementBoundary(insertionPos); 1022 insertionPos = positionAvoidingSpecialElementBoundary(insertionPos);
(...skipping 18 matching lines...) Expand all
1041 // We're finished if there is nothing to add. 1041 // We're finished if there is nothing to add.
1042 if (fragment.isEmpty() || !fragment.firstChild()) 1042 if (fragment.isEmpty() || !fragment.firstChild())
1043 return; 1043 return;
1044 1044
1045 // If we are not trying to match the destination style we prefer a position 1045 // If we are not trying to match the destination style we prefer a position
1046 // that is outside inline elements that provide style. 1046 // that is outside inline elements that provide style.
1047 // This way we can produce a less verbose markup. 1047 // This way we can produce a less verbose markup.
1048 // We can skip this optimization for fragments not wrapped in one of 1048 // We can skip this optimization for fragments not wrapped in one of
1049 // our style spans and for positions inside list items 1049 // our style spans and for positions inside list items
1050 // since insertAsListItems already does the right thing. 1050 // since insertAsListItems already does the right thing.
1051 if (!m_matchStyle && !enclosingList(insertionPos.containerNode().handle().ra w())) { 1051 if (!m_matchStyle && !enclosingList(insertionPos.containerNode())) {
1052 if (insertionPos.containerNode()->isTextNode() && insertionPos.offsetInC ontainerNode() && !insertionPos.atLastEditingPositionForNode()) { 1052 if (insertionPos.containerNode()->isTextNode() && insertionPos.offsetInC ontainerNode() && !insertionPos.atLastEditingPositionForNode()) {
1053 splitTextNode(insertionPos.containerText(), insertionPos.offsetInCon tainerNode()); 1053 splitTextNode(insertionPos.containerText(), insertionPos.offsetInCon tainerNode());
1054 insertionPos = firstPositionInNode(insertionPos.containerNode()); 1054 insertionPos = firstPositionInNode(insertionPos.containerNode());
1055 } 1055 }
1056 1056
1057 if (RefPtr<Node> nodeToSplitTo = nodeToSplitToAvoidPastingIntoInlineNode sWithStyle(insertionPos)) { 1057 if (RefPtr<Node> nodeToSplitTo = nodeToSplitToAvoidPastingIntoInlineNode sWithStyle(insertionPos)) {
1058 if (insertionPos.containerNode() != nodeToSplitTo->parentNode()) { 1058 if (insertionPos.containerNode() != nodeToSplitTo->parentNode()) {
1059 Handle<Node> splitStart = insertionPos.computeNodeAfterPosition( ); 1059 Handle<Node> splitStart = insertionPos.computeNodeAfterPosition( );
1060 if (!splitStart) 1060 if (!splitStart)
1061 splitStart = insertionPos.containerNode(); 1061 splitStart = insertionPos.containerNode();
(...skipping 15 matching lines...) Expand all
1077 // incoming fragment. 1077 // incoming fragment.
1078 // 5) Add spaces for smart replace. 1078 // 5) Add spaces for smart replace.
1079 // 6) Select the replacement if requested, and match style if requested. 1079 // 6) Select the replacement if requested, and match style if requested.
1080 1080
1081 InsertedNodes insertedNodes; 1081 InsertedNodes insertedNodes;
1082 Handle<Node> refNode = adoptRawResult(fragment.firstChild()); 1082 Handle<Node> refNode = adoptRawResult(fragment.firstChild());
1083 Handle<Node> node = refNode->nextSibling(); 1083 Handle<Node> node = refNode->nextSibling();
1084 1084
1085 fragment.removeNode(refNode.raw()); 1085 fragment.removeNode(refNode.raw());
1086 1086
1087 Handle<Node> blockStart = enclosingBlock(insertionPos.deprecatedNode().handl e().raw()); 1087 Handle<Node> blockStart = enclosingBlock(insertionPos.deprecatedNode());
1088 if ((isListElement(refNode.raw()) || (isLegacyAppleStyleSpan(refNode) && isL istElement(refNode->firstChild().handle().raw()))) 1088 if ((isListElement(refNode) || (isLegacyAppleStyleSpan(refNode) && isListEle ment(refNode->firstChild())))
1089 && blockStart && blockStart->renderer()->isListItem()) 1089 && blockStart && blockStart->renderer()->isListItem())
1090 refNode = adoptRawResult(insertAsListItems(toHTMLElement(refNode), block Start.raw(), insertionPos, insertedNodes)); 1090 refNode = adoptRawResult(insertAsListItems(toHTMLElement(refNode), block Start.raw(), insertionPos, insertedNodes));
1091 else { 1091 else {
1092 insertNodeAt(refNode, insertionPos); 1092 insertNodeAt(refNode, insertionPos);
1093 insertedNodes.respondToNodeInsertion(refNode.raw()); 1093 insertedNodes.respondToNodeInsertion(refNode.raw());
1094 } 1094 }
1095 1095
1096 // Mutation events (bug 22634) may have already removed the inserted content 1096 // Mutation events (bug 22634) may have already removed the inserted content
1097 if (!refNode->inDocument()) 1097 if (!refNode->inDocument())
1098 return; 1098 return;
(...skipping 19 matching lines...) Expand all
1118 1118
1119 removeUnrenderedTextNodesAtEnds(insertedNodes); 1119 removeUnrenderedTextNodesAtEnds(insertedNodes);
1120 1120
1121 if (!handledStyleSpans) 1121 if (!handledStyleSpans)
1122 handleStyleSpans(insertedNodes); 1122 handleStyleSpans(insertedNodes);
1123 1123
1124 // Mutation events (bug 20161) may have already removed the inserted content 1124 // Mutation events (bug 20161) may have already removed the inserted content
1125 if (!insertedNodes.firstNodeInserted() || !insertedNodes.firstNodeInserted() ->inDocument()) 1125 if (!insertedNodes.firstNodeInserted() || !insertedNodes.firstNodeInserted() ->inDocument())
1126 return; 1126 return;
1127 1127
1128 VisiblePosition startOfInsertedContent = firstPositionInOrBeforeNode(inserte dNodes.firstNodeInserted()); 1128 VisiblePosition startOfInsertedContent = firstPositionInOrBeforeNode(adoptRa wResult(insertedNodes.firstNodeInserted()));
1129 1129
1130 // We inserted before the startBlock to prevent nesting, and the content bef ore the startBlock wasn't in its own block and 1130 // We inserted before the startBlock to prevent nesting, and the content bef ore the startBlock wasn't in its own block and
1131 // didn't have a br after it, so the inserted content ended up in the same p aragraph. 1131 // didn't have a br after it, so the inserted content ended up in the same p aragraph.
1132 if (startBlock && insertionPos.deprecatedNode() == startBlock->parentNode() && (unsigned)insertionPos.deprecatedEditingOffset() < startBlock->nodeIndex() && !isStartOfParagraph(startOfInsertedContent)) 1132 if (startBlock && insertionPos.deprecatedNode() == startBlock->parentNode() && (unsigned)insertionPos.deprecatedEditingOffset() < startBlock->nodeIndex() && !isStartOfParagraph(startOfInsertedContent))
1133 insertNodeAt(createBreakElement(document()), startOfInsertedContent.deep Equivalent()); 1133 insertNodeAt(createBreakElement(document()), startOfInsertedContent.deep Equivalent());
1134 1134
1135 if (endBR && (plainTextFragment || shouldRemoveEndBR(endBR.raw(), originalVi sPosBeforeEndBR))) { 1135 if (endBR && (plainTextFragment || shouldRemoveEndBR(endBR.raw(), originalVi sPosBeforeEndBR))) {
1136 RefPtr<Node> parent = endBR->parentNode().passRefPtr(); 1136 Handle<Node> parent = endBR->parentNode();
1137 insertedNodes.willRemoveNode(endBR.raw()); 1137 insertedNodes.willRemoveNode(endBR.raw());
1138 removeNode(endBR); 1138 removeNode(endBR);
1139 if (Handle<Node> nodeToRemove = adoptRawResult(highestNodeToRemoveInPrun ing(parent.get()))) { 1139 if (Handle<Node> nodeToRemove = highestNodeToRemoveInPruning(parent)) {
1140 insertedNodes.willRemoveNode(nodeToRemove.raw()); 1140 insertedNodes.willRemoveNode(nodeToRemove.raw());
1141 removeNode(nodeToRemove); 1141 removeNode(nodeToRemove);
1142 } 1142 }
1143 } 1143 }
1144 1144
1145 makeInsertedContentRoundTrippableWithHTMLTreeBuilder(insertedNodes); 1145 makeInsertedContentRoundTrippableWithHTMLTreeBuilder(insertedNodes);
1146 1146
1147 removeRedundantStylesAndKeepStyleSpanInline(insertedNodes); 1147 removeRedundantStylesAndKeepStyleSpanInline(insertedNodes);
1148 1148
1149 if (m_sanitizeFragment) 1149 if (m_sanitizeFragment)
1150 applyCommandToComposite(SimplifyMarkupCommand::create(document(), insert edNodes.firstNodeInserted(), insertedNodes.pastLastLeaf())); 1150 applyCommandToComposite(SimplifyMarkupCommand::create(document(), insert edNodes.firstNodeInserted(), insertedNodes.pastLastLeaf()));
1151 1151
1152 // Setup m_startOfInsertedContent and m_endOfInsertedContent. This should be the last two lines of code that access insertedNodes. 1152 // Setup m_startOfInsertedContent and m_endOfInsertedContent. This should be the last two lines of code that access insertedNodes.
1153 m_startOfInsertedContent = firstPositionInOrBeforeNode(insertedNodes.firstNo deInserted()); 1153 m_startOfInsertedContent = firstPositionInOrBeforeNode(adoptRawResult(insert edNodes.firstNodeInserted()));
1154 m_endOfInsertedContent = lastPositionInOrAfterNode(insertedNodes.lastLeafIns erted()); 1154 m_endOfInsertedContent = lastPositionInOrAfterNode(adoptRawResult(insertedNo des.lastLeafInserted()));
1155 1155
1156 // Determine whether or not we should merge the end of inserted content with what's after it before we do 1156 // Determine whether or not we should merge the end of inserted content with what's after it before we do
1157 // the start merge so that the start merge doesn't effect our decision. 1157 // the start merge so that the start merge doesn't effect our decision.
1158 m_shouldMergeEnd = shouldMergeEnd(selectionEndWasEndOfParagraph); 1158 m_shouldMergeEnd = shouldMergeEnd(selectionEndWasEndOfParagraph);
1159 1159
1160 if (shouldMergeStart(selectionStartWasStartOfParagraph, fragment.hasIntercha ngeNewlineAtStart(), startIsInsideMailBlockquote)) { 1160 if (shouldMergeStart(selectionStartWasStartOfParagraph, fragment.hasIntercha ngeNewlineAtStart(), startIsInsideMailBlockquote)) {
1161 VisiblePosition startOfParagraphToMove = positionAtStartOfInsertedConten t(); 1161 VisiblePosition startOfParagraphToMove = positionAtStartOfInsertedConten t();
1162 VisiblePosition destination = startOfParagraphToMove.previous(); 1162 VisiblePosition destination = startOfParagraphToMove.previous();
1163 // We need to handle the case where we need to merge the end 1163 // We need to handle the case where we need to merge the end
1164 // but our destination node is inside an inline that is the last in the block. 1164 // but our destination node is inside an inline that is the last in the block.
(...skipping 26 matching lines...) Expand all
1191 } 1191 }
1192 1192
1193 Position lastPositionToSelect; 1193 Position lastPositionToSelect;
1194 if (fragment.hasInterchangeNewlineAtEnd()) { 1194 if (fragment.hasInterchangeNewlineAtEnd()) {
1195 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent(); 1195 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent();
1196 VisiblePosition next = endOfInsertedContent.next(CannotCrossEditingBound ary); 1196 VisiblePosition next = endOfInsertedContent.next(CannotCrossEditingBound ary);
1197 1197
1198 if (selectionEndWasEndOfParagraph || !isEndOfParagraph(endOfInsertedCont ent) || next.isNull()) { 1198 if (selectionEndWasEndOfParagraph || !isEndOfParagraph(endOfInsertedCont ent) || next.isNull()) {
1199 if (!isStartOfParagraph(endOfInsertedContent)) { 1199 if (!isStartOfParagraph(endOfInsertedContent)) {
1200 setEndingSelection(endOfInsertedContent); 1200 setEndingSelection(endOfInsertedContent);
1201 Handle<Node> enclosingNode = enclosingBlock(endOfInsertedContent .deepEquivalent().deprecatedNode().handle().raw()); 1201 Handle<Node> enclosingNode = enclosingBlock(endOfInsertedContent .deepEquivalent().deprecatedNode());
1202 if (isListItem(enclosingNode.raw())) { 1202 if (isListItem(enclosingNode)) {
1203 Handle<Node> newListItem = createListItemElement(document()) ; 1203 Handle<Node> newListItem = createListItemElement(document()) ;
1204 insertNodeAfter(newListItem, enclosingNode); 1204 insertNodeAfter(newListItem, enclosingNode);
1205 setEndingSelection(VisiblePosition(firstPositionInNode(newLi stItem))); 1205 setEndingSelection(VisiblePosition(firstPositionInNode(newLi stItem)));
1206 } else { 1206 } else {
1207 // Use a default paragraph element (a plain div) for the emp ty paragraph, using the last paragraph 1207 // Use a default paragraph element (a plain div) for the emp ty paragraph, using the last paragraph
1208 // block's style seems to annoy users. 1208 // block's style seems to annoy users.
1209 insertParagraphSeparator(true, !startIsInsideMailBlockquote && highestEnclosingNodeOfType(endOfInsertedContent.deepEquivalent(), 1209 insertParagraphSeparator(true, !startIsInsideMailBlockquote && highestEnclosingNodeOfType(endOfInsertedContent.deepEquivalent(),
1210 isMailBlockquote, CannotCrossEditingBoundary, insertedNo des.firstNodeInserted()->parentNode().handle().raw())); 1210 isMailBlockquote, CannotCrossEditingBoundary, insertedNo des.firstNodeInserted()->parentNode()));
1211 } 1211 }
1212 1212
1213 // Select up to the paragraph separator that was added. 1213 // Select up to the paragraph separator that was added.
1214 lastPositionToSelect = endingSelection().visibleStart().deepEqui valent(); 1214 lastPositionToSelect = endingSelection().visibleStart().deepEqui valent();
1215 updateNodesInserted(lastPositionToSelect.deprecatedNode().handle ().raw()); 1215 updateNodesInserted(lastPositionToSelect.deprecatedNode().handle ().raw());
1216 } 1216 }
1217 } else { 1217 } else {
1218 // Select up to the beginning of the next paragraph. 1218 // Select up to the beginning of the next paragraph.
1219 lastPositionToSelect = next.deepEquivalent().downstream(); 1219 lastPositionToSelect = next.deepEquivalent().downstream();
1220 } 1220 }
1221 1221
1222 } else 1222 } else
1223 mergeEndIfNeeded(); 1223 mergeEndIfNeeded();
1224 1224
1225 if (Node* mailBlockquote = enclosingNodeOfType(positionAtStartOfInsertedCont ent().deepEquivalent(), isMailPasteAsQuotationNode)) 1225 if (Handle<Node> mailBlockquote = enclosingNodeOfType(positionAtStartOfInser tedContent().deepEquivalent(), isMailPasteAsQuotationNode))
1226 removeNodeAttribute(adoptRawResult(toElement(mailBlockquote)), classAttr ); 1226 removeNodeAttribute(toElement(mailBlockquote), classAttr);
1227 1227
1228 if (shouldPerformSmartReplace()) 1228 if (shouldPerformSmartReplace())
1229 addSpacesForSmartReplace(); 1229 addSpacesForSmartReplace();
1230 1230
1231 // If we are dealing with a fragment created from plain text 1231 // If we are dealing with a fragment created from plain text
1232 // no style matching is necessary. 1232 // no style matching is necessary.
1233 if (plainTextFragment) 1233 if (plainTextFragment)
1234 m_matchStyle = false; 1234 m_matchStyle = false;
1235 1235
1236 completeHTMLReplacement(lastPositionToSelect); 1236 completeHTMLReplacement(lastPositionToSelect);
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
1378 if (!text) 1378 if (!text)
1379 return; 1379 return;
1380 1380
1381 if (text->previousSibling() && text->previousSibling()->isTextNode()) { 1381 if (text->previousSibling() && text->previousSibling()->isTextNode()) {
1382 Handle<Text> previous = toText(text->previousSibling()); 1382 Handle<Text> previous = toText(text->previousSibling());
1383 insertTextIntoNode(text, 0, previous->data()); 1383 insertTextIntoNode(text, 0, previous->data());
1384 1384
1385 if (positionIsOffsetInAnchor) 1385 if (positionIsOffsetInAnchor)
1386 position.moveToOffset(previous->length() + position.offsetInContaine rNode()); 1386 position.moveToOffset(previous->length() + position.offsetInContaine rNode());
1387 else 1387 else
1388 updatePositionForNodeRemoval(position, previous.raw()); 1388 updatePositionForNodeRemoval(position, previous);
1389 1389
1390 if (positionOnlyToBeUpdatedIsOffsetInAnchor) { 1390 if (positionOnlyToBeUpdatedIsOffsetInAnchor) {
1391 if (positionOnlyToBeUpdated.containerNode() == text) 1391 if (positionOnlyToBeUpdated.containerNode() == text)
1392 positionOnlyToBeUpdated.moveToOffset(previous->length() + positi onOnlyToBeUpdated.offsetInContainerNode()); 1392 positionOnlyToBeUpdated.moveToOffset(previous->length() + positi onOnlyToBeUpdated.offsetInContainerNode());
1393 else if (positionOnlyToBeUpdated.containerNode() == previous) 1393 else if (positionOnlyToBeUpdated.containerNode() == previous)
1394 positionOnlyToBeUpdated.moveToPosition(text, positionOnlyToBeUpd ated.offsetInContainerNode()); 1394 positionOnlyToBeUpdated.moveToPosition(text, positionOnlyToBeUpd ated.offsetInContainerNode());
1395 } else 1395 } else
1396 updatePositionForNodeRemoval(positionOnlyToBeUpdated, previous.raw() ); 1396 updatePositionForNodeRemoval(positionOnlyToBeUpdated, previous);
1397 1397
1398 removeNode(previous); 1398 removeNode(previous);
1399 } 1399 }
1400 if (text->nextSibling() && text->nextSibling()->isTextNode()) { 1400 if (text->nextSibling() && text->nextSibling()->isTextNode()) {
1401 Handle<Text> next = toText(text->nextSibling()); 1401 Handle<Text> next = toText(text->nextSibling());
1402 unsigned originalLength = text->length(); 1402 unsigned originalLength = text->length();
1403 insertTextIntoNode(text, originalLength, next->data()); 1403 insertTextIntoNode(text, originalLength, next->data());
1404 1404
1405 if (!positionIsOffsetInAnchor) 1405 if (!positionIsOffsetInAnchor)
1406 updatePositionForNodeRemoval(position, next.raw()); 1406 updatePositionForNodeRemoval(position, next);
1407 1407
1408 if (positionOnlyToBeUpdatedIsOffsetInAnchor && positionOnlyToBeUpdated.c ontainerNode() == next) 1408 if (positionOnlyToBeUpdatedIsOffsetInAnchor && positionOnlyToBeUpdated.c ontainerNode() == next)
1409 positionOnlyToBeUpdated.moveToPosition(text, originalLength + positi onOnlyToBeUpdated.offsetInContainerNode()); 1409 positionOnlyToBeUpdated.moveToPosition(text, originalLength + positi onOnlyToBeUpdated.offsetInContainerNode());
1410 else 1410 else
1411 updatePositionForNodeRemoval(positionOnlyToBeUpdated, next.raw()); 1411 updatePositionForNodeRemoval(positionOnlyToBeUpdated, next);
1412 1412
1413 removeNode(next); 1413 removeNode(next);
1414 } 1414 }
1415 } 1415 }
1416 1416
1417 EditAction ReplaceSelectionCommand::editingAction() const 1417 EditAction ReplaceSelectionCommand::editingAction() const
1418 { 1418 {
1419 return m_editAction; 1419 return m_editAction;
1420 } 1420 }
1421 1421
1422 // If the user is inserting a list into an existing list, instead of nesting the list, 1422 // If the user is inserting a list into an existing list, instead of nesting the list,
1423 // we put the list items into the existing list. 1423 // we put the list items into the existing list.
1424 Node* ReplaceSelectionCommand::insertAsListItems(const Handle<HTMLElement>& prpL istElement, Node* insertionBlock, const Position& insertPos, InsertedNodes& inse rtedNodes) 1424 Node* ReplaceSelectionCommand::insertAsListItems(const Handle<HTMLElement>& prpL istElement, Node* insertionBlock, const Position& insertPos, InsertedNodes& inse rtedNodes)
1425 { 1425 {
1426 Handle<HTMLElement> listElement = prpListElement; 1426 Handle<HTMLElement> listElement = prpListElement;
1427 1427
1428 while (listElement->hasChildNodes() && isListElement(listElement->firstChild ().handle().raw()) && listElement->childNodeCount() == 1) 1428 while (listElement->hasChildNodes() && isListElement(listElement->firstChild ()) && listElement->childNodeCount() == 1)
1429 listElement = toHTMLElement(listElement->firstChild()); 1429 listElement = toHTMLElement(listElement->firstChild());
1430 1430
1431 bool isStart = isStartOfParagraph(insertPos); 1431 bool isStart = isStartOfParagraph(insertPos);
1432 bool isEnd = isEndOfParagraph(insertPos); 1432 bool isEnd = isEndOfParagraph(insertPos);
1433 bool isMiddle = !isStart && !isEnd; 1433 bool isMiddle = !isStart && !isEnd;
1434 Handle<Node> lastNode = adoptRawResult(insertionBlock); 1434 Handle<Node> lastNode = adoptRawResult(insertionBlock);
1435 1435
1436 // If we're in the middle of a list item, we should split it into two separa te 1436 // If we're in the middle of a list item, we should split it into two separa te
1437 // list items and insert these nodes between them. 1437 // list items and insert these nodes between them.
1438 if (isMiddle) { 1438 if (isMiddle) {
(...skipping 20 matching lines...) Expand all
1459 lastNode = lastNode->previousSibling(); 1459 lastNode = lastNode->previousSibling();
1460 return lastNode.raw(); 1460 return lastNode.raw();
1461 } 1461 }
1462 1462
1463 void ReplaceSelectionCommand::updateNodesInserted(Node *node) 1463 void ReplaceSelectionCommand::updateNodesInserted(Node *node)
1464 { 1464 {
1465 if (!node) 1465 if (!node)
1466 return; 1466 return;
1467 1467
1468 if (m_startOfInsertedContent.isNull()) 1468 if (m_startOfInsertedContent.isNull())
1469 m_startOfInsertedContent = firstPositionInOrBeforeNode(node); 1469 m_startOfInsertedContent = firstPositionInOrBeforeNode(adoptRawResult(no de));
1470 1470
1471 m_endOfInsertedContent = lastPositionInOrAfterNode(node->lastDescendant().ha ndle().raw()); 1471 m_endOfInsertedContent = lastPositionInOrAfterNode(node->lastDescendant());
1472 } 1472 }
1473 1473
1474 // During simple pastes, where we're just pasting a text node into a run of text , we insert the text node 1474 // During simple pastes, where we're just pasting a text node into a run of text , we insert the text node
1475 // directly into the text node that holds the selection. This is much faster th an the generalized code in 1475 // directly into the text node that holds the selection. This is much faster th an the generalized code in
1476 // ReplaceSelectionCommand, and works around <https://bugs.webkit.org/show_bug.c gi?id=6148> since we don't 1476 // ReplaceSelectionCommand, and works around <https://bugs.webkit.org/show_bug.c gi?id=6148> since we don't
1477 // split text nodes. 1477 // split text nodes.
1478 bool ReplaceSelectionCommand::performTrivialReplace(const ReplacementFragment& f ragment) 1478 bool ReplaceSelectionCommand::performTrivialReplace(const ReplacementFragment& f ragment)
1479 { 1479 {
1480 if (!fragment.firstChild() || fragment.firstChild() != fragment.lastChild() || !fragment.firstChild()->isTextNode()) 1480 if (!fragment.firstChild() || fragment.firstChild() != fragment.lastChild() || !fragment.firstChild()->isTextNode())
1481 return false; 1481 return false;
(...skipping 20 matching lines...) Expand all
1502 removeNodeAndPruneAncestors(nodeAfterInsertionPos); 1502 removeNodeAndPruneAncestors(nodeAfterInsertionPos);
1503 1503
1504 VisibleSelection selectionAfterReplace(m_selectReplacement ? start : end, en d); 1504 VisibleSelection selectionAfterReplace(m_selectReplacement ? start : end, en d);
1505 1505
1506 setEndingSelection(selectionAfterReplace); 1506 setEndingSelection(selectionAfterReplace);
1507 1507
1508 return true; 1508 return true;
1509 } 1509 }
1510 1510
1511 } // namespace WebCore 1511 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/core/editing/ModifySelectionListLevel.cpp ('k') | Source/core/editing/TextIterator.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698