OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2007, 2008, 2009 Apple Computer, Inc. | 2 * Copyright (C) 2007, 2008, 2009 Apple Computer, Inc. |
3 * Copyright (C) 2010, 2011 Google Inc. All rights reserved. | 3 * Copyright (C) 2010, 2011 Google Inc. All rights reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
7 * are met: | 7 * are met: |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 12 matching lines...) Expand all Loading... |
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 */ | 25 */ |
26 | 26 |
27 #include "core/editing/EditingStyle.h" | 27 #include "core/editing/EditingStyle.h" |
28 | 28 |
29 #include "bindings/core/v8/ExceptionStatePlaceholder.h" | 29 #include "bindings/core/v8/ExceptionStatePlaceholder.h" |
30 #include "core/HTMLNames.h" | 30 #include "core/HTMLNames.h" |
31 #include "core/css/CSSColorValue.h" | 31 #include "core/css/CSSColorValue.h" |
32 #include "core/css/CSSComputedStyleDeclaration.h" | 32 #include "core/css/CSSComputedStyleDeclaration.h" |
| 33 #include "core/css/CSSPrimitiveValueMappings.h" |
33 #include "core/css/CSSPropertyMetadata.h" | 34 #include "core/css/CSSPropertyMetadata.h" |
34 #include "core/css/CSSRuleList.h" | 35 #include "core/css/CSSRuleList.h" |
35 #include "core/css/CSSStyleRule.h" | 36 #include "core/css/CSSStyleRule.h" |
36 #include "core/css/CSSValueList.h" | 37 #include "core/css/CSSValueList.h" |
37 #include "core/css/CSSValuePool.h" | 38 #include "core/css/CSSValuePool.h" |
38 #include "core/css/FontSize.h" | 39 #include "core/css/FontSize.h" |
39 #include "core/css/StylePropertySet.h" | 40 #include "core/css/StylePropertySet.h" |
40 #include "core/css/StyleRule.h" | 41 #include "core/css/StyleRule.h" |
41 #include "core/css/parser/CSSParser.h" | 42 #include "core/css/parser/CSSParser.h" |
42 #include "core/css/resolver/StyleResolver.h" | 43 #include "core/css/resolver/StyleResolver.h" |
43 #include "core/dom/Document.h" | 44 #include "core/dom/Document.h" |
44 #include "core/dom/Element.h" | 45 #include "core/dom/Element.h" |
45 #include "core/dom/Node.h" | 46 #include "core/dom/Node.h" |
| 47 #include "core/dom/NodeComputedStyle.h" |
46 #include "core/dom/NodeTraversal.h" | 48 #include "core/dom/NodeTraversal.h" |
47 #include "core/dom/QualifiedName.h" | 49 #include "core/dom/QualifiedName.h" |
48 #include "core/editing/EditingUtilities.h" | 50 #include "core/editing/EditingUtilities.h" |
49 #include "core/editing/Editor.h" | 51 #include "core/editing/Editor.h" |
50 #include "core/editing/FrameSelection.h" | 52 #include "core/editing/FrameSelection.h" |
51 #include "core/editing/Position.h" | 53 #include "core/editing/Position.h" |
52 #include "core/editing/commands/ApplyStyleCommand.h" | 54 #include "core/editing/commands/ApplyStyleCommand.h" |
53 #include "core/editing/serializers/HTMLInterchange.h" | 55 #include "core/editing/serializers/HTMLInterchange.h" |
54 #include "core/frame/LocalFrame.h" | 56 #include "core/frame/LocalFrame.h" |
55 #include "core/html/HTMLFontElement.h" | 57 #include "core/html/HTMLFontElement.h" |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 return CSSComputedStyleDeclaration::create(elem); | 158 return CSSComputedStyleDeclaration::create(elem); |
157 } | 159 } |
158 | 160 |
159 static MutableStylePropertySet* getPropertiesNotIn(StylePropertySet* styleWithRe
dundantProperties, CSSStyleDeclaration* baseStyle); | 161 static MutableStylePropertySet* getPropertiesNotIn(StylePropertySet* styleWithRe
dundantProperties, CSSStyleDeclaration* baseStyle); |
160 enum LegacyFontSizeMode { AlwaysUseLegacyFontSize, UseLegacyFontSizeOnlyIfPixelV
aluesMatch }; | 162 enum LegacyFontSizeMode { AlwaysUseLegacyFontSize, UseLegacyFontSizeOnlyIfPixelV
aluesMatch }; |
161 static int legacyFontSizeFromCSSValue(Document*, CSSPrimitiveValue*, bool, Legac
yFontSizeMode); | 163 static int legacyFontSizeFromCSSValue(Document*, CSSPrimitiveValue*, bool, Legac
yFontSizeMode); |
162 static bool isTransparentColorValue(CSSValue*); | 164 static bool isTransparentColorValue(CSSValue*); |
163 static bool hasTransparentBackgroundColor(CSSStyleDeclaration*); | 165 static bool hasTransparentBackgroundColor(CSSStyleDeclaration*); |
164 static bool hasTransparentBackgroundColor(StylePropertySet*); | 166 static bool hasTransparentBackgroundColor(StylePropertySet*); |
165 static CSSValue* backgroundColorValueInEffect(Node*); | 167 static CSSValue* backgroundColorValueInEffect(Node*); |
| 168 static bool hasAncestorVerticalAlignStyle(Node&, CSSValueID); |
166 | 169 |
167 class HTMLElementEquivalent : public GarbageCollected<HTMLElementEquivalent> { | 170 class HTMLElementEquivalent : public GarbageCollected<HTMLElementEquivalent> { |
168 public: | 171 public: |
169 static HTMLElementEquivalent* create(CSSPropertyID propertyID, CSSValueID pr
imitiveValue, const HTMLQualifiedName& tagName) | 172 static HTMLElementEquivalent* create(CSSPropertyID propertyID, CSSValueID pr
imitiveValue, const HTMLQualifiedName& tagName) |
170 { | 173 { |
171 return new HTMLElementEquivalent(propertyID, primitiveValue, tagName); | 174 return new HTMLElementEquivalent(propertyID, primitiveValue, tagName); |
172 } | 175 } |
173 | 176 |
174 virtual bool matches(const Element* element) const { return !m_tagName || el
ement->hasTagName(*m_tagName); } | 177 virtual bool matches(const Element* element) const { return !m_tagName || el
ement->hasTagName(*m_tagName); } |
175 virtual bool hasAttribute() const { return false; } | 178 virtual bool hasAttribute() const { return false; } |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
379 { | 382 { |
380 extractFontSizeDelta(); | 383 extractFontSizeDelta(); |
381 } | 384 } |
382 | 385 |
383 EditingStyle::EditingStyle(CSSPropertyID propertyID, const String& value) | 386 EditingStyle::EditingStyle(CSSPropertyID propertyID, const String& value) |
384 : m_mutableStyle(nullptr) | 387 : m_mutableStyle(nullptr) |
385 , m_isMonospaceFont(false) | 388 , m_isMonospaceFont(false) |
386 , m_fontSizeDelta(NoFontDelta) | 389 , m_fontSizeDelta(NoFontDelta) |
387 { | 390 { |
388 setProperty(propertyID, value); | 391 setProperty(propertyID, value); |
| 392 m_isVerticalAlign = propertyID == CSSPropertyVerticalAlign && (value == "sub
" || value == "super"); |
389 } | 393 } |
390 | 394 |
391 static Color cssValueToColor(CSSValue* colorValue) | 395 static Color cssValueToColor(CSSValue* colorValue) |
392 { | 396 { |
393 if (!colorValue || (!colorValue->isColorValue() && !colorValue->isPrimitiveV
alue())) | 397 if (!colorValue || (!colorValue->isColorValue() && !colorValue->isPrimitiveV
alue())) |
394 return Color::transparent; | 398 return Color::transparent; |
395 | 399 |
396 if (colorValue->isColorValue()) | 400 if (colorValue->isColorValue()) |
397 return toCSSColorValue(colorValue)->value(); | 401 return toCSSColorValue(colorValue)->value(); |
398 | 402 |
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
730 difference->removePropertiesInSet(textOnlyProperties, WTF_ARRAY_LENGTH(t
extOnlyProperties)); | 734 difference->removePropertiesInSet(textOnlyProperties, WTF_ARRAY_LENGTH(t
extOnlyProperties)); |
731 | 735 |
732 if (difference->isEmpty()) | 736 if (difference->isEmpty()) |
733 return TrueTriState; | 737 return TrueTriState; |
734 if (difference->propertyCount() == m_mutableStyle->propertyCount()) | 738 if (difference->propertyCount() == m_mutableStyle->propertyCount()) |
735 return FalseTriState; | 739 return FalseTriState; |
736 | 740 |
737 return MixedTriState; | 741 return MixedTriState; |
738 } | 742 } |
739 | 743 |
| 744 static bool hasAncestorVerticalAlignStyle(Node& node, CSSValueID value) |
| 745 { |
| 746 for (Node& runner : NodeTraversal::inclusiveAncestorsOf(node)) { |
| 747 CSSComputedStyleDeclaration* ancestorStyle = CSSComputedStyleDeclaration
::create(&runner); |
| 748 if (getIdentifierValue(ancestorStyle, CSSPropertyVerticalAlign) == value
) |
| 749 return true; |
| 750 } |
| 751 return false; |
| 752 } |
| 753 |
740 TriState EditingStyle::triStateOfStyle(const VisibleSelection& selection) const | 754 TriState EditingStyle::triStateOfStyle(const VisibleSelection& selection) const |
741 { | 755 { |
742 if (selection.isNone()) | 756 if (selection.isNone()) |
743 return FalseTriState; | 757 return FalseTriState; |
744 | 758 |
745 if (selection.isCaret()) | 759 if (selection.isCaret()) |
746 return triStateOfStyle(EditingStyle::styleAtSelectionStart(selection)); | 760 return triStateOfStyle(EditingStyle::styleAtSelectionStart(selection)); |
747 | 761 |
748 TriState state = FalseTriState; | 762 TriState state = FalseTriState; |
749 bool nodeIsStart = true; | 763 bool nodeIsStart = true; |
750 for (Node& node : NodeTraversal::startsAt(*selection.start().anchorNode()))
{ | 764 for (Node& node : NodeTraversal::startsAt(*selection.start().anchorNode()))
{ |
751 if (node.layoutObject() && node.hasEditableStyle()) { | 765 if (node.layoutObject() && node.hasEditableStyle()) { |
752 CSSComputedStyleDeclaration* nodeStyle = CSSComputedStyleDeclaration
::create(&node); | 766 CSSComputedStyleDeclaration* nodeStyle = CSSComputedStyleDeclaration
::create(&node); |
753 if (nodeStyle) { | 767 if (nodeStyle) { |
| 768 // If the selected element has <sub> or <sup> ancestor element,
apply the corresponding |
| 769 // style(vertical-align) to it so that document.queryCommandStat
e() works with the style. |
| 770 // See bug http://crbug.com/582225. |
| 771 if (m_isVerticalAlign && getIdentifierValue(nodeStyle, CSSProper
tyVerticalAlign) == CSSValueBaseline) { |
| 772 CSSPrimitiveValue* verticalAlign = toCSSPrimitiveValue(m_mut
ableStyle->getPropertyCSSValue(CSSPropertyVerticalAlign)); |
| 773 if (hasAncestorVerticalAlignStyle(node, verticalAlign->getVa
lueID())) |
| 774 node.mutableComputedStyle()->setVerticalAlign(verticalAl
ign->convertTo<EVerticalAlign>()); |
| 775 } |
| 776 |
754 // Pass EditingStyle::DoNotIgnoreTextOnlyProperties without chec
king if node.isTextNode() | 777 // Pass EditingStyle::DoNotIgnoreTextOnlyProperties without chec
king if node.isTextNode() |
755 // because the node can be an element node. See bug http://crbug
.com/584939. | 778 // because the node can be an element node. See bug http://crbug
.com/584939. |
756 TriState nodeState = triStateOfStyle(nodeStyle, EditingStyle::Do
NotIgnoreTextOnlyProperties); | 779 TriState nodeState = triStateOfStyle(nodeStyle, EditingStyle::Do
NotIgnoreTextOnlyProperties); |
757 if (nodeIsStart) { | 780 if (nodeIsStart) { |
758 state = nodeState; | 781 state = nodeState; |
759 nodeIsStart = false; | 782 nodeIsStart = false; |
760 } else if (state != nodeState && node.isTextNode()) { | 783 } else if (state != nodeState && node.isTextNode()) { |
761 state = MixedTriState; | 784 state = MixedTriState; |
762 break; | 785 break; |
763 } | 786 } |
(...skipping 543 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1307 | 1330 |
1308 int EditingStyle::legacyFontSize(Document* document) const | 1331 int EditingStyle::legacyFontSize(Document* document) const |
1309 { | 1332 { |
1310 CSSValue* cssValue = m_mutableStyle->getPropertyCSSValue(CSSPropertyFontSize
); | 1333 CSSValue* cssValue = m_mutableStyle->getPropertyCSSValue(CSSPropertyFontSize
); |
1311 if (!cssValue || !cssValue->isPrimitiveValue()) | 1334 if (!cssValue || !cssValue->isPrimitiveValue()) |
1312 return 0; | 1335 return 0; |
1313 return legacyFontSizeFromCSSValue(document, toCSSPrimitiveValue(cssValue), | 1336 return legacyFontSizeFromCSSValue(document, toCSSPrimitiveValue(cssValue), |
1314 m_isMonospaceFont, AlwaysUseLegacyFontSize); | 1337 m_isMonospaceFont, AlwaysUseLegacyFontSize); |
1315 } | 1338 } |
1316 | 1339 |
1317 EditingStyle* EditingStyle::styleAtSelectionStart(const VisibleSelection& select
ion, bool shouldUseBackgroundColorInEffect) | 1340 EditingStyle* EditingStyle::styleAtSelectionStart(const VisibleSelection& select
ion, bool shouldUseBackgroundColorInEffect, MutableStylePropertySet* styleToChec
k) |
1318 { | 1341 { |
1319 if (selection.isNone()) | 1342 if (selection.isNone()) |
1320 return nullptr; | 1343 return nullptr; |
1321 | 1344 |
1322 Position position = adjustedSelectionStartForStyleComputation(selection); | 1345 Position position = adjustedSelectionStartForStyleComputation(selection); |
1323 | 1346 |
1324 // If the pos is at the end of a text node, then this node is not fully sele
cted. | 1347 // If the pos is at the end of a text node, then this node is not fully sele
cted. |
1325 // Move it to the next deep equivalent position to avoid removing the style
from this node. | 1348 // Move it to the next deep equivalent position to avoid removing the style
from this node. |
1326 // e.g. if pos was at Position("hello", 5) in <b>hello<div>world</div></b>,
we want Position("world", 0) instead. | 1349 // e.g. if pos was at Position("hello", 5) in <b>hello<div>world</div></b>,
we want Position("world", 0) instead. |
1327 // We only do this for range because caret at Position("hello", 5) in <b>hel
lo</b>world should give you font-weight: bold. | 1350 // We only do this for range because caret at Position("hello", 5) in <b>hel
lo</b>world should give you font-weight: bold. |
1328 Node* positionNode = position.computeContainerNode(); | 1351 Node* positionNode = position.computeContainerNode(); |
1329 if (selection.isRange() && positionNode && positionNode->isTextNode() && pos
ition.computeOffsetInContainerNode() == positionNode->maxCharacterOffset()) | 1352 if (selection.isRange() && positionNode && positionNode->isTextNode() && pos
ition.computeOffsetInContainerNode() == positionNode->maxCharacterOffset()) |
1330 position = nextVisuallyDistinctCandidate(position); | 1353 position = nextVisuallyDistinctCandidate(position); |
1331 | 1354 |
1332 Element* element = associatedElementOf(position); | 1355 Element* element = associatedElementOf(position); |
1333 if (!element) | 1356 if (!element) |
1334 return nullptr; | 1357 return nullptr; |
1335 | 1358 |
1336 EditingStyle* style = EditingStyle::create(element, EditingStyle::AllPropert
ies); | 1359 EditingStyle* style = EditingStyle::create(element, EditingStyle::AllPropert
ies); |
1337 style->mergeTypingStyle(&element->document()); | 1360 style->mergeTypingStyle(&element->document()); |
1338 | 1361 |
| 1362 // If |element| has <sub> or <sup> ancestor element, apply the corresponding |
| 1363 // style(vertical-align) to it so that document.queryCommandState() works wi
th the style. |
| 1364 // See bug http://crbug.com/582225. |
| 1365 CSSValueID valueID = getIdentifierValue(styleToCheck, CSSPropertyVerticalAli
gn); |
| 1366 if (valueID == CSSValueSub || valueID == CSSValueSuper) { |
| 1367 CSSComputedStyleDeclaration* elementStyle = CSSComputedStyleDeclaration:
:create(element); |
| 1368 // Find the ancestor that has CSSValueSub or CSSValueSuper as the value
of CSS vertical-align property. |
| 1369 if (getIdentifierValue(elementStyle, CSSPropertyVerticalAlign) == CSSVal
ueBaseline && hasAncestorVerticalAlignStyle(*element, valueID)) |
| 1370 style->m_mutableStyle->setProperty(CSSPropertyVerticalAlign, valueID
); |
| 1371 } |
| 1372 |
1339 // If background color is transparent, traverse parent nodes until we hit a
different value or document root | 1373 // If background color is transparent, traverse parent nodes until we hit a
different value or document root |
1340 // Also, if the selection is a range, ignore the background color at the sta
rt of selection, | 1374 // Also, if the selection is a range, ignore the background color at the sta
rt of selection, |
1341 // and find the background color of the common ancestor. | 1375 // and find the background color of the common ancestor. |
1342 if (shouldUseBackgroundColorInEffect && (selection.isRange() || hasTranspare
ntBackgroundColor(style->m_mutableStyle.get()))) { | 1376 if (shouldUseBackgroundColorInEffect && (selection.isRange() || hasTranspare
ntBackgroundColor(style->m_mutableStyle.get()))) { |
1343 const EphemeralRange range(selection.toNormalizedEphemeralRange()); | 1377 const EphemeralRange range(selection.toNormalizedEphemeralRange()); |
1344 if (CSSValue* value = backgroundColorValueInEffect(Range::commonAncestor
Container(range.startPosition().computeContainerNode(), range.endPosition().comp
uteContainerNode()))) | 1378 if (CSSValue* value = backgroundColorValueInEffect(Range::commonAncestor
Container(range.startPosition().computeContainerNode(), range.endPosition().comp
uteContainerNode()))) |
1345 style->setProperty(CSSPropertyBackgroundColor, value->cssText()); | 1379 style->setProperty(CSSPropertyBackgroundColor, value->cssText()); |
1346 } | 1380 } |
1347 | 1381 |
1348 return style; | 1382 return style; |
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1730 { | 1764 { |
1731 for (Node* ancestor = node; ancestor; ancestor = ancestor->parentNode()) { | 1765 for (Node* ancestor = node; ancestor; ancestor = ancestor->parentNode()) { |
1732 CSSComputedStyleDeclaration* ancestorStyle = CSSComputedStyleDeclaration
::create(ancestor); | 1766 CSSComputedStyleDeclaration* ancestorStyle = CSSComputedStyleDeclaration
::create(ancestor); |
1733 if (!hasTransparentBackgroundColor(ancestorStyle)) | 1767 if (!hasTransparentBackgroundColor(ancestorStyle)) |
1734 return ancestorStyle->getPropertyCSSValue(CSSPropertyBackgroundColor
); | 1768 return ancestorStyle->getPropertyCSSValue(CSSPropertyBackgroundColor
); |
1735 } | 1769 } |
1736 return nullptr; | 1770 return nullptr; |
1737 } | 1771 } |
1738 | 1772 |
1739 } // namespace blink | 1773 } // namespace blink |
OLD | NEW |