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 |