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

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

Issue 196683003: Use new is*Element() helper functions more in editing code (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/core/editing/MarkupAccumulator.cpp ('k') | Source/core/editing/SpellChecker.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved. 2 * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2009, 2010, 2011 Google Inc. All rights reserved. 3 * Copyright (C) 2009, 2010, 2011 Google Inc. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 90
91 RefPtr<Document> m_document; 91 RefPtr<Document> m_document;
92 RefPtr<DocumentFragment> m_fragment; 92 RefPtr<DocumentFragment> m_fragment;
93 bool m_hasInterchangeNewlineAtStart; 93 bool m_hasInterchangeNewlineAtStart;
94 bool m_hasInterchangeNewlineAtEnd; 94 bool m_hasInterchangeNewlineAtEnd;
95 }; 95 };
96 96
97 static bool isInterchangeNewlineNode(const Node *node) 97 static bool isInterchangeNewlineNode(const Node *node)
98 { 98 {
99 DEFINE_STATIC_LOCAL(String, interchangeNewlineClassString, (AppleInterchange Newline)); 99 DEFINE_STATIC_LOCAL(String, interchangeNewlineClassString, (AppleInterchange Newline));
100 return node && node->hasTagName(brTag) && toElement(node)->getAttribute(clas sAttr) == interchangeNewlineClassString; 100 return isHTMLBRElement(node) && toElement(node)->getAttribute(classAttr) == interchangeNewlineClassString;
101 } 101 }
102 102
103 static bool isInterchangeConvertedSpaceSpan(const Node *node) 103 static bool isInterchangeConvertedSpaceSpan(const Node *node)
104 { 104 {
105 DEFINE_STATIC_LOCAL(String, convertedSpaceSpanClassString, (AppleConvertedSp ace)); 105 DEFINE_STATIC_LOCAL(String, convertedSpaceSpanClassString, (AppleConvertedSp ace));
106 return node->isHTMLElement() && toHTMLElement(node)->getAttribute(classAttr) == convertedSpaceSpanClassString; 106 return node->isHTMLElement() && toHTMLElement(node)->getAttribute(classAttr) == convertedSpaceSpanClassString;
107 } 107 }
108 108
109 static Position positionAvoidingPrecedingNodes(Position pos) 109 static Position positionAvoidingPrecedingNodes(Position pos)
110 { 110 {
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 // For a successful merge, we still need to make sure that the inserted cont ent starts with the beginning of a paragraph. 392 // For a successful merge, we still need to make sure that the inserted cont ent starts with the beginning of a paragraph.
393 // And we should only merge here if the selection start was inside a mail bl ockquote. This prevents against removing a 393 // And we should only merge here if the selection start was inside a mail bl ockquote. This prevents against removing a
394 // blockquote from newly pasted quoted content that was pasted into an unquo ted position. If that unquoted position happens 394 // blockquote from newly pasted quoted content that was pasted into an unquo ted position. If that unquoted position happens
395 // to be right after another blockquote, we don't want to merge and risk str ipping a valid block (and newline) from the pasted content. 395 // to be right after another blockquote, we don't want to merge and risk str ipping a valid block (and newline) from the pasted content.
396 if (isStartOfParagraph(startOfInsertedContent) && selectionStartWasInsideMai lBlockquote && hasMatchingQuoteLevel(prev, positionAtEndOfInsertedContent())) 396 if (isStartOfParagraph(startOfInsertedContent) && selectionStartWasInsideMai lBlockquote && hasMatchingQuoteLevel(prev, positionAtEndOfInsertedContent()))
397 return true; 397 return true;
398 398
399 return !selectionStartWasStartOfParagraph 399 return !selectionStartWasStartOfParagraph
400 && !fragmentHasInterchangeNewlineAtStart 400 && !fragmentHasInterchangeNewlineAtStart
401 && isStartOfParagraph(startOfInsertedContent) 401 && isStartOfParagraph(startOfInsertedContent)
402 && !startOfInsertedContent.deepEquivalent().deprecatedNode()->hasTagName (brTag) 402 && !isHTMLBRElement(*startOfInsertedContent.deepEquivalent().deprecatedN ode())
403 && shouldMerge(startOfInsertedContent, prev); 403 && shouldMerge(startOfInsertedContent, prev);
404 } 404 }
405 405
406 bool ReplaceSelectionCommand::shouldMergeEnd(bool selectionEndWasEndOfParagraph) 406 bool ReplaceSelectionCommand::shouldMergeEnd(bool selectionEndWasEndOfParagraph)
407 { 407 {
408 VisiblePosition endOfInsertedContent(positionAtEndOfInsertedContent()); 408 VisiblePosition endOfInsertedContent(positionAtEndOfInsertedContent());
409 VisiblePosition next = endOfInsertedContent.next(CannotCrossEditingBoundary) ; 409 VisiblePosition next = endOfInsertedContent.next(CannotCrossEditingBoundary) ;
410 if (next.isNull()) 410 if (next.isNull())
411 return false; 411 return false;
412 412
413 return !selectionEndWasEndOfParagraph 413 return !selectionEndWasEndOfParagraph
414 && isEndOfParagraph(endOfInsertedContent) 414 && isEndOfParagraph(endOfInsertedContent)
415 && !endOfInsertedContent.deepEquivalent().deprecatedNode()->hasTagName(b rTag) 415 && !isHTMLBRElement(*endOfInsertedContent.deepEquivalent().deprecatedNod e())
416 && shouldMerge(endOfInsertedContent, next); 416 && shouldMerge(endOfInsertedContent, next);
417 } 417 }
418 418
419 static bool isMailPasteAsQuotationNode(const Node* node) 419 static bool isMailPasteAsQuotationNode(const Node* node)
420 { 420 {
421 return node && node->hasTagName(blockquoteTag) && node->isElementNode() && t oElement(node)->getAttribute(classAttr) == ApplePasteAsQuotation; 421 return node && node->hasTagName(blockquoteTag) && toElement(node)->getAttrib ute(classAttr) == ApplePasteAsQuotation;
422 } 422 }
423 423
424 static bool isHeaderElement(const Node* a) 424 static bool isHeaderElement(const Node* a)
425 { 425 {
426 if (!a) 426 if (!a)
427 return false; 427 return false;
428 428
429 return a->hasTagName(h1Tag) 429 return a->hasTagName(h1Tag)
430 || a->hasTagName(h2Tag) 430 || a->hasTagName(h2Tag)
431 || a->hasTagName(h3Tag) 431 || a->hasTagName(h3Tag)
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after
691 691
692 VisiblePosition ReplaceSelectionCommand::positionAtStartOfInsertedContent() cons t 692 VisiblePosition ReplaceSelectionCommand::positionAtStartOfInsertedContent() cons t
693 { 693 {
694 return VisiblePosition(m_startOfInsertedContent); 694 return VisiblePosition(m_startOfInsertedContent);
695 } 695 }
696 696
697 static void removeHeadContents(ReplacementFragment& fragment) 697 static void removeHeadContents(ReplacementFragment& fragment)
698 { 698 {
699 Node* next = 0; 699 Node* next = 0;
700 for (Node* node = fragment.firstChild(); node; node = next) { 700 for (Node* node = fragment.firstChild(); node; node = next) {
701 if (node->hasTagName(baseTag) 701 if (isHTMLBaseElement(*node)
702 || node->hasTagName(linkTag) 702 || isHTMLLinkElement(*node)
703 || node->hasTagName(metaTag) 703 || isHTMLMetaElement(*node)
704 || node->hasTagName(styleTag) 704 || isHTMLStyleElement(*node)
705 || node->hasTagName(titleTag)) { 705 || isHTMLTitleElement(*node)) {
706 next = NodeTraversal::nextSkippingChildren(*node); 706 next = NodeTraversal::nextSkippingChildren(*node);
707 fragment.removeNode(node); 707 fragment.removeNode(node);
708 } else { 708 } else {
709 next = NodeTraversal::next(*node); 709 next = NodeTraversal::next(*node);
710 } 710 }
711 } 711 }
712 } 712 }
713 713
714 // Remove style spans before insertion if they are unnecessary. It's faster bec ause we'll 714 // Remove style spans before insertion if they are unnecessary. It's faster bec ause we'll
715 // avoid doing a layout. 715 // avoid doing a layout.
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
833 m_endOfInsertedContent = endingSelection().visibleEnd().deepEquivalent( ); 833 m_endOfInsertedContent = endingSelection().visibleEnd().deepEquivalent( );
834 // If we merged text nodes, m_endOfInsertedContent could be null. If thi s is the case, we use m_startOfInsertedContent. 834 // If we merged text nodes, m_endOfInsertedContent could be null. If thi s is the case, we use m_startOfInsertedContent.
835 if (m_endOfInsertedContent.isNull()) 835 if (m_endOfInsertedContent.isNull())
836 m_endOfInsertedContent = m_startOfInsertedContent; 836 m_endOfInsertedContent = m_startOfInsertedContent;
837 } 837 }
838 } 838 }
839 839
840 static Node* enclosingInline(Node* node) 840 static Node* enclosingInline(Node* node)
841 { 841 {
842 while (ContainerNode* parent = node->parentNode()) { 842 while (ContainerNode* parent = node->parentNode()) {
843 if (parent->isBlockFlowElement() || parent->hasTagName(bodyTag)) 843 if (parent->isBlockFlowElement() || isHTMLBodyElement(*parent))
844 return node; 844 return node;
845 // Stop if any previous sibling is a block. 845 // Stop if any previous sibling is a block.
846 for (Node* sibling = node->previousSibling(); sibling; sibling = sibling ->previousSibling()) { 846 for (Node* sibling = node->previousSibling(); sibling; sibling = sibling ->previousSibling()) {
847 if (sibling->isBlockFlowElement()) 847 if (sibling->isBlockFlowElement())
848 return node; 848 return node;
849 } 849 }
850 node = parent; 850 node = parent;
851 } 851 }
852 return node; 852 return node;
853 } 853 }
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
964 insertionPos = endingSelection().start(); 964 insertionPos = endingSelection().start();
965 } 965 }
966 966
967 // We don't want any of the pasted content to end up nested in a Mail blockq uote, so first break 967 // We don't want any of the pasted content to end up nested in a Mail blockq uote, so first break
968 // out of any surrounding Mail blockquotes. Unless we're inserting in a tabl e, in which case 968 // out of any surrounding Mail blockquotes. Unless we're inserting in a tabl e, in which case
969 // breaking the blockquote will prevent the content from actually being inse rted in the table. 969 // breaking the blockquote will prevent the content from actually being inse rted in the table.
970 if (startIsInsideMailBlockquote && m_preventNesting && !(enclosingNodeOfType (insertionPos, &isTableStructureNode))) { 970 if (startIsInsideMailBlockquote && m_preventNesting && !(enclosingNodeOfType (insertionPos, &isTableStructureNode))) {
971 applyCommandToComposite(BreakBlockquoteCommand::create(document())); 971 applyCommandToComposite(BreakBlockquoteCommand::create(document()));
972 // This will leave a br between the split. 972 // This will leave a br between the split.
973 Node* br = endingSelection().start().deprecatedNode(); 973 Node* br = endingSelection().start().deprecatedNode();
974 ASSERT(br->hasTagName(brTag)); 974 ASSERT(isHTMLBRElement(br));
975 // Insert content between the two blockquotes, but remove the br (since it was just a placeholder). 975 // Insert content between the two blockquotes, but remove the br (since it was just a placeholder).
976 insertionPos = positionInParentBeforeNode(*br); 976 insertionPos = positionInParentBeforeNode(*br);
977 removeNode(br); 977 removeNode(br);
978 } 978 }
979 979
980 // Inserting content could cause whitespace to collapse, e.g. inserting <div >foo</div> into hello^ world. 980 // Inserting content could cause whitespace to collapse, e.g. inserting <div >foo</div> into hello^ world.
981 prepareWhitespaceAtPositionForSplit(insertionPos); 981 prepareWhitespaceAtPositionForSplit(insertionPos);
982 982
983 // If the downstream node has been removed there's no point in continuing. 983 // If the downstream node has been removed there's no point in continuing.
984 if (!insertionPos.downstream().deprecatedNode()) 984 if (!insertionPos.downstream().deprecatedNode())
985 return; 985 return;
986 986
987 // NOTE: This would be an incorrect usage of downstream() if downstream() we re changed to mean the last position after 987 // NOTE: This would be an incorrect usage of downstream() if downstream() we re changed to mean the last position after
988 // 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 988 // 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
989 // away, there are positions after the br which map to the same visible posi tion as [br, 0]). 989 // away, there are positions after the br which map to the same visible posi tion as [br, 0]).
990 Node* endBR = insertionPos.downstream().deprecatedNode()->hasTagName(brTag) ? insertionPos.downstream().deprecatedNode() : 0; 990 Node* endBR = isHTMLBRElement(*insertionPos.downstream().deprecatedNode()) ? insertionPos.downstream().deprecatedNode() : 0;
991 VisiblePosition originalVisPosBeforeEndBR; 991 VisiblePosition originalVisPosBeforeEndBR;
992 if (endBR) 992 if (endBR)
993 originalVisPosBeforeEndBR = VisiblePosition(positionBeforeNode(endBR), D OWNSTREAM).previous(); 993 originalVisPosBeforeEndBR = VisiblePosition(positionBeforeNode(endBR), D OWNSTREAM).previous();
994 994
995 RefPtr<Node> insertionBlock = enclosingBlock(insertionPos.deprecatedNode()); 995 RefPtr<Node> insertionBlock = enclosingBlock(insertionPos.deprecatedNode());
996 996
997 // Adjust insertionPos to prevent nesting. 997 // Adjust insertionPos to prevent nesting.
998 // If the start was in a Mail blockquote, we will have already handled adjus ting insertionPos above. 998 // If the start was in a Mail blockquote, we will have already handled adjus ting insertionPos above.
999 if (m_preventNesting && insertionBlock && !isTableCell(insertionBlock.get()) && !startIsInsideMailBlockquote) { 999 if (m_preventNesting && insertionBlock && !isTableCell(insertionBlock.get()) && !startIsInsideMailBlockquote) {
1000 ASSERT(insertionBlock != currentRoot); 1000 ASSERT(insertionBlock != currentRoot);
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after
1247 // A br that was originally acting as a line break should still be acting as a line break, not as a placeholder. 1247 // A br that was originally acting as a line break should still be acting as a line break, not as a placeholder.
1248 return isStartOfParagraph(visiblePos) && isEndOfParagraph(visiblePos); 1248 return isStartOfParagraph(visiblePos) && isEndOfParagraph(visiblePos);
1249 } 1249 }
1250 1250
1251 bool ReplaceSelectionCommand::shouldPerformSmartReplace() const 1251 bool ReplaceSelectionCommand::shouldPerformSmartReplace() const
1252 { 1252 {
1253 if (!m_smartReplace) 1253 if (!m_smartReplace)
1254 return false; 1254 return false;
1255 1255
1256 Element* textControl = enclosingTextFormControl(positionAtStartOfInsertedCon tent().deepEquivalent()); 1256 Element* textControl = enclosingTextFormControl(positionAtStartOfInsertedCon tent().deepEquivalent());
1257 if (textControl && textControl->hasTagName(inputTag) && toHTMLInputElement(t extControl)->isPasswordField()) 1257 if (isHTMLInputElement(textControl) && toHTMLInputElement(textControl)->isPa sswordField())
1258 return false; // Disable smart replace for password fields. 1258 return false; // Disable smart replace for password fields.
1259 1259
1260 return true; 1260 return true;
1261 } 1261 }
1262 1262
1263 static bool isCharacterSmartReplaceExemptConsideringNonBreakingSpace(UChar32 cha racter, bool previousCharacter) 1263 static bool isCharacterSmartReplaceExemptConsideringNonBreakingSpace(UChar32 cha racter, bool previousCharacter)
1264 { 1264 {
1265 return isCharacterSmartReplaceExempt(character == noBreakSpace ? ' ' : chara cter, previousCharacter); 1265 return isCharacterSmartReplaceExempt(character == noBreakSpace ? ' ' : chara cter, previousCharacter);
1266 } 1266 }
1267 1267
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after
1482 1482
1483 RefPtr<Node> nodeAfterInsertionPos = endingSelection().end().downstream().an chorNode(); 1483 RefPtr<Node> nodeAfterInsertionPos = endingSelection().end().downstream().an chorNode();
1484 Text* textNode = toText(fragment.firstChild()); 1484 Text* textNode = toText(fragment.firstChild());
1485 // Our fragment creation code handles tabs, spaces, and newlines, so we don' t have to worry about those here. 1485 // Our fragment creation code handles tabs, spaces, and newlines, so we don' t have to worry about those here.
1486 1486
1487 Position start = endingSelection().start(); 1487 Position start = endingSelection().start();
1488 Position end = replaceSelectedTextInNode(textNode->data()); 1488 Position end = replaceSelectedTextInNode(textNode->data());
1489 if (end.isNull()) 1489 if (end.isNull())
1490 return false; 1490 return false;
1491 1491
1492 if (nodeAfterInsertionPos && nodeAfterInsertionPos->parentNode() && nodeAfte rInsertionPos->hasTagName(brTag) 1492 if (nodeAfterInsertionPos && nodeAfterInsertionPos->parentNode() && isHTMLBR Element(*nodeAfterInsertionPos)
1493 && shouldRemoveEndBR(nodeAfterInsertionPos.get(), VisiblePosition(positi onBeforeNode(nodeAfterInsertionPos.get())))) 1493 && shouldRemoveEndBR(nodeAfterInsertionPos.get(), VisiblePosition(positi onBeforeNode(nodeAfterInsertionPos.get()))))
1494 removeNodeAndPruneAncestors(nodeAfterInsertionPos.get()); 1494 removeNodeAndPruneAncestors(nodeAfterInsertionPos.get());
1495 1495
1496 VisibleSelection selectionAfterReplace(m_selectReplacement ? start : end, en d); 1496 VisibleSelection selectionAfterReplace(m_selectReplacement ? start : end, en d);
1497 1497
1498 setEndingSelection(selectionAfterReplace); 1498 setEndingSelection(selectionAfterReplace);
1499 1499
1500 return true; 1500 return true;
1501 } 1501 }
1502 1502
1503 } // namespace WebCore 1503 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/core/editing/MarkupAccumulator.cpp ('k') | Source/core/editing/SpellChecker.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698