1/*
2 * Copyright (C) 2017 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
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 */
26
27#include "config.h"
28#include "ConstantPropertyMap.h"
29
30#include "CSSCustomPropertyValue.h"
31#include "CSSParserTokenRange.h"
32#include "CSSVariableData.h"
33#include "Document.h"
34#include "Page.h"
35#include <wtf/NeverDestroyed.h>
36
37namespace WebCore {
38
39ConstantPropertyMap::ConstantPropertyMap(Document& document)
40 : m_document(document)
41{
42}
43
44const ConstantPropertyMap::Values& ConstantPropertyMap::values() const
45{
46 if (!m_values)
47 const_cast<ConstantPropertyMap&>(*this).buildValues();
48 return *m_values;
49}
50
51const AtomString& ConstantPropertyMap::nameForProperty(ConstantProperty property) const
52{
53 static NeverDestroyed<AtomString> safeAreaInsetTopName("safe-area-inset-top", AtomString::ConstructFromLiteral);
54 static NeverDestroyed<AtomString> safeAreaInsetRightName("safe-area-inset-right", AtomString::ConstructFromLiteral);
55 static NeverDestroyed<AtomString> safeAreaInsetBottomName("safe-area-inset-bottom", AtomString::ConstructFromLiteral);
56 static NeverDestroyed<AtomString> safeAreaInsetLeftName("safe-area-inset-left", AtomString::ConstructFromLiteral);
57 static NeverDestroyed<AtomString> fullscreenInsetTopName("fullscreen-inset-top", AtomString::ConstructFromLiteral);
58 static NeverDestroyed<AtomString> fullscreenInsetLeftName("fullscreen-inset-left", AtomString::ConstructFromLiteral);
59 static NeverDestroyed<AtomString> fullscreenInsetBottomName("fullscreen-inset-bottom", AtomString::ConstructFromLiteral);
60 static NeverDestroyed<AtomString> fullscreenInsetRightName("fullscreen-inset-right", AtomString::ConstructFromLiteral);
61 static NeverDestroyed<AtomString> fullscreenAutoHideDurationName("fullscreen-auto-hide-duration", AtomString::ConstructFromLiteral);
62
63 switch (property) {
64 case ConstantProperty::SafeAreaInsetTop:
65 return safeAreaInsetTopName;
66 case ConstantProperty::SafeAreaInsetRight:
67 return safeAreaInsetRightName;
68 case ConstantProperty::SafeAreaInsetBottom:
69 return safeAreaInsetBottomName;
70 case ConstantProperty::SafeAreaInsetLeft:
71 return safeAreaInsetLeftName;
72 case ConstantProperty::FullscreenInsetTop:
73 return fullscreenInsetTopName;
74 case ConstantProperty::FullscreenInsetLeft:
75 return fullscreenInsetLeftName;
76 case ConstantProperty::FullscreenInsetBottom:
77 return fullscreenInsetBottomName;
78 case ConstantProperty::FullscreenInsetRight:
79 return fullscreenInsetRightName;
80 case ConstantProperty::FullscreenAutoHideDuration:
81 return fullscreenAutoHideDurationName;
82 }
83
84 return nullAtom();
85}
86
87void ConstantPropertyMap::setValueForProperty(ConstantProperty property, Ref<CSSVariableData>&& data)
88{
89 if (!m_values)
90 buildValues();
91
92 auto& name = nameForProperty(property);
93 m_values->set(name, CSSCustomPropertyValue::createSyntaxAll(name, WTFMove(data)));
94}
95
96void ConstantPropertyMap::buildValues()
97{
98 m_values = Values { };
99
100 updateConstantsForSafeAreaInsets();
101 updateConstantsForFullscreen();
102}
103
104static Ref<CSSVariableData> variableDataForPositivePixelLength(float lengthInPx)
105{
106 ASSERT(lengthInPx >= 0);
107
108 CSSParserToken token(NumberToken, lengthInPx, NumberValueType, NoSign);
109 token.convertToDimensionWithUnit("px");
110
111 Vector<CSSParserToken> tokens { token };
112 CSSParserTokenRange tokenRange(tokens);
113 return CSSVariableData::create(tokenRange);
114}
115
116static Ref<CSSVariableData> variableDataForPositiveDuration(Seconds durationInSeconds)
117{
118 ASSERT(durationInSeconds >= 0_s);
119
120 CSSParserToken token(NumberToken, durationInSeconds.value(), NumberValueType, NoSign);
121 token.convertToDimensionWithUnit("s");
122
123 Vector<CSSParserToken> tokens { token };
124 CSSParserTokenRange tokenRange(tokens);
125 return CSSVariableData::create(tokenRange);
126}
127
128void ConstantPropertyMap::updateConstantsForSafeAreaInsets()
129{
130 FloatBoxExtent unobscuredSafeAreaInsets = m_document.page() ? m_document.page()->unobscuredSafeAreaInsets() : FloatBoxExtent();
131 setValueForProperty(ConstantProperty::SafeAreaInsetTop, variableDataForPositivePixelLength(unobscuredSafeAreaInsets.top()));
132 setValueForProperty(ConstantProperty::SafeAreaInsetRight, variableDataForPositivePixelLength(unobscuredSafeAreaInsets.right()));
133 setValueForProperty(ConstantProperty::SafeAreaInsetBottom, variableDataForPositivePixelLength(unobscuredSafeAreaInsets.bottom()));
134 setValueForProperty(ConstantProperty::SafeAreaInsetLeft, variableDataForPositivePixelLength(unobscuredSafeAreaInsets.left()));
135}
136
137void ConstantPropertyMap::didChangeSafeAreaInsets()
138{
139 updateConstantsForSafeAreaInsets();
140 m_document.invalidateMatchedPropertiesCacheAndForceStyleRecalc();
141}
142
143void ConstantPropertyMap::updateConstantsForFullscreen()
144{
145 FloatBoxExtent fullscreenInsets = m_document.page() ? m_document.page()->fullscreenInsets() : FloatBoxExtent();
146 setValueForProperty(ConstantProperty::FullscreenInsetTop, variableDataForPositivePixelLength(fullscreenInsets.top()));
147 setValueForProperty(ConstantProperty::FullscreenInsetRight, variableDataForPositivePixelLength(fullscreenInsets.right()));
148 setValueForProperty(ConstantProperty::FullscreenInsetBottom, variableDataForPositivePixelLength(fullscreenInsets.bottom()));
149 setValueForProperty(ConstantProperty::FullscreenInsetLeft, variableDataForPositivePixelLength(fullscreenInsets.left()));
150
151 Seconds fullscreenAutoHideDuration = m_document.page() ? m_document.page()->fullscreenAutoHideDuration() : 0_s;
152 setValueForProperty(ConstantProperty::FullscreenAutoHideDuration, variableDataForPositiveDuration(fullscreenAutoHideDuration));
153}
154
155void ConstantPropertyMap::didChangeFullscreenInsets()
156{
157 updateConstantsForFullscreen();
158 m_document.invalidateMatchedPropertiesCacheAndForceStyleRecalc();
159}
160
161void ConstantPropertyMap::setFullscreenAutoHideDuration(Seconds duration)
162{
163 setValueForProperty(ConstantProperty::FullscreenAutoHideDuration, variableDataForPositiveDuration(duration));
164 m_document.invalidateMatchedPropertiesCacheAndForceStyleRecalc();
165}
166
167}
168