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 30 matching lines...) Expand all Loading... | |
| 41 #include "core/editing/FrameSelection.h" | 41 #include "core/editing/FrameSelection.h" |
| 42 #include "core/editing/HTMLInterchange.h" | 42 #include "core/editing/HTMLInterchange.h" |
| 43 #include "core/editing/SimplifyMarkupCommand.h" | 43 #include "core/editing/SimplifyMarkupCommand.h" |
| 44 #include "core/editing/SmartReplace.h" | 44 #include "core/editing/SmartReplace.h" |
| 45 #include "core/editing/TextIterator.h" | 45 #include "core/editing/TextIterator.h" |
| 46 #include "core/editing/VisibleUnits.h" | 46 #include "core/editing/VisibleUnits.h" |
| 47 #include "core/editing/htmlediting.h" | 47 #include "core/editing/htmlediting.h" |
| 48 #include "core/editing/markup.h" | 48 #include "core/editing/markup.h" |
| 49 #include "core/events/BeforeTextInsertedEvent.h" | 49 #include "core/events/BeforeTextInsertedEvent.h" |
| 50 #include "core/frame/LocalFrame.h" | 50 #include "core/frame/LocalFrame.h" |
| 51 #include "core/frame/UseCounter.h" | |
| 51 #include "core/html/HTMLElement.h" | 52 #include "core/html/HTMLElement.h" |
| 52 #include "core/html/HTMLInputElement.h" | 53 #include "core/html/HTMLInputElement.h" |
| 53 #include "core/rendering/RenderObject.h" | 54 #include "core/rendering/RenderObject.h" |
| 54 #include "core/rendering/RenderText.h" | 55 #include "core/rendering/RenderText.h" |
| 55 #include "wtf/StdLibExtras.h" | 56 #include "wtf/StdLibExtras.h" |
| 56 #include "wtf/Vector.h" | 57 #include "wtf/Vector.h" |
| 57 | 58 |
| 58 namespace WebCore { | 59 namespace WebCore { |
| 59 | 60 |
| 60 using namespace HTMLNames; | 61 using namespace HTMLNames; |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 282 void ReplacementFragment::removeInterchangeNodes(Node* container) | 283 void ReplacementFragment::removeInterchangeNodes(Node* container) |
| 283 { | 284 { |
| 284 m_hasInterchangeNewlineAtStart = false; | 285 m_hasInterchangeNewlineAtStart = false; |
| 285 m_hasInterchangeNewlineAtEnd = false; | 286 m_hasInterchangeNewlineAtEnd = false; |
| 286 | 287 |
| 287 // Interchange newlines at the "start" of the incoming fragment must be | 288 // Interchange newlines at the "start" of the incoming fragment must be |
| 288 // either the first node in the fragment or the first leaf in the fragment. | 289 // either the first node in the fragment or the first leaf in the fragment. |
| 289 Node* node = container->firstChild(); | 290 Node* node = container->firstChild(); |
| 290 while (node) { | 291 while (node) { |
| 291 if (isInterchangeNewlineNode(node)) { | 292 if (isInterchangeNewlineNode(node)) { |
| 293 UseCounter::count(node->document(), UseCounter::EditingAppleIntercha ngeNewline); | |
|
Yuta Kitamura
2014/06/12 07:55:23
You add some count() calls in predicate functions
yosin_UTC9
2014/06/12 08:46:06
You're right. I move count() call to predicate.
| |
| 292 m_hasInterchangeNewlineAtStart = true; | 294 m_hasInterchangeNewlineAtStart = true; |
| 293 removeNode(node); | 295 removeNode(node); |
| 294 break; | 296 break; |
| 295 } | 297 } |
| 296 node = node->firstChild(); | 298 node = node->firstChild(); |
| 297 } | 299 } |
| 298 if (!container->hasChildren()) | 300 if (!container->hasChildren()) |
| 299 return; | 301 return; |
| 300 // Interchange newlines at the "end" of the incoming fragment must be | 302 // Interchange newlines at the "end" of the incoming fragment must be |
| 301 // either the last node in the fragment or the last leaf in the fragment. | 303 // either the last node in the fragment or the last leaf in the fragment. |
| 302 node = container->lastChild(); | 304 node = container->lastChild(); |
| 303 while (node) { | 305 while (node) { |
| 304 if (isInterchangeNewlineNode(node)) { | 306 if (isInterchangeNewlineNode(node)) { |
| 307 UseCounter::count(node->document(), UseCounter::EditingAppleIntercha ngeNewline); | |
| 305 m_hasInterchangeNewlineAtEnd = true; | 308 m_hasInterchangeNewlineAtEnd = true; |
| 306 removeNode(node); | 309 removeNode(node); |
| 307 break; | 310 break; |
| 308 } | 311 } |
| 309 node = node->lastChild(); | 312 node = node->lastChild(); |
| 310 } | 313 } |
| 311 | 314 |
| 312 node = container->firstChild(); | 315 node = container->firstChild(); |
| 313 while (node) { | 316 while (node) { |
| 314 RefPtrWillBeRawPtr<Node> next = NodeTraversal::next(*node); | 317 RefPtrWillBeRawPtr<Node> next = NodeTraversal::next(*node); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 411 return false; | 414 return false; |
| 412 | 415 |
| 413 return !selectionEndWasEndOfParagraph | 416 return !selectionEndWasEndOfParagraph |
| 414 && isEndOfParagraph(endOfInsertedContent) | 417 && isEndOfParagraph(endOfInsertedContent) |
| 415 && !isHTMLBRElement(*endOfInsertedContent.deepEquivalent().deprecatedNod e()) | 418 && !isHTMLBRElement(*endOfInsertedContent.deepEquivalent().deprecatedNod e()) |
| 416 && shouldMerge(endOfInsertedContent, next); | 419 && shouldMerge(endOfInsertedContent, next); |
| 417 } | 420 } |
| 418 | 421 |
| 419 static bool isMailPasteAsQuotationNode(const Node* node) | 422 static bool isMailPasteAsQuotationNode(const Node* node) |
| 420 { | 423 { |
| 421 return node && node->hasTagName(blockquoteTag) && toElement(node)->getAttrib ute(classAttr) == ApplePasteAsQuotation; | 424 if (!node || !node->hasTagName(blockquoteTag) || toElement(node)->getAttribu te(classAttr) != ApplePasteAsQuotation) |
| 425 return false; | |
| 426 UseCounter::count(node->document(), UseCounter::EditingApplePasteAsQuotation ); | |
| 427 return true; | |
| 422 } | 428 } |
| 423 | 429 |
| 424 static bool isHeaderElement(const Node* a) | 430 static bool isHeaderElement(const Node* a) |
| 425 { | 431 { |
| 426 if (!a) | 432 if (!a) |
| 427 return false; | 433 return false; |
| 428 | 434 |
| 429 return a->hasTagName(h1Tag) | 435 return a->hasTagName(h1Tag) |
| 430 || a->hasTagName(h2Tag) | 436 || a->hasTagName(h2Tag) |
| 431 || a->hasTagName(h3Tag) | 437 || a->hasTagName(h3Tag) |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 525 removeNodePreservingChildren(element); | 531 removeNodePreservingChildren(element); |
| 526 continue; | 532 continue; |
| 527 } | 533 } |
| 528 | 534 |
| 529 if (element->parentNode() && element->parentNode()->rendererIsRichlyEdit able()) | 535 if (element->parentNode() && element->parentNode()->rendererIsRichlyEdit able()) |
| 530 removeNodeAttribute(element, contenteditableAttr); | 536 removeNodeAttribute(element, contenteditableAttr); |
| 531 | 537 |
| 532 // WebKit used to not add display: inline and float: none on copy. | 538 // WebKit used to not add display: inline and float: none on copy. |
| 533 // Keep this code around for backward compatibility | 539 // Keep this code around for backward compatibility |
| 534 if (isLegacyAppleStyleSpan(element)) { | 540 if (isLegacyAppleStyleSpan(element)) { |
| 541 UseCounter::count(document(), UseCounter::EditingAppleStyleSpanClass ); | |
| 535 if (!element->firstChild()) { | 542 if (!element->firstChild()) { |
| 536 insertedNodes.willRemoveNodePreservingChildren(*element); | 543 insertedNodes.willRemoveNodePreservingChildren(*element); |
| 537 removeNodePreservingChildren(element); | 544 removeNodePreservingChildren(element); |
| 538 continue; | 545 continue; |
| 539 } | 546 } |
| 540 // There are other styles that style rules can give to style spans, | 547 // There are other styles that style rules can give to style spans, |
| 541 // but these are the two important ones because they'll prevent | 548 // but these are the two important ones because they'll prevent |
| 542 // inserted content from appearing in the right paragraph. | 549 // inserted content from appearing in the right paragraph. |
| 543 // FIXME: Hyatt is concerned that selectively using display:inline w ill give inconsistent | 550 // FIXME: Hyatt is concerned that selectively using display:inline w ill give inconsistent |
| 544 // results. We already know one issue because td elements ignore the ir display property | 551 // results. We already know one issue because td elements ignore the ir display property |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 721 // Handling the case where we are doing Paste as Quotation or pasting into q uoted content is more complicated (see handleStyleSpans) | 728 // Handling the case where we are doing Paste as Quotation or pasting into q uoted content is more complicated (see handleStyleSpans) |
| 722 // and doesn't receive the optimization. | 729 // and doesn't receive the optimization. |
| 723 if (isMailPasteAsQuotationNode(topNode) || enclosingNodeOfType(firstPosition InOrBeforeNode(topNode), isMailBlockquote, CanCrossEditingBoundary)) | 730 if (isMailPasteAsQuotationNode(topNode) || enclosingNodeOfType(firstPosition InOrBeforeNode(topNode), isMailBlockquote, CanCrossEditingBoundary)) |
| 724 return false; | 731 return false; |
| 725 | 732 |
| 726 // Either there are no style spans in the fragment or a WebKit client has ad ded content to the fragment | 733 // Either there are no style spans in the fragment or a WebKit client has ad ded content to the fragment |
| 727 // before inserting it. Look for and handle style spans after insertion. | 734 // before inserting it. Look for and handle style spans after insertion. |
| 728 if (!isLegacyAppleStyleSpan(topNode)) | 735 if (!isLegacyAppleStyleSpan(topNode)) |
| 729 return false; | 736 return false; |
| 730 | 737 |
| 738 UseCounter::count(topNode->document(), UseCounter::EditingAppleStyleSpanClas s); | |
| 731 Node* wrappingStyleSpan = topNode; | 739 Node* wrappingStyleSpan = topNode; |
| 732 RefPtrWillBeRawPtr<EditingStyle> styleAtInsertionPos = EditingStyle::create( insertionPos.parentAnchoredEquivalent()); | 740 RefPtrWillBeRawPtr<EditingStyle> styleAtInsertionPos = EditingStyle::create( insertionPos.parentAnchoredEquivalent()); |
| 733 String styleText = styleAtInsertionPos->style()->asText(); | 741 String styleText = styleAtInsertionPos->style()->asText(); |
| 734 | 742 |
| 735 // FIXME: This string comparison is a naive way of comparing two styles. | 743 // FIXME: This string comparison is a naive way of comparing two styles. |
| 736 // We should be taking the diff and check that the diff is empty. | 744 // We should be taking the diff and check that the diff is empty. |
| 737 if (styleText != toElement(wrappingStyleSpan)->getAttribute(styleAttr)) | 745 if (styleText != toElement(wrappingStyleSpan)->getAttribute(styleAttr)) |
| 738 return false; | 746 return false; |
| 739 | 747 |
| 740 fragment.removeNodePreservingChildren(wrappingStyleSpan); | 748 fragment.removeNodePreservingChildren(wrappingStyleSpan); |
| 741 return true; | 749 return true; |
| 742 } | 750 } |
| 743 | 751 |
| 744 // At copy time, WebKit wraps copied content in a span that contains the source document's | 752 // At copy time, WebKit wraps copied content in a span that contains the source document's |
| 745 // default styles. If the copied Range inherits any other styles from its ances tors, we put | 753 // default styles. If the copied Range inherits any other styles from its ances tors, we put |
| 746 // those styles on a second span. | 754 // those styles on a second span. |
| 747 // This function removes redundant styles from those spans, and removes the span s if all their | 755 // This function removes redundant styles from those spans, and removes the span s if all their |
| 748 // styles are redundant. | 756 // styles are redundant. |
| 749 // We should remove the Apple-style-span class when we're done, see <rdar://prob lem/5685600>. | 757 // We should remove the Apple-style-span class when we're done, see <rdar://prob lem/5685600>. |
| 750 // We should remove styles from spans that are overridden by all of their childr en, either here | 758 // We should remove styles from spans that are overridden by all of their childr en, either here |
| 751 // or at copy time. | 759 // or at copy time. |
| 752 void ReplaceSelectionCommand::handleStyleSpans(InsertedNodes& insertedNodes) | 760 void ReplaceSelectionCommand::handleStyleSpans(InsertedNodes& insertedNodes) |
| 753 { | 761 { |
| 754 HTMLElement* wrappingStyleSpan = 0; | 762 HTMLElement* wrappingStyleSpan = 0; |
| 755 // The style span that contains the source document's default style should b e at | 763 // The style span that contains the source document's default style should b e at |
| 756 // the top of the fragment, but Mail sometimes adds a wrapper (for Paste As Quotation), | 764 // the top of the fragment, but Mail sometimes adds a wrapper (for Paste As Quotation), |
| 757 // so search for the top level style span instead of assuming it's at the to p. | 765 // so search for the top level style span instead of assuming it's at the to p. |
| 758 for (Node* node = insertedNodes.firstNodeInserted(); node; node = NodeTraver sal::next(*node)) { | 766 for (Node* node = insertedNodes.firstNodeInserted(); node; node = NodeTraver sal::next(*node)) { |
| 759 if (isLegacyAppleStyleSpan(node)) { | 767 if (isLegacyAppleStyleSpan(node)) { |
| 768 UseCounter::count(document(), UseCounter::EditingAppleStyleSpanClass ); | |
| 760 wrappingStyleSpan = toHTMLElement(node); | 769 wrappingStyleSpan = toHTMLElement(node); |
| 761 break; | 770 break; |
| 762 } | 771 } |
| 763 } | 772 } |
| 764 | 773 |
| 765 // There might not be any style spans if we're pasting from another applicat ion or if | 774 // There might not be any style spans if we're pasting from another applicat ion or if |
| 766 // we are here because of a document.execCommand("InsertHTML", ...) call. | 775 // we are here because of a document.execCommand("InsertHTML", ...) call. |
| 767 if (!wrappingStyleSpan) | 776 if (!wrappingStyleSpan) |
| 768 return; | 777 return; |
| 769 | 778 |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 859 if (isBlock(node)) | 868 if (isBlock(node)) |
| 860 return false; | 869 return false; |
| 861 | 870 |
| 862 if (!node->isHTMLElement()) | 871 if (!node->isHTMLElement()) |
| 863 return false; | 872 return false; |
| 864 | 873 |
| 865 // We can skip over elements whose class attribute is | 874 // We can skip over elements whose class attribute is |
| 866 // one of our internal classes. | 875 // one of our internal classes. |
| 867 const HTMLElement* element = toHTMLElement(node); | 876 const HTMLElement* element = toHTMLElement(node); |
| 868 const AtomicString& classAttributeValue = element->getAttribute(classAttr); | 877 const AtomicString& classAttributeValue = element->getAttribute(classAttr); |
| 869 if (classAttributeValue == AppleTabSpanClass | 878 if (classAttributeValue == AppleTabSpanClass) { |
| 870 || classAttributeValue == AppleConvertedSpace | 879 UseCounter::count(node->document(), UseCounter::EditingAppleTabSpanClass ); |
| 871 || classAttributeValue == ApplePasteAsQuotation) | |
| 872 return true; | 880 return true; |
| 881 } | |
| 882 if (classAttributeValue == AppleConvertedSpace) { | |
| 883 UseCounter::count(node->document(), UseCounter::EditingAppleConvertedSpa ce); | |
| 884 return true; | |
| 885 } | |
| 886 if (classAttributeValue == ApplePasteAsQuotation) { | |
| 887 UseCounter::count(node->document(), UseCounter::EditingApplePasteAsQuota tion); | |
| 888 return true; | |
| 889 } | |
| 873 | 890 |
| 874 return EditingStyle::elementIsStyledSpanOrHTMLEquivalent(element); | 891 return EditingStyle::elementIsStyledSpanOrHTMLEquivalent(element); |
| 875 } | 892 } |
| 876 | 893 |
| 877 inline Node* nodeToSplitToAvoidPastingIntoInlineNodesWithStyle(const Position& i nsertionPos) | 894 inline Node* nodeToSplitToAvoidPastingIntoInlineNodesWithStyle(const Position& i nsertionPos) |
| 878 { | 895 { |
| 879 Node* containgBlock = enclosingBlock(insertionPos.containerNode()); | 896 Node* containgBlock = enclosingBlock(insertionPos.containerNode()); |
| 880 return highestEnclosingNodeOfType(insertionPos, isInlineNodeWithStyle, Canno tCrossEditingBoundary, containgBlock); | 897 return highestEnclosingNodeOfType(insertionPos, isInlineNodeWithStyle, Canno tCrossEditingBoundary, containgBlock); |
| 881 } | 898 } |
| 882 | 899 |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1068 | 1085 |
| 1069 InsertedNodes insertedNodes; | 1086 InsertedNodes insertedNodes; |
| 1070 RefPtrWillBeRawPtr<Node> refNode = fragment.firstChild(); | 1087 RefPtrWillBeRawPtr<Node> refNode = fragment.firstChild(); |
| 1071 ASSERT(refNode); | 1088 ASSERT(refNode); |
| 1072 RefPtrWillBeRawPtr<Node> node = refNode->nextSibling(); | 1089 RefPtrWillBeRawPtr<Node> node = refNode->nextSibling(); |
| 1073 | 1090 |
| 1074 fragment.removeNode(refNode); | 1091 fragment.removeNode(refNode); |
| 1075 | 1092 |
| 1076 Node* blockStart = enclosingBlock(insertionPos.deprecatedNode()); | 1093 Node* blockStart = enclosingBlock(insertionPos.deprecatedNode()); |
| 1077 if ((isListElement(refNode.get()) || (isLegacyAppleStyleSpan(refNode.get()) && isListElement(refNode->firstChild()))) | 1094 if ((isListElement(refNode.get()) || (isLegacyAppleStyleSpan(refNode.get()) && isListElement(refNode->firstChild()))) |
| 1078 && blockStart && blockStart->renderer()->isListItem()) | 1095 && blockStart && blockStart->renderer()->isListItem()) { |
| 1096 if (isLegacyAppleStyleSpan(refNode.get())) | |
| 1097 UseCounter::count(document(), UseCounter::EditingAppleStyleSpanClass ); | |
| 1079 refNode = insertAsListItems(toHTMLElement(refNode), blockStart, insertio nPos, insertedNodes); | 1098 refNode = insertAsListItems(toHTMLElement(refNode), blockStart, insertio nPos, insertedNodes); |
| 1080 else { | 1099 } else { |
| 1081 insertNodeAt(refNode, insertionPos); | 1100 insertNodeAt(refNode, insertionPos); |
| 1082 insertedNodes.respondToNodeInsertion(*refNode); | 1101 insertedNodes.respondToNodeInsertion(*refNode); |
| 1083 } | 1102 } |
| 1084 | 1103 |
| 1085 // Mutation events (bug 22634) may have already removed the inserted content | 1104 // Mutation events (bug 22634) may have already removed the inserted content |
| 1086 if (!refNode->inDocument()) | 1105 if (!refNode->inDocument()) |
| 1087 return; | 1106 return; |
| 1088 | 1107 |
| 1089 bool plainTextFragment = isPlainTextMarkup(refNode.get()); | 1108 bool plainTextFragment = isPlainTextMarkup(refNode.get()); |
| 1090 | 1109 |
| (...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1506 void ReplaceSelectionCommand::trace(Visitor* visitor) | 1525 void ReplaceSelectionCommand::trace(Visitor* visitor) |
| 1507 { | 1526 { |
| 1508 visitor->trace(m_startOfInsertedContent); | 1527 visitor->trace(m_startOfInsertedContent); |
| 1509 visitor->trace(m_endOfInsertedContent); | 1528 visitor->trace(m_endOfInsertedContent); |
| 1510 visitor->trace(m_insertionStyle); | 1529 visitor->trace(m_insertionStyle); |
| 1511 visitor->trace(m_documentFragment); | 1530 visitor->trace(m_documentFragment); |
| 1512 CompositeEditCommand::trace(visitor); | 1531 CompositeEditCommand::trace(visitor); |
| 1513 } | 1532 } |
| 1514 | 1533 |
| 1515 } // namespace WebCore | 1534 } // namespace WebCore |
| OLD | NEW |