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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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/frame/UseCounter.h" | 
| 52 #include "core/html/HTMLBRElement.h" | 52 #include "core/html/HTMLBRElement.h" | 
| 53 #include "core/html/HTMLElement.h" | 53 #include "core/html/HTMLElement.h" | 
| 54 #include "core/html/HTMLInputElement.h" | 54 #include "core/html/HTMLInputElement.h" | 
| 55 #include "core/html/HTMLLIElement.h" | 55 #include "core/html/HTMLLIElement.h" | 
| 56 #include "core/html/HTMLQuoteElement.h" | |
| 57 #include "core/html/HTMLSelectElement.h" | |
| 56 #include "core/html/HTMLSpanElement.h" | 58 #include "core/html/HTMLSpanElement.h" | 
| 57 #include "core/rendering/RenderObject.h" | 59 #include "core/rendering/RenderObject.h" | 
| 58 #include "core/rendering/RenderText.h" | 60 #include "core/rendering/RenderText.h" | 
| 59 #include "wtf/StdLibExtras.h" | 61 #include "wtf/StdLibExtras.h" | 
| 60 #include "wtf/Vector.h" | 62 #include "wtf/Vector.h" | 
| 61 | 63 | 
| 62 namespace blink { | 64 namespace blink { | 
| 63 | 65 | 
| 64 using namespace HTMLNames; | 66 using namespace HTMLNames; | 
| 65 | 67 | 
| 66 enum EFragmentType { EmptyFragment, SingleTextNodeFragment, TreeFragment }; | 68 enum EFragmentType { EmptyFragment, SingleTextNodeFragment, TreeFragment }; | 
| 67 | 69 | 
| 68 // --- ReplacementFragment helper class | 70 // --- ReplacementFragment helper class | 
| 69 | 71 | 
| 70 class ReplacementFragment FINAL { | 72 class ReplacementFragment FINAL { | 
| 71 WTF_MAKE_NONCOPYABLE(ReplacementFragment); | 73 WTF_MAKE_NONCOPYABLE(ReplacementFragment); | 
| 72 STACK_ALLOCATED(); | 74 STACK_ALLOCATED(); | 
| 73 public: | 75 public: | 
| 74 ReplacementFragment(Document*, DocumentFragment*, const VisibleSelection&); | 76 ReplacementFragment(Document*, DocumentFragment*, const VisibleSelection&); | 
| 75 | 77 | 
| 76 Node* firstChild() const; | 78 Node* firstChild() const; | 
| 77 Node* lastChild() const; | 79 Node* lastChild() const; | 
| 78 | 80 | 
| 79 bool isEmpty() const; | 81 bool isEmpty() const; | 
| 80 | 82 | 
| 81 bool hasInterchangeNewlineAtStart() const { return m_hasInterchangeNewlineAt Start; } | 83 bool hasInterchangeNewlineAtStart() const { return m_hasInterchangeNewlineAt Start; } | 
| 82 bool hasInterchangeNewlineAtEnd() const { return m_hasInterchangeNewlineAtEn d; } | 84 bool hasInterchangeNewlineAtEnd() const { return m_hasInterchangeNewlineAtEn d; } | 
| 83 | 85 | 
| 84 void removeNode(PassRefPtrWillBeRawPtr<Node>); | 86 void removeNode(PassRefPtrWillBeRawPtr<Node>); | 
| 85 void removeNodePreservingChildren(PassRefPtrWillBeRawPtr<Node>); | 87 void removeNodePreservingChildren(PassRefPtrWillBeRawPtr<ContainerNode>); | 
| 86 | 88 | 
| 87 private: | 89 private: | 
| 88 PassRefPtrWillBeRawPtr<Element> insertFragmentForTestRendering(Node* rootEdi tableNode); | 90 PassRefPtrWillBeRawPtr<HTMLElement> insertFragmentForTestRendering(Element* rootEditableElement); | 
| 89 void removeUnrenderedNodes(Node*); | 91 void removeUnrenderedNodes(ContainerNode*); | 
| 90 void restoreAndRemoveTestRenderingNodesToFragment(Element*); | 92 void restoreAndRemoveTestRenderingNodesToFragment(ContainerNode*); | 
| 
 
leviw_travelin_and_unemployed
2014/08/06 20:58:07
This is less tight typing. Why?
 
Inactive
2014/08/06 21:00:05
Hmm, This is a very good question. It looks like a
 
Inactive
2014/08/06 21:07:49
I probably changed it to HTMLElement*, then notice
 
 | |
| 91 void removeInterchangeNodes(Node*); | 93 void removeInterchangeNodes(ContainerNode*); | 
| 92 | 94 | 
| 93 void insertNodeBefore(PassRefPtrWillBeRawPtr<Node>, Node* refNode); | 95 void insertNodeBefore(PassRefPtrWillBeRawPtr<Node>, Node* refNode); | 
| 94 | 96 | 
| 95 RefPtrWillBeMember<Document> m_document; | 97 RefPtrWillBeMember<Document> m_document; | 
| 96 RefPtrWillBeMember<DocumentFragment> m_fragment; | 98 RefPtrWillBeMember<DocumentFragment> m_fragment; | 
| 97 bool m_hasInterchangeNewlineAtStart; | 99 bool m_hasInterchangeNewlineAtStart; | 
| 98 bool m_hasInterchangeNewlineAtEnd; | 100 bool m_hasInterchangeNewlineAtEnd; | 
| 99 }; | 101 }; | 
| 100 | 102 | 
| 101 static bool isInterchangeNewlineNode(const Node *node) | 103 static bool isInterchangeHTMLBRElement(const Node* node) | 
| 102 { | 104 { | 
| 103 DEFINE_STATIC_LOCAL(String, interchangeNewlineClassString, (AppleInterchange Newline)); | 105 DEFINE_STATIC_LOCAL(String, interchangeNewlineClassString, (AppleInterchange Newline)); | 
| 104 if (!isHTMLBRElement(node) || toElement(node)->getAttribute(classAttr) != in terchangeNewlineClassString) | 106 if (!isHTMLBRElement(node) || toHTMLBRElement(node)->getAttribute(classAttr) != interchangeNewlineClassString) | 
| 105 return false; | 107 return false; | 
| 106 UseCounter::count(node->document(), UseCounter::EditingAppleInterchangeNewli ne); | 108 UseCounter::count(node->document(), UseCounter::EditingAppleInterchangeNewli ne); | 
| 107 return true; | 109 return true; | 
| 108 } | 110 } | 
| 109 | 111 | 
| 110 static bool isInterchangeConvertedSpaceSpan(const Node *node) | 112 static bool isHTMLInterchangeConvertedSpaceSpan(const Node* node) | 
| 111 { | 113 { | 
| 112 DEFINE_STATIC_LOCAL(String, convertedSpaceSpanClassString, (AppleConvertedSp ace)); | 114 DEFINE_STATIC_LOCAL(String, convertedSpaceSpanClassString, (AppleConvertedSp ace)); | 
| 113 if (!node->isHTMLElement() || toHTMLElement(node)->getAttribute(classAttr) ! = convertedSpaceSpanClassString) | 115 if (!node->isHTMLElement() || toHTMLElement(node)->getAttribute(classAttr) ! = convertedSpaceSpanClassString) | 
| 114 return false; | 116 return false; | 
| 115 UseCounter::count(node->document(), UseCounter::EditingAppleConvertedSpace); | 117 UseCounter::count(node->document(), UseCounter::EditingAppleConvertedSpace); | 
| 116 return true; | 118 return true; | 
| 117 } | 119 } | 
| 118 | 120 | 
| 119 static Position positionAvoidingPrecedingNodes(Position pos) | 121 static Position positionAvoidingPrecedingNodes(Position pos) | 
| 120 { | 122 { | 
| 121 // If we're already on a break, it's probably a placeholder and we shouldn't change our position. | 123 // If we're already on a break, it's probably a placeholder and we shouldn't change our position. | 
| 122 if (editingIgnoresContent(pos.deprecatedNode())) | 124 if (editingIgnoresContent(pos.deprecatedNode())) | 
| 123 return pos; | 125 return pos; | 
| 124 | 126 | 
| 125 // We also stop when changing block flow elements because even though the vi sual position is the | 127 // We also stop when changing block flow elements because even though the vi sual position is the | 
| 126 // same. E.g., | 128 // same. E.g., | 
| 127 // <div>foo^</div>^ | 129 // <div>foo^</div>^ | 
| 128 // The two positions above are the same visual position, but we want to stay in the same block. | 130 // The two positions above are the same visual position, but we want to stay in the same block. | 
| 129 Node* enclosingBlockNode = enclosingBlock(pos.containerNode()); | 131 Element* enclosingBlockElement = enclosingBlock(pos.containerNode()); | 
| 130 for (Position nextPosition = pos; nextPosition.containerNode() != enclosingB lockNode; pos = nextPosition) { | 132 for (Position nextPosition = pos; nextPosition.containerNode() != enclosingB lockElement; pos = nextPosition) { | 
| 131 if (lineBreakExistsAtPosition(pos)) | 133 if (lineBreakExistsAtPosition(pos)) | 
| 132 break; | 134 break; | 
| 133 | 135 | 
| 134 if (pos.containerNode()->nonShadowBoundaryParentNode()) | 136 if (pos.containerNode()->nonShadowBoundaryParentNode()) | 
| 135 nextPosition = positionInParentAfterNode(*pos.containerNode()); | 137 nextPosition = positionInParentAfterNode(*pos.containerNode()); | 
| 136 | 138 | 
| 137 if (nextPosition == pos | 139 if (nextPosition == pos | 
| 138 || enclosingBlock(nextPosition.containerNode()) != enclosingBlockNod e | 140 || enclosingBlock(nextPosition.containerNode()) != enclosingBlockEle ment | 
| 139 || VisiblePosition(pos) != VisiblePosition(nextPosition)) | 141 || VisiblePosition(pos) != VisiblePosition(nextPosition)) | 
| 140 break; | 142 break; | 
| 141 } | 143 } | 
| 142 return pos; | 144 return pos; | 
| 143 } | 145 } | 
| 144 | 146 | 
| 145 ReplacementFragment::ReplacementFragment(Document* document, DocumentFragment* f ragment, const VisibleSelection& selection) | 147 ReplacementFragment::ReplacementFragment(Document* document, DocumentFragment* f ragment, const VisibleSelection& selection) | 
| 146 : m_document(document), | 148 : m_document(document), | 
| 147 m_fragment(fragment), | 149 m_fragment(fragment), | 
| 148 m_hasInterchangeNewlineAtStart(false), | 150 m_hasInterchangeNewlineAtStart(false), | 
| 149 m_hasInterchangeNewlineAtEnd(false) | 151 m_hasInterchangeNewlineAtEnd(false) | 
| 150 { | 152 { | 
| 151 if (!m_document) | 153 if (!m_document) | 
| 152 return; | 154 return; | 
| 153 if (!m_fragment || !m_fragment->hasChildren()) | 155 if (!m_fragment || !m_fragment->hasChildren()) | 
| 154 return; | 156 return; | 
| 155 | 157 | 
| 156 RefPtrWillBeRawPtr<Element> editableRoot = selection.rootEditableElement(); | 158 RefPtrWillBeRawPtr<Element> editableRoot = selection.rootEditableElement(); | 
| 157 ASSERT(editableRoot); | 159 ASSERT(editableRoot); | 
| 158 if (!editableRoot) | 160 if (!editableRoot) | 
| 159 return; | 161 return; | 
| 160 | 162 | 
| 161 Node* shadowAncestorNode; | 163 Element* shadowAncestorElement; | 
| 162 if (editableRoot->isInShadowTree()) | 164 if (editableRoot->isInShadowTree()) | 
| 163 shadowAncestorNode = editableRoot->shadowHost(); | 165 shadowAncestorElement = editableRoot->shadowHost(); | 
| 164 else | 166 else | 
| 165 shadowAncestorNode = editableRoot.get(); | 167 shadowAncestorElement = editableRoot.get(); | 
| 166 | 168 | 
| 167 if (!editableRoot->getAttributeEventListener(EventTypeNames::webkitBeforeTex tInserted) && | 169 if (!editableRoot->getAttributeEventListener(EventTypeNames::webkitBeforeTex tInserted) | 
| 168 // FIXME: Remove these checks once textareas and textfields actually reg ister an event handler. | 170 // FIXME: Remove these checks once textareas and textfields actually reg ister an event handler. | 
| 169 !(shadowAncestorNode && shadowAncestorNode->renderer() && shadowAncestor Node->renderer()->isTextControl()) && | 171 && !(shadowAncestorElement && shadowAncestorElement->renderer() && shado wAncestorElement->renderer()->isTextControl()) | 
| 170 editableRoot->rendererIsRichlyEditable()) { | 172 && editableRoot->rendererIsRichlyEditable()) { | 
| 171 removeInterchangeNodes(m_fragment.get()); | 173 removeInterchangeNodes(m_fragment.get()); | 
| 172 return; | 174 return; | 
| 173 } | 175 } | 
| 174 | 176 | 
| 175 RefPtrWillBeRawPtr<Element> holder = insertFragmentForTestRendering(editable Root.get()); | 177 RefPtrWillBeRawPtr<HTMLElement> holder = insertFragmentForTestRendering(edit ableRoot.get()); | 
| 176 if (!holder) { | 178 if (!holder) { | 
| 177 removeInterchangeNodes(m_fragment.get()); | 179 removeInterchangeNodes(m_fragment.get()); | 
| 178 return; | 180 return; | 
| 179 } | 181 } | 
| 180 | 182 | 
| 181 RefPtrWillBeRawPtr<Range> range = VisibleSelection::selectionFromContentsOfN ode(holder.get()).toNormalizedRange(); | 183 RefPtrWillBeRawPtr<Range> range = VisibleSelection::selectionFromContentsOfN ode(holder.get()).toNormalizedRange(); | 
| 182 String text = plainText(range.get(), static_cast<TextIteratorBehavior>(TextI teratorEmitsOriginalText | TextIteratorIgnoresStyleVisibility)); | 184 String text = plainText(range.get(), static_cast<TextIteratorBehavior>(TextI teratorEmitsOriginalText | TextIteratorIgnoresStyleVisibility)); | 
| 183 | 185 | 
| 184 removeInterchangeNodes(holder.get()); | 186 removeInterchangeNodes(holder.get()); | 
| 185 removeUnrenderedNodes(holder.get()); | 187 removeUnrenderedNodes(holder.get()); | 
| (...skipping 14 matching lines...) Expand all Loading... | |
| 200 removeUnrenderedNodes(holder.get()); | 202 removeUnrenderedNodes(holder.get()); | 
| 201 restoreAndRemoveTestRenderingNodesToFragment(holder.get()); | 203 restoreAndRemoveTestRenderingNodesToFragment(holder.get()); | 
| 202 } | 204 } | 
| 203 } | 205 } | 
| 204 | 206 | 
| 205 bool ReplacementFragment::isEmpty() const | 207 bool ReplacementFragment::isEmpty() const | 
| 206 { | 208 { | 
| 207 return (!m_fragment || !m_fragment->hasChildren()) && !m_hasInterchangeNewli neAtStart && !m_hasInterchangeNewlineAtEnd; | 209 return (!m_fragment || !m_fragment->hasChildren()) && !m_hasInterchangeNewli neAtStart && !m_hasInterchangeNewlineAtEnd; | 
| 208 } | 210 } | 
| 209 | 211 | 
| 210 Node *ReplacementFragment::firstChild() const | 212 Node* ReplacementFragment::firstChild() const | 
| 211 { | 213 { | 
| 212 return m_fragment ? m_fragment->firstChild() : 0; | 214 return m_fragment ? m_fragment->firstChild() : 0; | 
| 213 } | 215 } | 
| 214 | 216 | 
| 215 Node *ReplacementFragment::lastChild() const | 217 Node* ReplacementFragment::lastChild() const | 
| 216 { | 218 { | 
| 217 return m_fragment ? m_fragment->lastChild() : 0; | 219 return m_fragment ? m_fragment->lastChild() : 0; | 
| 218 } | 220 } | 
| 219 | 221 | 
| 220 void ReplacementFragment::removeNodePreservingChildren(PassRefPtrWillBeRawPtr<No de> node) | 222 void ReplacementFragment::removeNodePreservingChildren(PassRefPtrWillBeRawPtr<Co ntainerNode> node) | 
| 221 { | 223 { | 
| 222 if (!node) | 224 if (!node) | 
| 223 return; | 225 return; | 
| 224 | 226 | 
| 225 while (RefPtrWillBeRawPtr<Node> n = node->firstChild()) { | 227 while (RefPtrWillBeRawPtr<Node> n = node->firstChild()) { | 
| 226 removeNode(n); | 228 removeNode(n); | 
| 227 insertNodeBefore(n.release(), node.get()); | 229 insertNodeBefore(n.release(), node.get()); | 
| 228 } | 230 } | 
| 229 removeNode(node); | 231 removeNode(node); | 
| 230 } | 232 } | 
| (...skipping 15 matching lines...) Expand all Loading... | |
| 246 if (!node || !refNode) | 248 if (!node || !refNode) | 
| 247 return; | 249 return; | 
| 248 | 250 | 
| 249 ContainerNode* parent = refNode->nonShadowBoundaryParentNode(); | 251 ContainerNode* parent = refNode->nonShadowBoundaryParentNode(); | 
| 250 if (!parent) | 252 if (!parent) | 
| 251 return; | 253 return; | 
| 252 | 254 | 
| 253 parent->insertBefore(node, refNode); | 255 parent->insertBefore(node, refNode); | 
| 254 } | 256 } | 
| 255 | 257 | 
| 256 PassRefPtrWillBeRawPtr<Element> ReplacementFragment::insertFragmentForTestRender ing(Node* rootEditableElement) | 258 PassRefPtrWillBeRawPtr<HTMLElement> ReplacementFragment::insertFragmentForTestRe ndering(Element* rootEditableElement) | 
| 257 { | 259 { | 
| 258 ASSERT(m_document); | 260 ASSERT(m_document); | 
| 259 RefPtrWillBeRawPtr<Element> holder = createDefaultParagraphElement(*m_docume nt.get()); | 261 RefPtrWillBeRawPtr<HTMLElement> holder = createDefaultParagraphElement(*m_do cument.get()); | 
| 260 | 262 | 
| 261 holder->appendChild(m_fragment); | 263 holder->appendChild(m_fragment); | 
| 262 rootEditableElement->appendChild(holder.get()); | 264 rootEditableElement->appendChild(holder.get()); | 
| 263 m_document->updateLayoutIgnorePendingStylesheets(); | 265 m_document->updateLayoutIgnorePendingStylesheets(); | 
| 264 | 266 | 
| 265 return holder.release(); | 267 return holder.release(); | 
| 266 } | 268 } | 
| 267 | 269 | 
| 268 void ReplacementFragment::restoreAndRemoveTestRenderingNodesToFragment(Element* holder) | 270 void ReplacementFragment::restoreAndRemoveTestRenderingNodesToFragment(Container Node* holder) | 
| 269 { | 271 { | 
| 270 if (!holder) | 272 if (!holder) | 
| 271 return; | 273 return; | 
| 272 | 274 | 
| 273 while (RefPtrWillBeRawPtr<Node> node = holder->firstChild()) { | 275 while (RefPtrWillBeRawPtr<Node> node = holder->firstChild()) { | 
| 274 holder->removeChild(node.get()); | 276 holder->removeChild(node.get()); | 
| 275 m_fragment->appendChild(node.get()); | 277 m_fragment->appendChild(node.get()); | 
| 276 } | 278 } | 
| 277 | 279 | 
| 278 removeNode(holder); | 280 removeNode(holder); | 
| 279 } | 281 } | 
| 280 | 282 | 
| 281 void ReplacementFragment::removeUnrenderedNodes(Node* holder) | 283 void ReplacementFragment::removeUnrenderedNodes(ContainerNode* holder) | 
| 282 { | 284 { | 
| 283 WillBeHeapVector<RefPtrWillBeMember<Node> > unrendered; | 285 WillBeHeapVector<RefPtrWillBeMember<Node> > unrendered; | 
| 284 | 286 | 
| 285 for (Node* node = holder->firstChild(); node; node = NodeTraversal::next(*no de, holder)) | 287 for (Node* node = holder->firstChild(); node; node = NodeTraversal::next(*no de, holder)) | 
| 286 if (!isNodeRendered(node) && !isTableStructureNode(node)) | 288 if (!isNodeRendered(node) && !isTableStructureNode(node)) | 
| 287 unrendered.append(node); | 289 unrendered.append(node); | 
| 288 | 290 | 
| 289 size_t n = unrendered.size(); | 291 size_t n = unrendered.size(); | 
| 290 for (size_t i = 0; i < n; ++i) | 292 for (size_t i = 0; i < n; ++i) | 
| 291 removeNode(unrendered[i]); | 293 removeNode(unrendered[i]); | 
| 292 } | 294 } | 
| 293 | 295 | 
| 294 void ReplacementFragment::removeInterchangeNodes(Node* container) | 296 void ReplacementFragment::removeInterchangeNodes(ContainerNode* container) | 
| 295 { | 297 { | 
| 296 m_hasInterchangeNewlineAtStart = false; | 298 m_hasInterchangeNewlineAtStart = false; | 
| 297 m_hasInterchangeNewlineAtEnd = false; | 299 m_hasInterchangeNewlineAtEnd = false; | 
| 298 | 300 | 
| 299 // Interchange newlines at the "start" of the incoming fragment must be | 301 // Interchange newlines at the "start" of the incoming fragment must be | 
| 300 // either the first node in the fragment or the first leaf in the fragment. | 302 // either the first node in the fragment or the first leaf in the fragment. | 
| 301 Node* node = container->firstChild(); | 303 Node* node = container->firstChild(); | 
| 302 while (node) { | 304 while (node) { | 
| 303 if (isInterchangeNewlineNode(node)) { | 305 if (isInterchangeHTMLBRElement(node)) { | 
| 304 m_hasInterchangeNewlineAtStart = true; | 306 m_hasInterchangeNewlineAtStart = true; | 
| 305 removeNode(node); | 307 removeNode(node); | 
| 306 break; | 308 break; | 
| 307 } | 309 } | 
| 308 node = node->firstChild(); | 310 node = node->firstChild(); | 
| 309 } | 311 } | 
| 310 if (!container->hasChildren()) | 312 if (!container->hasChildren()) | 
| 311 return; | 313 return; | 
| 312 // Interchange newlines at the "end" of the incoming fragment must be | 314 // Interchange newlines at the "end" of the incoming fragment must be | 
| 313 // either the last node in the fragment or the last leaf in the fragment. | 315 // either the last node in the fragment or the last leaf in the fragment. | 
| 314 node = container->lastChild(); | 316 node = container->lastChild(); | 
| 315 while (node) { | 317 while (node) { | 
| 316 if (isInterchangeNewlineNode(node)) { | 318 if (isInterchangeHTMLBRElement(node)) { | 
| 317 m_hasInterchangeNewlineAtEnd = true; | 319 m_hasInterchangeNewlineAtEnd = true; | 
| 318 removeNode(node); | 320 removeNode(node); | 
| 319 break; | 321 break; | 
| 320 } | 322 } | 
| 321 node = node->lastChild(); | 323 node = node->lastChild(); | 
| 322 } | 324 } | 
| 323 | 325 | 
| 324 node = container->firstChild(); | 326 node = container->firstChild(); | 
| 325 while (node) { | 327 while (node) { | 
| 326 RefPtrWillBeRawPtr<Node> next = NodeTraversal::next(*node); | 328 RefPtrWillBeRawPtr<Node> next = NodeTraversal::next(*node); | 
| 327 if (isInterchangeConvertedSpaceSpan(node)) { | 329 if (isHTMLInterchangeConvertedSpaceSpan(node)) { | 
| 328 next = NodeTraversal::nextSkippingChildren(*node); | 330 HTMLElement& element = toHTMLElement(*node); | 
| 329 removeNodePreservingChildren(node); | 331 next = NodeTraversal::nextSkippingChildren(element); | 
| 332 removeNodePreservingChildren(&element); | |
| 330 } | 333 } | 
| 331 node = next.get(); | 334 node = next.get(); | 
| 332 } | 335 } | 
| 333 } | 336 } | 
| 334 | 337 | 
| 335 inline void ReplaceSelectionCommand::InsertedNodes::respondToNodeInsertion(Node& node) | 338 inline void ReplaceSelectionCommand::InsertedNodes::respondToNodeInsertion(Node& node) | 
| 336 { | 339 { | 
| 337 if (!m_firstNodeInserted) | 340 if (!m_firstNodeInserted) | 
| 338 m_firstNodeInserted = &node; | 341 m_firstNodeInserted = &node; | 
| 339 | 342 | 
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 421 VisiblePosition next = endOfInsertedContent.next(CannotCrossEditingBoundary) ; | 424 VisiblePosition next = endOfInsertedContent.next(CannotCrossEditingBoundary) ; | 
| 422 if (next.isNull()) | 425 if (next.isNull()) | 
| 423 return false; | 426 return false; | 
| 424 | 427 | 
| 425 return !selectionEndWasEndOfParagraph | 428 return !selectionEndWasEndOfParagraph | 
| 426 && isEndOfParagraph(endOfInsertedContent) | 429 && isEndOfParagraph(endOfInsertedContent) | 
| 427 && !isHTMLBRElement(*endOfInsertedContent.deepEquivalent().deprecatedNod e()) | 430 && !isHTMLBRElement(*endOfInsertedContent.deepEquivalent().deprecatedNod e()) | 
| 428 && shouldMerge(endOfInsertedContent, next); | 431 && shouldMerge(endOfInsertedContent, next); | 
| 429 } | 432 } | 
| 430 | 433 | 
| 431 static bool isMailPasteAsQuotationNode(const Node* node) | 434 static bool isMailPasteAsQuotationHTMLBlockQuoteElement(const Node* node) | 
| 432 { | 435 { | 
| 433 if (!node || !node->hasTagName(blockquoteTag) || toElement(node)->getAttribu te(classAttr) != ApplePasteAsQuotation) | 436 if (!node || !node->isHTMLElement()) | 
| 437 return false; | |
| 438 const HTMLElement& element = toHTMLElement(*node); | |
| 439 if (!element.hasTagName(blockquoteTag) || element.getAttribute(classAttr) != ApplePasteAsQuotation) | |
| 434 return false; | 440 return false; | 
| 435 UseCounter::count(node->document(), UseCounter::EditingApplePasteAsQuotation ); | 441 UseCounter::count(node->document(), UseCounter::EditingApplePasteAsQuotation ); | 
| 436 return true; | 442 return true; | 
| 437 } | 443 } | 
| 438 | 444 | 
| 439 static bool isHeaderElement(const Node* a) | 445 static bool isHTMLHeaderElement(const Node* a) | 
| 440 { | 446 { | 
| 441 if (!a || !a->isHTMLElement()) | 447 if (!a || !a->isHTMLElement()) | 
| 442 return false; | 448 return false; | 
| 443 | 449 | 
| 444 const HTMLElement& element = toHTMLElement(*a); | 450 const HTMLElement& element = toHTMLElement(*a); | 
| 445 return element.hasTagName(h1Tag) | 451 return element.hasTagName(h1Tag) | 
| 446 || element.hasTagName(h2Tag) | 452 || element.hasTagName(h2Tag) | 
| 447 || element.hasTagName(h3Tag) | 453 || element.hasTagName(h3Tag) | 
| 448 || element.hasTagName(h4Tag) | 454 || element.hasTagName(h4Tag) | 
| 449 || element.hasTagName(h5Tag) | 455 || element.hasTagName(h5Tag) | 
| 450 || element.hasTagName(h6Tag); | 456 || element.hasTagName(h6Tag); | 
| 451 } | 457 } | 
| 452 | 458 | 
| 453 static bool haveSameTagName(Node* a, Node* b) | 459 static bool haveSameTagName(Element* a, Element* b) | 
| 454 { | 460 { | 
| 455 return a && b && a->isElementNode() && b->isElementNode() && toElement(a)->t agName() == toElement(b)->tagName(); | 461 return a && b && a->tagName() == b->tagName(); | 
| 456 } | 462 } | 
| 457 | 463 | 
| 458 bool ReplaceSelectionCommand::shouldMerge(const VisiblePosition& source, const V isiblePosition& destination) | 464 bool ReplaceSelectionCommand::shouldMerge(const VisiblePosition& source, const V isiblePosition& destination) | 
| 459 { | 465 { | 
| 460 if (source.isNull() || destination.isNull()) | 466 if (source.isNull() || destination.isNull()) | 
| 461 return false; | 467 return false; | 
| 462 | 468 | 
| 463 Node* sourceNode = source.deepEquivalent().deprecatedNode(); | 469 Node* sourceNode = source.deepEquivalent().deprecatedNode(); | 
| 464 Node* destinationNode = destination.deepEquivalent().deprecatedNode(); | 470 Node* destinationNode = destination.deepEquivalent().deprecatedNode(); | 
| 465 Element* sourceBlock = enclosingBlock(sourceNode); | 471 Element* sourceBlock = enclosingBlock(sourceNode); | 
| 466 Element* destinationBlock = enclosingBlock(destinationNode); | 472 Element* destinationBlock = enclosingBlock(destinationNode); | 
| 467 return !enclosingNodeOfType(source.deepEquivalent(), &isMailPasteAsQuotation Node) | 473 return !enclosingNodeOfType(source.deepEquivalent(), &isMailPasteAsQuotation HTMLBlockQuoteElement) | 
| 468 && sourceBlock && (!sourceBlock->hasTagName(blockquoteTag) || isMailHTML BlockquoteElement(sourceBlock)) | 474 && sourceBlock && (!sourceBlock->hasTagName(blockquoteTag) || isMailHTML BlockquoteElement(sourceBlock)) | 
| 469 && enclosingListChild(sourceBlock) == enclosingListChild(destinationNode ) | 475 && enclosingListChild(sourceBlock) == enclosingListChild(destinationNode ) | 
| 470 && enclosingTableCell(source.deepEquivalent()) == enclosingTableCell(des tination.deepEquivalent()) | 476 && enclosingTableCell(source.deepEquivalent()) == enclosingTableCell(des tination.deepEquivalent()) | 
| 471 && (!isHeaderElement(sourceBlock) || haveSameTagName(sourceBlock, destin ationBlock)) | 477 && (!isHTMLHeaderElement(sourceBlock) || haveSameTagName(sourceBlock, de stinationBlock)) | 
| 472 // Don't merge to or from a position before or after a block because it would | 478 // 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. | 479 // be a no-op and cause infinite recursion. | 
| 474 && !isBlock(sourceNode) && !isBlock(destinationNode); | 480 && !isBlock(sourceNode) && !isBlock(destinationNode); | 
| 475 } | 481 } | 
| 476 | 482 | 
| 477 // Style rules that match just inserted elements could change their appearance, like | 483 // Style rules that match just inserted elements could change their appearance, like | 
| 478 // a div inserted into a document with div { display:inline; }. | 484 // a div inserted into a document with div { display:inline; }. | 
| 479 void ReplaceSelectionCommand::removeRedundantStylesAndKeepStyleSpanInline(Insert edNodes& insertedNodes) | 485 void ReplaceSelectionCommand::removeRedundantStylesAndKeepStyleSpanInline(Insert edNodes& insertedNodes) | 
| 480 { | 486 { | 
| 481 RefPtrWillBeRawPtr<Node> pastEndNode = insertedNodes.pastLastLeaf(); | 487 RefPtrWillBeRawPtr<Node> pastEndNode = insertedNodes.pastLastLeaf(); | 
| (...skipping 17 matching lines...) Expand all Loading... | |
| 499 | 505 | 
| 500 if (newInlineStyle->conflictsWithImplicitStyleOfElement(htmlElem ent)) { | 506 if (newInlineStyle->conflictsWithImplicitStyleOfElement(htmlElem ent)) { | 
| 501 // e.g. <b style="font-weight: normal;"> is converted to <sp an style="font-weight: normal;"> | 507 // e.g. <b style="font-weight: normal;"> is converted to <sp an style="font-weight: normal;"> | 
| 502 element = replaceElementWithSpanPreservingChildrenAndAttribu tes(htmlElement); | 508 element = replaceElementWithSpanPreservingChildrenAndAttribu tes(htmlElement); | 
| 503 inlineStyle = element->inlineStyle(); | 509 inlineStyle = element->inlineStyle(); | 
| 504 insertedNodes.didReplaceNode(*htmlElement, *element); | 510 insertedNodes.didReplaceNode(*htmlElement, *element); | 
| 505 } else if (newInlineStyle->extractConflictingImplicitStyleOfAttr ibutes(htmlElement, EditingStyle::PreserveWritingDirection, 0, attributes, | 511 } else if (newInlineStyle->extractConflictingImplicitStyleOfAttr ibutes(htmlElement, EditingStyle::PreserveWritingDirection, 0, attributes, | 
| 506 EditingStyle::DoNotExtractMatchingStyle)) { | 512 EditingStyle::DoNotExtractMatchingStyle)) { | 
| 507 // e.g. <font size="3" style="font-size: 20px;"> is converte d to <font style="font-size: 20px;"> | 513 // e.g. <font size="3" style="font-size: 20px;"> is converte d to <font style="font-size: 20px;"> | 
| 508 for (size_t i = 0; i < attributes.size(); i++) | 514 for (size_t i = 0; i < attributes.size(); i++) | 
| 509 removeNodeAttribute(element, attributes[i]); | 515 removeElementAttribute(htmlElement, attributes[i]); | 
| 510 } | 516 } | 
| 511 } | 517 } | 
| 512 | 518 | 
| 513 ContainerNode* context = element->parentNode(); | 519 ContainerNode* context = element->parentNode(); | 
| 514 | 520 | 
| 515 // If Mail wraps the fragment with a Paste as Quotation blockquote, or if you're pasting into a quoted region, | 521 // If Mail wraps the fragment with a Paste as Quotation blockquote, or if you're pasting into a quoted region, | 
| 516 // styles from blockquoteNode are allowed to override those from the source document, see <rdar://problem/4930986> and <rdar://problem/5089327>. | 522 // styles from blockquoteNode are allowed to override those from the source document, see <rdar://problem/4930986> and <rdar://problem/5089327>. | 
| 517 Node* blockquoteNode = !context || isMailPasteAsQuotationNode(contex t) ? context : enclosingNodeOfType(firstPositionInNode(context), isMailHTMLBlock quoteElement, CanCrossEditingBoundary); | 523 HTMLQuoteElement* blockquoteElement = !context || isMailPasteAsQuota tionHTMLBlockQuoteElement(context) ? toHTMLQuoteElement(context) : toHTMLQuoteEl ement(enclosingNodeOfType(firstPositionInNode(context), isMailHTMLBlockquoteElem ent, CanCrossEditingBoundary)); | 
| 518 if (blockquoteNode) | 524 if (blockquoteElement) | 
| 519 newInlineStyle->removeStyleFromRulesAndContext(element, document ().documentElement()); | 525 newInlineStyle->removeStyleFromRulesAndContext(element, document ().documentElement()); | 
| 520 | 526 | 
| 521 newInlineStyle->removeStyleFromRulesAndContext(element, context); | 527 newInlineStyle->removeStyleFromRulesAndContext(element, context); | 
| 522 } | 528 } | 
| 523 | 529 | 
| 524 if (!inlineStyle || newInlineStyle->isEmpty()) { | 530 if (!inlineStyle || newInlineStyle->isEmpty()) { | 
| 525 if (isStyleSpanOrSpanWithOnlyStyleAttribute(element) || isEmptyFontT ag(element, AllowNonEmptyStyleAttribute)) { | 531 if (isStyleSpanOrSpanWithOnlyStyleAttribute(element) || isEmptyFontT ag(element, AllowNonEmptyStyleAttribute)) { | 
| 526 insertedNodes.willRemoveNodePreservingChildren(*element); | 532 insertedNodes.willRemoveNodePreservingChildren(*element); | 
| 527 removeNodePreservingChildren(element); | 533 removeNodePreservingChildren(element); | 
| 528 continue; | 534 continue; | 
| 529 } | 535 } | 
| 530 removeNodeAttribute(element, styleAttr); | 536 removeElementAttribute(element, styleAttr); | 
| 531 } else if (newInlineStyle->style()->propertyCount() != inlineStyle->prop ertyCount()) { | 537 } else if (newInlineStyle->style()->propertyCount() != inlineStyle->prop ertyCount()) { | 
| 532 setNodeAttribute(element, styleAttr, AtomicString(newInlineStyle->st yle()->asText())); | 538 setNodeAttribute(element, styleAttr, AtomicString(newInlineStyle->st yle()->asText())); | 
| 533 } | 539 } | 
| 534 | 540 | 
| 535 // FIXME: Tolerate differences in id, class, and style attributes. | 541 // FIXME: Tolerate differences in id, class, and style attributes. | 
| 536 if (element->parentNode() && isNonTableCellHTMLBlockElement(element) && areIdenticalElements(element, element->parentNode()) | 542 if (element->parentNode() && isNonTableCellHTMLBlockElement(element) && areIdenticalElements(element, element->parentNode()) | 
| 537 && VisiblePosition(firstPositionInNode(element->parentNode())) == Vi siblePosition(firstPositionInNode(element)) | 543 && VisiblePosition(firstPositionInNode(element->parentNode())) == Vi siblePosition(firstPositionInNode(element)) | 
| 538 && VisiblePosition(lastPositionInNode(element->parentNode())) == Vis iblePosition(lastPositionInNode(element))) { | 544 && VisiblePosition(lastPositionInNode(element->parentNode())) == Vis iblePosition(lastPositionInNode(element))) { | 
| 539 insertedNodes.willRemoveNodePreservingChildren(*element); | 545 insertedNodes.willRemoveNodePreservingChildren(*element); | 
| 540 removeNodePreservingChildren(element); | 546 removeNodePreservingChildren(element); | 
| 541 continue; | 547 continue; | 
| 542 } | 548 } | 
| 543 | 549 | 
| 544 if (element->parentNode() && element->parentNode()->rendererIsRichlyEdit able()) | 550 if (element->parentNode() && element->parentNode()->rendererIsRichlyEdit able()) | 
| 545 removeNodeAttribute(element, contenteditableAttr); | 551 removeElementAttribute(element, contenteditableAttr); | 
| 546 | 552 | 
| 547 // WebKit used to not add display: inline and float: none on copy. | 553 // WebKit used to not add display: inline and float: none on copy. | 
| 548 // Keep this code around for backward compatibility | 554 // Keep this code around for backward compatibility | 
| 549 if (isLegacyAppleStyleSpan(element)) { | 555 if (isLegacyAppleHTMLSpanElement(element)) { | 
| 550 if (!element->hasChildren()) { | 556 if (!element->hasChildren()) { | 
| 551 insertedNodes.willRemoveNodePreservingChildren(*element); | 557 insertedNodes.willRemoveNodePreservingChildren(*element); | 
| 552 removeNodePreservingChildren(element); | 558 removeNodePreservingChildren(element); | 
| 553 continue; | 559 continue; | 
| 554 } | 560 } | 
| 555 // There are other styles that style rules can give to style spans, | 561 // There are other styles that style rules can give to style spans, | 
| 556 // but these are the two important ones because they'll prevent | 562 // but these are the two important ones because they'll prevent | 
| 557 // inserted content from appearing in the right paragraph. | 563 // inserted content from appearing in the right paragraph. | 
| 558 // FIXME: Hyatt is concerned that selectively using display:inline w ill give inconsistent | 564 // FIXME: Hyatt is concerned that selectively using display:inline w ill give inconsistent | 
| 559 // results. We already know one issue because td elements ignore the ir display property | 565 // results. We already know one issue because td elements ignore the ir display property | 
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 628 void ReplaceSelectionCommand::makeInsertedContentRoundTrippableWithHTMLTreeBuild er(const InsertedNodes& insertedNodes) | 634 void ReplaceSelectionCommand::makeInsertedContentRoundTrippableWithHTMLTreeBuild er(const InsertedNodes& insertedNodes) | 
| 629 { | 635 { | 
| 630 RefPtrWillBeRawPtr<Node> pastEndNode = insertedNodes.pastLastLeaf(); | 636 RefPtrWillBeRawPtr<Node> pastEndNode = insertedNodes.pastLastLeaf(); | 
| 631 RefPtrWillBeRawPtr<Node> next = nullptr; | 637 RefPtrWillBeRawPtr<Node> next = nullptr; | 
| 632 for (RefPtrWillBeRawPtr<Node> node = insertedNodes.firstNodeInserted(); node && node != pastEndNode; node = next) { | 638 for (RefPtrWillBeRawPtr<Node> node = insertedNodes.firstNodeInserted(); node && node != pastEndNode; node = next) { | 
| 633 next = NodeTraversal::next(*node); | 639 next = NodeTraversal::next(*node); | 
| 634 | 640 | 
| 635 if (!node->isHTMLElement()) | 641 if (!node->isHTMLElement()) | 
| 636 continue; | 642 continue; | 
| 637 | 643 | 
| 638 if (isProhibitedParagraphChild(toHTMLElement(node)->localName())) { | 644 HTMLElement& element = toHTMLElement(*node); | 
| 639 if (HTMLElement* paragraphElement = toHTMLElement(enclosingElementWi thTag(positionInParentBeforeNode(*node), pTag))) | 645 if (isProhibitedParagraphChild(element.localName())) { | 
| 640 moveNodeOutOfAncestor(node, paragraphElement); | 646 if (HTMLElement* paragraphElement = toHTMLElement(enclosingElementWi thTag(positionInParentBeforeNode(element), pTag))) | 
| 647 moveElementOutOfAncestor(&element, paragraphElement); | |
| 641 } | 648 } | 
| 642 | 649 | 
| 643 if (isHeaderElement(node.get())) { | 650 if (isHTMLHeaderElement(&element)) { | 
| 644 if (HTMLElement* headerElement = toHTMLElement(highestEnclosingNodeO fType(positionInParentBeforeNode(*node), isHeaderElement))) | 651 if (HTMLElement* headerElement = toHTMLElement(highestEnclosingNodeO fType(positionInParentBeforeNode(element), isHTMLHeaderElement))) | 
| 645 moveNodeOutOfAncestor(node, headerElement); | 652 moveElementOutOfAncestor(&element, headerElement); | 
| 646 } | 653 } | 
| 647 } | 654 } | 
| 648 } | 655 } | 
| 649 | 656 | 
| 650 void ReplaceSelectionCommand::moveNodeOutOfAncestor(PassRefPtrWillBeRawPtr<Node> prpNode, PassRefPtrWillBeRawPtr<ContainerNode> prpAncestor) | 657 void ReplaceSelectionCommand::moveElementOutOfAncestor(PassRefPtrWillBeRawPtr<El ement> prpElement, PassRefPtrWillBeRawPtr<ContainerNode> prpAncestor) | 
| 651 { | 658 { | 
| 652 RefPtrWillBeRawPtr<Node> node = prpNode; | 659 RefPtrWillBeRawPtr<Element> element = prpElement; | 
| 653 RefPtrWillBeRawPtr<Node> ancestor = prpAncestor; | 660 RefPtrWillBeRawPtr<ContainerNode> ancestor = prpAncestor; | 
| 654 | 661 | 
| 655 if (!ancestor->parentNode()->hasEditableStyle()) | 662 if (!ancestor->parentNode()->hasEditableStyle()) | 
| 656 return; | 663 return; | 
| 657 | 664 | 
| 658 VisiblePosition positionAtEndOfNode(lastPositionInOrAfterNode(node.get())); | 665 VisiblePosition positionAtEndOfNode(lastPositionInOrAfterNode(element.get()) ); | 
| 659 VisiblePosition lastPositionInParagraph(lastPositionInNode(ancestor.get())); | 666 VisiblePosition lastPositionInParagraph(lastPositionInNode(ancestor.get())); | 
| 660 if (positionAtEndOfNode == lastPositionInParagraph) { | 667 if (positionAtEndOfNode == lastPositionInParagraph) { | 
| 661 removeNode(node); | 668 removeNode(element); | 
| 662 if (ancestor->nextSibling()) | 669 if (ancestor->nextSibling()) | 
| 663 insertNodeBefore(node, ancestor->nextSibling()); | 670 insertNodeBefore(element, ancestor->nextSibling()); | 
| 664 else | 671 else | 
| 665 appendNode(node, ancestor->parentNode()); | 672 appendNode(element, ancestor->parentNode()); | 
| 666 } else { | 673 } else { | 
| 667 RefPtrWillBeRawPtr<Node> nodeToSplitTo = splitTreeToNode(node.get(), anc estor.get(), true); | 674 RefPtrWillBeRawPtr<Node> nodeToSplitTo = splitTreeToNode(element.get(), ancestor.get(), true); | 
| 668 removeNode(node); | 675 removeNode(element); | 
| 669 insertNodeBefore(node, nodeToSplitTo); | 676 insertNodeBefore(element, nodeToSplitTo); | 
| 670 } | 677 } | 
| 671 if (!ancestor->hasChildren()) | 678 if (!ancestor->hasChildren()) | 
| 672 removeNode(ancestor.release()); | 679 removeNode(ancestor.release()); | 
| 673 } | 680 } | 
| 674 | 681 | 
| 675 static inline bool nodeHasVisibleRenderText(Text& text) | 682 static inline bool nodeHasVisibleRenderText(Text& text) | 
| 676 { | 683 { | 
| 677 return text.renderer() && text.renderer()->renderedTextLength() > 0; | 684 return text.renderer() && text.renderer()->renderedTextLength() > 0; | 
| 678 } | 685 } | 
| 679 | 686 | 
| (...skipping 14 matching lines...) Expand all Loading... | |
| 694 Node* firstNodeInserted = insertedNodes.firstNodeInserted(); | 701 Node* firstNodeInserted = insertedNodes.firstNodeInserted(); | 
| 695 if (firstNodeInserted && firstNodeInserted->isTextNode() && !nodeHasVisibleR enderText(toText(*firstNodeInserted))) { | 702 if (firstNodeInserted && firstNodeInserted->isTextNode() && !nodeHasVisibleR enderText(toText(*firstNodeInserted))) { | 
| 696 insertedNodes.willRemoveNode(*firstNodeInserted); | 703 insertedNodes.willRemoveNode(*firstNodeInserted); | 
| 697 removeNode(firstNodeInserted); | 704 removeNode(firstNodeInserted); | 
| 698 } | 705 } | 
| 699 } | 706 } | 
| 700 | 707 | 
| 701 VisiblePosition ReplaceSelectionCommand::positionAtEndOfInsertedContent() const | 708 VisiblePosition ReplaceSelectionCommand::positionAtEndOfInsertedContent() const | 
| 702 { | 709 { | 
| 703 // FIXME: Why is this hack here? What's special about <select> tags? | 710 // FIXME: Why is this hack here? What's special about <select> tags? | 
| 704 Element* enclosingSelect = enclosingElementWithTag(m_endOfInsertedContent, s electTag); | 711 HTMLSelectElement* enclosingSelect = toHTMLSelectElement(enclosingElementWit hTag(m_endOfInsertedContent, selectTag)); | 
| 705 return VisiblePosition(enclosingSelect ? lastPositionInOrAfterNode(enclosing Select) : m_endOfInsertedContent); | 712 return VisiblePosition(enclosingSelect ? lastPositionInOrAfterNode(enclosing Select) : m_endOfInsertedContent); | 
| 706 } | 713 } | 
| 707 | 714 | 
| 708 VisiblePosition ReplaceSelectionCommand::positionAtStartOfInsertedContent() cons t | 715 VisiblePosition ReplaceSelectionCommand::positionAtStartOfInsertedContent() cons t | 
| 709 { | 716 { | 
| 710 return VisiblePosition(m_startOfInsertedContent); | 717 return VisiblePosition(m_startOfInsertedContent); | 
| 711 } | 718 } | 
| 712 | 719 | 
| 713 static void removeHeadContents(ReplacementFragment& fragment) | 720 static void removeHeadContents(ReplacementFragment& fragment) | 
| 714 { | 721 { | 
| (...skipping 13 matching lines...) Expand all Loading... | |
| 728 } | 735 } | 
| 729 | 736 | 
| 730 // Remove style spans before insertion if they are unnecessary. It's faster bec ause we'll | 737 // Remove style spans before insertion if they are unnecessary. It's faster bec ause we'll | 
| 731 // avoid doing a layout. | 738 // avoid doing a layout. | 
| 732 static bool handleStyleSpansBeforeInsertion(ReplacementFragment& fragment, const Position& insertionPos) | 739 static bool handleStyleSpansBeforeInsertion(ReplacementFragment& fragment, const Position& insertionPos) | 
| 733 { | 740 { | 
| 734 Node* topNode = fragment.firstChild(); | 741 Node* topNode = fragment.firstChild(); | 
| 735 | 742 | 
| 736 // Handling the case where we are doing Paste as Quotation or pasting into q uoted content is more complicated (see handleStyleSpans) | 743 // Handling the case where we are doing Paste as Quotation or pasting into q uoted content is more complicated (see handleStyleSpans) | 
| 737 // and doesn't receive the optimization. | 744 // and doesn't receive the optimization. | 
| 738 if (isMailPasteAsQuotationNode(topNode) || enclosingNodeOfType(firstPosition InOrBeforeNode(topNode), isMailHTMLBlockquoteElement, CanCrossEditingBoundary)) | 745 if (isMailPasteAsQuotationHTMLBlockQuoteElement(topNode) || enclosingNodeOfT ype(firstPositionInOrBeforeNode(topNode), isMailHTMLBlockquoteElement, CanCrossE ditingBoundary)) | 
| 739 return false; | 746 return false; | 
| 740 | 747 | 
| 741 // Either there are no style spans in the fragment or a WebKit client has ad ded content to the fragment | 748 // Either there are no style spans in the fragment or a WebKit client has ad ded content to the fragment | 
| 742 // before inserting it. Look for and handle style spans after insertion. | 749 // before inserting it. Look for and handle style spans after insertion. | 
| 743 if (!isLegacyAppleStyleSpan(topNode)) | 750 if (!isLegacyAppleHTMLSpanElement(topNode)) | 
| 744 return false; | 751 return false; | 
| 745 | 752 | 
| 746 Node* wrappingStyleSpan = topNode; | 753 HTMLSpanElement* wrappingStyleSpan = toHTMLSpanElement(topNode); | 
| 747 RefPtrWillBeRawPtr<EditingStyle> styleAtInsertionPos = EditingStyle::create( insertionPos.parentAnchoredEquivalent()); | 754 RefPtrWillBeRawPtr<EditingStyle> styleAtInsertionPos = EditingStyle::create( insertionPos.parentAnchoredEquivalent()); | 
| 748 String styleText = styleAtInsertionPos->style()->asText(); | 755 String styleText = styleAtInsertionPos->style()->asText(); | 
| 749 | 756 | 
| 750 // FIXME: This string comparison is a naive way of comparing two styles. | 757 // FIXME: This string comparison is a naive way of comparing two styles. | 
| 751 // We should be taking the diff and check that the diff is empty. | 758 // We should be taking the diff and check that the diff is empty. | 
| 752 if (styleText != toElement(wrappingStyleSpan)->getAttribute(styleAttr)) | 759 if (styleText != wrappingStyleSpan->getAttribute(styleAttr)) | 
| 753 return false; | 760 return false; | 
| 754 | 761 | 
| 755 fragment.removeNodePreservingChildren(wrappingStyleSpan); | 762 fragment.removeNodePreservingChildren(wrappingStyleSpan); | 
| 756 return true; | 763 return true; | 
| 757 } | 764 } | 
| 758 | 765 | 
| 759 // At copy time, WebKit wraps copied content in a span that contains the source document's | 766 // At copy time, WebKit wraps copied content in a span that contains the source document's | 
| 760 // default styles. If the copied Range inherits any other styles from its ances tors, we put | 767 // default styles. If the copied Range inherits any other styles from its ances tors, we put | 
| 761 // those styles on a second span. | 768 // those styles on a second span. | 
| 762 // This function removes redundant styles from those spans, and removes the span s if all their | 769 // This function removes redundant styles from those spans, and removes the span s if all their | 
| 763 // styles are redundant. | 770 // styles are redundant. | 
| 764 // We should remove the Apple-style-span class when we're done, see <rdar://prob lem/5685600>. | 771 // We should remove the Apple-style-span class when we're done, see <rdar://prob lem/5685600>. | 
| 765 // We should remove styles from spans that are overridden by all of their childr en, either here | 772 // We should remove styles from spans that are overridden by all of their childr en, either here | 
| 766 // or at copy time. | 773 // or at copy time. | 
| 767 void ReplaceSelectionCommand::handleStyleSpans(InsertedNodes& insertedNodes) | 774 void ReplaceSelectionCommand::handleStyleSpans(InsertedNodes& insertedNodes) | 
| 768 { | 775 { | 
| 769 HTMLElement* wrappingStyleSpan = 0; | 776 HTMLSpanElement* wrappingStyleSpan = 0; | 
| 770 // The style span that contains the source document's default style should b e at | 777 // The style span that contains the source document's default style should b e at | 
| 771 // the top of the fragment, but Mail sometimes adds a wrapper (for Paste As Quotation), | 778 // the top of the fragment, but Mail sometimes adds a wrapper (for Paste As Quotation), | 
| 772 // so search for the top level style span instead of assuming it's at the to p. | 779 // so search for the top level style span instead of assuming it's at the to p. | 
| 773 for (Node* node = insertedNodes.firstNodeInserted(); node; node = NodeTraver sal::next(*node)) { | 780 for (Node* node = insertedNodes.firstNodeInserted(); node; node = NodeTraver sal::next(*node)) { | 
| 774 if (isLegacyAppleStyleSpan(node)) { | 781 if (isLegacyAppleHTMLSpanElement(node)) { | 
| 775 wrappingStyleSpan = toHTMLElement(node); | 782 wrappingStyleSpan = toHTMLSpanElement(node); | 
| 776 break; | 783 break; | 
| 777 } | 784 } | 
| 778 } | 785 } | 
| 779 | 786 | 
| 780 // There might not be any style spans if we're pasting from another applicat ion or if | 787 // There might not be any style spans if we're pasting from another applicat ion or if | 
| 781 // we are here because of a document.execCommand("InsertHTML", ...) call. | 788 // we are here because of a document.execCommand("InsertHTML", ...) call. | 
| 782 if (!wrappingStyleSpan) | 789 if (!wrappingStyleSpan) | 
| 783 return; | 790 return; | 
| 784 | 791 | 
| 785 RefPtrWillBeRawPtr<EditingStyle> style = EditingStyle::create(wrappingStyleS pan->inlineStyle()); | 792 RefPtrWillBeRawPtr<EditingStyle> style = EditingStyle::create(wrappingStyleS pan->inlineStyle()); | 
| 786 ContainerNode* context = wrappingStyleSpan->parentNode(); | 793 ContainerNode* context = wrappingStyleSpan->parentNode(); | 
| 787 | 794 | 
| 788 // If Mail wraps the fragment with a Paste as Quotation blockquote, or if yo u're pasting into a quoted region, | 795 // If Mail wraps the fragment with a Paste as Quotation blockquote, or if yo u're pasting into a quoted region, | 
| 789 // styles from blockquoteNode are allowed to override those from the source document, see <rdar://problem/4930986> and <rdar://problem/5089327>. | 796 // styles from blockquoteElement are allowed to override those from the sour ce document, see <rdar://problem/4930986> and <rdar://problem/5089327>. | 
| 790 Node* blockquoteNode = isMailPasteAsQuotationNode(context) ? context : enclo singNodeOfType(firstPositionInNode(context), isMailHTMLBlockquoteElement, CanCro ssEditingBoundary); | 797 HTMLQuoteElement* blockquoteElement = isMailPasteAsQuotationHTMLBlockQuoteEl ement(context) ? toHTMLQuoteElement(context) : toHTMLQuoteElement(enclosingNodeO fType(firstPositionInNode(context), isMailHTMLBlockquoteElement, CanCrossEditing Boundary)); | 
| 791 if (blockquoteNode) | 798 if (blockquoteElement) | 
| 792 context = document().documentElement(); | 799 context = document().documentElement(); | 
| 793 | 800 | 
| 794 // This operation requires that only editing styles to be removed from sourc eDocumentStyle. | 801 // This operation requires that only editing styles to be removed from sourc eDocumentStyle. | 
| 795 style->prepareToApplyAt(firstPositionInNode(context)); | 802 style->prepareToApplyAt(firstPositionInNode(context)); | 
| 796 | 803 | 
| 797 // Remove block properties in the span's style. This prevents properties tha t probably have no effect | 804 // Remove block properties in the span's style. This prevents properties tha t probably have no effect | 
| 798 // currently from affecting blocks later if the style is cloned for a new bl ock element during a future | 805 // currently from affecting blocks later if the style is cloned for a new bl ock element during a future | 
| 799 // editing operation. | 806 // editing operation. | 
| 800 // FIXME: They *can* have an effect currently if blocks beneath the style sp an aren't individually marked | 807 // FIXME: They *can* have an effect currently if blocks beneath the style sp an aren't individually marked | 
| 801 // with block styles by the editing engine used to style them. WebKit doesn 't do this, but others might. | 808 // with block styles by the editing engine used to style them. WebKit doesn 't do this, but others might. | 
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 861 // Stop if any previous sibling is a block. | 868 // Stop if any previous sibling is a block. | 
| 862 for (Node* sibling = node->previousSibling(); sibling; sibling = sibling ->previousSibling()) { | 869 for (Node* sibling = node->previousSibling(); sibling; sibling = sibling ->previousSibling()) { | 
| 863 if (isBlockFlowElement(*sibling)) | 870 if (isBlockFlowElement(*sibling)) | 
| 864 return node; | 871 return node; | 
| 865 } | 872 } | 
| 866 node = parent; | 873 node = parent; | 
| 867 } | 874 } | 
| 868 return node; | 875 return node; | 
| 869 } | 876 } | 
| 870 | 877 | 
| 871 static bool isInlineNodeWithStyle(const Node* node) | 878 static bool isInlineHTMLElementWithStyle(const Node* node) | 
| 872 { | 879 { | 
| 873 // We don't want to skip over any block elements. | 880 // We don't want to skip over any block elements. | 
| 874 if (isBlock(node)) | 881 if (isBlock(node)) | 
| 875 return false; | 882 return false; | 
| 876 | 883 | 
| 877 if (!node->isHTMLElement()) | 884 if (!node->isHTMLElement()) | 
| 878 return false; | 885 return false; | 
| 879 | 886 | 
| 880 // We can skip over elements whose class attribute is | 887 // We can skip over elements whose class attribute is | 
| 881 // one of our internal classes. | 888 // one of our internal classes. | 
| 882 const HTMLElement* element = toHTMLElement(node); | 889 const HTMLElement* element = toHTMLElement(node); | 
| 883 const AtomicString& classAttributeValue = element->getAttribute(classAttr); | 890 const AtomicString& classAttributeValue = element->getAttribute(classAttr); | 
| 884 if (classAttributeValue == AppleTabSpanClass) { | 891 if (classAttributeValue == AppleTabSpanClass) { | 
| 885 UseCounter::count(node->document(), UseCounter::EditingAppleTabSpanClass ); | 892 UseCounter::count(element->document(), UseCounter::EditingAppleTabSpanCl ass); | 
| 886 return true; | 893 return true; | 
| 887 } | 894 } | 
| 888 if (classAttributeValue == AppleConvertedSpace) { | 895 if (classAttributeValue == AppleConvertedSpace) { | 
| 889 UseCounter::count(node->document(), UseCounter::EditingAppleConvertedSpa ce); | 896 UseCounter::count(element->document(), UseCounter::EditingAppleConverted Space); | 
| 890 return true; | 897 return true; | 
| 891 } | 898 } | 
| 892 if (classAttributeValue == ApplePasteAsQuotation) { | 899 if (classAttributeValue == ApplePasteAsQuotation) { | 
| 893 UseCounter::count(node->document(), UseCounter::EditingApplePasteAsQuota tion); | 900 UseCounter::count(element->document(), UseCounter::EditingApplePasteAsQu otation); | 
| 894 return true; | 901 return true; | 
| 895 } | 902 } | 
| 896 | 903 | 
| 897 return EditingStyle::elementIsStyledSpanOrHTMLEquivalent(element); | 904 return EditingStyle::elementIsStyledSpanOrHTMLEquivalent(element); | 
| 898 } | 905 } | 
| 899 | 906 | 
| 900 inline Node* nodeToSplitToAvoidPastingIntoInlineNodesWithStyle(const Position& i nsertionPos) | 907 static inline HTMLElement* elementToSplitToAvoidPastingIntoInlineElementsWithSty le(const Position& insertionPos) | 
| 901 { | 908 { | 
| 902 Element* containingBlock = enclosingBlock(insertionPos.containerNode()); | 909 Element* containingBlock = enclosingBlock(insertionPos.containerNode()); | 
| 903 return highestEnclosingNodeOfType(insertionPos, isInlineNodeWithStyle, Canno tCrossEditingBoundary, containingBlock); | 910 return toHTMLElement(highestEnclosingNodeOfType(insertionPos, isInlineHTMLEl ementWithStyle, CannotCrossEditingBoundary, containingBlock)); | 
| 904 } | 911 } | 
| 905 | 912 | 
| 906 void ReplaceSelectionCommand::doApply() | 913 void ReplaceSelectionCommand::doApply() | 
| 907 { | 914 { | 
| 908 VisibleSelection selection = endingSelection(); | 915 VisibleSelection selection = endingSelection(); | 
| 909 ASSERT(selection.isCaretOrRange()); | 916 ASSERT(selection.isCaretOrRange()); | 
| 910 ASSERT(selection.start().deprecatedNode()); | 917 ASSERT(selection.start().deprecatedNode()); | 
| 911 if (!selection.isNonOrphanedCaretOrRange() || !selection.start().deprecatedN ode()) | 918 if (!selection.isNonOrphanedCaretOrRange() || !selection.start().deprecatedN ode()) | 
| 912 return; | 919 return; | 
| 913 | 920 | 
| (...skipping 13 matching lines...) Expand all Loading... | |
| 927 m_insertionStyle = EditingStyle::create(selection.start()); | 934 m_insertionStyle = EditingStyle::create(selection.start()); | 
| 928 m_insertionStyle->mergeTypingStyle(&document()); | 935 m_insertionStyle->mergeTypingStyle(&document()); | 
| 929 } | 936 } | 
| 930 | 937 | 
| 931 VisiblePosition visibleStart = selection.visibleStart(); | 938 VisiblePosition visibleStart = selection.visibleStart(); | 
| 932 VisiblePosition visibleEnd = selection.visibleEnd(); | 939 VisiblePosition visibleEnd = selection.visibleEnd(); | 
| 933 | 940 | 
| 934 bool selectionEndWasEndOfParagraph = isEndOfParagraph(visibleEnd); | 941 bool selectionEndWasEndOfParagraph = isEndOfParagraph(visibleEnd); | 
| 935 bool selectionStartWasStartOfParagraph = isStartOfParagraph(visibleStart); | 942 bool selectionStartWasStartOfParagraph = isStartOfParagraph(visibleStart); | 
| 936 | 943 | 
| 937 Node* enclosingBlockOfVisibleStart = enclosingBlock(visibleStart.deepEquival ent().deprecatedNode()); | 944 Element* enclosingBlockOfVisibleStart = enclosingBlock(visibleStart.deepEqui valent().deprecatedNode()); | 
| 938 | 945 | 
| 939 Position insertionPos = selection.start(); | 946 Position insertionPos = selection.start(); | 
| 940 bool startIsInsideMailBlockquote = enclosingNodeOfType(insertionPos, isMailH TMLBlockquoteElement, CanCrossEditingBoundary); | 947 bool startIsInsideMailBlockquote = enclosingNodeOfType(insertionPos, isMailH TMLBlockquoteElement, CanCrossEditingBoundary); | 
| 941 bool selectionIsPlainText = !selection.isContentRichlyEditable(); | 948 bool selectionIsPlainText = !selection.isContentRichlyEditable(); | 
| 942 Element* currentRoot = selection.rootEditableElement(); | 949 Element* currentRoot = selection.rootEditableElement(); | 
| 943 | 950 | 
| 944 if ((selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph && ! startIsInsideMailBlockquote) || | 951 if ((selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph && ! startIsInsideMailBlockquote) || | 
| 945 enclosingBlockOfVisibleStart == currentRoot || isListItem(enclosingBlock OfVisibleStart) || selectionIsPlainText) | 952 enclosingBlockOfVisibleStart == currentRoot || isListItem(enclosingBlock OfVisibleStart) || selectionIsPlainText) | 
| 946 m_preventNesting = false; | 953 m_preventNesting = false; | 
| 947 | 954 | 
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1004 // Inserting content could cause whitespace to collapse, e.g. inserting <div >foo</div> into hello^ world. | 1011 // Inserting content could cause whitespace to collapse, e.g. inserting <div >foo</div> into hello^ world. | 
| 1005 prepareWhitespaceAtPositionForSplit(insertionPos); | 1012 prepareWhitespaceAtPositionForSplit(insertionPos); | 
| 1006 | 1013 | 
| 1007 // If the downstream node has been removed there's no point in continuing. | 1014 // If the downstream node has been removed there's no point in continuing. | 
| 1008 if (!insertionPos.downstream().deprecatedNode()) | 1015 if (!insertionPos.downstream().deprecatedNode()) | 
| 1009 return; | 1016 return; | 
| 1010 | 1017 | 
| 1011 // NOTE: This would be an incorrect usage of downstream() if downstream() we re changed to mean the last position after | 1018 // NOTE: This would be an incorrect usage of downstream() if downstream() we re changed to mean the last position after | 
| 1012 // 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 | 1019 // 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 | 
| 1013 // away, there are positions after the br which map to the same visible posi tion as [br, 0]). | 1020 // away, there are positions after the br which map to the same visible posi tion as [br, 0]). | 
| 1014 Node* endBR = isHTMLBRElement(*insertionPos.downstream().deprecatedNode()) ? insertionPos.downstream().deprecatedNode() : 0; | 1021 HTMLBRElement* endBR = isHTMLBRElement(*insertionPos.downstream().deprecated Node()) ? toHTMLBRElement(insertionPos.downstream().deprecatedNode()) : 0; | 
| 1015 VisiblePosition originalVisPosBeforeEndBR; | 1022 VisiblePosition originalVisPosBeforeEndBR; | 
| 1016 if (endBR) | 1023 if (endBR) | 
| 1017 originalVisPosBeforeEndBR = VisiblePosition(positionBeforeNode(endBR), D OWNSTREAM).previous(); | 1024 originalVisPosBeforeEndBR = VisiblePosition(positionBeforeNode(endBR), D OWNSTREAM).previous(); | 
| 1018 | 1025 | 
| 1019 RefPtrWillBeRawPtr<Node> enclosingBlockOfInsertionPos = enclosingBlock(inser tionPos.deprecatedNode()); | 1026 RefPtrWillBeRawPtr<Element> enclosingBlockOfInsertionPos = enclosingBlock(in sertionPos.deprecatedNode()); | 
| 1020 | 1027 | 
| 1021 // Adjust insertionPos to prevent nesting. | 1028 // Adjust insertionPos to prevent nesting. | 
| 1022 // If the start was in a Mail blockquote, we will have already handled adjus ting insertionPos above. | 1029 // If the start was in a Mail blockquote, we will have already handled adjus ting insertionPos above. | 
| 1023 if (m_preventNesting && enclosingBlockOfInsertionPos && !isTableCell(enclosi ngBlockOfInsertionPos.get()) && !startIsInsideMailBlockquote) { | 1030 if (m_preventNesting && enclosingBlockOfInsertionPos && !isTableCell(enclosi ngBlockOfInsertionPos.get()) && !startIsInsideMailBlockquote) { | 
| 1024 ASSERT(enclosingBlockOfInsertionPos != currentRoot); | 1031 ASSERT(enclosingBlockOfInsertionPos != currentRoot); | 
| 1025 VisiblePosition visibleInsertionPos(insertionPos); | 1032 VisiblePosition visibleInsertionPos(insertionPos); | 
| 1026 if (isEndOfBlock(visibleInsertionPos) && !(isStartOfBlock(visibleInserti onPos) && fragment.hasInterchangeNewlineAtEnd())) | 1033 if (isEndOfBlock(visibleInsertionPos) && !(isStartOfBlock(visibleInserti onPos) && fragment.hasInterchangeNewlineAtEnd())) | 
| 1027 insertionPos = positionInParentAfterNode(*enclosingBlockOfInsertionP os); | 1034 insertionPos = positionInParentAfterNode(*enclosingBlockOfInsertionP os); | 
| 1028 else if (isStartOfBlock(visibleInsertionPos)) | 1035 else if (isStartOfBlock(visibleInsertionPos)) | 
| 1029 insertionPos = positionInParentBeforeNode(*enclosingBlockOfInsertion Pos); | 1036 insertionPos = positionInParentBeforeNode(*enclosingBlockOfInsertion Pos); | 
| (...skipping 28 matching lines...) Expand all Loading... | |
| 1058 // This way we can produce a less verbose markup. | 1065 // This way we can produce a less verbose markup. | 
| 1059 // We can skip this optimization for fragments not wrapped in one of | 1066 // We can skip this optimization for fragments not wrapped in one of | 
| 1060 // our style spans and for positions inside list items | 1067 // our style spans and for positions inside list items | 
| 1061 // since insertAsListItems already does the right thing. | 1068 // since insertAsListItems already does the right thing. | 
| 1062 if (!m_matchStyle && !enclosingList(insertionPos.containerNode())) { | 1069 if (!m_matchStyle && !enclosingList(insertionPos.containerNode())) { | 
| 1063 if (insertionPos.containerNode()->isTextNode() && insertionPos.offsetInC ontainerNode() && !insertionPos.atLastEditingPositionForNode()) { | 1070 if (insertionPos.containerNode()->isTextNode() && insertionPos.offsetInC ontainerNode() && !insertionPos.atLastEditingPositionForNode()) { | 
| 1064 splitTextNode(insertionPos.containerText(), insertionPos.offsetInCon tainerNode()); | 1071 splitTextNode(insertionPos.containerText(), insertionPos.offsetInCon tainerNode()); | 
| 1065 insertionPos = firstPositionInNode(insertionPos.containerNode()); | 1072 insertionPos = firstPositionInNode(insertionPos.containerNode()); | 
| 1066 } | 1073 } | 
| 1067 | 1074 | 
| 1068 if (RefPtrWillBeRawPtr<Node> nodeToSplitTo = nodeToSplitToAvoidPastingIn toInlineNodesWithStyle(insertionPos)) { | 1075 if (RefPtrWillBeRawPtr<HTMLElement> elementToSplitTo = elementToSplitToA voidPastingIntoInlineElementsWithStyle(insertionPos)) { | 
| 1069 if (insertionPos.containerNode() != nodeToSplitTo->parentNode()) { | 1076 if (insertionPos.containerNode() != elementToSplitTo->parentNode()) { | 
| 1070 Node* splitStart = insertionPos.computeNodeAfterPosition(); | 1077 Node* splitStart = insertionPos.computeNodeAfterPosition(); | 
| 1071 if (!splitStart) | 1078 if (!splitStart) | 
| 1072 splitStart = insertionPos.containerNode(); | 1079 splitStart = insertionPos.containerNode(); | 
| 1073 nodeToSplitTo = splitTreeToNode(splitStart, nodeToSplitTo->paren tNode()).get(); | 1080 RefPtrWillBeRawPtr<Node> nodeToSplitTo = splitTreeToNode(splitSt art, elementToSplitTo->parentNode()).get(); | 
| 1074 insertionPos = positionInParentBeforeNode(*nodeToSplitTo); | 1081 insertionPos = positionInParentBeforeNode(*nodeToSplitTo); | 
| 1075 } | 1082 } | 
| 1076 } | 1083 } | 
| 1077 } | 1084 } | 
| 1078 | 1085 | 
| 1079 // FIXME: When pasting rich content we're often prevented from heading down the fast path by style spans. Try | 1086 // FIXME: When pasting rich content we're often prevented from heading down the fast path by style spans. Try | 
| 1080 // again here if they've been removed. | 1087 // again here if they've been removed. | 
| 1081 | 1088 | 
| 1082 // 1) Insert the content. | 1089 // 1) Insert the content. | 
| 1083 // 2) Remove redundant styles and style tags, this inner <b> for example: <b >foo <b>bar</b> baz</b>. | 1090 // 2) Remove redundant styles and style tags, this inner <b> for example: <b >foo <b>bar</b> baz</b>. | 
| 1084 // 3) Merge the start of the added content with the content before the posit ion being pasted into. | 1091 // 3) Merge the start of the added content with the content before the posit ion being pasted into. | 
| 1085 // 4) Do one of the following: a) expand the last br if the fragment ends wi th one and it collapsed, | 1092 // 4) Do one of the following: a) expand the last br if the fragment ends wi th one and it collapsed, | 
| 1086 // b) merge the last paragraph of the incoming fragment with the paragraph t hat contained the | 1093 // b) merge the last paragraph of the incoming fragment with the paragraph t hat contained the | 
| 1087 // end of the selection that was pasted into, or c) handle an interchange ne wline at the end of the | 1094 // end of the selection that was pasted into, or c) handle an interchange ne wline at the end of the | 
| 1088 // incoming fragment. | 1095 // incoming fragment. | 
| 1089 // 5) Add spaces for smart replace. | 1096 // 5) Add spaces for smart replace. | 
| 1090 // 6) Select the replacement if requested, and match style if requested. | 1097 // 6) Select the replacement if requested, and match style if requested. | 
| 1091 | 1098 | 
| 1092 InsertedNodes insertedNodes; | 1099 InsertedNodes insertedNodes; | 
| 1093 RefPtrWillBeRawPtr<Node> refNode = fragment.firstChild(); | 1100 RefPtrWillBeRawPtr<Node> refNode = fragment.firstChild(); | 
| 1094 ASSERT(refNode); | 1101 ASSERT(refNode); | 
| 1095 RefPtrWillBeRawPtr<Node> node = refNode->nextSibling(); | 1102 RefPtrWillBeRawPtr<Node> node = refNode->nextSibling(); | 
| 1096 | 1103 | 
| 1097 fragment.removeNode(refNode); | 1104 fragment.removeNode(refNode); | 
| 1098 | 1105 | 
| 1099 Node* blockStart = enclosingBlock(insertionPos.deprecatedNode()); | 1106 Element* blockStart = enclosingBlock(insertionPos.deprecatedNode()); | 
| 1100 if ((isHTMLListElement(refNode.get()) || (isLegacyAppleStyleSpan(refNode.get ()) && isHTMLListElement(refNode->firstChild()))) | 1107 if ((isHTMLListElement(refNode.get()) || (isLegacyAppleHTMLSpanElement(refNo de.get()) && isHTMLListElement(refNode->firstChild()))) | 
| 1101 && blockStart && blockStart->renderer()->isListItem()) | 1108 && blockStart && blockStart->renderer()->isListItem()) | 
| 1102 refNode = insertAsListItems(toHTMLElement(refNode), blockStart, insertio nPos, insertedNodes); | 1109 refNode = insertAsListItems(toHTMLElement(refNode), blockStart, insertio nPos, insertedNodes); | 
| 1103 else { | 1110 else { | 
| 1104 insertNodeAt(refNode, insertionPos); | 1111 insertNodeAt(refNode, insertionPos); | 
| 1105 insertedNodes.respondToNodeInsertion(*refNode); | 1112 insertedNodes.respondToNodeInsertion(*refNode); | 
| 1106 } | 1113 } | 
| 1107 | 1114 | 
| 1108 // Mutation events (bug 22634) may have already removed the inserted content | 1115 // Mutation events (bug 22634) may have already removed the inserted content | 
| 1109 if (!refNode->inDocument()) | 1116 if (!refNode->inDocument()) | 
| 1110 return; | 1117 return; | 
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1207 } | 1214 } | 
| 1208 | 1215 | 
| 1209 Position lastPositionToSelect; | 1216 Position lastPositionToSelect; | 
| 1210 if (fragment.hasInterchangeNewlineAtEnd()) { | 1217 if (fragment.hasInterchangeNewlineAtEnd()) { | 
| 1211 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent(); | 1218 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent(); | 
| 1212 VisiblePosition next = endOfInsertedContent.next(CannotCrossEditingBound ary); | 1219 VisiblePosition next = endOfInsertedContent.next(CannotCrossEditingBound ary); | 
| 1213 | 1220 | 
| 1214 if (selectionEndWasEndOfParagraph || !isEndOfParagraph(endOfInsertedCont ent) || next.isNull()) { | 1221 if (selectionEndWasEndOfParagraph || !isEndOfParagraph(endOfInsertedCont ent) || next.isNull()) { | 
| 1215 if (!isStartOfParagraph(endOfInsertedContent)) { | 1222 if (!isStartOfParagraph(endOfInsertedContent)) { | 
| 1216 setEndingSelection(endOfInsertedContent); | 1223 setEndingSelection(endOfInsertedContent); | 
| 1217 Node* enclosingNode = enclosingBlock(endOfInsertedContent.deepEq uivalent().deprecatedNode()); | 1224 Element* enclosingBlockElement = enclosingBlock(endOfInsertedCon tent.deepEquivalent().deprecatedNode()); | 
| 1218 if (isListItem(enclosingNode)) { | 1225 if (isListItem(enclosingBlockElement)) { | 
| 1219 RefPtrWillBeRawPtr<HTMLLIElement> newListItem = createListIt emElement(document()); | 1226 RefPtrWillBeRawPtr<HTMLLIElement> newListItem = createListIt emElement(document()); | 
| 1220 insertNodeAfter(newListItem, enclosingNode); | 1227 insertNodeAfter(newListItem, enclosingBlockElement); | 
| 1221 setEndingSelection(VisiblePosition(firstPositionInNode(newLi stItem.get()))); | 1228 setEndingSelection(VisiblePosition(firstPositionInNode(newLi stItem.get()))); | 
| 1222 } else { | 1229 } else { | 
| 1223 // Use a default paragraph element (a plain div) for the emp ty paragraph, using the last paragraph | 1230 // Use a default paragraph element (a plain div) for the emp ty paragraph, using the last paragraph | 
| 1224 // block's style seems to annoy users. | 1231 // block's style seems to annoy users. | 
| 1225 insertParagraphSeparator(true, !startIsInsideMailBlockquote && highestEnclosingNodeOfType(endOfInsertedContent.deepEquivalent(), | 1232 insertParagraphSeparator(true, !startIsInsideMailBlockquote && highestEnclosingNodeOfType(endOfInsertedContent.deepEquivalent(), | 
| 1226 isMailHTMLBlockquoteElement, CannotCrossEditingBoundary, insertedNodes.firstNodeInserted()->parentNode())); | 1233 isMailHTMLBlockquoteElement, CannotCrossEditingBoundary, insertedNodes.firstNodeInserted()->parentNode())); | 
| 1227 } | 1234 } | 
| 1228 | 1235 | 
| 1229 // Select up to the paragraph separator that was added. | 1236 // Select up to the paragraph separator that was added. | 
| 1230 lastPositionToSelect = endingSelection().visibleStart().deepEqui valent(); | 1237 lastPositionToSelect = endingSelection().visibleStart().deepEqui valent(); | 
| 1231 updateNodesInserted(lastPositionToSelect.deprecatedNode()); | 1238 updateNodesInserted(lastPositionToSelect.deprecatedNode()); | 
| 1232 } | 1239 } | 
| 1233 } else { | 1240 } else { | 
| 1234 // Select up to the beginning of the next paragraph. | 1241 // Select up to the beginning of the next paragraph. | 
| 1235 lastPositionToSelect = next.deepEquivalent().downstream(); | 1242 lastPositionToSelect = next.deepEquivalent().downstream(); | 
| 1236 } | 1243 } | 
| 1244 } else { | |
| 1245 mergeEndIfNeeded(); | |
| 1246 } | |
| 1237 | 1247 | 
| 1238 } else | 1248 if (HTMLQuoteElement* mailBlockquote = toHTMLQuoteElement(enclosingNodeOfTyp e(positionAtStartOfInsertedContent().deepEquivalent(), isMailPasteAsQuotationHTM LBlockQuoteElement))) | 
| 1239 mergeEndIfNeeded(); | 1249 removeElementAttribute(mailBlockquote, classAttr); | 
| 1240 | |
| 1241 if (Node* mailBlockquote = enclosingNodeOfType(positionAtStartOfInsertedCont ent().deepEquivalent(), isMailPasteAsQuotationNode)) | |
| 1242 removeNodeAttribute(toElement(mailBlockquote), classAttr); | |
| 1243 | 1250 | 
| 1244 if (shouldPerformSmartReplace()) | 1251 if (shouldPerformSmartReplace()) | 
| 1245 addSpacesForSmartReplace(); | 1252 addSpacesForSmartReplace(); | 
| 1246 | 1253 | 
| 1247 // If we are dealing with a fragment created from plain text | 1254 // If we are dealing with a fragment created from plain text | 
| 1248 // no style matching is necessary. | 1255 // no style matching is necessary. | 
| 1249 if (plainTextFragment) | 1256 if (plainTextFragment) | 
| 1250 m_matchStyle = false; | 1257 m_matchStyle = false; | 
| 1251 | 1258 | 
| 1252 completeHTMLReplacement(lastPositionToSelect); | 1259 completeHTMLReplacement(lastPositionToSelect); | 
| 1253 } | 1260 } | 
| 1254 | 1261 | 
| 1255 bool ReplaceSelectionCommand::shouldRemoveEndBR(Node* endBR, const VisiblePositi on& originalVisPosBeforeEndBR) | 1262 bool ReplaceSelectionCommand::shouldRemoveEndBR(HTMLBRElement* endBR, const Visi blePosition& originalVisPosBeforeEndBR) | 
| 1256 { | 1263 { | 
| 1257 if (!endBR || !endBR->inDocument()) | 1264 if (!endBR || !endBR->inDocument()) | 
| 1258 return false; | 1265 return false; | 
| 1259 | 1266 | 
| 1260 VisiblePosition visiblePos(positionBeforeNode(endBR)); | 1267 VisiblePosition visiblePos(positionBeforeNode(endBR)); | 
| 1261 | 1268 | 
| 1262 // Don't remove the br if nothing was inserted. | 1269 // Don't remove the br if nothing was inserted. | 
| 1263 if (visiblePos.previous() == originalVisPosBeforeEndBR) | 1270 if (visiblePos.previous() == originalVisPosBeforeEndBR) | 
| 1264 return false; | 1271 return false; | 
| 1265 | 1272 | 
| 1266 // Remove the br if it is collapsed away and so is unnecessary. | 1273 // Remove the br if it is collapsed away and so is unnecessary. | 
| 1267 if (!document().inNoQuirksMode() && isEndOfBlock(visiblePos) && !isStartOfPa ragraph(visiblePos)) | 1274 if (!document().inNoQuirksMode() && isEndOfBlock(visiblePos) && !isStartOfPa ragraph(visiblePos)) | 
| 1268 return true; | 1275 return true; | 
| 1269 | 1276 | 
| 1270 // A br that was originally holding a line open should be displaced by inser ted content or turned into a line break. | 1277 // A br that was originally holding a line open should be displaced by inser ted content or turned into a line break. | 
| 1271 // A br that was originally acting as a line break should still be acting as a line break, not as a placeholder. | 1278 // A br that was originally acting as a line break should still be acting as a line break, not as a placeholder. | 
| 1272 return isStartOfParagraph(visiblePos) && isEndOfParagraph(visiblePos); | 1279 return isStartOfParagraph(visiblePos) && isEndOfParagraph(visiblePos); | 
| 1273 } | 1280 } | 
| 1274 | 1281 | 
| 1275 bool ReplaceSelectionCommand::shouldPerformSmartReplace() const | 1282 bool ReplaceSelectionCommand::shouldPerformSmartReplace() const | 
| 1276 { | 1283 { | 
| 1277 if (!m_smartReplace) | 1284 if (!m_smartReplace) | 
| 1278 return false; | 1285 return false; | 
| 1279 | 1286 | 
| 1280 Element* textControl = enclosingTextFormControl(positionAtStartOfInsertedCon tent().deepEquivalent()); | 1287 HTMLTextFormControlElement* textControl = enclosingTextFormControl(positionA tStartOfInsertedContent().deepEquivalent()); | 
| 1281 if (isHTMLInputElement(textControl) && toHTMLInputElement(textControl)->isPa sswordField()) | 1288 if (isHTMLInputElement(textControl) && toHTMLInputElement(textControl)->isPa sswordField()) | 
| 1282 return false; // Disable smart replace for password fields. | 1289 return false; // Disable smart replace for password fields. | 
| 1283 | 1290 | 
| 1284 return true; | 1291 return true; | 
| 1285 } | 1292 } | 
| 1286 | 1293 | 
| 1287 static bool isCharacterSmartReplaceExemptConsideringNonBreakingSpace(UChar32 cha racter, bool previousCharacter) | 1294 static bool isCharacterSmartReplaceExemptConsideringNonBreakingSpace(UChar32 cha racter, bool previousCharacter) | 
| 1288 { | 1295 { | 
| 1289 return isCharacterSmartReplaceExempt(character == noBreakSpace ? ' ' : chara cter, previousCharacter); | 1296 return isCharacterSmartReplaceExempt(character == noBreakSpace ? ' ' : chara cter, previousCharacter); | 
| 1290 } | 1297 } | 
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1303 } | 1310 } | 
| 1304 | 1311 | 
| 1305 bool needsTrailingSpace = !isEndOfParagraph(endOfInsertedContent) && !isChar acterSmartReplaceExemptConsideringNonBreakingSpace(endOfInsertedContent.characte rAfter(), false); | 1312 bool needsTrailingSpace = !isEndOfParagraph(endOfInsertedContent) && !isChar acterSmartReplaceExemptConsideringNonBreakingSpace(endOfInsertedContent.characte rAfter(), false); | 
| 1306 if (needsTrailingSpace && endNode) { | 1313 if (needsTrailingSpace && endNode) { | 
| 1307 bool collapseWhiteSpace = !endNode->renderer() || endNode->renderer()->s tyle()->collapseWhiteSpace(); | 1314 bool collapseWhiteSpace = !endNode->renderer() || endNode->renderer()->s tyle()->collapseWhiteSpace(); | 
| 1308 if (endNode->isTextNode()) { | 1315 if (endNode->isTextNode()) { | 
| 1309 insertTextIntoNode(toText(endNode), endOffset, collapseWhiteSpace ? nonBreakingSpaceString() : " "); | 1316 insertTextIntoNode(toText(endNode), endOffset, collapseWhiteSpace ? nonBreakingSpaceString() : " "); | 
| 1310 if (m_endOfInsertedContent.containerNode() == endNode) | 1317 if (m_endOfInsertedContent.containerNode() == endNode) | 
| 1311 m_endOfInsertedContent.moveToOffset(m_endOfInsertedContent.offse tInContainerNode() + 1); | 1318 m_endOfInsertedContent.moveToOffset(m_endOfInsertedContent.offse tInContainerNode() + 1); | 
| 1312 } else { | 1319 } else { | 
| 1313 RefPtrWillBeRawPtr<Node> node = document().createEditingTextNode(col lapseWhiteSpace ? nonBreakingSpaceString() : " "); | 1320 RefPtrWillBeRawPtr<Text> node = document().createEditingTextNode(col lapseWhiteSpace ? nonBreakingSpaceString() : " "); | 
| 1314 insertNodeAfter(node, endNode); | 1321 insertNodeAfter(node, endNode); | 
| 1315 updateNodesInserted(node.get()); | 1322 updateNodesInserted(node.get()); | 
| 1316 } | 1323 } | 
| 1317 } | 1324 } | 
| 1318 | 1325 | 
| 1319 document().updateLayout(); | 1326 document().updateLayout(); | 
| 1320 | 1327 | 
| 1321 Position startDownstream = startOfInsertedContent.deepEquivalent().downstrea m(); | 1328 Position startDownstream = startOfInsertedContent.deepEquivalent().downstrea m(); | 
| 1322 Node* startNode = startDownstream.computeNodeAfterPosition(); | 1329 Node* startNode = startDownstream.computeNodeAfterPosition(); | 
| 1323 unsigned startOffset = 0; | 1330 unsigned startOffset = 0; | 
| 1324 if (startDownstream.anchorType() == Position::PositionIsOffsetInAnchor) { | 1331 if (startDownstream.anchorType() == Position::PositionIsOffsetInAnchor) { | 
| 1325 startNode = startDownstream.containerNode(); | 1332 startNode = startDownstream.containerNode(); | 
| 1326 startOffset = startDownstream.offsetInContainerNode(); | 1333 startOffset = startDownstream.offsetInContainerNode(); | 
| 1327 } | 1334 } | 
| 1328 | 1335 | 
| 1329 bool needsLeadingSpace = !isStartOfParagraph(startOfInsertedContent) && !isC haracterSmartReplaceExemptConsideringNonBreakingSpace(startOfInsertedContent.pre vious().characterAfter(), true); | 1336 bool needsLeadingSpace = !isStartOfParagraph(startOfInsertedContent) && !isC haracterSmartReplaceExemptConsideringNonBreakingSpace(startOfInsertedContent.pre vious().characterAfter(), true); | 
| 1330 if (needsLeadingSpace && startNode) { | 1337 if (needsLeadingSpace && startNode) { | 
| 1331 bool collapseWhiteSpace = !startNode->renderer() || startNode->renderer( )->style()->collapseWhiteSpace(); | 1338 bool collapseWhiteSpace = !startNode->renderer() || startNode->renderer( )->style()->collapseWhiteSpace(); | 
| 1332 if (startNode->isTextNode()) { | 1339 if (startNode->isTextNode()) { | 
| 1333 insertTextIntoNode(toText(startNode), startOffset, collapseWhiteSpac e ? nonBreakingSpaceString() : " "); | 1340 insertTextIntoNode(toText(startNode), startOffset, collapseWhiteSpac e ? nonBreakingSpaceString() : " "); | 
| 1334 if (m_endOfInsertedContent.containerNode() == startNode && m_endOfIn sertedContent.offsetInContainerNode()) | 1341 if (m_endOfInsertedContent.containerNode() == startNode && m_endOfIn sertedContent.offsetInContainerNode()) | 
| 1335 m_endOfInsertedContent.moveToOffset(m_endOfInsertedContent.offse tInContainerNode() + 1); | 1342 m_endOfInsertedContent.moveToOffset(m_endOfInsertedContent.offse tInContainerNode() + 1); | 
| 1336 } else { | 1343 } else { | 
| 1337 RefPtrWillBeRawPtr<Node> node = document().createEditingTextNode(col lapseWhiteSpace ? nonBreakingSpaceString() : " "); | 1344 RefPtrWillBeRawPtr<Text> node = document().createEditingTextNode(col lapseWhiteSpace ? nonBreakingSpaceString() : " "); | 
| 1338 // Don't updateNodesInserted. Doing so would set m_endOfInsertedCont ent to be the node containing the leading space, | 1345 // Don't updateNodesInserted. Doing so would set m_endOfInsertedCont ent to be the node containing the leading space, | 
| 1339 // but m_endOfInsertedContent is supposed to mark the end of pasted content. | 1346 // but m_endOfInsertedContent is supposed to mark the end of pasted content. | 
| 1340 insertNodeBefore(node, startNode); | 1347 insertNodeBefore(node, startNode); | 
| 1341 m_startOfInsertedContent = firstPositionInNode(node.get()); | 1348 m_startOfInsertedContent = firstPositionInNode(node.get()); | 
| 1342 } | 1349 } | 
| 1343 } | 1350 } | 
| 1344 } | 1351 } | 
| 1345 | 1352 | 
| 1346 void ReplaceSelectionCommand::completeHTMLReplacement(const Position &lastPositi onToSelect) | 1353 void ReplaceSelectionCommand::completeHTMLReplacement(const Position &lastPositi onToSelect) | 
| 1347 { | 1354 { | 
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1431 } | 1438 } | 
| 1432 } | 1439 } | 
| 1433 | 1440 | 
| 1434 EditAction ReplaceSelectionCommand::editingAction() const | 1441 EditAction ReplaceSelectionCommand::editingAction() const | 
| 1435 { | 1442 { | 
| 1436 return m_editAction; | 1443 return m_editAction; | 
| 1437 } | 1444 } | 
| 1438 | 1445 | 
| 1439 // If the user is inserting a list into an existing list, instead of nesting the list, | 1446 // If the user is inserting a list into an existing list, instead of nesting the list, | 
| 1440 // we put the list items into the existing list. | 1447 // we put the list items into the existing list. | 
| 1441 Node* ReplaceSelectionCommand::insertAsListItems(PassRefPtrWillBeRawPtr<HTMLElem ent> prpListElement, Node* insertionBlock, const Position& insertPos, InsertedNo des& insertedNodes) | 1448 Node* ReplaceSelectionCommand::insertAsListItems(PassRefPtrWillBeRawPtr<HTMLElem ent> prpListElement, Element* insertionBlock, const Position& insertPos, Inserte dNodes& insertedNodes) | 
| 1442 { | 1449 { | 
| 1443 RefPtrWillBeRawPtr<HTMLElement> listElement = prpListElement; | 1450 RefPtrWillBeRawPtr<HTMLElement> listElement = prpListElement; | 
| 1444 | 1451 | 
| 1445 while (listElement->hasOneChild() && isHTMLListElement(listElement->firstChi ld())) | 1452 while (listElement->hasOneChild() && isHTMLListElement(listElement->firstChi ld())) | 
| 1446 listElement = toHTMLElement(listElement->firstChild()); | 1453 listElement = toHTMLElement(listElement->firstChild()); | 
| 1447 | 1454 | 
| 1448 bool isStart = isStartOfParagraph(VisiblePosition(insertPos)); | 1455 bool isStart = isStartOfParagraph(VisiblePosition(insertPos)); | 
| 1449 bool isEnd = isEndOfParagraph(VisiblePosition(insertPos)); | 1456 bool isEnd = isEndOfParagraph(VisiblePosition(insertPos)); | 
| 1450 bool isMiddle = !isStart && !isEnd; | 1457 bool isMiddle = !isStart && !isEnd; | 
| 1451 Node* lastNode = insertionBlock; | 1458 Node* lastNode = insertionBlock; | 
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1496 bool ReplaceSelectionCommand::performTrivialReplace(const ReplacementFragment& f ragment) | 1503 bool ReplaceSelectionCommand::performTrivialReplace(const ReplacementFragment& f ragment) | 
| 1497 { | 1504 { | 
| 1498 if (!fragment.firstChild() || fragment.firstChild() != fragment.lastChild() || !fragment.firstChild()->isTextNode()) | 1505 if (!fragment.firstChild() || fragment.firstChild() != fragment.lastChild() || !fragment.firstChild()->isTextNode()) | 
| 1499 return false; | 1506 return false; | 
| 1500 | 1507 | 
| 1501 // FIXME: Would be nice to handle smart replace in the fast path. | 1508 // FIXME: Would be nice to handle smart replace in the fast path. | 
| 1502 if (m_smartReplace || fragment.hasInterchangeNewlineAtStart() || fragment.ha sInterchangeNewlineAtEnd()) | 1509 if (m_smartReplace || fragment.hasInterchangeNewlineAtStart() || fragment.ha sInterchangeNewlineAtEnd()) | 
| 1503 return false; | 1510 return false; | 
| 1504 | 1511 | 
| 1505 // e.g. when "bar" is inserted after "foo" in <div><u>foo</u></div>, "bar" s hould not be underlined. | 1512 // e.g. when "bar" is inserted after "foo" in <div><u>foo</u></div>, "bar" s hould not be underlined. | 
| 1506 if (nodeToSplitToAvoidPastingIntoInlineNodesWithStyle(endingSelection().star t())) | 1513 if (elementToSplitToAvoidPastingIntoInlineElementsWithStyle(endingSelection( ).start())) | 
| 1507 return false; | 1514 return false; | 
| 1508 | 1515 | 
| 1509 RefPtrWillBeRawPtr<Node> nodeAfterInsertionPos = endingSelection().end().dow nstream().anchorNode(); | 1516 RefPtrWillBeRawPtr<Node> nodeAfterInsertionPos = endingSelection().end().dow nstream().anchorNode(); | 
| 1510 Text* textNode = toText(fragment.firstChild()); | 1517 Text* textNode = toText(fragment.firstChild()); | 
| 1511 // Our fragment creation code handles tabs, spaces, and newlines, so we don' t have to worry about those here. | 1518 // Our fragment creation code handles tabs, spaces, and newlines, so we don' t have to worry about those here. | 
| 1512 | 1519 | 
| 1513 Position start = endingSelection().start(); | 1520 Position start = endingSelection().start(); | 
| 1514 Position end = replaceSelectedTextInNode(textNode->data()); | 1521 Position end = replaceSelectedTextInNode(textNode->data()); | 
| 1515 if (end.isNull()) | 1522 if (end.isNull()) | 
| 1516 return false; | 1523 return false; | 
| 1517 | 1524 | 
| 1518 if (nodeAfterInsertionPos && nodeAfterInsertionPos->parentNode() && isHTMLBR Element(*nodeAfterInsertionPos) | 1525 if (nodeAfterInsertionPos && nodeAfterInsertionPos->parentNode() && isHTMLBR Element(*nodeAfterInsertionPos) | 
| 1519 && shouldRemoveEndBR(nodeAfterInsertionPos.get(), VisiblePosition(positi onBeforeNode(nodeAfterInsertionPos.get())))) | 1526 && shouldRemoveEndBR(toHTMLBRElement(nodeAfterInsertionPos.get()), Visib lePosition(positionBeforeNode(nodeAfterInsertionPos.get())))) | 
| 1520 removeNodeAndPruneAncestors(nodeAfterInsertionPos.get()); | 1527 removeNodeAndPruneAncestors(nodeAfterInsertionPos.get()); | 
| 1521 | 1528 | 
| 1522 VisibleSelection selectionAfterReplace(m_selectReplacement ? start : end, en d); | 1529 VisibleSelection selectionAfterReplace(m_selectReplacement ? start : end, en d); | 
| 1523 | 1530 | 
| 1524 setEndingSelection(selectionAfterReplace); | 1531 setEndingSelection(selectionAfterReplace); | 
| 1525 | 1532 | 
| 1526 return true; | 1533 return true; | 
| 1527 } | 1534 } | 
| 1528 | 1535 | 
| 1529 void ReplaceSelectionCommand::trace(Visitor* visitor) | 1536 void ReplaceSelectionCommand::trace(Visitor* visitor) | 
| 1530 { | 1537 { | 
| 1531 visitor->trace(m_startOfInsertedContent); | 1538 visitor->trace(m_startOfInsertedContent); | 
| 1532 visitor->trace(m_endOfInsertedContent); | 1539 visitor->trace(m_endOfInsertedContent); | 
| 1533 visitor->trace(m_insertionStyle); | 1540 visitor->trace(m_insertionStyle); | 
| 1534 visitor->trace(m_documentFragment); | 1541 visitor->trace(m_documentFragment); | 
| 1535 CompositeEditCommand::trace(visitor); | 1542 CompositeEditCommand::trace(visitor); | 
| 1536 } | 1543 } | 
| 1537 | 1544 | 
| 1538 } // namespace blink | 1545 } // namespace blink | 
| OLD | NEW |