summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/css/parser/sizes_attribute_parser.cc
blob: 11ad76dae45685b873b05b3a5d3abdfe924ace9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/core/css/parser/sizes_attribute_parser.h"

#include "third_party/blink/renderer/core/css/media_query_evaluator.h"
#include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
#include "third_party/blink/renderer/core/css/parser/sizes_math_function_parser.h"
#include "third_party/blink/renderer/core/media_type_names.h"

namespace blink {

SizesAttributeParser::SizesAttributeParser(
    MediaValues* media_values,
    const String& attribute,
    const ExecutionContext* execution_context)
    : media_values_(media_values),
      execution_context_(execution_context),
      length_(0),
      length_was_set_(false) {
  DCHECK(media_values_);
  is_valid_ =
      Parse(CSSParserTokenRange(CSSTokenizer(attribute).TokenizeToEOF()));
}

float SizesAttributeParser::length() {
  if (is_valid_)
    return EffectiveSize();
  return EffectiveSizeDefaultValue();
}

bool SizesAttributeParser::CalculateLengthInPixels(CSSParserTokenRange range,
                                                   float& result) {
  const CSSParserToken& start_token = range.Peek();
  CSSParserTokenType type = start_token.GetType();
  if (type == kDimensionToken) {
    double length;
    if (!CSSPrimitiveValue::IsLength(start_token.GetUnitType()))
      return false;
    if ((media_values_->ComputeLength(start_token.NumericValue(),
                                      start_token.GetUnitType(), length)) &&
        (length >= 0)) {
      result = clampTo<float>(length);
      return true;
    }
  } else if (type == kFunctionToken) {
    SizesMathFunctionParser calc_parser(range, media_values_);
    if (!calc_parser.IsValid())
      return false;
    result = calc_parser.Result();
    return true;
  } else if (type == kNumberToken && !start_token.NumericValue()) {
    result = 0;
    return true;
  }

  return false;
}

bool SizesAttributeParser::MediaConditionMatches(
    const MediaQuerySet& media_condition) {
  // A Media Condition cannot have a media type other then screen.
  MediaQueryEvaluator media_query_evaluator(*media_values_);
  return media_query_evaluator.Eval(media_condition);
}

bool SizesAttributeParser::Parse(CSSParserTokenRange range) {
  // Split on a comma token and parse the result tokens as (media-condition,
  // length) pairs
  while (!range.AtEnd()) {
    const CSSParserToken* media_condition_start = &range.Peek();
    // The length is the last component value before the comma which isn't
    // whitespace or a comment
    const CSSParserToken* length_token_start = &range.Peek();
    const CSSParserToken* length_token_end = &range.Peek();
    while (!range.AtEnd() && range.Peek().GetType() != kCommaToken) {
      length_token_start = &range.Peek();
      range.ConsumeComponentValue();
      length_token_end = &range.Peek();
      range.ConsumeWhitespace();
    }
    range.Consume();

    float length;
    if (!CalculateLengthInPixels(
            range.MakeSubRange(length_token_start, length_token_end), length))
      continue;
    scoped_refptr<MediaQuerySet> media_condition =
        MediaQueryParser::ParseMediaCondition(
            range.MakeSubRange(media_condition_start, length_token_start),
            execution_context_);
    if (!media_condition || !MediaConditionMatches(*media_condition))
      continue;
    length_ = length;
    length_was_set_ = true;
    return true;
  }
  return false;
}

float SizesAttributeParser::EffectiveSize() {
  if (length_was_set_)
    return length_;
  return EffectiveSizeDefaultValue();
}

float SizesAttributeParser::EffectiveSizeDefaultValue() {
  // Returning the equivalent of "100vw"
  return clampTo<float>(media_values_->ViewportWidth());
}

}  // namespace blink