| 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 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 54 namespace WebCore { | 54 namespace WebCore { |
| 55 | 55 |
| 56 using namespace HTMLNames; | 56 using namespace HTMLNames; |
| 57 | 57 |
| 58 static String& styleSpanClassString() | 58 static String& styleSpanClassString() |
| 59 { | 59 { |
| 60 DEFINE_STATIC_LOCAL(String, styleSpanClassString, ((AppleStyleSpanClass))); | 60 DEFINE_STATIC_LOCAL(String, styleSpanClassString, ((AppleStyleSpanClass))); |
| 61 return styleSpanClassString; | 61 return styleSpanClassString; |
| 62 } | 62 } |
| 63 | 63 |
| 64 bool isLegacyAppleStyleSpan(const Node *node) | 64 bool isStyleSpan(const Node *node) |
| 65 { | 65 { |
| 66 if (!node || !node->isHTMLElement()) | 66 if (!node || !node->isHTMLElement()) |
| 67 return false; | 67 return false; |
| 68 | 68 |
| 69 const HTMLElement* elem = static_cast<const HTMLElement*>(node); | 69 const HTMLElement* elem = static_cast<const HTMLElement*>(node); |
| 70 return elem->hasLocalName(spanAttr) && elem->getAttribute(classAttr) == styl
eSpanClassString(); | 70 return elem->hasLocalName(spanAttr) && elem->getAttribute(classAttr) == styl
eSpanClassString(); |
| 71 } | 71 } |
| 72 | 72 |
| 73 enum ShouldStyleAttributeBeEmpty { AllowNonEmptyStyleAttribute, StyleAttributeSh
ouldBeEmpty }; | 73 enum ShouldStyleAttributeBeEmpty { AllowNonEmptyStyleAttribute, StyleAttributeSh
ouldBeEmpty }; |
| 74 static bool hasNoAttributeOrOnlyStyleAttribute(const StyledElement* element, Sho
uldStyleAttributeBeEmpty shouldStyleAttributeBeEmpty) | 74 static bool hasNoAttributeOrOnlyStyleAttribute(const StyledElement* element, Sho
uldStyleAttributeBeEmpty shouldStyleAttributeBeEmpty) |
| (...skipping 14 matching lines...) Expand all Loading... |
| 89 return matchedAttributes == map->length(); | 89 return matchedAttributes == map->length(); |
| 90 } | 90 } |
| 91 | 91 |
| 92 bool isStyleSpanOrSpanWithOnlyStyleAttribute(const Element* element) | 92 bool isStyleSpanOrSpanWithOnlyStyleAttribute(const Element* element) |
| 93 { | 93 { |
| 94 if (!element || !element->hasTagName(spanTag)) | 94 if (!element || !element->hasTagName(spanTag)) |
| 95 return false; | 95 return false; |
| 96 return hasNoAttributeOrOnlyStyleAttribute(toHTMLElement(element), AllowNonEm
ptyStyleAttribute); | 96 return hasNoAttributeOrOnlyStyleAttribute(toHTMLElement(element), AllowNonEm
ptyStyleAttribute); |
| 97 } | 97 } |
| 98 | 98 |
| 99 static inline bool isSpanWithoutAttributesOrUnstyledStyleSpan(const Node* node) | 99 static inline bool isUnstyledStyleSpan(const Node* node) |
| 100 { |
| 101 return isStyleSpan(node) && hasNoAttributeOrOnlyStyleAttribute(toHTMLElement
(node), StyleAttributeShouldBeEmpty); |
| 102 } |
| 103 |
| 104 static inline bool isSpanWithoutAttributesOrUnstyleStyleSpan(const Node* node) |
| 100 { | 105 { |
| 101 if (!node || !node->isHTMLElement() || !node->hasTagName(spanTag)) | 106 if (!node || !node->isHTMLElement() || !node->hasTagName(spanTag)) |
| 102 return false; | 107 return false; |
| 103 return hasNoAttributeOrOnlyStyleAttribute(toHTMLElement(node), StyleAttribut
eShouldBeEmpty); | 108 return hasNoAttributeOrOnlyStyleAttribute(toHTMLElement(node), StyleAttribut
eShouldBeEmpty); |
| 104 } | 109 } |
| 105 | 110 |
| 106 static bool isEmptyFontTag(const Node *node) | 111 static bool isEmptyFontTag(const Node *node) |
| 107 { | 112 { |
| 108 if (!node || !node->hasTagName(fontTag)) | 113 if (!node || !node->hasTagName(fontTag)) |
| 109 return false; | 114 return false; |
| 110 | 115 |
| 111 const Element *elem = static_cast<const Element *>(node); | 116 const Element *elem = static_cast<const Element *>(node); |
| 112 NamedNodeMap *map = elem->attributes(true); // true for read-only | 117 NamedNodeMap *map = elem->attributes(true); // true for read-only |
| 113 if (!map) | 118 if (!map) |
| 114 return true; | 119 return true; |
| 115 return map->isEmpty() || (map->length() == 1 && elem->getAttribute(classAttr
) == styleSpanClassString()); | 120 return map->isEmpty() || (map->length() == 1 && elem->getAttribute(classAttr
) == styleSpanClassString()); |
| 116 } | 121 } |
| 117 | 122 |
| 118 static PassRefPtr<Element> createFontElement(Document* document) | 123 static PassRefPtr<Element> createFontElement(Document* document) |
| 119 { | 124 { |
| 120 RefPtr<Element> fontNode = createHTMLElement(document, fontTag); | 125 RefPtr<Element> fontNode = createHTMLElement(document, fontTag); |
| 126 fontNode->setAttribute(classAttr, styleSpanClassString()); |
| 121 return fontNode.release(); | 127 return fontNode.release(); |
| 122 } | 128 } |
| 123 | 129 |
| 124 PassRefPtr<HTMLElement> createStyleSpanElement(Document* document) | 130 PassRefPtr<HTMLElement> createStyleSpanElement(Document* document) |
| 125 { | 131 { |
| 126 RefPtr<HTMLElement> styleElement = createHTMLElement(document, spanTag); | 132 RefPtr<HTMLElement> styleElement = createHTMLElement(document, spanTag); |
| 133 styleElement->setAttribute(classAttr, styleSpanClassString()); |
| 127 return styleElement.release(); | 134 return styleElement.release(); |
| 128 } | 135 } |
| 129 | 136 |
| 130 ApplyStyleCommand::ApplyStyleCommand(Document* document, const EditingStyle* sty
le, EditAction editingAction, EPropertyLevel propertyLevel) | 137 ApplyStyleCommand::ApplyStyleCommand(Document* document, const EditingStyle* sty
le, EditAction editingAction, EPropertyLevel propertyLevel) |
| 131 : CompositeEditCommand(document) | 138 : CompositeEditCommand(document) |
| 132 , m_style(style->copy()) | 139 , m_style(style->copy()) |
| 133 , m_editingAction(editingAction) | 140 , m_editingAction(editingAction) |
| 134 , m_propertyLevel(propertyLevel) | 141 , m_propertyLevel(propertyLevel) |
| 135 , m_start(endingSelection().start().downstream()) | 142 , m_start(endingSelection().start().downstream()) |
| 136 , m_end(endingSelection().end().upstream()) | 143 , m_end(endingSelection().end().upstream()) |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 if (value) { | 399 if (value) { |
| 393 inlineStyleDecl->removeProperty(CSSPropertyFontSize, true); | 400 inlineStyleDecl->removeProperty(CSSPropertyFontSize, true); |
| 394 currentFontSize = computedFontSize(node); | 401 currentFontSize = computedFontSize(node); |
| 395 } | 402 } |
| 396 if (currentFontSize != desiredFontSize) { | 403 if (currentFontSize != desiredFontSize) { |
| 397 inlineStyleDecl->setProperty(CSSPropertyFontSize, String::number(des
iredFontSize) + "px", false, false); | 404 inlineStyleDecl->setProperty(CSSPropertyFontSize, String::number(des
iredFontSize) + "px", false, false); |
| 398 setNodeAttribute(element.get(), styleAttr, inlineStyleDecl->cssText(
)); | 405 setNodeAttribute(element.get(), styleAttr, inlineStyleDecl->cssText(
)); |
| 399 } | 406 } |
| 400 if (inlineStyleDecl->isEmpty()) { | 407 if (inlineStyleDecl->isEmpty()) { |
| 401 removeNodeAttribute(element.get(), styleAttr); | 408 removeNodeAttribute(element.get(), styleAttr); |
| 402 if (isSpanWithoutAttributesOrUnstyledStyleSpan(element.get())) | 409 // FIXME: should this be isSpanWithoutAttributesOrUnstyleStyleSpan?
Need a test. |
| 410 if (isUnstyledStyleSpan(element.get())) |
| 403 unstyledSpans.append(element.release()); | 411 unstyledSpans.append(element.release()); |
| 404 } | 412 } |
| 405 } | 413 } |
| 406 | 414 |
| 407 size_t size = unstyledSpans.size(); | 415 size_t size = unstyledSpans.size(); |
| 408 for (size_t i = 0; i < size; ++i) | 416 for (size_t i = 0; i < size; ++i) |
| 409 removeNodePreservingChildren(unstyledSpans[i].get()); | 417 removeNodePreservingChildren(unstyledSpans[i].get()); |
| 410 } | 418 } |
| 411 | 419 |
| 412 static Node* dummySpanAncestorForNode(const Node* node) | 420 static Node* dummySpanAncestorForNode(const Node* node) |
| 413 { | 421 { |
| 414 while (node && (!node->isElementNode() || !isStyleSpanOrSpanWithOnlyStyleAtt
ribute(toElement(node)))) | 422 while (node && !isStyleSpan(node)) |
| 415 node = node->parentNode(); | 423 node = node->parentNode(); |
| 416 | 424 |
| 417 return node ? node->parentNode() : 0; | 425 return node ? node->parentNode() : 0; |
| 418 } | 426 } |
| 419 | 427 |
| 420 void ApplyStyleCommand::cleanupUnstyledAppleStyleSpans(Node* dummySpanAncestor) | 428 void ApplyStyleCommand::cleanupUnstyledAppleStyleSpans(Node* dummySpanAncestor) |
| 421 { | 429 { |
| 422 if (!dummySpanAncestor) | 430 if (!dummySpanAncestor) |
| 423 return; | 431 return; |
| 424 | 432 |
| 425 // Dummy spans are created when text node is split, so that style informatio
n | 433 // Dummy spans are created when text node is split, so that style informatio
n |
| 426 // can be propagated, which can result in more splitting. If a dummy span ge
ts | 434 // can be propagated, which can result in more splitting. If a dummy span ge
ts |
| 427 // cloned/split, the new node is always a sibling of it. Therefore, we scan | 435 // cloned/split, the new node is always a sibling of it. Therefore, we scan |
| 428 // all the children of the dummy's parent | 436 // all the children of the dummy's parent |
| 429 Node* next; | 437 Node* next; |
| 430 for (Node* node = dummySpanAncestor->firstChild(); node; node = next) { | 438 for (Node* node = dummySpanAncestor->firstChild(); node; node = next) { |
| 431 next = node->nextSibling(); | 439 next = node->nextSibling(); |
| 432 if (isSpanWithoutAttributesOrUnstyledStyleSpan(node)) | 440 if (isUnstyledStyleSpan(node)) |
| 433 removeNodePreservingChildren(node); | 441 removeNodePreservingChildren(node); |
| 434 node = next; | 442 node = next; |
| 435 } | 443 } |
| 436 } | 444 } |
| 437 | 445 |
| 438 HTMLElement* ApplyStyleCommand::splitAncestorsWithUnicodeBidi(Node* node, bool b
efore, WritingDirection allowedDirection) | 446 HTMLElement* ApplyStyleCommand::splitAncestorsWithUnicodeBidi(Node* node, bool b
efore, WritingDirection allowedDirection) |
| 439 { | 447 { |
| 440 // We are allowed to leave the highest ancestor with unicode-bidi unsplit if
it is unicode-bidi: embed and direction: allowedDirection. | 448 // We are allowed to leave the highest ancestor with unicode-bidi unsplit if
it is unicode-bidi: embed and direction: allowedDirection. |
| 441 // In that case, we return the unsplit ancestor. Otherwise, we return 0. | 449 // In that case, we return the unsplit ancestor. Otherwise, we return 0. |
| 442 Node* block = enclosingBlock(node); | 450 Node* block = enclosingBlock(node); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 509 // otherwise it sets the property in the inline style declaration. | 517 // otherwise it sets the property in the inline style declaration. |
| 510 if (element->hasAttribute(dirAttr)) { | 518 if (element->hasAttribute(dirAttr)) { |
| 511 // FIXME: If this is a BDO element, we should probably just remove i
t if it has no | 519 // FIXME: If this is a BDO element, we should probably just remove i
t if it has no |
| 512 // other attributes, like we (should) do with B and I elements. | 520 // other attributes, like we (should) do with B and I elements. |
| 513 removeNodeAttribute(element, dirAttr); | 521 removeNodeAttribute(element, dirAttr); |
| 514 } else { | 522 } else { |
| 515 RefPtr<CSSMutableStyleDeclaration> inlineStyle = element->getInlineS
tyleDecl()->copy(); | 523 RefPtr<CSSMutableStyleDeclaration> inlineStyle = element->getInlineS
tyleDecl()->copy(); |
| 516 inlineStyle->setProperty(CSSPropertyUnicodeBidi, CSSValueNormal); | 524 inlineStyle->setProperty(CSSPropertyUnicodeBidi, CSSValueNormal); |
| 517 inlineStyle->removeProperty(CSSPropertyDirection); | 525 inlineStyle->removeProperty(CSSPropertyDirection); |
| 518 setNodeAttribute(element, styleAttr, inlineStyle->cssText()); | 526 setNodeAttribute(element, styleAttr, inlineStyle->cssText()); |
| 519 if (isSpanWithoutAttributesOrUnstyledStyleSpan(element)) | 527 // FIXME: should this be isSpanWithoutAttributesOrUnstyleStyleSpan?
Need a test. |
| 528 if (isUnstyledStyleSpan(element)) |
| 520 removeNodePreservingChildren(element); | 529 removeNodePreservingChildren(element); |
| 521 } | 530 } |
| 522 } | 531 } |
| 523 } | 532 } |
| 524 | 533 |
| 525 static Node* highestEmbeddingAncestor(Node* startNode, Node* enclosingNode) | 534 static Node* highestEmbeddingAncestor(Node* startNode, Node* enclosingNode) |
| 526 { | 535 { |
| 527 for (Node* n = startNode; n && n != enclosingNode; n = n->parentNode()) { | 536 for (Node* n = startNode; n && n != enclosingNode; n = n->parentNode()) { |
| 528 if (n->isHTMLElement() && getIdentifierValue(computedStyle(n).get(), CSS
PropertyUnicodeBidi) == CSSValueEmbed) | 537 if (n->isHTMLElement() && getIdentifierValue(computedStyle(n).get(), CSS
PropertyUnicodeBidi) == CSSValueEmbed) |
| 529 return n; | 538 return n; |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 866 | 875 |
| 867 // unicode-bidi and direction are pushed down separately so don't push down
with other styles | 876 // unicode-bidi and direction are pushed down separately so don't push down
with other styles |
| 868 Vector<QualifiedName> attributes; | 877 Vector<QualifiedName> attributes; |
| 869 if (!style->extractConflictingImplicitStyleOfAttributes(element, extractedSt
yle ? EditingStyle::PreserveWritingDirection : EditingStyle::DoNotPreserveWritin
gDirection, | 878 if (!style->extractConflictingImplicitStyleOfAttributes(element, extractedSt
yle ? EditingStyle::PreserveWritingDirection : EditingStyle::DoNotPreserveWritin
gDirection, |
| 870 extractedStyle, attributes, mode == RemoveAlways ? EditingStyle::Extract
MatchingStyle : EditingStyle::DoNotExtractMatchingStyle)) | 879 extractedStyle, attributes, mode == RemoveAlways ? EditingStyle::Extract
MatchingStyle : EditingStyle::DoNotExtractMatchingStyle)) |
| 871 return false; | 880 return false; |
| 872 | 881 |
| 873 for (size_t i = 0; i < attributes.size(); i++) | 882 for (size_t i = 0; i < attributes.size(); i++) |
| 874 removeNodeAttribute(element, attributes[i]); | 883 removeNodeAttribute(element, attributes[i]); |
| 875 | 884 |
| 876 if (isEmptyFontTag(element) || isSpanWithoutAttributesOrUnstyledStyleSpan(el
ement)) | 885 if (isEmptyFontTag(element) || isSpanWithoutAttributesOrUnstyleStyleSpan(ele
ment)) |
| 877 removeNodePreservingChildren(element); | 886 removeNodePreservingChildren(element); |
| 878 | 887 |
| 879 return true; | 888 return true; |
| 880 } | 889 } |
| 881 | 890 |
| 882 bool ApplyStyleCommand::removeCSSStyle(EditingStyle* style, HTMLElement* element
, InlineStyleRemovalMode mode, EditingStyle* extractedStyle) | 891 bool ApplyStyleCommand::removeCSSStyle(EditingStyle* style, HTMLElement* element
, InlineStyleRemovalMode mode, EditingStyle* extractedStyle) |
| 883 { | 892 { |
| 884 ASSERT(style); | 893 ASSERT(style); |
| 885 ASSERT(element); | 894 ASSERT(element); |
| 886 | 895 |
| 887 if (mode == RemoveNone) | 896 if (mode == RemoveNone) |
| 888 return style->conflictsWithInlineStyleOfElement(element); | 897 return style->conflictsWithInlineStyleOfElement(element); |
| 889 | 898 |
| 890 Vector<CSSPropertyID> properties; | 899 Vector<CSSPropertyID> properties; |
| 891 if (!style->conflictsWithInlineStyleOfElement(element, extractedStyle, prope
rties)) | 900 if (!style->conflictsWithInlineStyleOfElement(element, extractedStyle, prope
rties)) |
| 892 return false; | 901 return false; |
| 893 | 902 |
| 894 CSSMutableStyleDeclaration* inlineStyle = element->inlineStyleDecl(); | 903 CSSMutableStyleDeclaration* inlineStyle = element->inlineStyleDecl(); |
| 895 ASSERT(inlineStyle); | 904 ASSERT(inlineStyle); |
| 896 // FIXME: We should use a mass-removal function here but we don't have an un
doable one yet. | 905 // FIXME: We should use a mass-removal function here but we don't have an un
doable one yet. |
| 897 for (size_t i = 0; i < properties.size(); i++) | 906 for (size_t i = 0; i < properties.size(); i++) |
| 898 removeCSSProperty(element, properties[i]); | 907 removeCSSProperty(element, properties[i]); |
| 899 | 908 |
| 900 // No need to serialize <foo style=""> if we just removed the last css prope
rty | 909 // No need to serialize <foo style=""> if we just removed the last css prope
rty |
| 901 if (inlineStyle->isEmpty()) | 910 if (inlineStyle->isEmpty()) |
| 902 removeNodeAttribute(element, styleAttr); | 911 removeNodeAttribute(element, styleAttr); |
| 903 | 912 |
| 904 if (isSpanWithoutAttributesOrUnstyledStyleSpan(element)) | 913 if (isSpanWithoutAttributesOrUnstyleStyleSpan(element)) |
| 905 removeNodePreservingChildren(element); | 914 removeNodePreservingChildren(element); |
| 906 | 915 |
| 907 return true; | 916 return true; |
| 908 } | 917 } |
| 909 | 918 |
| 910 HTMLElement* ApplyStyleCommand::highestAncestorWithConflictingInlineStyle(Editin
gStyle* style, Node* node) | 919 HTMLElement* ApplyStyleCommand::highestAncestorWithConflictingInlineStyle(Editin
gStyle* style, Node* node) |
| 911 { | 920 { |
| 912 if (!node) | 921 if (!node) |
| 913 return 0; | 922 return 0; |
| 914 | 923 |
| (...skipping 573 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1488 } | 1497 } |
| 1489 else { | 1498 else { |
| 1490 child = child->nextSibling(); | 1499 child = child->nextSibling(); |
| 1491 } | 1500 } |
| 1492 } | 1501 } |
| 1493 | 1502 |
| 1494 updateStartEnd(newStart, newEnd); | 1503 updateStartEnd(newStart, newEnd); |
| 1495 } | 1504 } |
| 1496 | 1505 |
| 1497 } | 1506 } |
| OLD | NEW |