| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserv
ed. | 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserv
ed. |
| 3 * Copyright (C) 2008, 2009, 2010, 2011 Google Inc. All rights reserved. | 3 * Copyright (C) 2008, 2009, 2010, 2011 Google Inc. All rights reserved. |
| 4 * Copyright (C) 2011 Igalia S.L. | 4 * Copyright (C) 2011 Igalia S.L. |
| 5 * Copyright (C) 2011 Motorola Mobility. All rights reserved. | 5 * Copyright (C) 2011 Motorola Mobility. All rights reserved. |
| 6 * | 6 * |
| 7 * Redistribution and use in source and binary forms, with or without | 7 * Redistribution and use in source and binary forms, with or without |
| 8 * modification, are permitted provided that the following conditions | 8 * modification, are permitted provided that the following conditions |
| 9 * are met: | 9 * are met: |
| 10 * 1. Redistributions of source code must retain the above copyright | 10 * 1. Redistributions of source code must retain the above copyright |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 | 31 |
| 32 #include "bindings/core/v8/ExceptionState.h" | 32 #include "bindings/core/v8/ExceptionState.h" |
| 33 #include "core/CSSPropertyNames.h" | 33 #include "core/CSSPropertyNames.h" |
| 34 #include "core/CSSValueKeywords.h" | 34 #include "core/CSSValueKeywords.h" |
| 35 #include "core/HTMLNames.h" | 35 #include "core/HTMLNames.h" |
| 36 #include "core/css/CSSPrimitiveValue.h" | 36 #include "core/css/CSSPrimitiveValue.h" |
| 37 #include "core/css/CSSValue.h" | 37 #include "core/css/CSSValue.h" |
| 38 #include "core/css/StylePropertySet.h" | 38 #include "core/css/StylePropertySet.h" |
| 39 #include "core/dom/CDATASection.h" | 39 #include "core/dom/CDATASection.h" |
| 40 #include "core/dom/ChildListMutationScope.h" | 40 #include "core/dom/ChildListMutationScope.h" |
| 41 #include "core/dom/Comment.h" |
| 41 #include "core/dom/ContextFeatures.h" | 42 #include "core/dom/ContextFeatures.h" |
| 42 #include "core/dom/DocumentFragment.h" | 43 #include "core/dom/DocumentFragment.h" |
| 43 #include "core/dom/ElementTraversal.h" | 44 #include "core/dom/ElementTraversal.h" |
| 44 #include "core/dom/ExceptionCode.h" | 45 #include "core/dom/ExceptionCode.h" |
| 45 #include "core/dom/NodeTraversal.h" | 46 #include "core/dom/NodeTraversal.h" |
| 46 #include "core/dom/Range.h" | 47 #include "core/dom/Range.h" |
| 47 #include "core/editing/Editor.h" | 48 #include "core/editing/Editor.h" |
| 48 #include "core/editing/MarkupAccumulator.h" | 49 #include "core/editing/MarkupAccumulator.h" |
| 49 #include "core/editing/TextIterator.h" | 50 #include "core/editing/TextIterator.h" |
| 50 #include "core/editing/VisibleSelection.h" | 51 #include "core/editing/VisibleSelection.h" |
| 51 #include "core/editing/VisibleUnits.h" | 52 #include "core/editing/VisibleUnits.h" |
| 52 #include "core/editing/htmlediting.h" | 53 #include "core/editing/htmlediting.h" |
| 53 #include "core/frame/LocalFrame.h" | 54 #include "core/frame/LocalFrame.h" |
| 55 #include "core/html/HTMLAnchorElement.h" |
| 54 #include "core/html/HTMLBRElement.h" | 56 #include "core/html/HTMLBRElement.h" |
| 55 #include "core/html/HTMLBodyElement.h" | 57 #include "core/html/HTMLBodyElement.h" |
| 58 #include "core/html/HTMLDivElement.h" |
| 56 #include "core/html/HTMLElement.h" | 59 #include "core/html/HTMLElement.h" |
| 57 #include "core/html/HTMLQuoteElement.h" | 60 #include "core/html/HTMLQuoteElement.h" |
| 58 #include "core/html/HTMLSpanElement.h" | 61 #include "core/html/HTMLSpanElement.h" |
| 59 #include "core/html/HTMLTableCellElement.h" | 62 #include "core/html/HTMLTableCellElement.h" |
| 63 #include "core/html/HTMLTableElement.h" |
| 60 #include "core/html/HTMLTextFormControlElement.h" | 64 #include "core/html/HTMLTextFormControlElement.h" |
| 61 #include "core/rendering/RenderObject.h" | 65 #include "core/rendering/RenderObject.h" |
| 62 #include "platform/weborigin/KURL.h" | 66 #include "platform/weborigin/KURL.h" |
| 63 #include "wtf/StdLibExtras.h" | 67 #include "wtf/StdLibExtras.h" |
| 64 #include "wtf/text/StringBuilder.h" | 68 #include "wtf/text/StringBuilder.h" |
| 65 | 69 |
| 66 namespace blink { | 70 namespace blink { |
| 67 | 71 |
| 68 using namespace HTMLNames; | 72 using namespace HTMLNames; |
| 69 | 73 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 changes[i].apply(); | 130 changes[i].apply(); |
| 127 } | 131 } |
| 128 | 132 |
| 129 class StyledMarkupAccumulator FINAL : public MarkupAccumulator { | 133 class StyledMarkupAccumulator FINAL : public MarkupAccumulator { |
| 130 public: | 134 public: |
| 131 enum RangeFullySelectsNode { DoesFullySelectNode, DoesNotFullySelectNode }; | 135 enum RangeFullySelectsNode { DoesFullySelectNode, DoesNotFullySelectNode }; |
| 132 | 136 |
| 133 StyledMarkupAccumulator(WillBeHeapVector<RawPtrWillBeMember<Node> >* nodes,
EAbsoluteURLs, EAnnotateForInterchange, RawPtr<const Range>, Node* highestNodeTo
BeSerialized = 0); | 137 StyledMarkupAccumulator(WillBeHeapVector<RawPtrWillBeMember<Node> >* nodes,
EAbsoluteURLs, EAnnotateForInterchange, RawPtr<const Range>, Node* highestNodeTo
BeSerialized = 0); |
| 134 Node* serializeNodes(Node* startNode, Node* pastEnd); | 138 Node* serializeNodes(Node* startNode, Node* pastEnd); |
| 135 void appendString(const String& s) { return MarkupAccumulator::appendString(
s); } | 139 void appendString(const String& s) { return MarkupAccumulator::appendString(
s); } |
| 136 void wrapWithNode(Node&, bool convertBlocksToInlines = false, RangeFullySele
ctsNode = DoesFullySelectNode); | 140 void wrapWithNode(ContainerNode&, bool convertBlocksToInlines = false, Range
FullySelectsNode = DoesFullySelectNode); |
| 137 void wrapWithStyleNode(StylePropertySet*, const Document&, bool isBlock = fa
lse); | 141 void wrapWithStyleNode(StylePropertySet*, const Document&, bool isBlock = fa
lse); |
| 138 String takeResults(); | 142 String takeResults(); |
| 139 | 143 |
| 140 private: | 144 private: |
| 141 void appendStyleNodeOpenTag(StringBuilder&, StylePropertySet*, const Documen
t&, bool isBlock = false); | 145 void appendStyleNodeOpenTag(StringBuilder&, StylePropertySet*, const Documen
t&, bool isBlock = false); |
| 142 const String& styleNodeCloseTag(bool isBlock = false); | 146 const String& styleNodeCloseTag(bool isBlock = false); |
| 143 virtual void appendText(StringBuilder& out, Text&) OVERRIDE; | 147 virtual void appendText(StringBuilder& out, Text&) OVERRIDE; |
| 144 String renderedText(Node&, const Range*); | 148 String renderedText(Node&, const Range*); |
| 145 String stringValueForRange(const Node&, const Range*); | 149 String stringValueForRange(const Node&, const Range*); |
| 146 void appendElement(StringBuilder& out, Element&, bool addDisplayInline, Rang
eFullySelectsNode); | 150 void appendElement(StringBuilder& out, Element&, bool addDisplayInline, Rang
eFullySelectsNode); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 162 RefPtrWillBeMember<EditingStyle> m_wrappingStyle; | 166 RefPtrWillBeMember<EditingStyle> m_wrappingStyle; |
| 163 }; | 167 }; |
| 164 | 168 |
| 165 inline StyledMarkupAccumulator::StyledMarkupAccumulator(WillBeHeapVector<RawPtrW
illBeMember<Node> >* nodes, EAbsoluteURLs shouldResolveURLs, EAnnotateForInterch
ange shouldAnnotate, RawPtr<const Range> range, Node* highestNodeToBeSerialized) | 169 inline StyledMarkupAccumulator::StyledMarkupAccumulator(WillBeHeapVector<RawPtrW
illBeMember<Node> >* nodes, EAbsoluteURLs shouldResolveURLs, EAnnotateForInterch
ange shouldAnnotate, RawPtr<const Range> range, Node* highestNodeToBeSerialized) |
| 166 : MarkupAccumulator(nodes, shouldResolveURLs, range) | 170 : MarkupAccumulator(nodes, shouldResolveURLs, range) |
| 167 , m_shouldAnnotate(shouldAnnotate) | 171 , m_shouldAnnotate(shouldAnnotate) |
| 168 , m_highestNodeToBeSerialized(highestNodeToBeSerialized) | 172 , m_highestNodeToBeSerialized(highestNodeToBeSerialized) |
| 169 { | 173 { |
| 170 } | 174 } |
| 171 | 175 |
| 172 void StyledMarkupAccumulator::wrapWithNode(Node& node, bool convertBlocksToInlin
es, RangeFullySelectsNode rangeFullySelectsNode) | 176 void StyledMarkupAccumulator::wrapWithNode(ContainerNode& node, bool convertBloc
ksToInlines, RangeFullySelectsNode rangeFullySelectsNode) |
| 173 { | 177 { |
| 174 StringBuilder markup; | 178 StringBuilder markup; |
| 175 if (node.isElementNode()) | 179 if (node.isElementNode()) |
| 176 appendElement(markup, toElement(node), convertBlocksToInlines && isBlock
(&node), rangeFullySelectsNode); | 180 appendElement(markup, toElement(node), convertBlocksToInlines && isBlock
(&node), rangeFullySelectsNode); |
| 177 else | 181 else |
| 178 appendStartMarkup(markup, node, 0); | 182 appendStartMarkup(markup, node, 0); |
| 179 m_reversedPrecedingMarkup.append(markup.toString()); | 183 m_reversedPrecedingMarkup.append(markup.toString()); |
| 180 appendEndTag(node); | 184 appendEndTag(node); |
| 181 if (m_nodes) | 185 if (m_nodes) |
| 182 m_nodes->append(&node); | 186 m_nodes->append(&node); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 250 | 254 |
| 251 if (wrappingSpan) | 255 if (wrappingSpan) |
| 252 out.append(styleNodeCloseTag()); | 256 out.append(styleNodeCloseTag()); |
| 253 } | 257 } |
| 254 | 258 |
| 255 String StyledMarkupAccumulator::renderedText(Node& node, const Range* range) | 259 String StyledMarkupAccumulator::renderedText(Node& node, const Range* range) |
| 256 { | 260 { |
| 257 if (!node.isTextNode()) | 261 if (!node.isTextNode()) |
| 258 return String(); | 262 return String(); |
| 259 | 263 |
| 260 const Text& textNode = toText(node); | 264 Text& textNode = toText(node); |
| 261 unsigned startOffset = 0; | 265 unsigned startOffset = 0; |
| 262 unsigned endOffset = textNode.length(); | 266 unsigned endOffset = textNode.length(); |
| 263 | 267 |
| 264 if (range && node == range->startContainer()) | 268 if (range && textNode == range->startContainer()) |
| 265 startOffset = range->startOffset(); | 269 startOffset = range->startOffset(); |
| 266 if (range && node == range->endContainer()) | 270 if (range && textNode == range->endContainer()) |
| 267 endOffset = range->endOffset(); | 271 endOffset = range->endOffset(); |
| 268 | 272 |
| 269 Position start = createLegacyEditingPosition(&node, startOffset); | 273 Position start = createLegacyEditingPosition(&textNode, startOffset); |
| 270 Position end = createLegacyEditingPosition(&node, endOffset); | 274 Position end = createLegacyEditingPosition(&textNode, endOffset); |
| 271 return plainText(Range::create(node.document(), start, end).get()); | 275 return plainText(Range::create(textNode.document(), start, end).get()); |
| 272 } | 276 } |
| 273 | 277 |
| 274 String StyledMarkupAccumulator::stringValueForRange(const Node& node, const Rang
e* range) | 278 String StyledMarkupAccumulator::stringValueForRange(const Node& node, const Rang
e* range) |
| 275 { | 279 { |
| 276 if (!range) | 280 if (!range) |
| 277 return node.nodeValue(); | 281 return node.nodeValue(); |
| 278 | 282 |
| 279 String str = node.nodeValue(); | 283 String str = node.nodeValue(); |
| 280 if (node == range->endContainer()) | 284 if (node == range->endContainer()) |
| 281 str.truncate(range->endOffset()); | 285 str.truncate(range->endOffset()); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 } | 361 } |
| 358 } | 362 } |
| 359 | 363 |
| 360 | 364 |
| 361 return traverseNodesForSerialization(startNode, pastEnd, EmitString); | 365 return traverseNodesForSerialization(startNode, pastEnd, EmitString); |
| 362 } | 366 } |
| 363 | 367 |
| 364 Node* StyledMarkupAccumulator::traverseNodesForSerialization(Node* startNode, No
de* pastEnd, NodeTraversalMode traversalMode) | 368 Node* StyledMarkupAccumulator::traverseNodesForSerialization(Node* startNode, No
de* pastEnd, NodeTraversalMode traversalMode) |
| 365 { | 369 { |
| 366 const bool shouldEmit = traversalMode == EmitString; | 370 const bool shouldEmit = traversalMode == EmitString; |
| 367 WillBeHeapVector<RawPtrWillBeMember<Node> > ancestorsToClose; | 371 WillBeHeapVector<RawPtrWillBeMember<ContainerNode> > ancestorsToClose; |
| 368 Node* next; | 372 Node* next; |
| 369 Node* lastClosed = 0; | 373 Node* lastClosed = 0; |
| 370 for (Node* n = startNode; n != pastEnd; n = next) { | 374 for (Node* n = startNode; n != pastEnd; n = next) { |
| 371 // According to <rdar://problem/5730668>, it is possible for n to blow | 375 // According to <rdar://problem/5730668>, it is possible for n to blow |
| 372 // past pastEnd and become null here. This shouldn't be possible. | 376 // past pastEnd and become null here. This shouldn't be possible. |
| 373 // This null check will prevent crashes (but create too much markup) | 377 // This null check will prevent crashes (but create too much markup) |
| 374 // and the ASSERT will hopefully lead us to understanding the problem. | 378 // and the ASSERT will hopefully lead us to understanding the problem. |
| 375 ASSERT(n); | 379 ASSERT(n); |
| 376 if (!n) | 380 if (!n) |
| 377 break; | 381 break; |
| 378 | 382 |
| 379 next = NodeTraversal::next(*n); | 383 next = NodeTraversal::next(*n); |
| 380 bool openedTag = false; | 384 bool openedTag = false; |
| 381 | 385 |
| 382 if (isBlock(n) && canHaveChildrenForEditing(n) && next == pastEnd) | 386 if (isBlock(n) && canHaveChildrenForEditing(n) && next == pastEnd) |
| 383 // Don't write out empty block containers that aren't fully selected
. | 387 // Don't write out empty block containers that aren't fully selected
. |
| 384 continue; | 388 continue; |
| 385 | 389 |
| 386 if (!n->renderer() && !enclosingElementWithTag(firstPositionInOrBeforeNo
de(n), selectTag) && m_shouldAnnotate != AnnotateForNavigationTransition) { | 390 if (!n->renderer() && !enclosingElementWithTag(firstPositionInOrBeforeNo
de(n), selectTag) && m_shouldAnnotate != AnnotateForNavigationTransition) { |
| 387 next = NodeTraversal::nextSkippingChildren(*n); | 391 next = NodeTraversal::nextSkippingChildren(*n); |
| 388 // Don't skip over pastEnd. | 392 // Don't skip over pastEnd. |
| 389 if (pastEnd && pastEnd->isDescendantOf(n)) | 393 if (pastEnd && pastEnd->isDescendantOf(n)) |
| 390 next = pastEnd; | 394 next = pastEnd; |
| 391 } else { | 395 } else { |
| 392 // Add the node to the markup if we're not skipping the descendants | 396 // Add the node to the markup if we're not skipping the descendants |
| 393 if (shouldEmit) | 397 if (shouldEmit) |
| 394 appendStartTag(*n); | 398 appendStartTag(*n); |
| 395 | 399 |
| 396 // If node has no children, close the tag now. | 400 // If node has no children, close the tag now. |
| 397 if (!n->hasChildren()) { | 401 if (n->isContainerNode() && toContainerNode(n)->hasChildren()) { |
| 402 openedTag = true; |
| 403 ancestorsToClose.append(toContainerNode(n)); |
| 404 } else { |
| 398 if (shouldEmit) | 405 if (shouldEmit) |
| 399 appendEndTag(*n); | 406 appendEndTag(*n); |
| 400 lastClosed = n; | 407 lastClosed = n; |
| 401 } else { | |
| 402 openedTag = true; | |
| 403 ancestorsToClose.append(n); | |
| 404 } | 408 } |
| 405 } | 409 } |
| 406 | 410 |
| 407 // If we didn't insert open tag and there's no more siblings or we're at
the end of the traversal, take care of ancestors. | 411 // If we didn't insert open tag and there's no more siblings or we're at
the end of the traversal, take care of ancestors. |
| 408 // FIXME: What happens if we just inserted open tag and reached the end? | 412 // FIXME: What happens if we just inserted open tag and reached the end? |
| 409 if (!openedTag && (!n->nextSibling() || next == pastEnd)) { | 413 if (!openedTag && (!n->nextSibling() || next == pastEnd)) { |
| 410 // Close up the ancestors. | 414 // Close up the ancestors. |
| 411 while (!ancestorsToClose.isEmpty()) { | 415 while (!ancestorsToClose.isEmpty()) { |
| 412 Node* ancestor = ancestorsToClose.last(); | 416 ContainerNode* ancestor = ancestorsToClose.last(); |
| 413 ASSERT(ancestor); | 417 ASSERT(ancestor); |
| 414 if (next != pastEnd && next->isDescendantOf(ancestor)) | 418 if (next != pastEnd && next->isDescendantOf(ancestor)) |
| 415 break; | 419 break; |
| 416 // Not at the end of the range, close ancestors up to sibling of
next node. | 420 // Not at the end of the range, close ancestors up to sibling of
next node. |
| 417 if (shouldEmit) | 421 if (shouldEmit) |
| 418 appendEndTag(*ancestor); | 422 appendEndTag(*ancestor); |
| 419 lastClosed = ancestor; | 423 lastClosed = ancestor; |
| 420 ancestorsToClose.removeLast(); | 424 ancestorsToClose.removeLast(); |
| 421 } | 425 } |
| 422 | 426 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 441 return lastClosed; | 445 return lastClosed; |
| 442 } | 446 } |
| 443 | 447 |
| 444 static bool isHTMLBlockElement(const Node* node) | 448 static bool isHTMLBlockElement(const Node* node) |
| 445 { | 449 { |
| 446 ASSERT(node); | 450 ASSERT(node); |
| 447 return isHTMLTableCellElement(*node) | 451 return isHTMLTableCellElement(*node) |
| 448 || isNonTableCellHTMLBlockElement(node); | 452 || isNonTableCellHTMLBlockElement(node); |
| 449 } | 453 } |
| 450 | 454 |
| 451 static ContainerNode* ancestorToRetainStructureAndAppearanceForBlock(Node* commo
nAncestorBlock) | 455 static HTMLElement* ancestorToRetainStructureAndAppearanceForBlock(Element* comm
onAncestorBlock) |
| 452 { | 456 { |
| 453 if (!commonAncestorBlock) | 457 if (!commonAncestorBlock) |
| 454 return 0; | 458 return 0; |
| 455 | 459 |
| 456 if (commonAncestorBlock->hasTagName(tbodyTag) || isHTMLTableRowElement(*comm
onAncestorBlock)) { | 460 if (commonAncestorBlock->hasTagName(tbodyTag) || isHTMLTableRowElement(*comm
onAncestorBlock)) |
| 457 ContainerNode* table = commonAncestorBlock->parentNode(); | 461 return Traversal<HTMLTableElement>::firstAncestor(*commonAncestorBlock); |
| 458 while (table && !isHTMLTableElement(*table)) | |
| 459 table = table->parentNode(); | |
| 460 | |
| 461 return table; | |
| 462 } | |
| 463 | 462 |
| 464 if (isNonTableCellHTMLBlockElement(commonAncestorBlock)) | 463 if (isNonTableCellHTMLBlockElement(commonAncestorBlock)) |
| 465 return toHTMLElement(commonAncestorBlock); | 464 return toHTMLElement(commonAncestorBlock); |
| 466 | 465 |
| 467 return 0; | 466 return 0; |
| 468 } | 467 } |
| 469 | 468 |
| 470 static inline ContainerNode* ancestorToRetainStructureAndAppearance(Node* common
Ancestor) | 469 static inline HTMLElement* ancestorToRetainStructureAndAppearance(Node* commonAn
cestor) |
| 471 { | 470 { |
| 472 return ancestorToRetainStructureAndAppearanceForBlock(enclosingBlock(commonA
ncestor)); | 471 return ancestorToRetainStructureAndAppearanceForBlock(enclosingBlock(commonA
ncestor)); |
| 473 } | 472 } |
| 474 | 473 |
| 475 static inline ContainerNode* ancestorToRetainStructureAndAppearanceWithNoRendere
r(Node* commonAncestor) | 474 static inline HTMLElement* ancestorToRetainStructureAndAppearanceWithNoRenderer(
Node* commonAncestor) |
| 476 { | 475 { |
| 477 Node* commonAncestorBlock = enclosingNodeOfType(firstPositionInOrBeforeNode(
commonAncestor), isHTMLBlockElement); | 476 HTMLElement* commonAncestorBlock = toHTMLElement(enclosingNodeOfType(firstPo
sitionInOrBeforeNode(commonAncestor), isHTMLBlockElement)); |
| 478 return ancestorToRetainStructureAndAppearanceForBlock(commonAncestorBlock); | 477 return ancestorToRetainStructureAndAppearanceForBlock(commonAncestorBlock); |
| 479 } | 478 } |
| 480 | 479 |
| 481 static bool propertyMissingOrEqualToNone(StylePropertySet* style, CSSPropertyID
propertyID) | 480 static bool propertyMissingOrEqualToNone(StylePropertySet* style, CSSPropertyID
propertyID) |
| 482 { | 481 { |
| 483 if (!style) | 482 if (!style) |
| 484 return false; | 483 return false; |
| 485 RefPtrWillBeRawPtr<CSSValue> value = style->getPropertyCSSValue(propertyID); | 484 RefPtrWillBeRawPtr<CSSValue> value = style->getPropertyCSSValue(propertyID); |
| 486 if (!value) | 485 if (!value) |
| 487 return true; | 486 return true; |
| 488 if (!value->isPrimitiveValue()) | 487 if (!value->isPrimitiveValue()) |
| 489 return false; | 488 return false; |
| 490 return toCSSPrimitiveValue(value.get())->getValueID() == CSSValueNone; | 489 return toCSSPrimitiveValue(value.get())->getValueID() == CSSValueNone; |
| 491 } | 490 } |
| 492 | 491 |
| 493 static bool needInterchangeNewlineAfter(const VisiblePosition& v) | 492 static bool needInterchangeNewlineAfter(const VisiblePosition& v) |
| 494 { | 493 { |
| 495 VisiblePosition next = v.next(); | 494 VisiblePosition next = v.next(); |
| 496 Node* upstreamNode = next.deepEquivalent().upstream().deprecatedNode(); | 495 Node* upstreamNode = next.deepEquivalent().upstream().deprecatedNode(); |
| 497 Node* downstreamNode = v.deepEquivalent().downstream().deprecatedNode(); | 496 Node* downstreamNode = v.deepEquivalent().downstream().deprecatedNode(); |
| 498 // Add an interchange newline if a paragraph break is selected and a br won'
t already be added to the markup to represent it. | 497 // Add an interchange newline if a paragraph break is selected and a br won'
t already be added to the markup to represent it. |
| 499 return isEndOfParagraph(v) && isStartOfParagraph(next) && !(isHTMLBRElement(
*upstreamNode) && upstreamNode == downstreamNode); | 498 return isEndOfParagraph(v) && isStartOfParagraph(next) && !(isHTMLBRElement(
*upstreamNode) && upstreamNode == downstreamNode); |
| 500 } | 499 } |
| 501 | 500 |
| 502 static PassRefPtrWillBeRawPtr<EditingStyle> styleFromMatchedRulesAndInlineDecl(c
onst Node* node) | 501 static PassRefPtrWillBeRawPtr<EditingStyle> styleFromMatchedRulesAndInlineDecl(c
onst HTMLElement* element) |
| 503 { | 502 { |
| 504 if (!node->isHTMLElement()) | 503 RefPtrWillBeRawPtr<EditingStyle> style = EditingStyle::create(element->inlin
eStyle()); |
| 505 return nullptr; | |
| 506 | |
| 507 // FIXME: Having to const_cast here is ugly, but it is quite a bit of work t
o untangle | 504 // FIXME: Having to const_cast here is ugly, but it is quite a bit of work t
o untangle |
| 508 // the non-const-ness of styleFromMatchedRulesForElement. | 505 // the non-const-ness of styleFromMatchedRulesForElement. |
| 509 HTMLElement* element = const_cast<HTMLElement*>(toHTMLElement(node)); | 506 style->mergeStyleFromRules(const_cast<HTMLElement*>(element)); |
| 510 RefPtrWillBeRawPtr<EditingStyle> style = EditingStyle::create(element->inlin
eStyle()); | |
| 511 style->mergeStyleFromRules(element); | |
| 512 return style.release(); | 507 return style.release(); |
| 513 } | 508 } |
| 514 | 509 |
| 515 static bool isPresentationalHTMLElement(const Node* node) | 510 static bool isPresentationalHTMLElement(const Node* node) |
| 516 { | 511 { |
| 517 if (!node->isHTMLElement()) | 512 if (!node->isHTMLElement()) |
| 518 return false; | 513 return false; |
| 519 | 514 |
| 520 const HTMLElement& element = toHTMLElement(*node); | 515 const HTMLElement& element = toHTMLElement(*node); |
| 521 return element.hasTagName(uTag) || element.hasTagName(sTag) || element.hasTa
gName(strikeTag) | 516 return element.hasTagName(uTag) || element.hasTagName(sTag) || element.hasTa
gName(strikeTag) |
| 522 || element.hasTagName(iTag) || element.hasTagName(emTag) || element.hasT
agName(bTag) || element.hasTagName(strongTag); | 517 || element.hasTagName(iTag) || element.hasTagName(emTag) || element.hasT
agName(bTag) || element.hasTagName(strongTag); |
| 523 } | 518 } |
| 524 | 519 |
| 525 static ContainerNode* highestAncestorToWrapMarkup(const Range* range, EAnnotateF
orInterchange shouldAnnotate, Node* constrainingAncestor) | 520 static HTMLElement* highestAncestorToWrapMarkup(const Range* range, EAnnotateFor
Interchange shouldAnnotate, Node* constrainingAncestor) |
| 526 { | 521 { |
| 527 Node* commonAncestor = range->commonAncestorContainer(); | 522 Node* commonAncestor = range->commonAncestorContainer(); |
| 528 ASSERT(commonAncestor); | 523 ASSERT(commonAncestor); |
| 529 ContainerNode* specialCommonAncestor = 0; | 524 HTMLElement* specialCommonAncestor = 0; |
| 530 if (shouldAnnotate == AnnotateForInterchange) { | 525 if (shouldAnnotate == AnnotateForInterchange) { |
| 531 // Include ancestors that aren't completely inside the range but are req
uired to retain | 526 // Include ancestors that aren't completely inside the range but are req
uired to retain |
| 532 // the structure and appearance of the copied markup. | 527 // the structure and appearance of the copied markup. |
| 533 specialCommonAncestor = ancestorToRetainStructureAndAppearance(commonAnc
estor); | 528 specialCommonAncestor = ancestorToRetainStructureAndAppearance(commonAnc
estor); |
| 534 | 529 |
| 535 if (Node* parentListNode = enclosingNodeOfType(firstPositionInOrBeforeNo
de(range->firstNode()), isListItem)) { | 530 if (Node* parentListNode = enclosingNodeOfType(firstPositionInOrBeforeNo
de(range->firstNode()), isListItem)) { |
| 536 if (blink::areRangesEqual(VisibleSelection::selectionFromContentsOfN
ode(parentListNode).toNormalizedRange().get(), range)) { | 531 if (blink::areRangesEqual(VisibleSelection::selectionFromContentsOfN
ode(parentListNode).toNormalizedRange().get(), range)) { |
| 537 specialCommonAncestor = parentListNode->parentNode(); | 532 ContainerNode* ancestor = parentListNode->parentNode(); |
| 538 while (specialCommonAncestor && !isListElement(specialCommonAnce
stor)) | 533 while (ancestor && !isHTMLListElement(ancestor)) |
| 539 specialCommonAncestor = specialCommonAncestor->parentNode(); | 534 ancestor = ancestor->parentNode(); |
| 535 specialCommonAncestor = toHTMLElement(ancestor); |
| 540 } | 536 } |
| 541 } | 537 } |
| 542 | 538 |
| 543 // Retain the Mail quote level by including all ancestor mail block quot
es. | 539 // Retain the Mail quote level by including all ancestor mail block quot
es. |
| 544 if (HTMLQuoteElement* highestMailBlockquote = toHTMLQuoteElement(highest
EnclosingNodeOfType(firstPositionInOrBeforeNode(range->firstNode()), isMailHTMLB
lockquoteElement, CanCrossEditingBoundary))) | 540 if (HTMLQuoteElement* highestMailBlockquote = toHTMLQuoteElement(highest
EnclosingNodeOfType(firstPositionInOrBeforeNode(range->firstNode()), isMailHTMLB
lockquoteElement, CanCrossEditingBoundary))) |
| 545 specialCommonAncestor = highestMailBlockquote; | 541 specialCommonAncestor = highestMailBlockquote; |
| 546 } | 542 } |
| 547 | 543 |
| 548 Node* checkAncestor = specialCommonAncestor ? specialCommonAncestor : common
Ancestor; | 544 Node* checkAncestor = specialCommonAncestor ? specialCommonAncestor : common
Ancestor; |
| 549 if (checkAncestor->renderer()) { | 545 if (checkAncestor->renderer()) { |
| 550 HTMLElement* newSpecialCommonAncestor = toHTMLElement(highestEnclosingNo
deOfType(firstPositionInNode(checkAncestor), &isPresentationalHTMLElement, CanCr
ossEditingBoundary, constrainingAncestor)); | 546 HTMLElement* newSpecialCommonAncestor = toHTMLElement(highestEnclosingNo
deOfType(firstPositionInNode(checkAncestor), &isPresentationalHTMLElement, CanCr
ossEditingBoundary, constrainingAncestor)); |
| 551 if (newSpecialCommonAncestor) | 547 if (newSpecialCommonAncestor) |
| 552 specialCommonAncestor = newSpecialCommonAncestor; | 548 specialCommonAncestor = newSpecialCommonAncestor; |
| 553 } | 549 } |
| 554 | 550 |
| 555 // If a single tab is selected, commonAncestor will be a text node inside a
tab span. | 551 // If a single tab is selected, commonAncestor will be a text node inside a
tab span. |
| 556 // If two or more tabs are selected, commonAncestor will be the tab span. | 552 // If two or more tabs are selected, commonAncestor will be the tab span. |
| 557 // In either case, if there is a specialCommonAncestor already, it will nece
ssarily be above | 553 // In either case, if there is a specialCommonAncestor already, it will nece
ssarily be above |
| 558 // any tab span that needs to be included. | 554 // any tab span that needs to be included. |
| 559 if (!specialCommonAncestor && isTabSpanTextNode(commonAncestor)) | 555 if (!specialCommonAncestor && isTabHTMLSpanElementTextNode(commonAncestor)) |
| 560 specialCommonAncestor = commonAncestor->parentNode(); | 556 specialCommonAncestor = toHTMLSpanElement(commonAncestor->parentNode()); |
| 561 if (!specialCommonAncestor && isTabSpanElement(commonAncestor)) | 557 if (!specialCommonAncestor && isTabHTMLSpanElement(commonAncestor)) |
| 562 specialCommonAncestor = toElement(commonAncestor); | 558 specialCommonAncestor = toHTMLSpanElement(commonAncestor); |
| 563 | 559 |
| 564 if (Element* enclosingAnchor = enclosingElementWithTag(firstPositionInNode(s
pecialCommonAncestor ? specialCommonAncestor : commonAncestor), aTag)) | 560 if (HTMLAnchorElement* enclosingAnchor = toHTMLAnchorElement(enclosingElemen
tWithTag(firstPositionInNode(specialCommonAncestor ? specialCommonAncestor : com
monAncestor), aTag))) |
| 565 specialCommonAncestor = enclosingAnchor; | 561 specialCommonAncestor = enclosingAnchor; |
| 566 | 562 |
| 567 return specialCommonAncestor; | 563 return specialCommonAncestor; |
| 568 } | 564 } |
| 569 | 565 |
| 570 // FIXME: Shouldn't we omit style info when annotate == DoNotAnnotateForIntercha
nge? | 566 // FIXME: Shouldn't we omit style info when annotate == DoNotAnnotateForIntercha
nge? |
| 571 // FIXME: At least, annotation and style info should probably not be included in
range.markupString() | 567 // FIXME: At least, annotation and style info should probably not be included in
range.markupString() |
| 572 static String createMarkupInternal(Document& document, const Range* range, const
Range* updatedRange, WillBeHeapVector<RawPtrWillBeMember<Node> >* nodes, | 568 static String createMarkupInternal(Document& document, const Range* range, const
Range* updatedRange, WillBeHeapVector<RawPtrWillBeMember<Node> >* nodes, |
| 573 EAnnotateForInterchange shouldAnnotate, bool convertBlocksToInlines, EAbsolu
teURLs shouldResolveURLs, Node* constrainingAncestor) | 569 EAnnotateForInterchange shouldAnnotate, bool convertBlocksToInlines, EAbsolu
teURLs shouldResolveURLs, Node* constrainingAncestor) |
| 574 { | 570 { |
| 575 ASSERT(range); | 571 ASSERT(range); |
| 576 ASSERT(updatedRange); | 572 ASSERT(updatedRange); |
| 577 DEFINE_STATIC_LOCAL(const String, interchangeNewlineString, ("<br class=\""
AppleInterchangeNewline "\">")); | 573 DEFINE_STATIC_LOCAL(const String, interchangeNewlineString, ("<br class=\""
AppleInterchangeNewline "\">")); |
| 578 | 574 |
| 579 bool collapsed = updatedRange->collapsed(); | 575 bool collapsed = updatedRange->collapsed(); |
| 580 if (collapsed) | 576 if (collapsed) |
| 581 return emptyString(); | 577 return emptyString(); |
| 582 Node* commonAncestor = updatedRange->commonAncestorContainer(); | 578 Node* commonAncestor = updatedRange->commonAncestorContainer(); |
| 583 if (!commonAncestor) | 579 if (!commonAncestor) |
| 584 return emptyString(); | 580 return emptyString(); |
| 585 | 581 |
| 586 document.updateLayoutIgnorePendingStylesheets(); | 582 document.updateLayoutIgnorePendingStylesheets(); |
| 587 | 583 |
| 588 Element* body = enclosingElementWithTag(firstPositionInNode(commonAncestor),
bodyTag); | 584 HTMLBodyElement* body = toHTMLBodyElement(enclosingElementWithTag(firstPosit
ionInNode(commonAncestor), bodyTag)); |
| 589 Node* fullySelectedRoot = 0; | 585 HTMLBodyElement* fullySelectedRoot = 0; |
| 590 // FIXME: Do this for all fully selected blocks, not just the body. | 586 // FIXME: Do this for all fully selected blocks, not just the body. |
| 591 if (body && areRangesEqual(VisibleSelection::selectionFromContentsOfNode(bod
y).toNormalizedRange().get(), range)) | 587 if (body && areRangesEqual(VisibleSelection::selectionFromContentsOfNode(bod
y).toNormalizedRange().get(), range)) |
| 592 fullySelectedRoot = body; | 588 fullySelectedRoot = body; |
| 593 ContainerNode* specialCommonAncestor = highestAncestorToWrapMarkup(updatedRa
nge, shouldAnnotate, constrainingAncestor); | 589 HTMLElement* specialCommonAncestor = highestAncestorToWrapMarkup(updatedRang
e, shouldAnnotate, constrainingAncestor); |
| 594 StyledMarkupAccumulator accumulator(nodes, shouldResolveURLs, shouldAnnotate
, updatedRange, specialCommonAncestor); | 590 StyledMarkupAccumulator accumulator(nodes, shouldResolveURLs, shouldAnnotate
, updatedRange, specialCommonAncestor); |
| 595 Node* pastEnd = updatedRange->pastLastNode(); | 591 Node* pastEnd = updatedRange->pastLastNode(); |
| 596 | 592 |
| 597 Node* startNode = updatedRange->firstNode(); | 593 Node* startNode = updatedRange->firstNode(); |
| 598 VisiblePosition visibleStart(updatedRange->startPosition(), VP_DEFAULT_AFFIN
ITY); | 594 VisiblePosition visibleStart(updatedRange->startPosition(), VP_DEFAULT_AFFIN
ITY); |
| 599 VisiblePosition visibleEnd(updatedRange->endPosition(), VP_DEFAULT_AFFINITY)
; | 595 VisiblePosition visibleEnd(updatedRange->endPosition(), VP_DEFAULT_AFFINITY)
; |
| 600 if (shouldAnnotate == AnnotateForInterchange && needInterchangeNewlineAfter(
visibleStart)) { | 596 if (shouldAnnotate == AnnotateForInterchange && needInterchangeNewlineAfter(
visibleStart)) { |
| 601 if (visibleStart == visibleEnd.previous()) | 597 if (visibleStart == visibleEnd.previous()) |
| 602 return interchangeNewlineString; | 598 return interchangeNewlineString; |
| 603 | 599 |
| 604 accumulator.appendString(interchangeNewlineString); | 600 accumulator.appendString(interchangeNewlineString); |
| 605 startNode = visibleStart.next().deepEquivalent().deprecatedNode(); | 601 startNode = visibleStart.next().deepEquivalent().deprecatedNode(); |
| 606 | 602 |
| 607 if (pastEnd && Range::compareBoundaryPoints(startNode, 0, pastEnd, 0, AS
SERT_NO_EXCEPTION) >= 0) | 603 if (pastEnd && Range::compareBoundaryPoints(startNode, 0, pastEnd, 0, AS
SERT_NO_EXCEPTION) >= 0) |
| 608 return interchangeNewlineString; | 604 return interchangeNewlineString; |
| 609 } | 605 } |
| 610 | 606 |
| 611 Node* lastClosed = accumulator.serializeNodes(startNode, pastEnd); | 607 Node* lastClosed = accumulator.serializeNodes(startNode, pastEnd); |
| 612 | 608 |
| 613 if (specialCommonAncestor && lastClosed) { | 609 if (specialCommonAncestor && lastClosed) { |
| 614 // Also include all of the ancestors of lastClosed up to this special an
cestor. | 610 // Also include all of the ancestors of lastClosed up to this special an
cestor. |
| 615 for (ContainerNode* ancestor = lastClosed->parentNode(); ancestor; ances
tor = ancestor->parentNode()) { | 611 for (ContainerNode* ancestor = lastClosed->parentNode(); ancestor; ances
tor = ancestor->parentNode()) { |
| 616 if (ancestor == fullySelectedRoot && !convertBlocksToInlines) { | 612 if (ancestor == fullySelectedRoot && !convertBlocksToInlines) { |
| 617 RefPtrWillBeRawPtr<EditingStyle> fullySelectedRootStyle = styleF
romMatchedRulesAndInlineDecl(fullySelectedRoot); | 613 RefPtrWillBeRawPtr<EditingStyle> fullySelectedRootStyle = styleF
romMatchedRulesAndInlineDecl(fullySelectedRoot); |
| 618 | 614 |
| 619 // Bring the background attribute over, but not as an attribute
because a background attribute on a div | 615 // Bring the background attribute over, but not as an attribute
because a background attribute on a div |
| 620 // appears to have no effect. | 616 // appears to have no effect. |
| 621 if ((!fullySelectedRootStyle || !fullySelectedRootStyle->style()
|| !fullySelectedRootStyle->style()->getPropertyCSSValue(CSSPropertyBackgroundI
mage)) | 617 if ((!fullySelectedRootStyle || !fullySelectedRootStyle->style()
|| !fullySelectedRootStyle->style()->getPropertyCSSValue(CSSPropertyBackgroundI
mage)) |
| 622 && toElement(fullySelectedRoot)->hasAttribute(backgroundAttr
)) | 618 && fullySelectedRoot->hasAttribute(backgroundAttr)) |
| 623 fullySelectedRootStyle->style()->setProperty(CSSPropertyBack
groundImage, "url('" + toElement(fullySelectedRoot)->getAttribute(backgroundAttr
) + "')"); | 619 fullySelectedRootStyle->style()->setProperty(CSSPropertyBack
groundImage, "url('" + fullySelectedRoot->getAttribute(backgroundAttr) + "')"); |
| 624 | 620 |
| 625 if (fullySelectedRootStyle->style()) { | 621 if (fullySelectedRootStyle->style()) { |
| 626 // Reset the CSS properties to avoid an assertion error in a
ddStyleMarkup(). | 622 // Reset the CSS properties to avoid an assertion error in a
ddStyleMarkup(). |
| 627 // This assertion is caused at least when we select all text
of a <body> element whose | 623 // This assertion is caused at least when we select all text
of a <body> element whose |
| 628 // 'text-decoration' property is "inherit", and copy it. | 624 // 'text-decoration' property is "inherit", and copy it. |
| 629 if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->st
yle(), CSSPropertyTextDecoration)) | 625 if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->st
yle(), CSSPropertyTextDecoration)) |
| 630 fullySelectedRootStyle->style()->setProperty(CSSProperty
TextDecoration, CSSValueNone); | 626 fullySelectedRootStyle->style()->setProperty(CSSProperty
TextDecoration, CSSValueNone); |
| 631 if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->st
yle(), CSSPropertyWebkitTextDecorationsInEffect)) | 627 if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->st
yle(), CSSPropertyWebkitTextDecorationsInEffect)) |
| 632 fullySelectedRootStyle->style()->setProperty(CSSProperty
WebkitTextDecorationsInEffect, CSSValueNone); | 628 fullySelectedRootStyle->style()->setProperty(CSSProperty
WebkitTextDecorationsInEffect, CSSValueNone); |
| 633 accumulator.wrapWithStyleNode(fullySelectedRootStyle->style(
), document, true); | 629 accumulator.wrapWithStyleNode(fullySelectedRootStyle->style(
), document, true); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 672 fragment->parseHTML(markup, fakeBody.get(), parserContentPolicy); | 668 fragment->parseHTML(markup, fakeBody.get(), parserContentPolicy); |
| 673 | 669 |
| 674 if (!baseURL.isEmpty() && baseURL != blankURL() && baseURL != document.baseU
RL()) | 670 if (!baseURL.isEmpty() && baseURL != blankURL() && baseURL != document.baseU
RL()) |
| 675 completeURLs(*fragment, baseURL); | 671 completeURLs(*fragment, baseURL); |
| 676 | 672 |
| 677 return fragment.release(); | 673 return fragment.release(); |
| 678 } | 674 } |
| 679 | 675 |
| 680 static const char fragmentMarkerTag[] = "webkit-fragment-marker"; | 676 static const char fragmentMarkerTag[] = "webkit-fragment-marker"; |
| 681 | 677 |
| 682 static bool findNodesSurroundingContext(Document* document, RefPtrWillBeRawPtr<N
ode>& nodeBeforeContext, RefPtrWillBeRawPtr<Node>& nodeAfterContext) | 678 static bool findNodesSurroundingContext(Document* document, RefPtrWillBeRawPtr<C
omment>& nodeBeforeContext, RefPtrWillBeRawPtr<Comment>& nodeAfterContext) |
| 683 { | 679 { |
| 684 for (Node* node = document->firstChild(); node; node = NodeTraversal::next(*
node)) { | 680 for (Node* node = document->firstChild(); node; node = NodeTraversal::next(*
node)) { |
| 685 if (node->nodeType() == Node::COMMENT_NODE && toCharacterData(node)->dat
a() == fragmentMarkerTag) { | 681 if (node->nodeType() == Node::COMMENT_NODE && toComment(node)->data() ==
fragmentMarkerTag) { |
| 686 if (!nodeBeforeContext) | 682 if (!nodeBeforeContext) |
| 687 nodeBeforeContext = node; | 683 nodeBeforeContext = toComment(node); |
| 688 else { | 684 else { |
| 689 nodeAfterContext = node; | 685 nodeAfterContext = toComment(node); |
| 690 return true; | 686 return true; |
| 691 } | 687 } |
| 692 } | 688 } |
| 693 } | 689 } |
| 694 return false; | 690 return false; |
| 695 } | 691 } |
| 696 | 692 |
| 697 static void trimFragment(DocumentFragment* fragment, Node* nodeBeforeContext, No
de* nodeAfterContext) | 693 static void trimFragment(DocumentFragment* fragment, Comment* nodeBeforeContext,
Comment* nodeAfterContext) |
| 698 { | 694 { |
| 699 RefPtrWillBeRawPtr<Node> next = nullptr; | 695 RefPtrWillBeRawPtr<Node> next = nullptr; |
| 700 for (RefPtrWillBeRawPtr<Node> node = fragment->firstChild(); node; node = ne
xt) { | 696 for (RefPtrWillBeRawPtr<Node> node = fragment->firstChild(); node; node = ne
xt) { |
| 701 if (nodeBeforeContext->isDescendantOf(node.get())) { | 697 if (nodeBeforeContext->isDescendantOf(node.get())) { |
| 702 next = NodeTraversal::next(*node); | 698 next = NodeTraversal::next(*node); |
| 703 continue; | 699 continue; |
| 704 } | 700 } |
| 705 next = NodeTraversal::nextSkippingChildren(*node); | 701 next = NodeTraversal::nextSkippingChildren(*node); |
| 706 ASSERT(!node->contains(nodeAfterContext)); | 702 ASSERT(!node->contains(nodeAfterContext)); |
| 707 node->parentNode()->removeChild(node.get(), ASSERT_NO_EXCEPTION); | 703 node->parentNode()->removeChild(node.get(), ASSERT_NO_EXCEPTION); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 729 taggedMarkup.append(markup.substring(fragmentEnd)); | 725 taggedMarkup.append(markup.substring(fragmentEnd)); |
| 730 | 726 |
| 731 RefPtrWillBeRawPtr<DocumentFragment> taggedFragment = createFragmentFromMark
up(document, taggedMarkup.toString(), baseURL, parserContentPolicy); | 727 RefPtrWillBeRawPtr<DocumentFragment> taggedFragment = createFragmentFromMark
up(document, taggedMarkup.toString(), baseURL, parserContentPolicy); |
| 732 RefPtrWillBeRawPtr<Document> taggedDocument = Document::create(); | 728 RefPtrWillBeRawPtr<Document> taggedDocument = Document::create(); |
| 733 taggedDocument->setContextFeatures(document.contextFeatures()); | 729 taggedDocument->setContextFeatures(document.contextFeatures()); |
| 734 | 730 |
| 735 // FIXME: It's not clear what this code is trying to do. It puts nodes as di
rect children of a | 731 // FIXME: It's not clear what this code is trying to do. It puts nodes as di
rect children of a |
| 736 // Document that are not normally allowed by using the parser machinery. | 732 // Document that are not normally allowed by using the parser machinery. |
| 737 taggedDocument->parserTakeAllChildrenFrom(*taggedFragment); | 733 taggedDocument->parserTakeAllChildrenFrom(*taggedFragment); |
| 738 | 734 |
| 739 RefPtrWillBeRawPtr<Node> nodeBeforeContext = nullptr; | 735 RefPtrWillBeRawPtr<Comment> nodeBeforeContext = nullptr; |
| 740 RefPtrWillBeRawPtr<Node> nodeAfterContext = nullptr; | 736 RefPtrWillBeRawPtr<Comment> nodeAfterContext = nullptr; |
| 741 if (!findNodesSurroundingContext(taggedDocument.get(), nodeBeforeContext, no
deAfterContext)) | 737 if (!findNodesSurroundingContext(taggedDocument.get(), nodeBeforeContext, no
deAfterContext)) |
| 742 return nullptr; | 738 return nullptr; |
| 743 | 739 |
| 744 RefPtrWillBeRawPtr<Range> range = Range::create(*taggedDocument.get(), | 740 RefPtrWillBeRawPtr<Range> range = Range::create(*taggedDocument.get(), |
| 745 positionAfterNode(nodeBeforeContext.get()).parentAnchoredEquivalent(), | 741 positionAfterNode(nodeBeforeContext.get()).parentAnchoredEquivalent(), |
| 746 positionBeforeNode(nodeAfterContext.get()).parentAnchoredEquivalent()); | 742 positionBeforeNode(nodeAfterContext.get()).parentAnchoredEquivalent()); |
| 747 | 743 |
| 748 Node* commonAncestor = range->commonAncestorContainer(); | 744 Node* commonAncestor = range->commonAncestorContainer(); |
| 749 Node* specialCommonAncestor = ancestorToRetainStructureAndAppearanceWithNoRe
nderer(commonAncestor); | 745 HTMLElement* specialCommonAncestor = ancestorToRetainStructureAndAppearanceW
ithNoRenderer(commonAncestor); |
| 750 | 746 |
| 751 // When there's a special common ancestor outside of the fragment, we must i
nclude it as well to | 747 // When there's a special common ancestor outside of the fragment, we must i
nclude it as well to |
| 752 // preserve the structure and appearance of the fragment. For example, if th
e fragment contains | 748 // preserve the structure and appearance of the fragment. For example, if th
e fragment contains |
| 753 // TD, we need to include the enclosing TABLE tag as well. | 749 // TD, we need to include the enclosing TABLE tag as well. |
| 754 RefPtrWillBeRawPtr<DocumentFragment> fragment = DocumentFragment::create(doc
ument); | 750 RefPtrWillBeRawPtr<DocumentFragment> fragment = DocumentFragment::create(doc
ument); |
| 755 if (specialCommonAncestor) | 751 if (specialCommonAncestor) |
| 756 fragment->appendChild(specialCommonAncestor); | 752 fragment->appendChild(specialCommonAncestor); |
| 757 else | 753 else |
| 758 fragment->parserTakeAllChildrenFrom(toContainerNode(*commonAncestor)); | 754 fragment->parserTakeAllChildrenFrom(toContainerNode(*commonAncestor)); |
| 759 | 755 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 789 size_t numEntries = tabList.size(); | 785 size_t numEntries = tabList.size(); |
| 790 for (size_t i = 0; i < numEntries; ++i) { | 786 for (size_t i = 0; i < numEntries; ++i) { |
| 791 const String& s = tabList[i]; | 787 const String& s = tabList[i]; |
| 792 | 788 |
| 793 // append the non-tab textual part | 789 // append the non-tab textual part |
| 794 if (!s.isEmpty()) { | 790 if (!s.isEmpty()) { |
| 795 if (!tabText.isEmpty()) { | 791 if (!tabText.isEmpty()) { |
| 796 paragraph->appendChild(createTabSpanElement(document, tabText.to
String())); | 792 paragraph->appendChild(createTabSpanElement(document, tabText.to
String())); |
| 797 tabText.clear(); | 793 tabText.clear(); |
| 798 } | 794 } |
| 799 RefPtrWillBeRawPtr<Node> textNode = document.createTextNode(stringWi
thRebalancedWhitespace(s, first, i + 1 == numEntries)); | 795 RefPtrWillBeRawPtr<Text> textNode = document.createTextNode(stringWi
thRebalancedWhitespace(s, first, i + 1 == numEntries)); |
| 800 paragraph->appendChild(textNode.release()); | 796 paragraph->appendChild(textNode.release()); |
| 801 } | 797 } |
| 802 | 798 |
| 803 // there is a tab after every entry, except the last entry | 799 // there is a tab after every entry, except the last entry |
| 804 // (if the last character is a tab, the list gets an extra empty entry) | 800 // (if the last character is a tab, the list gets an extra empty entry) |
| 805 if (i + 1 != numEntries) | 801 if (i + 1 != numEntries) |
| 806 tabText.append('\t'); | 802 tabText.append('\t'); |
| 807 else if (!tabText.isEmpty()) | 803 else if (!tabText.isEmpty()) |
| 808 paragraph->appendChild(createTabSpanElement(document, tabText.toStri
ng())); | 804 paragraph->appendChild(createTabSpanElement(document, tabText.toStri
ng())); |
| 809 | 805 |
| 810 first = false; | 806 first = false; |
| 811 } | 807 } |
| 812 } | 808 } |
| 813 | 809 |
| 814 bool isPlainTextMarkup(Node* node) | 810 bool isPlainTextMarkup(Node* node) |
| 815 { | 811 { |
| 816 ASSERT(node); | 812 ASSERT(node); |
| 817 if (!node->isElementNode()) | 813 if (!isHTMLDivElement(*node)) |
| 818 return false; | 814 return false; |
| 819 | 815 |
| 820 Element* element = toElement(node); | 816 HTMLDivElement& element = toHTMLDivElement(*node); |
| 821 if (!isHTMLDivElement(*element) || !element->hasAttributes()) | 817 if (!element.hasAttributes()) |
| 822 return false; | 818 return false; |
| 823 | 819 |
| 824 if (element->hasOneChild() && (element->firstChild()->isTextNode() || elemen
t->firstChild()->hasChildren())) | 820 if (element.hasOneChild()) |
| 825 return true; | 821 return element.firstChild()->isTextNode() || element.firstChild()->hasCh
ildren(); |
| 826 | 822 |
| 827 return element->hasChildCount(2) && isTabSpanTextNode(element->firstChild()-
>firstChild()) && element->lastChild()->isTextNode(); | 823 return element.hasChildCount(2) && isTabHTMLSpanElementTextNode(element.firs
tChild()->firstChild()) && element.lastChild()->isTextNode(); |
| 828 } | 824 } |
| 829 | 825 |
| 830 static bool shouldPreserveNewline(const Range& range) | 826 static bool shouldPreserveNewline(const Range& range) |
| 831 { | 827 { |
| 832 if (Node* node = range.firstNode()) { | 828 if (Node* node = range.firstNode()) { |
| 833 if (RenderObject* renderer = node->renderer()) | 829 if (RenderObject* renderer = node->renderer()) |
| 834 return renderer->style()->preserveNewline(); | 830 return renderer->style()->preserveNewline(); |
| 835 } | 831 } |
| 836 | 832 |
| 837 if (Node* node = range.startPosition().anchorNode()) { | 833 if (Node* node = range.startPosition().anchorNode()) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 867 return fragment.release(); | 863 return fragment.release(); |
| 868 } | 864 } |
| 869 | 865 |
| 870 // A string with no newlines gets added inline, rather than being put into a
paragraph. | 866 // A string with no newlines gets added inline, rather than being put into a
paragraph. |
| 871 if (string.find('\n') == kNotFound) { | 867 if (string.find('\n') == kNotFound) { |
| 872 fillContainerFromString(fragment.get(), string); | 868 fillContainerFromString(fragment.get(), string); |
| 873 return fragment.release(); | 869 return fragment.release(); |
| 874 } | 870 } |
| 875 | 871 |
| 876 // Break string into paragraphs. Extra line breaks turn into empty paragraph
s. | 872 // Break string into paragraphs. Extra line breaks turn into empty paragraph
s. |
| 877 Node* blockNode = enclosingBlock(context->firstNode()); | 873 Element* block = enclosingBlock(context->firstNode()); |
| 878 Element* block = toElement(blockNode); | 874 bool useClonesOfEnclosingBlock = block |
| 879 bool useClonesOfEnclosingBlock = blockNode | |
| 880 && blockNode->isElementNode() | |
| 881 && !isHTMLBodyElement(*block) | 875 && !isHTMLBodyElement(*block) |
| 882 && !isHTMLHtmlElement(*block) | 876 && !isHTMLHtmlElement(*block) |
| 883 && block != editableRootForPosition(context->startPosition()); | 877 && block != editableRootForPosition(context->startPosition()); |
| 884 bool useLineBreak = enclosingTextFormControl(context->startPosition()); | 878 bool useLineBreak = enclosingTextFormControl(context->startPosition()); |
| 885 | 879 |
| 886 Vector<String> list; | 880 Vector<String> list; |
| 887 string.split('\n', true, list); // true gets us empty strings in the list | 881 string.split('\n', true, list); // true gets us empty strings in the list |
| 888 size_t numLines = list.size(); | 882 size_t numLines = list.size(); |
| 889 for (size_t i = 0; i < numLines; ++i) { | 883 for (size_t i = 0; i < numLines; ++i) { |
| 890 const String& s = list[i]; | 884 const String& s = list[i]; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 913 { | 907 { |
| 914 if (!node) | 908 if (!node) |
| 915 return String(); | 909 return String(); |
| 916 | 910 |
| 917 LocalFrame* frame = node->document().frame(); | 911 LocalFrame* frame = node->document().frame(); |
| 918 if (!frame) | 912 if (!frame) |
| 919 return String(); | 913 return String(); |
| 920 | 914 |
| 921 // FIXME: This is never "for interchange". Is that right? | 915 // FIXME: This is never "for interchange". Is that right? |
| 922 String markupString = createMarkup(node, IncludeNode, 0); | 916 String markupString = createMarkup(node, IncludeNode, 0); |
| 923 Node::NodeType nodeType = node->nodeType(); | 917 if (!node->isDocumentNode() && !node->isDocumentTypeNode()) |
| 924 if (nodeType != Node::DOCUMENT_NODE && !node->isDocumentTypeNode()) | |
| 925 markupString = frame->documentTypeString() + markupString; | 918 markupString = frame->documentTypeString() + markupString; |
| 926 | 919 |
| 927 return markupString; | 920 return markupString; |
| 928 } | 921 } |
| 929 | 922 |
| 930 String urlToMarkup(const KURL& url, const String& title) | 923 String urlToMarkup(const KURL& url, const String& title) |
| 931 { | 924 { |
| 932 StringBuilder markup; | 925 StringBuilder markup; |
| 933 markup.appendLiteral("<a href=\""); | 926 markup.appendLiteral("<a href=\""); |
| 934 markup.append(url.string()); | 927 markup.append(url.string()); |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1091 // FIXME: No need to replace the child it is a text node and its contents ar
e already == text. | 1084 // FIXME: No need to replace the child it is a text node and its contents ar
e already == text. |
| 1092 if (containerNode->hasOneChild()) { | 1085 if (containerNode->hasOneChild()) { |
| 1093 containerNode->replaceChild(textNode.release(), containerNode->firstChil
d(), exceptionState); | 1086 containerNode->replaceChild(textNode.release(), containerNode->firstChil
d(), exceptionState); |
| 1094 return; | 1087 return; |
| 1095 } | 1088 } |
| 1096 | 1089 |
| 1097 containerNode->removeChildren(); | 1090 containerNode->removeChildren(); |
| 1098 containerNode->appendChild(textNode.release(), exceptionState); | 1091 containerNode->appendChild(textNode.release(), exceptionState); |
| 1099 } | 1092 } |
| 1100 | 1093 |
| 1101 void mergeWithNextTextNode(PassRefPtrWillBeRawPtr<Node> node, ExceptionState& ex
ceptionState) | 1094 void mergeWithNextTextNode(Text* textNode, ExceptionState& exceptionState) |
| 1102 { | 1095 { |
| 1103 ASSERT(node && node->isTextNode()); | 1096 ASSERT(textNode); |
| 1104 Node* next = node->nextSibling(); | 1097 Node* next = textNode->nextSibling(); |
| 1105 if (!next || !next->isTextNode()) | 1098 if (!next || !next->isTextNode()) |
| 1106 return; | 1099 return; |
| 1107 | 1100 |
| 1108 RefPtrWillBeRawPtr<Text> textNode = toText(node.get()); | |
| 1109 RefPtrWillBeRawPtr<Text> textNext = toText(next); | 1101 RefPtrWillBeRawPtr<Text> textNext = toText(next); |
| 1110 textNode->appendData(textNext->data()); | 1102 textNode->appendData(textNext->data()); |
| 1111 if (textNext->parentNode()) // Might have been removed by mutation event. | 1103 if (textNext->parentNode()) // Might have been removed by mutation event. |
| 1112 textNext->remove(exceptionState); | 1104 textNext->remove(exceptionState); |
| 1113 } | 1105 } |
| 1114 | 1106 |
| 1115 String createStyledMarkupForNavigationTransition(Node* node) | 1107 String createStyledMarkupForNavigationTransition(Node* node) |
| 1116 { | 1108 { |
| 1117 node->document().updateLayoutIgnorePendingStylesheets(); | 1109 node->document().updateLayoutIgnorePendingStylesheets(); |
| 1118 | 1110 |
| 1119 StyledMarkupAccumulator accumulator(0, ResolveAllURLs, AnnotateForNavigation
Transition, nullptr, 0); | 1111 StyledMarkupAccumulator accumulator(0, ResolveAllURLs, AnnotateForNavigation
Transition, nullptr, 0); |
| 1120 accumulator.serializeNodes(node, NodeTraversal::nextSkippingChildren(*node))
; | 1112 accumulator.serializeNodes(node, NodeTraversal::nextSkippingChildren(*node))
; |
| 1121 | 1113 |
| 1122 static const char* documentMarkup = "<!DOCTYPE html><meta name=\"viewport\"
content=\"width=device-width, user-scalable=0\">"; | 1114 static const char* documentMarkup = "<!DOCTYPE html><meta name=\"viewport\"
content=\"width=device-width, user-scalable=0\">"; |
| 1123 return documentMarkup + accumulator.takeResults(); | 1115 return documentMarkup + accumulator.takeResults(); |
| 1124 } | 1116 } |
| 1125 | 1117 |
| 1126 } | 1118 } |
| OLD | NEW |