| 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 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 159 StylePropertySet* styleWithRedundantProperties, | 159 StylePropertySet* styleWithRedundantProperties, |
| 160 CSSStyleDeclaration* baseStyle); | 160 CSSStyleDeclaration* baseStyle); |
| 161 enum LegacyFontSizeMode { | 161 enum LegacyFontSizeMode { |
| 162 AlwaysUseLegacyFontSize, | 162 AlwaysUseLegacyFontSize, |
| 163 UseLegacyFontSizeOnlyIfPixelValuesMatch | 163 UseLegacyFontSizeOnlyIfPixelValuesMatch |
| 164 }; | 164 }; |
| 165 static int legacyFontSizeFromCSSValue(Document*, | 165 static int legacyFontSizeFromCSSValue(Document*, |
| 166 const CSSValue*, | 166 const CSSValue*, |
| 167 bool, | 167 bool, |
| 168 LegacyFontSizeMode); | 168 LegacyFontSizeMode); |
| 169 static bool isTransparentColorValue(const CSSValue*); | |
| 170 static bool hasTransparentBackgroundColor(CSSStyleDeclaration*); | |
| 171 static bool hasTransparentBackgroundColor(StylePropertySet*); | |
| 172 static const CSSValue* backgroundColorValueInEffect(Node*); | |
| 173 static bool hasAncestorVerticalAlignStyle(Node&, CSSValueID); | |
| 174 | 169 |
| 175 class HTMLElementEquivalent : public GarbageCollected<HTMLElementEquivalent> { | 170 class HTMLElementEquivalent : public GarbageCollected<HTMLElementEquivalent> { |
| 176 public: | 171 public: |
| 177 static HTMLElementEquivalent* create(CSSPropertyID propertyID, | 172 static HTMLElementEquivalent* create(CSSPropertyID propertyID, |
| 178 CSSValueID primitiveValue, | 173 CSSValueID primitiveValue, |
| 179 const HTMLQualifiedName& tagName) { | 174 const HTMLQualifiedName& tagName) { |
| 180 return new HTMLElementEquivalent(propertyID, primitiveValue, tagName); | 175 return new HTMLElementEquivalent(propertyID, primitiveValue, tagName); |
| 181 } | 176 } |
| 182 | 177 |
| 183 virtual bool matches(const Element* element) const { | 178 virtual bool matches(const Element* element) const { |
| (...skipping 586 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 770 WTF_ARRAY_LENGTH(textOnlyProperties)); | 765 WTF_ARRAY_LENGTH(textOnlyProperties)); |
| 771 | 766 |
| 772 if (difference->isEmpty()) | 767 if (difference->isEmpty()) |
| 773 return TrueTriState; | 768 return TrueTriState; |
| 774 if (difference->propertyCount() == m_mutableStyle->propertyCount()) | 769 if (difference->propertyCount() == m_mutableStyle->propertyCount()) |
| 775 return FalseTriState; | 770 return FalseTriState; |
| 776 | 771 |
| 777 return MixedTriState; | 772 return MixedTriState; |
| 778 } | 773 } |
| 779 | 774 |
| 780 static bool hasAncestorVerticalAlignStyle(Node& node, CSSValueID value) { | |
| 781 for (Node& runner : NodeTraversal::inclusiveAncestorsOf(node)) { | |
| 782 CSSComputedStyleDeclaration* ancestorStyle = | |
| 783 CSSComputedStyleDeclaration::create(&runner); | |
| 784 if (getIdentifierValue(ancestorStyle, CSSPropertyVerticalAlign) == value) | |
| 785 return true; | |
| 786 } | |
| 787 return false; | |
| 788 } | |
| 789 | |
| 790 TriState EditingStyle::triStateOfStyle( | 775 TriState EditingStyle::triStateOfStyle( |
| 791 const VisibleSelection& selection) const { | 776 const VisibleSelection& selection) const { |
| 792 if (selection.isNone()) | 777 if (selection.isNone()) |
| 793 return FalseTriState; | 778 return FalseTriState; |
| 794 | 779 |
| 795 if (selection.isCaret()) { | 780 if (selection.isCaret()) { |
| 796 return triStateOfStyle( | 781 return triStateOfStyle( |
| 797 EditingStyleUtilities::createStyleAtSelectionStart(selection)); | 782 EditingStyleUtilities::createStyleAtSelectionStart(selection)); |
| 798 } | 783 } |
| 799 | 784 |
| (...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1247 htmlAttributeEquivalents(); | 1232 htmlAttributeEquivalents(); |
| 1248 for (const auto& attribute : attributeEquivalents) { | 1233 for (const auto& attribute : attributeEquivalents) { |
| 1249 if (attribute->attributeName() == HTMLNames::dirAttr) | 1234 if (attribute->attributeName() == HTMLNames::dirAttr) |
| 1250 continue; // We don't want to include directionality | 1235 continue; // We don't want to include directionality |
| 1251 if (elementMatchesAndPropertyIsNotInInlineStyleDecl( | 1236 if (elementMatchesAndPropertyIsNotInInlineStyleDecl( |
| 1252 attribute.get(), element, mode, m_mutableStyle.get())) | 1237 attribute.get(), element, mode, m_mutableStyle.get())) |
| 1253 attribute->addToStyle(element, this); | 1238 attribute->addToStyle(element, this); |
| 1254 } | 1239 } |
| 1255 } | 1240 } |
| 1256 | 1241 |
| 1257 EditingStyle* EditingStyle::wrappingStyleForAnnotatedSerialization( | |
| 1258 ContainerNode* context) { | |
| 1259 EditingStyle* wrappingStyle = | |
| 1260 EditingStyle::create(context, EditingStyle::EditingPropertiesInEffect); | |
| 1261 | |
| 1262 // Styles that Mail blockquotes contribute should only be placed on the Mail | |
| 1263 // blockquote, to help us differentiate those styles from ones that the user | |
| 1264 // has applied. This helps us get the color of content pasted into | |
| 1265 // blockquotes right. | |
| 1266 wrappingStyle->removeStyleAddedByElement(toHTMLElement(enclosingNodeOfType( | |
| 1267 firstPositionInOrBeforeNode(context), isMailHTMLBlockquoteElement, | |
| 1268 CanCrossEditingBoundary))); | |
| 1269 | |
| 1270 // Call collapseTextDecorationProperties first or otherwise it'll copy the | |
| 1271 // value over from in-effect to text-decorations. | |
| 1272 wrappingStyle->collapseTextDecorationProperties(); | |
| 1273 | |
| 1274 return wrappingStyle; | |
| 1275 } | |
| 1276 | |
| 1277 EditingStyle* EditingStyle::wrappingStyleForSerialization( | |
| 1278 ContainerNode* context) { | |
| 1279 DCHECK(context); | |
| 1280 EditingStyle* wrappingStyle = EditingStyle::create(); | |
| 1281 | |
| 1282 // When not annotating for interchange, we only preserve inline style | |
| 1283 // declarations. | |
| 1284 for (Node& node : NodeTraversal::inclusiveAncestorsOf(*context)) { | |
| 1285 if (node.isDocumentNode()) | |
| 1286 break; | |
| 1287 if (node.isStyledElement() && !isMailHTMLBlockquoteElement(&node)) { | |
| 1288 wrappingStyle->mergeInlineAndImplicitStyleOfElement( | |
| 1289 toElement(&node), EditingStyle::DoNotOverrideValues, | |
| 1290 EditingStyle::EditingPropertiesInEffect); | |
| 1291 } | |
| 1292 } | |
| 1293 | |
| 1294 return wrappingStyle; | |
| 1295 } | |
| 1296 | |
| 1297 static const CSSValueList& mergeTextDecorationValues( | 1242 static const CSSValueList& mergeTextDecorationValues( |
| 1298 const CSSValueList& mergedValue, | 1243 const CSSValueList& mergedValue, |
| 1299 const CSSValueList& valueToMerge) { | 1244 const CSSValueList& valueToMerge) { |
| 1300 DEFINE_STATIC_LOCAL(CSSIdentifierValue, underline, | 1245 DEFINE_STATIC_LOCAL(CSSIdentifierValue, underline, |
| 1301 (CSSIdentifierValue::create(CSSValueUnderline))); | 1246 (CSSIdentifierValue::create(CSSValueUnderline))); |
| 1302 DEFINE_STATIC_LOCAL(CSSIdentifierValue, lineThrough, | 1247 DEFINE_STATIC_LOCAL(CSSIdentifierValue, lineThrough, |
| 1303 (CSSIdentifierValue::create(CSSValueLineThrough))); | 1248 (CSSIdentifierValue::create(CSSValueLineThrough))); |
| 1304 CSSValueList& result = *mergedValue.copy(); | 1249 CSSValueList& result = *mergedValue.copy(); |
| 1305 if (valueToMerge.hasValue(underline) && !mergedValue.hasValue(underline)) | 1250 if (valueToMerge.hasValue(underline) && !mergedValue.hasValue(underline)) |
| 1306 result.append(underline); | 1251 result.append(underline); |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1523 int EditingStyle::legacyFontSize(Document* document) const { | 1468 int EditingStyle::legacyFontSize(Document* document) const { |
| 1524 const CSSValue* cssValue = | 1469 const CSSValue* cssValue = |
| 1525 m_mutableStyle->getPropertyCSSValue(CSSPropertyFontSize); | 1470 m_mutableStyle->getPropertyCSSValue(CSSPropertyFontSize); |
| 1526 if (!cssValue || | 1471 if (!cssValue || |
| 1527 !(cssValue->isPrimitiveValue() || cssValue->isIdentifierValue())) | 1472 !(cssValue->isPrimitiveValue() || cssValue->isIdentifierValue())) |
| 1528 return 0; | 1473 return 0; |
| 1529 return legacyFontSizeFromCSSValue(document, cssValue, m_isMonospaceFont, | 1474 return legacyFontSizeFromCSSValue(document, cssValue, m_isMonospaceFont, |
| 1530 AlwaysUseLegacyFontSize); | 1475 AlwaysUseLegacyFontSize); |
| 1531 } | 1476 } |
| 1532 | 1477 |
| 1533 EditingStyle* EditingStyle::styleAtSelectionStart( | |
| 1534 const VisibleSelection& selection, | |
| 1535 bool shouldUseBackgroundColorInEffect, | |
| 1536 MutableStylePropertySet* styleToCheck) { | |
| 1537 if (selection.isNone()) | |
| 1538 return nullptr; | |
| 1539 | |
| 1540 Document& document = *selection.start().document(); | |
| 1541 | |
| 1542 DCHECK(!document.needsLayoutTreeUpdate()); | |
| 1543 DocumentLifecycle::DisallowTransitionScope disallowTransition( | |
| 1544 document.lifecycle()); | |
| 1545 | |
| 1546 Position position = adjustedSelectionStartForStyleComputation(selection); | |
| 1547 | |
| 1548 // If the pos is at the end of a text node, then this node is not fully | |
| 1549 // selected. Move it to the next deep equivalent position to avoid removing | |
| 1550 // the style from this node. | |
| 1551 // e.g. if pos was at Position("hello", 5) in <b>hello<div>world</div></b>, we | |
| 1552 // want Position("world", 0) instead. | |
| 1553 // We only do this for range because caret at Position("hello", 5) in | |
| 1554 // <b>hello</b>world should give you font-weight: bold. | |
| 1555 Node* positionNode = position.computeContainerNode(); | |
| 1556 if (selection.isRange() && positionNode && positionNode->isTextNode() && | |
| 1557 position.computeOffsetInContainerNode() == | |
| 1558 positionNode->maxCharacterOffset()) | |
| 1559 position = nextVisuallyDistinctCandidate(position); | |
| 1560 | |
| 1561 Element* element = associatedElementOf(position); | |
| 1562 if (!element) | |
| 1563 return nullptr; | |
| 1564 | |
| 1565 EditingStyle* style = | |
| 1566 EditingStyle::create(element, EditingStyle::AllProperties); | |
| 1567 style->mergeTypingStyle(&element->document()); | |
| 1568 | |
| 1569 // If |element| has <sub> or <sup> ancestor element, apply the corresponding | |
| 1570 // style(vertical-align) to it so that document.queryCommandState() works with | |
| 1571 // the style. See bug http://crbug.com/582225. | |
| 1572 CSSValueID valueID = | |
| 1573 getIdentifierValue(styleToCheck, CSSPropertyVerticalAlign); | |
| 1574 if (valueID == CSSValueSub || valueID == CSSValueSuper) { | |
| 1575 CSSComputedStyleDeclaration* elementStyle = | |
| 1576 CSSComputedStyleDeclaration::create(element); | |
| 1577 // Find the ancestor that has CSSValueSub or CSSValueSuper as the value of | |
| 1578 // CSS vertical-align property. | |
| 1579 if (getIdentifierValue(elementStyle, CSSPropertyVerticalAlign) == | |
| 1580 CSSValueBaseline && | |
| 1581 hasAncestorVerticalAlignStyle(*element, valueID)) | |
| 1582 style->m_mutableStyle->setProperty(CSSPropertyVerticalAlign, valueID); | |
| 1583 } | |
| 1584 | |
| 1585 // If background color is transparent, traverse parent nodes until we hit a | |
| 1586 // different value or document root Also, if the selection is a range, ignore | |
| 1587 // the background color at the start of selection, and find the background | |
| 1588 // color of the common ancestor. | |
| 1589 if (shouldUseBackgroundColorInEffect && | |
| 1590 (selection.isRange() || | |
| 1591 hasTransparentBackgroundColor(style->m_mutableStyle.get()))) { | |
| 1592 const EphemeralRange range(selection.toNormalizedEphemeralRange()); | |
| 1593 if (const CSSValue* value = | |
| 1594 backgroundColorValueInEffect(Range::commonAncestorContainer( | |
| 1595 range.startPosition().computeContainerNode(), | |
| 1596 range.endPosition().computeContainerNode()))) | |
| 1597 style->setProperty(CSSPropertyBackgroundColor, value->cssText()); | |
| 1598 } | |
| 1599 | |
| 1600 return style; | |
| 1601 } | |
| 1602 | |
| 1603 static bool isUnicodeBidiNestedOrMultipleEmbeddings(CSSValueID valueID) { | |
| 1604 return valueID == CSSValueEmbed || valueID == CSSValueBidiOverride || | |
| 1605 valueID == CSSValueWebkitIsolate || | |
| 1606 valueID == CSSValueWebkitIsolateOverride || | |
| 1607 valueID == CSSValueWebkitPlaintext || valueID == CSSValueIsolate || | |
| 1608 valueID == CSSValueIsolateOverride || valueID == CSSValuePlaintext; | |
| 1609 } | |
| 1610 | |
| 1611 WritingDirection EditingStyle::textDirectionForSelection( | |
| 1612 const VisibleSelection& selection, | |
| 1613 EditingStyle* typingStyle, | |
| 1614 bool& hasNestedOrMultipleEmbeddings) { | |
| 1615 hasNestedOrMultipleEmbeddings = true; | |
| 1616 | |
| 1617 if (selection.isNone()) | |
| 1618 return NaturalWritingDirection; | |
| 1619 | |
| 1620 Position position = mostForwardCaretPosition(selection.start()); | |
| 1621 | |
| 1622 Node* node = position.anchorNode(); | |
| 1623 if (!node) | |
| 1624 return NaturalWritingDirection; | |
| 1625 | |
| 1626 Position end; | |
| 1627 if (selection.isRange()) { | |
| 1628 end = mostBackwardCaretPosition(selection.end()); | |
| 1629 | |
| 1630 DCHECK(end.document()); | |
| 1631 const EphemeralRange caretRange(position.parentAnchoredEquivalent(), | |
| 1632 end.parentAnchoredEquivalent()); | |
| 1633 for (Node& n : caretRange.nodes()) { | |
| 1634 if (!n.isStyledElement()) | |
| 1635 continue; | |
| 1636 | |
| 1637 CSSComputedStyleDeclaration* style = | |
| 1638 CSSComputedStyleDeclaration::create(&n); | |
| 1639 const CSSValue* unicodeBidi = | |
| 1640 style->getPropertyCSSValue(CSSPropertyUnicodeBidi); | |
| 1641 if (!unicodeBidi || !unicodeBidi->isIdentifierValue()) | |
| 1642 continue; | |
| 1643 | |
| 1644 CSSValueID unicodeBidiValue = | |
| 1645 toCSSIdentifierValue(unicodeBidi)->getValueID(); | |
| 1646 if (isUnicodeBidiNestedOrMultipleEmbeddings(unicodeBidiValue)) | |
| 1647 return NaturalWritingDirection; | |
| 1648 } | |
| 1649 } | |
| 1650 | |
| 1651 if (selection.isCaret()) { | |
| 1652 WritingDirection direction; | |
| 1653 if (typingStyle && typingStyle->textDirection(direction)) { | |
| 1654 hasNestedOrMultipleEmbeddings = false; | |
| 1655 return direction; | |
| 1656 } | |
| 1657 node = selection.visibleStart().deepEquivalent().anchorNode(); | |
| 1658 } | |
| 1659 DCHECK(node); | |
| 1660 | |
| 1661 // The selection is either a caret with no typing attributes or a range in | |
| 1662 // which no embedding is added, so just use the start position to decide. | |
| 1663 Node* block = enclosingBlock(node); | |
| 1664 WritingDirection foundDirection = NaturalWritingDirection; | |
| 1665 | |
| 1666 for (Node& runner : NodeTraversal::inclusiveAncestorsOf(*node)) { | |
| 1667 if (runner == block) | |
| 1668 break; | |
| 1669 if (!runner.isStyledElement()) | |
| 1670 continue; | |
| 1671 | |
| 1672 Element* element = &toElement(runner); | |
| 1673 CSSComputedStyleDeclaration* style = | |
| 1674 CSSComputedStyleDeclaration::create(element); | |
| 1675 const CSSValue* unicodeBidi = | |
| 1676 style->getPropertyCSSValue(CSSPropertyUnicodeBidi); | |
| 1677 if (!unicodeBidi || !unicodeBidi->isIdentifierValue()) | |
| 1678 continue; | |
| 1679 | |
| 1680 CSSValueID unicodeBidiValue = | |
| 1681 toCSSIdentifierValue(unicodeBidi)->getValueID(); | |
| 1682 if (unicodeBidiValue == CSSValueNormal) | |
| 1683 continue; | |
| 1684 | |
| 1685 if (unicodeBidiValue == CSSValueBidiOverride) | |
| 1686 return NaturalWritingDirection; | |
| 1687 | |
| 1688 DCHECK(isEmbedOrIsolate(unicodeBidiValue)) << unicodeBidiValue; | |
| 1689 const CSSValue* direction = | |
| 1690 style->getPropertyCSSValue(CSSPropertyDirection); | |
| 1691 if (!direction || !direction->isIdentifierValue()) | |
| 1692 continue; | |
| 1693 | |
| 1694 int directionValue = toCSSIdentifierValue(direction)->getValueID(); | |
| 1695 if (directionValue != CSSValueLtr && directionValue != CSSValueRtl) | |
| 1696 continue; | |
| 1697 | |
| 1698 if (foundDirection != NaturalWritingDirection) | |
| 1699 return NaturalWritingDirection; | |
| 1700 | |
| 1701 // In the range case, make sure that the embedding element persists until | |
| 1702 // the end of the range. | |
| 1703 if (selection.isRange() && !end.anchorNode()->isDescendantOf(element)) | |
| 1704 return NaturalWritingDirection; | |
| 1705 | |
| 1706 foundDirection = directionValue == CSSValueLtr | |
| 1707 ? LeftToRightWritingDirection | |
| 1708 : RightToLeftWritingDirection; | |
| 1709 } | |
| 1710 hasNestedOrMultipleEmbeddings = false; | |
| 1711 return foundDirection; | |
| 1712 } | |
| 1713 | |
| 1714 DEFINE_TRACE(EditingStyle) { | 1478 DEFINE_TRACE(EditingStyle) { |
| 1715 visitor->trace(m_mutableStyle); | 1479 visitor->trace(m_mutableStyle); |
| 1716 } | 1480 } |
| 1717 | 1481 |
| 1718 static void reconcileTextDecorationProperties(MutableStylePropertySet* style) { | 1482 static void reconcileTextDecorationProperties(MutableStylePropertySet* style) { |
| 1719 const CSSValue* textDecorationsInEffect = | 1483 const CSSValue* textDecorationsInEffect = |
| 1720 style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect); | 1484 style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect); |
| 1721 const CSSValue* textDecoration = | 1485 const CSSValue* textDecoration = |
| 1722 style->getPropertyCSSValue(textDecorationPropertyForEditing()); | 1486 style->getPropertyCSSValue(textDecorationPropertyForEditing()); |
| 1723 // "LayoutTests/editing/execCommand/insert-list-and-strikethrough.html" makes | 1487 // "LayoutTests/editing/execCommand/insert-list-and-strikethrough.html" makes |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2014 if (value->isIdentifierValue()) { | 1778 if (value->isIdentifierValue()) { |
| 2015 const CSSIdentifierValue& identifierValue = toCSSIdentifierValue(*value); | 1779 const CSSIdentifierValue& identifierValue = toCSSIdentifierValue(*value); |
| 2016 if (CSSValueXSmall <= identifierValue.getValueID() && | 1780 if (CSSValueXSmall <= identifierValue.getValueID() && |
| 2017 identifierValue.getValueID() <= CSSValueWebkitXxxLarge) | 1781 identifierValue.getValueID() <= CSSValueWebkitXxxLarge) |
| 2018 return identifierValue.getValueID() - CSSValueXSmall + 1; | 1782 return identifierValue.getValueID() - CSSValueXSmall + 1; |
| 2019 } | 1783 } |
| 2020 | 1784 |
| 2021 return 0; | 1785 return 0; |
| 2022 } | 1786 } |
| 2023 | 1787 |
| 2024 bool isTransparentColorValue(const CSSValue* cssValue) { | |
| 2025 if (!cssValue) | |
| 2026 return true; | |
| 2027 if (cssValue->isColorValue()) | |
| 2028 return !toCSSColorValue(cssValue)->value().alpha(); | |
| 2029 if (!cssValue->isIdentifierValue()) | |
| 2030 return false; | |
| 2031 return toCSSIdentifierValue(cssValue)->getValueID() == CSSValueTransparent; | |
| 2032 } | |
| 2033 | |
| 2034 bool hasTransparentBackgroundColor(CSSStyleDeclaration* style) { | |
| 2035 const CSSValue* cssValue = | |
| 2036 style->getPropertyCSSValueInternal(CSSPropertyBackgroundColor); | |
| 2037 return isTransparentColorValue(cssValue); | |
| 2038 } | |
| 2039 | |
| 2040 bool hasTransparentBackgroundColor(StylePropertySet* style) { | |
| 2041 const CSSValue* cssValue = | |
| 2042 style->getPropertyCSSValue(CSSPropertyBackgroundColor); | |
| 2043 return isTransparentColorValue(cssValue); | |
| 2044 } | |
| 2045 | |
| 2046 const CSSValue* backgroundColorValueInEffect(Node* node) { | |
| 2047 for (Node* ancestor = node; ancestor; ancestor = ancestor->parentNode()) { | |
| 2048 CSSComputedStyleDeclaration* ancestorStyle = | |
| 2049 CSSComputedStyleDeclaration::create(ancestor); | |
| 2050 if (!hasTransparentBackgroundColor(ancestorStyle)) | |
| 2051 return ancestorStyle->getPropertyCSSValue(CSSPropertyBackgroundColor); | |
| 2052 } | |
| 2053 return nullptr; | |
| 2054 } | |
| 2055 | |
| 2056 } // namespace blink | 1788 } // namespace blink |
| OLD | NEW |