1 // Copyright 2018 PDFium 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 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fxcrt/css/cfx_cssdata.h"
8
9 #include <algorithm>
10 #include <utility>
11
12 #include "core/fxcrt/css/cfx_cssstyleselector.h"
13 #include "core/fxcrt/css/cfx_cssvaluelistparser.h"
14 #include "core/fxcrt/fx_codepage.h"
15 #include "core/fxcrt/fx_extension.h"
16
17 namespace {
18
19 #undef PROP
20 #define PROP(a, b, c, d) a, c, d
21
22 const CFX_CSSData::Property propertyTable[] = {
23 {PROP(CFX_CSSProperty::BorderLeft,
24 "border-left",
25 0x04080036,
26 CFX_CSSVALUETYPE_Shorthand)},
27 {PROP(CFX_CSSProperty::Top,
28 "top",
29 0x0BEDAF33,
30 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum |
31 CFX_CSSVALUETYPE_MaybeNumber)},
32 {PROP(CFX_CSSProperty::Margin,
33 "margin",
34 0x0CB016BE,
35 CFX_CSSVALUETYPE_List | CFX_CSSVALUETYPE_MaybeEnum |
36 CFX_CSSVALUETYPE_MaybeNumber)},
37 {PROP(CFX_CSSProperty::TextIndent,
38 "text-indent",
39 0x169ADB74,
40 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber)},
41 {PROP(CFX_CSSProperty::Right,
42 "right",
43 0x193ADE3E,
44 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum |
45 CFX_CSSVALUETYPE_MaybeNumber)},
46 {PROP(CFX_CSSProperty::PaddingLeft,
47 "padding-left",
48 0x228CF02F,
49 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber)},
50 {PROP(CFX_CSSProperty::MarginLeft,
51 "margin-left",
52 0x297C5656,
53 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber |
54 CFX_CSSVALUETYPE_MaybeEnum)},
55 {PROP(CFX_CSSProperty::Border,
56 "border",
57 0x2A23349E,
58 CFX_CSSVALUETYPE_Shorthand)},
59 {PROP(CFX_CSSProperty::BorderTop,
60 "border-top",
61 0x2B866ADE,
62 CFX_CSSVALUETYPE_Shorthand)},
63 {PROP(CFX_CSSProperty::Bottom,
64 "bottom",
65 0x399F02B5,
66 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum |
67 CFX_CSSVALUETYPE_MaybeNumber)},
68 {PROP(CFX_CSSProperty::PaddingRight,
69 "padding-right",
70 0x3F616AC2,
71 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber)},
72 {PROP(CFX_CSSProperty::BorderBottom,
73 "border-bottom",
74 0x452CE780,
75 CFX_CSSVALUETYPE_Shorthand)},
76 {PROP(CFX_CSSProperty::FontFamily,
77 "font-family",
78 0x574686E6,
79 CFX_CSSVALUETYPE_List | CFX_CSSVALUETYPE_MaybeString)},
80 {PROP(CFX_CSSProperty::FontWeight,
81 "font-weight",
82 0x6692F60C,
83 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum |
84 CFX_CSSVALUETYPE_MaybeNumber)},
85 {PROP(CFX_CSSProperty::Color,
86 "color",
87 0x6E67921F,
88 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum |
89 CFX_CSSVALUETYPE_MaybeColor)},
90 {PROP(CFX_CSSProperty::LetterSpacing,
91 "letter-spacing",
92 0x70536102,
93 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum |
94 CFX_CSSVALUETYPE_MaybeNumber)},
95 {PROP(CFX_CSSProperty::TextAlign,
96 "text-align",
97 0x7553F1BD,
98 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum)},
99 {PROP(CFX_CSSProperty::BorderRightWidth,
100 "border-right-width",
101 0x8F5A6036,
102 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum |
103 CFX_CSSVALUETYPE_MaybeNumber)},
104 {PROP(CFX_CSSProperty::VerticalAlign,
105 "vertical-align",
106 0x934A87D2,
107 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum |
108 CFX_CSSVALUETYPE_MaybeNumber)},
109 {PROP(CFX_CSSProperty::PaddingTop,
110 "padding-top",
111 0x959D22B7,
112 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber)},
113 {PROP(CFX_CSSProperty::FontVariant,
114 "font-variant",
115 0x9C785779,
116 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum)},
117 {PROP(CFX_CSSProperty::BorderWidth,
118 "border-width",
119 0xA8DE4FEB,
120 CFX_CSSVALUETYPE_List | CFX_CSSVALUETYPE_MaybeEnum |
121 CFX_CSSVALUETYPE_MaybeNumber)},
122 {PROP(CFX_CSSProperty::BorderBottomWidth,
123 "border-bottom-width",
124 0xAE41204D,
125 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum |
126 CFX_CSSVALUETYPE_MaybeNumber)},
127 {PROP(CFX_CSSProperty::BorderRight,
128 "border-right",
129 0xB78E9EA9,
130 CFX_CSSVALUETYPE_Shorthand)},
131 {PROP(CFX_CSSProperty::FontSize,
132 "font-size",
133 0xB93956DF,
134 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum |
135 CFX_CSSVALUETYPE_MaybeNumber)},
136 {PROP(CFX_CSSProperty::BorderSpacing,
137 "border-spacing",
138 0xC72030F0,
139 CFX_CSSVALUETYPE_List | CFX_CSSVALUETYPE_MaybeNumber)},
140 {PROP(CFX_CSSProperty::FontStyle,
141 "font-style",
142 0xCB1950F5,
143 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum)},
144 {PROP(CFX_CSSProperty::Font,
145 "font",
146 0xCD308B77,
147 CFX_CSSVALUETYPE_Shorthand)},
148 {PROP(CFX_CSSProperty::LineHeight,
149 "line-height",
150 0xCFCACE2E,
151 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum |
152 CFX_CSSVALUETYPE_MaybeNumber)},
153 {PROP(CFX_CSSProperty::MarginRight,
154 "margin-right",
155 0xD13C58C9,
156 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber |
157 CFX_CSSVALUETYPE_MaybeEnum)},
158 {PROP(CFX_CSSProperty::BorderLeftWidth,
159 "border-left-width",
160 0xD1E93D83,
161 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum |
162 CFX_CSSVALUETYPE_MaybeNumber)},
163 {PROP(CFX_CSSProperty::Display,
164 "display",
165 0xD4224C36,
166 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum)},
167 {PROP(CFX_CSSProperty::PaddingBottom,
168 "padding-bottom",
169 0xE555B3B9,
170 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber)},
171 {PROP(CFX_CSSProperty::BorderTopWidth,
172 "border-top-width",
173 0xED2CB62B,
174 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum |
175 CFX_CSSVALUETYPE_MaybeNumber)},
176 {PROP(CFX_CSSProperty::WordSpacing,
177 "word-spacing",
178 0xEDA63BAE,
179 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum |
180 CFX_CSSVALUETYPE_MaybeNumber)},
181 {PROP(CFX_CSSProperty::Left,
182 "left",
183 0xF5AD782B,
184 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum |
185 CFX_CSSVALUETYPE_MaybeNumber)},
186 {PROP(CFX_CSSProperty::TextDecoration,
187 "text-decoration",
188 0xF7C634BA,
189 CFX_CSSVALUETYPE_List | CFX_CSSVALUETYPE_MaybeEnum)},
190 {PROP(CFX_CSSProperty::Padding,
191 "padding",
192 0xF8C373F7,
193 CFX_CSSVALUETYPE_List | CFX_CSSVALUETYPE_MaybeNumber)},
194 {PROP(CFX_CSSProperty::MarginBottom,
195 "margin-bottom",
196 0xF93485A0,
197 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber |
198 CFX_CSSVALUETYPE_MaybeEnum)},
199 {PROP(CFX_CSSProperty::MarginTop,
200 "margin-top",
201 0xFE51DCFE,
202 CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber |
203 CFX_CSSVALUETYPE_MaybeEnum)},
204 };
205
206 #undef PROP
207
208 #undef PVAL
209 #define PVAL(a, b, c) a, c
210
211 const CFX_CSSData::PropertyValue propertyValueTable[] = {
212 {PVAL(CFX_CSSPropertyValue::Bolder, "bolder", 0x009F1058)},
213 {PVAL(CFX_CSSPropertyValue::None, "none", 0x048B6670)},
214 {PVAL(CFX_CSSPropertyValue::Dot, "dot", 0x0A48CB27)},
215 {PVAL(CFX_CSSPropertyValue::Sub, "sub", 0x0BD37FAA)},
216 {PVAL(CFX_CSSPropertyValue::Top, "top", 0x0BEDAF33)},
217 {PVAL(CFX_CSSPropertyValue::Right, "right", 0x193ADE3E)},
218 {PVAL(CFX_CSSPropertyValue::Normal, "normal", 0x247CF3E9)},
219 {PVAL(CFX_CSSPropertyValue::Auto, "auto", 0x2B35B6D9)},
220 {PVAL(CFX_CSSPropertyValue::Text, "text", 0x2D08AF85)},
221 {PVAL(CFX_CSSPropertyValue::XSmall, "x-small", 0x2D2FCAFE)},
222 {PVAL(CFX_CSSPropertyValue::Thin, "thin", 0x2D574D53)},
223 {PVAL(CFX_CSSPropertyValue::Small, "small", 0x316A3739)},
224 {PVAL(CFX_CSSPropertyValue::Bottom, "bottom", 0x399F02B5)},
225 {PVAL(CFX_CSSPropertyValue::Underline, "underline", 0x3A0273A6)},
226 {PVAL(CFX_CSSPropertyValue::Double, "double", 0x3D98515B)},
227 {PVAL(CFX_CSSPropertyValue::Lighter, "lighter", 0x45BEB7AF)},
228 {PVAL(CFX_CSSPropertyValue::Oblique, "oblique", 0x53EBDDB1)},
229 {PVAL(CFX_CSSPropertyValue::Super, "super", 0x6A4F842F)},
230 {PVAL(CFX_CSSPropertyValue::Center, "center", 0x6C51AFC1)},
231 {PVAL(CFX_CSSPropertyValue::XxLarge, "xx-large", 0x70BB1508)},
232 {PVAL(CFX_CSSPropertyValue::Smaller, "smaller", 0x849769F0)},
233 {PVAL(CFX_CSSPropertyValue::Baseline, "baseline", 0x87436BA3)},
234 {PVAL(CFX_CSSPropertyValue::Thick, "thick", 0x8CC35EB3)},
235 {PVAL(CFX_CSSPropertyValue::Justify, "justify", 0x8D269CAE)},
236 {PVAL(CFX_CSSPropertyValue::Middle, "middle", 0x947FA00F)},
237 {PVAL(CFX_CSSPropertyValue::Medium, "medium", 0xA084A381)},
238 {PVAL(CFX_CSSPropertyValue::ListItem, "list-item", 0xA32382B8)},
239 {PVAL(CFX_CSSPropertyValue::XxSmall, "xx-small", 0xADE1FC76)},
240 {PVAL(CFX_CSSPropertyValue::Bold, "bold", 0xB18313A1)},
241 {PVAL(CFX_CSSPropertyValue::SmallCaps, "small-caps", 0xB299428D)},
242 {PVAL(CFX_CSSPropertyValue::Inline, "inline", 0xC02D649F)},
243 {PVAL(CFX_CSSPropertyValue::Overline, "overline", 0xC0EC9FA4)},
244 {PVAL(CFX_CSSPropertyValue::TextBottom, "text-bottom", 0xC7D08D87)},
245 {PVAL(CFX_CSSPropertyValue::Larger, "larger", 0xCD3C409D)},
246 {PVAL(CFX_CSSPropertyValue::InlineTable, "inline-table", 0xD131F494)},
247 {PVAL(CFX_CSSPropertyValue::InlineBlock, "inline-block", 0xD26A8BD7)},
248 {PVAL(CFX_CSSPropertyValue::Blink, "blink", 0xDC36E390)},
249 {PVAL(CFX_CSSPropertyValue::Block, "block", 0xDCD480AB)},
250 {PVAL(CFX_CSSPropertyValue::Italic, "italic", 0xE31D5396)},
251 {PVAL(CFX_CSSPropertyValue::LineThrough, "line-through", 0xE4C5A276)},
252 {PVAL(CFX_CSSPropertyValue::XLarge, "x-large", 0xF008E390)},
253 {PVAL(CFX_CSSPropertyValue::Large, "large", 0xF4434FCB)},
254 {PVAL(CFX_CSSPropertyValue::Left, "left", 0xF5AD782B)},
255 {PVAL(CFX_CSSPropertyValue::TextTop, "text-top", 0xFCB58D45)},
256 };
257
258 #undef PVAL
259
260 const CFX_CSSData::LengthUnit lengthUnitTable[] = {
261 {L"cm", CFX_CSSNumberType::CentiMeters}, {L"em", CFX_CSSNumberType::EMS},
262 {L"ex", CFX_CSSNumberType::EXS}, {L"in", CFX_CSSNumberType::Inches},
263 {L"mm", CFX_CSSNumberType::MilliMeters}, {L"pc", CFX_CSSNumberType::Picas},
264 {L"pt", CFX_CSSNumberType::Points}, {L"px", CFX_CSSNumberType::Pixels},
265 };
266
267 // 16 colours from CSS 2.0 + alternate spelling of grey/gray.
268 const CFX_CSSData::Color colorTable[] = {
269 {L"aqua", 0xff00ffff}, {L"black", 0xff000000}, {L"blue", 0xff0000ff},
270 {L"fuchsia", 0xffff00ff}, {L"gray", 0xff808080}, {L"green", 0xff008000},
271 {L"grey", 0xff808080}, {L"lime", 0xff00ff00}, {L"maroon", 0xff800000},
272 {L"navy", 0xff000080}, {L"olive", 0xff808000}, {L"orange", 0xffffa500},
273 {L"purple", 0xff800080}, {L"red", 0xffff0000}, {L"silver", 0xffc0c0c0},
274 {L"teal", 0xff008080}, {L"white", 0xffffffff}, {L"yellow", 0xffffff00},
275 };
276
277 } // namespace
278
GetPropertyByName(WideStringView name)279 const CFX_CSSData::Property* CFX_CSSData::GetPropertyByName(
280 WideStringView name) {
281 if (name.IsEmpty())
282 return nullptr;
283
284 uint32_t hash = FX_HashCode_GetW(name, true);
285 auto* result =
286 std::lower_bound(std::begin(propertyTable), std::end(propertyTable), hash,
287 [](const CFX_CSSData::Property& iter,
288 const uint32_t& hash) { return iter.dwHash < hash; });
289
290 if (result != std::end(propertyTable) && result->dwHash == hash)
291 return result;
292 return nullptr;
293 }
294
GetPropertyByEnum(CFX_CSSProperty property)295 const CFX_CSSData::Property* CFX_CSSData::GetPropertyByEnum(
296 CFX_CSSProperty property) {
297 return &propertyTable[static_cast<uint8_t>(property)];
298 }
299
GetPropertyValueByName(WideStringView wsName)300 const CFX_CSSData::PropertyValue* CFX_CSSData::GetPropertyValueByName(
301 WideStringView wsName) {
302 if (wsName.IsEmpty())
303 return nullptr;
304
305 uint32_t hash = FX_HashCode_GetW(wsName, true);
306 auto* result = std::lower_bound(
307 std::begin(propertyValueTable), std::end(propertyValueTable), hash,
308 [](const PropertyValue& iter, const uint32_t& hash) {
309 return iter.dwHash < hash;
310 });
311
312 if (result != std::end(propertyValueTable) && result->dwHash == hash)
313 return result;
314 return nullptr;
315 }
316
GetLengthUnitByName(WideStringView wsName)317 const CFX_CSSData::LengthUnit* CFX_CSSData::GetLengthUnitByName(
318 WideStringView wsName) {
319 if (wsName.IsEmpty() || wsName.GetLength() != 2)
320 return nullptr;
321
322 WideString lowerName = WideString(wsName);
323 lowerName.MakeLower();
324
325 for (auto* iter = std::begin(lengthUnitTable);
326 iter != std::end(lengthUnitTable); ++iter) {
327 if (lowerName.Compare(iter->value) == 0)
328 return iter;
329 }
330
331 return nullptr;
332 }
333
GetColorByName(WideStringView wsName)334 const CFX_CSSData::Color* CFX_CSSData::GetColorByName(WideStringView wsName) {
335 if (wsName.IsEmpty())
336 return nullptr;
337
338 WideString lowerName = WideString(wsName);
339 lowerName.MakeLower();
340
341 for (auto* iter = std::begin(colorTable); iter != std::end(colorTable);
342 ++iter) {
343 if (lowerName.Compare(iter->name) == 0)
344 return iter;
345 }
346 return nullptr;
347 }
348