Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "config.h" | 5 #include "config.h" |
| 6 #include "core/animation/StringKeyframe.h" | 6 #include "core/animation/StringKeyframe.h" |
| 7 | 7 |
| 8 #include "core/animation/AngleSVGInterpolation.h" | 8 #include "core/animation/AngleSVGInterpolation.h" |
| 9 #include "core/animation/AnimationType.h" | |
| 9 #include "core/animation/ColorStyleInterpolation.h" | 10 #include "core/animation/ColorStyleInterpolation.h" |
| 10 #include "core/animation/CompositorAnimations.h" | 11 #include "core/animation/CompositorAnimations.h" |
| 11 #include "core/animation/ConstantStyleInterpolation.h" | 12 #include "core/animation/ConstantStyleInterpolation.h" |
| 13 #include "core/animation/DefaultAnimationType.h" | |
| 12 #include "core/animation/DefaultSVGInterpolation.h" | 14 #include "core/animation/DefaultSVGInterpolation.h" |
| 13 #include "core/animation/DeferredLegacyStyleInterpolation.h" | 15 #include "core/animation/DeferredLegacyStyleInterpolation.h" |
| 14 #include "core/animation/DoubleStyleInterpolation.h" | 16 #include "core/animation/DoubleStyleInterpolation.h" |
| 15 #include "core/animation/FilterStyleInterpolation.h" | 17 #include "core/animation/FilterStyleInterpolation.h" |
| 16 #include "core/animation/ImageSliceStyleInterpolation.h" | 18 #include "core/animation/ImageSliceStyleInterpolation.h" |
| 17 #include "core/animation/ImageStyleInterpolation.h" | 19 #include "core/animation/ImageStyleInterpolation.h" |
| 18 #include "core/animation/IntegerOptionalIntegerSVGInterpolation.h" | 20 #include "core/animation/IntegerOptionalIntegerSVGInterpolation.h" |
| 19 #include "core/animation/IntegerSVGInterpolation.h" | 21 #include "core/animation/IntegerSVGInterpolation.h" |
| 22 #include "core/animation/InvalidatableStyleInterpolation.h" | |
| 20 #include "core/animation/LegacyStyleInterpolation.h" | 23 #include "core/animation/LegacyStyleInterpolation.h" |
| 21 #include "core/animation/LengthBoxStyleInterpolation.h" | 24 #include "core/animation/LengthBoxStyleInterpolation.h" |
| 22 #include "core/animation/LengthPairStyleInterpolation.h" | 25 #include "core/animation/LengthPairStyleInterpolation.h" |
| 23 #include "core/animation/LengthSVGInterpolation.h" | 26 #include "core/animation/LengthSVGInterpolation.h" |
| 24 #include "core/animation/LengthStyleInterpolation.h" | 27 #include "core/animation/LengthStyleInterpolation.h" |
| 25 #include "core/animation/ListSVGInterpolation.h" | 28 #include "core/animation/ListSVGInterpolation.h" |
| 26 #include "core/animation/ListStyleInterpolation.h" | 29 #include "core/animation/ListStyleInterpolation.h" |
| 27 #include "core/animation/NumberOptionalNumberSVGInterpolation.h" | 30 #include "core/animation/NumberOptionalNumberSVGInterpolation.h" |
| 28 #include "core/animation/NumberSVGInterpolation.h" | 31 #include "core/animation/NumberSVGInterpolation.h" |
| 29 #include "core/animation/PathSVGInterpolation.h" | 32 #include "core/animation/PathSVGInterpolation.h" |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 81 properties.add(PropertyHandle(*key)); | 84 properties.add(PropertyHandle(*key)); |
| 82 | 85 |
| 83 return properties; | 86 return properties; |
| 84 } | 87 } |
| 85 | 88 |
| 86 PassRefPtrWillBeRawPtr<Keyframe> StringKeyframe::clone() const | 89 PassRefPtrWillBeRawPtr<Keyframe> StringKeyframe::clone() const |
| 87 { | 90 { |
| 88 return adoptRefWillBeNoop(new StringKeyframe(*this)); | 91 return adoptRefWillBeNoop(new StringKeyframe(*this)); |
| 89 } | 92 } |
| 90 | 93 |
| 91 PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> StringKeyframe::creat ePropertySpecificKeyframe(PropertyHandle property) const | 94 PassRefPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> StringKeyframe::creat ePropertySpecificKeyframe(PropertyHandle property) const |
| 92 { | 95 { |
| 93 if (property.isCSSProperty()) | 96 if (property.isCSSProperty()) |
| 94 return adoptPtrWillBeNoop(new CSSPropertySpecificKeyframe(offset(), &eas ing(), cssPropertyValue(property.cssProperty()), composite())); | 97 return adoptRefWillBeNoop(new CSSPropertySpecificKeyframe(offset(), &eas ing(), cssPropertyValue(property.cssProperty()), composite())); |
| 95 | 98 |
| 96 ASSERT(property.isSVGAttribute()); | 99 ASSERT(property.isSVGAttribute()); |
| 97 return adoptPtrWillBeNoop(new SVGPropertySpecificKeyframe(offset(), &easing( ), svgPropertyValue(*property.svgAttribute()), composite())); | 100 return adoptRefWillBeNoop(new SVGPropertySpecificKeyframe(offset(), &easing( ), svgPropertyValue(*property.svgAttribute()), composite())); |
| 98 } | 101 } |
| 99 | 102 |
| 100 DEFINE_TRACE(StringKeyframe) | 103 DEFINE_TRACE(StringKeyframe) |
| 101 { | 104 { |
| 102 visitor->trace(m_propertySet); | 105 visitor->trace(m_propertySet); |
| 103 Keyframe::trace(visitor); | 106 Keyframe::trace(visitor); |
| 104 } | 107 } |
| 105 | 108 |
| 106 StringKeyframe::CSSPropertySpecificKeyframe::CSSPropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, CSSValue* value, EffectModel::Composi teOperation op) | 109 StringKeyframe::CSSPropertySpecificKeyframe::CSSPropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, CSSValue* value, EffectModel::Composi teOperation op) |
| 107 : Keyframe::PropertySpecificKeyframe(offset, easing, op) | 110 : Keyframe::PropertySpecificKeyframe(offset, easing, op) |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 143 case CSSPropertyStrokeMiterlimit: | 146 case CSSPropertyStrokeMiterlimit: |
| 144 return RangeGreaterThanOrEqualToOne; | 147 return RangeGreaterThanOrEqualToOne; |
| 145 case CSSPropertyFontSizeAdjust: | 148 case CSSPropertyFontSizeAdjust: |
| 146 return RangeNonNegative; | 149 return RangeNonNegative; |
| 147 default: | 150 default: |
| 148 ASSERT_NOT_REACHED(); | 151 ASSERT_NOT_REACHED(); |
| 149 return RangeAll; | 152 return RangeAll; |
| 150 } | 153 } |
| 151 } | 154 } |
| 152 | 155 |
| 156 const Vector<const AnimationType*>* applicableTypesForProperty(CSSPropertyID pro perty) | |
|
shans
2015/05/28 05:48:14
This can be deferred until we support anything tha
alancutter (OOO until 2018)
2015/06/01 07:35:29
This code serves the AnimationTypes as per propert
| |
| 157 { | |
| 158 using ApplicableTypesMap = HashMap<CSSPropertyID, const Vector<const Animati onType*>*>; | |
| 159 DEFINE_STATIC_LOCAL(ApplicableTypesMap, applicableTypesMap, ()); | |
| 160 if (applicableTypesMap.contains(property)) | |
| 161 return applicableTypesMap.get(property); | |
| 162 | |
| 163 // TODO(alancutter): Support all animatable CSS properties here so we can st op falling back to the old StyleInterpolation implementation. | |
| 164 if (CSSPropertyMetadata::isAnimatableProperty(property)) | |
| 165 return nullptr; | |
| 166 | |
| 167 auto applicableTypes = new Vector<const AnimationType*>(); | |
| 168 applicableTypes->append(new DefaultAnimationType(property)); | |
| 169 applicableTypesMap.add(property, applicableTypes); | |
| 170 return applicableTypes; | |
| 171 } | |
| 172 | |
| 153 } // namespace | 173 } // namespace |
| 154 | 174 |
| 155 PassRefPtrWillBeRawPtr<Interpolation> StringKeyframe::CSSPropertySpecificKeyfram e::maybeCreateInterpolation(PropertyHandle propertyHandle, Keyframe::PropertySpe cificKeyframe& end, Element* element, const ComputedStyle* baseStyle) const | 175 PassRefPtrWillBeRawPtr<Interpolation> StringKeyframe::CSSPropertySpecificKeyfram e::maybeCreateInterpolation(PropertyHandle propertyHandle, Keyframe::PropertySpe cificKeyframe& end, Element* element, const ComputedStyle* baseStyle) |
| 156 { | 176 { |
| 157 CSSPropertyID property = propertyHandle.cssProperty(); | 177 CSSPropertyID property = propertyHandle.cssProperty(); |
| 178 const Vector<const AnimationType*>* applicableTypes = applicableTypesForProp erty(property); | |
| 179 if (applicableTypes) | |
| 180 return InvalidatableStyleInterpolation::create(*applicableTypes, this, t oCSSPropertySpecificKeyframe(&end)); | |
| 181 | |
| 182 // TODO(alancutter): Remove the remainder of this function. | |
| 158 | 183 |
| 159 // FIXME: Refactor this into a generic piece that lives in InterpolationEffe ct, and a template parameter specific converter. | 184 // FIXME: Refactor this into a generic piece that lives in InterpolationEffe ct, and a template parameter specific converter. |
| 160 CSSValue* fromCSSValue = m_value.get(); | 185 CSSValue* fromCSSValue = m_value.get(); |
| 161 CSSValue* toCSSValue = toCSSPropertySpecificKeyframe(end).value(); | 186 CSSValue* toCSSValue = toCSSPropertySpecificKeyframe(end).value(); |
| 162 InterpolationRange range = RangeAll; | 187 InterpolationRange range = RangeAll; |
| 163 bool fallBackToLegacy = false; | 188 bool fallBackToLegacy = false; |
| 164 | 189 |
| 165 // FIXME: Remove this flag once we can rely on legacy's behaviour being corr ect. | 190 // FIXME: Remove this flag once we can rely on legacy's behaviour being corr ect. |
| 166 bool forceDefaultInterpolation = false; | 191 bool forceDefaultInterpolation = false; |
| 167 | 192 |
| 168 // FIXME: Remove this check once neutral keyframes are implemented in String Keyframes. | 193 // FIXME: Remove this check once neutral keyframes are implemented in String Keyframes. |
| 169 if (!fromCSSValue || !toCSSValue) | 194 if (!fromCSSValue || !toCSSValue) |
| 170 return DeferredLegacyStyleInterpolation::create(fromCSSValue, toCSSValue , property); | 195 return DeferredLegacyStyleInterpolation::create(fromCSSValue, toCSSValue , property); |
| 171 | 196 |
| 172 ASSERT(fromCSSValue && toCSSValue); | 197 ASSERT(fromCSSValue && toCSSValue); |
| 173 | 198 |
| 174 if (!CSSPropertyMetadata::isAnimatableProperty(property)) { | 199 if (!CSSPropertyMetadata::isAnimatableProperty(property)) { |
| 175 if (fromCSSValue == toCSSValue) | 200 if (fromCSSValue == toCSSValue) |
| 176 return ConstantStyleInterpolation::create(fromCSSValue, property); | 201 return ConstantStyleInterpolation::create(fromCSSValue, property); |
| 177 | 202 |
| 178 return nullptr; | 203 return nullptr; |
| 179 } | 204 } |
| 180 | 205 |
| 181 // FIXME: Generate this giant switch statement. | |
| 182 switch (property) { | 206 switch (property) { |
| 183 case CSSPropertyLineHeight: | 207 case CSSPropertyLineHeight: |
| 184 if (LengthStyleInterpolation::canCreateFrom(*fromCSSValue) && LengthStyl eInterpolation::canCreateFrom(*toCSSValue)) | 208 if (LengthStyleInterpolation::canCreateFrom(*fromCSSValue) && LengthStyl eInterpolation::canCreateFrom(*toCSSValue)) |
| 185 return LengthStyleInterpolation::create(*fromCSSValue, *toCSSValue, property, RangeNonNegative); | 209 return LengthStyleInterpolation::create(*fromCSSValue, *toCSSValue, property, RangeNonNegative); |
| 186 | 210 |
| 187 if (DoubleStyleInterpolation::canCreateFrom(*fromCSSValue) && DoubleStyl eInterpolation::canCreateFrom(*toCSSValue)) | 211 if (DoubleStyleInterpolation::canCreateFrom(*fromCSSValue) && DoubleStyl eInterpolation::canCreateFrom(*toCSSValue)) |
| 188 return DoubleStyleInterpolation::create(*fromCSSValue, *toCSSValue, property, CSSPrimitiveValue::CSS_NUMBER, RangeNonNegative); | 212 return DoubleStyleInterpolation::create(*fromCSSValue, *toCSSValue, property, CSSPrimitiveValue::CSS_NUMBER, RangeNonNegative); |
| 189 | 213 |
| 190 break; | 214 break; |
| 191 case CSSPropertyBorderBottomWidth: | 215 case CSSPropertyBorderBottomWidth: |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 431 } | 455 } |
| 432 | 456 |
| 433 ASSERT(AnimatableValue::usesDefaultInterpolation( | 457 ASSERT(AnimatableValue::usesDefaultInterpolation( |
| 434 StyleResolver::createAnimatableValueSnapshot(*element, baseStyle, proper ty, fromCSSValue).get(), | 458 StyleResolver::createAnimatableValueSnapshot(*element, baseStyle, proper ty, fromCSSValue).get(), |
| 435 StyleResolver::createAnimatableValueSnapshot(*element, baseStyle, proper ty, toCSSValue).get())); | 459 StyleResolver::createAnimatableValueSnapshot(*element, baseStyle, proper ty, toCSSValue).get())); |
| 436 | 460 |
| 437 return nullptr; | 461 return nullptr; |
| 438 | 462 |
| 439 } | 463 } |
| 440 | 464 |
| 441 PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> StringKeyframe::CSSPr opertySpecificKeyframe::neutralKeyframe(double offset, PassRefPtr<TimingFunction > easing) const | 465 PassRefPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> StringKeyframe::CSSPr opertySpecificKeyframe::neutralKeyframe(double offset, PassRefPtr<TimingFunction > easing) const |
| 442 { | 466 { |
| 443 return adoptPtrWillBeNoop(new CSSPropertySpecificKeyframe(offset, easing, st atic_cast<CSSValue*>(0), EffectModel::CompositeAdd)); | 467 return adoptRefWillBeNoop(new CSSPropertySpecificKeyframe(offset, easing, st atic_cast<CSSValue*>(0), EffectModel::CompositeAdd)); |
| 444 } | 468 } |
| 445 | 469 |
| 446 PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> StringKeyframe::CSSPr opertySpecificKeyframe::cloneWithOffset(double offset) const | 470 PassRefPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> StringKeyframe::CSSPr opertySpecificKeyframe::cloneWithOffset(double offset) const |
| 447 { | 471 { |
| 448 Keyframe::PropertySpecificKeyframe* theClone = new CSSPropertySpecificKeyfra me(offset, m_easing, m_value.get()); | 472 Keyframe::PropertySpecificKeyframe* theClone = new CSSPropertySpecificKeyfra me(offset, m_easing, m_value.get()); |
| 449 toCSSPropertySpecificKeyframe(theClone)->m_animatableValueCache = m_animatab leValueCache; | 473 toCSSPropertySpecificKeyframe(theClone)->m_animatableValueCache = m_animatab leValueCache; |
| 450 return adoptPtrWillBeNoop(theClone); | 474 return adoptRefWillBeNoop(theClone); |
| 451 } | 475 } |
| 452 | 476 |
| 453 DEFINE_TRACE(StringKeyframe::CSSPropertySpecificKeyframe) | 477 DEFINE_TRACE(StringKeyframe::CSSPropertySpecificKeyframe) |
| 454 { | 478 { |
| 455 visitor->trace(m_value); | 479 visitor->trace(m_value); |
| 456 visitor->trace(m_animatableValueCache); | 480 visitor->trace(m_animatableValueCache); |
| 457 Keyframe::PropertySpecificKeyframe::trace(visitor); | 481 Keyframe::PropertySpecificKeyframe::trace(visitor); |
| 458 } | 482 } |
| 459 | 483 |
| 460 SVGPropertySpecificKeyframe::SVGPropertySpecificKeyframe(double offset, PassRefP tr<TimingFunction> easing, const String& value, EffectModel::CompositeOperation op) | 484 SVGPropertySpecificKeyframe::SVGPropertySpecificKeyframe(double offset, PassRefP tr<TimingFunction> easing, const String& value, EffectModel::CompositeOperation op) |
| 461 : Keyframe::PropertySpecificKeyframe(offset, easing, op) | 485 : Keyframe::PropertySpecificKeyframe(offset, easing, op) |
| 462 , m_value(value) | 486 , m_value(value) |
| 463 { | 487 { |
| 464 } | 488 } |
| 465 | 489 |
| 466 SVGPropertySpecificKeyframe::SVGPropertySpecificKeyframe(double offset, PassRefP tr<TimingFunction> easing, const String& value) | 490 SVGPropertySpecificKeyframe::SVGPropertySpecificKeyframe(double offset, PassRefP tr<TimingFunction> easing, const String& value) |
| 467 : Keyframe::PropertySpecificKeyframe(offset, easing, EffectModel::CompositeR eplace) | 491 : Keyframe::PropertySpecificKeyframe(offset, easing, EffectModel::CompositeR eplace) |
| 468 , m_value(value) | 492 , m_value(value) |
| 469 { | 493 { |
| 470 ASSERT(!isNull(m_offset)); | 494 ASSERT(!isNull(m_offset)); |
| 471 } | 495 } |
| 472 | 496 |
| 473 DEFINE_TRACE(StringKeyframe::SVGPropertySpecificKeyframe) | 497 DEFINE_TRACE(StringKeyframe::SVGPropertySpecificKeyframe) |
| 474 { | 498 { |
| 475 Keyframe::PropertySpecificKeyframe::trace(visitor); | 499 Keyframe::PropertySpecificKeyframe::trace(visitor); |
| 476 } | 500 } |
| 477 | 501 |
| 478 PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> SVGPropertySpecificKe yframe::cloneWithOffset(double offset) const | 502 PassRefPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> SVGPropertySpecificKe yframe::cloneWithOffset(double offset) const |
| 479 { | 503 { |
| 480 return adoptPtrWillBeNoop(new SVGPropertySpecificKeyframe(offset, m_easing, m_value)); | 504 return adoptRefWillBeNoop(new SVGPropertySpecificKeyframe(offset, m_easing, m_value)); |
| 481 } | 505 } |
| 482 | 506 |
| 483 PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> SVGPropertySpecificKe yframe::neutralKeyframe(double offset, PassRefPtr<TimingFunction> easing) const | 507 PassRefPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> SVGPropertySpecificKe yframe::neutralKeyframe(double offset, PassRefPtr<TimingFunction> easing) const |
| 484 { | 508 { |
| 485 return adoptPtrWillBeNoop(new SVGPropertySpecificKeyframe(offset, easing, "" , EffectModel::CompositeAdd)); | 509 return adoptRefWillBeNoop(new SVGPropertySpecificKeyframe(offset, easing, "" , EffectModel::CompositeAdd)); |
| 486 } | 510 } |
| 487 | 511 |
| 488 namespace { | 512 namespace { |
| 489 | 513 |
| 490 PassRefPtrWillBeRawPtr<Interpolation> createSVGInterpolation(SVGPropertyBase* fr omValue, SVGPropertyBase* toValue, SVGAnimatedPropertyBase* attribute) | 514 PassRefPtrWillBeRawPtr<Interpolation> createSVGInterpolation(SVGPropertyBase* fr omValue, SVGPropertyBase* toValue, SVGAnimatedPropertyBase* attribute) |
| 491 { | 515 { |
| 492 RefPtrWillBeRawPtr<Interpolation> interpolation = nullptr; | 516 RefPtrWillBeRawPtr<Interpolation> interpolation = nullptr; |
| 493 ASSERT(fromValue->type() == toValue->type()); | 517 ASSERT(fromValue->type() == toValue->type()); |
| 494 switch (fromValue->type()) { | 518 switch (fromValue->type()) { |
| 495 case AnimatedAngle: | 519 case AnimatedAngle: |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 533 break; | 557 break; |
| 534 } | 558 } |
| 535 if (interpolation) | 559 if (interpolation) |
| 536 return interpolation.release(); | 560 return interpolation.release(); |
| 537 | 561 |
| 538 return DefaultSVGInterpolation::create(fromValue, toValue, attribute); | 562 return DefaultSVGInterpolation::create(fromValue, toValue, attribute); |
| 539 } | 563 } |
| 540 | 564 |
| 541 } // namespace | 565 } // namespace |
| 542 | 566 |
| 543 PassRefPtrWillBeRawPtr<Interpolation> SVGPropertySpecificKeyframe::maybeCreateIn terpolation(PropertyHandle propertyHandle, Keyframe::PropertySpecificKeyframe& e nd, Element* element, const ComputedStyle* baseStyle) const | 567 PassRefPtrWillBeRawPtr<Interpolation> SVGPropertySpecificKeyframe::maybeCreateIn terpolation(PropertyHandle propertyHandle, Keyframe::PropertySpecificKeyframe& e nd, Element* element, const ComputedStyle* baseStyle) |
| 544 { | 568 { |
| 545 ASSERT(element); | 569 ASSERT(element); |
| 546 RefPtrWillBeRawPtr<SVGAnimatedPropertyBase> attribute = toSVGElement(element )->propertyFromAttribute(*propertyHandle.svgAttribute()); | 570 RefPtrWillBeRawPtr<SVGAnimatedPropertyBase> attribute = toSVGElement(element )->propertyFromAttribute(*propertyHandle.svgAttribute()); |
| 547 ASSERT(attribute); | 571 ASSERT(attribute); |
| 548 | 572 |
| 549 RefPtrWillBeRawPtr<SVGPropertyBase> fromValue = attribute->currentValueBase( )->cloneForAnimation(m_value); | 573 RefPtrWillBeRawPtr<SVGPropertyBase> fromValue = attribute->currentValueBase( )->cloneForAnimation(m_value); |
| 550 RefPtrWillBeRawPtr<SVGPropertyBase> toValue = attribute->currentValueBase()- >cloneForAnimation(toSVGPropertySpecificKeyframe(end).value()); | 574 RefPtrWillBeRawPtr<SVGPropertyBase> toValue = attribute->currentValueBase()- >cloneForAnimation(toSVGPropertySpecificKeyframe(end).value()); |
| 551 | 575 |
| 552 if (!fromValue || !toValue) | 576 if (!fromValue || !toValue) |
| 553 return nullptr; | 577 return nullptr; |
| 554 | 578 |
| 555 return createSVGInterpolation(fromValue.get(), toValue.get(), attribute.get( )); | 579 return createSVGInterpolation(fromValue.get(), toValue.get(), attribute.get( )); |
| 556 } | 580 } |
| 557 | 581 |
| 558 } // namespace blink | 582 } // namespace blink |
| OLD | NEW |