| // Copyright 2014 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "cobalt/cssom/computed_style.h" |
| |
| #include <vector> |
| |
| #include "base/memory/scoped_ptr.h" |
| #include "cobalt/base/polymorphic_downcast.h" |
| #include "cobalt/cssom/absolute_url_value.h" |
| #include "cobalt/cssom/calc_value.h" |
| #include "cobalt/cssom/css_computed_style_data.h" |
| #include "cobalt/cssom/css_computed_style_declaration.h" |
| #include "cobalt/cssom/font_weight_value.h" |
| #include "cobalt/cssom/keyword_value.h" |
| #include "cobalt/cssom/length_value.h" |
| #include "cobalt/cssom/linear_gradient_value.h" |
| #include "cobalt/cssom/matrix_function.h" |
| #include "cobalt/cssom/number_value.h" |
| #include "cobalt/cssom/percentage_value.h" |
| #include "cobalt/cssom/property_list_value.h" |
| #include "cobalt/cssom/property_value_visitor.h" |
| #include "cobalt/cssom/radial_gradient_value.h" |
| #include "cobalt/cssom/rotate_function.h" |
| #include "cobalt/cssom/scale_function.h" |
| #include "cobalt/cssom/shadow_value.h" |
| #include "cobalt/cssom/transform_function.h" |
| #include "cobalt/cssom/transform_function_list_value.h" |
| #include "cobalt/cssom/transform_function_visitor.h" |
| #include "cobalt/cssom/translate_function.h" |
| #include "cobalt/cssom/url_value.h" |
| |
| namespace cobalt { |
| namespace cssom { |
| |
| namespace { |
| |
| scoped_refptr<LengthValue> ProvideAbsoluteLength( |
| const scoped_refptr<LengthValue>& specified_length, |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size) { |
| switch (specified_length->unit()) { |
| // "px" is an absolute unit. |
| // https://www.w3.org/TR/css3-values/#absolute-lengths |
| case kPixelsUnit: |
| return scoped_refptr<LengthValue>(specified_length); |
| |
| // "em" equals to the computed value of the "font-size" property of |
| // the element on which it is used. |
| // https://www.w3.org/TR/css3-values/#font-relative-lengths |
| case kFontSizesAkaEmUnit: { |
| DCHECK_EQ(kPixelsUnit, computed_font_size->unit()); |
| |
| return new LengthValue( |
| computed_font_size->value() * specified_length->value(), kPixelsUnit); |
| } |
| |
| // "rem" equals to the computed value of font-size on the root element. |
| // https://www.w3.org/TR/css3-values/#font-relative-lengths |
| case kRootElementFontSizesAkaRemUnit: { |
| DCHECK_EQ(kPixelsUnit, root_computed_font_size->unit()); |
| |
| return new LengthValue( |
| root_computed_font_size->value() * specified_length->value(), |
| kPixelsUnit); |
| } |
| |
| // "vw" equal to 1% of the width of the initial containing block. |
| // https://www.w3.org/TR/css3-values/#viewport-relative-lengths |
| case kViewportWidthPercentsAkaVwUnit: { |
| return new LengthValue( |
| viewport_size.width() * specified_length->value() / 100.0f, |
| kPixelsUnit); |
| } |
| |
| // "vh" equal to 1% of the height of the initial containing block. |
| // https://www.w3.org/TR/css3-values/#viewport-relative-lengths |
| case kViewportHeightPercentsAkaVhUnit: { |
| return new LengthValue( |
| viewport_size.height() * specified_length->value() / 100.0f, |
| kPixelsUnit); |
| } |
| |
| default: |
| NOTREACHED(); |
| return NULL; |
| } |
| } |
| |
| // For values that can be either lengths or percentages, this function will |
| // return a value that, if the original value was a length, is now |
| // absolutized. |
| scoped_refptr<PropertyValue> ProvideAbsoluteLengthIfNonNullLength( |
| const scoped_refptr<PropertyValue>& specified_value, |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size) { |
| if (!specified_value) { |
| return specified_value; |
| } |
| |
| if (specified_value->GetTypeId() == base::GetTypeId<LengthValue>()) { |
| LengthValue* value_as_length = |
| base::polymorphic_downcast<LengthValue*>(specified_value.get()); |
| |
| return ProvideAbsoluteLength(value_as_length, computed_font_size, |
| root_computed_font_size, viewport_size); |
| } else { |
| return specified_value; |
| } |
| } |
| |
| // Applices ProvideAbsoluteLengthIfNonNullLength() for every item in a |
| // PropertyValueList. |
| scoped_refptr<PropertyListValue> ProvideAbsoluteLengthsForNonNullLengthsInList( |
| const scoped_refptr<PropertyListValue>& specified_value, |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size) { |
| scoped_ptr<PropertyListValue::Builder> builder( |
| new PropertyListValue::Builder()); |
| builder->reserve(specified_value->value().size()); |
| |
| for (PropertyListValue::Builder::const_iterator iter = |
| specified_value->value().begin(); |
| iter != specified_value->value().end(); ++iter) { |
| builder->push_back(ProvideAbsoluteLengthIfNonNullLength( |
| *iter, computed_font_size, root_computed_font_size, viewport_size)); |
| } |
| |
| return new PropertyListValue(builder.Pass()); |
| } |
| |
| // Computed value: absolute length; |
| // '0' if the border style is 'none' or 'hidden'. |
| // https://www.w3.org/TR/css3-background/#border-width |
| class ComputedBorderWidthProvider : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedBorderWidthProvider(const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size, |
| const PropertyValue* border_style); |
| |
| void VisitLength(LengthValue* length) OVERRIDE; |
| |
| const scoped_refptr<PropertyValue>& computed_border_width() const { |
| return computed_border_width_; |
| } |
| |
| private: |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| const PropertyValue* border_style_; |
| |
| scoped_refptr<PropertyValue> computed_border_width_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedBorderWidthProvider); |
| }; |
| |
| ComputedBorderWidthProvider::ComputedBorderWidthProvider( |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size, |
| const PropertyValue* border_style) |
| : computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size), |
| border_style_(border_style) {} |
| |
| void ComputedBorderWidthProvider::VisitLength(LengthValue* specified_length) { |
| if (border_style_ == KeywordValue::GetNone().get() || |
| border_style_ == KeywordValue::GetHidden().get()) { |
| computed_border_width_ = new LengthValue(0, kPixelsUnit); |
| } else { |
| DCHECK_EQ(border_style_, KeywordValue::GetSolid().get()); |
| computed_border_width_ = |
| ProvideAbsoluteLength(specified_length, computed_font_size_, |
| root_computed_font_size_, viewport_size_); |
| } |
| } |
| |
| // Computed value: numeric weight value. |
| // https://www.w3.org/TR/css3-fonts/#font-weight-prop |
| class ComputedFontWeightProvider : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedFontWeightProvider() {} |
| |
| void VisitFontWeight(FontWeightValue* weight) OVERRIDE; |
| |
| const scoped_refptr<FontWeightValue>& computed_font_weight() const { |
| return computed_font_weight_; |
| } |
| |
| private: |
| scoped_refptr<FontWeightValue> computed_font_weight_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedFontWeightProvider); |
| }; |
| |
| // TODO: Support bolder and lighter. Match the weight with font face. |
| // Quite often there are only a few weights available for a particular font |
| // family. When a weight is specified for which no face exists, a face with a |
| // nearby weight is used. |
| // https://www.w3.org/TR/css3-fonts/#font-matching-algorithm |
| void ComputedFontWeightProvider::VisitFontWeight( |
| FontWeightValue* specified_weight) { |
| computed_font_weight_ = specified_weight; |
| } |
| |
| // Computed value: absolute length. |
| // https://www.w3.org/TR/css3-fonts/#font-size-prop |
| class ComputedFontSizeProvider : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedFontSizeProvider(const LengthValue* parent_computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size); |
| |
| void VisitLength(LengthValue* length) OVERRIDE; |
| void VisitPercentage(PercentageValue* percentage) OVERRIDE; |
| |
| const scoped_refptr<LengthValue>& computed_font_size() const { |
| return computed_font_size_; |
| } |
| |
| private: |
| const LengthValue* parent_computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| |
| scoped_refptr<LengthValue> computed_font_size_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedFontSizeProvider); |
| }; |
| |
| ComputedFontSizeProvider::ComputedFontSizeProvider( |
| const LengthValue* parent_computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size) |
| : parent_computed_font_size_(parent_computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size) {} |
| |
| void ComputedFontSizeProvider::VisitLength(LengthValue* specified_length) { |
| // "em" on "font-size" is calculated relatively to the inherited value |
| // of "font-size". |
| // https://www.w3.org/TR/css3-values/#font-relative-lengths |
| computed_font_size_ = |
| ProvideAbsoluteLength(specified_length, parent_computed_font_size_, |
| root_computed_font_size_, viewport_size_); |
| } |
| |
| void ComputedFontSizeProvider::VisitPercentage( |
| PercentageValue* specified_percentage) { |
| // A percentage value specifies an absolute font size relative to the parent |
| // element's fonts size. |
| // https://www.w3.org/TR/css3-fonts/#percentage-size-value |
| computed_font_size_ = new LengthValue( |
| parent_computed_font_size_->value() * specified_percentage->value(), |
| kPixelsUnit); |
| } |
| |
| // Computed value: for length and percentage the absolute value; |
| // otherwise as specified. |
| // https://www.w3.org/TR/CSS21/visudet.html#line-height |
| class ComputedLineHeightProvider : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedLineHeightProvider(const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size); |
| |
| void VisitKeyword(KeywordValue* keyword) OVERRIDE; |
| void VisitLength(LengthValue* length) OVERRIDE; |
| void VisitNumber(NumberValue* number) OVERRIDE; |
| void VisitPercentage(PercentageValue* percentage) OVERRIDE; |
| |
| const scoped_refptr<PropertyValue>& computed_line_height() const { |
| return computed_line_height_; |
| } |
| |
| private: |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| |
| scoped_refptr<PropertyValue> computed_line_height_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedLineHeightProvider); |
| }; |
| |
| ComputedLineHeightProvider::ComputedLineHeightProvider( |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size) |
| : computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size) {} |
| |
| void ComputedLineHeightProvider::VisitLength(LengthValue* specified_length) { |
| computed_line_height_ = |
| ProvideAbsoluteLength(specified_length, computed_font_size_, |
| root_computed_font_size_, viewport_size_); |
| } |
| |
| void ComputedLineHeightProvider::VisitNumber(NumberValue* specified_number) { |
| // The computed value is the same as the specified value. |
| // https://www.w3.org/TR/CSS2/visudet.html#line-height |
| computed_line_height_ = specified_number; |
| } |
| |
| void ComputedLineHeightProvider::VisitPercentage(PercentageValue* percentage) { |
| // The computed value of the property is this percentage multiplied by the |
| // element's computed font size. Negative values are illegal. |
| // https://www.w3.org/TR/CSS21/visudet.html#line-height |
| computed_line_height_ = new LengthValue( |
| computed_font_size_->value() * percentage->value(), kPixelsUnit); |
| } |
| |
| void ComputedLineHeightProvider::VisitKeyword(KeywordValue* keyword) { |
| switch (keyword->value()) { |
| case KeywordValue::kNormal: |
| computed_line_height_ = keyword; |
| break; |
| |
| case KeywordValue::kAbsolute: |
| case KeywordValue::kAlternate: |
| case KeywordValue::kAlternateReverse: |
| case KeywordValue::kAuto: |
| case KeywordValue::kBackwards: |
| case KeywordValue::kBaseline: |
| case KeywordValue::kBlock: |
| case KeywordValue::kBoth: |
| case KeywordValue::kBottom: |
| case KeywordValue::kBreakWord: |
| case KeywordValue::kCenter: |
| case KeywordValue::kClip: |
| case KeywordValue::kContain: |
| case KeywordValue::kCover: |
| case KeywordValue::kCurrentColor: |
| case KeywordValue::kCursive: |
| case KeywordValue::kEllipsis: |
| case KeywordValue::kEnd: |
| case KeywordValue::kEquirectangular: |
| case KeywordValue::kFantasy: |
| case KeywordValue::kForwards: |
| case KeywordValue::kFixed: |
| case KeywordValue::kHidden: |
| case KeywordValue::kInfinite: |
| case KeywordValue::kInherit: |
| case KeywordValue::kInitial: |
| case KeywordValue::kInline: |
| case KeywordValue::kInlineBlock: |
| case KeywordValue::kLeft: |
| case KeywordValue::kLineThrough: |
| case KeywordValue::kMiddle: |
| case KeywordValue::kMonoscopic: |
| case KeywordValue::kMonospace: |
| case KeywordValue::kNone: |
| case KeywordValue::kNoRepeat: |
| case KeywordValue::kNoWrap: |
| case KeywordValue::kPre: |
| case KeywordValue::kPreLine: |
| case KeywordValue::kPreWrap: |
| case KeywordValue::kRelative: |
| case KeywordValue::kRepeat: |
| case KeywordValue::kReverse: |
| case KeywordValue::kRight: |
| case KeywordValue::kSansSerif: |
| case KeywordValue::kSerif: |
| case KeywordValue::kSolid: |
| case KeywordValue::kStart: |
| case KeywordValue::kStatic: |
| case KeywordValue::kStereoscopicLeftRight: |
| case KeywordValue::kStereoscopicTopBottom: |
| case KeywordValue::kTop: |
| case KeywordValue::kUppercase: |
| case KeywordValue::kVisible: |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| // Computed value: the percentage as specified or the absolute length. |
| // https://www.w3.org/TR/CSS21/box.html#margin-properties |
| // https://www.w3.org/TR/CSS21/box.html#padding-properties |
| class ComputedMarginOrPaddingEdgeProvider |
| : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedMarginOrPaddingEdgeProvider( |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size); |
| |
| void VisitKeyword(KeywordValue* keyword) OVERRIDE; |
| void VisitLength(LengthValue* length) OVERRIDE; |
| void VisitPercentage(PercentageValue* percentage) OVERRIDE; |
| |
| const scoped_refptr<PropertyValue>& computed_margin_or_padding_edge() const { |
| return computed_margin_or_padding_edge_; |
| } |
| |
| private: |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| |
| scoped_refptr<PropertyValue> computed_margin_or_padding_edge_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedMarginOrPaddingEdgeProvider); |
| }; |
| |
| ComputedMarginOrPaddingEdgeProvider::ComputedMarginOrPaddingEdgeProvider( |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size) |
| : computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size) {} |
| |
| void ComputedMarginOrPaddingEdgeProvider::VisitKeyword(KeywordValue* keyword) { |
| switch (keyword->value()) { |
| case KeywordValue::kAuto: |
| computed_margin_or_padding_edge_ = keyword; |
| break; |
| |
| case KeywordValue::kAbsolute: |
| case KeywordValue::kAlternate: |
| case KeywordValue::kAlternateReverse: |
| case KeywordValue::kBackwards: |
| case KeywordValue::kBaseline: |
| case KeywordValue::kBlock: |
| case KeywordValue::kBoth: |
| case KeywordValue::kBottom: |
| case KeywordValue::kBreakWord: |
| case KeywordValue::kCenter: |
| case KeywordValue::kClip: |
| case KeywordValue::kContain: |
| case KeywordValue::kCover: |
| case KeywordValue::kCurrentColor: |
| case KeywordValue::kCursive: |
| case KeywordValue::kEllipsis: |
| case KeywordValue::kEnd: |
| case KeywordValue::kEquirectangular: |
| case KeywordValue::kFantasy: |
| case KeywordValue::kFixed: |
| case KeywordValue::kForwards: |
| case KeywordValue::kHidden: |
| case KeywordValue::kInfinite: |
| case KeywordValue::kInherit: |
| case KeywordValue::kInitial: |
| case KeywordValue::kInline: |
| case KeywordValue::kInlineBlock: |
| case KeywordValue::kLeft: |
| case KeywordValue::kLineThrough: |
| case KeywordValue::kMiddle: |
| case KeywordValue::kMonoscopic: |
| case KeywordValue::kMonospace: |
| case KeywordValue::kNoRepeat: |
| case KeywordValue::kNone: |
| case KeywordValue::kNormal: |
| case KeywordValue::kNoWrap: |
| case KeywordValue::kPre: |
| case KeywordValue::kPreLine: |
| case KeywordValue::kPreWrap: |
| case KeywordValue::kRelative: |
| case KeywordValue::kRepeat: |
| case KeywordValue::kReverse: |
| case KeywordValue::kRight: |
| case KeywordValue::kSansSerif: |
| case KeywordValue::kSerif: |
| case KeywordValue::kSolid: |
| case KeywordValue::kStart: |
| case KeywordValue::kStatic: |
| case KeywordValue::kStereoscopicLeftRight: |
| case KeywordValue::kStereoscopicTopBottom: |
| case KeywordValue::kTop: |
| case KeywordValue::kUppercase: |
| case KeywordValue::kVisible: |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| void ComputedMarginOrPaddingEdgeProvider::VisitLength( |
| LengthValue* specified_length) { |
| computed_margin_or_padding_edge_ = |
| ProvideAbsoluteLength(specified_length, computed_font_size_, |
| root_computed_font_size_, viewport_size_); |
| } |
| |
| void ComputedMarginOrPaddingEdgeProvider::VisitPercentage( |
| PercentageValue* percentage) { |
| computed_margin_or_padding_edge_ = percentage; |
| } |
| |
| class ComputedPositionOffsetProvider : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedPositionOffsetProvider(const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size); |
| |
| void VisitKeyword(KeywordValue* keyword) OVERRIDE; |
| void VisitLength(LengthValue* length) OVERRIDE; |
| void VisitPercentage(PercentageValue* percentage) OVERRIDE; |
| |
| const scoped_refptr<PropertyValue>& computed_position_offset() const { |
| return computed_position_offset_; |
| } |
| |
| private: |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| |
| scoped_refptr<PropertyValue> computed_position_offset_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedPositionOffsetProvider); |
| }; |
| |
| void ComputedPositionOffsetProvider::VisitLength( |
| LengthValue* specified_length) { |
| computed_position_offset_ = |
| ProvideAbsoluteLength(specified_length, computed_font_size_, |
| root_computed_font_size_, viewport_size_); |
| } |
| |
| void ComputedPositionOffsetProvider::VisitKeyword(KeywordValue* keyword) { |
| switch (keyword->value()) { |
| case KeywordValue::kAuto: |
| computed_position_offset_ = keyword; |
| break; |
| |
| case KeywordValue::kAbsolute: |
| case KeywordValue::kAlternate: |
| case KeywordValue::kAlternateReverse: |
| case KeywordValue::kBackwards: |
| case KeywordValue::kBaseline: |
| case KeywordValue::kBlock: |
| case KeywordValue::kBoth: |
| case KeywordValue::kBottom: |
| case KeywordValue::kBreakWord: |
| case KeywordValue::kCenter: |
| case KeywordValue::kClip: |
| case KeywordValue::kContain: |
| case KeywordValue::kCover: |
| case KeywordValue::kCurrentColor: |
| case KeywordValue::kCursive: |
| case KeywordValue::kEllipsis: |
| case KeywordValue::kEnd: |
| case KeywordValue::kEquirectangular: |
| case KeywordValue::kFantasy: |
| case KeywordValue::kFixed: |
| case KeywordValue::kForwards: |
| case KeywordValue::kHidden: |
| case KeywordValue::kInfinite: |
| case KeywordValue::kInherit: |
| case KeywordValue::kInitial: |
| case KeywordValue::kInline: |
| case KeywordValue::kInlineBlock: |
| case KeywordValue::kLeft: |
| case KeywordValue::kLineThrough: |
| case KeywordValue::kMiddle: |
| case KeywordValue::kMonoscopic: |
| case KeywordValue::kMonospace: |
| case KeywordValue::kNone: |
| case KeywordValue::kNoRepeat: |
| case KeywordValue::kNormal: |
| case KeywordValue::kNoWrap: |
| case KeywordValue::kPre: |
| case KeywordValue::kPreLine: |
| case KeywordValue::kPreWrap: |
| case KeywordValue::kRelative: |
| case KeywordValue::kRepeat: |
| case KeywordValue::kReverse: |
| case KeywordValue::kRight: |
| case KeywordValue::kSansSerif: |
| case KeywordValue::kSerif: |
| case KeywordValue::kSolid: |
| case KeywordValue::kStart: |
| case KeywordValue::kStatic: |
| case KeywordValue::kStereoscopicLeftRight: |
| case KeywordValue::kStereoscopicTopBottom: |
| case KeywordValue::kTop: |
| case KeywordValue::kUppercase: |
| case KeywordValue::kVisible: |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| void ComputedPositionOffsetProvider::VisitPercentage( |
| PercentageValue* percentage) { |
| computed_position_offset_ = percentage; |
| } |
| |
| ComputedPositionOffsetProvider::ComputedPositionOffsetProvider( |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size) |
| : computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size) {} |
| |
| // Computed value: the percentage or "auto" or the absolute length. |
| // https://www.w3.org/TR/CSS21/visudet.html#the-height-property |
| class ComputedHeightProvider : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedHeightProvider(const PropertyValue* parent_computed_height, |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size, bool out_of_flow); |
| |
| void VisitKeyword(KeywordValue* keyword) OVERRIDE; |
| void VisitLength(LengthValue* length) OVERRIDE; |
| void VisitPercentage(PercentageValue* percentage) OVERRIDE; |
| |
| const scoped_refptr<PropertyValue>& computed_height() const { |
| return computed_height_; |
| } |
| |
| private: |
| const PropertyValue* parent_computed_height_; |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| bool out_of_flow_; |
| |
| scoped_refptr<PropertyValue> computed_height_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedHeightProvider); |
| }; |
| |
| ComputedHeightProvider::ComputedHeightProvider( |
| const PropertyValue* parent_computed_height, |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size, |
| bool out_of_flow) |
| : parent_computed_height_(parent_computed_height), |
| computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size), |
| out_of_flow_(out_of_flow) {} |
| |
| void ComputedHeightProvider::VisitLength(LengthValue* specified_length) { |
| computed_height_ = |
| ProvideAbsoluteLength(specified_length, computed_font_size_, |
| root_computed_font_size_, viewport_size_); |
| } |
| |
| void ComputedHeightProvider::VisitKeyword(KeywordValue* keyword) { |
| switch (keyword->value()) { |
| case KeywordValue::kAuto: |
| computed_height_ = keyword; |
| break; |
| |
| case KeywordValue::kAbsolute: |
| case KeywordValue::kAlternate: |
| case KeywordValue::kAlternateReverse: |
| case KeywordValue::kBackwards: |
| case KeywordValue::kBaseline: |
| case KeywordValue::kBlock: |
| case KeywordValue::kBoth: |
| case KeywordValue::kBottom: |
| case KeywordValue::kBreakWord: |
| case KeywordValue::kCenter: |
| case KeywordValue::kClip: |
| case KeywordValue::kContain: |
| case KeywordValue::kCover: |
| case KeywordValue::kCurrentColor: |
| case KeywordValue::kCursive: |
| case KeywordValue::kEllipsis: |
| case KeywordValue::kEnd: |
| case KeywordValue::kEquirectangular: |
| case KeywordValue::kFantasy: |
| case KeywordValue::kFixed: |
| case KeywordValue::kForwards: |
| case KeywordValue::kHidden: |
| case KeywordValue::kInfinite: |
| case KeywordValue::kInherit: |
| case KeywordValue::kInitial: |
| case KeywordValue::kInline: |
| case KeywordValue::kInlineBlock: |
| case KeywordValue::kLeft: |
| case KeywordValue::kLineThrough: |
| case KeywordValue::kMiddle: |
| case KeywordValue::kMonospace: |
| case KeywordValue::kMonoscopic: |
| case KeywordValue::kNone: |
| case KeywordValue::kNoRepeat: |
| case KeywordValue::kNormal: |
| case KeywordValue::kNoWrap: |
| case KeywordValue::kPre: |
| case KeywordValue::kPreLine: |
| case KeywordValue::kPreWrap: |
| case KeywordValue::kRelative: |
| case KeywordValue::kRepeat: |
| case KeywordValue::kReverse: |
| case KeywordValue::kRight: |
| case KeywordValue::kSansSerif: |
| case KeywordValue::kSerif: |
| case KeywordValue::kSolid: |
| case KeywordValue::kStart: |
| case KeywordValue::kStatic: |
| case KeywordValue::kStereoscopicLeftRight: |
| case KeywordValue::kStereoscopicTopBottom: |
| case KeywordValue::kTop: |
| case KeywordValue::kUppercase: |
| case KeywordValue::kVisible: |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| void ComputedHeightProvider::VisitPercentage(PercentageValue* percentage) { |
| const scoped_refptr<PropertyValue>& auto_value = KeywordValue::GetAuto(); |
| |
| // If the height of the containing block is not specified explicitly |
| // (i.e., it depends on content height), and this element is not absolutely |
| // positioned, the value computes to "auto". |
| // https://www.w3.org/TR/CSS21/visudet.html#the-height-property |
| computed_height_ = (parent_computed_height_ == auto_value && !out_of_flow_) |
| ? auto_value |
| : percentage; |
| } |
| |
| // Computed value: the percentage or "auto" or the absolute length. |
| // https://www.w3.org/TR/CSS2/visudet.html#propdef-max-height |
| class ComputedMaxHeightProvider : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedMaxHeightProvider(const PropertyValue* parent_computed_max_height, |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size, bool out_of_flow); |
| |
| void VisitKeyword(KeywordValue* keyword) OVERRIDE; |
| void VisitLength(LengthValue* length) OVERRIDE; |
| void VisitPercentage(PercentageValue* percentage) OVERRIDE; |
| |
| const scoped_refptr<PropertyValue>& computed_max_height() const { |
| return computed_max_height_; |
| } |
| |
| private: |
| const PropertyValue* parent_computed_max_height_; |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| bool out_of_flow_; |
| |
| scoped_refptr<PropertyValue> computed_max_height_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedMaxHeightProvider); |
| }; |
| |
| ComputedMaxHeightProvider::ComputedMaxHeightProvider( |
| const PropertyValue* parent_computed_max_height, |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size, |
| bool out_of_flow) |
| : parent_computed_max_height_(parent_computed_max_height), |
| computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size), |
| out_of_flow_(out_of_flow) {} |
| |
| void ComputedMaxHeightProvider::VisitLength(LengthValue* specified_length) { |
| computed_max_height_ = |
| ProvideAbsoluteLength(specified_length, computed_font_size_, |
| root_computed_font_size_, viewport_size_); |
| } |
| |
| void ComputedMaxHeightProvider::VisitKeyword(KeywordValue* keyword) { |
| switch (keyword->value()) { |
| case KeywordValue::kAuto: |
| case KeywordValue::kNone: |
| computed_max_height_ = keyword; |
| break; |
| |
| case KeywordValue::kAbsolute: |
| case KeywordValue::kAlternate: |
| case KeywordValue::kAlternateReverse: |
| case KeywordValue::kBackwards: |
| case KeywordValue::kBaseline: |
| case KeywordValue::kBlock: |
| case KeywordValue::kBoth: |
| case KeywordValue::kBottom: |
| case KeywordValue::kBreakWord: |
| case KeywordValue::kCenter: |
| case KeywordValue::kClip: |
| case KeywordValue::kContain: |
| case KeywordValue::kCover: |
| case KeywordValue::kCursive: |
| case KeywordValue::kCurrentColor: |
| case KeywordValue::kEllipsis: |
| case KeywordValue::kEnd: |
| case KeywordValue::kEquirectangular: |
| case KeywordValue::kFantasy: |
| case KeywordValue::kFixed: |
| case KeywordValue::kForwards: |
| case KeywordValue::kHidden: |
| case KeywordValue::kInfinite: |
| case KeywordValue::kInherit: |
| case KeywordValue::kInitial: |
| case KeywordValue::kInline: |
| case KeywordValue::kInlineBlock: |
| case KeywordValue::kLeft: |
| case KeywordValue::kLineThrough: |
| case KeywordValue::kMiddle: |
| case KeywordValue::kMonoscopic: |
| case KeywordValue::kMonospace: |
| case KeywordValue::kNoRepeat: |
| case KeywordValue::kNormal: |
| case KeywordValue::kNoWrap: |
| case KeywordValue::kPre: |
| case KeywordValue::kPreLine: |
| case KeywordValue::kPreWrap: |
| case KeywordValue::kRelative: |
| case KeywordValue::kRepeat: |
| case KeywordValue::kReverse: |
| case KeywordValue::kRight: |
| case KeywordValue::kSansSerif: |
| case KeywordValue::kSerif: |
| case KeywordValue::kSolid: |
| case KeywordValue::kStart: |
| case KeywordValue::kStatic: |
| case KeywordValue::kStereoscopicLeftRight: |
| case KeywordValue::kStereoscopicTopBottom: |
| case KeywordValue::kTop: |
| case KeywordValue::kUppercase: |
| case KeywordValue::kVisible: |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| void ComputedMaxHeightProvider::VisitPercentage(PercentageValue* percentage) { |
| const scoped_refptr<PropertyValue>& auto_value = KeywordValue::GetAuto(); |
| const scoped_refptr<PropertyValue>& none_value = KeywordValue::GetNone(); |
| |
| // If the max_height of the containing block is not specified explicitly |
| // (i.e., it depends on content max_height), and this element is not |
| // absolutely positioned, the percentage value is treated as 'none'. |
| // https://www.w3.org/TR/CSS2/visudet.html#propdef-max-height |
| computed_max_height_ = |
| (parent_computed_max_height_ == auto_value && !out_of_flow_) ? none_value |
| : percentage; |
| } |
| |
| // Computed value: the percentage or "auto" or the absolute length. |
| // https://www.w3.org/TR/CSS2/visudet.html#propdef-min-height |
| class ComputedMinHeightProvider : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedMinHeightProvider(const PropertyValue* parent_computed_min_max_height, |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size, bool out_of_flow); |
| |
| void VisitKeyword(KeywordValue* keyword) OVERRIDE; |
| void VisitLength(LengthValue* length) OVERRIDE; |
| void VisitPercentage(PercentageValue* percentage) OVERRIDE; |
| |
| const scoped_refptr<PropertyValue>& computed_min_height() const { |
| return computed_min_height_; |
| } |
| |
| private: |
| const PropertyValue* parent_computed_min_max_height_; |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| bool out_of_flow_; |
| |
| scoped_refptr<PropertyValue> computed_min_height_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedMinHeightProvider); |
| }; |
| |
| ComputedMinHeightProvider::ComputedMinHeightProvider( |
| const PropertyValue* parent_computed_min_max_height, |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size, |
| bool out_of_flow) |
| : parent_computed_min_max_height_(parent_computed_min_max_height), |
| computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size), |
| out_of_flow_(out_of_flow) {} |
| |
| void ComputedMinHeightProvider::VisitLength(LengthValue* specified_length) { |
| computed_min_height_ = |
| ProvideAbsoluteLength(specified_length, computed_font_size_, |
| root_computed_font_size_, viewport_size_); |
| } |
| |
| void ComputedMinHeightProvider::VisitKeyword(KeywordValue* keyword) { |
| switch (keyword->value()) { |
| case KeywordValue::kAuto: |
| computed_min_height_ = keyword; |
| break; |
| |
| case KeywordValue::kAbsolute: |
| case KeywordValue::kAlternate: |
| case KeywordValue::kAlternateReverse: |
| case KeywordValue::kBackwards: |
| case KeywordValue::kBaseline: |
| case KeywordValue::kBlock: |
| case KeywordValue::kBoth: |
| case KeywordValue::kBottom: |
| case KeywordValue::kBreakWord: |
| case KeywordValue::kCenter: |
| case KeywordValue::kClip: |
| case KeywordValue::kContain: |
| case KeywordValue::kCover: |
| case KeywordValue::kCurrentColor: |
| case KeywordValue::kCursive: |
| case KeywordValue::kEllipsis: |
| case KeywordValue::kEquirectangular: |
| case KeywordValue::kEnd: |
| case KeywordValue::kFantasy: |
| case KeywordValue::kFixed: |
| case KeywordValue::kForwards: |
| case KeywordValue::kHidden: |
| case KeywordValue::kInfinite: |
| case KeywordValue::kInherit: |
| case KeywordValue::kInitial: |
| case KeywordValue::kInline: |
| case KeywordValue::kInlineBlock: |
| case KeywordValue::kLeft: |
| case KeywordValue::kLineThrough: |
| case KeywordValue::kMiddle: |
| case KeywordValue::kMonoscopic: |
| case KeywordValue::kMonospace: |
| case KeywordValue::kNone: |
| case KeywordValue::kNoRepeat: |
| case KeywordValue::kNormal: |
| case KeywordValue::kNoWrap: |
| case KeywordValue::kPre: |
| case KeywordValue::kPreLine: |
| case KeywordValue::kPreWrap: |
| case KeywordValue::kRelative: |
| case KeywordValue::kRepeat: |
| case KeywordValue::kReverse: |
| case KeywordValue::kRight: |
| case KeywordValue::kSansSerif: |
| case KeywordValue::kSerif: |
| case KeywordValue::kSolid: |
| case KeywordValue::kStart: |
| case KeywordValue::kStatic: |
| case KeywordValue::kStereoscopicLeftRight: |
| case KeywordValue::kStereoscopicTopBottom: |
| case KeywordValue::kTop: |
| case KeywordValue::kUppercase: |
| case KeywordValue::kVisible: |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| void ComputedMinHeightProvider::VisitPercentage(PercentageValue* percentage) { |
| const scoped_refptr<PropertyValue>& auto_value = KeywordValue::GetAuto(); |
| |
| // If the min_height of the containing block is not specified explicitly |
| // (i.e., it depends on content min_height), and this element is not |
| // absolutely positioned, the percentage value is treated as '0'. |
| // https://www.w3.org/TR/CSS2/visudet.html#propdef-min-height |
| if (parent_computed_min_max_height_ == auto_value && !out_of_flow_) { |
| computed_min_height_ = new LengthValue(0, kPixelsUnit); |
| } else { |
| computed_min_height_ = percentage; |
| } |
| } |
| |
| // Computed value: the percentage or "auto" as specified or the absolute length. |
| // https://www.w3.org/TR/CSS21/visudet.html#the-width-property |
| class ComputedWidthProvider : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedWidthProvider(const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size); |
| |
| void VisitKeyword(KeywordValue* keyword) OVERRIDE; |
| void VisitLength(LengthValue* length) OVERRIDE; |
| void VisitPercentage(PercentageValue* percentage) OVERRIDE; |
| |
| const scoped_refptr<PropertyValue>& computed_width() const { |
| return computed_width_; |
| } |
| |
| private: |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| |
| scoped_refptr<PropertyValue> computed_width_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedWidthProvider); |
| }; |
| |
| ComputedWidthProvider::ComputedWidthProvider( |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size) |
| : computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size) {} |
| |
| void ComputedWidthProvider::VisitLength(LengthValue* specified_length) { |
| computed_width_ = |
| ProvideAbsoluteLength(specified_length, computed_font_size_, |
| root_computed_font_size_, viewport_size_); |
| } |
| |
| void ComputedWidthProvider::VisitKeyword(KeywordValue* keyword) { |
| switch (keyword->value()) { |
| case KeywordValue::kAuto: |
| computed_width_ = keyword; |
| break; |
| |
| case KeywordValue::kAbsolute: |
| case KeywordValue::kAlternate: |
| case KeywordValue::kAlternateReverse: |
| case KeywordValue::kBackwards: |
| case KeywordValue::kBaseline: |
| case KeywordValue::kBlock: |
| case KeywordValue::kBoth: |
| case KeywordValue::kBottom: |
| case KeywordValue::kBreakWord: |
| case KeywordValue::kCenter: |
| case KeywordValue::kClip: |
| case KeywordValue::kContain: |
| case KeywordValue::kCover: |
| case KeywordValue::kCurrentColor: |
| case KeywordValue::kCursive: |
| case KeywordValue::kEllipsis: |
| case KeywordValue::kEnd: |
| case KeywordValue::kEquirectangular: |
| case KeywordValue::kFantasy: |
| case KeywordValue::kFixed: |
| case KeywordValue::kForwards: |
| case KeywordValue::kHidden: |
| case KeywordValue::kInfinite: |
| case KeywordValue::kInherit: |
| case KeywordValue::kInitial: |
| case KeywordValue::kInline: |
| case KeywordValue::kInlineBlock: |
| case KeywordValue::kLeft: |
| case KeywordValue::kLineThrough: |
| case KeywordValue::kMiddle: |
| case KeywordValue::kMonoscopic: |
| case KeywordValue::kMonospace: |
| case KeywordValue::kNone: |
| case KeywordValue::kNoRepeat: |
| case KeywordValue::kNormal: |
| case KeywordValue::kNoWrap: |
| case KeywordValue::kPre: |
| case KeywordValue::kPreLine: |
| case KeywordValue::kPreWrap: |
| case KeywordValue::kRelative: |
| case KeywordValue::kRepeat: |
| case KeywordValue::kReverse: |
| case KeywordValue::kRight: |
| case KeywordValue::kSansSerif: |
| case KeywordValue::kSerif: |
| case KeywordValue::kSolid: |
| case KeywordValue::kStart: |
| case KeywordValue::kStatic: |
| case KeywordValue::kStereoscopicLeftRight: |
| case KeywordValue::kStereoscopicTopBottom: |
| case KeywordValue::kTop: |
| case KeywordValue::kUppercase: |
| case KeywordValue::kVisible: |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| void ComputedWidthProvider::VisitPercentage(PercentageValue* percentage) { |
| computed_width_ = percentage; |
| } |
| |
| // Computed value: the percentage or "auto" as specified or the absolute length. |
| // https://www.w3.org/TR/CSS2/visudet.html#min-max-widths |
| class ComputedMinMaxWidthProvider : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedMinMaxWidthProvider(PropertyValue* parent_computed_min_max_height, |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size); |
| |
| void VisitKeyword(KeywordValue* keyword) OVERRIDE; |
| void VisitLength(LengthValue* length) OVERRIDE; |
| void VisitPercentage(PercentageValue* percentage) OVERRIDE; |
| |
| const scoped_refptr<PropertyValue>& computed_min_max_width() const { |
| return computed_min_max_width_; |
| } |
| |
| private: |
| PropertyValue* parent_computed_min_max_width_; |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| |
| scoped_refptr<PropertyValue> computed_min_max_width_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedMinMaxWidthProvider); |
| }; |
| |
| ComputedMinMaxWidthProvider::ComputedMinMaxWidthProvider( |
| PropertyValue* parent_computed_min_max_width, |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size) |
| : parent_computed_min_max_width_(parent_computed_min_max_width), |
| computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size) {} |
| |
| void ComputedMinMaxWidthProvider::VisitLength(LengthValue* specified_length) { |
| computed_min_max_width_ = |
| ProvideAbsoluteLength(specified_length, computed_font_size_, |
| root_computed_font_size_, viewport_size_); |
| } |
| |
| void ComputedMinMaxWidthProvider::VisitKeyword(KeywordValue* keyword) { |
| switch (keyword->value()) { |
| case KeywordValue::kAuto: |
| case KeywordValue::kNone: |
| computed_min_max_width_ = keyword; |
| break; |
| |
| case KeywordValue::kAbsolute: |
| case KeywordValue::kAlternate: |
| case KeywordValue::kAlternateReverse: |
| case KeywordValue::kBackwards: |
| case KeywordValue::kBaseline: |
| case KeywordValue::kBlock: |
| case KeywordValue::kBoth: |
| case KeywordValue::kBottom: |
| case KeywordValue::kBreakWord: |
| case KeywordValue::kCenter: |
| case KeywordValue::kClip: |
| case KeywordValue::kContain: |
| case KeywordValue::kCover: |
| case KeywordValue::kCurrentColor: |
| case KeywordValue::kCursive: |
| case KeywordValue::kEllipsis: |
| case KeywordValue::kEnd: |
| case KeywordValue::kEquirectangular: |
| case KeywordValue::kFantasy: |
| case KeywordValue::kFixed: |
| case KeywordValue::kForwards: |
| case KeywordValue::kHidden: |
| case KeywordValue::kInfinite: |
| case KeywordValue::kInherit: |
| case KeywordValue::kInitial: |
| case KeywordValue::kInline: |
| case KeywordValue::kInlineBlock: |
| case KeywordValue::kLeft: |
| case KeywordValue::kLineThrough: |
| case KeywordValue::kMiddle: |
| case KeywordValue::kMonospace: |
| case KeywordValue::kMonoscopic: |
| case KeywordValue::kNoRepeat: |
| case KeywordValue::kNormal: |
| case KeywordValue::kNoWrap: |
| case KeywordValue::kPre: |
| case KeywordValue::kPreLine: |
| case KeywordValue::kPreWrap: |
| case KeywordValue::kRelative: |
| case KeywordValue::kRepeat: |
| case KeywordValue::kReverse: |
| case KeywordValue::kRight: |
| case KeywordValue::kSansSerif: |
| case KeywordValue::kSerif: |
| case KeywordValue::kSolid: |
| case KeywordValue::kStart: |
| case KeywordValue::kStatic: |
| case KeywordValue::kStereoscopicLeftRight: |
| case KeywordValue::kStereoscopicTopBottom: |
| case KeywordValue::kTop: |
| case KeywordValue::kUppercase: |
| case KeywordValue::kVisible: |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| class ComputedLengthIsNegativeProvider : public DefaultingPropertyValueVisitor { |
| public: |
| ComputedLengthIsNegativeProvider() : computed_length_is_negative_(false) {} |
| |
| void VisitLength(LengthValue* length_value) OVERRIDE { |
| switch (length_value->unit()) { |
| case kPixelsUnit: |
| case kFontSizesAkaEmUnit: |
| case kRootElementFontSizesAkaRemUnit: |
| case kViewportWidthPercentsAkaVwUnit: |
| case kViewportHeightPercentsAkaVhUnit: |
| computed_length_is_negative_ = length_value->value() < 0; |
| break; |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| void VisitDefault(PropertyValue* property_value) OVERRIDE { |
| UNREFERENCED_PARAMETER(property_value); |
| } |
| |
| bool computed_length_is_negative() { return computed_length_is_negative_; } |
| |
| private: |
| bool computed_length_is_negative_; |
| }; |
| |
| void ComputedMinMaxWidthProvider::VisitPercentage(PercentageValue* percentage) { |
| ComputedLengthIsNegativeProvider computed_length_is_negative_provider; |
| parent_computed_min_max_width_->Accept(&computed_length_is_negative_provider); |
| // If the containing block's width is negative, the used value is zero. |
| // https://www.w3.org/TR/CSS2/visudet.html#min-max-widths |
| if (computed_length_is_negative_provider.computed_length_is_negative()) { |
| computed_min_max_width_ = new LengthValue(0, kPixelsUnit); |
| } else { |
| computed_min_max_width_ = percentage; |
| } |
| } |
| |
| namespace { |
| |
| // Helper class for |ComputedBackgroundPositionProvider| and |
| // |ComputedTransformOriginProvider| to resolve the computed value of position |
| // part. |
| // https://www.w3.org/TR/css3-background/#the-background-position |
| // https://www.w3.org/TR/css3-transforms/#propdef-transform-origin |
| class ComputedPositionHelper { |
| public: |
| ComputedPositionHelper(const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size); |
| |
| // Forwards the call on to the appropriate method depending on the number |
| // of parameters in |input_position_builder|. |
| void ComputePosition(const PropertyListValue::Builder& input_position_builder, |
| PropertyListValue::Builder* output_position_builder); |
| |
| // Only resolve the first value of |input_position_builder|, other than the |
| // first value would be ignored. |
| void ComputeOneValuePosition( |
| const PropertyListValue::Builder& input_position_builder, |
| PropertyListValue::Builder* output_position_builder); |
| |
| // Only resolve the first two values of |input_position_builder|, other than |
| // the first two values would be ignored. |
| void ComputeTwoValuesPosition( |
| const PropertyListValue::Builder& input_position_builder, |
| PropertyListValue::Builder* output_position_builder); |
| |
| // Only resolve three or four values of |input_position_builder|. |
| void ComputeThreeOrFourValuesPosition( |
| const PropertyListValue::Builder& input_position_builder, |
| PropertyListValue::Builder* output_position_builder); |
| |
| private: |
| enum Direction { |
| kHorizontal, |
| kVertical, |
| kCenter, |
| kNone, |
| }; |
| |
| struct OriginInfo { |
| OriginInfo(float origin_as_percentage, int offset_multiplier, |
| Direction direction) |
| : origin_as_percentage(origin_as_percentage), |
| offset_multiplier(offset_multiplier), |
| direction(direction) {} |
| |
| float origin_as_percentage; |
| int offset_multiplier; |
| Direction direction; |
| }; |
| |
| const OriginInfo ConvertToOriginInfo( |
| const scoped_refptr<PropertyValue>& keyword) const; |
| |
| scoped_refptr<CalcValue> ProvideCalcValueFromOriginAndOffset( |
| OriginInfo* origin_info, const scoped_refptr<PropertyValue>& offset); |
| |
| void FillPositionBuilderFromOriginAndOffset( |
| const scoped_refptr<PropertyValue>& origin, |
| const scoped_refptr<PropertyValue>& offset, |
| PropertyListValue::Builder* position_builder); |
| |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedPositionHelper); |
| }; |
| |
| ComputedPositionHelper::ComputedPositionHelper( |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size) |
| : computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size) {} |
| |
| void ComputedPositionHelper::ComputePosition( |
| const PropertyListValue::Builder& input_position_builder, |
| PropertyListValue::Builder* output_position_builder) { |
| switch (input_position_builder.size()) { |
| case 1: |
| ComputeOneValuePosition(input_position_builder, output_position_builder); |
| break; |
| case 2: |
| ComputeTwoValuesPosition(input_position_builder, output_position_builder); |
| break; |
| case 3: // fall-through |
| case 4: |
| ComputeThreeOrFourValuesPosition(input_position_builder, |
| output_position_builder); |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| // If only one value is specified, the second value is assumed to be center. |
| void ComputedPositionHelper::ComputeOneValuePosition( |
| const PropertyListValue::Builder& input_position_builder, |
| PropertyListValue::Builder* output_position_builder) { |
| DCHECK_GE(input_position_builder.size(), 1u); |
| |
| PropertyListValue::Builder position_builder; |
| position_builder.push_back(input_position_builder[0]); |
| position_builder.push_back(KeywordValue::GetCenter()); |
| |
| ComputeTwoValuesPosition(position_builder, output_position_builder); |
| } |
| |
| // If two position values are given, a length or percentage as the |
| // first value represents the horizontal position (or offset) and a length or |
| // percentage as the second value represents the vertical position (or offset). |
| void ComputedPositionHelper::ComputeTwoValuesPosition( |
| const PropertyListValue::Builder& input_position_builder, |
| PropertyListValue::Builder* output_position_builder) { |
| DCHECK_GE(input_position_builder.size(), 2u); |
| |
| for (size_t i = 0; i < 2; ++i) { |
| scoped_refptr<PropertyValue> current_value = input_position_builder[i]; |
| |
| if (current_value->GetTypeId() == base::GetTypeId<CalcValue>()) { |
| // If it is already a CalcValue, nothing needs to be done. |
| (*output_position_builder)[i] = current_value; |
| } else if (current_value->GetTypeId() == base::GetTypeId<KeywordValue>()) { |
| FillPositionBuilderFromOriginAndOffset(current_value, NULL, |
| output_position_builder); |
| } else { |
| OriginInfo default_origin = OriginInfo(0.0f, 1, kNone); |
| (*output_position_builder)[i] = |
| ProvideCalcValueFromOriginAndOffset(&default_origin, current_value); |
| } |
| } |
| } |
| |
| // If three values are given, then there are two cases: |
| // 1. <KeywordValue Length/Percentage KeywordValue> |
| // 2. <KeywordValue KeywordValue Length/Percentage> |
| // If four values are given, then each <percentage> or <length> represents |
| // an offset and must be preceded by a keyword, which specifies from which |
| // edge the offset is given. Keyword cannot be 'center'. The pattern is |
| // <KeywordValue Length/Percentage KeywordValue Length/Percentage> |
| void ComputedPositionHelper::ComputeThreeOrFourValuesPosition( |
| const PropertyListValue::Builder& input_position_builder, |
| PropertyListValue::Builder* output_position_builder) { |
| DCHECK_GT(input_position_builder.size(), 2u); |
| DCHECK_LE(input_position_builder.size(), 4u); |
| |
| for (size_t i = 0; i < input_position_builder.size(); ++i) { |
| scoped_refptr<PropertyValue> previous_value = |
| (i == 0) ? NULL : input_position_builder[i - 1]; |
| |
| scoped_refptr<PropertyValue> current_value = input_position_builder[i]; |
| |
| if (current_value->GetTypeId() == base::GetTypeId<KeywordValue>()) { |
| FillPositionBuilderFromOriginAndOffset(current_value, NULL, |
| output_position_builder); |
| } else { |
| DCHECK(previous_value); |
| DCHECK(previous_value->GetTypeId() == base::GetTypeId<KeywordValue>()); |
| FillPositionBuilderFromOriginAndOffset(previous_value, current_value, |
| output_position_builder); |
| } |
| } |
| } |
| |
| // 1) 'top' computes to '0%' for the vertical position if one or two values are |
| // given, otherwise specifies the top edge as the origin for the next |
| // offset. |
| // 2) 'right' computes to '100%' for the horizontal position if one or two |
| // values are given, otherwise specifies the right edge as the origin for |
| // the next offset. |
| // 3) 'bottom' computes to '100%' for the vertical position if one or two values |
| // are given, otherwise specifies the bottom edge as the origin for the |
| // the next offset. |
| // 4) 'left' computes to '0%' for the horizontal position if one or two values |
| // are given, otherwise specifies the left edge as the origin for the next |
| // offset. |
| // 5) 'center' computes to '50%' (left 50%) for the horizontal position if |
| // horizontal position is not specified, or '50%' (right 50%) for the |
| // vertical position is not specified. |
| const ComputedPositionHelper::OriginInfo |
| ComputedPositionHelper::ConvertToOriginInfo( |
| const scoped_refptr<PropertyValue>& keyword) const { |
| DCHECK(keyword->GetTypeId() == base::GetTypeId<KeywordValue>()); |
| |
| if (keyword == KeywordValue::GetLeft()) { |
| return OriginInfo(0.0f, 1, kHorizontal); |
| } else if (keyword == KeywordValue::GetRight()) { |
| return OriginInfo(1.0f, -1, kHorizontal); |
| } else if (keyword == KeywordValue::GetTop()) { |
| return OriginInfo(0.0f, 1, kVertical); |
| } else if (keyword == KeywordValue::GetBottom()) { |
| return OriginInfo(1.0f, -1, kVertical); |
| } else { |
| return OriginInfo(0.5f, 1, kCenter); |
| } |
| } |
| |
| // If the |offset| is specified, the |origin| specifies from which edge |
| // the offset is given. Otherwise, the |origin| indicates the corresponding |
| // percentage value to the upper left corner for the horizontal/vertical |
| // position. The horizontal and vertical values are stored as CalcValue in |
| // computed style. eg: (background-position: bottom 20px left 40%;) would be |
| // computed as Calc(0px, 40%), Calc(-20px, 100%) |
| scoped_refptr<CalcValue> |
| ComputedPositionHelper::ProvideCalcValueFromOriginAndOffset( |
| OriginInfo* origin_info, const scoped_refptr<PropertyValue>& offset) { |
| DCHECK(origin_info); |
| |
| if (!offset) { |
| return new CalcValue( |
| new PercentageValue(origin_info->origin_as_percentage)); |
| } |
| |
| scoped_refptr<LengthValue> length_value; |
| scoped_refptr<PercentageValue> percentage_value; |
| if (offset->GetTypeId() == base::GetTypeId<LengthValue>()) { |
| scoped_refptr<LengthValue> length_provider = ProvideAbsoluteLength( |
| base::polymorphic_downcast<LengthValue*>(offset.get()), |
| computed_font_size_, root_computed_font_size_, viewport_size_); |
| length_value = new LengthValue( |
| origin_info->offset_multiplier * length_provider->value(), |
| length_provider->unit()); |
| percentage_value = new PercentageValue(origin_info->origin_as_percentage); |
| |
| return new CalcValue(length_value, percentage_value); |
| } else { |
| DCHECK(offset->GetTypeId() == base::GetTypeId<PercentageValue>()); |
| PercentageValue* percentage = |
| base::polymorphic_downcast<PercentageValue*>(offset.get()); |
| percentage_value = new PercentageValue(origin_info->origin_as_percentage + |
| origin_info->offset_multiplier * |
| percentage->value()); |
| |
| return new CalcValue(percentage_value); |
| } |
| } |
| |
| void ComputedPositionHelper::FillPositionBuilderFromOriginAndOffset( |
| const scoped_refptr<PropertyValue>& origin, |
| const scoped_refptr<PropertyValue>& offset, |
| PropertyListValue::Builder* output_position_builder) { |
| DCHECK(origin->GetTypeId() == base::GetTypeId<KeywordValue>()); |
| |
| OriginInfo origin_info = ConvertToOriginInfo(origin); |
| switch (origin_info.direction) { |
| case kHorizontal: { |
| (*output_position_builder)[0] = |
| ProvideCalcValueFromOriginAndOffset(&origin_info, offset); |
| break; |
| } |
| case kVertical: { |
| (*output_position_builder)[1] = |
| ProvideCalcValueFromOriginAndOffset(&origin_info, offset); |
| break; |
| } |
| case kCenter: { |
| if (!(*output_position_builder)[0]) { |
| (*output_position_builder)[0] = |
| ProvideCalcValueFromOriginAndOffset(&origin_info, offset); |
| } |
| if (!(*output_position_builder)[1]) { |
| (*output_position_builder)[1] = |
| ProvideCalcValueFromOriginAndOffset(&origin_info, offset); |
| } |
| break; |
| } |
| case kNone: // fall-through |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| } // namespace |
| |
| // Absolutizes the value of "background-image" property. |
| // Computed value: as specified, but with URIs made absolute. |
| // https://www.w3.org/TR/css3-background/#the-background-image |
| class ComputedBackgroundImageSingleLayerProvider |
| : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedBackgroundImageSingleLayerProvider( |
| const GURL& base_url, const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size) |
| : base_url_(base_url), |
| computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size) {} |
| |
| void VisitKeyword(KeywordValue* keyword) OVERRIDE; |
| void VisitLinearGradient(LinearGradientValue* linear_gradient_value) OVERRIDE; |
| void VisitRadialGradient(RadialGradientValue* radial_gradient_value) OVERRIDE; |
| void VisitURL(URLValue* url_value) OVERRIDE; |
| |
| const scoped_refptr<PropertyValue>& computed_background_image() const { |
| return computed_background_image_; |
| } |
| |
| private: |
| const GURL base_url_; |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| |
| scoped_refptr<PropertyValue> computed_background_image_; |
| }; |
| |
| void ComputedBackgroundImageSingleLayerProvider::VisitKeyword( |
| KeywordValue* keyword) { |
| switch (keyword->value()) { |
| case KeywordValue::kNone: |
| computed_background_image_ = keyword; |
| break; |
| case KeywordValue::kAbsolute: |
| case KeywordValue::kAlternate: |
| case KeywordValue::kAlternateReverse: |
| case KeywordValue::kAuto: |
| case KeywordValue::kBackwards: |
| case KeywordValue::kBaseline: |
| case KeywordValue::kBlock: |
| case KeywordValue::kBoth: |
| case KeywordValue::kBottom: |
| case KeywordValue::kBreakWord: |
| case KeywordValue::kCenter: |
| case KeywordValue::kClip: |
| case KeywordValue::kContain: |
| case KeywordValue::kCover: |
| case KeywordValue::kCurrentColor: |
| case KeywordValue::kCursive: |
| case KeywordValue::kEllipsis: |
| case KeywordValue::kEnd: |
| case KeywordValue::kEquirectangular: |
| case KeywordValue::kFantasy: |
| case KeywordValue::kFixed: |
| case KeywordValue::kForwards: |
| case KeywordValue::kHidden: |
| case KeywordValue::kInfinite: |
| case KeywordValue::kInherit: |
| case KeywordValue::kInitial: |
| case KeywordValue::kInline: |
| case KeywordValue::kInlineBlock: |
| case KeywordValue::kLeft: |
| case KeywordValue::kLineThrough: |
| case KeywordValue::kMiddle: |
| case KeywordValue::kMonoscopic: |
| case KeywordValue::kMonospace: |
| case KeywordValue::kNoRepeat: |
| case KeywordValue::kNormal: |
| case KeywordValue::kNoWrap: |
| case KeywordValue::kPre: |
| case KeywordValue::kPreLine: |
| case KeywordValue::kPreWrap: |
| case KeywordValue::kRelative: |
| case KeywordValue::kRepeat: |
| case KeywordValue::kReverse: |
| case KeywordValue::kRight: |
| case KeywordValue::kSansSerif: |
| case KeywordValue::kSerif: |
| case KeywordValue::kSolid: |
| case KeywordValue::kStart: |
| case KeywordValue::kStatic: |
| case KeywordValue::kStereoscopicLeftRight: |
| case KeywordValue::kStereoscopicTopBottom: |
| case KeywordValue::kTop: |
| case KeywordValue::kUppercase: |
| case KeywordValue::kVisible: |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| namespace { |
| ColorStopList ComputeColorStopList(const ColorStopList& color_stops, |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size) { |
| ColorStopList computed_color_stops; |
| computed_color_stops.reserve(color_stops.size()); |
| |
| for (ColorStopList::const_iterator iter = color_stops.begin(); |
| iter != color_stops.end(); ++iter) { |
| const ColorStop& color_stop = **iter; |
| |
| computed_color_stops.push_back(new ColorStop( |
| color_stop.rgba(), ProvideAbsoluteLengthIfNonNullLength( |
| color_stop.position(), computed_font_size, |
| root_computed_font_size, viewport_size))); |
| } |
| |
| return computed_color_stops.Pass(); |
| } |
| } // namespace |
| |
| void ComputedBackgroundImageSingleLayerProvider::VisitLinearGradient( |
| LinearGradientValue* linear_gradient_value) { |
| // We must walk through the list of color stop positions and absolutize the |
| // any length values. |
| ColorStopList computed_color_stops = ComputeColorStopList( |
| linear_gradient_value->color_stop_list(), computed_font_size_, |
| root_computed_font_size_, viewport_size_); |
| |
| if (linear_gradient_value->angle_in_radians()) { |
| computed_background_image_ = |
| new LinearGradientValue(*linear_gradient_value->angle_in_radians(), |
| computed_color_stops.Pass()); |
| } else { |
| computed_background_image_ = new LinearGradientValue( |
| *linear_gradient_value->side_or_corner(), computed_color_stops.Pass()); |
| } |
| } |
| |
| namespace { |
| scoped_refptr<PropertyListValue> CalculateComputedRadialGradientPosition( |
| const scoped_refptr<PropertyListValue>& specified_position, |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size) { |
| if (!specified_position) { |
| // If no position is specified, we default to 'center'. |
| scoped_ptr<PropertyListValue::Builder> builder( |
| new PropertyListValue::Builder(2, new PercentageValue(0.5f))); |
| return new PropertyListValue(builder.Pass()); |
| } |
| |
| size_t size = specified_position->value().size(); |
| DCHECK_GE(size, 1u); |
| DCHECK_LE(size, 4u); |
| |
| ComputedPositionHelper position_helper( |
| computed_font_size, root_computed_font_size, viewport_size); |
| scoped_ptr<PropertyListValue::Builder> computed_position_builder( |
| new PropertyListValue::Builder(2, scoped_refptr<PropertyValue>())); |
| position_helper.ComputePosition(specified_position->value(), |
| computed_position_builder.get()); |
| |
| return new PropertyListValue(computed_position_builder.Pass()); |
| } |
| } // namespace |
| |
| void ComputedBackgroundImageSingleLayerProvider::VisitRadialGradient( |
| RadialGradientValue* radial_gradient_value) { |
| // We must walk through the list of color stop positions and absolutize the |
| // any length values. |
| ColorStopList computed_color_stops = ComputeColorStopList( |
| radial_gradient_value->color_stop_list(), computed_font_size_, |
| root_computed_font_size_, viewport_size_); |
| |
| // The center of the gradient must be absolutized if it is a length. |
| scoped_refptr<PropertyListValue> computed_position = |
| CalculateComputedRadialGradientPosition( |
| radial_gradient_value->position(), computed_font_size_, |
| root_computed_font_size_, viewport_size_); |
| |
| // If the radial gradient specifies size values, they must also be absolutized |
| // if they are lengths. |
| if (radial_gradient_value->size_value()) { |
| computed_background_image_ = new RadialGradientValue( |
| radial_gradient_value->shape(), |
| ProvideAbsoluteLengthsForNonNullLengthsInList( |
| radial_gradient_value->size_value(), computed_font_size_, |
| root_computed_font_size_, viewport_size_), |
| computed_position, computed_color_stops.Pass()); |
| } else { |
| computed_background_image_ = new RadialGradientValue( |
| radial_gradient_value->shape(), *radial_gradient_value->size_keyword(), |
| computed_position, computed_color_stops.Pass()); |
| } |
| } |
| |
| void ComputedBackgroundImageSingleLayerProvider::VisitURL(URLValue* url_value) { |
| if (url_value->value().empty()) { |
| // No need to convert URLValue into AbsoluteURLValue. |
| computed_background_image_ = KeywordValue::GetNone(); |
| return; |
| } |
| |
| GURL absolute_url; |
| if (url_value->is_absolute()) { |
| absolute_url = GURL(url_value->value()); |
| } else { |
| absolute_url = url_value->Resolve(base_url_); |
| } |
| |
| if (!absolute_url.is_valid()) { |
| DLOG(WARNING) << "Invalid url: " << absolute_url.spec(); |
| // No further process is needed if the url is invalid. |
| computed_background_image_ = KeywordValue::GetNone(); |
| return; |
| } |
| |
| computed_background_image_ = new AbsoluteURLValue(absolute_url); |
| } |
| |
| class ComputedBackgroundImageProvider : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedBackgroundImageProvider(const GURL& base_url, |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size) |
| : base_url_(base_url), |
| computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size) {} |
| |
| void VisitPropertyList(PropertyListValue* property_list_value) OVERRIDE; |
| |
| const scoped_refptr<PropertyValue>& computed_background_image() const { |
| return computed_background_image_; |
| } |
| |
| private: |
| const GURL base_url_; |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| |
| scoped_refptr<PropertyValue> computed_background_image_; |
| }; |
| |
| void ComputedBackgroundImageProvider::VisitPropertyList( |
| PropertyListValue* property_list_value) { |
| scoped_ptr<PropertyListValue::Builder> builder( |
| new PropertyListValue::Builder()); |
| builder->reserve(property_list_value->value().size()); |
| |
| ComputedBackgroundImageSingleLayerProvider single_layer_provider( |
| base_url_, computed_font_size_, root_computed_font_size_, viewport_size_); |
| for (size_t i = 0; i < property_list_value->value().size(); ++i) { |
| property_list_value->value()[i]->Accept(&single_layer_provider); |
| scoped_refptr<PropertyValue> computed_background_image = |
| single_layer_provider.computed_background_image(); |
| builder->push_back(computed_background_image); |
| } |
| |
| computed_background_image_ = new PropertyListValue(builder.Pass()); |
| } |
| |
| class ComputedBackgroundSizeSingleValueProvider |
| : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedBackgroundSizeSingleValueProvider( |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size); |
| |
| void VisitLength(LengthValue* length) OVERRIDE; |
| void VisitPercentage(PercentageValue* percentage) OVERRIDE; |
| void VisitKeyword(KeywordValue* keyword) OVERRIDE; |
| |
| const scoped_refptr<PropertyValue>& computed_background_size() const { |
| return computed_background_size_; |
| } |
| |
| private: |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| |
| scoped_refptr<PropertyValue> computed_background_size_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedBackgroundSizeSingleValueProvider); |
| }; |
| |
| ComputedBackgroundSizeSingleValueProvider:: |
| ComputedBackgroundSizeSingleValueProvider( |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size) |
| : computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size) {} |
| |
| void ComputedBackgroundSizeSingleValueProvider::VisitLength( |
| LengthValue* length) { |
| computed_background_size_ = ProvideAbsoluteLength( |
| length, computed_font_size_, root_computed_font_size_, viewport_size_); |
| } |
| |
| void ComputedBackgroundSizeSingleValueProvider::VisitPercentage( |
| PercentageValue* percentage) { |
| computed_background_size_ = percentage; |
| } |
| |
| void ComputedBackgroundSizeSingleValueProvider::VisitKeyword( |
| KeywordValue* keyword) { |
| switch (keyword->value()) { |
| case KeywordValue::kAuto: |
| case KeywordValue::kContain: |
| case KeywordValue::kCover: |
| computed_background_size_ = keyword; |
| break; |
| |
| case KeywordValue::kAbsolute: |
| case KeywordValue::kAlternate: |
| case KeywordValue::kAlternateReverse: |
| case KeywordValue::kBackwards: |
| case KeywordValue::kBaseline: |
| case KeywordValue::kBlock: |
| case KeywordValue::kBoth: |
| case KeywordValue::kBottom: |
| case KeywordValue::kBreakWord: |
| case KeywordValue::kCenter: |
| case KeywordValue::kClip: |
| case KeywordValue::kCurrentColor: |
| case KeywordValue::kCursive: |
| case KeywordValue::kEllipsis: |
| case KeywordValue::kEnd: |
| case KeywordValue::kEquirectangular: |
| case KeywordValue::kFantasy: |
| case KeywordValue::kFixed: |
| case KeywordValue::kForwards: |
| case KeywordValue::kHidden: |
| case KeywordValue::kInfinite: |
| case KeywordValue::kInherit: |
| case KeywordValue::kInitial: |
| case KeywordValue::kInline: |
| case KeywordValue::kInlineBlock: |
| case KeywordValue::kLeft: |
| case KeywordValue::kLineThrough: |
| case KeywordValue::kMiddle: |
| case KeywordValue::kMonoscopic: |
| case KeywordValue::kMonospace: |
| case KeywordValue::kNone: |
| case KeywordValue::kNoRepeat: |
| case KeywordValue::kNormal: |
| case KeywordValue::kNoWrap: |
| case KeywordValue::kPre: |
| case KeywordValue::kPreLine: |
| case KeywordValue::kPreWrap: |
| case KeywordValue::kRelative: |
| case KeywordValue::kRepeat: |
| case KeywordValue::kReverse: |
| case KeywordValue::kRight: |
| case KeywordValue::kSansSerif: |
| case KeywordValue::kSerif: |
| case KeywordValue::kSolid: |
| case KeywordValue::kStart: |
| case KeywordValue::kStatic: |
| case KeywordValue::kStereoscopicLeftRight: |
| case KeywordValue::kStereoscopicTopBottom: |
| case KeywordValue::kTop: |
| case KeywordValue::kUppercase: |
| case KeywordValue::kVisible: |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| // ComputedBackgroundPositionProvider provides a property list which has two |
| // CalcValue. Each of CalcValue has two parts <percentage> and <length>. |
| // <percentage> and <length> values here represent an offset of the top left |
| // corner of the background image from the top left corner of the background |
| // positioning area. |
| // https://www.w3.org/TR/css3-background/#the-background-position |
| class ComputedBackgroundPositionProvider |
| : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedBackgroundPositionProvider(const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size); |
| |
| void VisitPropertyList(PropertyListValue* property_list_value) OVERRIDE; |
| |
| const scoped_refptr<PropertyValue>& computed_background_position() const { |
| return computed_background_position_; |
| } |
| |
| private: |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| |
| scoped_refptr<PropertyValue> computed_background_position_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedBackgroundPositionProvider); |
| }; |
| |
| ComputedBackgroundPositionProvider::ComputedBackgroundPositionProvider( |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size) |
| : computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size) {} |
| |
| void ComputedBackgroundPositionProvider::VisitPropertyList( |
| PropertyListValue* property_list_value) { |
| size_t size = property_list_value->value().size(); |
| DCHECK_GE(size, 1u); |
| DCHECK_LE(size, 4u); |
| |
| ComputedPositionHelper position_helper( |
| computed_font_size_, root_computed_font_size_, viewport_size_); |
| scoped_ptr<PropertyListValue::Builder> background_position_builder( |
| new PropertyListValue::Builder(2, scoped_refptr<PropertyValue>())); |
| |
| position_helper.ComputePosition(property_list_value->value(), |
| background_position_builder.get()); |
| |
| computed_background_position_ = |
| new PropertyListValue(background_position_builder.Pass()); |
| } |
| |
| class ComputedBackgroundSizeProvider : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedBackgroundSizeProvider(const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size); |
| |
| void VisitKeyword(KeywordValue* keyword) OVERRIDE; |
| void VisitPropertyList(PropertyListValue* property_list_value) OVERRIDE; |
| |
| const scoped_refptr<PropertyValue>& computed_background_size() const { |
| return computed_background_size_; |
| } |
| |
| private: |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| |
| scoped_refptr<PropertyValue> computed_background_size_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedBackgroundSizeProvider); |
| }; |
| |
| ComputedBackgroundSizeProvider::ComputedBackgroundSizeProvider( |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size) |
| : computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size) {} |
| |
| void ComputedBackgroundSizeProvider::VisitKeyword(KeywordValue* keyword) { |
| computed_background_size_ = keyword; |
| } |
| |
| void ComputedBackgroundSizeProvider::VisitPropertyList( |
| PropertyListValue* property_list_value) { |
| ComputedBackgroundSizeSingleValueProvider left_value_provider( |
| computed_font_size_, root_computed_font_size_, viewport_size_); |
| property_list_value->value()[0]->Accept(&left_value_provider); |
| |
| ComputedBackgroundSizeSingleValueProvider right_value_provider( |
| computed_font_size_, root_computed_font_size_, viewport_size_); |
| property_list_value->value()[1]->Accept(&right_value_provider); |
| |
| scoped_ptr<PropertyListValue::Builder> builder( |
| new PropertyListValue::Builder()); |
| builder->reserve(2); |
| builder->push_back(left_value_provider.computed_background_size()); |
| builder->push_back(right_value_provider.computed_background_size()); |
| computed_background_size_ = new PropertyListValue(builder.Pass()); |
| } |
| |
| // https://www.w3.org/TR/css3-background/#border-radius |
| class ComputedBorderRadiusProvider : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedBorderRadiusProvider(const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size); |
| |
| void VisitLength(LengthValue* specified_length); |
| void VisitPercentage(PercentageValue* percentage); |
| |
| const scoped_refptr<PropertyValue>& computed_border_radius() const { |
| return computed_border_radius_; |
| } |
| |
| private: |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| |
| scoped_refptr<PropertyValue> computed_border_radius_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedBorderRadiusProvider); |
| }; |
| |
| ComputedBorderRadiusProvider::ComputedBorderRadiusProvider( |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size) |
| : computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size) {} |
| |
| void ComputedBorderRadiusProvider::VisitLength(LengthValue* specified_length) { |
| computed_border_radius_ = |
| ProvideAbsoluteLength(specified_length, computed_font_size_, |
| root_computed_font_size_, viewport_size_); |
| } |
| |
| void ComputedBorderRadiusProvider::VisitPercentage( |
| PercentageValue* percentage) { |
| computed_border_radius_ = percentage; |
| } |
| |
| // Computed value: any <length> made absolute; any specified color computed; |
| // otherwise as specified. |
| // https://www.w3.org/TR/css3-background/#box-shadow |
| // https://www.w3.org/TR/css-text-decor-3/#text-shadow-property |
| class ComputedShadowProvider : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedShadowProvider(const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size, |
| const RGBAColorValue* computed_color); |
| |
| void VisitKeyword(KeywordValue* keyword) OVERRIDE; |
| void VisitPropertyList(PropertyListValue* property_list_value) OVERRIDE; |
| |
| const scoped_refptr<PropertyValue>& computed_shadow() const { |
| return computed_shadow_; |
| } |
| |
| private: |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| const RGBAColorValue* computed_color_; |
| |
| scoped_refptr<PropertyValue> computed_shadow_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedShadowProvider); |
| }; |
| |
| ComputedShadowProvider::ComputedShadowProvider( |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size, |
| const RGBAColorValue* computed_color) |
| : computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size), |
| computed_color_(computed_color) {} |
| |
| void ComputedShadowProvider::VisitKeyword(KeywordValue* keyword) { |
| switch (keyword->value()) { |
| case KeywordValue::kNone: |
| computed_shadow_ = keyword; |
| break; |
| |
| case KeywordValue::kAbsolute: |
| case KeywordValue::kAlternate: |
| case KeywordValue::kAlternateReverse: |
| case KeywordValue::kAuto: |
| case KeywordValue::kBackwards: |
| case KeywordValue::kBaseline: |
| case KeywordValue::kBlock: |
| case KeywordValue::kBoth: |
| case KeywordValue::kBottom: |
| case KeywordValue::kBreakWord: |
| case KeywordValue::kCenter: |
| case KeywordValue::kClip: |
| case KeywordValue::kContain: |
| case KeywordValue::kCover: |
| case KeywordValue::kCurrentColor: |
| case KeywordValue::kCursive: |
| case KeywordValue::kEllipsis: |
| case KeywordValue::kEnd: |
| case KeywordValue::kEquirectangular: |
| case KeywordValue::kFantasy: |
| case KeywordValue::kForwards: |
| case KeywordValue::kFixed: |
| case KeywordValue::kHidden: |
| case KeywordValue::kInfinite: |
| case KeywordValue::kInherit: |
| case KeywordValue::kInitial: |
| case KeywordValue::kInline: |
| case KeywordValue::kInlineBlock: |
| case KeywordValue::kLeft: |
| case KeywordValue::kLineThrough: |
| case KeywordValue::kMiddle: |
| case KeywordValue::kMonoscopic: |
| case KeywordValue::kMonospace: |
| case KeywordValue::kNormal: |
| case KeywordValue::kNoRepeat: |
| case KeywordValue::kNoWrap: |
| case KeywordValue::kPre: |
| case KeywordValue::kPreLine: |
| case KeywordValue::kPreWrap: |
| case KeywordValue::kRelative: |
| case KeywordValue::kRepeat: |
| case KeywordValue::kReverse: |
| case KeywordValue::kRight: |
| case KeywordValue::kSansSerif: |
| case KeywordValue::kSerif: |
| case KeywordValue::kSolid: |
| case KeywordValue::kStart: |
| case KeywordValue::kStatic: |
| case KeywordValue::kStereoscopicLeftRight: |
| case KeywordValue::kStereoscopicTopBottom: |
| case KeywordValue::kTop: |
| case KeywordValue::kUppercase: |
| case KeywordValue::kVisible: |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| void ComputedShadowProvider::VisitPropertyList( |
| PropertyListValue* property_list_value) { |
| scoped_ptr<PropertyListValue::Builder> builder( |
| new PropertyListValue::Builder()); |
| builder->reserve(property_list_value->value().size()); |
| |
| for (size_t i = 0; i < property_list_value->value().size(); ++i) { |
| ShadowValue* shadow_value = base::polymorphic_downcast<ShadowValue*>( |
| property_list_value->value()[i].get()); |
| |
| scoped_refptr<LengthValue> computed_lengths[ShadowValue::kMaxLengths]; |
| for (int j = 0; j < ShadowValue::kMaxLengths; ++j) { |
| LengthValue* specified_length = shadow_value->lengths()[j].get(); |
| if (specified_length) { |
| computed_lengths[j] = |
| ProvideAbsoluteLength(specified_length, computed_font_size_, |
| root_computed_font_size_, viewport_size_); |
| } |
| } |
| |
| scoped_refptr<RGBAColorValue> color = shadow_value->color(); |
| if (!color) { |
| color = new RGBAColorValue(computed_color_->value()); |
| } |
| |
| builder->push_back( |
| new ShadowValue(computed_lengths, color, shadow_value->has_inset())); |
| } |
| |
| computed_shadow_ = new PropertyListValue(builder.Pass()); |
| } |
| |
| // Computed value: for length of translation transforms. |
| // https://www.w3.org/TR/css3-transforms/#propdef-transform |
| class ComputedTransformFunctionProvider : public TransformFunctionVisitor { |
| public: |
| ComputedTransformFunctionProvider(const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size); |
| |
| void VisitMatrix(const MatrixFunction* matrix_function) OVERRIDE; |
| void VisitRotate(const RotateFunction* rotate_function) OVERRIDE; |
| void VisitScale(const ScaleFunction* scale_function) OVERRIDE; |
| void VisitTranslate(const TranslateFunction* translate_function) OVERRIDE; |
| |
| scoped_ptr<TransformFunction> PassComputedTransformFunction() { |
| return computed_transform_function_.Pass(); |
| } |
| |
| private: |
| scoped_ptr<TransformFunction> computed_transform_function_; |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| }; |
| |
| ComputedTransformFunctionProvider::ComputedTransformFunctionProvider( |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size) |
| : computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size) {} |
| |
| void ComputedTransformFunctionProvider::VisitMatrix( |
| const MatrixFunction* matrix_function) { |
| computed_transform_function_.reset(new MatrixFunction(*matrix_function)); |
| } |
| |
| void ComputedTransformFunctionProvider::VisitRotate( |
| const RotateFunction* rotate_function) { |
| computed_transform_function_.reset(new RotateFunction(*rotate_function)); |
| } |
| |
| void ComputedTransformFunctionProvider::VisitScale( |
| const ScaleFunction* scale_function) { |
| computed_transform_function_.reset(new ScaleFunction(*scale_function)); |
| } |
| |
| void ComputedTransformFunctionProvider::VisitTranslate( |
| const TranslateFunction* translate_function) { |
| switch (translate_function->offset_type()) { |
| case TranslateFunction::kLength: { |
| computed_transform_function_.reset(new TranslateFunction( |
| translate_function->axis(), |
| ProvideAbsoluteLength(translate_function->offset_as_length(), |
| computed_font_size_, root_computed_font_size_, |
| viewport_size_))); |
| } break; |
| case TranslateFunction::kPercentage: { |
| computed_transform_function_.reset( |
| new TranslateFunction(*translate_function)); |
| } break; |
| case TranslateFunction::kCalc: { |
| scoped_refptr<CalcValue> calc_value = |
| translate_function->offset_as_calc(); |
| computed_transform_function_.reset(new TranslateFunction( |
| translate_function->axis(), |
| new CalcValue(ProvideAbsoluteLength( |
| calc_value->length_value(), computed_font_size_, |
| root_computed_font_size_, viewport_size_), |
| calc_value->percentage_value()))); |
| } break; |
| default: { NOTREACHED(); } |
| } |
| } |
| |
| // Absolutizes the value of "text-indent" property. |
| class ComputedTextIndentProvider : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedTextIndentProvider(const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size); |
| |
| void VisitLength(LengthValue* length) OVERRIDE; |
| |
| const scoped_refptr<LengthValue>& computed_text_indent() const { |
| return computed_text_indent_; |
| } |
| |
| private: |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| |
| scoped_refptr<LengthValue> computed_text_indent_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedTextIndentProvider); |
| }; |
| |
| ComputedTextIndentProvider::ComputedTextIndentProvider( |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size) |
| : computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size) {} |
| |
| void ComputedTextIndentProvider::VisitLength(LengthValue* specified_length) { |
| computed_text_indent_ = |
| ProvideAbsoluteLength(specified_length, computed_font_size_, |
| root_computed_font_size_, viewport_size_); |
| } |
| |
| // ComputedTransformOriginProvider provides a property list which has three |
| // PropertyValues. The first two PropertyValues are CalcValue to represent |
| // the horizontal position (or offset) and the vertical position (or offset). |
| // The third value always represents the Z position (or offset) and must be a |
| // LengthValue. |
| // https://www.w3.org/TR/css3-transforms/#propdef-transform-origin |
| class ComputedTransformOriginProvider : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedTransformOriginProvider(const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size); |
| |
| void VisitPropertyList(PropertyListValue* property_list_value) OVERRIDE; |
| |
| const scoped_refptr<PropertyValue>& computed_transform_origin() const { |
| return computed_transform_origin_; |
| } |
| |
| private: |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| |
| scoped_refptr<PropertyValue> computed_transform_origin_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedTransformOriginProvider); |
| }; |
| |
| ComputedTransformOriginProvider::ComputedTransformOriginProvider( |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size) |
| : computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size) {} |
| |
| void ComputedTransformOriginProvider::VisitPropertyList( |
| PropertyListValue* property_list_value) { |
| size_t size = property_list_value->value().size(); |
| DCHECK_GE(size, 1u); |
| DCHECK_LE(size, 3u); |
| |
| ComputedPositionHelper position_helper( |
| computed_font_size_, root_computed_font_size_, viewport_size_); |
| scoped_ptr<PropertyListValue::Builder> transform_origin_builder( |
| new PropertyListValue::Builder(3, scoped_refptr<PropertyValue>())); |
| |
| // If one or two values are specified, the third value is assumed to be 0px. |
| switch (size) { |
| case 1: |
| case 2: |
| position_helper.ComputePosition(property_list_value->value(), |
| transform_origin_builder.get()); |
| (*transform_origin_builder)[2] = new LengthValue(0.0f, kPixelsUnit); |
| break; |
| case 3: |
| position_helper.ComputeTwoValuesPosition(property_list_value->value(), |
| transform_origin_builder.get()); |
| // The third value must be LengthValue type. |
| (*transform_origin_builder)[2] = ProvideAbsoluteLength( |
| base::polymorphic_downcast<LengthValue*>( |
| property_list_value->value()[2].get()), |
| computed_font_size_, root_computed_font_size_, viewport_size_); |
| break; |
| default: |
| NOTREACHED(); |
| } |
| |
| computed_transform_origin_ = |
| new PropertyListValue(transform_origin_builder.Pass()); |
| } |
| |
| namespace { |
| |
| // Functionality to check if a transform contains any relative units, such as |
| // "em" or "rem". |
| |
| class TransformFunctionContainsRelativeUnitVisitor |
| : public TransformFunctionVisitor { |
| public: |
| TransformFunctionContainsRelativeUnitVisitor() |
| : contains_relative_unit_(false) {} |
| |
| void VisitMatrix(const MatrixFunction* matrix_function) OVERRIDE { |
| UNREFERENCED_PARAMETER(matrix_function); |
| } |
| void VisitRotate(const RotateFunction* rotate_function) OVERRIDE { |
| UNREFERENCED_PARAMETER(rotate_function); |
| } |
| void VisitScale(const ScaleFunction* scale_function) OVERRIDE { |
| UNREFERENCED_PARAMETER(scale_function); |
| } |
| void VisitTranslate(const TranslateFunction* translate_function) OVERRIDE { |
| contains_relative_unit_ = |
| translate_function->offset_type() == TranslateFunction::kLength && |
| translate_function->offset_as_length()->IsUnitRelative(); |
| } |
| |
| bool contains_relative_unit() const { return contains_relative_unit_; } |
| |
| private: |
| bool contains_relative_unit_; |
| }; |
| |
| bool TransformListContainsRelativeUnits( |
| TransformFunctionListValue* transform_function_list) { |
| for (TransformFunctionListValue::Builder::const_iterator iter = |
| transform_function_list->value().begin(); |
| iter != transform_function_list->value().end(); ++iter) { |
| TransformFunction* transform_function = *iter; |
| |
| TransformFunctionContainsRelativeUnitVisitor contains_ems_visitor; |
| transform_function->Accept(&contains_ems_visitor); |
| if (contains_ems_visitor.contains_relative_unit()) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| } // namespace |
| |
| class ComputedTransformProvider : public NotReachedPropertyValueVisitor { |
| public: |
| ComputedTransformProvider(const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, |
| const math::Size& viewport_size); |
| |
| void VisitKeyword(KeywordValue* keyword) OVERRIDE; |
| void VisitTransformFunctionList( |
| TransformFunctionListValue* transform_function_list) OVERRIDE; |
| |
| const scoped_refptr<PropertyValue>& computed_transform_list() const { |
| return computed_transform_list_; |
| } |
| |
| private: |
| const LengthValue* computed_font_size_; |
| const LengthValue* root_computed_font_size_; |
| const math::Size& viewport_size_; |
| |
| scoped_refptr<PropertyValue> computed_transform_list_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ComputedTransformProvider); |
| }; |
| |
| ComputedTransformProvider::ComputedTransformProvider( |
| const LengthValue* computed_font_size, |
| const LengthValue* root_computed_font_size, const math::Size& viewport_size) |
| : computed_font_size_(computed_font_size), |
| root_computed_font_size_(root_computed_font_size), |
| viewport_size_(viewport_size) {} |
| |
| void ComputedTransformProvider::VisitTransformFunctionList( |
| TransformFunctionListValue* transform_function_list) { |
| if (!TransformListContainsRelativeUnits(transform_function_list)) { |
| // If the transform list contains no transforms that use relative units, |
| // then we do not need to do anything and we can pass through the existing |
| // transform. |
| computed_transform_list_ = transform_function_list; |
| } else { |
| // The transform list contains at least one transform with relative units. |
| // In this case, rebuild the transform list with computed length values. |
| TransformFunctionListValue::Builder computed_list_builder; |
| |
| for (TransformFunctionListValue::Builder::const_iterator iter = |
| transform_function_list->value().begin(); |
| iter != transform_function_list->value().end(); ++iter) { |
| TransformFunction* transform_function = *iter; |
| |
| ComputedTransformFunctionProvider computed_transform_function_provider( |
| computed_font_size_, root_computed_font_size_, viewport_size_); |
| transform_function->Accept(&computed_transform_function_provider); |
| |
| computed_list_builder.push_back( |
| computed_transform_function_provider.PassComputedTransformFunction() |
| .release()); |
| } |
| |
| computed_transform_list_ = |
| new TransformFunctionListValue(computed_list_builder.Pass()); |
| } |
| } |
| |
| void ComputedTransformProvider::VisitKeyword(KeywordValue* keyword) { |
| switch (keyword->value()) { |
| case KeywordValue::kNone: |
| computed_transform_list_ = keyword; |
| break; |
| case KeywordValue::kAbsolute: |
| case KeywordValue::kAlternate: |
| case KeywordValue::kAlternateReverse: |
| case KeywordValue::kAuto: |
| case KeywordValue::kBackwards: |
| case KeywordValue::kBaseline: |
| case KeywordValue::kBlock: |
| case KeywordValue::kBoth: |
| case KeywordValue::kBottom: |
| case KeywordValue::kBreakWord: |
| case KeywordValue::kCenter: |
| case KeywordValue::kClip: |
| case KeywordValue::kContain: |
| case KeywordValue::kCover: |
| case KeywordValue::kCurrentColor: |
| case KeywordValue::kCursive: |
| case KeywordValue::kEllipsis: |
| case KeywordValue::kEnd: |
| case KeywordValue::kEquirectangular: |
| case KeywordValue::kFantasy: |
| case KeywordValue::kFixed: |
| case KeywordValue::kForwards: |
| case KeywordValue::kHidden: |
| case KeywordValue::kInfinite: |
| case KeywordValue::kInherit: |
| case KeywordValue::kInitial: |
| case KeywordValue::kInline: |
| case KeywordValue::kInlineBlock: |
| case KeywordValue::kLeft: |
| case KeywordValue::kLineThrough: |
| case KeywordValue::kMiddle: |
| case KeywordValue::kMonoscopic: |
| case KeywordValue::kMonospace: |
| case KeywordValue::kNoRepeat: |
| case KeywordValue::kNormal: |
| case KeywordValue::kNoWrap: |
| case KeywordValue::kPre: |
| case KeywordValue::kPreLine: |
| case KeywordValue::kPreWrap: |
| case KeywordValue::kRelative: |
| case KeywordValue::kRepeat: |
| case KeywordValue::kReverse: |
| case KeywordValue::kRight: |
| case KeywordValue::kSansSerif: |
| case KeywordValue::kSerif: |
| case KeywordValue::kSolid: |
| case KeywordValue::kStart: |
| case KeywordValue::kStatic: |
| case KeywordValue::kStereoscopicLeftRight: |
| case KeywordValue::kStereoscopicTopBottom: |
| case KeywordValue::kTop: |
| case KeywordValue::kUppercase: |
| case KeywordValue::kVisible: |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| // This helper class creates a context within which cascaded style properties |
| // can be efficiently promoted to computed properties. |
| // In particular, some computed style calculations depend on other computed |
| // styles, and this class manages the caching of those dependent values so that |
| // if they are depended upon more than once, they are quickly recalled, and if |
| // they are never depended upon, no extra time is spend resolving them. For |
| // example, many properties depend on font size, and so they can simply call |
| // CalculateComputedStyleContext::GetFontSize() to obtain that value, and all |
| // computations will be handled internally. |
| class CalculateComputedStyleContext { |
| public: |
| CalculateComputedStyleContext( |
| CSSComputedStyleData* cascaded_style, |
| const scoped_refptr<CSSComputedStyleDeclaration>& |
| parent_computed_style_declaration, |
| const scoped_refptr<const CSSComputedStyleData>& root_computed_style, |
| const math::Size& viewport_size, |
| GURLMap* const property_key_to_base_url_map) |
| : cascaded_style_(cascaded_style), |
| parent_computed_style_(*parent_computed_style_declaration->data()), |
| root_computed_style_(*root_computed_style), |
| viewport_size_(viewport_size), |
| property_key_to_base_url_map_(property_key_to_base_url_map) { |
| cascaded_style_->SetParentComputedStyleDeclaration( |
| parent_computed_style_declaration); |
| } |
| |
| // Updates the property specified by the iterator to its computed value. |
| void SetComputedStyleForProperty(PropertyKey key, |
| scoped_refptr<PropertyValue>* value); |
| |
| private: |
| // Immediately promote the specified property key to computed value (if |
| // necessary). |
| void ComputeValue(PropertyKey key); |
| |
| // Check if the property value is set to inherit or initial, and assign it |
| // an appropriate computed value in this case. |
| bool HandleInheritOrInitial(PropertyKey key, |
| scoped_refptr<PropertyValue>* value); |
| |
| // Check what property property we are dealing with, and promote it to |
| // a computed value accordingly (e.g. by invoking one of the many different |
| // computed style computations defined above.) |
| void HandleSpecifiedValue(PropertyKey key, |
| scoped_refptr<PropertyValue>* value); |
| |
| // If the modified value was a (potentially) dependent property value, cache |
| // its computed value so that we know it has been computed. |
| void OnComputedStyleCalculated(PropertyKey key, |
| const scoped_refptr<PropertyValue>& value); |
| |
| // Helper function to determine if the computed style implies absolute |
| // positioning. |
| bool IsAbsolutelyPositioned(); |
| |
| // Helper function to return the computed font size. |
| LengthValue* GetFontSize(); |
| // Helper function to return the computed font size of root element. |
| LengthValue* GetRootFontSize(); |
| // Helper function to return one percent of the viewport size . |
| const math::Size& GetViewportSizeOnePercent(); |
| |
| // Helper function to return the computed border style for an edge based on |
| // border width properties. |
| PropertyValue* GetBorderOrOutlineStyleBasedOnWidth(PropertyKey key); |
| PropertyValue* GetBorderBottomStyle(); |
| PropertyValue* GetBorderLeftStyle(); |
| PropertyValue* GetBorderRightStyle(); |
| PropertyValue* GetBorderTopStyle(); |
| PropertyValue* GetOutlineStyle(); |
| |
| // Helper function to return the computed color. |
| RGBAColorValue* GetColor(); |
| |
| // The style that, during the scope of CalculateComputedStyleContext, is |
| // promoted from being a cascaded style to a computed style. |
| CSSComputedStyleData* cascaded_style_; |
| |
| // The parent computed style. |
| const CSSComputedStyleData& parent_computed_style_; |
| // The root computed style. |
| const CSSComputedStyleData& root_computed_style_; |
| |
| // One percent of width and height of viewport size. |
| const math::Size& viewport_size_; |
| |
| // Provides a base URL for each property key. This is used by properties |
| // that deal with URLs, such as background-image, to resolve relative URLs |
| // based on which style sheet they were specified from. |
| GURLMap* const property_key_to_base_url_map_; |
| |
| // Cached computed values for a small specific set of properties that other |
| // properties computed style calculations depend upon. These are lazily |
| // computed. |
| scoped_refptr<PropertyValue> computed_border_bottom_style_; |
| scoped_refptr<PropertyValue> computed_border_left_style_; |
| scoped_refptr<PropertyValue> computed_border_right_style_; |
| scoped_refptr<PropertyValue> computed_border_top_style_; |
| scoped_refptr<PropertyValue> computed_color_; |
| scoped_refptr<PropertyValue> computed_font_size_; |
| scoped_refptr<PropertyValue> computed_outline_style_; |
| scoped_refptr<PropertyValue> computed_position_; |
| }; |
| |
| void CalculateComputedStyleContext::SetComputedStyleForProperty( |
| PropertyKey key, scoped_refptr<PropertyValue>* value) { |
| // If a property has keyword value 'inherit' or 'initial', it must be |
| // set to the corresponding inherited or initial value. In this case, |
| // the parent's value is already computed so we can skip the computation |
| // step. |
| if (!HandleInheritOrInitial(key, value)) { |
| HandleSpecifiedValue(key, value); |
| } |
| OnComputedStyleCalculated(key, *value); |
| } |
| |
| bool CalculateComputedStyleContext::IsAbsolutelyPositioned() { |
| // An absolutely positioned element (or its box) implies that the element's |
| // 'position' property has the value 'absolute' or 'fixed'. |
| // https://www.w3.org/TR/CSS21/visuren.html#absolutely-positioned |
| if (!computed_position_) { |
| ComputeValue(kPositionProperty); |
| } |
| |
| DCHECK(computed_position_); |
| return computed_position_ == KeywordValue::GetAbsolute() || |
| computed_position_ == KeywordValue::GetFixed(); |
| } |
| |
| LengthValue* CalculateComputedStyleContext::GetFontSize() { |
| if (!computed_font_size_) { |
| ComputeValue(kFontSizeProperty); |
| } |
| |
| DCHECK(computed_font_size_); |
| return base::polymorphic_downcast<LengthValue*>(computed_font_size_.get()); |
| } |
| |
| LengthValue* CalculateComputedStyleContext::GetRootFontSize() { |
| return base::polymorphic_downcast<LengthValue*>( |
| root_computed_style_.font_size().get()); |
| } |
| |
| const math::Size& CalculateComputedStyleContext::GetViewportSizeOnePercent() { |
| return viewport_size_; |
| } |
| |
| PropertyValue* |
| CalculateComputedStyleContext::GetBorderOrOutlineStyleBasedOnWidth( |
| PropertyKey key) { |
| if (key == kBorderBottomWidthProperty) { |
| return GetBorderBottomStyle(); |
| } else if (key == kBorderLeftWidthProperty) { |
| return GetBorderLeftStyle(); |
| } else if (key == kBorderRightWidthProperty) { |
| return GetBorderRightStyle(); |
| } else if (key == kBorderTopWidthProperty) { |
| return GetBorderTopStyle(); |
| } else { |
| DCHECK_EQ(key, kOutlineWidthProperty); |
| return GetOutlineStyle(); |
| } |
| } |
| |
| PropertyValue* CalculateComputedStyleContext::GetBorderBottomStyle() { |
| if (!computed_border_bottom_style_) { |
| ComputeValue(kBorderBottomStyleProperty); |
| } |
| |
| DCHECK(computed_border_bottom_style_); |
| return computed_border_bottom_style_.get(); |
| } |
| |
| PropertyValue* CalculateComputedStyleContext::GetBorderLeftStyle() { |
| if (!computed_border_left_style_) { |
| ComputeValue(kBorderLeftStyleProperty); |
| } |
| |
| DCHECK(computed_border_left_style_); |
| return computed_border_left_style_.get(); |
| } |
| |
| PropertyValue* CalculateComputedStyleContext::GetBorderRightStyle() { |
| if (!computed_border_right_style_) { |
| ComputeValue(kBorderRightStyleProperty); |
| } |
| |
| DCHECK(computed_border_right_style_); |
| return computed_border_right_style_.get(); |
| } |
| |
| PropertyValue* CalculateComputedStyleContext::GetBorderTopStyle() { |
| if (!computed_border_top_style_) { |
| ComputeValue(kBorderTopStyleProperty); |
| } |
| |
| DCHECK(computed_border_top_style_); |
| return computed_border_top_style_.get(); |
| } |
| |
| RGBAColorValue* CalculateComputedStyleContext::GetColor() { |
| if (!computed_color_) { |
| ComputeValue(kColorProperty); |
| } |
| |
| DCHECK(computed_color_); |
| return base::polymorphic_downcast<RGBAColorValue*>(computed_color_.get()); |
| } |
| |
| PropertyValue* CalculateComputedStyleContext::GetOutlineStyle() { |
| if (!computed_outline_style_) { |
| ComputeValue(kOutlineStyleProperty); |
| } |
| |
| DCHECK(computed_outline_style_); |
| return computed_outline_style_.get(); |
| } |
| |
| void CalculateComputedStyleContext::ComputeValue(PropertyKey key) { |
| if (cascaded_style_->IsDeclared(key)) { |
| scoped_refptr<PropertyValue>& cascaded_value = |
| cascaded_style_->GetDeclaredPropertyValueReference(key); |
| SetComputedStyleForProperty(key, &cascaded_value); |
| } else { |
| const scoped_refptr<PropertyValue>& computed_value = |
| cascaded_style_->GetPropertyValueReference(key); |
| OnComputedStyleCalculated(key, computed_value); |
| } |
| } |
| |
| bool CalculateComputedStyleContext::HandleInheritOrInitial( |
| PropertyKey key, scoped_refptr<PropertyValue>* value) { |
| if (*value == KeywordValue::GetInherit()) { |
| // Add this property to the list of those that inherited their declared |
| // value from the parent. This allows the computed style to later determine |
| // if a value that was explicitly inherited from the parent is no longer |
| // valid. |
| cascaded_style_->AddDeclaredPropertyInheritedFromParent(key); |
| *value = parent_computed_style_.GetPropertyValue(key); |
| return true; |
| } else if (*value == KeywordValue::GetInitial()) { |
| *value = GetPropertyInitialValue(key); |
| // If the initial value is current color, it still requires to do further |
| // processing. |
| return *value == KeywordValue::GetCurrentColor() ? false : true; |
| } else { |
| return false; |
| } |
| } |
| |
| void CalculateComputedStyleContext::HandleSpecifiedValue( |
| PropertyKey key, scoped_refptr<PropertyValue>* value) { |
| switch (key) { |
| case kBackgroundPositionProperty: { |
| ComputedBackgroundPositionProvider background_position_provider( |
| GetFontSize(), GetRootFontSize(), GetViewportSizeOnePercent()); |
| (*value)->Accept(&background_position_provider); |
| const scoped_refptr<PropertyValue>& computed_background_position = |
| background_position_provider.computed_background_position(); |
| if (computed_background_position) { |
| *value = computed_background_position; |
| } |
| } break; |
| case kBorderBottomColorProperty: |
| case kBorderLeftColorProperty: |
| case kBorderRightColorProperty: |
| case kBorderTopColorProperty: |
| case kOutlineColorProperty: |
| case kTextDecorationColorProperty: { |
| if (*value == KeywordValue::GetCurrentColor()) { |
| // The computed value of the 'currentColor' keyword is the computed |
| // value of the 'color' property. |
| *value = GetColor(); |
| } |
| } break; |
| case kBorderBottomWidthProperty: |
| case kBorderLeftWidthProperty: |
| case kBorderRightWidthProperty: |
| case kBorderTopWidthProperty: |
| case kOutlineWidthProperty: { |
| ComputedBorderWidthProvider border_width_provider( |
| GetFontSize(), GetRootFontSize(), GetViewportSizeOnePercent(), |
| GetBorderOrOutlineStyleBasedOnWidth(key)); |
| (*value)->Accept(&border_width_provider); |
| *value = border_width_provider.computed_border_width(); |
| } break; |
| case kBoxShadowProperty: |
| case kTextShadowProperty: { |
| ComputedShadowProvider shadow_provider(GetFontSize(), GetRootFontSize(), |
| GetViewportSizeOnePercent(), |
| GetColor()); |
| (*value)->Accept(&shadow_provider); |
| *value = shadow_provider.computed_shadow(); |
| } break; |
| case kDisplayProperty: { |
| // According to https://www.w3.org/TR/CSS21/visuren.html#dis-pos-flo, |
| // "inline" and "inline-block" values of "display" become "block" if |
| // "position" is "absolute" or "fixed". |
| // TODO: Modify this logic so that the original display value is |
| // not lost. Being unable to determine the original value breaks static |
| // positioning of "inline" and "inline-block" values with absolute |
| // positioning, because they are treated as block boxes but are supposed |
| // to placed at the position they would be in the normal flow. |
| // https://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width |
| if ((*value == KeywordValue::GetInline() || |
| *value == KeywordValue::GetInlineBlock()) && |
| IsAbsolutelyPositioned()) { |
| *value = KeywordValue::GetBlock(); |
| } |
| } break; |
| case kFontSizeProperty: { |
| // Only compute this if computed_font_size_ isn't set, otherwise that |
| // is an indication that it was previously computed as a dependency for |
| // another property value computation. |
| if (!computed_font_size_) { |
| ComputedFontSizeProvider font_size_provider( |
| base::polymorphic_downcast<LengthValue*>( |
| parent_computed_style_.font_size().get()), |
| GetRootFontSize(), GetViewportSizeOnePercent()); |
| (*value)->Accept(&font_size_provider); |
| if (font_size_provider.computed_font_size()) { |
| *value = font_size_provider.computed_font_size(); |
| } |
| } |
| } break; |
| case kFontWeightProperty: { |
| ComputedFontWeightProvider font_weight_provider; |
| (*value)->Accept(&font_weight_provider); |
| *value = font_weight_provider.computed_font_weight(); |
| } break; |
| case kHeightProperty: { |
| ComputedHeightProvider height_provider( |
| parent_computed_style_.height().get(), GetFontSize(), |
| GetRootFontSize(), GetViewportSizeOnePercent(), |
| IsAbsolutelyPositioned()); |
| (*value)->Accept(&height_provider); |
| *value = height_provider.computed_height(); |
| } break; |
| case kLineHeightProperty: { |
| ComputedLineHeightProvider line_height_provider( |
| GetFontSize(), GetRootFontSize(), GetViewportSizeOnePercent()); |
| (*value)->Accept(&line_height_provider); |
| *value = line_height_provider.computed_line_height(); |
| } break; |
| case kMarginBottomProperty: |
| case kMarginLeftProperty: |
| case kMarginRightProperty: |
| case kMarginTopProperty: { |
| ComputedMarginOrPaddingEdgeProvider margin_provider( |
| GetFontSize(), GetRootFontSize(), GetViewportSizeOnePercent()); |
| (*value)->Accept(&margin_provider); |
| *value = margin_provider.computed_margin_or_padding_edge(); |
| } break; |
| case kPaddingBottomProperty: |
| case kPaddingLeftProperty: |
| case kPaddingRightProperty: |
| case kPaddingTopProperty: { |
| ComputedMarginOrPaddingEdgeProvider padding_provider( |
| GetFontSize(), GetRootFontSize(), GetViewportSizeOnePercent()); |
| (*value)->Accept(&padding_provider); |
| *value = padding_provider.computed_margin_or_padding_edge(); |
| } break; |
| case kMaxHeightProperty: { |
| ComputedMaxHeightProvider max_height_provider( |
| parent_computed_style_.height().get(), GetFontSize(), |
| GetRootFontSize(), GetViewportSizeOnePercent(), |
| IsAbsolutelyPositioned()); |
| (*value)->Accept(&max_height_provider); |
| *value = max_height_provider.computed_max_height(); |
| } break; |
| case kMinHeightProperty: { |
| ComputedMinHeightProvider min_height_provider( |
| parent_computed_style_.height().get(), GetFontSize(), |
| GetRootFontSize(), GetViewportSizeOnePercent(), |
| IsAbsolutelyPositioned()); |
| (*value)->Accept(&min_height_provider); |
| *value = min_height_provider.computed_min_height(); |
| } break; |
| case kMaxWidthProperty: |
| case kMinWidthProperty: { |
| ComputedMinMaxWidthProvider min_max_width_provider( |
| parent_computed_style_.width().get(), GetFontSize(), |
| GetRootFontSize(), GetViewportSizeOnePercent()); |
| (*value)->Accept(&min_max_width_provider); |
| *value = min_max_width_provider.computed_min_max_width(); |
| } break; |
| case kWidthProperty: { |
| ComputedWidthProvider width_provider(GetFontSize(), GetRootFontSize(), |
| GetViewportSizeOnePercent()); |
| (*value)->Accept(&width_provider); |
| *value = width_provider.computed_width(); |
| } break; |
| case kBackgroundImageProperty: { |
| if (property_key_to_base_url_map_ |