| 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 30 matching lines...) Expand all Loading... |
| 41 #include "core/css/StylePropertySet.h" | 41 #include "core/css/StylePropertySet.h" |
| 42 #include "core/css/StyleRule.h" | 42 #include "core/css/StyleRule.h" |
| 43 #include "core/css/parser/CSSParser.h" | 43 #include "core/css/parser/CSSParser.h" |
| 44 #include "core/css/resolver/StyleResolver.h" | 44 #include "core/css/resolver/StyleResolver.h" |
| 45 #include "core/dom/Document.h" | 45 #include "core/dom/Document.h" |
| 46 #include "core/dom/Element.h" | 46 #include "core/dom/Element.h" |
| 47 #include "core/dom/Node.h" | 47 #include "core/dom/Node.h" |
| 48 #include "core/dom/NodeComputedStyle.h" | 48 #include "core/dom/NodeComputedStyle.h" |
| 49 #include "core/dom/NodeTraversal.h" | 49 #include "core/dom/NodeTraversal.h" |
| 50 #include "core/dom/QualifiedName.h" | 50 #include "core/dom/QualifiedName.h" |
| 51 #include "core/editing/EditingStyleUtilities.h" |
| 51 #include "core/editing/EditingUtilities.h" | 52 #include "core/editing/EditingUtilities.h" |
| 52 #include "core/editing/Editor.h" | 53 #include "core/editing/Editor.h" |
| 53 #include "core/editing/FrameSelection.h" | 54 #include "core/editing/FrameSelection.h" |
| 54 #include "core/editing/Position.h" | 55 #include "core/editing/Position.h" |
| 55 #include "core/editing/commands/ApplyStyleCommand.h" | 56 #include "core/editing/commands/ApplyStyleCommand.h" |
| 56 #include "core/editing/serializers/HTMLInterchange.h" | 57 #include "core/editing/serializers/HTMLInterchange.h" |
| 57 #include "core/frame/LocalFrame.h" | 58 #include "core/frame/LocalFrame.h" |
| 58 #include "core/html/HTMLFontElement.h" | 59 #include "core/html/HTMLFontElement.h" |
| 59 #include "core/html/HTMLSpanElement.h" | 60 #include "core/html/HTMLSpanElement.h" |
| 60 #include "core/layout/LayoutBox.h" | 61 #include "core/layout/LayoutBox.h" |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 StylePropertySet* styleWithRedundantProperties, | 159 StylePropertySet* styleWithRedundantProperties, |
| 159 CSSStyleDeclaration* baseStyle); | 160 CSSStyleDeclaration* baseStyle); |
| 160 enum LegacyFontSizeMode { | 161 enum LegacyFontSizeMode { |
| 161 AlwaysUseLegacyFontSize, | 162 AlwaysUseLegacyFontSize, |
| 162 UseLegacyFontSizeOnlyIfPixelValuesMatch | 163 UseLegacyFontSizeOnlyIfPixelValuesMatch |
| 163 }; | 164 }; |
| 164 static int legacyFontSizeFromCSSValue(Document*, | 165 static int legacyFontSizeFromCSSValue(Document*, |
| 165 const CSSValue*, | 166 const CSSValue*, |
| 166 bool, | 167 bool, |
| 167 LegacyFontSizeMode); | 168 LegacyFontSizeMode); |
| 168 static bool isTransparentColorValue(const CSSValue*); | |
| 169 static bool hasTransparentBackgroundColor(CSSStyleDeclaration*); | |
| 170 static bool hasTransparentBackgroundColor(StylePropertySet*); | |
| 171 static const CSSValue* backgroundColorValueInEffect(Node*); | |
| 172 static bool hasAncestorVerticalAlignStyle(Node&, CSSValueID); | |
| 173 | 169 |
| 174 class HTMLElementEquivalent : public GarbageCollected<HTMLElementEquivalent> { | 170 class HTMLElementEquivalent : public GarbageCollected<HTMLElementEquivalent> { |
| 175 public: | 171 public: |
| 176 static HTMLElementEquivalent* create(CSSPropertyID propertyID, | 172 static HTMLElementEquivalent* create(CSSPropertyID propertyID, |
| 177 CSSValueID primitiveValue, | 173 CSSValueID primitiveValue, |
| 178 const HTMLQualifiedName& tagName) { | 174 const HTMLQualifiedName& tagName) { |
| 179 return new HTMLElementEquivalent(propertyID, primitiveValue, tagName); | 175 return new HTMLElementEquivalent(propertyID, primitiveValue, tagName); |
| 180 } | 176 } |
| 181 | 177 |
| 182 virtual bool matches(const Element* element) const { | 178 virtual bool matches(const Element* element) const { |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 return cssValueToColor( | 422 return cssValueToColor( |
| 427 style->getPropertyCSSValueInternal(CSSPropertyBackgroundColor)); | 423 style->getPropertyCSSValueInternal(CSSPropertyBackgroundColor)); |
| 428 } | 424 } |
| 429 | 425 |
| 430 static inline Color getBackgroundColor(StylePropertySet* style) { | 426 static inline Color getBackgroundColor(StylePropertySet* style) { |
| 431 return cssValueToColor( | 427 return cssValueToColor( |
| 432 style->getPropertyCSSValue(CSSPropertyBackgroundColor)); | 428 style->getPropertyCSSValue(CSSPropertyBackgroundColor)); |
| 433 } | 429 } |
| 434 | 430 |
| 435 static inline Color backgroundColorInEffect(Node* node) { | 431 static inline Color backgroundColorInEffect(Node* node) { |
| 436 return cssValueToColor(backgroundColorValueInEffect(node)); | 432 return cssValueToColor( |
| 433 EditingStyleUtilities::backgroundColorValueInEffect(node)); |
| 437 } | 434 } |
| 438 | 435 |
| 439 static int textAlignResolvingStartAndEnd(int textAlign, int direction) { | 436 static int textAlignResolvingStartAndEnd(int textAlign, int direction) { |
| 440 switch (textAlign) { | 437 switch (textAlign) { |
| 441 case CSSValueCenter: | 438 case CSSValueCenter: |
| 442 case CSSValueWebkitCenter: | 439 case CSSValueWebkitCenter: |
| 443 return CSSValueCenter; | 440 return CSSValueCenter; |
| 444 case CSSValueJustify: | 441 case CSSValueJustify: |
| 445 return CSSValueJustify; | 442 return CSSValueJustify; |
| 446 case CSSValueLeft: | 443 case CSSValueLeft: |
| (...skipping 24 matching lines...) Expand all Loading... |
| 471 node = node->parentNode(); | 468 node = node->parentNode(); |
| 472 | 469 |
| 473 CSSComputedStyleDeclaration* computedStyleAtPosition = | 470 CSSComputedStyleDeclaration* computedStyleAtPosition = |
| 474 CSSComputedStyleDeclaration::create(node); | 471 CSSComputedStyleDeclaration::create(node); |
| 475 m_mutableStyle = | 472 m_mutableStyle = |
| 476 propertiesToInclude == AllProperties && computedStyleAtPosition | 473 propertiesToInclude == AllProperties && computedStyleAtPosition |
| 477 ? computedStyleAtPosition->copyProperties() | 474 ? computedStyleAtPosition->copyProperties() |
| 478 : editingStyleFromComputedStyle(computedStyleAtPosition); | 475 : editingStyleFromComputedStyle(computedStyleAtPosition); |
| 479 | 476 |
| 480 if (propertiesToInclude == EditingPropertiesInEffect) { | 477 if (propertiesToInclude == EditingPropertiesInEffect) { |
| 481 if (const CSSValue* value = backgroundColorValueInEffect(node)) | 478 if (const CSSValue* value = |
| 479 EditingStyleUtilities::backgroundColorValueInEffect(node)) |
| 482 m_mutableStyle->setProperty(CSSPropertyBackgroundColor, value->cssText()); | 480 m_mutableStyle->setProperty(CSSPropertyBackgroundColor, value->cssText()); |
| 483 if (const CSSValue* value = computedStyleAtPosition->getPropertyCSSValue( | 481 if (const CSSValue* value = computedStyleAtPosition->getPropertyCSSValue( |
| 484 CSSPropertyWebkitTextDecorationsInEffect)) | 482 CSSPropertyWebkitTextDecorationsInEffect)) |
| 485 m_mutableStyle->setProperty(CSSPropertyTextDecoration, value->cssText()); | 483 m_mutableStyle->setProperty(CSSPropertyTextDecoration, value->cssText()); |
| 486 } | 484 } |
| 487 | 485 |
| 488 if (node && node->ensureComputedStyle()) { | 486 if (node && node->ensureComputedStyle()) { |
| 489 const ComputedStyle* computedStyle = node->ensureComputedStyle(); | 487 const ComputedStyle* computedStyle = node->ensureComputedStyle(); |
| 490 removeInheritedColorsIfNeeded(computedStyle); | 488 removeInheritedColorsIfNeeded(computedStyle); |
| 491 replaceFontSizeByKeywordIfPossible(computedStyle, computedStyleAtPosition); | 489 replaceFontSizeByKeywordIfPossible(computedStyle, computedStyleAtPosition); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 564 bool EditingStyle::textDirection(WritingDirection& writingDirection) const { | 562 bool EditingStyle::textDirection(WritingDirection& writingDirection) const { |
| 565 if (!m_mutableStyle) | 563 if (!m_mutableStyle) |
| 566 return false; | 564 return false; |
| 567 | 565 |
| 568 const CSSValue* unicodeBidi = | 566 const CSSValue* unicodeBidi = |
| 569 m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi); | 567 m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi); |
| 570 if (!unicodeBidi || !unicodeBidi->isIdentifierValue()) | 568 if (!unicodeBidi || !unicodeBidi->isIdentifierValue()) |
| 571 return false; | 569 return false; |
| 572 | 570 |
| 573 CSSValueID unicodeBidiValue = toCSSIdentifierValue(unicodeBidi)->getValueID(); | 571 CSSValueID unicodeBidiValue = toCSSIdentifierValue(unicodeBidi)->getValueID(); |
| 574 if (isEmbedOrIsolate(unicodeBidiValue)) { | 572 if (EditingStyleUtilities::isEmbedOrIsolate(unicodeBidiValue)) { |
| 575 const CSSValue* direction = | 573 const CSSValue* direction = |
| 576 m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection); | 574 m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection); |
| 577 if (!direction || !direction->isIdentifierValue()) | 575 if (!direction || !direction->isIdentifierValue()) |
| 578 return false; | 576 return false; |
| 579 | 577 |
| 580 writingDirection = | 578 writingDirection = |
| 581 toCSSIdentifierValue(direction)->getValueID() == CSSValueLtr | 579 toCSSIdentifierValue(direction)->getValueID() == CSSValueLtr |
| 582 ? LeftToRightWritingDirection | 580 ? LeftToRightWritingDirection |
| 583 : RightToLeftWritingDirection; | 581 : RightToLeftWritingDirection; |
| 584 | 582 |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 767 WTF_ARRAY_LENGTH(textOnlyProperties)); | 765 WTF_ARRAY_LENGTH(textOnlyProperties)); |
| 768 | 766 |
| 769 if (difference->isEmpty()) | 767 if (difference->isEmpty()) |
| 770 return TrueTriState; | 768 return TrueTriState; |
| 771 if (difference->propertyCount() == m_mutableStyle->propertyCount()) | 769 if (difference->propertyCount() == m_mutableStyle->propertyCount()) |
| 772 return FalseTriState; | 770 return FalseTriState; |
| 773 | 771 |
| 774 return MixedTriState; | 772 return MixedTriState; |
| 775 } | 773 } |
| 776 | 774 |
| 777 static bool hasAncestorVerticalAlignStyle(Node& node, CSSValueID value) { | |
| 778 for (Node& runner : NodeTraversal::inclusiveAncestorsOf(node)) { | |
| 779 CSSComputedStyleDeclaration* ancestorStyle = | |
| 780 CSSComputedStyleDeclaration::create(&runner); | |
| 781 if (getIdentifierValue(ancestorStyle, CSSPropertyVerticalAlign) == value) | |
| 782 return true; | |
| 783 } | |
| 784 return false; | |
| 785 } | |
| 786 | |
| 787 TriState EditingStyle::triStateOfStyle( | 775 TriState EditingStyle::triStateOfStyle( |
| 788 const VisibleSelection& selection) const { | 776 const VisibleSelection& selection) const { |
| 789 if (selection.isNone()) | 777 if (selection.isNone()) |
| 790 return FalseTriState; | 778 return FalseTriState; |
| 791 | 779 |
| 792 if (selection.isCaret()) | 780 if (selection.isCaret()) { |
| 793 return triStateOfStyle(EditingStyle::styleAtSelectionStart(selection)); | 781 return triStateOfStyle( |
| 782 EditingStyleUtilities::createStyleAtSelectionStart(selection)); |
| 783 } |
| 794 | 784 |
| 795 TriState state = FalseTriState; | 785 TriState state = FalseTriState; |
| 796 bool nodeIsStart = true; | 786 bool nodeIsStart = true; |
| 797 for (Node& node : NodeTraversal::startsAt(*selection.start().anchorNode())) { | 787 for (Node& node : NodeTraversal::startsAt(*selection.start().anchorNode())) { |
| 798 if (node.layoutObject() && hasEditableStyle(node)) { | 788 if (node.layoutObject() && hasEditableStyle(node)) { |
| 799 CSSComputedStyleDeclaration* nodeStyle = | 789 CSSComputedStyleDeclaration* nodeStyle = |
| 800 CSSComputedStyleDeclaration::create(&node); | 790 CSSComputedStyleDeclaration::create(&node); |
| 801 if (nodeStyle) { | 791 if (nodeStyle) { |
| 802 // If the selected element has <sub> or <sup> ancestor element, apply | 792 // If the selected element has <sub> or <sup> ancestor element, apply |
| 803 // the corresponding style(vertical-align) to it so that | 793 // the corresponding style(vertical-align) to it so that |
| 804 // document.queryCommandState() works with the style. See bug | 794 // document.queryCommandState() works with the style. See bug |
| 805 // http://crbug.com/582225. | 795 // http://crbug.com/582225. |
| 806 if (m_isVerticalAlign && | 796 if (m_isVerticalAlign && |
| 807 getIdentifierValue(nodeStyle, CSSPropertyVerticalAlign) == | 797 getIdentifierValue(nodeStyle, CSSPropertyVerticalAlign) == |
| 808 CSSValueBaseline) { | 798 CSSValueBaseline) { |
| 809 const CSSIdentifierValue* verticalAlign = toCSSIdentifierValue( | 799 const CSSIdentifierValue* verticalAlign = toCSSIdentifierValue( |
| 810 m_mutableStyle->getPropertyCSSValue(CSSPropertyVerticalAlign)); | 800 m_mutableStyle->getPropertyCSSValue(CSSPropertyVerticalAlign)); |
| 811 if (hasAncestorVerticalAlignStyle(node, verticalAlign->getValueID())) | 801 if (EditingStyleUtilities::hasAncestorVerticalAlignStyle( |
| 802 node, verticalAlign->getValueID())) |
| 812 node.mutableComputedStyle()->setVerticalAlign( | 803 node.mutableComputedStyle()->setVerticalAlign( |
| 813 verticalAlign->convertTo<EVerticalAlign>()); | 804 verticalAlign->convertTo<EVerticalAlign>()); |
| 814 } | 805 } |
| 815 | 806 |
| 816 // Pass EditingStyle::DoNotIgnoreTextOnlyProperties without checking if | 807 // Pass EditingStyle::DoNotIgnoreTextOnlyProperties without checking if |
| 817 // node.isTextNode() because the node can be an element node. See bug | 808 // node.isTextNode() because the node can be an element node. See bug |
| 818 // http://crbug.com/584939. | 809 // http://crbug.com/584939. |
| 819 TriState nodeState = triStateOfStyle( | 810 TriState nodeState = triStateOfStyle( |
| 820 nodeStyle, EditingStyle::DoNotIgnoreTextOnlyProperties); | 811 nodeStyle, EditingStyle::DoNotIgnoreTextOnlyProperties); |
| 821 if (nodeIsStart) { | 812 if (nodeIsStart) { |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1124 | 1115 |
| 1125 m_mutableStyle->removeEquivalentProperties(styleAtPosition); | 1116 m_mutableStyle->removeEquivalentProperties(styleAtPosition); |
| 1126 | 1117 |
| 1127 if (textAlignResolvingStartAndEnd(m_mutableStyle.get()) == | 1118 if (textAlignResolvingStartAndEnd(m_mutableStyle.get()) == |
| 1128 textAlignResolvingStartAndEnd(styleAtPosition)) | 1119 textAlignResolvingStartAndEnd(styleAtPosition)) |
| 1129 m_mutableStyle->removeProperty(CSSPropertyTextAlign); | 1120 m_mutableStyle->removeProperty(CSSPropertyTextAlign); |
| 1130 | 1121 |
| 1131 if (getFontColor(m_mutableStyle.get()) == getFontColor(styleAtPosition)) | 1122 if (getFontColor(m_mutableStyle.get()) == getFontColor(styleAtPosition)) |
| 1132 m_mutableStyle->removeProperty(CSSPropertyColor); | 1123 m_mutableStyle->removeProperty(CSSPropertyColor); |
| 1133 | 1124 |
| 1134 if (hasTransparentBackgroundColor(m_mutableStyle.get()) || | 1125 if (EditingStyleUtilities::hasTransparentBackgroundColor( |
| 1126 m_mutableStyle.get()) || |
| 1135 cssValueToColor( | 1127 cssValueToColor( |
| 1136 m_mutableStyle->getPropertyCSSValue(CSSPropertyBackgroundColor)) == | 1128 m_mutableStyle->getPropertyCSSValue(CSSPropertyBackgroundColor)) == |
| 1137 backgroundColorInEffect(position.computeContainerNode())) | 1129 backgroundColorInEffect(position.computeContainerNode())) |
| 1138 m_mutableStyle->removeProperty(CSSPropertyBackgroundColor); | 1130 m_mutableStyle->removeProperty(CSSPropertyBackgroundColor); |
| 1139 | 1131 |
| 1140 if (unicodeBidi && unicodeBidi->isIdentifierValue()) { | 1132 if (unicodeBidi && unicodeBidi->isIdentifierValue()) { |
| 1141 m_mutableStyle->setProperty( | 1133 m_mutableStyle->setProperty( |
| 1142 CSSPropertyUnicodeBidi, | 1134 CSSPropertyUnicodeBidi, |
| 1143 toCSSIdentifierValue(unicodeBidi)->getValueID()); | 1135 toCSSIdentifierValue(unicodeBidi)->getValueID()); |
| 1144 if (direction && direction->isIdentifierValue()) { | 1136 if (direction && direction->isIdentifierValue()) { |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1240 htmlAttributeEquivalents(); | 1232 htmlAttributeEquivalents(); |
| 1241 for (const auto& attribute : attributeEquivalents) { | 1233 for (const auto& attribute : attributeEquivalents) { |
| 1242 if (attribute->attributeName() == HTMLNames::dirAttr) | 1234 if (attribute->attributeName() == HTMLNames::dirAttr) |
| 1243 continue; // We don't want to include directionality | 1235 continue; // We don't want to include directionality |
| 1244 if (elementMatchesAndPropertyIsNotInInlineStyleDecl( | 1236 if (elementMatchesAndPropertyIsNotInInlineStyleDecl( |
| 1245 attribute.get(), element, mode, m_mutableStyle.get())) | 1237 attribute.get(), element, mode, m_mutableStyle.get())) |
| 1246 attribute->addToStyle(element, this); | 1238 attribute->addToStyle(element, this); |
| 1247 } | 1239 } |
| 1248 } | 1240 } |
| 1249 | 1241 |
| 1250 EditingStyle* EditingStyle::wrappingStyleForAnnotatedSerialization( | |
| 1251 ContainerNode* context) { | |
| 1252 EditingStyle* wrappingStyle = | |
| 1253 EditingStyle::create(context, EditingStyle::EditingPropertiesInEffect); | |
| 1254 | |
| 1255 // Styles that Mail blockquotes contribute should only be placed on the Mail | |
| 1256 // blockquote, to help us differentiate those styles from ones that the user | |
| 1257 // has applied. This helps us get the color of content pasted into | |
| 1258 // blockquotes right. | |
| 1259 wrappingStyle->removeStyleAddedByElement(toHTMLElement(enclosingNodeOfType( | |
| 1260 firstPositionInOrBeforeNode(context), isMailHTMLBlockquoteElement, | |
| 1261 CanCrossEditingBoundary))); | |
| 1262 | |
| 1263 // Call collapseTextDecorationProperties first or otherwise it'll copy the | |
| 1264 // value over from in-effect to text-decorations. | |
| 1265 wrappingStyle->collapseTextDecorationProperties(); | |
| 1266 | |
| 1267 return wrappingStyle; | |
| 1268 } | |
| 1269 | |
| 1270 EditingStyle* EditingStyle::wrappingStyleForSerialization( | |
| 1271 ContainerNode* context) { | |
| 1272 DCHECK(context); | |
| 1273 EditingStyle* wrappingStyle = EditingStyle::create(); | |
| 1274 | |
| 1275 // When not annotating for interchange, we only preserve inline style | |
| 1276 // declarations. | |
| 1277 for (Node& node : NodeTraversal::inclusiveAncestorsOf(*context)) { | |
| 1278 if (node.isDocumentNode()) | |
| 1279 break; | |
| 1280 if (node.isStyledElement() && !isMailHTMLBlockquoteElement(&node)) { | |
| 1281 wrappingStyle->mergeInlineAndImplicitStyleOfElement( | |
| 1282 toElement(&node), EditingStyle::DoNotOverrideValues, | |
| 1283 EditingStyle::EditingPropertiesInEffect); | |
| 1284 } | |
| 1285 } | |
| 1286 | |
| 1287 return wrappingStyle; | |
| 1288 } | |
| 1289 | 1242 |
| 1290 static const CSSValueList& mergeTextDecorationValues( | 1243 static const CSSValueList& mergeTextDecorationValues( |
| 1291 const CSSValueList& mergedValue, | 1244 const CSSValueList& mergedValue, |
| 1292 const CSSValueList& valueToMerge) { | 1245 const CSSValueList& valueToMerge) { |
| 1293 DEFINE_STATIC_LOCAL(CSSIdentifierValue, underline, | 1246 DEFINE_STATIC_LOCAL(CSSIdentifierValue, underline, |
| 1294 (CSSIdentifierValue::create(CSSValueUnderline))); | 1247 (CSSIdentifierValue::create(CSSValueUnderline))); |
| 1295 DEFINE_STATIC_LOCAL(CSSIdentifierValue, lineThrough, | 1248 DEFINE_STATIC_LOCAL(CSSIdentifierValue, lineThrough, |
| 1296 (CSSIdentifierValue::create(CSSValueLineThrough))); | 1249 (CSSIdentifierValue::create(CSSValueLineThrough))); |
| 1297 CSSValueList& result = *mergedValue.copy(); | 1250 CSSValueList& result = *mergedValue.copy(); |
| 1298 if (valueToMerge.hasValue(underline) && !mergedValue.hasValue(underline)) | 1251 if (valueToMerge.hasValue(underline) && !mergedValue.hasValue(underline)) |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1516 int EditingStyle::legacyFontSize(Document* document) const { | 1469 int EditingStyle::legacyFontSize(Document* document) const { |
| 1517 const CSSValue* cssValue = | 1470 const CSSValue* cssValue = |
| 1518 m_mutableStyle->getPropertyCSSValue(CSSPropertyFontSize); | 1471 m_mutableStyle->getPropertyCSSValue(CSSPropertyFontSize); |
| 1519 if (!cssValue || | 1472 if (!cssValue || |
| 1520 !(cssValue->isPrimitiveValue() || cssValue->isIdentifierValue())) | 1473 !(cssValue->isPrimitiveValue() || cssValue->isIdentifierValue())) |
| 1521 return 0; | 1474 return 0; |
| 1522 return legacyFontSizeFromCSSValue(document, cssValue, m_isMonospaceFont, | 1475 return legacyFontSizeFromCSSValue(document, cssValue, m_isMonospaceFont, |
| 1523 AlwaysUseLegacyFontSize); | 1476 AlwaysUseLegacyFontSize); |
| 1524 } | 1477 } |
| 1525 | 1478 |
| 1526 EditingStyle* EditingStyle::styleAtSelectionStart( | |
| 1527 const VisibleSelection& selection, | |
| 1528 bool shouldUseBackgroundColorInEffect, | |
| 1529 MutableStylePropertySet* styleToCheck) { | |
| 1530 if (selection.isNone()) | |
| 1531 return nullptr; | |
| 1532 | |
| 1533 Document& document = *selection.start().document(); | |
| 1534 | |
| 1535 DCHECK(!document.needsLayoutTreeUpdate()); | |
| 1536 DocumentLifecycle::DisallowTransitionScope disallowTransition( | |
| 1537 document.lifecycle()); | |
| 1538 | |
| 1539 Position position = adjustedSelectionStartForStyleComputation(selection); | |
| 1540 | |
| 1541 // If the pos is at the end of a text node, then this node is not fully | |
| 1542 // selected. Move it to the next deep equivalent position to avoid removing | |
| 1543 // the style from this node. | |
| 1544 // e.g. if pos was at Position("hello", 5) in <b>hello<div>world</div></b>, we | |
| 1545 // want Position("world", 0) instead. | |
| 1546 // We only do this for range because caret at Position("hello", 5) in | |
| 1547 // <b>hello</b>world should give you font-weight: bold. | |
| 1548 Node* positionNode = position.computeContainerNode(); | |
| 1549 if (selection.isRange() && positionNode && positionNode->isTextNode() && | |
| 1550 position.computeOffsetInContainerNode() == | |
| 1551 positionNode->maxCharacterOffset()) | |
| 1552 position = nextVisuallyDistinctCandidate(position); | |
| 1553 | |
| 1554 Element* element = associatedElementOf(position); | |
| 1555 if (!element) | |
| 1556 return nullptr; | |
| 1557 | |
| 1558 EditingStyle* style = | |
| 1559 EditingStyle::create(element, EditingStyle::AllProperties); | |
| 1560 style->mergeTypingStyle(&element->document()); | |
| 1561 | |
| 1562 // If |element| has <sub> or <sup> ancestor element, apply the corresponding | |
| 1563 // style(vertical-align) to it so that document.queryCommandState() works with | |
| 1564 // the style. See bug http://crbug.com/582225. | |
| 1565 CSSValueID valueID = | |
| 1566 getIdentifierValue(styleToCheck, CSSPropertyVerticalAlign); | |
| 1567 if (valueID == CSSValueSub || valueID == CSSValueSuper) { | |
| 1568 CSSComputedStyleDeclaration* elementStyle = | |
| 1569 CSSComputedStyleDeclaration::create(element); | |
| 1570 // Find the ancestor that has CSSValueSub or CSSValueSuper as the value of | |
| 1571 // CSS vertical-align property. | |
| 1572 if (getIdentifierValue(elementStyle, CSSPropertyVerticalAlign) == | |
| 1573 CSSValueBaseline && | |
| 1574 hasAncestorVerticalAlignStyle(*element, valueID)) | |
| 1575 style->m_mutableStyle->setProperty(CSSPropertyVerticalAlign, valueID); | |
| 1576 } | |
| 1577 | |
| 1578 // If background color is transparent, traverse parent nodes until we hit a | |
| 1579 // different value or document root Also, if the selection is a range, ignore | |
| 1580 // the background color at the start of selection, and find the background | |
| 1581 // color of the common ancestor. | |
| 1582 if (shouldUseBackgroundColorInEffect && | |
| 1583 (selection.isRange() || | |
| 1584 hasTransparentBackgroundColor(style->m_mutableStyle.get()))) { | |
| 1585 const EphemeralRange range(selection.toNormalizedEphemeralRange()); | |
| 1586 if (const CSSValue* value = | |
| 1587 backgroundColorValueInEffect(Range::commonAncestorContainer( | |
| 1588 range.startPosition().computeContainerNode(), | |
| 1589 range.endPosition().computeContainerNode()))) | |
| 1590 style->setProperty(CSSPropertyBackgroundColor, value->cssText()); | |
| 1591 } | |
| 1592 | |
| 1593 return style; | |
| 1594 } | |
| 1595 | |
| 1596 static bool isUnicodeBidiNestedOrMultipleEmbeddings(CSSValueID valueID) { | |
| 1597 return valueID == CSSValueEmbed || valueID == CSSValueBidiOverride || | |
| 1598 valueID == CSSValueWebkitIsolate || | |
| 1599 valueID == CSSValueWebkitIsolateOverride || | |
| 1600 valueID == CSSValueWebkitPlaintext || valueID == CSSValueIsolate || | |
| 1601 valueID == CSSValueIsolateOverride || valueID == CSSValuePlaintext; | |
| 1602 } | |
| 1603 | |
| 1604 WritingDirection EditingStyle::textDirectionForSelection( | |
| 1605 const VisibleSelection& selection, | |
| 1606 EditingStyle* typingStyle, | |
| 1607 bool& hasNestedOrMultipleEmbeddings) { | |
| 1608 hasNestedOrMultipleEmbeddings = true; | |
| 1609 | |
| 1610 if (selection.isNone()) | |
| 1611 return NaturalWritingDirection; | |
| 1612 | |
| 1613 Position position = mostForwardCaretPosition(selection.start()); | |
| 1614 | |
| 1615 Node* node = position.anchorNode(); | |
| 1616 if (!node) | |
| 1617 return NaturalWritingDirection; | |
| 1618 | |
| 1619 Position end; | |
| 1620 if (selection.isRange()) { | |
| 1621 end = mostBackwardCaretPosition(selection.end()); | |
| 1622 | |
| 1623 DCHECK(end.document()); | |
| 1624 const EphemeralRange caretRange(position.parentAnchoredEquivalent(), | |
| 1625 end.parentAnchoredEquivalent()); | |
| 1626 for (Node& n : caretRange.nodes()) { | |
| 1627 if (!n.isStyledElement()) | |
| 1628 continue; | |
| 1629 | |
| 1630 CSSComputedStyleDeclaration* style = | |
| 1631 CSSComputedStyleDeclaration::create(&n); | |
| 1632 const CSSValue* unicodeBidi = | |
| 1633 style->getPropertyCSSValue(CSSPropertyUnicodeBidi); | |
| 1634 if (!unicodeBidi || !unicodeBidi->isIdentifierValue()) | |
| 1635 continue; | |
| 1636 | |
| 1637 CSSValueID unicodeBidiValue = | |
| 1638 toCSSIdentifierValue(unicodeBidi)->getValueID(); | |
| 1639 if (isUnicodeBidiNestedOrMultipleEmbeddings(unicodeBidiValue)) | |
| 1640 return NaturalWritingDirection; | |
| 1641 } | |
| 1642 } | |
| 1643 | |
| 1644 if (selection.isCaret()) { | |
| 1645 WritingDirection direction; | |
| 1646 if (typingStyle && typingStyle->textDirection(direction)) { | |
| 1647 hasNestedOrMultipleEmbeddings = false; | |
| 1648 return direction; | |
| 1649 } | |
| 1650 node = selection.visibleStart().deepEquivalent().anchorNode(); | |
| 1651 } | |
| 1652 DCHECK(node); | |
| 1653 | |
| 1654 // The selection is either a caret with no typing attributes or a range in | |
| 1655 // which no embedding is added, so just use the start position to decide. | |
| 1656 Node* block = enclosingBlock(node); | |
| 1657 WritingDirection foundDirection = NaturalWritingDirection; | |
| 1658 | |
| 1659 for (Node& runner : NodeTraversal::inclusiveAncestorsOf(*node)) { | |
| 1660 if (runner == block) | |
| 1661 break; | |
| 1662 if (!runner.isStyledElement()) | |
| 1663 continue; | |
| 1664 | |
| 1665 Element* element = &toElement(runner); | |
| 1666 CSSComputedStyleDeclaration* style = | |
| 1667 CSSComputedStyleDeclaration::create(element); | |
| 1668 const CSSValue* unicodeBidi = | |
| 1669 style->getPropertyCSSValue(CSSPropertyUnicodeBidi); | |
| 1670 if (!unicodeBidi || !unicodeBidi->isIdentifierValue()) | |
| 1671 continue; | |
| 1672 | |
| 1673 CSSValueID unicodeBidiValue = | |
| 1674 toCSSIdentifierValue(unicodeBidi)->getValueID(); | |
| 1675 if (unicodeBidiValue == CSSValueNormal) | |
| 1676 continue; | |
| 1677 | |
| 1678 if (unicodeBidiValue == CSSValueBidiOverride) | |
| 1679 return NaturalWritingDirection; | |
| 1680 | |
| 1681 DCHECK(isEmbedOrIsolate(unicodeBidiValue)) << unicodeBidiValue; | |
| 1682 const CSSValue* direction = | |
| 1683 style->getPropertyCSSValue(CSSPropertyDirection); | |
| 1684 if (!direction || !direction->isIdentifierValue()) | |
| 1685 continue; | |
| 1686 | |
| 1687 int directionValue = toCSSIdentifierValue(direction)->getValueID(); | |
| 1688 if (directionValue != CSSValueLtr && directionValue != CSSValueRtl) | |
| 1689 continue; | |
| 1690 | |
| 1691 if (foundDirection != NaturalWritingDirection) | |
| 1692 return NaturalWritingDirection; | |
| 1693 | |
| 1694 // In the range case, make sure that the embedding element persists until | |
| 1695 // the end of the range. | |
| 1696 if (selection.isRange() && !end.anchorNode()->isDescendantOf(element)) | |
| 1697 return NaturalWritingDirection; | |
| 1698 | |
| 1699 foundDirection = directionValue == CSSValueLtr | |
| 1700 ? LeftToRightWritingDirection | |
| 1701 : RightToLeftWritingDirection; | |
| 1702 } | |
| 1703 hasNestedOrMultipleEmbeddings = false; | |
| 1704 return foundDirection; | |
| 1705 } | |
| 1706 | |
| 1707 DEFINE_TRACE(EditingStyle) { | 1479 DEFINE_TRACE(EditingStyle) { |
| 1708 visitor->trace(m_mutableStyle); | 1480 visitor->trace(m_mutableStyle); |
| 1709 } | 1481 } |
| 1710 | 1482 |
| 1711 static void reconcileTextDecorationProperties(MutableStylePropertySet* style) { | 1483 static void reconcileTextDecorationProperties(MutableStylePropertySet* style) { |
| 1712 const CSSValue* textDecorationsInEffect = | 1484 const CSSValue* textDecorationsInEffect = |
| 1713 style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect); | 1485 style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect); |
| 1714 const CSSValue* textDecoration = | 1486 const CSSValue* textDecoration = |
| 1715 style->getPropertyCSSValue(textDecorationPropertyForEditing()); | 1487 style->getPropertyCSSValue(textDecorationPropertyForEditing()); |
| 1716 // "LayoutTests/editing/execCommand/insert-list-and-strikethrough.html" makes | 1488 // "LayoutTests/editing/execCommand/insert-list-and-strikethrough.html" makes |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2007 if (value->isIdentifierValue()) { | 1779 if (value->isIdentifierValue()) { |
| 2008 const CSSIdentifierValue& identifierValue = toCSSIdentifierValue(*value); | 1780 const CSSIdentifierValue& identifierValue = toCSSIdentifierValue(*value); |
| 2009 if (CSSValueXSmall <= identifierValue.getValueID() && | 1781 if (CSSValueXSmall <= identifierValue.getValueID() && |
| 2010 identifierValue.getValueID() <= CSSValueWebkitXxxLarge) | 1782 identifierValue.getValueID() <= CSSValueWebkitXxxLarge) |
| 2011 return identifierValue.getValueID() - CSSValueXSmall + 1; | 1783 return identifierValue.getValueID() - CSSValueXSmall + 1; |
| 2012 } | 1784 } |
| 2013 | 1785 |
| 2014 return 0; | 1786 return 0; |
| 2015 } | 1787 } |
| 2016 | 1788 |
| 2017 bool isTransparentColorValue(const CSSValue* cssValue) { | |
| 2018 if (!cssValue) | |
| 2019 return true; | |
| 2020 if (cssValue->isColorValue()) | |
| 2021 return !toCSSColorValue(cssValue)->value().alpha(); | |
| 2022 if (!cssValue->isIdentifierValue()) | |
| 2023 return false; | |
| 2024 return toCSSIdentifierValue(cssValue)->getValueID() == CSSValueTransparent; | |
| 2025 } | |
| 2026 | |
| 2027 bool hasTransparentBackgroundColor(CSSStyleDeclaration* style) { | |
| 2028 const CSSValue* cssValue = | |
| 2029 style->getPropertyCSSValueInternal(CSSPropertyBackgroundColor); | |
| 2030 return isTransparentColorValue(cssValue); | |
| 2031 } | |
| 2032 | |
| 2033 bool hasTransparentBackgroundColor(StylePropertySet* style) { | |
| 2034 const CSSValue* cssValue = | |
| 2035 style->getPropertyCSSValue(CSSPropertyBackgroundColor); | |
| 2036 return isTransparentColorValue(cssValue); | |
| 2037 } | |
| 2038 | |
| 2039 const CSSValue* backgroundColorValueInEffect(Node* node) { | |
| 2040 for (Node* ancestor = node; ancestor; ancestor = ancestor->parentNode()) { | |
| 2041 CSSComputedStyleDeclaration* ancestorStyle = | |
| 2042 CSSComputedStyleDeclaration::create(ancestor); | |
| 2043 if (!hasTransparentBackgroundColor(ancestorStyle)) | |
| 2044 return ancestorStyle->getPropertyCSSValue(CSSPropertyBackgroundColor); | |
| 2045 } | |
| 2046 return nullptr; | |
| 2047 } | |
| 2048 | |
| 2049 } // namespace blink | 1789 } // namespace blink |
| OLD | NEW |