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 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
377 , m_editAction(editAction) | 377 , m_editAction(editAction) |
378 , m_sanitizeFragment(options & SanitizeFragment) | 378 , m_sanitizeFragment(options & SanitizeFragment) |
379 , m_shouldMergeEnd(false) | 379 , m_shouldMergeEnd(false) |
380 { | 380 { |
381 } | 381 } |
382 | 382 |
383 static bool hasMatchingQuoteLevel(VisiblePosition endOfExistingContent, VisibleP
osition endOfInsertedContent) | 383 static bool hasMatchingQuoteLevel(VisiblePosition endOfExistingContent, VisibleP
osition endOfInsertedContent) |
384 { | 384 { |
385 Position existing = endOfExistingContent.deepEquivalent(); | 385 Position existing = endOfExistingContent.deepEquivalent(); |
386 Position inserted = endOfInsertedContent.deepEquivalent(); | 386 Position inserted = endOfInsertedContent.deepEquivalent(); |
387 bool isInsideMailBlockquote = enclosingNodeOfType(inserted, isMailBlockquote
, CanCrossEditingBoundary); | 387 bool isInsideMailBlockquote = enclosingNodeOfType(inserted, isMailHTMLBlockq
uoteElement, CanCrossEditingBoundary); |
388 return isInsideMailBlockquote && (numEnclosingMailBlockquotes(existing) == n
umEnclosingMailBlockquotes(inserted)); | 388 return isInsideMailBlockquote && (numEnclosingMailBlockquotes(existing) == n
umEnclosingMailBlockquotes(inserted)); |
389 } | 389 } |
390 | 390 |
391 bool ReplaceSelectionCommand::shouldMergeStart(bool selectionStartWasStartOfPara
graph, bool fragmentHasInterchangeNewlineAtStart, bool selectionStartWasInsideMa
ilBlockquote) | 391 bool ReplaceSelectionCommand::shouldMergeStart(bool selectionStartWasStartOfPara
graph, bool fragmentHasInterchangeNewlineAtStart, bool selectionStartWasInsideMa
ilBlockquote) |
392 { | 392 { |
393 if (m_movingParagraph) | 393 if (m_movingParagraph) |
394 return false; | 394 return false; |
395 | 395 |
396 VisiblePosition startOfInsertedContent(positionAtStartOfInsertedContent()); | 396 VisiblePosition startOfInsertedContent(positionAtStartOfInsertedContent()); |
397 VisiblePosition prev = startOfInsertedContent.previous(CannotCrossEditingBou
ndary); | 397 VisiblePosition prev = startOfInsertedContent.previous(CannotCrossEditingBou
ndary); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
455 | 455 |
456 bool ReplaceSelectionCommand::shouldMerge(const VisiblePosition& source, const V
isiblePosition& destination) | 456 bool ReplaceSelectionCommand::shouldMerge(const VisiblePosition& source, const V
isiblePosition& destination) |
457 { | 457 { |
458 if (source.isNull() || destination.isNull()) | 458 if (source.isNull() || destination.isNull()) |
459 return false; | 459 return false; |
460 | 460 |
461 Node* sourceNode = source.deepEquivalent().deprecatedNode(); | 461 Node* sourceNode = source.deepEquivalent().deprecatedNode(); |
462 Node* destinationNode = destination.deepEquivalent().deprecatedNode(); | 462 Node* destinationNode = destination.deepEquivalent().deprecatedNode(); |
463 Element* sourceBlock = enclosingBlock(sourceNode); | 463 Element* sourceBlock = enclosingBlock(sourceNode); |
464 Element* destinationBlock = enclosingBlock(destinationNode); | 464 Element* destinationBlock = enclosingBlock(destinationNode); |
465 return !enclosingNodeOfType(source.deepEquivalent(), &isMailPasteAsQuotation
Node) && | 465 return !enclosingNodeOfType(source.deepEquivalent(), &isMailPasteAsQuotation
Node) |
466 sourceBlock && (!sourceBlock->hasTagName(blockquoteTag) || isMailBloc
kquote(sourceBlock)) && | 466 && sourceBlock && (!sourceBlock->hasTagName(blockquoteTag) || isMailHTML
BlockquoteElement(sourceBlock)) |
467 enclosingListChild(sourceBlock) == enclosingListChild(destinationNode
) && | 467 && enclosingListChild(sourceBlock) == enclosingListChild(destinationNode
) |
468 enclosingTableCell(source.deepEquivalent()) == enclosingTableCell(des
tination.deepEquivalent()) && | 468 && enclosingTableCell(source.deepEquivalent()) == enclosingTableCell(des
tination.deepEquivalent()) |
469 (!isHeaderElement(sourceBlock) || haveSameTagName(sourceBlock, destin
ationBlock)) && | 469 && (!isHeaderElement(sourceBlock) || haveSameTagName(sourceBlock, destin
ationBlock)) |
470 // Don't merge to or from a position before or after a block because
it would | 470 // Don't merge to or from a position before or after a block because it
would |
471 // be a no-op and cause infinite recursion. | 471 // be a no-op and cause infinite recursion. |
472 !isBlock(sourceNode) && !isBlock(destinationNode); | 472 && !isBlock(sourceNode) && !isBlock(destinationNode); |
473 } | 473 } |
474 | 474 |
475 // Style rules that match just inserted elements could change their appearance,
like | 475 // Style rules that match just inserted elements could change their appearance,
like |
476 // a div inserted into a document with div { display:inline; }. | 476 // a div inserted into a document with div { display:inline; }. |
477 void ReplaceSelectionCommand::removeRedundantStylesAndKeepStyleSpanInline(Insert
edNodes& insertedNodes) | 477 void ReplaceSelectionCommand::removeRedundantStylesAndKeepStyleSpanInline(Insert
edNodes& insertedNodes) |
478 { | 478 { |
479 RefPtrWillBeRawPtr<Node> pastEndNode = insertedNodes.pastLastLeaf(); | 479 RefPtrWillBeRawPtr<Node> pastEndNode = insertedNodes.pastLastLeaf(); |
480 RefPtrWillBeRawPtr<Node> next = nullptr; | 480 RefPtrWillBeRawPtr<Node> next = nullptr; |
481 for (RefPtrWillBeRawPtr<Node> node = insertedNodes.firstNodeInserted(); node
&& node != pastEndNode; node = next) { | 481 for (RefPtrWillBeRawPtr<Node> node = insertedNodes.firstNodeInserted(); node
&& node != pastEndNode; node = next) { |
482 // FIXME: <rdar://problem/5371536> Style rules that match pasted content
can change it's appearance | 482 // FIXME: <rdar://problem/5371536> Style rules that match pasted content
can change it's appearance |
(...skipping 23 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 ContainerNode* context = element->parentNode(); | 512 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 = !context || isMailPasteAsQuotationNode(contex
t) ? context : enclosingNodeOfType(firstPositionInNode(context), isMailBlockquot
e, CanCrossEditingBoundary); | 516 Node* blockquoteNode = !context || isMailPasteAsQuotationNode(contex
t) ? context : enclosingNodeOfType(firstPositionInNode(context), isMailHTMLBlock
quoteElement, 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); | 525 insertedNodes.willRemoveNodePreservingChildren(*element); |
526 removeNodePreservingChildren(element); | 526 removeNodePreservingChildren(element); |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
727 } | 727 } |
728 | 728 |
729 // Remove style spans before insertion if they are unnecessary. It's faster bec
ause we'll | 729 // Remove style spans before insertion if they are unnecessary. It's faster bec
ause we'll |
730 // avoid doing a layout. | 730 // avoid doing a layout. |
731 static bool handleStyleSpansBeforeInsertion(ReplacementFragment& fragment, const
Position& insertionPos) | 731 static bool handleStyleSpansBeforeInsertion(ReplacementFragment& fragment, const
Position& insertionPos) |
732 { | 732 { |
733 Node* topNode = fragment.firstChild(); | 733 Node* topNode = fragment.firstChild(); |
734 | 734 |
735 // Handling the case where we are doing Paste as Quotation or pasting into q
uoted content is more complicated (see handleStyleSpans) | 735 // Handling the case where we are doing Paste as Quotation or pasting into q
uoted content is more complicated (see handleStyleSpans) |
736 // and doesn't receive the optimization. | 736 // and doesn't receive the optimization. |
737 if (isMailPasteAsQuotationNode(topNode) || enclosingNodeOfType(firstPosition
InOrBeforeNode(topNode), isMailBlockquote, CanCrossEditingBoundary)) | 737 if (isMailPasteAsQuotationNode(topNode) || enclosingNodeOfType(firstPosition
InOrBeforeNode(topNode), isMailHTMLBlockquoteElement, CanCrossEditingBoundary)) |
738 return false; | 738 return false; |
739 | 739 |
740 // Either there are no style spans in the fragment or a WebKit client has ad
ded content to the fragment | 740 // Either there are no style spans in the fragment or a WebKit client has ad
ded content to the fragment |
741 // before inserting it. Look for and handle style spans after insertion. | 741 // before inserting it. Look for and handle style spans after insertion. |
742 if (!isLegacyAppleStyleSpan(topNode)) | 742 if (!isLegacyAppleStyleSpan(topNode)) |
743 return false; | 743 return false; |
744 | 744 |
745 Node* wrappingStyleSpan = topNode; | 745 Node* wrappingStyleSpan = topNode; |
746 RefPtrWillBeRawPtr<EditingStyle> styleAtInsertionPos = EditingStyle::create(
insertionPos.parentAnchoredEquivalent()); | 746 RefPtrWillBeRawPtr<EditingStyle> styleAtInsertionPos = EditingStyle::create(
insertionPos.parentAnchoredEquivalent()); |
747 String styleText = styleAtInsertionPos->style()->asText(); | 747 String styleText = styleAtInsertionPos->style()->asText(); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
779 // There might not be any style spans if we're pasting from another applicat
ion or if | 779 // There might not be any style spans if we're pasting from another applicat
ion or if |
780 // we are here because of a document.execCommand("InsertHTML", ...) call. | 780 // we are here because of a document.execCommand("InsertHTML", ...) call. |
781 if (!wrappingStyleSpan) | 781 if (!wrappingStyleSpan) |
782 return; | 782 return; |
783 | 783 |
784 RefPtrWillBeRawPtr<EditingStyle> style = EditingStyle::create(wrappingStyleS
pan->inlineStyle()); | 784 RefPtrWillBeRawPtr<EditingStyle> style = EditingStyle::create(wrappingStyleS
pan->inlineStyle()); |
785 ContainerNode* context = wrappingStyleSpan->parentNode(); | 785 ContainerNode* context = wrappingStyleSpan->parentNode(); |
786 | 786 |
787 // If Mail wraps the fragment with a Paste as Quotation blockquote, or if yo
u're pasting into a quoted region, | 787 // If Mail wraps the fragment with a Paste as Quotation blockquote, or if yo
u're pasting into a quoted region, |
788 // styles from blockquoteNode are allowed to override those from the source
document, see <rdar://problem/4930986> and <rdar://problem/5089327>. | 788 // styles from blockquoteNode are allowed to override those from the source
document, see <rdar://problem/4930986> and <rdar://problem/5089327>. |
789 Node* blockquoteNode = isMailPasteAsQuotationNode(context) ? context : enclo
singNodeOfType(firstPositionInNode(context), isMailBlockquote, CanCrossEditingBo
undary); | 789 Node* blockquoteNode = isMailPasteAsQuotationNode(context) ? context : enclo
singNodeOfType(firstPositionInNode(context), isMailHTMLBlockquoteElement, CanCro
ssEditingBoundary); |
790 if (blockquoteNode) | 790 if (blockquoteNode) |
791 context = document().documentElement(); | 791 context = document().documentElement(); |
792 | 792 |
793 // This operation requires that only editing styles to be removed from sourc
eDocumentStyle. | 793 // This operation requires that only editing styles to be removed from sourc
eDocumentStyle. |
794 style->prepareToApplyAt(firstPositionInNode(context)); | 794 style->prepareToApplyAt(firstPositionInNode(context)); |
795 | 795 |
796 // Remove block properties in the span's style. This prevents properties tha
t probably have no effect | 796 // Remove block properties in the span's style. This prevents properties tha
t probably have no effect |
797 // currently from affecting blocks later if the style is cloned for a new bl
ock element during a future | 797 // currently from affecting blocks later if the style is cloned for a new bl
ock element during a future |
798 // editing operation. | 798 // editing operation. |
799 // FIXME: They *can* have an effect currently if blocks beneath the style sp
an aren't individually marked | 799 // FIXME: They *can* have an effect currently if blocks beneath the style sp
an aren't individually marked |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
929 | 929 |
930 VisiblePosition visibleStart = selection.visibleStart(); | 930 VisiblePosition visibleStart = selection.visibleStart(); |
931 VisiblePosition visibleEnd = selection.visibleEnd(); | 931 VisiblePosition visibleEnd = selection.visibleEnd(); |
932 | 932 |
933 bool selectionEndWasEndOfParagraph = isEndOfParagraph(visibleEnd); | 933 bool selectionEndWasEndOfParagraph = isEndOfParagraph(visibleEnd); |
934 bool selectionStartWasStartOfParagraph = isStartOfParagraph(visibleStart); | 934 bool selectionStartWasStartOfParagraph = isStartOfParagraph(visibleStart); |
935 | 935 |
936 Node* enclosingBlockOfVisibleStart = enclosingBlock(visibleStart.deepEquival
ent().deprecatedNode()); | 936 Node* enclosingBlockOfVisibleStart = enclosingBlock(visibleStart.deepEquival
ent().deprecatedNode()); |
937 | 937 |
938 Position insertionPos = selection.start(); | 938 Position insertionPos = selection.start(); |
939 bool startIsInsideMailBlockquote = enclosingNodeOfType(insertionPos, isMailB
lockquote, CanCrossEditingBoundary); | 939 bool startIsInsideMailBlockquote = enclosingNodeOfType(insertionPos, isMailH
TMLBlockquoteElement, CanCrossEditingBoundary); |
940 bool selectionIsPlainText = !selection.isContentRichlyEditable(); | 940 bool selectionIsPlainText = !selection.isContentRichlyEditable(); |
941 Element* currentRoot = selection.rootEditableElement(); | 941 Element* currentRoot = selection.rootEditableElement(); |
942 | 942 |
943 if ((selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph && !
startIsInsideMailBlockquote) || | 943 if ((selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph && !
startIsInsideMailBlockquote) || |
944 enclosingBlockOfVisibleStart == currentRoot || isListItem(enclosingBlock
OfVisibleStart) || selectionIsPlainText) | 944 enclosingBlockOfVisibleStart == currentRoot || isListItem(enclosingBlock
OfVisibleStart) || selectionIsPlainText) |
945 m_preventNesting = false; | 945 m_preventNesting = false; |
946 | 946 |
947 if (selection.isRange()) { | 947 if (selection.isRange()) { |
948 // When the end of the selection being pasted into is at the end of a pa
ragraph, and that selection | 948 // When the end of the selection being pasted into is at the end of a pa
ragraph, and that selection |
949 // spans multiple blocks, not merging may leave an empty line. | 949 // spans multiple blocks, not merging may leave an empty line. |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1215 setEndingSelection(endOfInsertedContent); | 1215 setEndingSelection(endOfInsertedContent); |
1216 Node* enclosingNode = enclosingBlock(endOfInsertedContent.deepEq
uivalent().deprecatedNode()); | 1216 Node* enclosingNode = enclosingBlock(endOfInsertedContent.deepEq
uivalent().deprecatedNode()); |
1217 if (isListItem(enclosingNode)) { | 1217 if (isListItem(enclosingNode)) { |
1218 RefPtrWillBeRawPtr<Node> newListItem = createListItemElement
(document()); | 1218 RefPtrWillBeRawPtr<Node> newListItem = createListItemElement
(document()); |
1219 insertNodeAfter(newListItem, enclosingNode); | 1219 insertNodeAfter(newListItem, enclosingNode); |
1220 setEndingSelection(VisiblePosition(firstPositionInNode(newLi
stItem.get()))); | 1220 setEndingSelection(VisiblePosition(firstPositionInNode(newLi
stItem.get()))); |
1221 } else { | 1221 } else { |
1222 // Use a default paragraph element (a plain div) for the emp
ty paragraph, using the last paragraph | 1222 // Use a default paragraph element (a plain div) for the emp
ty paragraph, using the last paragraph |
1223 // block's style seems to annoy users. | 1223 // block's style seems to annoy users. |
1224 insertParagraphSeparator(true, !startIsInsideMailBlockquote
&& highestEnclosingNodeOfType(endOfInsertedContent.deepEquivalent(), | 1224 insertParagraphSeparator(true, !startIsInsideMailBlockquote
&& highestEnclosingNodeOfType(endOfInsertedContent.deepEquivalent(), |
1225 isMailBlockquote, CannotCrossEditingBoundary, insertedNo
des.firstNodeInserted()->parentNode())); | 1225 isMailHTMLBlockquoteElement, CannotCrossEditingBoundary,
insertedNodes.firstNodeInserted()->parentNode())); |
1226 } | 1226 } |
1227 | 1227 |
1228 // Select up to the paragraph separator that was added. | 1228 // Select up to the paragraph separator that was added. |
1229 lastPositionToSelect = endingSelection().visibleStart().deepEqui
valent(); | 1229 lastPositionToSelect = endingSelection().visibleStart().deepEqui
valent(); |
1230 updateNodesInserted(lastPositionToSelect.deprecatedNode()); | 1230 updateNodesInserted(lastPositionToSelect.deprecatedNode()); |
1231 } | 1231 } |
1232 } else { | 1232 } else { |
1233 // Select up to the beginning of the next paragraph. | 1233 // Select up to the beginning of the next paragraph. |
1234 lastPositionToSelect = next.deepEquivalent().downstream(); | 1234 lastPositionToSelect = next.deepEquivalent().downstream(); |
1235 } | 1235 } |
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1528 void ReplaceSelectionCommand::trace(Visitor* visitor) | 1528 void ReplaceSelectionCommand::trace(Visitor* visitor) |
1529 { | 1529 { |
1530 visitor->trace(m_startOfInsertedContent); | 1530 visitor->trace(m_startOfInsertedContent); |
1531 visitor->trace(m_endOfInsertedContent); | 1531 visitor->trace(m_endOfInsertedContent); |
1532 visitor->trace(m_insertionStyle); | 1532 visitor->trace(m_insertionStyle); |
1533 visitor->trace(m_documentFragment); | 1533 visitor->trace(m_documentFragment); |
1534 CompositeEditCommand::trace(visitor); | 1534 CompositeEditCommand::trace(visitor); |
1535 } | 1535 } |
1536 | 1536 |
1537 } // namespace blink | 1537 } // namespace blink |
OLD | NEW |