Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |