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