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 "core/fxcrt/css/cfx_cssstyleselector.h"
      8 
      9 #include <algorithm>
     10 #include <utility>
     11 
     12 #include "core/fxcrt/css/cfx_csscolorvalue.h"
     13 #include "core/fxcrt/css/cfx_csscomputedstyle.h"
     14 #include "core/fxcrt/css/cfx_csscustomproperty.h"
     15 #include "core/fxcrt/css/cfx_cssdeclaration.h"
     16 #include "core/fxcrt/css/cfx_cssenumvalue.h"
     17 #include "core/fxcrt/css/cfx_csspropertyholder.h"
     18 #include "core/fxcrt/css/cfx_cssselector.h"
     19 #include "core/fxcrt/css/cfx_cssstylesheet.h"
     20 #include "core/fxcrt/css/cfx_csssyntaxparser.h"
     21 #include "core/fxcrt/css/cfx_cssvaluelist.h"
     22 #include "third_party/base/logging.h"
     23 #include "third_party/base/ptr_util.h"
     24 
     25 CFX_CSSStyleSelector::CFX_CSSStyleSelector() : m_fDefFontSize(12.0f) {}
     26 
     27 CFX_CSSStyleSelector::~CFX_CSSStyleSelector() {}
     28 
     29 void CFX_CSSStyleSelector::SetDefFontSize(float fFontSize) {
     30   ASSERT(fFontSize > 0);
     31   m_fDefFontSize = fFontSize;
     32 }
     33 
     34 RetainPtr<CFX_CSSComputedStyle> CFX_CSSStyleSelector::CreateComputedStyle(
     35     CFX_CSSComputedStyle* pParentStyle) {
     36   auto pStyle = pdfium::MakeRetain<CFX_CSSComputedStyle>();
     37   if (pParentStyle)
     38     pStyle->m_InheritedData = pParentStyle->m_InheritedData;
     39   return pStyle;
     40 }
     41 
     42 void CFX_CSSStyleSelector::SetUAStyleSheet(
     43     std::unique_ptr<CFX_CSSStyleSheet> pSheet) {
     44   m_UAStyles = std::move(pSheet);
     45 }
     46 
     47 void CFX_CSSStyleSelector::UpdateStyleIndex() {
     48   m_UARules.Clear();
     49   m_UARules.AddRulesFrom(m_UAStyles.get());
     50 }
     51 
     52 std::vector<const CFX_CSSDeclaration*> CFX_CSSStyleSelector::MatchDeclarations(
     53     const WideString& tagname) {
     54   std::vector<const CFX_CSSDeclaration*> matchedDecls;
     55   if (m_UARules.CountSelectors() == 0 || tagname.IsEmpty())
     56     return matchedDecls;
     57 
     58   auto* rules = m_UARules.GetTagRuleData(tagname);
     59   if (!rules)
     60     return matchedDecls;
     61 
     62   for (const auto& d : *rules) {
     63     if (MatchSelector(tagname, d->pSelector))
     64       matchedDecls.push_back(d->pDeclaration);
     65   }
     66   return matchedDecls;
     67 }
     68 
     69 bool CFX_CSSStyleSelector::MatchSelector(const WideString& tagname,
     70                                          CFX_CSSSelector* pSel) {
     71   // TODO(dsinclair): The code only supports a single level of selector at this
     72   // point. None of the code using selectors required the complexity so lets
     73   // just say we don't support them to simplify the code for now.
     74   if (!pSel || pSel->GetNextSelector() ||
     75       pSel->GetType() == CFX_CSSSelectorType::Descendant) {
     76     return false;
     77   }
     78   return pSel->GetNameHash() == FX_HashCode_GetW(tagname.c_str(), true);
     79 }
     80 
     81 void CFX_CSSStyleSelector::ComputeStyle(
     82     const std::vector<const CFX_CSSDeclaration*>& declArray,
     83     const WideString& styleString,
     84     const WideString& alignString,
     85     CFX_CSSComputedStyle* pDest) {
     86   std::unique_ptr<CFX_CSSDeclaration> pDecl;
     87   if (!styleString.IsEmpty() || !alignString.IsEmpty()) {
     88     pDecl = pdfium::MakeUnique<CFX_CSSDeclaration>();
     89 
     90     if (!styleString.IsEmpty())
     91       AppendInlineStyle(pDecl.get(), styleString);
     92     if (!alignString.IsEmpty()) {
     93       pDecl->AddProperty(CFX_GetCSSPropertyByEnum(CFX_CSSProperty::TextAlign),
     94                          alignString.AsStringView());
     95     }
     96   }
     97   ApplyDeclarations(declArray, pDecl.get(), pDest);
     98 }
     99 
    100 void CFX_CSSStyleSelector::ApplyDeclarations(
    101     const std::vector<const CFX_CSSDeclaration*>& declArray,
    102     const CFX_CSSDeclaration* extraDecl,
    103     CFX_CSSComputedStyle* pComputedStyle) {
    104   std::vector<const CFX_CSSPropertyHolder*> importants;
    105   std::vector<const CFX_CSSPropertyHolder*> normals;
    106   std::vector<const CFX_CSSCustomProperty*> customs;
    107 
    108   for (auto* decl : declArray)
    109     ExtractValues(decl, &importants, &normals, &customs);
    110 
    111   if (extraDecl)
    112     ExtractValues(extraDecl, &importants, &normals, &customs);
    113 
    114   for (auto* prop : normals)
    115     ApplyProperty(prop->eProperty, prop->pValue, pComputedStyle);
    116 
    117   for (auto* prop : customs)
    118     pComputedStyle->AddCustomStyle(*prop);
    119 
    120   for (auto* prop : importants)
    121     ApplyProperty(prop->eProperty, prop->pValue, pComputedStyle);
    122 }
    123 
    124 void CFX_CSSStyleSelector::ExtractValues(
    125     const CFX_CSSDeclaration* decl,
    126     std::vector<const CFX_CSSPropertyHolder*>* importants,
    127     std::vector<const CFX_CSSPropertyHolder*>* normals,
    128     std::vector<const CFX_CSSCustomProperty*>* custom) {
    129   for (const auto& holder : *decl) {
    130     if (holder->bImportant)
    131       importants->push_back(holder.get());
    132     else
    133       normals->push_back(holder.get());
    134   }
    135   for (auto it = decl->custom_begin(); it != decl->custom_end(); it++)
    136     custom->push_back(it->get());
    137 }
    138 
    139 void CFX_CSSStyleSelector::AppendInlineStyle(CFX_CSSDeclaration* pDecl,
    140                                              const WideString& style) {
    141   ASSERT(pDecl && !style.IsEmpty());
    142 
    143   auto pSyntax = pdfium::MakeUnique<CFX_CSSSyntaxParser>(
    144       style.c_str(), style.GetLength(), 32, true);
    145   int32_t iLen2 = 0;
    146   const CFX_CSSPropertyTable* table = nullptr;
    147   WideString wsName;
    148   while (1) {
    149     CFX_CSSSyntaxStatus eStatus = pSyntax->DoSyntaxParse();
    150     if (eStatus == CFX_CSSSyntaxStatus::PropertyName) {
    151       WideStringView strValue = pSyntax->GetCurrentString();
    152       table = CFX_GetCSSPropertyByName(strValue);
    153       if (!table)
    154         wsName = WideString(strValue);
    155     } else if (eStatus == CFX_CSSSyntaxStatus::PropertyValue) {
    156       if (table || iLen2 > 0) {
    157         WideStringView strValue = pSyntax->GetCurrentString();
    158         if (!strValue.IsEmpty()) {
    159           if (table)
    160             pDecl->AddProperty(table, strValue);
    161           else if (iLen2 > 0)
    162             pDecl->AddProperty(wsName, WideString(strValue));
    163         }
    164       }
    165     } else {
    166       break;
    167     }
    168   }
    169 }
    170 
    171 void CFX_CSSStyleSelector::ApplyProperty(CFX_CSSProperty eProperty,
    172                                          const RetainPtr<CFX_CSSValue>& pValue,
    173                                          CFX_CSSComputedStyle* pComputedStyle) {
    174   if (pValue->GetType() != CFX_CSSPrimitiveType::List) {
    175     CFX_CSSPrimitiveType eType = pValue->GetType();
    176     switch (eProperty) {
    177       case CFX_CSSProperty::Display:
    178         if (eType == CFX_CSSPrimitiveType::Enum) {
    179           pComputedStyle->m_NonInheritedData.m_eDisplay =
    180               ToDisplay(pValue.As<CFX_CSSEnumValue>()->Value());
    181         }
    182         break;
    183       case CFX_CSSProperty::FontSize: {
    184         float& fFontSize = pComputedStyle->m_InheritedData.m_fFontSize;
    185         if (eType == CFX_CSSPrimitiveType::Number) {
    186           fFontSize = pValue.As<CFX_CSSNumberValue>()->Apply(fFontSize);
    187         } else if (eType == CFX_CSSPrimitiveType::Enum) {
    188           fFontSize =
    189               ToFontSize(pValue.As<CFX_CSSEnumValue>()->Value(), fFontSize);
    190         }
    191       } break;
    192       case CFX_CSSProperty::LineHeight:
    193         if (eType == CFX_CSSPrimitiveType::Number) {
    194           RetainPtr<CFX_CSSNumberValue> v = pValue.As<CFX_CSSNumberValue>();
    195           if (v->Kind() == CFX_CSSNumberType::Number) {
    196             pComputedStyle->m_InheritedData.m_fLineHeight =
    197                 v->Value() * pComputedStyle->m_InheritedData.m_fFontSize;
    198           } else {
    199             pComputedStyle->m_InheritedData.m_fLineHeight =
    200                 v->Apply(pComputedStyle->m_InheritedData.m_fFontSize);
    201           }
    202         }
    203         break;
    204       case CFX_CSSProperty::TextAlign:
    205         if (eType == CFX_CSSPrimitiveType::Enum) {
    206           pComputedStyle->m_InheritedData.m_eTextAlign =
    207               ToTextAlign(pValue.As<CFX_CSSEnumValue>()->Value());
    208         }
    209         break;
    210       case CFX_CSSProperty::TextIndent:
    211         SetLengthWithPercent(pComputedStyle->m_InheritedData.m_TextIndent,
    212                              eType, pValue,
    213                              pComputedStyle->m_InheritedData.m_fFontSize);
    214         break;
    215       case CFX_CSSProperty::FontWeight:
    216         if (eType == CFX_CSSPrimitiveType::Enum) {
    217           pComputedStyle->m_InheritedData.m_wFontWeight =
    218               ToFontWeight(pValue.As<CFX_CSSEnumValue>()->Value());
    219         } else if (eType == CFX_CSSPrimitiveType::Number) {
    220           int32_t iValue =
    221               (int32_t)pValue.As<CFX_CSSNumberValue>()->Value() / 100;
    222           if (iValue >= 1 && iValue <= 9) {
    223             pComputedStyle->m_InheritedData.m_wFontWeight = iValue * 100;
    224           }
    225         }
    226         break;
    227       case CFX_CSSProperty::FontStyle:
    228         if (eType == CFX_CSSPrimitiveType::Enum) {
    229           pComputedStyle->m_InheritedData.m_eFontStyle =
    230               ToFontStyle(pValue.As<CFX_CSSEnumValue>()->Value());
    231         }
    232         break;
    233       case CFX_CSSProperty::Color:
    234         if (eType == CFX_CSSPrimitiveType::RGB) {
    235           pComputedStyle->m_InheritedData.m_dwFontColor =
    236               pValue.As<CFX_CSSColorValue>()->Value();
    237         }
    238         break;
    239       case CFX_CSSProperty::MarginLeft:
    240         if (SetLengthWithPercent(
    241                 pComputedStyle->m_NonInheritedData.m_MarginWidth.left, eType,
    242                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
    243           pComputedStyle->m_NonInheritedData.m_bHasMargin = true;
    244         }
    245         break;
    246       case CFX_CSSProperty::MarginTop:
    247         if (SetLengthWithPercent(
    248                 pComputedStyle->m_NonInheritedData.m_MarginWidth.top, eType,
    249                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
    250           pComputedStyle->m_NonInheritedData.m_bHasMargin = true;
    251         }
    252         break;
    253       case CFX_CSSProperty::MarginRight:
    254         if (SetLengthWithPercent(
    255                 pComputedStyle->m_NonInheritedData.m_MarginWidth.right, eType,
    256                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
    257           pComputedStyle->m_NonInheritedData.m_bHasMargin = true;
    258         }
    259         break;
    260       case CFX_CSSProperty::MarginBottom:
    261         if (SetLengthWithPercent(
    262                 pComputedStyle->m_NonInheritedData.m_MarginWidth.bottom, eType,
    263                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
    264           pComputedStyle->m_NonInheritedData.m_bHasMargin = true;
    265         }
    266         break;
    267       case CFX_CSSProperty::PaddingLeft:
    268         if (SetLengthWithPercent(
    269                 pComputedStyle->m_NonInheritedData.m_PaddingWidth.left, eType,
    270                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
    271           pComputedStyle->m_NonInheritedData.m_bHasPadding = true;
    272         }
    273         break;
    274       case CFX_CSSProperty::PaddingTop:
    275         if (SetLengthWithPercent(
    276                 pComputedStyle->m_NonInheritedData.m_PaddingWidth.top, eType,
    277                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
    278           pComputedStyle->m_NonInheritedData.m_bHasPadding = true;
    279         }
    280         break;
    281       case CFX_CSSProperty::PaddingRight:
    282         if (SetLengthWithPercent(
    283                 pComputedStyle->m_NonInheritedData.m_PaddingWidth.right, eType,
    284                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
    285           pComputedStyle->m_NonInheritedData.m_bHasPadding = true;
    286         }
    287         break;
    288       case CFX_CSSProperty::PaddingBottom:
    289         if (SetLengthWithPercent(
    290                 pComputedStyle->m_NonInheritedData.m_PaddingWidth.bottom, eType,
    291                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
    292           pComputedStyle->m_NonInheritedData.m_bHasPadding = true;
    293         }
    294         break;
    295       case CFX_CSSProperty::BorderLeftWidth:
    296         if (SetLengthWithPercent(
    297                 pComputedStyle->m_NonInheritedData.m_BorderWidth.left, eType,
    298                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
    299           pComputedStyle->m_NonInheritedData.m_bHasBorder = true;
    300         }
    301         break;
    302       case CFX_CSSProperty::BorderTopWidth:
    303         if (SetLengthWithPercent(
    304                 pComputedStyle->m_NonInheritedData.m_BorderWidth.top, eType,
    305                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
    306           pComputedStyle->m_NonInheritedData.m_bHasBorder = true;
    307         }
    308         break;
    309       case CFX_CSSProperty::BorderRightWidth:
    310         if (SetLengthWithPercent(
    311                 pComputedStyle->m_NonInheritedData.m_BorderWidth.right, eType,
    312                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
    313           pComputedStyle->m_NonInheritedData.m_bHasBorder = true;
    314         }
    315         break;
    316       case CFX_CSSProperty::BorderBottomWidth:
    317         if (SetLengthWithPercent(
    318                 pComputedStyle->m_NonInheritedData.m_BorderWidth.bottom, eType,
    319                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
    320           pComputedStyle->m_NonInheritedData.m_bHasBorder = true;
    321         }
    322         break;
    323       case CFX_CSSProperty::VerticalAlign:
    324         if (eType == CFX_CSSPrimitiveType::Enum) {
    325           pComputedStyle->m_NonInheritedData.m_eVerticalAlign =
    326               ToVerticalAlign(pValue.As<CFX_CSSEnumValue>()->Value());
    327         } else if (eType == CFX_CSSPrimitiveType::Number) {
    328           pComputedStyle->m_NonInheritedData.m_eVerticalAlign =
    329               CFX_CSSVerticalAlign::Number;
    330           pComputedStyle->m_NonInheritedData.m_fVerticalAlign =
    331               pValue.As<CFX_CSSNumberValue>()->Apply(
    332                   pComputedStyle->m_InheritedData.m_fFontSize);
    333         }
    334         break;
    335       case CFX_CSSProperty::FontVariant:
    336         if (eType == CFX_CSSPrimitiveType::Enum) {
    337           pComputedStyle->m_InheritedData.m_eFontVariant =
    338               ToFontVariant(pValue.As<CFX_CSSEnumValue>()->Value());
    339         }
    340         break;
    341       case CFX_CSSProperty::LetterSpacing:
    342         if (eType == CFX_CSSPrimitiveType::Enum) {
    343           pComputedStyle->m_InheritedData.m_LetterSpacing.Set(
    344               CFX_CSSLengthUnit::Normal);
    345         } else if (eType == CFX_CSSPrimitiveType::Number) {
    346           if (pValue.As<CFX_CSSNumberValue>()->Kind() ==
    347               CFX_CSSNumberType::Percent) {
    348             break;
    349           }
    350 
    351           SetLengthWithPercent(pComputedStyle->m_InheritedData.m_LetterSpacing,
    352                                eType, pValue,
    353                                pComputedStyle->m_InheritedData.m_fFontSize);
    354         }
    355         break;
    356       case CFX_CSSProperty::WordSpacing:
    357         if (eType == CFX_CSSPrimitiveType::Enum) {
    358           pComputedStyle->m_InheritedData.m_WordSpacing.Set(
    359               CFX_CSSLengthUnit::Normal);
    360         } else if (eType == CFX_CSSPrimitiveType::Number) {
    361           if (pValue.As<CFX_CSSNumberValue>()->Kind() ==
    362               CFX_CSSNumberType::Percent) {
    363             break;
    364           }
    365           SetLengthWithPercent(pComputedStyle->m_InheritedData.m_WordSpacing,
    366                                eType, pValue,
    367                                pComputedStyle->m_InheritedData.m_fFontSize);
    368         }
    369         break;
    370       case CFX_CSSProperty::Top:
    371         SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Top, eType,
    372                              pValue,
    373                              pComputedStyle->m_InheritedData.m_fFontSize);
    374         break;
    375       case CFX_CSSProperty::Bottom:
    376         SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Bottom, eType,
    377                              pValue,
    378                              pComputedStyle->m_InheritedData.m_fFontSize);
    379         break;
    380       case CFX_CSSProperty::Left:
    381         SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Left, eType,
    382                              pValue,
    383                              pComputedStyle->m_InheritedData.m_fFontSize);
    384         break;
    385       case CFX_CSSProperty::Right:
    386         SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Right, eType,
    387                              pValue,
    388                              pComputedStyle->m_InheritedData.m_fFontSize);
    389         break;
    390       default:
    391         break;
    392     }
    393   } else if (pValue->GetType() == CFX_CSSPrimitiveType::List) {
    394     RetainPtr<CFX_CSSValueList> pList = pValue.As<CFX_CSSValueList>();
    395     int32_t iCount = pList->CountValues();
    396     if (iCount > 0) {
    397       switch (eProperty) {
    398         case CFX_CSSProperty::FontFamily:
    399           pComputedStyle->m_InheritedData.m_pFontFamily = pList;
    400           break;
    401         case CFX_CSSProperty::TextDecoration:
    402           pComputedStyle->m_NonInheritedData.m_dwTextDecoration =
    403               ToTextDecoration(pList);
    404           break;
    405         default:
    406           break;
    407       }
    408     }
    409   } else {
    410     NOTREACHED();
    411   }
    412 }
    413 
    414 CFX_CSSDisplay CFX_CSSStyleSelector::ToDisplay(CFX_CSSPropertyValue eValue) {
    415   switch (eValue) {
    416     case CFX_CSSPropertyValue::Block:
    417       return CFX_CSSDisplay::Block;
    418     case CFX_CSSPropertyValue::None:
    419       return CFX_CSSDisplay::None;
    420     case CFX_CSSPropertyValue::ListItem:
    421       return CFX_CSSDisplay::ListItem;
    422     case CFX_CSSPropertyValue::InlineTable:
    423       return CFX_CSSDisplay::InlineTable;
    424     case CFX_CSSPropertyValue::InlineBlock:
    425       return CFX_CSSDisplay::InlineBlock;
    426     case CFX_CSSPropertyValue::Inline:
    427     default:
    428       return CFX_CSSDisplay::Inline;
    429   }
    430 }
    431 
    432 CFX_CSSTextAlign CFX_CSSStyleSelector::ToTextAlign(
    433     CFX_CSSPropertyValue eValue) {
    434   switch (eValue) {
    435     case CFX_CSSPropertyValue::Center:
    436       return CFX_CSSTextAlign::Center;
    437     case CFX_CSSPropertyValue::Right:
    438       return CFX_CSSTextAlign::Right;
    439     case CFX_CSSPropertyValue::Justify:
    440       return CFX_CSSTextAlign::Justify;
    441     case CFX_CSSPropertyValue::Left:
    442     default:
    443       return CFX_CSSTextAlign::Left;
    444   }
    445 }
    446 
    447 uint16_t CFX_CSSStyleSelector::ToFontWeight(CFX_CSSPropertyValue eValue) {
    448   switch (eValue) {
    449     case CFX_CSSPropertyValue::Bold:
    450       return 700;
    451     case CFX_CSSPropertyValue::Bolder:
    452       return 900;
    453     case CFX_CSSPropertyValue::Lighter:
    454       return 200;
    455     case CFX_CSSPropertyValue::Normal:
    456     default:
    457       return 400;
    458   }
    459 }
    460 
    461 CFX_CSSFontStyle CFX_CSSStyleSelector::ToFontStyle(
    462     CFX_CSSPropertyValue eValue) {
    463   switch (eValue) {
    464     case CFX_CSSPropertyValue::Italic:
    465     case CFX_CSSPropertyValue::Oblique:
    466       return CFX_CSSFontStyle::Italic;
    467     default:
    468       return CFX_CSSFontStyle::Normal;
    469   }
    470 }
    471 
    472 bool CFX_CSSStyleSelector::SetLengthWithPercent(
    473     CFX_CSSLength& width,
    474     CFX_CSSPrimitiveType eType,
    475     const RetainPtr<CFX_CSSValue>& pValue,
    476     float fFontSize) {
    477   if (eType == CFX_CSSPrimitiveType::Number) {
    478     RetainPtr<CFX_CSSNumberValue> v = pValue.As<CFX_CSSNumberValue>();
    479     if (v->Kind() == CFX_CSSNumberType::Percent) {
    480       width.Set(CFX_CSSLengthUnit::Percent,
    481                 pValue.As<CFX_CSSNumberValue>()->Value() / 100.0f);
    482       return width.NonZero();
    483     }
    484 
    485     float fValue = v->Apply(fFontSize);
    486     width.Set(CFX_CSSLengthUnit::Point, fValue);
    487     return width.NonZero();
    488   } else if (eType == CFX_CSSPrimitiveType::Enum) {
    489     switch (pValue.As<CFX_CSSEnumValue>()->Value()) {
    490       case CFX_CSSPropertyValue::Auto:
    491         width.Set(CFX_CSSLengthUnit::Auto);
    492         return true;
    493       case CFX_CSSPropertyValue::None:
    494         width.Set(CFX_CSSLengthUnit::None);
    495         return true;
    496       case CFX_CSSPropertyValue::Thin:
    497         width.Set(CFX_CSSLengthUnit::Point, 2);
    498         return true;
    499       case CFX_CSSPropertyValue::Medium:
    500         width.Set(CFX_CSSLengthUnit::Point, 3);
    501         return true;
    502       case CFX_CSSPropertyValue::Thick:
    503         width.Set(CFX_CSSLengthUnit::Point, 4);
    504         return true;
    505       default:
    506         return false;
    507     }
    508   }
    509   return false;
    510 }
    511 
    512 float CFX_CSSStyleSelector::ToFontSize(CFX_CSSPropertyValue eValue,
    513                                        float fCurFontSize) {
    514   switch (eValue) {
    515     case CFX_CSSPropertyValue::XxSmall:
    516       return m_fDefFontSize / 1.2f / 1.2f / 1.2f;
    517     case CFX_CSSPropertyValue::XSmall:
    518       return m_fDefFontSize / 1.2f / 1.2f;
    519     case CFX_CSSPropertyValue::Small:
    520       return m_fDefFontSize / 1.2f;
    521     case CFX_CSSPropertyValue::Medium:
    522       return m_fDefFontSize;
    523     case CFX_CSSPropertyValue::Large:
    524       return m_fDefFontSize * 1.2f;
    525     case CFX_CSSPropertyValue::XLarge:
    526       return m_fDefFontSize * 1.2f * 1.2f;
    527     case CFX_CSSPropertyValue::XxLarge:
    528       return m_fDefFontSize * 1.2f * 1.2f * 1.2f;
    529     case CFX_CSSPropertyValue::Larger:
    530       return fCurFontSize * 1.2f;
    531     case CFX_CSSPropertyValue::Smaller:
    532       return fCurFontSize / 1.2f;
    533     default:
    534       return fCurFontSize;
    535   }
    536 }
    537 
    538 CFX_CSSVerticalAlign CFX_CSSStyleSelector::ToVerticalAlign(
    539     CFX_CSSPropertyValue eValue) {
    540   switch (eValue) {
    541     case CFX_CSSPropertyValue::Middle:
    542       return CFX_CSSVerticalAlign::Middle;
    543     case CFX_CSSPropertyValue::Bottom:
    544       return CFX_CSSVerticalAlign::Bottom;
    545     case CFX_CSSPropertyValue::Super:
    546       return CFX_CSSVerticalAlign::Super;
    547     case CFX_CSSPropertyValue::Sub:
    548       return CFX_CSSVerticalAlign::Sub;
    549     case CFX_CSSPropertyValue::Top:
    550       return CFX_CSSVerticalAlign::Top;
    551     case CFX_CSSPropertyValue::TextTop:
    552       return CFX_CSSVerticalAlign::TextTop;
    553     case CFX_CSSPropertyValue::TextBottom:
    554       return CFX_CSSVerticalAlign::TextBottom;
    555     case CFX_CSSPropertyValue::Baseline:
    556     default:
    557       return CFX_CSSVerticalAlign::Baseline;
    558   }
    559 }
    560 
    561 uint32_t CFX_CSSStyleSelector::ToTextDecoration(
    562     const RetainPtr<CFX_CSSValueList>& pValue) {
    563   uint32_t dwDecoration = 0;
    564   for (int32_t i = pValue->CountValues() - 1; i >= 0; --i) {
    565     const RetainPtr<CFX_CSSValue> pVal = pValue->GetValue(i);
    566     if (pVal->GetType() != CFX_CSSPrimitiveType::Enum)
    567       continue;
    568 
    569     switch (pVal.As<CFX_CSSEnumValue>()->Value()) {
    570       case CFX_CSSPropertyValue::Underline:
    571         dwDecoration |= CFX_CSSTEXTDECORATION_Underline;
    572         break;
    573       case CFX_CSSPropertyValue::LineThrough:
    574         dwDecoration |= CFX_CSSTEXTDECORATION_LineThrough;
    575         break;
    576       case CFX_CSSPropertyValue::Overline:
    577         dwDecoration |= CFX_CSSTEXTDECORATION_Overline;
    578         break;
    579       case CFX_CSSPropertyValue::Blink:
    580         dwDecoration |= CFX_CSSTEXTDECORATION_Blink;
    581         break;
    582       case CFX_CSSPropertyValue::Double:
    583         dwDecoration |= CFX_CSSTEXTDECORATION_Double;
    584         break;
    585       default:
    586         break;
    587     }
    588   }
    589   return dwDecoration;
    590 }
    591 
    592 CFX_CSSFontVariant CFX_CSSStyleSelector::ToFontVariant(
    593     CFX_CSSPropertyValue eValue) {
    594   return eValue == CFX_CSSPropertyValue::SmallCaps
    595              ? CFX_CSSFontVariant::SmallCaps
    596              : CFX_CSSFontVariant::Normal;
    597 }
    598