OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "config.h" |
| 6 #include "core/css/resolver/CascadedValues.h" |
| 7 |
| 8 #include "core/css/CSSValuePool.h" |
| 9 #include "core/css/StylePropertySet.h" |
| 10 #include "core/css/resolver/MatchResult.h" |
| 11 #include "core/css/resolver/StyleBuilder.h" |
| 12 #include "core/css/resolver/StyleResolver.h" |
| 13 #include "core/css/resolver/StyleResolverState.h" |
| 14 #include <algorithm> |
| 15 |
| 16 namespace blink { |
| 17 |
| 18 // We want properties in their prefixed and non-prefixed variants to cascade |
| 19 // together, so we map them to the same property before adding to the cascade. |
| 20 static CSSPropertyID resolveProperty(CSSPropertyID property, TextDirection direc
tion, WritingMode writingMode) |
| 21 { |
| 22 switch (property) { |
| 23 case CSSPropertyWebkitBorderEndColor: |
| 24 case CSSPropertyWebkitBorderBeforeStyle: |
| 25 case CSSPropertyWebkitBorderEndStyle: |
| 26 case CSSPropertyWebkitPaddingStart: |
| 27 case CSSPropertyWebkitBorderStartWidth: |
| 28 case CSSPropertyWebkitMaxLogicalWidth: |
| 29 case CSSPropertyWebkitLogicalHeight: |
| 30 case CSSPropertyWebkitMinLogicalWidth: |
| 31 case CSSPropertyWebkitBorderBeforeWidth: |
| 32 case CSSPropertyWebkitPaddingBefore: |
| 33 case CSSPropertyWebkitBorderBeforeColor: |
| 34 case CSSPropertyWebkitMarginEnd: |
| 35 case CSSPropertyWebkitBorderAfterWidth: |
| 36 case CSSPropertyWebkitMinLogicalHeight: |
| 37 case CSSPropertyWebkitBorderEndWidth: |
| 38 case CSSPropertyWebkitPaddingEnd: |
| 39 case CSSPropertyWebkitLogicalWidth: |
| 40 case CSSPropertyWebkitBorderAfterColor: |
| 41 case CSSPropertyWebkitMaxLogicalHeight: |
| 42 case CSSPropertyWebkitBorderStartColor: |
| 43 case CSSPropertyWebkitBorderAfterStyle: |
| 44 case CSSPropertyWebkitPaddingAfter: |
| 45 case CSSPropertyWebkitBorderStartStyle: |
| 46 case CSSPropertyWebkitMarginBefore: |
| 47 case CSSPropertyWebkitMarginStart: |
| 48 case CSSPropertyWebkitMarginAfter: |
| 49 return CSSProperty::resolveDirectionAwareProperty(property, direction, w
ritingMode); |
| 50 case CSSPropertyWebkitBackfaceVisibility: |
| 51 return CSSPropertyBackfaceVisibility; |
| 52 case CSSPropertyWebkitBackgroundClip: |
| 53 return CSSPropertyBackgroundClip; |
| 54 case CSSPropertyWebkitBackgroundOrigin: |
| 55 return CSSPropertyBackgroundOrigin; |
| 56 case CSSPropertyWebkitBackgroundSize: |
| 57 return CSSPropertyBackgroundSize; |
| 58 case CSSPropertyWebkitBoxShadow: |
| 59 return CSSPropertyBoxShadow; |
| 60 case CSSPropertyWebkitTransform: |
| 61 return CSSPropertyTransform; |
| 62 case CSSPropertyWebkitTransformStyle: |
| 63 return CSSPropertyTransformStyle; |
| 64 case CSSPropertyWebkitPerspective: |
| 65 return CSSPropertyPerspective; |
| 66 case CSSPropertyWebkitPerspectiveOrigin: |
| 67 return CSSPropertyPerspectiveOrigin; |
| 68 // Used by editing when the css3 text decorations flag is off |
| 69 case CSSPropertyTextDecoration: |
| 70 ASSERT(!RuntimeEnabledFeatures::css3TextDecorationsEnabled()); |
| 71 return CSSPropertyTextDecorationLine; |
| 72 // As per css3-text, word-wrap is an alias for overflow-wrap |
| 73 case CSSPropertyWordWrap: |
| 74 return CSSPropertyOverflowWrap; |
| 75 default: |
| 76 return property; |
| 77 } |
| 78 } |
| 79 |
| 80 CascadedValues::CascadedValues(StyleResolverState& state, const MatchResult& mat
chResult, bool onlyAddUARules) |
| 81 : m_state(state) |
| 82 { |
| 83 memset(m_values, 0, sizeof(m_values)); |
| 84 if (m_state.style()->insideLink()) |
| 85 memset(m_visitedLinkValues, 0, sizeof(m_visitedLinkValues)); |
| 86 |
| 87 // The MatchResult has rules in UA - User - Author order, although we only |
| 88 // use user rules for callback selectors. |
| 89 addMatchResult(matchResult, CSSPropertyDirection, CSSPropertyWebkitWritingMo
de); |
| 90 applyValues(CSSPropertyDirection, CSSPropertyWebkitWritingMode); |
| 91 m_direction = state.style()->direction(); |
| 92 m_writingMode = state.style()->writingMode(); |
| 93 |
| 94 COMPILE_ASSERT(CSSPropertyColor == CSSPropertyWebkitWritingMode + 1, CSS_col
or_is_after_super_high_priority); |
| 95 if (onlyAddUARules) { |
| 96 addMatchResultRange(matchResult, false, matchResult.ranges.firstUARule,
matchResult.ranges.lastUARule, CSSPropertyColor, convertToCSSPropertyID(lastCSSP
roperty)); |
| 97 } else { |
| 98 addMatchResult(matchResult, CSSPropertyColor, convertToCSSPropertyID(las
tCSSProperty)); |
| 99 } |
| 100 |
| 101 std::sort(setProperties.begin(), setProperties.end()); |
| 102 std::sort(setVisitedProperties.begin(), setVisitedProperties.end()); |
| 103 } |
| 104 |
| 105 void CascadedValues::addMatchResult(const MatchResult& matchResult, CSSPropertyI
D firstId, CSSPropertyID lastId) |
| 106 { |
| 107 addMatchResultRange(matchResult, false, 0, matchResult.matchedProperties.siz
e() - 1, firstId, lastId); |
| 108 addMatchResultRange(matchResult, true, matchResult.ranges.firstAuthorRule, m
atchResult.ranges.lastAuthorRule, firstId, lastId); |
| 109 addMatchResultRange(matchResult, true, matchResult.ranges.firstUARule, match
Result.ranges.lastUARule, firstId, lastId); |
| 110 } |
| 111 |
| 112 void CascadedValues::addMatchResultRange(const MatchResult& matchResult, bool is
Important, int firstIndex, int lastIndex, CSSPropertyID firstId, CSSPropertyID l
astId) |
| 113 { |
| 114 if (firstIndex == -1) |
| 115 return; |
| 116 |
| 117 for (int i = firstIndex; i <= lastIndex; ++i) { |
| 118 const MatchedProperties& matchedProperties = matchResult.matchedProperti
es[i]; |
| 119 SelectorChecker::LinkMatchMask linkMatchType = SelectorChecker::MatchLin
k; |
| 120 if (m_state.style()->insideLink()) |
| 121 linkMatchType = static_cast<SelectorChecker::LinkMatchMask>(matchedP
roperties.m_types.linkMatchType); |
| 122 addStylePropertySet(matchedProperties.properties.get(), matchResult.matc
hedRules[i], isImportant, firstId, lastId, static_cast<PropertyWhitelistType>(ma
tchedProperties.m_types.whitelistType), linkMatchType); |
| 123 } |
| 124 } |
| 125 |
| 126 void CascadedValues::addStylePropertySet(const StylePropertySet* properties, con
st StyleRule* rule, bool isImportant, CSSPropertyID first, CSSPropertyID last, P
ropertyWhitelistType propertyWhitelistType, SelectorChecker::LinkMatchMask linkM
atchType) |
| 127 { |
| 128 unsigned propertyCount = properties->propertyCount(); |
| 129 for (unsigned i = 0; i < propertyCount; ++i) { |
| 130 StylePropertySet::PropertyReference current = properties->propertyAt(i); |
| 131 if (isImportant != current.isImportant()) |
| 132 continue; |
| 133 |
| 134 CSSPropertyID property = current.id(); |
| 135 if (property < first || property > last) |
| 136 continue; |
| 137 |
| 138 // FIXME: We should check the whitelist, otherwise we might run into |
| 139 // problems with e.g. foo:first-letter { all: inherit; } |
| 140 if (property == CSSPropertyAll) { |
| 141 addAllProperty(current.value(), linkMatchType); |
| 142 continue; |
| 143 } |
| 144 |
| 145 if (propertyWhitelistType == PropertyWhitelistCue && !StyleResolver::isV
alidCueStyleProperty(property)) |
| 146 continue; |
| 147 if (propertyWhitelistType == PropertyWhitelistFirstLetter && !StyleResol
ver::isValidFirstLetterStyleProperty(property)) |
| 148 continue; |
| 149 addValue(current.id(), current.value(), rule, linkMatchType); |
| 150 } |
| 151 } |
| 152 |
| 153 void CascadedValues::addValue(CSSPropertyID property, CSSValue* value, const Sty
leRule* rule, SelectorChecker::LinkMatchMask linkMatchType) |
| 154 { |
| 155 property = resolveProperty(property, m_direction, m_writingMode); |
| 156 |
| 157 if (property == CSSPropertyInternalCallback) { |
| 158 ASSERT(value->isPrimitiveValue() && toCSSPrimitiveValue(value)->getValue
ID() == CSSValueInternalPresence); |
| 159 m_state.style()->addCallbackSelector(rule->selectorList().selectorsText(
)); |
| 160 return; |
| 161 } |
| 162 |
| 163 // Shorthands that are not expanded in the parser need special handling here
. |
| 164 // The shorthand property occurs earlier in CSSPropertyNames.in than its |
| 165 // longhands so we can cascade properly. If a longhand value is explicitly |
| 166 // set, with higher priority than the shorthand, then the value computed |
| 167 // from the shorthand will be overriden. |
| 168 |
| 169 // FIXME: font should always be expanded by the parser; crbug.com/353932 |
| 170 if (property == CSSPropertyFont) { |
| 171 clearCascadedValue(CSSPropertyLineHeight); |
| 172 clearCascadedValue(CSSPropertyFontStyle); |
| 173 clearCascadedValue(CSSPropertyFontFamily); |
| 174 clearCascadedValue(CSSPropertyFontVariant); |
| 175 clearCascadedValue(CSSPropertyFontWeight); |
| 176 clearCascadedValue(CSSPropertyFontStretch); |
| 177 clearCascadedValue(CSSPropertyFontSize); |
| 178 } |
| 179 |
| 180 // -webkit-border-image sometimes also sets border-*-width, but properly |
| 181 // cascading this requires too much effort |
| 182 if (property == CSSPropertyWebkitBorderImage) { |
| 183 clearCascadedValue(CSSPropertyBorderImageSource); |
| 184 clearCascadedValue(CSSPropertyBorderImageSlice); |
| 185 clearCascadedValue(CSSPropertyBorderImageWidth); |
| 186 clearCascadedValue(CSSPropertyBorderImageOutset); |
| 187 clearCascadedValue(CSSPropertyBorderImageRepeat); |
| 188 } |
| 189 |
| 190 if (linkMatchType & SelectorChecker::MatchLink) |
| 191 setCascadedValue(property, value); |
| 192 if (linkMatchType & SelectorChecker::MatchVisited) |
| 193 setCascadedVisitedLinkValue(property, value); |
| 194 } |
| 195 |
| 196 void CascadedValues::addAllProperty(CSSValue* value, SelectorChecker::LinkMatchM
ask linkMatchType) |
| 197 { |
| 198 if (!value->isInitialValue() && !value->isInheritedValue()) { |
| 199 ASSERT(value->isPrimitiveValue() && toCSSPrimitiveValue(value)->getValue
ID() == CSSValueUnset); |
| 200 value = nullptr; |
| 201 } |
| 202 |
| 203 for (int i = firstCSSProperty; i <= lastCSSProperty; ++i) { |
| 204 CSSPropertyID property = convertToCSSPropertyID(i); |
| 205 if (CSSProperty::isAffectedByAllProperty(property)) |
| 206 addValue(property, value, nullptr, linkMatchType); |
| 207 } |
| 208 } |
| 209 |
| 210 void CascadedValues::setCascadedValue(CSSPropertyID id, CSSValue* value) |
| 211 { |
| 212 if (!m_values[id - firstCSSProperty]) |
| 213 setProperties.append(id); |
| 214 m_values[id - firstCSSProperty] = value; |
| 215 } |
| 216 |
| 217 void CascadedValues::setCascadedVisitedLinkValue(CSSPropertyID id, CSSValue* val
ue) |
| 218 { |
| 219 ASSERT(m_state.style()->insideLink()); |
| 220 if (!m_visitedLinkValues[id - firstCSSProperty]) |
| 221 setVisitedProperties.append(id); |
| 222 m_visitedLinkValues[id - firstCSSProperty] = value; |
| 223 } |
| 224 |
| 225 void CascadedValues::applyValues(CSSPropertyID first, CSSPropertyID last, bool i
nheritedOnly) |
| 226 { |
| 227 for (size_t i = 0; i < setProperties.size(); i++) { |
| 228 CSSPropertyID property = setProperties[i]; |
| 229 if (property < first || property > last) |
| 230 continue; |
| 231 // We might not have a value due to the shorthand special-cases in addVa
lue |
| 232 if (!cascadedValue(property)) |
| 233 continue; |
| 234 if (!inheritedOnly || CSSProperty::isInheritedProperty(property)) |
| 235 StyleBuilder::applyProperty(property, m_state, cascadedValue(propert
y)); |
| 236 } |
| 237 |
| 238 if (!m_state.style()->insideLink()) |
| 239 return; |
| 240 |
| 241 m_state.setApplyPropertyToRegularStyle(false); |
| 242 m_state.setApplyPropertyToVisitedLinkStyle(true); |
| 243 for (size_t i = 0; i < setVisitedProperties.size(); i++) { |
| 244 CSSPropertyID property = setVisitedProperties[i]; |
| 245 if (property < first || property > last) |
| 246 continue; |
| 247 ASSERT(cascadedVisitedLinkValue(property)); |
| 248 if (!inheritedOnly || CSSProperty::isInheritedProperty(property)) |
| 249 StyleBuilder::applyProperty(property, m_state, cascadedVisitedLinkVa
lue(property)); |
| 250 } |
| 251 m_state.setApplyPropertyToRegularStyle(true); |
| 252 m_state.setApplyPropertyToVisitedLinkStyle(false); |
| 253 } |
| 254 |
| 255 |
| 256 } // namespace blink |
OLD | NEW |