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