1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/core/css/parser/sizes_attribute_parser.h"
6
7 #include "third_party/blink/renderer/core/css/media_query_evaluator.h"
8 #include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
9 #include "third_party/blink/renderer/core/css/parser/sizes_math_function_parser.h"
10 #include "third_party/blink/renderer/core/media_type_names.h"
11
12 namespace blink {
13
SizesAttributeParser(MediaValues * media_values,const String & attribute,const ExecutionContext * execution_context)14 SizesAttributeParser::SizesAttributeParser(
15 MediaValues* media_values,
16 const String& attribute,
17 const ExecutionContext* execution_context)
18 : media_values_(media_values),
19 execution_context_(execution_context),
20 length_(0),
21 length_was_set_(false) {
22 DCHECK(media_values_);
23 is_valid_ =
24 Parse(CSSParserTokenRange(CSSTokenizer(attribute).TokenizeToEOF()));
25 }
26
length()27 float SizesAttributeParser::length() {
28 if (is_valid_)
29 return EffectiveSize();
30 return EffectiveSizeDefaultValue();
31 }
32
CalculateLengthInPixels(CSSParserTokenRange range,float & result)33 bool SizesAttributeParser::CalculateLengthInPixels(CSSParserTokenRange range,
34 float& result) {
35 const CSSParserToken& start_token = range.Peek();
36 CSSParserTokenType type = start_token.GetType();
37 if (type == kDimensionToken) {
38 double length;
39 if (!CSSPrimitiveValue::IsLength(start_token.GetUnitType()))
40 return false;
41 if ((media_values_->ComputeLength(start_token.NumericValue(),
42 start_token.GetUnitType(), length)) &&
43 (length >= 0)) {
44 result = clampTo<float>(length);
45 return true;
46 }
47 } else if (type == kFunctionToken) {
48 SizesMathFunctionParser calc_parser(range, media_values_);
49 if (!calc_parser.IsValid())
50 return false;
51 result = calc_parser.Result();
52 return true;
53 } else if (type == kNumberToken && !start_token.NumericValue()) {
54 result = 0;
55 return true;
56 }
57
58 return false;
59 }
60
MediaConditionMatches(const MediaQuerySet & media_condition)61 bool SizesAttributeParser::MediaConditionMatches(
62 const MediaQuerySet& media_condition) {
63 // A Media Condition cannot have a media type other then screen.
64 MediaQueryEvaluator media_query_evaluator(*media_values_);
65 return media_query_evaluator.Eval(media_condition);
66 }
67
Parse(CSSParserTokenRange range)68 bool SizesAttributeParser::Parse(CSSParserTokenRange range) {
69 // Split on a comma token and parse the result tokens as (media-condition,
70 // length) pairs
71 while (!range.AtEnd()) {
72 const CSSParserToken* media_condition_start = &range.Peek();
73 // The length is the last component value before the comma which isn't
74 // whitespace or a comment
75 const CSSParserToken* length_token_start = &range.Peek();
76 const CSSParserToken* length_token_end = &range.Peek();
77 while (!range.AtEnd() && range.Peek().GetType() != kCommaToken) {
78 length_token_start = &range.Peek();
79 range.ConsumeComponentValue();
80 length_token_end = &range.Peek();
81 range.ConsumeWhitespace();
82 }
83 range.Consume();
84
85 float length;
86 if (!CalculateLengthInPixels(
87 range.MakeSubRange(length_token_start, length_token_end), length))
88 continue;
89 scoped_refptr<MediaQuerySet> media_condition =
90 MediaQueryParser::ParseMediaCondition(
91 range.MakeSubRange(media_condition_start, length_token_start),
92 execution_context_);
93 if (!media_condition || !MediaConditionMatches(*media_condition))
94 continue;
95 length_ = length;
96 length_was_set_ = true;
97 return true;
98 }
99 return false;
100 }
101
EffectiveSize()102 float SizesAttributeParser::EffectiveSize() {
103 if (length_was_set_)
104 return length_;
105 return EffectiveSizeDefaultValue();
106 }
107
EffectiveSizeDefaultValue()108 float SizesAttributeParser::EffectiveSizeDefaultValue() {
109 // Returning the equivalent of "100vw"
110 return clampTo<float>(media_values_->ViewportWidth());
111 }
112
113 } // namespace blink
114