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 <cmath>
10 #include <utility>
11 
12 #include "core/fxcrt/css/cfx_csscolorvalue.h"
13 #include "core/fxcrt/css/cfx_csscustomproperty.h"
14 #include "core/fxcrt/css/cfx_cssenumvalue.h"
15 #include "core/fxcrt/css/cfx_cssnumbervalue.h"
16 #include "core/fxcrt/css/cfx_csspropertyholder.h"
17 #include "core/fxcrt/css/cfx_cssstringvalue.h"
18 #include "core/fxcrt/css/cfx_cssvaluelist.h"
19 #include "core/fxcrt/css/cfx_cssvaluelistparser.h"
20 #include "core/fxcrt/fx_extension.h"
21 #include "third_party/base/logging.h"
22 #include "third_party/base/ptr_util.h"
23 
24 namespace {
25 
Hex2Dec(uint8_t hexHigh,uint8_t hexLow)26 uint8_t Hex2Dec(uint8_t hexHigh, uint8_t hexLow) {
27   return (FXSYS_HexCharToInt(hexHigh) << 4) + FXSYS_HexCharToInt(hexLow);
28 }
29 
ParseCSSNumber(const wchar_t * pszValue,int32_t iValueLen,float * pValue,CFX_CSSNumberType * pOutUnit)30 bool ParseCSSNumber(const wchar_t* pszValue,
31                     int32_t iValueLen,
32                     float* pValue,
33                     CFX_CSSNumberType* pOutUnit) {
34   ASSERT(pszValue);
35   ASSERT(iValueLen > 0);
36 
37   int32_t iUsedLen = 0;
38   *pValue = FXSYS_wcstof(pszValue, iValueLen, &iUsedLen);
39   if (iUsedLen <= 0 || !std::isfinite(*pValue))
40     return false;
41 
42   iValueLen -= iUsedLen;
43   pszValue += iUsedLen;
44   *pOutUnit = CFX_CSSNumberType::Number;
45   if (iValueLen >= 1 && *pszValue == '%') {
46     *pOutUnit = CFX_CSSNumberType::Percent;
47   } else if (iValueLen == 2) {
48     const CFX_CSSData::LengthUnit* pUnit =
49         CFX_CSSData::GetLengthUnitByName(WideStringView(pszValue, 2));
50     if (pUnit)
51       *pOutUnit = pUnit->type;
52   }
53   return true;
54 }
55 
56 }  // namespace
57 
58 // static
ParseCSSString(const wchar_t * pszValue,int32_t iValueLen,int32_t * iOffset,int32_t * iLength)59 bool CFX_CSSDeclaration::ParseCSSString(const wchar_t* pszValue,
60                                         int32_t iValueLen,
61                                         int32_t* iOffset,
62                                         int32_t* iLength) {
63   ASSERT(pszValue);
64   ASSERT(iValueLen > 0);
65 
66   *iOffset = 0;
67   *iLength = iValueLen;
68   if (iValueLen >= 2) {
69     wchar_t first = pszValue[0], last = pszValue[iValueLen - 1];
70     if ((first == '\"' && last == '\"') || (first == '\'' && last == '\'')) {
71       *iOffset = 1;
72       *iLength -= 2;
73     }
74   }
75   return iValueLen > 0;
76 }
77 
78 // static.
ParseCSSColor(const wchar_t * pszValue,int32_t iValueLen,FX_ARGB * dwColor)79 bool CFX_CSSDeclaration::ParseCSSColor(const wchar_t* pszValue,
80                                        int32_t iValueLen,
81                                        FX_ARGB* dwColor) {
82   ASSERT(pszValue);
83   ASSERT(iValueLen > 0);
84   ASSERT(dwColor);
85 
86   if (*pszValue == '#') {
87     switch (iValueLen) {
88       case 4: {
89         uint8_t red = Hex2Dec((uint8_t)pszValue[1], (uint8_t)pszValue[1]);
90         uint8_t green = Hex2Dec((uint8_t)pszValue[2], (uint8_t)pszValue[2]);
91         uint8_t blue = Hex2Dec((uint8_t)pszValue[3], (uint8_t)pszValue[3]);
92         *dwColor = ArgbEncode(255, red, green, blue);
93         return true;
94       }
95       case 7: {
96         uint8_t red = Hex2Dec((uint8_t)pszValue[1], (uint8_t)pszValue[2]);
97         uint8_t green = Hex2Dec((uint8_t)pszValue[3], (uint8_t)pszValue[4]);
98         uint8_t blue = Hex2Dec((uint8_t)pszValue[5], (uint8_t)pszValue[6]);
99         *dwColor = ArgbEncode(255, red, green, blue);
100         return true;
101       }
102       default:
103         return false;
104     }
105   }
106 
107   if (iValueLen >= 10) {
108     if (pszValue[iValueLen - 1] != ')' || FXSYS_wcsnicmp(L"rgb(", pszValue, 4))
109       return false;
110 
111     uint8_t rgb[3] = {0};
112     float fValue;
113     CFX_CSSPrimitiveType eType;
114     CFX_CSSValueListParser list(pszValue + 4, iValueLen - 5, ',');
115     for (int32_t i = 0; i < 3; ++i) {
116       if (!list.NextValue(&eType, &pszValue, &iValueLen))
117         return false;
118       if (eType != CFX_CSSPrimitiveType::Number)
119         return false;
120       CFX_CSSNumberType eNumType;
121       if (!ParseCSSNumber(pszValue, iValueLen, &fValue, &eNumType))
122         return false;
123 
124       rgb[i] = eNumType == CFX_CSSNumberType::Percent
125                    ? FXSYS_roundf(fValue * 2.55f)
126                    : FXSYS_roundf(fValue);
127     }
128     *dwColor = ArgbEncode(255, rgb[0], rgb[1], rgb[2]);
129     return true;
130   }
131 
132   const CFX_CSSData::Color* pColor =
133       CFX_CSSData::GetColorByName(WideStringView(pszValue, iValueLen));
134   if (!pColor)
135     return false;
136 
137   *dwColor = pColor->value;
138   return true;
139 }
140 
CFX_CSSDeclaration()141 CFX_CSSDeclaration::CFX_CSSDeclaration() {}
142 
~CFX_CSSDeclaration()143 CFX_CSSDeclaration::~CFX_CSSDeclaration() {}
144 
GetProperty(CFX_CSSProperty eProperty,bool * bImportant) const145 RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::GetProperty(
146     CFX_CSSProperty eProperty,
147     bool* bImportant) const {
148   for (const auto& p : properties_) {
149     if (p->eProperty == eProperty) {
150       *bImportant = p->bImportant;
151       return p->pValue;
152     }
153   }
154   return nullptr;
155 }
156 
AddPropertyHolder(CFX_CSSProperty eProperty,RetainPtr<CFX_CSSValue> pValue,bool bImportant)157 void CFX_CSSDeclaration::AddPropertyHolder(CFX_CSSProperty eProperty,
158                                            RetainPtr<CFX_CSSValue> pValue,
159                                            bool bImportant) {
160   auto pHolder = pdfium::MakeUnique<CFX_CSSPropertyHolder>();
161   pHolder->bImportant = bImportant;
162   pHolder->eProperty = eProperty;
163   pHolder->pValue = pValue;
164   properties_.push_back(std::move(pHolder));
165 }
166 
AddProperty(const CFX_CSSData::Property * property,WideStringView value)167 void CFX_CSSDeclaration::AddProperty(const CFX_CSSData::Property* property,
168                                      WideStringView value) {
169   ASSERT(!value.IsEmpty());
170 
171   const wchar_t* pszValue = value.unterminated_c_str();
172   int32_t iValueLen = value.GetLength();
173   bool bImportant = false;
174   if (iValueLen >= 10 && pszValue[iValueLen - 10] == '!' &&
175       FXSYS_wcsnicmp(L"important", pszValue + iValueLen - 9, 9) == 0) {
176     if ((iValueLen -= 10) == 0)
177       return;
178 
179     bImportant = true;
180   }
181   const uint32_t dwType = property->dwType;
182   switch (dwType & 0x0F) {
183     case CFX_CSSVALUETYPE_Primitive: {
184       static constexpr CFX_CSSVALUETYPE kValueGuessOrder[] = {
185           CFX_CSSVALUETYPE_MaybeNumber,
186           CFX_CSSVALUETYPE_MaybeEnum,
187           CFX_CSSVALUETYPE_MaybeColor,
188           CFX_CSSVALUETYPE_MaybeString,
189       };
190       for (uint32_t guess : kValueGuessOrder) {
191         const uint32_t dwMatch = dwType & guess;
192         if (dwMatch == 0)
193           continue;
194 
195         RetainPtr<CFX_CSSValue> pCSSValue;
196         switch (dwMatch) {
197           case CFX_CSSVALUETYPE_MaybeNumber:
198             pCSSValue = ParseNumber(pszValue, iValueLen);
199             break;
200           case CFX_CSSVALUETYPE_MaybeEnum:
201             pCSSValue = ParseEnum(pszValue, iValueLen);
202             break;
203           case CFX_CSSVALUETYPE_MaybeColor:
204             pCSSValue = ParseColor(pszValue, iValueLen);
205             break;
206           case CFX_CSSVALUETYPE_MaybeString:
207             pCSSValue = ParseString(pszValue, iValueLen);
208             break;
209           default:
210             break;
211         }
212         if (pCSSValue) {
213           AddPropertyHolder(property->eName, pCSSValue, bImportant);
214           return;
215         }
216 
217         if ((dwType & ~guess) == CFX_CSSVALUETYPE_Primitive)
218           return;
219       }
220       break;
221     }
222     case CFX_CSSVALUETYPE_Shorthand: {
223       RetainPtr<CFX_CSSValue> pWidth;
224       switch (property->eName) {
225         case CFX_CSSProperty::Font:
226           ParseFontProperty(pszValue, iValueLen, bImportant);
227           return;
228         case CFX_CSSProperty::Border:
229           if (ParseBorderProperty(pszValue, iValueLen, pWidth)) {
230             AddPropertyHolder(CFX_CSSProperty::BorderLeftWidth, pWidth,
231                               bImportant);
232             AddPropertyHolder(CFX_CSSProperty::BorderTopWidth, pWidth,
233                               bImportant);
234             AddPropertyHolder(CFX_CSSProperty::BorderRightWidth, pWidth,
235                               bImportant);
236             AddPropertyHolder(CFX_CSSProperty::BorderBottomWidth, pWidth,
237                               bImportant);
238             return;
239           }
240           break;
241         case CFX_CSSProperty::BorderLeft:
242           if (ParseBorderProperty(pszValue, iValueLen, pWidth)) {
243             AddPropertyHolder(CFX_CSSProperty::BorderLeftWidth, pWidth,
244                               bImportant);
245             return;
246           }
247           break;
248         case CFX_CSSProperty::BorderTop:
249           if (ParseBorderProperty(pszValue, iValueLen, pWidth)) {
250             AddPropertyHolder(CFX_CSSProperty::BorderTopWidth, pWidth,
251                               bImportant);
252             return;
253           }
254           break;
255         case CFX_CSSProperty::BorderRight:
256           if (ParseBorderProperty(pszValue, iValueLen, pWidth)) {
257             AddPropertyHolder(CFX_CSSProperty::BorderRightWidth, pWidth,
258                               bImportant);
259             return;
260           }
261           break;
262         case CFX_CSSProperty::BorderBottom:
263           if (ParseBorderProperty(pszValue, iValueLen, pWidth)) {
264             AddPropertyHolder(CFX_CSSProperty::BorderBottomWidth, pWidth,
265                               bImportant);
266             return;
267           }
268           break;
269         default:
270           break;
271       }
272     } break;
273     case CFX_CSSVALUETYPE_List:
274       ParseValueListProperty(property, pszValue, iValueLen, bImportant);
275       return;
276     default:
277       NOTREACHED();
278       break;
279   }
280 }
281 
AddProperty(const WideString & prop,const WideString & value)282 void CFX_CSSDeclaration::AddProperty(const WideString& prop,
283                                      const WideString& value) {
284   custom_properties_.push_back(
285       pdfium::MakeUnique<CFX_CSSCustomProperty>(prop, value));
286 }
287 
ParseNumber(const wchar_t * pszValue,int32_t iValueLen)288 RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseNumber(const wchar_t* pszValue,
289                                                         int32_t iValueLen) {
290   float fValue;
291   CFX_CSSNumberType eUnit;
292   if (!ParseCSSNumber(pszValue, iValueLen, &fValue, &eUnit))
293     return nullptr;
294   return pdfium::MakeRetain<CFX_CSSNumberValue>(eUnit, fValue);
295 }
296 
ParseEnum(const wchar_t * pszValue,int32_t iValueLen)297 RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseEnum(const wchar_t* pszValue,
298                                                       int32_t iValueLen) {
299   const CFX_CSSData::PropertyValue* pValue =
300       CFX_CSSData::GetPropertyValueByName(WideStringView(pszValue, iValueLen));
301   return pValue ? pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName) : nullptr;
302 }
303 
ParseColor(const wchar_t * pszValue,int32_t iValueLen)304 RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseColor(const wchar_t* pszValue,
305                                                        int32_t iValueLen) {
306   FX_ARGB dwColor;
307   if (!ParseCSSColor(pszValue, iValueLen, &dwColor))
308     return nullptr;
309   return pdfium::MakeRetain<CFX_CSSColorValue>(dwColor);
310 }
311 
ParseString(const wchar_t * pszValue,int32_t iValueLen)312 RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseString(const wchar_t* pszValue,
313                                                         int32_t iValueLen) {
314   int32_t iOffset;
315   if (!ParseCSSString(pszValue, iValueLen, &iOffset, &iValueLen))
316     return nullptr;
317 
318   if (iValueLen <= 0)
319     return nullptr;
320 
321   return pdfium::MakeRetain<CFX_CSSStringValue>(
322       WideString(pszValue + iOffset, iValueLen));
323 }
324 
ParseValueListProperty(const CFX_CSSData::Property * pProperty,const wchar_t * pszValue,int32_t iValueLen,bool bImportant)325 void CFX_CSSDeclaration::ParseValueListProperty(
326     const CFX_CSSData::Property* pProperty,
327     const wchar_t* pszValue,
328     int32_t iValueLen,
329     bool bImportant) {
330   wchar_t separator =
331       (pProperty->eName == CFX_CSSProperty::FontFamily) ? ',' : ' ';
332   CFX_CSSValueListParser parser(pszValue, iValueLen, separator);
333 
334   const uint32_t dwType = pProperty->dwType;
335   CFX_CSSPrimitiveType eType;
336   std::vector<RetainPtr<CFX_CSSValue>> list;
337   while (parser.NextValue(&eType, &pszValue, &iValueLen)) {
338     switch (eType) {
339       case CFX_CSSPrimitiveType::Number:
340         if (dwType & CFX_CSSVALUETYPE_MaybeNumber) {
341           float fValue;
342           CFX_CSSNumberType eNumType;
343           if (ParseCSSNumber(pszValue, iValueLen, &fValue, &eNumType))
344             list.push_back(
345                 pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue));
346         }
347         break;
348       case CFX_CSSPrimitiveType::String:
349         if (dwType & CFX_CSSVALUETYPE_MaybeColor) {
350           FX_ARGB dwColor;
351           if (ParseCSSColor(pszValue, iValueLen, &dwColor)) {
352             list.push_back(pdfium::MakeRetain<CFX_CSSColorValue>(dwColor));
353             continue;
354           }
355         }
356         if (dwType & CFX_CSSVALUETYPE_MaybeEnum) {
357           const CFX_CSSData::PropertyValue* pValue =
358               CFX_CSSData::GetPropertyValueByName(
359                   WideStringView(pszValue, iValueLen));
360           if (pValue) {
361             list.push_back(pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName));
362             continue;
363           }
364         }
365         if (dwType & CFX_CSSVALUETYPE_MaybeString) {
366           list.push_back(pdfium::MakeRetain<CFX_CSSStringValue>(
367               WideString(pszValue, iValueLen)));
368         }
369         break;
370       case CFX_CSSPrimitiveType::RGB:
371         if (dwType & CFX_CSSVALUETYPE_MaybeColor) {
372           FX_ARGB dwColor;
373           if (ParseCSSColor(pszValue, iValueLen, &dwColor)) {
374             list.push_back(pdfium::MakeRetain<CFX_CSSColorValue>(dwColor));
375           }
376         }
377         break;
378       default:
379         break;
380     }
381   }
382   if (list.empty())
383     return;
384 
385   switch (pProperty->eName) {
386     case CFX_CSSProperty::BorderWidth:
387       Add4ValuesProperty(list, bImportant, CFX_CSSProperty::BorderLeftWidth,
388                          CFX_CSSProperty::BorderTopWidth,
389                          CFX_CSSProperty::BorderRightWidth,
390                          CFX_CSSProperty::BorderBottomWidth);
391       return;
392     case CFX_CSSProperty::Margin:
393       Add4ValuesProperty(list, bImportant, CFX_CSSProperty::MarginLeft,
394                          CFX_CSSProperty::MarginTop,
395                          CFX_CSSProperty::MarginRight,
396                          CFX_CSSProperty::MarginBottom);
397       return;
398     case CFX_CSSProperty::Padding:
399       Add4ValuesProperty(list, bImportant, CFX_CSSProperty::PaddingLeft,
400                          CFX_CSSProperty::PaddingTop,
401                          CFX_CSSProperty::PaddingRight,
402                          CFX_CSSProperty::PaddingBottom);
403       return;
404     default: {
405       auto pList = pdfium::MakeRetain<CFX_CSSValueList>(list);
406       AddPropertyHolder(pProperty->eName, pList, bImportant);
407       return;
408     }
409   }
410 }
411 
Add4ValuesProperty(const std::vector<RetainPtr<CFX_CSSValue>> & list,bool bImportant,CFX_CSSProperty eLeft,CFX_CSSProperty eTop,CFX_CSSProperty eRight,CFX_CSSProperty eBottom)412 void CFX_CSSDeclaration::Add4ValuesProperty(
413     const std::vector<RetainPtr<CFX_CSSValue>>& list,
414     bool bImportant,
415     CFX_CSSProperty eLeft,
416     CFX_CSSProperty eTop,
417     CFX_CSSProperty eRight,
418     CFX_CSSProperty eBottom) {
419   switch (list.size()) {
420     case 1:
421       AddPropertyHolder(eLeft, list[0], bImportant);
422       AddPropertyHolder(eTop, list[0], bImportant);
423       AddPropertyHolder(eRight, list[0], bImportant);
424       AddPropertyHolder(eBottom, list[0], bImportant);
425       return;
426     case 2:
427       AddPropertyHolder(eLeft, list[1], bImportant);
428       AddPropertyHolder(eTop, list[0], bImportant);
429       AddPropertyHolder(eRight, list[1], bImportant);
430       AddPropertyHolder(eBottom, list[0], bImportant);
431       return;
432     case 3:
433       AddPropertyHolder(eLeft, list[1], bImportant);
434       AddPropertyHolder(eTop, list[0], bImportant);
435       AddPropertyHolder(eRight, list[1], bImportant);
436       AddPropertyHolder(eBottom, list[2], bImportant);
437       return;
438     case 4:
439       AddPropertyHolder(eLeft, list[3], bImportant);
440       AddPropertyHolder(eTop, list[0], bImportant);
441       AddPropertyHolder(eRight, list[1], bImportant);
442       AddPropertyHolder(eBottom, list[2], bImportant);
443       return;
444     default:
445       break;
446   }
447 }
448 
ParseBorderProperty(const wchar_t * pszValue,int32_t iValueLen,RetainPtr<CFX_CSSValue> & pWidth) const449 bool CFX_CSSDeclaration::ParseBorderProperty(
450     const wchar_t* pszValue,
451     int32_t iValueLen,
452     RetainPtr<CFX_CSSValue>& pWidth) const {
453   pWidth.Reset(nullptr);
454 
455   CFX_CSSValueListParser parser(pszValue, iValueLen, ' ');
456   CFX_CSSPrimitiveType eType;
457   while (parser.NextValue(&eType, &pszValue, &iValueLen)) {
458     switch (eType) {
459       case CFX_CSSPrimitiveType::Number: {
460         if (pWidth)
461           continue;
462 
463         float fValue;
464         CFX_CSSNumberType eNumType;
465         if (ParseCSSNumber(pszValue, iValueLen, &fValue, &eNumType))
466           pWidth = pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue);
467         break;
468       }
469       case CFX_CSSPrimitiveType::String: {
470         const CFX_CSSData::Color* pColorItem =
471             CFX_CSSData::GetColorByName(WideStringView(pszValue, iValueLen));
472         if (pColorItem)
473           continue;
474 
475         const CFX_CSSData::PropertyValue* pValue =
476             CFX_CSSData::GetPropertyValueByName(
477                 WideStringView(pszValue, iValueLen));
478         if (!pValue)
479           continue;
480 
481         switch (pValue->eName) {
482           case CFX_CSSPropertyValue::Thin:
483           case CFX_CSSPropertyValue::Thick:
484           case CFX_CSSPropertyValue::Medium:
485             if (!pWidth)
486               pWidth = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
487             break;
488           default:
489             break;
490         }
491         break;
492       }
493       default:
494         break;
495     }
496   }
497   if (!pWidth)
498     pWidth =
499         pdfium::MakeRetain<CFX_CSSNumberValue>(CFX_CSSNumberType::Number, 0.0f);
500 
501   return true;
502 }
503 
ParseFontProperty(const wchar_t * pszValue,int32_t iValueLen,bool bImportant)504 void CFX_CSSDeclaration::ParseFontProperty(const wchar_t* pszValue,
505                                            int32_t iValueLen,
506                                            bool bImportant) {
507   CFX_CSSValueListParser parser(pszValue, iValueLen, '/');
508   RetainPtr<CFX_CSSValue> pStyle;
509   RetainPtr<CFX_CSSValue> pVariant;
510   RetainPtr<CFX_CSSValue> pWeight;
511   RetainPtr<CFX_CSSValue> pFontSize;
512   RetainPtr<CFX_CSSValue> pLineHeight;
513   std::vector<RetainPtr<CFX_CSSValue>> familyList;
514   CFX_CSSPrimitiveType eType;
515   while (parser.NextValue(&eType, &pszValue, &iValueLen)) {
516     switch (eType) {
517       case CFX_CSSPrimitiveType::String: {
518         const CFX_CSSData::PropertyValue* pValue =
519             CFX_CSSData::GetPropertyValueByName(
520                 WideStringView(pszValue, iValueLen));
521         if (pValue) {
522           switch (pValue->eName) {
523             case CFX_CSSPropertyValue::XxSmall:
524             case CFX_CSSPropertyValue::XSmall:
525             case CFX_CSSPropertyValue::Small:
526             case CFX_CSSPropertyValue::Medium:
527             case CFX_CSSPropertyValue::Large:
528             case CFX_CSSPropertyValue::XLarge:
529             case CFX_CSSPropertyValue::XxLarge:
530             case CFX_CSSPropertyValue::Smaller:
531             case CFX_CSSPropertyValue::Larger:
532               if (!pFontSize)
533                 pFontSize = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
534               continue;
535             case CFX_CSSPropertyValue::Bold:
536             case CFX_CSSPropertyValue::Bolder:
537             case CFX_CSSPropertyValue::Lighter:
538               if (!pWeight)
539                 pWeight = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
540               continue;
541             case CFX_CSSPropertyValue::Italic:
542             case CFX_CSSPropertyValue::Oblique:
543               if (!pStyle)
544                 pStyle = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
545               continue;
546             case CFX_CSSPropertyValue::SmallCaps:
547               if (!pVariant)
548                 pVariant = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
549               continue;
550             case CFX_CSSPropertyValue::Normal:
551               if (!pStyle)
552                 pStyle = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
553               else if (!pVariant)
554                 pVariant = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
555               else if (!pWeight)
556                 pWeight = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
557               else if (!pFontSize)
558                 pFontSize = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
559               else if (!pLineHeight)
560                 pLineHeight =
561                     pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName);
562               continue;
563             default:
564               break;
565           }
566         }
567         if (pFontSize) {
568           familyList.push_back(pdfium::MakeRetain<CFX_CSSStringValue>(
569               WideString(pszValue, iValueLen)));
570         }
571         parser.UseCommaSeparator();
572         break;
573       }
574       case CFX_CSSPrimitiveType::Number: {
575         float fValue;
576         CFX_CSSNumberType eNumType;
577         if (!ParseCSSNumber(pszValue, iValueLen, &fValue, &eNumType))
578           break;
579         if (eType == CFX_CSSPrimitiveType::Number) {
580           switch ((int32_t)fValue) {
581             case 100:
582             case 200:
583             case 300:
584             case 400:
585             case 500:
586             case 600:
587             case 700:
588             case 800:
589             case 900:
590               if (!pWeight)
591                 pWeight = pdfium::MakeRetain<CFX_CSSNumberValue>(
592                     CFX_CSSNumberType::Number, fValue);
593               continue;
594           }
595         }
596         if (!pFontSize)
597           pFontSize = pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue);
598         else if (!pLineHeight)
599           pLineHeight =
600               pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue);
601         break;
602       }
603       default:
604         break;
605     }
606   }
607 
608   if (!pStyle) {
609     pStyle = pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Normal);
610   }
611   if (!pVariant) {
612     pVariant =
613         pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Normal);
614   }
615   if (!pWeight) {
616     pWeight =
617         pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Normal);
618   }
619   if (!pFontSize) {
620     pFontSize =
621         pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Medium);
622   }
623   if (!pLineHeight) {
624     pLineHeight =
625         pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Normal);
626   }
627 
628   AddPropertyHolder(CFX_CSSProperty::FontStyle, pStyle, bImportant);
629   AddPropertyHolder(CFX_CSSProperty::FontVariant, pVariant, bImportant);
630   AddPropertyHolder(CFX_CSSProperty::FontWeight, pWeight, bImportant);
631   AddPropertyHolder(CFX_CSSProperty::FontSize, pFontSize, bImportant);
632   AddPropertyHolder(CFX_CSSProperty::LineHeight, pLineHeight, bImportant);
633   if (!familyList.empty()) {
634     auto pList = pdfium::MakeRetain<CFX_CSSValueList>(familyList);
635     AddPropertyHolder(CFX_CSSProperty::FontFamily, pList, bImportant);
636   }
637 }
638 
PropertyCountForTesting() const639 size_t CFX_CSSDeclaration::PropertyCountForTesting() const {
640   return properties_.size();
641 }
642