1 // Copyright 2014 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_cssdeclaration.h"
8
9 #include "core/fxcrt/css/cfx_csscolorvalue.h"
10 #include "core/fxcrt/css/cfx_csscustomproperty.h"
11 #include "core/fxcrt/css/cfx_cssenumvalue.h"
12 #include "core/fxcrt/css/cfx_cssnumbervalue.h"
13 #include "core/fxcrt/css/cfx_csspropertyholder.h"
14 #include "core/fxcrt/css/cfx_cssstringvalue.h"
15 #include "core/fxcrt/css/cfx_cssvaluelist.h"
16 #include "core/fxcrt/css/cfx_cssvaluelistparser.h"
17 #include "core/fxcrt/fx_extension.h"
18 #include "third_party/base/logging.h"
19 #include "third_party/base/ptr_util.h"
20
21 namespace {
22
Hex2Dec(uint8_t hexHigh,uint8_t hexLow)23 uint8_t Hex2Dec(uint8_t hexHigh, uint8_t hexLow) {
24 return (FXSYS_HexCharToInt(hexHigh) << 4) + FXSYS_HexCharToInt(hexLow);
25 }
26
27 struct CFX_CSSPropertyValueTable {
28 CFX_CSSPropertyValue eName;
29 const wchar_t* pszName;
30 uint32_t dwHash;
31 };
32 const CFX_CSSPropertyValueTable g_CFX_CSSPropertyValues[] = {
33 {CFX_CSSPropertyValue::Bolder, L"bolder", 0x009F1058},
34 {CFX_CSSPropertyValue::None, L"none", 0x048B6670},
35 {CFX_CSSPropertyValue::Dot, L"dot", 0x0A48CB27},
36 {CFX_CSSPropertyValue::Sub, L"sub", 0x0BD37FAA},
37 {CFX_CSSPropertyValue::Top, L"top", 0x0BEDAF33},
38 {CFX_CSSPropertyValue::Right, L"right", 0x193ADE3E},
39 {CFX_CSSPropertyValue::Normal, L"normal", 0x247CF3E9},
40 {CFX_CSSPropertyValue::Auto, L"auto", 0x2B35B6D9},
41 {CFX_CSSPropertyValue::Text, L"text", 0x2D08AF85},
42 {CFX_CSSPropertyValue::XSmall, L"x-small", 0x2D2FCAFE},
43 {CFX_CSSPropertyValue::Thin, L"thin", 0x2D574D53},
44 {CFX_CSSPropertyValue::Small, L"small", 0x316A3739},
45 {CFX_CSSPropertyValue::Bottom, L"bottom", 0x399F02B5},
46 {CFX_CSSPropertyValue::Underline, L"underline", 0x3A0273A6},
47 {CFX_CSSPropertyValue::Double, L"double", 0x3D98515B},
48 {CFX_CSSPropertyValue::Lighter, L"lighter", 0x45BEB7AF},
49 {CFX_CSSPropertyValue::Oblique, L"oblique", 0x53EBDDB1},
50 {CFX_CSSPropertyValue::Super, L"super", 0x6A4F842F},
51 {CFX_CSSPropertyValue::Center, L"center", 0x6C51AFC1},
52 {CFX_CSSPropertyValue::XxLarge, L"xx-large", 0x70BB1508},
53 {CFX_CSSPropertyValue::Smaller, L"smaller", 0x849769F0},
54 {CFX_CSSPropertyValue::Baseline, L"baseline", 0x87436BA3},
55 {CFX_CSSPropertyValue::Thick, L"thick", 0x8CC35EB3},
56 {CFX_CSSPropertyValue::Justify, L"justify", 0x8D269CAE},
57 {CFX_CSSPropertyValue::Middle, L"middle", 0x947FA00F},
58 {CFX_CSSPropertyValue::Medium, L"medium", 0xA084A381},
59 {CFX_CSSPropertyValue::ListItem, L"list-item", 0xA32382B8},
60 {CFX_CSSPropertyValue::XxSmall, L"xx-small", 0xADE1FC76},
61 {CFX_CSSPropertyValue::Bold, L"bold", 0xB18313A1},
62 {CFX_CSSPropertyValue::SmallCaps, L"small-caps", 0xB299428D},
63 {CFX_CSSPropertyValue::Inline, L"inline", 0xC02D649F},
64 {CFX_CSSPropertyValue::Overline, L"overline", 0xC0EC9FA4},
65 {CFX_CSSPropertyValue::TextBottom, L"text-bottom", 0xC7D08D87},
66 {CFX_CSSPropertyValue::Larger, L"larger", 0xCD3C409D},
67 {CFX_CSSPropertyValue::InlineTable, L"inline-table", 0xD131F494},
68 {CFX_CSSPropertyValue::InlineBlock, L"inline-block", 0xD26A8BD7},
69 {CFX_CSSPropertyValue::Blink, L"blink", 0xDC36E390},
70 {CFX_CSSPropertyValue::Block, L"block", 0xDCD480AB},
71 {CFX_CSSPropertyValue::Italic, L"italic", 0xE31D5396},
72 {CFX_CSSPropertyValue::LineThrough, L"line-through", 0xE4C5A276},
73 {CFX_CSSPropertyValue::XLarge, L"x-large", 0xF008E390},
74 {CFX_CSSPropertyValue::Large, L"large", 0xF4434FCB},
75 {CFX_CSSPropertyValue::Left, L"left", 0xF5AD782B},
76 {CFX_CSSPropertyValue::TextTop, L"text-top", 0xFCB58D45},
77 };
78 const int32_t g_iCSSPropertyValueCount =
79 sizeof(g_CFX_CSSPropertyValues) / sizeof(CFX_CSSPropertyValueTable);
80 static_assert(g_iCSSPropertyValueCount ==
81 static_cast<int32_t>(CFX_CSSPropertyValue::LAST_MARKER),
82 "Property value table differs in size from property value enum");
83
84 struct CFX_CSSLengthUnitTable {
85 uint16_t wHash;
86 CFX_CSSNumberType wValue;
87 };
88 const CFX_CSSLengthUnitTable g_CFX_CSSLengthUnits[] = {
89 {0x0672, CFX_CSSNumberType::EMS},
90 {0x067D, CFX_CSSNumberType::EXS},
91 {0x1AF7, CFX_CSSNumberType::Inches},
92 {0x2F7A, CFX_CSSNumberType::MilliMeters},
93 {0x3ED3, CFX_CSSNumberType::Picas},
94 {0x3EE4, CFX_CSSNumberType::Points},
95 {0x3EE8, CFX_CSSNumberType::Pixels},
96 {0xFC30, CFX_CSSNumberType::CentiMeters},
97 };
98
99 struct CFX_CSSColorTable {
100 uint32_t dwHash;
101 FX_ARGB dwValue;
102 };
103 const CFX_CSSColorTable g_CFX_CSSColors[] = {
104 {0x031B47FE, 0xff000080}, {0x0BB8DF5B, 0xffff0000},
105 {0x0D82A78C, 0xff800000}, {0x2ACC82E8, 0xff00ffff},
106 {0x2D083986, 0xff008080}, {0x4A6A6195, 0xffc0c0c0},
107 {0x546A8EF3, 0xff808080}, {0x65C9169C, 0xffffa500},
108 {0x8422BB61, 0xffffffff}, {0x9271A558, 0xff800080},
109 {0xA65A3EE3, 0xffff00ff}, {0xB1345708, 0xff0000ff},
110 {0xB6D2CF1F, 0xff808000}, {0xD19B5E1C, 0xffffff00},
111 {0xDB64391D, 0xff000000}, {0xF616D507, 0xff00ff00},
112 {0xF6EFFF31, 0xff008000},
113 };
114
GetCSSPropertyValueByName(const WideStringView & wsName)115 const CFX_CSSPropertyValueTable* GetCSSPropertyValueByName(
116 const WideStringView& wsName) {
117 ASSERT(!wsName.IsEmpty());
118 uint32_t dwHash = FX_HashCode_GetW(wsName, true);
119 int32_t iEnd = g_iCSSPropertyValueCount;
120 int32_t iMid, iStart = 0;
121 uint32_t dwMid;
122 do {
123 iMid = (iStart + iEnd) / 2;
124 dwMid = g_CFX_CSSPropertyValues[iMid].dwHash;
125 if (dwHash == dwMid) {
126 return g_CFX_CSSPropertyValues + iMid;
127 } else if (dwHash > dwMid) {
128 iStart = iMid + 1;
129 } else {
130 iEnd = iMid - 1;
131 }
132 } while (iStart <= iEnd);
133 return nullptr;
134 }
135
GetCSSLengthUnitByName(const WideStringView & wsName)136 const CFX_CSSLengthUnitTable* GetCSSLengthUnitByName(
137 const WideStringView& wsName) {
138 ASSERT(!wsName.IsEmpty());
139 uint16_t wHash = FX_HashCode_GetW(wsName, true);
140 int32_t iEnd =
141 sizeof(g_CFX_CSSLengthUnits) / sizeof(CFX_CSSLengthUnitTable) - 1;
142 int32_t iMid, iStart = 0;
143 uint16_t wMid;
144 do {
145 iMid = (iStart + iEnd) / 2;
146 wMid = g_CFX_CSSLengthUnits[iMid].wHash;
147 if (wHash == wMid) {
148 return g_CFX_CSSLengthUnits + iMid;
149 } else if (wHash > wMid) {
150 iStart = iMid + 1;
151 } else {
152 iEnd = iMid - 1;
153 }
154 } while (iStart <= iEnd);
155 return nullptr;
156 }
157
GetCSSColorByName(const WideStringView & wsName)158 const CFX_CSSColorTable* GetCSSColorByName(const WideStringView& wsName) {
159 ASSERT(!wsName.IsEmpty());
160 uint32_t dwHash = FX_HashCode_GetW(wsName, true);
161 int32_t iEnd = sizeof(g_CFX_CSSColors) / sizeof(CFX_CSSColorTable) - 1;
162 int32_t iMid, iStart = 0;
163 uint32_t dwMid;
164 do {
165 iMid = (iStart + iEnd) / 2;
166 dwMid = g_CFX_CSSColors[iMid].dwHash;
167 if (dwHash == dwMid) {
168 return g_CFX_CSSColors + iMid;
169 } else if (dwHash > dwMid) {
170 iStart = iMid + 1;
171 } else {
172 iEnd = iMid - 1;
173 }
174 } while (iStart <= iEnd);
175 return nullptr;
176 }
177
ParseCSSNumber(const wchar_t * pszValue,int32_t iValueLen,float & fValue,CFX_CSSNumberType & eUnit)178 bool ParseCSSNumber(const wchar_t* pszValue,
179 int32_t iValueLen,
180 float& fValue,
181 CFX_CSSNumberType& eUnit) {
182 ASSERT(pszValue && iValueLen > 0);
183 int32_t iUsedLen = 0;
184 fValue = FXSYS_wcstof(pszValue, iValueLen, &iUsedLen);
185 if (iUsedLen <= 0)
186 return false;
187
188 iValueLen -= iUsedLen;
189 pszValue += iUsedLen;
190 eUnit = CFX_CSSNumberType::Number;
191 if (iValueLen >= 1 && *pszValue == '%') {
192 eUnit = CFX_CSSNumberType::Percent;
193 } else if (iValueLen == 2) {
194 const CFX_CSSLengthUnitTable* pUnit =
195 GetCSSLengthUnitByName(WideStringView(pszValue, 2));
196 if (pUnit)
197 eUnit = pUnit->wValue;
198 }
199 return true;
200 }
201
202 } // namespace
203
204 // static
ParseCSSString(const wchar_t * pszValue,int32_t iValueLen,int32_t * iOffset,int32_t * iLength)205 bool CFX_CSSDeclaration::ParseCSSString(const wchar_t* pszValue,
206 int32_t iValueLen,
207 int32_t* iOffset,
208 int32_t* iLength) {
209 ASSERT(pszValue && iValueLen > 0);
210 *iOffset = 0;
211 *iLength = iValueLen;
212 if (iValueLen >= 2) {
213 wchar_t first = pszValue[0], last = pszValue[iValueLen - 1];
214 if ((first == '\"' && last == '\"') || (first == '\'' && last == '\'')) {
215 *iOffset = 1;
216 *iLength -= 2;
217 }
218 }
219 return iValueLen > 0;
220 }
221
222 // static.
ParseCSSColor(const wchar_t * pszValue,int32_t iValueLen,FX_ARGB * dwColor)223 bool CFX_CSSDeclaration::ParseCSSColor(const wchar_t* pszValue,
224 int32_t iValueLen,
225 FX_ARGB* dwColor) {
226 ASSERT(pszValue && iValueLen > 0);
227 ASSERT(dwColor);
228
229 if (*pszValue == '#') {
230 switch (iValueLen) {
231 case 4: {
232 uint8_t red = Hex2Dec((uint8_t)pszValue[1], (uint8_t)pszValue[1]);
233 uint8_t green = Hex2Dec((uint8_t)pszValue[2], (uint8_t)pszValue[2]);
234 uint8_t blue = Hex2Dec((uint8_t)pszValue[3], (uint8_t)pszValue[3]);
235 *dwColor = ArgbEncode(255, red, green, blue);
236 return true;
237 }
238 case 7: {
239 uint8_t red = Hex2Dec((uint8_t)pszValue[1], (uint8_t)pszValue[2]);
240 uint8_t green = Hex2Dec((uint8_t)pszValue[3], (uint8_t)pszValue[4]);
241 uint8_t blue = Hex2Dec((uint8_t)pszValue[5], (uint8_t)pszValue[6]);
242 *dwColor = ArgbEncode(255, red, green, blue);
243 return true;
244 }
245 default:
246 return false;
247 }
248 }
249
250 if (iValueLen >= 10) {
251 if (pszValue[iValueLen - 1] != ')' || FXSYS_wcsnicmp(L"rgb(", pszValue, 4))
252 return false;
253
254 uint8_t rgb[3] = {0};
255 float fValue;
256 CFX_CSSPrimitiveType eType;
257 CFX_CSSValueListParser list(pszValue + 4, iValueLen - 5, ',');
258 for (int32_t i = 0; i < 3; ++i) {
259 if (!list.NextValue(&eType, &pszValue, &iValueLen))
260 return false;
261 if (eType != CFX_CSSPrimitiveType::Number)
262 return false;
263 CFX_CSSNumberType eNumType;
264 if (!ParseCSSNumber(pszValue, iValueLen, fValue, eNumType))
265 return false;
266
267 rgb[i] = eNumType == CFX_CSSNumberType::Percent
268 ? FXSYS_round(fValue * 2.55f)
269 : FXSYS_round(fValue);
270 }
271 *dwColor = ArgbEncode(255, rgb[0], rgb[1], rgb[2]);
272 return true;
273 }
274
275 const CFX_CSSColorTable* pColor =
276 GetCSSColorByName(WideStringView(pszValue, iValueLen));
277 if (!pColor)
278 return false;
279
280 *dwColor = pColor->dwValue;
281 return true;
282 }
283
CFX_CSSDeclaration()284 CFX_CSSDeclaration::CFX_CSSDeclaration() {}
285
~CFX_CSSDeclaration()286 CFX_CSSDeclaration::~CFX_CSSDeclaration() {}
287
GetProperty(CFX_CSSProperty eProperty,bool * bImportant) const288 RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::GetProperty(
289 CFX_CSSProperty eProperty,
290 bool* bImportant) const {
291 for (const auto& p : properties_) {
292 if (p->eProperty == eProperty) {
293 *bImportant = p->bImportant;
294 return p->pValue;
295 }
296 }
297 return nullptr;
298 }
299
AddPropertyHolder(CFX_CSSProperty eProperty,RetainPtr<CFX_CSSValue> pValue,bool bImportant)300 void CFX_CSSDeclaration::AddPropertyHolder(CFX_CSSProperty eProperty,
301 RetainPtr<CFX_CSSValue> pValue,
302 bool bImportant) {
303 auto pHolder = pdfium::MakeUnique<CFX_CSSPropertyHolder>();
304 pHolder->bImportant = bImportant;
305 pHolder->eProperty = eProperty;
306 pHolder->pValue = pValue;
307 properties_.push_back(std::move(pHolder));
308 }
309
AddProperty(const CFX_CSSPropertyTable * pTable,const WideStringView & value)310 void CFX_CSSDeclaration::AddProperty(const CFX_CSSPropertyTable* pTable,
311 const WideStringView& value) {
312 ASSERT(!value.IsEmpty());
313
314 const wchar_t* pszValue = value.unterminated_c_str();
315 int32_t iValueLen = value.GetLength();
316 bool bImportant = false;
317 if (iValueLen >= 10 && pszValue[iValueLen - 10] == '!' &&
318 FXSYS_wcsnicmp(L"important", pszValue + iValueLen - 9, 9) == 0) {
319 if ((iValueLen -= 10) == 0)
320 return;
321
322 bImportant = true;
323 }
324 const uint32_t dwType = pTable->dwType;
325 switch (dwType & 0x0F) {
326 case CFX_CSSVALUETYPE_Primitive: {
327 static const uint32_t g_ValueGuessOrder[] = {
328 CFX_CSSVALUETYPE_MaybeNumber, CFX_CSSVALUETYPE_MaybeEnum,
329 CFX_CSSVALUETYPE_MaybeColor, CFX_CSSVALUETYPE_MaybeString,
330 };
331 static const int32_t g_ValueGuessCount =
332 sizeof(g_ValueGuessOrder) / sizeof(uint32_t);
333 for (int32_t i = 0; i < g_ValueGuessCount; ++i) {
334 const uint32_t dwMatch = dwType & g_ValueGuessOrder[i];
335 if (dwMatch == 0) {
336 continue;
337 }
338 RetainPtr<CFX_CSSValue> pCSSValue;
339 switch (dwMatch) {
340 case CFX_CSSVALUETYPE_MaybeNumber:
341 pCSSValue = ParseNumber(pszValue, iValueLen);
342 break;
343 case CFX_CSSVALUETYPE_MaybeEnum:
344 pCSSValue = ParseEnum(pszValue, iValueLen);
345 break;
346 case CFX_CSSVALUETYPE_MaybeColor:
347 pCSSValue = ParseColor(pszValue, iValueLen);
348 break;
349 case CFX_CSSVALUETYPE_MaybeString:
350 pCSSValue = ParseString(pszValue, iValueLen);
351 break;
352 default:
353 break;
354 }
355 if (pCSSValue) {
356 AddPropertyHolder(pTable->eName, pCSSValue, bImportant);
357 return;
358 }
359
360 if ((dwType & ~(g_ValueGuessOrder[i])) == CFX_CSSVALUETYPE_Primitive)
361 return;
362 }
363 break;
364 }
365 case CFX_CSSVALUETYPE_Shorthand: {
366 RetainPtr<CFX_CSSValue> pWidth;
367 switch (pTable->eName) {
368 case CFX_CSSProperty::Font:
369 ParseFontProperty(pszValue, iValueLen, bImportant);
370 return;
371 case CFX_CSSProperty::Border:
372 if (ParseBorderProperty(pszValue, iValueLen, pWidth)) {
373 AddPropertyHolder(CFX_CSSProperty::BorderLeftWidth, pWidth,
374 bImportant);
375 AddPropertyHolder(CFX_CSSProperty::BorderTopWidth, pWidth,
376 bImportant);
377 AddPropertyHolder(CFX_CSSProperty::BorderRightWidth, pWidth,
378 bImportant);
379 AddPropertyHolder(CFX_CSSProperty::BorderBottomWidth, pWidth,
380 bImportant);
381 return;
382 }
383 break;
384 case CFX_CSSProperty::BorderLeft:
385 if (ParseBorderProperty(pszValue, iValueLen, pWidth)) {
386 AddPropertyHolder(CFX_CSSProperty::BorderLeftWidth, pWidth,
387 bImportant);
388 return;
389 }
390 break;
391 case CFX_CSSProperty::BorderTop:
392 if (ParseBorderProperty(pszValue, iValueLen, pWidth)) {
393 AddPropertyHolder(CFX_CSSProperty::BorderTopWidth, pWidth,
394 bImportant);
395 return;
396 }
397 break;
398 case CFX_CSSProperty::BorderRight:
399 if (ParseBorderProperty(pszValue, iValueLen, pWidth)) {
400 AddPropertyHolder(CFX_CSSProperty::BorderRightWidth, pWidth,
401 bImportant);
402 return;
403 }
404 break;
405 case CFX_CSSProperty::BorderBottom:
406 if (ParseBorderProperty(pszValue, iValueLen, pWidth)) {
407 AddPropertyHolder(CFX_CSSProperty::BorderBottomWidth, pWidth,
408 bImportant);
409 return;
410 }
411 break;
412 default:
413 break;
414 }
415 } break;
416 case CFX_CSSVALUETYPE_List:
417 ParseValueListProperty(pTable, pszValue, iValueLen, bImportant);
418 return;
419 default:
420 NOTREACHED();
421 break;
422 }
423 }
424
AddProperty(const WideString & prop,const WideString & value)425 void CFX_CSSDeclaration::AddProperty(const WideString& prop,
426 const WideString& value) {
427 custom_properties_.push_back(
428 pdfium::MakeUnique<CFX_CSSCustomProperty>(prop, value));
429 }
430
ParseNumber(const wchar_t * pszValue,int32_t iValueLen)431 RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseNumber(const wchar_t* pszValue,
432 int32_t iValueLen) {
433 float fValue;
434 CFX_CSSNumberType eUnit;
435 if (!ParseCSSNumber(pszValue, iValueLen, fValue, eUnit))
436 return nullptr;
437 return pdfium::MakeRetain<CFX_CSSNumberValue>(eUnit, fValue);
438 }
439
ParseEnum(const wchar_t * pszValue,int32_t iValueLen)440 RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseEnum(const wchar_t* pszValue,
441 int32_t iValueLen) {
442 const CFX_CSSPropertyValueTable* pValue =
443 GetCSSPropertyValueByName(WideStringView(pszValue, iValueLen));
444 return pValue ? pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName) : nullptr;
445 }
446
ParseColor(const wchar_t * pszValue,int32_t iValueLen)447 RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseColor(const wchar_t* pszValue,
448 int32_t iValueLen) {
449 FX_ARGB dwColor;
450 if (!ParseCSSColor(pszValue, iValueLen, &dwColor))
451 return nullptr;
452 return pdfium::MakeRetain<CFX_CSSColorValue>(dwColor);
453 }
454
ParseString(const wchar_t * pszValue,int32_t iValueLen)455 RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseString(const wchar_t* pszValue,
456 int32_t iValueLen) {
457 int32_t iOffset;
458 if (!ParseCSSString(pszValue, iValueLen, &iOffset, &iValueLen))
459 return nullptr;
460
461 if (iValueLen <= 0)
462 return nullptr;
463
464 return pdfium::MakeRetain<CFX_CSSStringValue>(
465 WideString(pszValue + iOffset, iValueLen));
466 }
467
ParseValueListProperty(const CFX_CSSPropertyTable * pTable,const wchar_t * pszValue,int32_t iValueLen,bool bImportant)468 void CFX_CSSDeclaration::ParseValueListProperty(
469 const CFX_CSSPropertyTable* pTable,
470 const wchar_t* pszValue,
471 int32_t iValueLen,
472 bool bImportant) {
473 wchar_t separator =
474 (pTable->eName == CFX_CSSProperty::FontFamily) ? ',' : ' ';
475 CFX_CSSValueListParser parser(pszValue, iValueLen, separator);
476
477 const uint32_t dwType = pTable->dwType;
478 CFX_CSSPrimitiveType eType;
479 std::vector<RetainPtr<CFX_CSSValue>> list;
480 while (parser.NextValue(&eType, &pszValue, &iValueLen)) {
481 switch (eType) {
482 case CFX_CSSPrimitiveType::Number:
483 if (dwType & CFX_CSSVALUETYPE_MaybeNumber) {
484 float fValue;
485 CFX_CSSNumberType eNumType;
486 if (ParseCSSNumber(pszValue, iValueLen, fValue, eNumType))
487 list.push_back(
488 pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue));
489 }
490 break;
491 case CFX_CSSPrimitiveType::String:
492 if (dwType & CFX_CSSVALUETYPE_MaybeColor) {
493 FX_ARGB dwColor;
494 if (ParseCSSColor(pszValue, iValueLen, &dwColor)) {
495 list.push_back(pdfium::MakeRetain<CFX_CSSColorValue>(dwColor));
496 continue;
497 }
498 }
499 if (dwType & CFX_CSSVALUETYPE_MaybeEnum) {
500 const CFX_CSSPropertyValueTable* pValue =
501 GetCSSPropertyValueByName(WideStringView(pszValue, iValueLen));
502 if (pValue) {
503 list.push_back(pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName));
504 continue;
505 }
506 }
507 if (dwType & CFX_CSSVALUETYPE_MaybeString) {
508 list.push_back(pdfium::MakeRetain<CFX_CSSStringValue>(
509 WideString(pszValue, iValueLen)));
510 }
511 break;
512 case CFX_CSSPrimitiveType::RGB:
513 if (dwType & CFX_CSSVALUETYPE_MaybeColor) {
514 FX_ARGB dwColor;
515 if (ParseCSSColor(pszValue, iValueLen, &dwColor)) {
516 list.push_back(pdfium::MakeRetain<CFX_CSSColorValue>(dwColor));
517 }
518 }
519 break;
520 default:
521 break;
522 }
523 }
524 if (list.empty())
525 return;
526
527 switch (pTable->eName) {
528 case CFX_CSSProperty::BorderWidth:
529 Add4ValuesProperty(list, bImportant, CFX_CSSProperty::BorderLeftWidth,
530 CFX_CSSProperty::BorderTopWidth,
531 CFX_CSSProperty::BorderRightWidth,
532 CFX_CSSProperty::BorderBottomWidth);
533 return;
534 case CFX_CSSProperty::Margin:
535 Add4ValuesProperty(list, bImportant, CFX_CSSProperty::MarginLeft,
536 CFX_CSSProperty::MarginTop,
537 CFX_CSSProperty::MarginRight,
538 CFX_CSSProperty::MarginBottom);
539 return;
540 case CFX_CSSProperty::Padding:
541 Add4ValuesProperty(list, bImportant, CFX_CSSProperty::PaddingLeft,
542 CFX_CSSProperty::PaddingTop,
543 CFX_CSSProperty::PaddingRight,
544 CFX_CSSProperty::PaddingBottom);
545 return;
546 default: {
547 auto pList = pdfium::MakeRetain<CFX_CSSValueList>(list);
548 AddPropertyHolder(pTable->eName, pList, bImportant);
549 return;
550 }
551 }
552 }
553
Add4ValuesProperty(const std::vector<RetainPtr<CFX_CSSValue>> & list,bool bImportant,CFX_CSSProperty eLeft,CFX_CSSProperty eTop,CFX_CSSProperty eRight,CFX_CSSProperty eBottom)554 void CFX_CSSDeclaration::Add4ValuesProperty(
555 const std::vector<RetainPtr<CFX_CSSValue>>& list,
556 bool bImportant,
557 CFX_CSSProperty eLeft,
558 CFX_CSSProperty eTop,
559 CFX_CSSProperty eRight,
560 CFX_CSSProperty eBottom) {
561 switch (list.size()) {
562 case 1:
563 AddPropertyHolder(eLeft, list[0], bImportant);
564 AddPropertyHolder(eTop, list[0], bImportant);
565 AddPropertyHolder(eRight, list[0], bImportant);
566 AddPropertyHolder(eBottom, list[0], bImportant);
567 return;
568 case 2:
569 AddPropertyHolder(eLeft, list[1], bImportant);
570 AddPropertyHolder(eTop, list[0], bImportant);
571 AddPropertyHolder(eRight, list[1], bImportant);
572 AddPropertyHolder(eBottom, list[0], bImportant);
573 return;
574 case 3:
575 AddPropertyHolder(eLeft, list[1], bImportant);
576 AddPropertyHolder(eTop, list[0], bImportant);
577 AddPropertyHolder(eRight, list[1], bImportant);
578 AddPropertyHolder(eBottom, list[2], bImportant);
579 return;
580 case 4:
581 AddPropertyHolder(eLeft, list[3], bImportant);
582 AddPropertyHolder(eTop, list[0], bImportant);
583 AddPropertyHolder(eRight, list[1], bImportant);
584 AddPropertyHolder(eBottom, list[2], bImportant);
585 return;
586 default:
587 break;
588 }
589 }
590
ParseBorderProperty(const wchar_t * pszValue,int32_t iValueLen,RetainPtr<CFX_CSSValue> & pWidth) const591 bool CFX_CSSDeclaration::ParseBorderProperty(
592 const wchar_t* pszValue,
593 int32_t iValueLen,
594 RetainPtr<CFX_CSSValue>& pWidth) const {
595 pWidth.Reset(nullptr);
596
597 CFX_CSSValueListParser parser(pszValue, iValueLen, ' ');
598 CFX_CSSPrimitiveType eType;
599 while (parser.NextValue(&eType, &pszValue, &iValueLen)) {
600 switch (eType) {
601 case CFX_CSSPrimitiveType::Number: {
602 if (pWidth)
603 continue;
604
605 float fValue;
606 CFX_CSSNumberType eNumType;
607 if (ParseCSSNumber(pszValue, iValueLen, fValue, eNumType))
608 pWidth = pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue);
609 break;
610 }
611 case CFX_CSSPrimitiveType::String: {
612 const CFX_CSSColorTable* pColorItem =
613 GetCSSColorByName(WideStringView(pszValue, iValueLen));
614 if (pColorItem)
615 continue;
616
617 const CFX_CSSPropertyValueTable* pValue =
618 GetCSSPropertyValueByName(WideStringView(pszValue, iValueLen));
619 if (!pValue)
620 continue;
621
622 switch (pValue->eName) {
623 case CFX_CSSPropertyValue::Thin:
624 case CFX_CSSPropertyValue::Thick:
625 case CFX_CSSPropertyValue::Medium:
626 if (!pWidth)
627 pWidth = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
628 break;
629 default:
630 break;
631 }
632 break;
633 }
634 default:
635 break;
636 }
637 }
638 if (!pWidth)
639 pWidth =
640 pdfium::MakeRetain<CFX_CSSNumberValue>(CFX_CSSNumberType::Number, 0.0f);
641
642 return true;
643 }
644
ParseFontProperty(const wchar_t * pszValue,int32_t iValueLen,bool bImportant)645 void CFX_CSSDeclaration::ParseFontProperty(const wchar_t* pszValue,
646 int32_t iValueLen,
647 bool bImportant) {
648 CFX_CSSValueListParser parser(pszValue, iValueLen, '/');
649 RetainPtr<CFX_CSSValue> pStyle;
650 RetainPtr<CFX_CSSValue> pVariant;
651 RetainPtr<CFX_CSSValue> pWeight;
652 RetainPtr<CFX_CSSValue> pFontSize;
653 RetainPtr<CFX_CSSValue> pLineHeight;
654 std::vector<RetainPtr<CFX_CSSValue>> familyList;
655 CFX_CSSPrimitiveType eType;
656 while (parser.NextValue(&eType, &pszValue, &iValueLen)) {
657 switch (eType) {
658 case CFX_CSSPrimitiveType::String: {
659 const CFX_CSSPropertyValueTable* pValue =
660 GetCSSPropertyValueByName(WideStringView(pszValue, iValueLen));
661 if (pValue) {
662 switch (pValue->eName) {
663 case CFX_CSSPropertyValue::XxSmall:
664 case CFX_CSSPropertyValue::XSmall:
665 case CFX_CSSPropertyValue::Small:
666 case CFX_CSSPropertyValue::Medium:
667 case CFX_CSSPropertyValue::Large:
668 case CFX_CSSPropertyValue::XLarge:
669 case CFX_CSSPropertyValue::XxLarge:
670 case CFX_CSSPropertyValue::Smaller:
671 case CFX_CSSPropertyValue::Larger:
672 if (!pFontSize)
673 pFontSize = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
674 continue;
675 case CFX_CSSPropertyValue::Bold:
676 case CFX_CSSPropertyValue::Bolder:
677 case CFX_CSSPropertyValue::Lighter:
678 if (!pWeight)
679 pWeight = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
680 continue;
681 case CFX_CSSPropertyValue::Italic:
682 case CFX_CSSPropertyValue::Oblique:
683 if (!pStyle)
684 pStyle = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
685 continue;
686 case CFX_CSSPropertyValue::SmallCaps:
687 if (!pVariant)
688 pVariant = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
689 continue;
690 case CFX_CSSPropertyValue::Normal:
691 if (!pStyle)
692 pStyle = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
693 else if (!pVariant)
694 pVariant = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
695 else if (!pWeight)
696 pWeight = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
697 else if (!pFontSize)
698 pFontSize = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
699 else if (!pLineHeight)
700 pLineHeight =
701 pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
702 continue;
703 default:
704 break;
705 }
706 }
707 if (pFontSize) {
708 familyList.push_back(pdfium::MakeRetain<CFX_CSSStringValue>(
709 WideString(pszValue, iValueLen)));
710 }
711 parser.UseCommaSeparator();
712 break;
713 }
714 case CFX_CSSPrimitiveType::Number: {
715 float fValue;
716 CFX_CSSNumberType eNumType;
717 if (!ParseCSSNumber(pszValue, iValueLen, fValue, eNumType))
718 break;
719 if (eType == CFX_CSSPrimitiveType::Number) {
720 switch ((int32_t)fValue) {
721 case 100:
722 case 200:
723 case 300:
724 case 400:
725 case 500:
726 case 600:
727 case 700:
728 case 800:
729 case 900:
730 if (!pWeight)
731 pWeight = pdfium::MakeRetain<CFX_CSSNumberValue>(
732 CFX_CSSNumberType::Number, fValue);
733 continue;
734 }
735 }
736 if (!pFontSize)
737 pFontSize = pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue);
738 else if (!pLineHeight)
739 pLineHeight =
740 pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue);
741 break;
742 }
743 default:
744 break;
745 }
746 }
747
748 if (!pStyle) {
749 pStyle = pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Normal);
750 }
751 if (!pVariant) {
752 pVariant =
753 pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Normal);
754 }
755 if (!pWeight) {
756 pWeight =
757 pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Normal);
758 }
759 if (!pFontSize) {
760 pFontSize =
761 pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Medium);
762 }
763 if (!pLineHeight) {
764 pLineHeight =
765 pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Normal);
766 }
767
768 AddPropertyHolder(CFX_CSSProperty::FontStyle, pStyle, bImportant);
769 AddPropertyHolder(CFX_CSSProperty::FontVariant, pVariant, bImportant);
770 AddPropertyHolder(CFX_CSSProperty::FontWeight, pWeight, bImportant);
771 AddPropertyHolder(CFX_CSSProperty::FontSize, pFontSize, bImportant);
772 AddPropertyHolder(CFX_CSSProperty::LineHeight, pLineHeight, bImportant);
773 if (!familyList.empty()) {
774 auto pList = pdfium::MakeRetain<CFX_CSSValueList>(familyList);
775 AddPropertyHolder(CFX_CSSProperty::FontFamily, pList, bImportant);
776 }
777 }
778
PropertyCountForTesting() const779 size_t CFX_CSSDeclaration::PropertyCountForTesting() const {
780 return properties_.size();
781 }
782