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