| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2005, 2006, 2008, 2009 Apple Inc. All rights reserved. | 2 * Copyright (C) 2005, 2006, 2008, 2009 Apple Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 26 matching lines...) Expand all Loading... |
| 37 #include "core/dom/NodeTraversal.h" | 37 #include "core/dom/NodeTraversal.h" |
| 38 #include "core/dom/Range.h" | 38 #include "core/dom/Range.h" |
| 39 #include "core/dom/Text.h" | 39 #include "core/dom/Text.h" |
| 40 #include "core/editing/EditingStyle.h" | 40 #include "core/editing/EditingStyle.h" |
| 41 #include "core/editing/HTMLInterchange.h" | 41 #include "core/editing/HTMLInterchange.h" |
| 42 #include "core/editing/PlainTextRange.h" | 42 #include "core/editing/PlainTextRange.h" |
| 43 #include "core/editing/TextIterator.h" | 43 #include "core/editing/TextIterator.h" |
| 44 #include "core/editing/VisibleUnits.h" | 44 #include "core/editing/VisibleUnits.h" |
| 45 #include "core/editing/htmlediting.h" | 45 #include "core/editing/htmlediting.h" |
| 46 #include "core/frame/UseCounter.h" | 46 #include "core/frame/UseCounter.h" |
| 47 #include "core/html/HTMLFontElement.h" |
| 48 #include "core/html/HTMLSpanElement.h" |
| 47 #include "core/rendering/RenderObject.h" | 49 #include "core/rendering/RenderObject.h" |
| 48 #include "core/rendering/RenderText.h" | 50 #include "core/rendering/RenderText.h" |
| 49 #include "platform/heap/Handle.h" | 51 #include "platform/heap/Handle.h" |
| 50 #include "wtf/StdLibExtras.h" | 52 #include "wtf/StdLibExtras.h" |
| 51 #include "wtf/text/StringBuilder.h" | 53 #include "wtf/text/StringBuilder.h" |
| 52 | 54 |
| 53 namespace blink { | 55 namespace blink { |
| 54 | 56 |
| 55 using namespace HTMLNames; | 57 using namespace HTMLNames; |
| 56 | 58 |
| 57 static String& styleSpanClassString() | 59 static String& styleSpanClassString() |
| 58 { | 60 { |
| 59 DEFINE_STATIC_LOCAL(String, styleSpanClassString, ((AppleStyleSpanClass))); | 61 DEFINE_STATIC_LOCAL(String, styleSpanClassString, ((AppleStyleSpanClass))); |
| 60 return styleSpanClassString; | 62 return styleSpanClassString; |
| 61 } | 63 } |
| 62 | 64 |
| 63 bool isLegacyAppleStyleSpan(const Node *node) | 65 bool isLegacyAppleStyleSpan(const Node* node) |
| 64 { | 66 { |
| 65 if (!node || !node->isHTMLElement()) | 67 if (!isHTMLSpanElement(node)) |
| 66 return false; | 68 return false; |
| 67 | 69 |
| 68 const HTMLElement& element = toHTMLElement(*node); | 70 const HTMLSpanElement& span = toHTMLSpanElement(*node); |
| 69 if (!isHTMLSpanElement(element) || element.getAttribute(classAttr) != styleS
panClassString()) | 71 if (span.getAttribute(classAttr) != styleSpanClassString()) |
| 70 return false; | 72 return false; |
| 71 UseCounter::count(element.document(), UseCounter::EditingAppleStyleSpanClass
); | 73 UseCounter::count(span.document(), UseCounter::EditingAppleStyleSpanClass); |
| 72 return true; | 74 return true; |
| 73 } | 75 } |
| 74 | 76 |
| 75 static bool hasNoAttributeOrOnlyStyleAttribute(const Element* element, ShouldSty
leAttributeBeEmpty shouldStyleAttributeBeEmpty) | 77 static bool hasNoAttributeOrOnlyStyleAttribute(const HTMLElement* element, Shoul
dStyleAttributeBeEmpty shouldStyleAttributeBeEmpty) |
| 76 { | 78 { |
| 77 if (!element->hasAttributes()) | 79 if (!element->hasAttributes()) |
| 78 return true; | 80 return true; |
| 79 | 81 |
| 80 unsigned matchedAttributes = 0; | 82 unsigned matchedAttributes = 0; |
| 81 if (element->getAttribute(classAttr) == styleSpanClassString()) | 83 if (element->getAttribute(classAttr) == styleSpanClassString()) |
| 82 matchedAttributes++; | 84 matchedAttributes++; |
| 83 if (element->hasAttribute(styleAttr) && (shouldStyleAttributeBeEmpty == Allo
wNonEmptyStyleAttribute | 85 if (element->hasAttribute(styleAttr) && (shouldStyleAttributeBeEmpty == Allo
wNonEmptyStyleAttribute |
| 84 || !element->inlineStyle() || element->inlineStyle()->isEmpty())) | 86 || !element->inlineStyle() || element->inlineStyle()->isEmpty())) |
| 85 matchedAttributes++; | 87 matchedAttributes++; |
| 86 | 88 |
| 87 ASSERT(matchedAttributes <= element->attributes().size()); | 89 ASSERT(matchedAttributes <= element->attributes().size()); |
| 88 return matchedAttributes == element->attributes().size(); | 90 return matchedAttributes == element->attributes().size(); |
| 89 } | 91 } |
| 90 | 92 |
| 91 bool isStyleSpanOrSpanWithOnlyStyleAttribute(const Element* element) | 93 bool isStyleSpanOrSpanWithOnlyStyleAttribute(const Element* element) |
| 92 { | 94 { |
| 93 if (!isHTMLSpanElement(element)) | 95 if (!isHTMLSpanElement(element)) |
| 94 return false; | 96 return false; |
| 95 return hasNoAttributeOrOnlyStyleAttribute(toHTMLElement(element), AllowNonEm
ptyStyleAttribute); | 97 return hasNoAttributeOrOnlyStyleAttribute(toHTMLSpanElement(element), AllowN
onEmptyStyleAttribute); |
| 96 } | 98 } |
| 97 | 99 |
| 98 static inline bool isSpanWithoutAttributesOrUnstyledStyleSpan(const Node* node) | 100 static inline bool isSpanWithoutAttributesOrUnstyledStyleSpan(const Node* node) |
| 99 { | 101 { |
| 100 if (!isHTMLSpanElement(node)) | 102 if (!isHTMLSpanElement(node)) |
| 101 return false; | 103 return false; |
| 102 return hasNoAttributeOrOnlyStyleAttribute(toHTMLElement(node), StyleAttribut
eShouldBeEmpty); | 104 return hasNoAttributeOrOnlyStyleAttribute(toHTMLSpanElement(node), StyleAttr
ibuteShouldBeEmpty); |
| 103 } | 105 } |
| 104 | 106 |
| 105 bool isEmptyFontTag(const Element* element, ShouldStyleAttributeBeEmpty shouldSt
yleAttributeBeEmpty) | 107 bool isEmptyFontTag(const Element* element, ShouldStyleAttributeBeEmpty shouldSt
yleAttributeBeEmpty) |
| 106 { | 108 { |
| 107 if (!isHTMLFontElement(element)) | 109 if (!isHTMLFontElement(element)) |
| 108 return false; | 110 return false; |
| 109 | 111 |
| 110 return hasNoAttributeOrOnlyStyleAttribute(toHTMLElement(element), shouldStyl
eAttributeBeEmpty); | 112 return hasNoAttributeOrOnlyStyleAttribute(toHTMLFontElement(element), should
StyleAttributeBeEmpty); |
| 111 } | 113 } |
| 112 | 114 |
| 113 static PassRefPtrWillBeRawPtr<Element> createFontElement(Document& document) | 115 static PassRefPtrWillBeRawPtr<HTMLFontElement> createFontElement(Document& docum
ent) |
| 114 { | 116 { |
| 115 return createHTMLElement(document, fontTag); | 117 return toHTMLFontElement(createHTMLElement(document, fontTag).get()); |
| 116 } | 118 } |
| 117 | 119 |
| 118 PassRefPtrWillBeRawPtr<HTMLElement> createStyleSpanElement(Document& document) | 120 PassRefPtrWillBeRawPtr<HTMLSpanElement> createStyleSpanElement(Document& documen
t) |
| 119 { | 121 { |
| 120 return createHTMLElement(document, spanTag); | 122 return toHTMLSpanElement(createHTMLElement(document, spanTag).get()); |
| 121 } | 123 } |
| 122 | 124 |
| 123 ApplyStyleCommand::ApplyStyleCommand(Document& document, const EditingStyle* sty
le, EditAction editingAction, EPropertyLevel propertyLevel) | 125 ApplyStyleCommand::ApplyStyleCommand(Document& document, const EditingStyle* sty
le, EditAction editingAction, EPropertyLevel propertyLevel) |
| 124 : CompositeEditCommand(document) | 126 : CompositeEditCommand(document) |
| 125 , m_style(style->copy()) | 127 , m_style(style->copy()) |
| 126 , m_editingAction(editingAction) | 128 , m_editingAction(editingAction) |
| 127 , m_propertyLevel(propertyLevel) | 129 , m_propertyLevel(propertyLevel) |
| 128 , m_start(endingSelection().start().downstream()) | 130 , m_start(endingSelection().start().downstream()) |
| 129 , m_end(endingSelection().end().upstream()) | 131 , m_end(endingSelection().end().upstream()) |
| 130 , m_useEndingSelection(true) | 132 , m_useEndingSelection(true) |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 RefPtrWillBeRawPtr<Range> endRange = Range::create(document(), firstPosition
InNode(&scope), visibleEnd.deepEquivalent().parentAnchoredEquivalent()); | 263 RefPtrWillBeRawPtr<Range> endRange = Range::create(document(), firstPosition
InNode(&scope), visibleEnd.deepEquivalent().parentAnchoredEquivalent()); |
| 262 int startIndex = TextIterator::rangeLength(startRange.get(), true); | 264 int startIndex = TextIterator::rangeLength(startRange.get(), true); |
| 263 int endIndex = TextIterator::rangeLength(endRange.get(), true); | 265 int endIndex = TextIterator::rangeLength(endRange.get(), true); |
| 264 | 266 |
| 265 VisiblePosition paragraphStart(startOfParagraph(visibleStart)); | 267 VisiblePosition paragraphStart(startOfParagraph(visibleStart)); |
| 266 VisiblePosition nextParagraphStart(endOfParagraph(paragraphStart).next()); | 268 VisiblePosition nextParagraphStart(endOfParagraph(paragraphStart).next()); |
| 267 VisiblePosition beyondEnd(endOfParagraph(visibleEnd).next()); | 269 VisiblePosition beyondEnd(endOfParagraph(visibleEnd).next()); |
| 268 while (paragraphStart.isNotNull() && paragraphStart != beyondEnd) { | 270 while (paragraphStart.isNotNull() && paragraphStart != beyondEnd) { |
| 269 StyleChange styleChange(style, paragraphStart.deepEquivalent()); | 271 StyleChange styleChange(style, paragraphStart.deepEquivalent()); |
| 270 if (styleChange.cssStyle().length() || m_removeOnly) { | 272 if (styleChange.cssStyle().length() || m_removeOnly) { |
| 271 RefPtrWillBeRawPtr<Node> block = enclosingBlock(paragraphStart.deepE
quivalent().deprecatedNode()); | 273 RefPtrWillBeRawPtr<Element> block = enclosingBlock(paragraphStart.de
epEquivalent().deprecatedNode()); |
| 272 const Position& paragraphStartToMove = paragraphStart.deepEquivalent
(); | 274 const Position& paragraphStartToMove = paragraphStart.deepEquivalent
(); |
| 273 if (!m_removeOnly && isEditablePosition(paragraphStartToMove)) { | 275 if (!m_removeOnly && isEditablePosition(paragraphStartToMove)) { |
| 274 RefPtrWillBeRawPtr<Element> newBlock = moveParagraphContentsToNe
wBlockIfNecessary(paragraphStartToMove); | 276 RefPtrWillBeRawPtr<Element> newBlock = moveParagraphContentsToNe
wBlockIfNecessary(paragraphStartToMove); |
| 275 if (newBlock) | 277 if (newBlock) |
| 276 block = newBlock; | 278 block = newBlock; |
| 277 } | 279 } |
| 278 ASSERT(!block || block->isElementNode()); | |
| 279 if (block && block->isHTMLElement()) { | 280 if (block && block->isHTMLElement()) { |
| 280 removeCSSStyle(style, toHTMLElement(block)); | 281 removeCSSStyle(style, toHTMLElement(block)); |
| 281 if (!m_removeOnly) | 282 if (!m_removeOnly) |
| 282 addBlockStyle(styleChange, toHTMLElement(block)); | 283 addBlockStyle(styleChange, toHTMLElement(block)); |
| 283 } | 284 } |
| 284 | 285 |
| 285 if (nextParagraphStart.isOrphan()) | 286 if (nextParagraphStart.isOrphan()) |
| 286 nextParagraphStart = endOfParagraph(paragraphStart).next(); | 287 nextParagraphStart = endOfParagraph(paragraphStart).next(); |
| 287 } | 288 } |
| 288 | 289 |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 | 384 |
| 384 // These spans were added by us. If empty after font size changes, they can
be removed. | 385 // These spans were added by us. If empty after font size changes, they can
be removed. |
| 385 WillBeHeapVector<RefPtrWillBeMember<HTMLElement> > unstyledSpans; | 386 WillBeHeapVector<RefPtrWillBeMember<HTMLElement> > unstyledSpans; |
| 386 | 387 |
| 387 Node* lastStyledNode = 0; | 388 Node* lastStyledNode = 0; |
| 388 for (Node* node = startNode; node != beyondEnd; node = NodeTraversal::next(*
node)) { | 389 for (Node* node = startNode; node != beyondEnd; node = NodeTraversal::next(*
node)) { |
| 389 ASSERT(node); | 390 ASSERT(node); |
| 390 RefPtrWillBeRawPtr<HTMLElement> element = nullptr; | 391 RefPtrWillBeRawPtr<HTMLElement> element = nullptr; |
| 391 if (node->isHTMLElement()) { | 392 if (node->isHTMLElement()) { |
| 392 // Only work on fully selected nodes. | 393 // Only work on fully selected nodes. |
| 393 if (!nodeFullySelected(node, start, end)) | 394 if (!elementFullySelected(toHTMLElement(*node), start, end)) |
| 394 continue; | 395 continue; |
| 395 element = toHTMLElement(node); | 396 element = toHTMLElement(node); |
| 396 } else if (node->isTextNode() && node->renderer() && node->parentNode()
!= lastStyledNode) { | 397 } else if (node->isTextNode() && node->renderer() && node->parentNode()
!= lastStyledNode) { |
| 397 // Last styled node was not parent node of this text node, but we wi
sh to style this | 398 // Last styled node was not parent node of this text node, but we wi
sh to style this |
| 398 // text node. To make this possible, add a style span to surround th
is text node. | 399 // text node. To make this possible, add a style span to surround th
is text node. |
| 399 RefPtrWillBeRawPtr<HTMLElement> span = createStyleSpanElement(docume
nt()); | 400 RefPtrWillBeRawPtr<HTMLSpanElement> span = createStyleSpanElement(do
cument()); |
| 400 surroundNodeRangeWithElement(node, node, span.get()); | 401 surroundNodeRangeWithElement(node, node, span.get()); |
| 401 element = span.release(); | 402 element = span.release(); |
| 402 } else { | 403 } else { |
| 403 // Only handle HTML elements and text nodes. | 404 // Only handle HTML elements and text nodes. |
| 404 continue; | 405 continue; |
| 405 } | 406 } |
| 406 lastStyledNode = node; | 407 lastStyledNode = node; |
| 407 | 408 |
| 408 RefPtrWillBeRawPtr<MutableStylePropertySet> inlineStyle = copyStyleOrCre
ateEmpty(element->inlineStyle()); | 409 RefPtrWillBeRawPtr<MutableStylePropertySet> inlineStyle = copyStyleOrCre
ateEmpty(element->inlineStyle()); |
| 409 float currentFontSize = computedFontSize(node); | 410 float currentFontSize = computedFontSize(node); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 451 next = node->nextSibling(); | 452 next = node->nextSibling(); |
| 452 if (isSpanWithoutAttributesOrUnstyledStyleSpan(node)) | 453 if (isSpanWithoutAttributesOrUnstyledStyleSpan(node)) |
| 453 removeNodePreservingChildren(node); | 454 removeNodePreservingChildren(node); |
| 454 } | 455 } |
| 455 } | 456 } |
| 456 | 457 |
| 457 HTMLElement* ApplyStyleCommand::splitAncestorsWithUnicodeBidi(Node* node, bool b
efore, WritingDirection allowedDirection) | 458 HTMLElement* ApplyStyleCommand::splitAncestorsWithUnicodeBidi(Node* node, bool b
efore, WritingDirection allowedDirection) |
| 458 { | 459 { |
| 459 // We are allowed to leave the highest ancestor with unicode-bidi unsplit if
it is unicode-bidi: embed and direction: allowedDirection. | 460 // We are allowed to leave the highest ancestor with unicode-bidi unsplit if
it is unicode-bidi: embed and direction: allowedDirection. |
| 460 // In that case, we return the unsplit ancestor. Otherwise, we return 0. | 461 // In that case, we return the unsplit ancestor. Otherwise, we return 0. |
| 461 Node* block = enclosingBlock(node); | 462 Element* block = enclosingBlock(node); |
| 462 if (!block) | 463 if (!block) |
| 463 return 0; | 464 return 0; |
| 464 | 465 |
| 465 Node* highestAncestorWithUnicodeBidi = 0; | 466 ContainerNode* highestAncestorWithUnicodeBidi = 0; |
| 466 Node* nextHighestAncestorWithUnicodeBidi = 0; | 467 ContainerNode* nextHighestAncestorWithUnicodeBidi = 0; |
| 467 int highestAncestorUnicodeBidi = 0; | 468 int highestAncestorUnicodeBidi = 0; |
| 468 for (Node* n = node->parentNode(); n != block; n = n->parentNode()) { | 469 for (ContainerNode* n = node->parentNode(); n != block; n = n->parentNode())
{ |
| 469 int unicodeBidi = getIdentifierValue(CSSComputedStyleDeclaration::create
(n).get(), CSSPropertyUnicodeBidi); | 470 int unicodeBidi = getIdentifierValue(CSSComputedStyleDeclaration::create
(n).get(), CSSPropertyUnicodeBidi); |
| 470 if (unicodeBidi && unicodeBidi != CSSValueNormal) { | 471 if (unicodeBidi && unicodeBidi != CSSValueNormal) { |
| 471 highestAncestorUnicodeBidi = unicodeBidi; | 472 highestAncestorUnicodeBidi = unicodeBidi; |
| 472 nextHighestAncestorWithUnicodeBidi = highestAncestorWithUnicodeBidi; | 473 nextHighestAncestorWithUnicodeBidi = highestAncestorWithUnicodeBidi; |
| 473 highestAncestorWithUnicodeBidi = n; | 474 highestAncestorWithUnicodeBidi = n; |
| 474 } | 475 } |
| 475 } | 476 } |
| 476 | 477 |
| 477 if (!highestAncestorWithUnicodeBidi) | 478 if (!highestAncestorWithUnicodeBidi) |
| 478 return 0; | 479 return 0; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 498 RefPtrWillBeRawPtr<Element> parent = toElement(currentNode->parentNode()
); | 499 RefPtrWillBeRawPtr<Element> parent = toElement(currentNode->parentNode()
); |
| 499 if (before ? currentNode->previousSibling() : currentNode->nextSibling()
) | 500 if (before ? currentNode->previousSibling() : currentNode->nextSibling()
) |
| 500 splitElement(parent, before ? currentNode.get() : currentNode->nextS
ibling()); | 501 splitElement(parent, before ? currentNode.get() : currentNode->nextS
ibling()); |
| 501 if (parent == highestAncestorWithUnicodeBidi) | 502 if (parent == highestAncestorWithUnicodeBidi) |
| 502 break; | 503 break; |
| 503 currentNode = parent; | 504 currentNode = parent; |
| 504 } | 505 } |
| 505 return unsplitAncestor; | 506 return unsplitAncestor; |
| 506 } | 507 } |
| 507 | 508 |
| 508 void ApplyStyleCommand::removeEmbeddingUpToEnclosingBlock(Node* node, Node* unsp
litAncestor) | 509 void ApplyStyleCommand::removeEmbeddingUpToEnclosingBlock(Node* node, HTMLElemen
t* unsplitAncestor) |
| 509 { | 510 { |
| 510 Node* block = enclosingBlock(node); | 511 Element* block = enclosingBlock(node); |
| 511 if (!block) | 512 if (!block) |
| 512 return; | 513 return; |
| 513 | 514 |
| 514 for (Node* n = node->parentNode(); n != block && n != unsplitAncestor; n = n
->parentNode()) { | 515 for (ContainerNode* n = node->parentNode(); n != block && n != unsplitAncest
or; n = n->parentNode()) { |
| 515 if (!n->isStyledElement()) | 516 if (!n->isStyledElement()) |
| 516 continue; | 517 continue; |
| 517 | 518 |
| 518 Element* element = toElement(n); | 519 Element* element = toElement(n); |
| 519 int unicodeBidi = getIdentifierValue(CSSComputedStyleDeclaration::create
(element).get(), CSSPropertyUnicodeBidi); | 520 int unicodeBidi = getIdentifierValue(CSSComputedStyleDeclaration::create
(element).get(), CSSPropertyUnicodeBidi); |
| 520 if (!unicodeBidi || unicodeBidi == CSSValueNormal) | 521 if (!unicodeBidi || unicodeBidi == CSSValueNormal) |
| 521 continue; | 522 continue; |
| 522 | 523 |
| 523 // FIXME: This code should really consider the mapped attribute 'dir', t
he inline style declaration, | 524 // FIXME: This code should really consider the mapped attribute 'dir', t
he inline style declaration, |
| 524 // and all matching style rules in order to determine how to best set th
e unicode-bidi property to 'normal'. | 525 // and all matching style rules in order to determine how to best set th
e unicode-bidi property to 'normal'. |
| 525 // For now, it assumes that if the 'dir' attribute is present, then remo
ving it will suffice, and | 526 // For now, it assumes that if the 'dir' attribute is present, then remo
ving it will suffice, and |
| 526 // otherwise it sets the property in the inline style declaration. | 527 // otherwise it sets the property in the inline style declaration. |
| 527 if (element->hasAttribute(dirAttr)) { | 528 if (element->hasAttribute(dirAttr)) { |
| 528 // FIXME: If this is a BDO element, we should probably just remove i
t if it has no | 529 // FIXME: If this is a BDO element, we should probably just remove i
t if it has no |
| 529 // other attributes, like we (should) do with B and I elements. | 530 // other attributes, like we (should) do with B and I elements. |
| 530 removeNodeAttribute(element, dirAttr); | 531 removeNodeAttribute(element, dirAttr); |
| 531 } else { | 532 } else { |
| 532 RefPtrWillBeRawPtr<MutableStylePropertySet> inlineStyle = copyStyleO
rCreateEmpty(element->inlineStyle()); | 533 RefPtrWillBeRawPtr<MutableStylePropertySet> inlineStyle = copyStyleO
rCreateEmpty(element->inlineStyle()); |
| 533 inlineStyle->setProperty(CSSPropertyUnicodeBidi, CSSValueNormal); | 534 inlineStyle->setProperty(CSSPropertyUnicodeBidi, CSSValueNormal); |
| 534 inlineStyle->removeProperty(CSSPropertyDirection); | 535 inlineStyle->removeProperty(CSSPropertyDirection); |
| 535 setNodeAttribute(element, styleAttr, AtomicString(inlineStyle->asTex
t())); | 536 setNodeAttribute(element, styleAttr, AtomicString(inlineStyle->asTex
t())); |
| 536 if (isSpanWithoutAttributesOrUnstyledStyleSpan(element)) | 537 if (isSpanWithoutAttributesOrUnstyledStyleSpan(element)) |
| 537 removeNodePreservingChildren(element); | 538 removeNodePreservingChildren(element); |
| 538 } | 539 } |
| 539 } | 540 } |
| 540 } | 541 } |
| 541 | 542 |
| 542 static Node* highestEmbeddingAncestor(Node* startNode, Node* enclosingNode) | 543 static HTMLElement* highestEmbeddingAncestor(Node* startNode, Node* enclosingNod
e) |
| 543 { | 544 { |
| 544 for (Node* n = startNode; n && n != enclosingNode; n = n->parentNode()) { | 545 for (Node* n = startNode; n && n != enclosingNode; n = n->parentNode()) { |
| 545 if (n->isHTMLElement() && getIdentifierValue(CSSComputedStyleDeclaration
::create(n).get(), CSSPropertyUnicodeBidi) == CSSValueEmbed) | 546 if (n->isHTMLElement() && getIdentifierValue(CSSComputedStyleDeclaration
::create(n).get(), CSSPropertyUnicodeBidi) == CSSValueEmbed) |
| 546 return n; | 547 return toHTMLElement(n); |
| 547 } | 548 } |
| 548 | 549 |
| 549 return 0; | 550 return 0; |
| 550 } | 551 } |
| 551 | 552 |
| 552 void ApplyStyleCommand::applyInlineStyle(EditingStyle* style) | 553 void ApplyStyleCommand::applyInlineStyle(EditingStyle* style) |
| 553 { | 554 { |
| 554 RefPtrWillBeRawPtr<ContainerNode> startDummySpanAncestor = nullptr; | 555 RefPtrWillBeRawPtr<ContainerNode> startDummySpanAncestor = nullptr; |
| 555 RefPtrWillBeRawPtr<ContainerNode> endDummySpanAncestor = nullptr; | 556 RefPtrWillBeRawPtr<ContainerNode> endDummySpanAncestor = nullptr; |
| 556 | 557 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 608 RefPtrWillBeRawPtr<EditingStyle> embeddingStyle = nullptr; | 609 RefPtrWillBeRawPtr<EditingStyle> embeddingStyle = nullptr; |
| 609 if (hasTextDirection) { | 610 if (hasTextDirection) { |
| 610 // Leave alone an ancestor that provides the desired single level embedd
ing, if there is one. | 611 // Leave alone an ancestor that provides the desired single level embedd
ing, if there is one. |
| 611 HTMLElement* startUnsplitAncestor = splitAncestorsWithUnicodeBidi(start.
deprecatedNode(), true, textDirection); | 612 HTMLElement* startUnsplitAncestor = splitAncestorsWithUnicodeBidi(start.
deprecatedNode(), true, textDirection); |
| 612 HTMLElement* endUnsplitAncestor = splitAncestorsWithUnicodeBidi(end.depr
ecatedNode(), false, textDirection); | 613 HTMLElement* endUnsplitAncestor = splitAncestorsWithUnicodeBidi(end.depr
ecatedNode(), false, textDirection); |
| 613 removeEmbeddingUpToEnclosingBlock(start.deprecatedNode(), startUnsplitAn
cestor); | 614 removeEmbeddingUpToEnclosingBlock(start.deprecatedNode(), startUnsplitAn
cestor); |
| 614 removeEmbeddingUpToEnclosingBlock(end.deprecatedNode(), endUnsplitAncest
or); | 615 removeEmbeddingUpToEnclosingBlock(end.deprecatedNode(), endUnsplitAncest
or); |
| 615 | 616 |
| 616 // Avoid removing the dir attribute and the unicode-bidi and direction p
roperties from the unsplit ancestors. | 617 // Avoid removing the dir attribute and the unicode-bidi and direction p
roperties from the unsplit ancestors. |
| 617 Position embeddingRemoveStart = removeStart; | 618 Position embeddingRemoveStart = removeStart; |
| 618 if (startUnsplitAncestor && nodeFullySelected(startUnsplitAncestor, remo
veStart, end)) | 619 if (startUnsplitAncestor && elementFullySelected(*startUnsplitAncestor,
removeStart, end)) |
| 619 embeddingRemoveStart = positionInParentAfterNode(*startUnsplitAncest
or); | 620 embeddingRemoveStart = positionInParentAfterNode(*startUnsplitAncest
or); |
| 620 | 621 |
| 621 Position embeddingRemoveEnd = end; | 622 Position embeddingRemoveEnd = end; |
| 622 if (endUnsplitAncestor && nodeFullySelected(endUnsplitAncestor, removeSt
art, end)) | 623 if (endUnsplitAncestor && elementFullySelected(*endUnsplitAncestor, remo
veStart, end)) |
| 623 embeddingRemoveEnd = positionInParentBeforeNode(*endUnsplitAncestor)
.downstream(); | 624 embeddingRemoveEnd = positionInParentBeforeNode(*endUnsplitAncestor)
.downstream(); |
| 624 | 625 |
| 625 if (embeddingRemoveEnd != removeStart || embeddingRemoveEnd != end) { | 626 if (embeddingRemoveEnd != removeStart || embeddingRemoveEnd != end) { |
| 626 styleWithoutEmbedding = style->copy(); | 627 styleWithoutEmbedding = style->copy(); |
| 627 embeddingStyle = styleWithoutEmbedding->extractAndRemoveTextDirectio
n(); | 628 embeddingStyle = styleWithoutEmbedding->extractAndRemoveTextDirectio
n(); |
| 628 | 629 |
| 629 if (comparePositions(embeddingRemoveStart, embeddingRemoveEnd) <= 0) | 630 if (comparePositions(embeddingRemoveStart, embeddingRemoveEnd) <= 0) |
| 630 removeInlineStyle(embeddingStyle.get(), embeddingRemoveStart, em
beddingRemoveEnd); | 631 removeInlineStyle(embeddingStyle.get(), embeddingRemoveStart, em
beddingRemoveEnd); |
| 631 } | 632 } |
| 632 } | 633 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 649 } | 650 } |
| 650 | 651 |
| 651 // update document layout once before running the rest of the function | 652 // update document layout once before running the rest of the function |
| 652 // so that we avoid the expense of updating before each and every call | 653 // so that we avoid the expense of updating before each and every call |
| 653 // to check a computed style | 654 // to check a computed style |
| 654 document().updateLayoutIgnorePendingStylesheets(); | 655 document().updateLayoutIgnorePendingStylesheets(); |
| 655 | 656 |
| 656 RefPtrWillBeRawPtr<EditingStyle> styleToApply = style; | 657 RefPtrWillBeRawPtr<EditingStyle> styleToApply = style; |
| 657 if (hasTextDirection) { | 658 if (hasTextDirection) { |
| 658 // Avoid applying the unicode-bidi and direction properties beneath ance
stors that already have them. | 659 // Avoid applying the unicode-bidi and direction properties beneath ance
stors that already have them. |
| 659 Node* embeddingStartNode = highestEmbeddingAncestor(start.deprecatedNode
(), enclosingBlock(start.deprecatedNode())); | 660 HTMLElement* embeddingStartElement = highestEmbeddingAncestor(start.depr
ecatedNode(), enclosingBlock(start.deprecatedNode())); |
| 660 Node* embeddingEndNode = highestEmbeddingAncestor(end.deprecatedNode(),
enclosingBlock(end.deprecatedNode())); | 661 HTMLElement* embeddingEndElement = highestEmbeddingAncestor(end.deprecat
edNode(), enclosingBlock(end.deprecatedNode())); |
| 661 | 662 |
| 662 if (embeddingStartNode || embeddingEndNode) { | 663 if (embeddingStartElement || embeddingEndElement) { |
| 663 Position embeddingApplyStart = embeddingStartNode ? positionInParent
AfterNode(*embeddingStartNode) : start; | 664 Position embeddingApplyStart = embeddingStartElement ? positionInPar
entAfterNode(*embeddingStartElement) : start; |
| 664 Position embeddingApplyEnd = embeddingEndNode ? positionInParentBefo
reNode(*embeddingEndNode) : end; | 665 Position embeddingApplyEnd = embeddingEndElement ? positionInParentB
eforeNode(*embeddingEndElement) : end; |
| 665 ASSERT(embeddingApplyStart.isNotNull() && embeddingApplyEnd.isNotNul
l()); | 666 ASSERT(embeddingApplyStart.isNotNull() && embeddingApplyEnd.isNotNul
l()); |
| 666 | 667 |
| 667 if (!embeddingStyle) { | 668 if (!embeddingStyle) { |
| 668 styleWithoutEmbedding = style->copy(); | 669 styleWithoutEmbedding = style->copy(); |
| 669 embeddingStyle = styleWithoutEmbedding->extractAndRemoveTextDire
ction(); | 670 embeddingStyle = styleWithoutEmbedding->extractAndRemoveTextDire
ction(); |
| 670 } | 671 } |
| 671 fixRangeAndApplyInlineStyle(embeddingStyle.get(), embeddingApplyStar
t, embeddingApplyEnd); | 672 fixRangeAndApplyInlineStyle(embeddingStyle.get(), embeddingApplyStar
t, embeddingApplyEnd); |
| 672 | 673 |
| 673 styleToApply = styleWithoutEmbedding; | 674 styleToApply = styleWithoutEmbedding; |
| 674 } | 675 } |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 751 visitor->trace(end); | 752 visitor->trace(end); |
| 752 visitor->trace(pastEndNode); | 753 visitor->trace(pastEndNode); |
| 753 visitor->trace(positionForStyleComputation); | 754 visitor->trace(positionForStyleComputation); |
| 754 visitor->trace(dummyElement); | 755 visitor->trace(dummyElement); |
| 755 } | 756 } |
| 756 | 757 |
| 757 RefPtrWillBeMember<Node> start; | 758 RefPtrWillBeMember<Node> start; |
| 758 RefPtrWillBeMember<Node> end; | 759 RefPtrWillBeMember<Node> end; |
| 759 RefPtrWillBeMember<Node> pastEndNode; | 760 RefPtrWillBeMember<Node> pastEndNode; |
| 760 Position positionForStyleComputation; | 761 Position positionForStyleComputation; |
| 761 RefPtrWillBeMember<Node> dummyElement; | 762 RefPtrWillBeMember<HTMLSpanElement> dummyElement; |
| 762 StyleChange change; | 763 StyleChange change; |
| 763 }; | 764 }; |
| 764 | 765 |
| 765 } // namespace blink | 766 } // namespace blink |
| 766 | 767 |
| 767 WTF_ALLOW_INIT_WITH_MEM_FUNCTIONS(blink::InlineRunToApplyStyle); | 768 WTF_ALLOW_INIT_WITH_MEM_FUNCTIONS(blink::InlineRunToApplyStyle); |
| 768 | 769 |
| 769 namespace blink { | 770 namespace blink { |
| 770 | 771 |
| 771 void ApplyStyleCommand::applyInlineStyleToNodeRange(EditingStyle* style, PassRef
PtrWillBeRawPtr<Node> startNode, PassRefPtrWillBeRawPtr<Node> pastEndNode) | 772 void ApplyStyleCommand::applyInlineStyleToNodeRange(EditingStyle* style, PassRef
PtrWillBeRawPtr<Node> startNode, PassRefPtrWillBeRawPtr<Node> pastEndNode) |
| 772 { | 773 { |
| 773 if (m_removeOnly) | 774 if (m_removeOnly) |
| 774 return; | 775 return; |
| 775 | 776 |
| 776 document().updateLayoutIgnorePendingStylesheets(); | 777 document().updateLayoutIgnorePendingStylesheets(); |
| 777 | 778 |
| 778 WillBeHeapVector<InlineRunToApplyStyle> runs; | 779 WillBeHeapVector<InlineRunToApplyStyle> runs; |
| 779 RefPtrWillBeRawPtr<Node> node = startNode; | 780 RefPtrWillBeRawPtr<Node> node = startNode; |
| 780 for (RefPtrWillBeRawPtr<Node> next; node && node != pastEndNode; node = next
) { | 781 for (RefPtrWillBeRawPtr<Node> next; node && node != pastEndNode; node = next
) { |
| 781 next = NodeTraversal::next(*node); | 782 next = NodeTraversal::next(*node); |
| 782 | 783 |
| 783 if (!node->renderer() || !node->hasEditableStyle()) | 784 if (!node->renderer() || !node->hasEditableStyle()) |
| 784 continue; | 785 continue; |
| 785 | 786 |
| 786 if (!node->rendererIsRichlyEditable() && node->isHTMLElement()) { | 787 if (!node->rendererIsRichlyEditable() && node->isHTMLElement()) { |
| 788 HTMLElement* element = toHTMLElement(node); |
| 787 // This is a plaintext-only region. Only proceed if it's fully selec
ted. | 789 // This is a plaintext-only region. Only proceed if it's fully selec
ted. |
| 788 // pastEndNode is the node after the last fully selected node, so if
it's inside node then | 790 // pastEndNode is the node after the last fully selected node, so if
it's inside node then |
| 789 // node isn't fully selected. | 791 // node isn't fully selected. |
| 790 if (pastEndNode && pastEndNode->isDescendantOf(node.get())) | 792 if (pastEndNode && pastEndNode->isDescendantOf(element)) |
| 791 break; | 793 break; |
| 792 // Add to this element's inline style and skip over its contents. | 794 // Add to this element's inline style and skip over its contents. |
| 793 HTMLElement* element = toHTMLElement(node); | |
| 794 next = NodeTraversal::nextSkippingChildren(*node); | 795 next = NodeTraversal::nextSkippingChildren(*node); |
| 795 if (!style->style()) | 796 if (!style->style()) |
| 796 continue; | 797 continue; |
| 797 RefPtrWillBeRawPtr<MutableStylePropertySet> inlineStyle = copyStyleO
rCreateEmpty(element->inlineStyle()); | 798 RefPtrWillBeRawPtr<MutableStylePropertySet> inlineStyle = copyStyleO
rCreateEmpty(element->inlineStyle()); |
| 798 inlineStyle->mergeAndOverrideOnConflict(style->style()); | 799 inlineStyle->mergeAndOverrideOnConflict(style->style()); |
| 799 setNodeAttribute(element, styleAttr, AtomicString(inlineStyle->asTex
t())); | 800 setNodeAttribute(element, styleAttr, AtomicString(inlineStyle->asTex
t())); |
| 800 continue; | 801 continue; |
| 801 } | 802 } |
| 802 | 803 |
| 803 if (isBlock(node.get())) | 804 if (isBlock(node.get())) |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 882 for (RefPtrWillBeRawPtr<Node> node = next; node && node->inDocument() && nod
e != pastEndNode; node = next) { | 883 for (RefPtrWillBeRawPtr<Node> node = next; node && node->inDocument() && nod
e != pastEndNode; node = next) { |
| 883 if (editingIgnoresContent(node.get())) { | 884 if (editingIgnoresContent(node.get())) { |
| 884 ASSERT(!node->contains(pastEndNode.get())); | 885 ASSERT(!node->contains(pastEndNode.get())); |
| 885 next = NodeTraversal::nextSkippingChildren(*node); | 886 next = NodeTraversal::nextSkippingChildren(*node); |
| 886 } else { | 887 } else { |
| 887 next = NodeTraversal::next(*node); | 888 next = NodeTraversal::next(*node); |
| 888 } | 889 } |
| 889 if (!node->isHTMLElement()) | 890 if (!node->isHTMLElement()) |
| 890 continue; | 891 continue; |
| 891 | 892 |
| 892 RefPtrWillBeRawPtr<Node> previousSibling = node->previousSibling(); | 893 HTMLElement& element = toHTMLElement(*node); |
| 893 RefPtrWillBeRawPtr<Node> nextSibling = node->nextSibling(); | 894 RefPtrWillBeRawPtr<Node> previousSibling = element.previousSibling(); |
| 894 RefPtrWillBeRawPtr<ContainerNode> parent = node->parentNode(); | 895 RefPtrWillBeRawPtr<Node> nextSibling = element.nextSibling(); |
| 895 removeInlineStyleFromElement(style, toHTMLElement(node), RemoveAlways); | 896 RefPtrWillBeRawPtr<ContainerNode> parent = element.parentNode(); |
| 896 if (!node->inDocument()) { | 897 removeInlineStyleFromElement(style, &element, RemoveAlways); |
| 898 if (!element.inDocument()) { |
| 897 // FIXME: We might need to update the start and the end of current s
election here but need a test. | 899 // FIXME: We might need to update the start and the end of current s
election here but need a test. |
| 898 if (runStart == node) | 900 if (runStart == element) |
| 899 runStart = previousSibling ? previousSibling->nextSibling() : pa
rent->firstChild(); | 901 runStart = previousSibling ? previousSibling->nextSibling() : pa
rent->firstChild(); |
| 900 if (runEnd == node) | 902 if (runEnd == element) |
| 901 runEnd = nextSibling ? nextSibling->previousSibling() : parent->
lastChild(); | 903 runEnd = nextSibling ? nextSibling->previousSibling() : parent->
lastChild(); |
| 902 } | 904 } |
| 903 } | 905 } |
| 904 } | 906 } |
| 905 | 907 |
| 906 bool ApplyStyleCommand::removeInlineStyleFromElement(EditingStyle* style, PassRe
fPtrWillBeRawPtr<HTMLElement> element, InlineStyleRemovalMode mode, EditingStyle
* extractedStyle) | 908 bool ApplyStyleCommand::removeInlineStyleFromElement(EditingStyle* style, PassRe
fPtrWillBeRawPtr<HTMLElement> element, InlineStyleRemovalMode mode, EditingStyle
* extractedStyle) |
| 907 { | 909 { |
| 908 ASSERT(element); | 910 ASSERT(element); |
| 909 | 911 |
| 910 if (!element->parentNode() || !element->parentNode()->isContentEditable(Node
::UserSelectAllIsAlwaysNonEditable)) | 912 if (!element->parentNode() || !element->parentNode()->isContentEditable(Node
::UserSelectAllIsAlwaysNonEditable)) |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1132 | 1134 |
| 1133 RefPtrWillBeRawPtr<Node> node = start.deprecatedNode(); | 1135 RefPtrWillBeRawPtr<Node> node = start.deprecatedNode(); |
| 1134 while (node) { | 1136 while (node) { |
| 1135 RefPtrWillBeRawPtr<Node> next = nullptr; | 1137 RefPtrWillBeRawPtr<Node> next = nullptr; |
| 1136 if (editingIgnoresContent(node.get())) { | 1138 if (editingIgnoresContent(node.get())) { |
| 1137 ASSERT(node == end.deprecatedNode() || !node->contains(end.deprecate
dNode())); | 1139 ASSERT(node == end.deprecatedNode() || !node->contains(end.deprecate
dNode())); |
| 1138 next = NodeTraversal::nextSkippingChildren(*node); | 1140 next = NodeTraversal::nextSkippingChildren(*node); |
| 1139 } else { | 1141 } else { |
| 1140 next = NodeTraversal::next(*node); | 1142 next = NodeTraversal::next(*node); |
| 1141 } | 1143 } |
| 1142 if (node->isHTMLElement() && nodeFullySelected(node.get(), start, end))
{ | 1144 if (node->isHTMLElement() && elementFullySelected(toHTMLElement(*node),
start, end)) { |
| 1143 RefPtrWillBeRawPtr<HTMLElement> elem = toHTMLElement(node); | 1145 RefPtrWillBeRawPtr<HTMLElement> elem = toHTMLElement(node); |
| 1144 RefPtrWillBeRawPtr<Node> prev = NodeTraversal::previousPostOrder(*el
em); | 1146 RefPtrWillBeRawPtr<Node> prev = NodeTraversal::previousPostOrder(*el
em); |
| 1145 RefPtrWillBeRawPtr<Node> next = NodeTraversal::next(*elem); | 1147 RefPtrWillBeRawPtr<Node> next = NodeTraversal::next(*elem); |
| 1146 RefPtrWillBeRawPtr<EditingStyle> styleToPushDown = nullptr; | 1148 RefPtrWillBeRawPtr<EditingStyle> styleToPushDown = nullptr; |
| 1147 RefPtrWillBeRawPtr<Node> childNode = nullptr; | 1149 RefPtrWillBeRawPtr<Node> childNode = nullptr; |
| 1148 if (isStyledInlineElementToRemove(elem.get())) { | 1150 if (isStyledInlineElementToRemove(elem.get())) { |
| 1149 styleToPushDown = EditingStyle::create(); | 1151 styleToPushDown = EditingStyle::create(); |
| 1150 childNode = elem->firstChild(); | 1152 childNode = elem->firstChild(); |
| 1151 } | 1153 } |
| 1152 | 1154 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1173 } | 1175 } |
| 1174 } | 1176 } |
| 1175 if (node == end.deprecatedNode()) | 1177 if (node == end.deprecatedNode()) |
| 1176 break; | 1178 break; |
| 1177 node = next; | 1179 node = next; |
| 1178 } | 1180 } |
| 1179 | 1181 |
| 1180 updateStartEnd(s, e); | 1182 updateStartEnd(s, e); |
| 1181 } | 1183 } |
| 1182 | 1184 |
| 1183 bool ApplyStyleCommand::nodeFullySelected(Node *node, const Position &start, con
st Position &end) const | 1185 bool ApplyStyleCommand::elementFullySelected(HTMLElement& element, const Positio
n& start, const Position& end) const |
| 1184 { | 1186 { |
| 1185 ASSERT(node); | 1187 // The tree may have changed and Position::upstream() relies on an up-to-dat
e layout. |
| 1186 ASSERT(node->isElementNode()); | 1188 element.document().updateLayoutIgnorePendingStylesheets(); |
| 1187 | 1189 |
| 1188 // The tree may have changed and Position::upstream() relies on an up-to-dat
e layout. | 1190 return comparePositions(firstPositionInOrBeforeNode(&element), start) >= 0 |
| 1189 node->document().updateLayoutIgnorePendingStylesheets(); | 1191 && comparePositions(lastPositionInOrAfterNode(&element).upstream(), end)
<= 0; |
| 1190 | |
| 1191 return comparePositions(firstPositionInOrBeforeNode(node), start) >= 0 | |
| 1192 && comparePositions(lastPositionInOrAfterNode(node).upstream(), end) <=
0; | |
| 1193 } | 1192 } |
| 1194 | 1193 |
| 1195 void ApplyStyleCommand::splitTextAtStart(const Position& start, const Position&
end) | 1194 void ApplyStyleCommand::splitTextAtStart(const Position& start, const Position&
end) |
| 1196 { | 1195 { |
| 1197 ASSERT(start.containerNode()->isTextNode()); | 1196 ASSERT(start.containerNode()->isTextNode()); |
| 1198 | 1197 |
| 1199 Position newEnd; | 1198 Position newEnd; |
| 1200 if (end.anchorType() == Position::PositionIsOffsetInAnchor && start.containe
rNode() == end.containerNode()) | 1199 if (end.anchorType() == Position::PositionIsOffsetInAnchor && start.containe
rNode() == end.containerNode()) |
| 1201 newEnd = Position(end.containerText(), end.offsetInContainerNode() - sta
rt.offsetInContainerNode()); | 1200 newEnd = Position(end.containerText(), end.offsetInContainerNode() - sta
rt.offsetInContainerNode()); |
| 1202 else | 1201 else |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1402 } | 1401 } |
| 1403 setNodeAttribute(block, styleAttr, cssText.toAtomicString()); | 1402 setNodeAttribute(block, styleAttr, cssText.toAtomicString()); |
| 1404 } | 1403 } |
| 1405 | 1404 |
| 1406 void ApplyStyleCommand::addInlineStyleIfNeeded(EditingStyle* style, PassRefPtrWi
llBeRawPtr<Node> passedStart, PassRefPtrWillBeRawPtr<Node> passedEnd, EAddStyled
Element addStyledElement) | 1405 void ApplyStyleCommand::addInlineStyleIfNeeded(EditingStyle* style, PassRefPtrWi
llBeRawPtr<Node> passedStart, PassRefPtrWillBeRawPtr<Node> passedEnd, EAddStyled
Element addStyledElement) |
| 1407 { | 1406 { |
| 1408 if (!passedStart || !passedEnd || !passedStart->inDocument() || !passedEnd->
inDocument()) | 1407 if (!passedStart || !passedEnd || !passedStart->inDocument() || !passedEnd->
inDocument()) |
| 1409 return; | 1408 return; |
| 1410 | 1409 |
| 1411 RefPtrWillBeRawPtr<Node> start = passedStart; | 1410 RefPtrWillBeRawPtr<Node> start = passedStart; |
| 1412 RefPtrWillBeMember<Node> dummyElement = nullptr; | 1411 RefPtrWillBeMember<HTMLSpanElement> dummyElement = nullptr; |
| 1413 StyleChange styleChange(style, positionToComputeInlineStyleChange(start, dum
myElement)); | 1412 StyleChange styleChange(style, positionToComputeInlineStyleChange(start, dum
myElement)); |
| 1414 | 1413 |
| 1415 if (dummyElement) | 1414 if (dummyElement) |
| 1416 removeNode(dummyElement); | 1415 removeNode(dummyElement); |
| 1417 | 1416 |
| 1418 applyInlineStyleChange(start, passedEnd, styleChange, addStyledElement); | 1417 applyInlineStyleChange(start, passedEnd, styleChange, addStyledElement); |
| 1419 } | 1418 } |
| 1420 | 1419 |
| 1421 Position ApplyStyleCommand::positionToComputeInlineStyleChange(PassRefPtrWillBeR
awPtr<Node> startNode, RefPtrWillBeMember<Node>& dummyElement) | 1420 Position ApplyStyleCommand::positionToComputeInlineStyleChange(PassRefPtrWillBeR
awPtr<Node> startNode, RefPtrWillBeMember<HTMLSpanElement>& dummyElement) |
| 1422 { | 1421 { |
| 1423 // It's okay to obtain the style at the startNode because we've removed all
relevant styles from the current run. | 1422 // It's okay to obtain the style at the startNode because we've removed all
relevant styles from the current run. |
| 1424 if (!startNode->isElementNode()) { | 1423 if (!startNode->isElementNode()) { |
| 1425 dummyElement = createStyleSpanElement(document()); | 1424 dummyElement = createStyleSpanElement(document()); |
| 1426 insertNodeAt(dummyElement, positionBeforeNode(startNode.get())); | 1425 insertNodeAt(dummyElement, positionBeforeNode(startNode.get())); |
| 1427 return positionBeforeNode(dummyElement.get()); | 1426 return positionBeforeNode(dummyElement.get()); |
| 1428 } | 1427 } |
| 1429 | 1428 |
| 1430 return firstPositionInOrBeforeNode(startNode.get()); | 1429 return firstPositionInOrBeforeNode(startNode.get()); |
| 1431 } | 1430 } |
| 1432 | 1431 |
| 1433 void ApplyStyleCommand::applyInlineStyleChange(PassRefPtrWillBeRawPtr<Node> pass
edStart, PassRefPtrWillBeRawPtr<Node> passedEnd, StyleChange& styleChange, EAddS
tyledElement addStyledElement) | 1432 void ApplyStyleCommand::applyInlineStyleChange(PassRefPtrWillBeRawPtr<Node> pass
edStart, PassRefPtrWillBeRawPtr<Node> passedEnd, StyleChange& styleChange, EAddS
tyledElement addStyledElement) |
| 1434 { | 1433 { |
| 1435 RefPtrWillBeRawPtr<Node> startNode = passedStart; | 1434 RefPtrWillBeRawPtr<Node> startNode = passedStart; |
| 1436 RefPtrWillBeRawPtr<Node> endNode = passedEnd; | 1435 RefPtrWillBeRawPtr<Node> endNode = passedEnd; |
| 1437 ASSERT(startNode->inDocument()); | 1436 ASSERT(startNode->inDocument()); |
| 1438 ASSERT(endNode->inDocument()); | 1437 ASSERT(endNode->inDocument()); |
| 1439 | 1438 |
| 1440 // Find appropriate font and span elements top-down. | 1439 // Find appropriate font and span elements top-down. |
| 1441 HTMLElement* fontContainer = 0; | 1440 HTMLFontElement* fontContainer = 0; |
| 1442 HTMLElement* styleContainer = 0; | 1441 HTMLElement* styleContainer = 0; |
| 1443 for (Node* container = startNode.get(); container && startNode == endNode; c
ontainer = container->firstChild()) { | 1442 for (Node* container = startNode.get(); container && startNode == endNode; c
ontainer = container->firstChild()) { |
| 1444 if (isHTMLFontElement(*container)) | 1443 if (isHTMLFontElement(*container)) |
| 1445 fontContainer = toHTMLElement(container); | 1444 fontContainer = toHTMLFontElement(container); |
| 1446 bool styleContainerIsNotSpan = !isHTMLSpanElement(styleContainer); | 1445 bool styleContainerIsNotSpan = !isHTMLSpanElement(styleContainer); |
| 1447 if (container->isHTMLElement()) { | 1446 if (container->isHTMLElement()) { |
| 1448 HTMLElement* containerElement = toHTMLElement(container); | 1447 HTMLElement* containerElement = toHTMLElement(container); |
| 1449 if (isHTMLSpanElement(*containerElement) || (styleContainerIsNotSpan
&& containerElement->hasChildren())) | 1448 if (isHTMLSpanElement(*containerElement) || (styleContainerIsNotSpan
&& containerElement->hasChildren())) |
| 1450 styleContainer = toHTMLElement(container); | 1449 styleContainer = toHTMLElement(container); |
| 1451 } | 1450 } |
| 1452 if (!container->firstChild()) | 1451 if (!container->firstChild()) |
| 1453 break; | 1452 break; |
| 1454 startNode = container->firstChild(); | 1453 startNode = container->firstChild(); |
| 1455 endNode = container->lastChild(); | 1454 endNode = container->lastChild(); |
| 1456 } | 1455 } |
| 1457 | 1456 |
| 1458 // Font tags need to go outside of CSS so that CSS font sizes override leagc
y font sizes. | 1457 // Font tags need to go outside of CSS so that CSS font sizes override leagc
y font sizes. |
| 1459 if (styleChange.applyFontColor() || styleChange.applyFontFace() || styleChan
ge.applyFontSize()) { | 1458 if (styleChange.applyFontColor() || styleChange.applyFontFace() || styleChan
ge.applyFontSize()) { |
| 1460 if (fontContainer) { | 1459 if (fontContainer) { |
| 1461 if (styleChange.applyFontColor()) | 1460 if (styleChange.applyFontColor()) |
| 1462 setNodeAttribute(fontContainer, colorAttr, AtomicString(styleCha
nge.fontColor())); | 1461 setNodeAttribute(fontContainer, colorAttr, AtomicString(styleCha
nge.fontColor())); |
| 1463 if (styleChange.applyFontFace()) | 1462 if (styleChange.applyFontFace()) |
| 1464 setNodeAttribute(fontContainer, faceAttr, AtomicString(styleChan
ge.fontFace())); | 1463 setNodeAttribute(fontContainer, faceAttr, AtomicString(styleChan
ge.fontFace())); |
| 1465 if (styleChange.applyFontSize()) | 1464 if (styleChange.applyFontSize()) |
| 1466 setNodeAttribute(fontContainer, sizeAttr, AtomicString(styleChan
ge.fontSize())); | 1465 setNodeAttribute(fontContainer, sizeAttr, AtomicString(styleChan
ge.fontSize())); |
| 1467 } else { | 1466 } else { |
| 1468 RefPtrWillBeRawPtr<Element> fontElement = createFontElement(document
()); | 1467 RefPtrWillBeRawPtr<HTMLFontElement> fontElement = createFontElement(
document()); |
| 1469 if (styleChange.applyFontColor()) | 1468 if (styleChange.applyFontColor()) |
| 1470 fontElement->setAttribute(colorAttr, AtomicString(styleChange.fo
ntColor())); | 1469 fontElement->setAttribute(colorAttr, AtomicString(styleChange.fo
ntColor())); |
| 1471 if (styleChange.applyFontFace()) | 1470 if (styleChange.applyFontFace()) |
| 1472 fontElement->setAttribute(faceAttr, AtomicString(styleChange.fon
tFace())); | 1471 fontElement->setAttribute(faceAttr, AtomicString(styleChange.fon
tFace())); |
| 1473 if (styleChange.applyFontSize()) | 1472 if (styleChange.applyFontSize()) |
| 1474 fontElement->setAttribute(sizeAttr, AtomicString(styleChange.fon
tSize())); | 1473 fontElement->setAttribute(sizeAttr, AtomicString(styleChange.fon
tSize())); |
| 1475 surroundNodeRangeWithElement(startNode, endNode, fontElement.get()); | 1474 surroundNodeRangeWithElement(startNode, endNode, fontElement.get()); |
| 1476 } | 1475 } |
| 1477 } | 1476 } |
| 1478 | 1477 |
| 1479 if (styleChange.cssStyle().length()) { | 1478 if (styleChange.cssStyle().length()) { |
| 1480 if (styleContainer) { | 1479 if (styleContainer) { |
| 1481 if (const StylePropertySet* existingStyle = styleContainer->inlineSt
yle()) { | 1480 if (const StylePropertySet* existingStyle = styleContainer->inlineSt
yle()) { |
| 1482 String existingText = existingStyle->asText(); | 1481 String existingText = existingStyle->asText(); |
| 1483 StringBuilder cssText; | 1482 StringBuilder cssText; |
| 1484 cssText.append(existingText); | 1483 cssText.append(existingText); |
| 1485 if (!existingText.isEmpty()) | 1484 if (!existingText.isEmpty()) |
| 1486 cssText.append(' '); | 1485 cssText.append(' '); |
| 1487 cssText.append(styleChange.cssStyle()); | 1486 cssText.append(styleChange.cssStyle()); |
| 1488 setNodeAttribute(styleContainer, styleAttr, cssText.toAtomicStri
ng()); | 1487 setNodeAttribute(styleContainer, styleAttr, cssText.toAtomicStri
ng()); |
| 1489 } else { | 1488 } else { |
| 1490 setNodeAttribute(styleContainer, styleAttr, AtomicString(styleCh
ange.cssStyle())); | 1489 setNodeAttribute(styleContainer, styleAttr, AtomicString(styleCh
ange.cssStyle())); |
| 1491 } | 1490 } |
| 1492 } else { | 1491 } else { |
| 1493 RefPtrWillBeRawPtr<Element> styleElement = createStyleSpanElement(do
cument()); | 1492 RefPtrWillBeRawPtr<HTMLSpanElement> styleElement = createStyleSpanEl
ement(document()); |
| 1494 styleElement->setAttribute(styleAttr, AtomicString(styleChange.cssSt
yle())); | 1493 styleElement->setAttribute(styleAttr, AtomicString(styleChange.cssSt
yle())); |
| 1495 surroundNodeRangeWithElement(startNode, endNode, styleElement.releas
e()); | 1494 surroundNodeRangeWithElement(startNode, endNode, styleElement.releas
e()); |
| 1496 } | 1495 } |
| 1497 } | 1496 } |
| 1498 | 1497 |
| 1499 if (styleChange.applyBold()) | 1498 if (styleChange.applyBold()) |
| 1500 surroundNodeRangeWithElement(startNode, endNode, createHTMLElement(docum
ent(), bTag)); | 1499 surroundNodeRangeWithElement(startNode, endNode, createHTMLElement(docum
ent(), bTag)); |
| 1501 | 1500 |
| 1502 if (styleChange.applyItalic()) | 1501 if (styleChange.applyItalic()) |
| 1503 surroundNodeRangeWithElement(startNode, endNode, createHTMLElement(docum
ent(), iTag)); | 1502 surroundNodeRangeWithElement(startNode, endNode, createHTMLElement(docum
ent(), iTag)); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1572 void ApplyStyleCommand::trace(Visitor* visitor) | 1571 void ApplyStyleCommand::trace(Visitor* visitor) |
| 1573 { | 1572 { |
| 1574 visitor->trace(m_style); | 1573 visitor->trace(m_style); |
| 1575 visitor->trace(m_start); | 1574 visitor->trace(m_start); |
| 1576 visitor->trace(m_end); | 1575 visitor->trace(m_end); |
| 1577 visitor->trace(m_styledInlineElement); | 1576 visitor->trace(m_styledInlineElement); |
| 1578 CompositeEditCommand::trace(visitor); | 1577 CompositeEditCommand::trace(visitor); |
| 1579 } | 1578 } |
| 1580 | 1579 |
| 1581 } | 1580 } |
| OLD | NEW |