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