blob: 7bb30fc6b5b23547684bae468ebdd8a47a97c96b [file] [log] [blame]
// Copyright 2014 The Cobalt Authors. 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);
}
}
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::kScroll:
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:
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::kScroll:
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:
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::kScroll:
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:
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 PropertyValue* parent_computed_top,
const PropertyValue* parent_computed_bottom,
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 PropertyValue* parent_computed_top_;
const PropertyValue* parent_computed_bottom_;
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 PropertyValue* parent_computed_top,
const PropertyValue* parent_computed_bottom,
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),
parent_computed_top_(parent_computed_top),
parent_computed_bottom_(parent_computed_bottom),
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::kScroll:
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:
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 &&
(parent_computed_top_ == auto_value ||
parent_computed_bottom_ == 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::kScroll:
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:
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::kScroll:
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:
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::kScroll:
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:
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::kScroll:
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:
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;
}
}
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;
}
}
// 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
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::kScroll:
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:
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::kScroll:
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:
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::kScroll:
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:
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;
}
}
// 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;
}
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::kScroll:
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:
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 CalculateCompu