Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 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 "core/animation/CSSSizeListInterpolationType.h" | |
| 6 | |
| 7 #include "core/animation/CSSLengthInterpolationType.h" | |
| 8 #include "core/animation/ListInterpolationFunctions.h" | |
| 9 #include "core/animation/SizeListPropertyFunctions.h" | |
| 10 #include "core/css/CSSValueList.h" | |
| 11 #include "core/css/CSSValuePair.h" | |
| 12 #include "core/css/resolver/StyleResolverState.h" | |
|
suzyh_UTC10 (ex-contributor)
2016/08/26 04:14:34
Consider also explicitly including the headers wer
alancutter (OOO until 2018)
2016/08/26 13:31:48
I think the policy is only to not include things t
| |
| 13 | |
| 14 namespace blink { | |
| 15 | |
| 16 class CSSSizeNonInterpolableValue : public NonInterpolableValue { | |
| 17 public: | |
| 18 static PassRefPtr<CSSSizeNonInterpolableValue> create(CSSValueID keyword) | |
| 19 { | |
| 20 return adoptRef(new CSSSizeNonInterpolableValue(keyword)); | |
| 21 } | |
| 22 | |
| 23 static PassRefPtr<CSSSizeNonInterpolableValue> create(PassRefPtr<NonInterpol ableValue> lengthNonInterpolableValue) | |
| 24 { | |
| 25 return adoptRef(new CSSSizeNonInterpolableValue(lengthNonInterpolableVal ue)); | |
| 26 } | |
| 27 | |
| 28 bool isKeyword() const { return m_keyword != CSSValueInvalid; } | |
| 29 CSSValueID keyword() const { DCHECK(isKeyword()); return m_keyword; } | |
| 30 | |
| 31 const NonInterpolableValue* lengthNonInterpolableValue() const { DCHECK(!isK eyword()); return m_lengthNonInterpolableValue.get(); } | |
| 32 RefPtr<NonInterpolableValue>& lengthNonInterpolableValue() { DCHECK(!isKeywo rd()); return m_lengthNonInterpolableValue; } | |
| 33 | |
| 34 DECLARE_NON_INTERPOLABLE_VALUE_TYPE(); | |
| 35 | |
| 36 private: | |
| 37 CSSSizeNonInterpolableValue(CSSValueID keyword) | |
|
suzyh_UTC10 (ex-contributor)
2016/08/26 04:14:34
Is there a reason to have two constructors mirrori
alancutter (OOO until 2018)
2016/08/26 13:31:48
I think it's better for assertions to be in constr
suzyh_UTC10 (ex-contributor)
2016/08/30 08:01:07
I think this is a style thing, and I am undecided.
alancutter (OOO until 2018)
2016/09/05 07:44:27
There is precedence for checking in the constructo
| |
| 38 : m_keyword(keyword) | |
| 39 , m_lengthNonInterpolableValue(nullptr) | |
| 40 { | |
| 41 DCHECK_NE(keyword, CSSValueInvalid); | |
| 42 } | |
| 43 | |
| 44 CSSSizeNonInterpolableValue(PassRefPtr<NonInterpolableValue> lengthNonInterp olableValue) | |
| 45 : m_keyword(CSSValueInvalid) | |
| 46 , m_lengthNonInterpolableValue(lengthNonInterpolableValue) | |
| 47 { } | |
| 48 | |
| 49 CSSValueID m_keyword; | |
| 50 RefPtr<NonInterpolableValue> m_lengthNonInterpolableValue; | |
| 51 }; | |
| 52 | |
| 53 DEFINE_NON_INTERPOLABLE_VALUE_TYPE(CSSSizeNonInterpolableValue); | |
| 54 DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(CSSSizeNonInterpolableValue); | |
| 55 | |
| 56 static bool sizesAreCompatible(const NonInterpolableValue* a, const NonInterpola bleValue* b) | |
|
suzyh_UTC10 (ex-contributor)
2016/08/26 04:14:34
Does this function belong in a separate helper lib
alancutter (OOO until 2018)
2016/08/26 13:31:48
Moved into SizeInterpolationFunctions.
| |
| 57 { | |
| 58 const auto& sizeA = toCSSSizeNonInterpolableValue(*a); | |
| 59 const auto& sizeB = toCSSSizeNonInterpolableValue(*b); | |
| 60 if (sizeA.isKeyword() != sizeB.isKeyword()) | |
| 61 return false; | |
| 62 if (sizeA.isKeyword()) | |
| 63 return sizeA.keyword() == sizeB.keyword(); | |
| 64 return true; | |
| 65 } | |
| 66 | |
| 67 class UnderlyingSizeListChecker : public InterpolationType::ConversionChecker { | |
| 68 public: | |
| 69 ~UnderlyingSizeListChecker() final {} | |
| 70 | |
| 71 static std::unique_ptr<UnderlyingSizeListChecker> create(const NonInterpolab leList& underlyingList) | |
| 72 { | |
| 73 return wrapUnique(new UnderlyingSizeListChecker(underlyingList)); | |
| 74 } | |
| 75 | |
| 76 private: | |
| 77 UnderlyingSizeListChecker(const NonInterpolableList& underlyingList) | |
| 78 : m_underlyingList(&underlyingList) | |
| 79 { } | |
| 80 | |
| 81 bool isValid(const InterpolationEnvironment&, const InterpolationValue& unde rlying) const final | |
| 82 { | |
| 83 const auto& underlyingList = toNonInterpolableList(*underlying.nonInterp olableValue); | |
| 84 size_t underlyingLength = underlyingList.length(); | |
| 85 if (underlyingLength != m_underlyingList->length()) | |
| 86 return false; | |
| 87 for (size_t i = 0; i < underlyingLength; i++) { | |
| 88 if (!sizesAreCompatible(underlyingList.get(i), m_underlyingList->get (i))) | |
| 89 return false; | |
| 90 } | |
| 91 return true; | |
| 92 } | |
| 93 | |
| 94 RefPtr<const NonInterpolableList> m_underlyingList; | |
| 95 }; | |
| 96 | |
| 97 class InheritedSizeListChecker : public InterpolationType::ConversionChecker { | |
| 98 public: | |
| 99 ~InheritedSizeListChecker() final {} | |
| 100 | |
| 101 static std::unique_ptr<InheritedSizeListChecker> create(CSSPropertyID proper ty, const SizeList& inheritedSizeList) | |
| 102 { | |
| 103 return wrapUnique(new InheritedSizeListChecker(property, inheritedSizeLi st)); | |
| 104 } | |
| 105 | |
| 106 private: | |
| 107 InheritedSizeListChecker(CSSPropertyID property, const SizeList& inheritedSi zeList) | |
| 108 : m_property(property) | |
| 109 , m_inheritedSizeList(inheritedSizeList) | |
| 110 { } | |
| 111 | |
| 112 bool isValid(const InterpolationEnvironment& environment, const Interpolatio nValue&) const final | |
| 113 { | |
| 114 return m_inheritedSizeList == SizeListPropertyFunctions::getSizeList(m_p roperty, *environment.state().parentStyle()); | |
| 115 } | |
| 116 | |
| 117 CSSPropertyID m_property; | |
| 118 SizeList m_inheritedSizeList; | |
| 119 }; | |
| 120 | |
| 121 InterpolationValue convertKeyword(CSSValueID keyword) | |
| 122 { | |
| 123 return InterpolationValue(InterpolableList::create(0), CSSSizeNonInterpolabl eValue::create(keyword)); | |
| 124 } | |
| 125 | |
| 126 InterpolationValue wrapConvertedLength(InterpolationValue&& convertedLength) | |
| 127 { | |
| 128 if (!convertedLength) | |
| 129 return nullptr; | |
| 130 return InterpolationValue( | |
| 131 std::move(convertedLength.interpolableValue), | |
| 132 CSSSizeNonInterpolableValue::create(convertedLength.nonInterpolableValue .release())); | |
| 133 } | |
| 134 | |
| 135 InterpolationValue convertSizeList(const SizeList& sizeList, float zoom) | |
| 136 { | |
| 137 // Flatten pairs of width/height into individual items, even for contain and cover. | |
| 138 return ListInterpolationFunctions::createList(sizeList.size() * 2, [&sizeLis t, zoom](size_t index) -> InterpolationValue { | |
| 139 const FillSize& size = sizeList[index / 2]; | |
| 140 switch (size.type) { | |
| 141 case SizeLength: { | |
| 142 const Length& side = index % 2 == 0 ? size.size.width() : size.size. height(); | |
| 143 if (side.isAuto()) | |
| 144 return convertKeyword(CSSValueAuto); | |
| 145 return wrapConvertedLength(CSSLengthInterpolationType::maybeConvertL ength(side, zoom)); | |
| 146 } | |
| 147 case Contain: | |
| 148 return convertKeyword(CSSValueContain); | |
| 149 case Cover: | |
| 150 return convertKeyword(CSSValueCover); | |
| 151 case SizeNone: | |
| 152 default: | |
| 153 NOTREACHED(); | |
| 154 return nullptr; | |
| 155 } | |
| 156 }); | |
| 157 } | |
| 158 | |
| 159 InterpolationValue CSSSizeListInterpolationType::maybeConvertNeutral(const Inter polationValue& underlying, ConversionCheckers& conversionCheckers) const | |
| 160 { | |
| 161 const auto& underlyingList = toNonInterpolableList(*underlying.nonInterpolab leValue); | |
| 162 conversionCheckers.append(UnderlyingSizeListChecker::create(underlyingList)) ; | |
| 163 return ListInterpolationFunctions::createList(underlyingList.length(), [&und erlyingList](size_t index) { | |
| 164 // const_cast to take a ref. | |
| 165 auto& item = toCSSSizeNonInterpolableValue(const_cast<NonInterpolableVal ue&>(*underlyingList.get(index))); | |
| 166 if (item.isKeyword()) | |
| 167 return InterpolationValue(InterpolableList::create(0), &item); | |
| 168 return InterpolationValue(CSSLengthInterpolationType::createNeutralInter polableValue(), &item); | |
| 169 }); | |
| 170 } | |
| 171 | |
| 172 InterpolationValue CSSSizeListInterpolationType::maybeConvertInitial(const Style ResolverState&, ConversionCheckers&) const | |
| 173 { | |
| 174 return convertSizeList(SizeListPropertyFunctions::getInitialSizeList(cssProp erty()), 1); | |
| 175 } | |
| 176 | |
| 177 InterpolationValue CSSSizeListInterpolationType::maybeConvertInherit(const Style ResolverState& state, ConversionCheckers& conversionCheckers) const | |
| 178 { | |
| 179 SizeList inheritedSizeList = SizeListPropertyFunctions::getSizeList(cssPrope rty(), *state.parentStyle()); | |
| 180 conversionCheckers.append(InheritedSizeListChecker::create(cssProperty(), in heritedSizeList)); | |
| 181 return convertSizeList(inheritedSizeList, state.style()->effectiveZoom()); | |
| 182 } | |
| 183 | |
| 184 InterpolationValue CSSSizeListInterpolationType::maybeConvertValue(const CSSValu e& value, const StyleResolverState& state, ConversionCheckers&) const | |
| 185 { | |
| 186 // CSSPropertyParser doesn't put single values in lists so wrap it up in a t emporary list. | |
| 187 const CSSValueList* list = nullptr; | |
| 188 if (!value.isBaseValueList()) { | |
| 189 CSSValueList* tempList = CSSValueList::createCommaSeparated(); | |
| 190 tempList->append(value); | |
| 191 list = tempList; | |
| 192 } else { | |
| 193 list = toCSSValueList(&value); | |
| 194 } | |
| 195 | |
| 196 // Flatten pairs of width/height into individual items, even for contain and cover. | |
| 197 return ListInterpolationFunctions::createList(list->length() * 2, [list](siz e_t index) -> InterpolationValue { | |
|
suzyh_UTC10 (ex-contributor)
2016/08/26 04:14:34
I think I would prefer to see a separate library o
alancutter (OOO until 2018)
2016/08/26 13:31:48
This is a lambda due to the closure of list (and t
| |
| 198 const CSSValue& item = list->item(index / 2); | |
| 199 if (item.isValuePair()) { | |
| 200 const CSSValuePair& pair = toCSSValuePair(item); | |
| 201 const CSSValue& side = index % 2 == 0 ? pair.first() : pair.second() ; | |
| 202 if (side.isPrimitiveValue() && toCSSPrimitiveValue(side).getValueID( ) == CSSValueAuto) | |
| 203 return convertKeyword(CSSValueAuto); | |
| 204 return wrapConvertedLength(CSSLengthInterpolationType::maybeConvertC SSValue(side)); | |
| 205 } | |
| 206 if (!item.isPrimitiveValue()) | |
| 207 return nullptr; | |
| 208 CSSValueID keyword = toCSSPrimitiveValue(item).getValueID(); | |
| 209 if (keyword) | |
| 210 return convertKeyword(keyword); | |
| 211 // A single length is equivalent to "<length> auto". | |
| 212 if (index % 2 == 0) | |
| 213 return wrapConvertedLength(CSSLengthInterpolationType::maybeConvertC SSValue(item)); | |
| 214 return convertKeyword(CSSValueAuto); | |
| 215 }); | |
| 216 } | |
| 217 | |
| 218 static PairwiseInterpolationValue maybeMergeSingleSizes(InterpolationValue&& sta rt, InterpolationValue&& end) | |
| 219 { | |
| 220 if (!sizesAreCompatible(start.nonInterpolableValue.get(), end.nonInterpolabl eValue.get())) | |
| 221 return nullptr; | |
| 222 return PairwiseInterpolationValue( | |
| 223 std::move(start.interpolableValue), | |
| 224 std::move(end.interpolableValue), | |
| 225 start.nonInterpolableValue.release()); | |
| 226 } | |
| 227 | |
| 228 PairwiseInterpolationValue CSSSizeListInterpolationType::maybeMergeSingles(Inter polationValue&& start, InterpolationValue&& end) const | |
| 229 { | |
| 230 return ListInterpolationFunctions::maybeMergeSingles(std::move(start), std:: move(end), maybeMergeSingleSizes); | |
| 231 } | |
| 232 | |
| 233 InterpolationValue CSSSizeListInterpolationType::maybeConvertUnderlyingValue(con st InterpolationEnvironment& environment) const | |
| 234 { | |
| 235 const ComputedStyle& style = *environment.state().style(); | |
| 236 return convertSizeList(SizeListPropertyFunctions::getSizeList(cssProperty(), style), style.effectiveZoom()); | |
| 237 } | |
| 238 | |
| 239 void compositeSizes(std::unique_ptr<InterpolableValue>& underlyingInterpolableVa lue, RefPtr<NonInterpolableValue>& underlyingNonInterpolableValue, double underl yingFraction, const InterpolableValue& interpolableValue, const NonInterpolableV alue* nonInterpolableValue) | |
| 240 { | |
| 241 const auto& sizeNonInterpolableValue = toCSSSizeNonInterpolableValue(*nonInt erpolableValue); | |
| 242 if (sizeNonInterpolableValue.isKeyword()) | |
| 243 return; | |
| 244 auto& underlyingSizeNonInterpolableValue = toCSSSizeNonInterpolableValue(*un derlyingNonInterpolableValue); | |
| 245 CSSLengthInterpolationType::composite( | |
| 246 underlyingInterpolableValue, | |
| 247 underlyingSizeNonInterpolableValue.lengthNonInterpolableValue(), | |
| 248 underlyingFraction, | |
| 249 interpolableValue, | |
| 250 sizeNonInterpolableValue.lengthNonInterpolableValue()); | |
| 251 } | |
| 252 | |
| 253 void CSSSizeListInterpolationType::composite(UnderlyingValueOwner& underlyingVal ueOwner, double underlyingFraction, const InterpolationValue& value, double inte rpolationFraction) const | |
| 254 { | |
| 255 ListInterpolationFunctions::composite(underlyingValueOwner, underlyingFracti on, *this, value, sizesAreCompatible, compositeSizes); | |
| 256 } | |
| 257 | |
| 258 Length createLength(const InterpolableValue& interpolableValue, const CSSSizeNon InterpolableValue& nonInterpolableValue, const CSSToLengthConversionData& conver sionData) | |
| 259 { | |
| 260 if (nonInterpolableValue.isKeyword()) { | |
| 261 DCHECK_EQ(nonInterpolableValue.keyword(), CSSValueAuto); | |
| 262 return Length(Auto); | |
| 263 } | |
| 264 return CSSLengthInterpolationType::resolveInterpolableLength(interpolableVal ue, nonInterpolableValue.lengthNonInterpolableValue(), conversionData, ValueRang eNonNegative); | |
|
suzyh_UTC10 (ex-contributor)
2016/08/26 04:14:34
As a reader of this code it is surprising to have
alancutter (OOO until 2018)
2016/08/26 13:31:48
Agreed, CSSLengthInterpolationType should have its
| |
| 265 } | |
| 266 | |
| 267 FillSize createFillSize(const InterpolableValue& interpolableValueA, const NonIn terpolableValue* nonInterpolableValueA, const InterpolableValue& interpolableVal ueB, const NonInterpolableValue* nonInterpolableValueB, const CSSToLengthConvers ionData& conversionData) | |
| 268 { | |
| 269 const auto& sideA = toCSSSizeNonInterpolableValue(*nonInterpolableValueA); | |
| 270 const auto& sideB = toCSSSizeNonInterpolableValue(*nonInterpolableValueB); | |
| 271 if (sideA.isKeyword()) { | |
| 272 switch (sideA.keyword()) { | |
| 273 case CSSValueCover: | |
| 274 DCHECK_EQ(sideA.keyword(), sideB.keyword()); | |
| 275 return FillSize(Cover, LengthSize()); | |
| 276 case CSSValueContain: | |
| 277 DCHECK_EQ(sideA.keyword(), sideB.keyword()); | |
| 278 return FillSize(Contain, LengthSize()); | |
| 279 case CSSValueAuto: | |
| 280 break; | |
| 281 default: | |
| 282 NOTREACHED(); | |
| 283 break; | |
| 284 } | |
| 285 } | |
| 286 return FillSize(SizeLength, LengthSize( | |
| 287 createLength(interpolableValueA, sideA, conversionData), | |
| 288 createLength(interpolableValueB, sideB, conversionData))); | |
| 289 } | |
| 290 | |
| 291 void CSSSizeListInterpolationType::apply(const InterpolableValue& interpolableVa lue, const NonInterpolableValue* nonInterpolableValue, InterpolationEnvironment& environment) const | |
| 292 { | |
| 293 const auto& interpolableList = toInterpolableList(interpolableValue); | |
| 294 const auto& nonInterpolableList = toNonInterpolableList(*nonInterpolableValu e); | |
| 295 size_t length = interpolableList.length(); | |
| 296 DCHECK_EQ(length, nonInterpolableList.length()); | |
| 297 DCHECK_EQ(length % 2, 0ul); | |
| 298 size_t sizeListLength = length / 2; | |
| 299 SizeList sizeList(sizeListLength); | |
| 300 for (size_t i = 0; i < sizeListLength; i++) { | |
| 301 sizeList[i] = createFillSize( | |
| 302 *interpolableList.get(i * 2), | |
| 303 nonInterpolableList.get(i * 2), | |
| 304 *interpolableList.get(i * 2 + 1), | |
| 305 nonInterpolableList.get(i * 2 + 1), | |
| 306 environment.state().cssToLengthConversionData()); | |
| 307 } | |
| 308 SizeListPropertyFunctions::setSizeList(cssProperty(), *environment.state().s tyle(), sizeList); | |
| 309 } | |
| 310 | |
| 311 } // namespace blink | |
| OLD | NEW |