• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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