Home | History | Annotate | Download | only in css
      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 
     20 namespace {
     21 
     22 uint8_t Hex2Dec(uint8_t hexHigh, uint8_t hexLow) {
     23   return (FXSYS_toHexDigit(hexHigh) << 4) + FXSYS_toHexDigit(hexLow);
     24 }
     25 
     26 bool 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
     53 bool 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.
     71 bool 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 
    132 CFDE_CSSDeclaration::CFDE_CSSDeclaration() {}
    133 
    134 CFDE_CSSDeclaration::~CFDE_CSSDeclaration() {}
    135 
    136 CFX_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 
    148 void 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 
    158 void 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 
    273 void 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 
    279 CFX_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 
    289 CFX_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 
    298 CFX_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 
    307 CFX_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 
    321 void 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 
    409 void 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 
    446 bool 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 
    500 void 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 
    637 size_t CFDE_CSSDeclaration::PropertyCountForTesting() const {
    638   return properties_.size();
    639 }
    640