Remove excessive include directives from WebCore/css
[WebKit-https.git] / Source / WebCore / css / parser / SizesAttributeParser.cpp
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Copyright (C) 2016 Apple Inc. All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //    * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //    * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //    * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "config.h"
31 #include "SizesAttributeParser.h"
32
33 #include "CSSPrimitiveValue.h"
34 #include "CSSToLengthConversionData.h"
35 #include "CSSTokenizer.h"
36 #include "FontCascade.h"
37 #include "MediaList.h"
38 #include "MediaQueryEvaluator.h"
39 #include "MediaQueryParser.h"
40 #include "RenderView.h"
41 #include "SizesCalcParser.h"
42 #include "StyleScope.h"
43
44 namespace WebCore {
45
46 float SizesAttributeParser::computeLength(double value, CSSPrimitiveValue::UnitType type, const Document& document)
47 {
48     auto* renderer = document.renderView();
49     if (!renderer)
50         return 0;
51     auto& style = renderer->style();
52
53     CSSToLengthConversionData conversionData(&style, &style, renderer);
54     
55     // Because we evaluate "sizes" at parse time (before style has been resolved), the font metrics used for these specific units
56     // are not available. The font selector's internal consistency isn't guaranteed just yet, so we can just temporarily clear
57     // the pointer to it for the duration of the unit evaluation. This is acceptible because the style always comes from the
58     // RenderView, which has its font information hardcoded in resolveForDocument() to be -webkit-standard, whose operations
59     // don't require a font selector.
60     if (type == CSSPrimitiveValue::CSS_EXS || type == CSSPrimitiveValue::CSS_CHS) {
61         RefPtr<FontSelector> fontSelector = style.fontCascade().fontSelector();
62         style.fontCascade().update(nullptr);
63         float result = CSSPrimitiveValue::computeNonCalcLengthDouble(conversionData, type, value);
64         style.fontCascade().update(fontSelector.get());
65         return result;
66     }
67     
68     return clampTo<float>(CSSPrimitiveValue::computeNonCalcLengthDouble(conversionData, type, value));
69 }
70     
71 SizesAttributeParser::SizesAttributeParser(const String& attribute, const Document& document)
72     : m_document(document)
73     , m_length(0)
74     , m_lengthWasSet(false)
75 {
76     // Ensure iframes have correct view size.
77     if (m_document.ownerElement())
78         m_document.ownerElement()->document().updateLayoutIgnorePendingStylesheets();
79
80     m_isValid = parse(CSSTokenizer(attribute).tokenRange());
81 }
82
83 float SizesAttributeParser::length()
84 {
85     if (m_isValid)
86         return effectiveSize();
87     return effectiveSizeDefaultValue();
88 }
89
90 bool SizesAttributeParser::calculateLengthInPixels(CSSParserTokenRange range, float& result)
91 {
92     const CSSParserToken& startToken = range.peek();
93     CSSParserTokenType type = startToken.type();
94     if (type == DimensionToken) {
95         if (!CSSPrimitiveValue::isLength(startToken.unitType()))
96             return false;
97         result = computeLength(startToken.numericValue(), startToken.unitType(), m_document);
98         if (result >= 0)
99             return true;
100     } else if (type == FunctionToken) {
101         SizesCalcParser calcParser(range, m_document);
102         if (!calcParser.isValid())
103             return false;
104         result = calcParser.result();
105         return true;
106     } else if (type == NumberToken && !startToken.numericValue()) {
107         result = 0;
108         return true;
109     }
110
111     return false;
112 }
113
114 bool SizesAttributeParser::mediaConditionMatches(const MediaQuerySet& mediaCondition)
115 {
116     // A Media Condition cannot have a media type other than screen.
117     auto* renderer = m_document.renderView();
118     if (!renderer)
119         return false;
120     auto& style = renderer->style();
121     return MediaQueryEvaluator { "screen", m_document, &style }.evaluate(mediaCondition, const_cast<Style::Scope&>(m_document.styleScope()).resolverIfExists());
122 }
123
124 bool SizesAttributeParser::parse(CSSParserTokenRange range)
125 {
126     // Split on a comma token and parse the result tokens as (media-condition, length) pairs
127     while (!range.atEnd()) {
128         const CSSParserToken* mediaConditionStart = &range.peek();
129         // The length is the last component value before the comma which isn't whitespace or a comment
130         const CSSParserToken* lengthTokenStart = &range.peek();
131         const CSSParserToken* lengthTokenEnd = &range.peek();
132         while (!range.atEnd() && range.peek().type() != CommaToken) {
133             lengthTokenStart = &range.peek();
134             range.consumeComponentValue();
135             lengthTokenEnd = &range.peek();
136             range.consumeWhitespace();
137         }
138         range.consume();
139
140         float length;
141         if (!calculateLengthInPixels(range.makeSubRange(lengthTokenStart, lengthTokenEnd), length))
142             continue;
143         RefPtr<MediaQuerySet> mediaCondition = MediaQueryParser::parseMediaCondition(range.makeSubRange(mediaConditionStart, lengthTokenStart));
144         if (!mediaCondition || !mediaConditionMatches(*mediaCondition))
145             continue;
146         m_length = length;
147         m_lengthWasSet = true;
148         return true;
149     }
150     return false;
151 }
152
153 float SizesAttributeParser::effectiveSize()
154 {
155     if (m_lengthWasSet)
156         return m_length;
157     return effectiveSizeDefaultValue();
158 }
159
160 unsigned SizesAttributeParser::effectiveSizeDefaultValue()
161 {
162     auto* renderer = m_document.renderView();
163     if (!renderer)
164         return 0;
165     auto& style = renderer->style();
166     return clampTo<float>(CSSPrimitiveValue::computeNonCalcLengthDouble({ &style, &style, renderer }, CSSPrimitiveValue::CSS_VW, 100.0));
167 }
168
169 } // namespace WebCore