Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(318)

Side by Side Diff: third_party/WebKit/Source/core/editing/EditingStyle.cpp

Issue 1986563002: Apply vertical-align style of <sub> and <sup> to child elements. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: simplify the test case Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698