1/*
2 * Copyright (C) 2011-2018 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. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "CSSValuePool.h"
28
29#include "CSSParser.h"
30#include "CSSPrimitiveValueMappings.h"
31#include "CSSValueKeywords.h"
32#include "CSSValueList.h"
33
34namespace WebCore {
35
36CSSValuePool& CSSValuePool::singleton()
37{
38 static NeverDestroyed<CSSValuePool> pool;
39 return pool;
40}
41
42CSSValuePool::CSSValuePool()
43{
44 m_inheritedValue.construct();
45 m_implicitInitialValue.construct(true);
46 m_explicitInitialValue.construct(false);
47 m_unsetValue.construct();
48 m_revertValue.construct();
49
50 m_transparentColor.construct(Color(Color::transparent));
51 m_whiteColor.construct(Color(Color::white));
52 m_blackColor.construct(Color(Color::black));
53
54 for (unsigned i = firstCSSValueKeyword; i <= lastCSSValueKeyword; ++i)
55 m_identifierValues[i].construct(static_cast<CSSValueID>(i));
56
57 for (unsigned i = 0; i < (maximumCacheableIntegerValue + 1); ++i) {
58 m_pixelValues[i].construct(i, CSSPrimitiveValue::CSS_PX);
59 m_percentValues[i].construct(i, CSSPrimitiveValue::CSS_PERCENTAGE);
60 m_numberValues[i].construct(i, CSSPrimitiveValue::CSS_NUMBER);
61 }
62}
63
64Ref<CSSPrimitiveValue> CSSValuePool::createIdentifierValue(CSSValueID ident)
65{
66 RELEASE_ASSERT(ident >= firstCSSValueKeyword && ident <= lastCSSValueKeyword);
67 return m_identifierValues[ident].get();
68}
69
70Ref<CSSPrimitiveValue> CSSValuePool::createIdentifierValue(CSSPropertyID ident)
71{
72 return CSSPrimitiveValue::createIdentifier(ident);
73}
74
75Ref<CSSPrimitiveValue> CSSValuePool::createColorValue(const Color& color)
76{
77 // These are the empty and deleted values of the hash table.
78 if (color == Color::transparent)
79 return m_transparentColor.get();
80 if (color == Color::white)
81 return m_whiteColor.get();
82 // Just because it is common.
83 if (color == Color::black)
84 return m_blackColor.get();
85
86 // Remove one entry at random if the cache grows too large.
87 // FIXME: Use TinyLRUCache instead?
88 const int maximumColorCacheSize = 512;
89 if (m_colorValueCache.size() >= maximumColorCacheSize)
90 m_colorValueCache.remove(m_colorValueCache.random());
91
92 return *m_colorValueCache.ensure(color, [&color] {
93 return CSSPrimitiveValue::create(color);
94 }).iterator->value;
95}
96
97Ref<CSSPrimitiveValue> CSSValuePool::createValue(double value, CSSPrimitiveValue::UnitType type)
98{
99 ASSERT(std::isfinite(value));
100
101 if (value < 0 || value > maximumCacheableIntegerValue)
102 return CSSPrimitiveValue::create(value, type);
103
104 int intValue = static_cast<int>(value);
105 if (value != intValue)
106 return CSSPrimitiveValue::create(value, type);
107
108 switch (type) {
109 case CSSPrimitiveValue::CSS_PX:
110 return m_pixelValues[intValue].get();
111 case CSSPrimitiveValue::CSS_PERCENTAGE:
112 return m_percentValues[intValue].get();
113 case CSSPrimitiveValue::CSS_NUMBER:
114 return m_numberValues[intValue].get();
115 default:
116 return CSSPrimitiveValue::create(value, type);
117 }
118}
119
120Ref<CSSPrimitiveValue> CSSValuePool::createFontFamilyValue(const String& familyName, FromSystemFontID fromSystemFontID)
121{
122 // Remove one entry at random if the cache grows too large.
123 // FIXME: Use TinyLRUCache instead?
124 const int maximumFontFamilyCacheSize = 128;
125 if (m_fontFamilyValueCache.size() >= maximumFontFamilyCacheSize)
126 m_fontFamilyValueCache.remove(m_fontFamilyValueCache.random());
127
128 bool isFromSystemID = fromSystemFontID == FromSystemFontID::Yes;
129 return *m_fontFamilyValueCache.ensure({ familyName, isFromSystemID }, [&familyName, isFromSystemID] {
130 return CSSPrimitiveValue::create(CSSFontFamily { familyName, isFromSystemID });
131 }).iterator->value;
132}
133
134RefPtr<CSSValueList> CSSValuePool::createFontFaceValue(const AtomicString& string)
135{
136 // Remove one entry at random if the cache grows too large.
137 // FIXME: Use TinyLRUCache instead?
138 const int maximumFontFaceCacheSize = 128;
139 if (m_fontFaceValueCache.size() >= maximumFontFaceCacheSize)
140 m_fontFaceValueCache.remove(m_fontFaceValueCache.random());
141
142 return m_fontFaceValueCache.ensure(string, [&string] () -> RefPtr<CSSValueList> {
143 auto result = CSSParser::parseSingleValue(CSSPropertyFontFamily, string);
144 if (!is<CSSValueList>(result))
145 return nullptr;
146 // FIXME: Make downcast work on RefPtr, remove the get() below, and save one reference count churn.
147 return downcast<CSSValueList>(result.get());
148 }).iterator->value;
149}
150
151void CSSValuePool::drain()
152{
153 m_colorValueCache.clear();
154 m_fontFaceValueCache.clear();
155 m_fontFamilyValueCache.clear();
156}
157
158}
159