| // Copyright 2014 PDFium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 
 |  | 
 | #include "xfa/fde/css/cfde_cssstyleselector.h" | 
 |  | 
 | #include <algorithm> | 
 | #include <utility> | 
 |  | 
 | #include "third_party/base/logging.h" | 
 | #include "third_party/base/ptr_util.h" | 
 | #include "xfa/fde/css/cfde_csscolorvalue.h" | 
 | #include "xfa/fde/css/cfde_csscomputedstyle.h" | 
 | #include "xfa/fde/css/cfde_csscustomproperty.h" | 
 | #include "xfa/fde/css/cfde_cssdeclaration.h" | 
 | #include "xfa/fde/css/cfde_cssenumvalue.h" | 
 | #include "xfa/fde/css/cfde_csspropertyholder.h" | 
 | #include "xfa/fde/css/cfde_cssselector.h" | 
 | #include "xfa/fde/css/cfde_cssstylesheet.h" | 
 | #include "xfa/fde/css/cfde_csssyntaxparser.h" | 
 | #include "xfa/fde/css/cfde_cssvaluelist.h" | 
 | #include "xfa/fxfa/app/cxfa_csstagprovider.h" | 
 |  | 
 | CFDE_CSSStyleSelector::CFDE_CSSStyleSelector(CFGAS_FontMgr* pFontMgr) | 
 |     : m_pFontMgr(pFontMgr), m_fDefFontSize(12.0f) {} | 
 |  | 
 | CFDE_CSSStyleSelector::~CFDE_CSSStyleSelector() {} | 
 |  | 
 | void CFDE_CSSStyleSelector::SetDefFontSize(float fFontSize) { | 
 |   ASSERT(fFontSize > 0); | 
 |   m_fDefFontSize = fFontSize; | 
 | } | 
 |  | 
 | CFX_RetainPtr<CFDE_CSSComputedStyle> CFDE_CSSStyleSelector::CreateComputedStyle( | 
 |     CFDE_CSSComputedStyle* pParentStyle) { | 
 |   auto pStyle = pdfium::MakeRetain<CFDE_CSSComputedStyle>(); | 
 |   if (pParentStyle) | 
 |     pStyle->m_InheritedData = pParentStyle->m_InheritedData; | 
 |   return pStyle; | 
 | } | 
 |  | 
 | void CFDE_CSSStyleSelector::SetUAStyleSheet( | 
 |     std::unique_ptr<CFDE_CSSStyleSheet> pSheet) { | 
 |   m_UAStyles = std::move(pSheet); | 
 | } | 
 |  | 
 | void CFDE_CSSStyleSelector::UpdateStyleIndex() { | 
 |   m_UARules.Clear(); | 
 |   m_UARules.AddRulesFrom(m_UAStyles.get(), m_pFontMgr.Get()); | 
 | } | 
 |  | 
 | std::vector<const CFDE_CSSDeclaration*> | 
 | CFDE_CSSStyleSelector::MatchDeclarations(const CFX_WideString& tagname) { | 
 |   std::vector<const CFDE_CSSDeclaration*> matchedDecls; | 
 |   if (m_UARules.CountSelectors() == 0 || tagname.IsEmpty()) | 
 |     return matchedDecls; | 
 |  | 
 |   auto* rules = m_UARules.GetTagRuleData(tagname); | 
 |   if (!rules) | 
 |     return matchedDecls; | 
 |  | 
 |   for (const auto& d : *rules) { | 
 |     if (MatchSelector(tagname, d->pSelector)) | 
 |       matchedDecls.push_back(d->pDeclaration); | 
 |   } | 
 |   return matchedDecls; | 
 | } | 
 |  | 
 | bool CFDE_CSSStyleSelector::MatchSelector(const CFX_WideString& tagname, | 
 |                                           CFDE_CSSSelector* pSel) { | 
 |   // TODO(dsinclair): The code only supports a single level of selector at this | 
 |   // point. None of the code using selectors required the complexity so lets | 
 |   // just say we don't support them to simplify the code for now. | 
 |   if (!pSel || pSel->GetNextSelector() || | 
 |       pSel->GetType() == FDE_CSSSelectorType::Descendant) { | 
 |     return false; | 
 |   } | 
 |   return pSel->GetNameHash() == FX_HashCode_GetW(tagname.c_str(), true); | 
 | } | 
 |  | 
 | void CFDE_CSSStyleSelector::ComputeStyle( | 
 |     const std::vector<const CFDE_CSSDeclaration*>& declArray, | 
 |     const CFX_WideString& styleString, | 
 |     const CFX_WideString& alignString, | 
 |     CFDE_CSSComputedStyle* pDest) { | 
 |   std::unique_ptr<CFDE_CSSDeclaration> pDecl; | 
 |   if (!styleString.IsEmpty() || !alignString.IsEmpty()) { | 
 |     pDecl = pdfium::MakeUnique<CFDE_CSSDeclaration>(); | 
 |  | 
 |     if (!styleString.IsEmpty()) | 
 |       AppendInlineStyle(pDecl.get(), styleString); | 
 |     if (!alignString.IsEmpty()) { | 
 |       pDecl->AddProperty(FDE_GetCSSPropertyByEnum(FDE_CSSProperty::TextAlign), | 
 |                          alignString.AsStringC()); | 
 |     } | 
 |   } | 
 |   ApplyDeclarations(declArray, pDecl.get(), pDest); | 
 | } | 
 |  | 
 | void CFDE_CSSStyleSelector::ApplyDeclarations( | 
 |     const std::vector<const CFDE_CSSDeclaration*>& declArray, | 
 |     const CFDE_CSSDeclaration* extraDecl, | 
 |     CFDE_CSSComputedStyle* pComputedStyle) { | 
 |   std::vector<const CFDE_CSSPropertyHolder*> importants; | 
 |   std::vector<const CFDE_CSSPropertyHolder*> normals; | 
 |   std::vector<const CFDE_CSSCustomProperty*> customs; | 
 |  | 
 |   for (auto* decl : declArray) | 
 |     ExtractValues(decl, &importants, &normals, &customs); | 
 |  | 
 |   if (extraDecl) | 
 |     ExtractValues(extraDecl, &importants, &normals, &customs); | 
 |  | 
 |   for (auto* prop : normals) | 
 |     ApplyProperty(prop->eProperty, prop->pValue, pComputedStyle); | 
 |  | 
 |   for (auto* prop : customs) | 
 |     pComputedStyle->AddCustomStyle(*prop); | 
 |  | 
 |   for (auto* prop : importants) | 
 |     ApplyProperty(prop->eProperty, prop->pValue, pComputedStyle); | 
 | } | 
 |  | 
 | void CFDE_CSSStyleSelector::ExtractValues( | 
 |     const CFDE_CSSDeclaration* decl, | 
 |     std::vector<const CFDE_CSSPropertyHolder*>* importants, | 
 |     std::vector<const CFDE_CSSPropertyHolder*>* normals, | 
 |     std::vector<const CFDE_CSSCustomProperty*>* custom) { | 
 |   for (const auto& holder : *decl) { | 
 |     if (holder->bImportant) | 
 |       importants->push_back(holder.get()); | 
 |     else | 
 |       normals->push_back(holder.get()); | 
 |   } | 
 |   for (auto it = decl->custom_begin(); it != decl->custom_end(); it++) | 
 |     custom->push_back(it->get()); | 
 | } | 
 |  | 
 | void CFDE_CSSStyleSelector::AppendInlineStyle(CFDE_CSSDeclaration* pDecl, | 
 |                                               const CFX_WideString& style) { | 
 |   ASSERT(pDecl && !style.IsEmpty()); | 
 |  | 
 |   auto pSyntax = pdfium::MakeUnique<CFDE_CSSSyntaxParser>(); | 
 |   if (!pSyntax->Init(style.c_str(), style.GetLength(), 32, true)) | 
 |     return; | 
 |  | 
 |   int32_t iLen2 = 0; | 
 |   const FDE_CSSPropertyTable* table = nullptr; | 
 |   CFX_WideString wsName; | 
 |   while (1) { | 
 |     FDE_CSSSyntaxStatus eStatus = pSyntax->DoSyntaxParse(); | 
 |     if (eStatus == FDE_CSSSyntaxStatus::PropertyName) { | 
 |       CFX_WideStringC strValue = pSyntax->GetCurrentString(); | 
 |       table = FDE_GetCSSPropertyByName(strValue); | 
 |       if (!table) | 
 |         wsName = CFX_WideString(strValue); | 
 |     } else if (eStatus == FDE_CSSSyntaxStatus::PropertyValue) { | 
 |       if (table || iLen2 > 0) { | 
 |         CFX_WideStringC strValue = pSyntax->GetCurrentString(); | 
 |         if (!strValue.IsEmpty()) { | 
 |           if (table) | 
 |             pDecl->AddProperty(table, strValue); | 
 |           else if (iLen2 > 0) | 
 |             pDecl->AddProperty(wsName, CFX_WideString(strValue)); | 
 |         } | 
 |       } | 
 |     } else { | 
 |       break; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void CFDE_CSSStyleSelector::ApplyProperty( | 
 |     FDE_CSSProperty eProperty, | 
 |     const CFX_RetainPtr<CFDE_CSSValue>& pValue, | 
 |     CFDE_CSSComputedStyle* pComputedStyle) { | 
 |   if (pValue->GetType() != FDE_CSSPrimitiveType::List) { | 
 |     FDE_CSSPrimitiveType eType = pValue->GetType(); | 
 |     switch (eProperty) { | 
 |       case FDE_CSSProperty::Display: | 
 |         if (eType == FDE_CSSPrimitiveType::Enum) { | 
 |           pComputedStyle->m_NonInheritedData.m_eDisplay = | 
 |               ToDisplay(pValue.As<CFDE_CSSEnumValue>()->Value()); | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::FontSize: { | 
 |         float& fFontSize = pComputedStyle->m_InheritedData.m_fFontSize; | 
 |         if (eType == FDE_CSSPrimitiveType::Number) { | 
 |           fFontSize = pValue.As<CFDE_CSSNumberValue>()->Apply(fFontSize); | 
 |         } else if (eType == FDE_CSSPrimitiveType::Enum) { | 
 |           fFontSize = | 
 |               ToFontSize(pValue.As<CFDE_CSSEnumValue>()->Value(), fFontSize); | 
 |         } | 
 |       } break; | 
 |       case FDE_CSSProperty::LineHeight: | 
 |         if (eType == FDE_CSSPrimitiveType::Number) { | 
 |           CFX_RetainPtr<CFDE_CSSNumberValue> v = | 
 |               pValue.As<CFDE_CSSNumberValue>(); | 
 |           if (v->Kind() == FDE_CSSNumberType::Number) { | 
 |             pComputedStyle->m_InheritedData.m_fLineHeight = | 
 |                 v->Value() * pComputedStyle->m_InheritedData.m_fFontSize; | 
 |           } else { | 
 |             pComputedStyle->m_InheritedData.m_fLineHeight = | 
 |                 v->Apply(pComputedStyle->m_InheritedData.m_fFontSize); | 
 |           } | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::TextAlign: | 
 |         if (eType == FDE_CSSPrimitiveType::Enum) { | 
 |           pComputedStyle->m_InheritedData.m_eTextAlign = | 
 |               ToTextAlign(pValue.As<CFDE_CSSEnumValue>()->Value()); | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::TextIndent: | 
 |         SetLengthWithPercent(pComputedStyle->m_InheritedData.m_TextIndent, | 
 |                              eType, pValue, | 
 |                              pComputedStyle->m_InheritedData.m_fFontSize); | 
 |         break; | 
 |       case FDE_CSSProperty::FontWeight: | 
 |         if (eType == FDE_CSSPrimitiveType::Enum) { | 
 |           pComputedStyle->m_InheritedData.m_wFontWeight = | 
 |               ToFontWeight(pValue.As<CFDE_CSSEnumValue>()->Value()); | 
 |         } else if (eType == FDE_CSSPrimitiveType::Number) { | 
 |           int32_t iValue = | 
 |               (int32_t)pValue.As<CFDE_CSSNumberValue>()->Value() / 100; | 
 |           if (iValue >= 1 && iValue <= 9) { | 
 |             pComputedStyle->m_InheritedData.m_wFontWeight = iValue * 100; | 
 |           } | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::FontStyle: | 
 |         if (eType == FDE_CSSPrimitiveType::Enum) { | 
 |           pComputedStyle->m_InheritedData.m_eFontStyle = | 
 |               ToFontStyle(pValue.As<CFDE_CSSEnumValue>()->Value()); | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::Color: | 
 |         if (eType == FDE_CSSPrimitiveType::RGB) { | 
 |           pComputedStyle->m_InheritedData.m_dwFontColor = | 
 |               pValue.As<CFDE_CSSColorValue>()->Value(); | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::MarginLeft: | 
 |         if (SetLengthWithPercent( | 
 |                 pComputedStyle->m_NonInheritedData.m_MarginWidth.left, eType, | 
 |                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { | 
 |           pComputedStyle->m_NonInheritedData.m_bHasMargin = true; | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::MarginTop: | 
 |         if (SetLengthWithPercent( | 
 |                 pComputedStyle->m_NonInheritedData.m_MarginWidth.top, eType, | 
 |                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { | 
 |           pComputedStyle->m_NonInheritedData.m_bHasMargin = true; | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::MarginRight: | 
 |         if (SetLengthWithPercent( | 
 |                 pComputedStyle->m_NonInheritedData.m_MarginWidth.right, eType, | 
 |                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { | 
 |           pComputedStyle->m_NonInheritedData.m_bHasMargin = true; | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::MarginBottom: | 
 |         if (SetLengthWithPercent( | 
 |                 pComputedStyle->m_NonInheritedData.m_MarginWidth.bottom, eType, | 
 |                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { | 
 |           pComputedStyle->m_NonInheritedData.m_bHasMargin = true; | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::PaddingLeft: | 
 |         if (SetLengthWithPercent( | 
 |                 pComputedStyle->m_NonInheritedData.m_PaddingWidth.left, eType, | 
 |                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { | 
 |           pComputedStyle->m_NonInheritedData.m_bHasPadding = true; | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::PaddingTop: | 
 |         if (SetLengthWithPercent( | 
 |                 pComputedStyle->m_NonInheritedData.m_PaddingWidth.top, eType, | 
 |                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { | 
 |           pComputedStyle->m_NonInheritedData.m_bHasPadding = true; | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::PaddingRight: | 
 |         if (SetLengthWithPercent( | 
 |                 pComputedStyle->m_NonInheritedData.m_PaddingWidth.right, eType, | 
 |                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { | 
 |           pComputedStyle->m_NonInheritedData.m_bHasPadding = true; | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::PaddingBottom: | 
 |         if (SetLengthWithPercent( | 
 |                 pComputedStyle->m_NonInheritedData.m_PaddingWidth.bottom, eType, | 
 |                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { | 
 |           pComputedStyle->m_NonInheritedData.m_bHasPadding = true; | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::BorderLeftWidth: | 
 |         if (SetLengthWithPercent( | 
 |                 pComputedStyle->m_NonInheritedData.m_BorderWidth.left, eType, | 
 |                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { | 
 |           pComputedStyle->m_NonInheritedData.m_bHasBorder = true; | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::BorderTopWidth: | 
 |         if (SetLengthWithPercent( | 
 |                 pComputedStyle->m_NonInheritedData.m_BorderWidth.top, eType, | 
 |                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { | 
 |           pComputedStyle->m_NonInheritedData.m_bHasBorder = true; | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::BorderRightWidth: | 
 |         if (SetLengthWithPercent( | 
 |                 pComputedStyle->m_NonInheritedData.m_BorderWidth.right, eType, | 
 |                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { | 
 |           pComputedStyle->m_NonInheritedData.m_bHasBorder = true; | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::BorderBottomWidth: | 
 |         if (SetLengthWithPercent( | 
 |                 pComputedStyle->m_NonInheritedData.m_BorderWidth.bottom, eType, | 
 |                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { | 
 |           pComputedStyle->m_NonInheritedData.m_bHasBorder = true; | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::VerticalAlign: | 
 |         if (eType == FDE_CSSPrimitiveType::Enum) { | 
 |           pComputedStyle->m_NonInheritedData.m_eVerticalAlign = | 
 |               ToVerticalAlign(pValue.As<CFDE_CSSEnumValue>()->Value()); | 
 |         } else if (eType == FDE_CSSPrimitiveType::Number) { | 
 |           pComputedStyle->m_NonInheritedData.m_eVerticalAlign = | 
 |               FDE_CSSVerticalAlign::Number; | 
 |           pComputedStyle->m_NonInheritedData.m_fVerticalAlign = | 
 |               pValue.As<CFDE_CSSNumberValue>()->Apply( | 
 |                   pComputedStyle->m_InheritedData.m_fFontSize); | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::FontVariant: | 
 |         if (eType == FDE_CSSPrimitiveType::Enum) { | 
 |           pComputedStyle->m_InheritedData.m_eFontVariant = | 
 |               ToFontVariant(pValue.As<CFDE_CSSEnumValue>()->Value()); | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::LetterSpacing: | 
 |         if (eType == FDE_CSSPrimitiveType::Enum) { | 
 |           pComputedStyle->m_InheritedData.m_LetterSpacing.Set( | 
 |               FDE_CSSLengthUnit::Normal); | 
 |         } else if (eType == FDE_CSSPrimitiveType::Number) { | 
 |           if (pValue.As<CFDE_CSSNumberValue>()->Kind() == | 
 |               FDE_CSSNumberType::Percent) { | 
 |             break; | 
 |           } | 
 |  | 
 |           SetLengthWithPercent(pComputedStyle->m_InheritedData.m_LetterSpacing, | 
 |                                eType, pValue, | 
 |                                pComputedStyle->m_InheritedData.m_fFontSize); | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::WordSpacing: | 
 |         if (eType == FDE_CSSPrimitiveType::Enum) { | 
 |           pComputedStyle->m_InheritedData.m_WordSpacing.Set( | 
 |               FDE_CSSLengthUnit::Normal); | 
 |         } else if (eType == FDE_CSSPrimitiveType::Number) { | 
 |           if (pValue.As<CFDE_CSSNumberValue>()->Kind() == | 
 |               FDE_CSSNumberType::Percent) { | 
 |             break; | 
 |           } | 
 |           SetLengthWithPercent(pComputedStyle->m_InheritedData.m_WordSpacing, | 
 |                                eType, pValue, | 
 |                                pComputedStyle->m_InheritedData.m_fFontSize); | 
 |         } | 
 |         break; | 
 |       case FDE_CSSProperty::Top: | 
 |         SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Top, eType, | 
 |                              pValue, | 
 |                              pComputedStyle->m_InheritedData.m_fFontSize); | 
 |         break; | 
 |       case FDE_CSSProperty::Bottom: | 
 |         SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Bottom, eType, | 
 |                              pValue, | 
 |                              pComputedStyle->m_InheritedData.m_fFontSize); | 
 |         break; | 
 |       case FDE_CSSProperty::Left: | 
 |         SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Left, eType, | 
 |                              pValue, | 
 |                              pComputedStyle->m_InheritedData.m_fFontSize); | 
 |         break; | 
 |       case FDE_CSSProperty::Right: | 
 |         SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Right, eType, | 
 |                              pValue, | 
 |                              pComputedStyle->m_InheritedData.m_fFontSize); | 
 |         break; | 
 |       default: | 
 |         break; | 
 |     } | 
 |   } else if (pValue->GetType() == FDE_CSSPrimitiveType::List) { | 
 |     CFX_RetainPtr<CFDE_CSSValueList> pList = pValue.As<CFDE_CSSValueList>(); | 
 |     int32_t iCount = pList->CountValues(); | 
 |     if (iCount > 0) { | 
 |       switch (eProperty) { | 
 |         case FDE_CSSProperty::FontFamily: | 
 |           pComputedStyle->m_InheritedData.m_pFontFamily = pList; | 
 |           break; | 
 |         case FDE_CSSProperty::TextDecoration: | 
 |           pComputedStyle->m_NonInheritedData.m_dwTextDecoration = | 
 |               ToTextDecoration(pList); | 
 |           break; | 
 |         default: | 
 |           break; | 
 |       } | 
 |     } | 
 |   } else { | 
 |     NOTREACHED(); | 
 |   } | 
 | } | 
 |  | 
 | FDE_CSSDisplay CFDE_CSSStyleSelector::ToDisplay(FDE_CSSPropertyValue eValue) { | 
 |   switch (eValue) { | 
 |     case FDE_CSSPropertyValue::Block: | 
 |       return FDE_CSSDisplay::Block; | 
 |     case FDE_CSSPropertyValue::None: | 
 |       return FDE_CSSDisplay::None; | 
 |     case FDE_CSSPropertyValue::ListItem: | 
 |       return FDE_CSSDisplay::ListItem; | 
 |     case FDE_CSSPropertyValue::InlineTable: | 
 |       return FDE_CSSDisplay::InlineTable; | 
 |     case FDE_CSSPropertyValue::InlineBlock: | 
 |       return FDE_CSSDisplay::InlineBlock; | 
 |     case FDE_CSSPropertyValue::Inline: | 
 |     default: | 
 |       return FDE_CSSDisplay::Inline; | 
 |   } | 
 | } | 
 |  | 
 | FDE_CSSTextAlign CFDE_CSSStyleSelector::ToTextAlign( | 
 |     FDE_CSSPropertyValue eValue) { | 
 |   switch (eValue) { | 
 |     case FDE_CSSPropertyValue::Center: | 
 |       return FDE_CSSTextAlign::Center; | 
 |     case FDE_CSSPropertyValue::Right: | 
 |       return FDE_CSSTextAlign::Right; | 
 |     case FDE_CSSPropertyValue::Justify: | 
 |       return FDE_CSSTextAlign::Justify; | 
 |     case FDE_CSSPropertyValue::Left: | 
 |     default: | 
 |       return FDE_CSSTextAlign::Left; | 
 |   } | 
 | } | 
 |  | 
 | uint16_t CFDE_CSSStyleSelector::ToFontWeight(FDE_CSSPropertyValue eValue) { | 
 |   switch (eValue) { | 
 |     case FDE_CSSPropertyValue::Bold: | 
 |       return 700; | 
 |     case FDE_CSSPropertyValue::Bolder: | 
 |       return 900; | 
 |     case FDE_CSSPropertyValue::Lighter: | 
 |       return 200; | 
 |     case FDE_CSSPropertyValue::Normal: | 
 |     default: | 
 |       return 400; | 
 |   } | 
 | } | 
 |  | 
 | FDE_CSSFontStyle CFDE_CSSStyleSelector::ToFontStyle( | 
 |     FDE_CSSPropertyValue eValue) { | 
 |   switch (eValue) { | 
 |     case FDE_CSSPropertyValue::Italic: | 
 |     case FDE_CSSPropertyValue::Oblique: | 
 |       return FDE_CSSFontStyle::Italic; | 
 |     default: | 
 |       return FDE_CSSFontStyle::Normal; | 
 |   } | 
 | } | 
 |  | 
 | bool CFDE_CSSStyleSelector::SetLengthWithPercent( | 
 |     FDE_CSSLength& width, | 
 |     FDE_CSSPrimitiveType eType, | 
 |     const CFX_RetainPtr<CFDE_CSSValue>& pValue, | 
 |     float fFontSize) { | 
 |   if (eType == FDE_CSSPrimitiveType::Number) { | 
 |     CFX_RetainPtr<CFDE_CSSNumberValue> v = pValue.As<CFDE_CSSNumberValue>(); | 
 |     if (v->Kind() == FDE_CSSNumberType::Percent) { | 
 |       width.Set(FDE_CSSLengthUnit::Percent, | 
 |                 pValue.As<CFDE_CSSNumberValue>()->Value() / 100.0f); | 
 |       return width.NonZero(); | 
 |     } | 
 |  | 
 |     float fValue = v->Apply(fFontSize); | 
 |     width.Set(FDE_CSSLengthUnit::Point, fValue); | 
 |     return width.NonZero(); | 
 |   } else if (eType == FDE_CSSPrimitiveType::Enum) { | 
 |     switch (pValue.As<CFDE_CSSEnumValue>()->Value()) { | 
 |       case FDE_CSSPropertyValue::Auto: | 
 |         width.Set(FDE_CSSLengthUnit::Auto); | 
 |         return true; | 
 |       case FDE_CSSPropertyValue::None: | 
 |         width.Set(FDE_CSSLengthUnit::None); | 
 |         return true; | 
 |       case FDE_CSSPropertyValue::Thin: | 
 |         width.Set(FDE_CSSLengthUnit::Point, 2); | 
 |         return true; | 
 |       case FDE_CSSPropertyValue::Medium: | 
 |         width.Set(FDE_CSSLengthUnit::Point, 3); | 
 |         return true; | 
 |       case FDE_CSSPropertyValue::Thick: | 
 |         width.Set(FDE_CSSLengthUnit::Point, 4); | 
 |         return true; | 
 |       default: | 
 |         return false; | 
 |     } | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | float CFDE_CSSStyleSelector::ToFontSize(FDE_CSSPropertyValue eValue, | 
 |                                         float fCurFontSize) { | 
 |   switch (eValue) { | 
 |     case FDE_CSSPropertyValue::XxSmall: | 
 |       return m_fDefFontSize / 1.2f / 1.2f / 1.2f; | 
 |     case FDE_CSSPropertyValue::XSmall: | 
 |       return m_fDefFontSize / 1.2f / 1.2f; | 
 |     case FDE_CSSPropertyValue::Small: | 
 |       return m_fDefFontSize / 1.2f; | 
 |     case FDE_CSSPropertyValue::Medium: | 
 |       return m_fDefFontSize; | 
 |     case FDE_CSSPropertyValue::Large: | 
 |       return m_fDefFontSize * 1.2f; | 
 |     case FDE_CSSPropertyValue::XLarge: | 
 |       return m_fDefFontSize * 1.2f * 1.2f; | 
 |     case FDE_CSSPropertyValue::XxLarge: | 
 |       return m_fDefFontSize * 1.2f * 1.2f * 1.2f; | 
 |     case FDE_CSSPropertyValue::Larger: | 
 |       return fCurFontSize * 1.2f; | 
 |     case FDE_CSSPropertyValue::Smaller: | 
 |       return fCurFontSize / 1.2f; | 
 |     default: | 
 |       return fCurFontSize; | 
 |   } | 
 | } | 
 |  | 
 | FDE_CSSVerticalAlign CFDE_CSSStyleSelector::ToVerticalAlign( | 
 |     FDE_CSSPropertyValue eValue) { | 
 |   switch (eValue) { | 
 |     case FDE_CSSPropertyValue::Middle: | 
 |       return FDE_CSSVerticalAlign::Middle; | 
 |     case FDE_CSSPropertyValue::Bottom: | 
 |       return FDE_CSSVerticalAlign::Bottom; | 
 |     case FDE_CSSPropertyValue::Super: | 
 |       return FDE_CSSVerticalAlign::Super; | 
 |     case FDE_CSSPropertyValue::Sub: | 
 |       return FDE_CSSVerticalAlign::Sub; | 
 |     case FDE_CSSPropertyValue::Top: | 
 |       return FDE_CSSVerticalAlign::Top; | 
 |     case FDE_CSSPropertyValue::TextTop: | 
 |       return FDE_CSSVerticalAlign::TextTop; | 
 |     case FDE_CSSPropertyValue::TextBottom: | 
 |       return FDE_CSSVerticalAlign::TextBottom; | 
 |     case FDE_CSSPropertyValue::Baseline: | 
 |     default: | 
 |       return FDE_CSSVerticalAlign::Baseline; | 
 |   } | 
 | } | 
 |  | 
 | uint32_t CFDE_CSSStyleSelector::ToTextDecoration( | 
 |     const CFX_RetainPtr<CFDE_CSSValueList>& pValue) { | 
 |   uint32_t dwDecoration = 0; | 
 |   for (int32_t i = pValue->CountValues() - 1; i >= 0; --i) { | 
 |     const CFX_RetainPtr<CFDE_CSSValue> pVal = pValue->GetValue(i); | 
 |     if (pVal->GetType() != FDE_CSSPrimitiveType::Enum) | 
 |       continue; | 
 |  | 
 |     switch (pVal.As<CFDE_CSSEnumValue>()->Value()) { | 
 |       case FDE_CSSPropertyValue::Underline: | 
 |         dwDecoration |= FDE_CSSTEXTDECORATION_Underline; | 
 |         break; | 
 |       case FDE_CSSPropertyValue::LineThrough: | 
 |         dwDecoration |= FDE_CSSTEXTDECORATION_LineThrough; | 
 |         break; | 
 |       case FDE_CSSPropertyValue::Overline: | 
 |         dwDecoration |= FDE_CSSTEXTDECORATION_Overline; | 
 |         break; | 
 |       case FDE_CSSPropertyValue::Blink: | 
 |         dwDecoration |= FDE_CSSTEXTDECORATION_Blink; | 
 |         break; | 
 |       case FDE_CSSPropertyValue::Double: | 
 |         dwDecoration |= FDE_CSSTEXTDECORATION_Double; | 
 |         break; | 
 |       default: | 
 |         break; | 
 |     } | 
 |   } | 
 |   return dwDecoration; | 
 | } | 
 |  | 
 | FDE_CSSFontVariant CFDE_CSSStyleSelector::ToFontVariant( | 
 |     FDE_CSSPropertyValue eValue) { | 
 |   return eValue == FDE_CSSPropertyValue::SmallCaps | 
 |              ? FDE_CSSFontVariant::SmallCaps | 
 |              : FDE_CSSFontVariant::Normal; | 
 | } |