summaryrefslogtreecommitdiff
path: root/xfa/fde/css/cfde_cssstyleselector.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xfa/fde/css/cfde_cssstyleselector.cpp')
-rw-r--r--xfa/fde/css/cfde_cssstyleselector.cpp808
1 files changed, 808 insertions, 0 deletions
diff --git a/xfa/fde/css/cfde_cssstyleselector.cpp b/xfa/fde/css/cfde_cssstyleselector.cpp
new file mode 100644
index 0000000000..1539894017
--- /dev/null
+++ b/xfa/fde/css/cfde_cssstyleselector.cpp
@@ -0,0 +1,808 @@
+// 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 "third_party/base/ptr_util.h"
+#include "xfa/fde/css/cfde_cssaccelerator.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_csssyntaxparser.h"
+#include "xfa/fde/css/cfde_csstagcache.h"
+#include "xfa/fde/css/cfde_cssvaluelist.h"
+#include "xfa/fxfa/app/cxfa_csstagprovider.h"
+
+namespace {
+
+template <class T>
+T* ToValue(CFDE_CSSValue* val) {
+ return static_cast<T*>(val);
+}
+
+template <class T>
+const T* ToValue(const CFDE_CSSValue* val) {
+ return static_cast<T*>(val);
+}
+
+} // namespace
+
+#define FDE_CSSUNIVERSALHASH ('*')
+
+CFDE_CSSStyleSelector::CFDE_CSSStyleSelector(CFGAS_FontMgr* pFontMgr)
+ : m_pFontMgr(pFontMgr), m_fDefFontSize(12.0f) {
+ m_ePriorities[static_cast<int32_t>(FDE_CSSStyleSheetPriority::High)] =
+ FDE_CSSStyleSheetGroup::Author;
+ m_ePriorities[static_cast<int32_t>(FDE_CSSStyleSheetPriority::Mid)] =
+ FDE_CSSStyleSheetGroup::User;
+ m_ePriorities[static_cast<int32_t>(FDE_CSSStyleSheetPriority::Low)] =
+ FDE_CSSStyleSheetGroup::UserAgent;
+}
+
+CFDE_CSSStyleSelector::~CFDE_CSSStyleSelector() {
+ Reset();
+}
+
+void CFDE_CSSStyleSelector::SetDefFontSize(FX_FLOAT fFontSize) {
+ ASSERT(fFontSize > 0);
+ m_fDefFontSize = fFontSize;
+}
+
+CFDE_CSSAccelerator* CFDE_CSSStyleSelector::InitAccelerator() {
+ if (!m_pAccelerator)
+ m_pAccelerator = pdfium::MakeUnique<CFDE_CSSAccelerator>();
+ m_pAccelerator->Clear();
+ return m_pAccelerator.get();
+}
+
+CFDE_CSSComputedStyle* CFDE_CSSStyleSelector::CreateComputedStyle(
+ CFDE_CSSComputedStyle* pParentStyle) {
+ CFDE_CSSComputedStyle* pStyle = new CFDE_CSSComputedStyle();
+ if (pParentStyle)
+ pStyle->m_InheritedData = pParentStyle->m_InheritedData;
+ return pStyle;
+}
+
+bool CFDE_CSSStyleSelector::SetStyleSheet(FDE_CSSStyleSheetGroup eType,
+ CFDE_CSSStyleSheet* pSheet) {
+ CFX_ArrayTemplate<CFDE_CSSStyleSheet*>& dest =
+ m_SheetGroups[static_cast<int32_t>(eType)];
+ dest.RemoveAt(0, dest.GetSize());
+ if (pSheet)
+ dest.Add(pSheet);
+ return true;
+}
+
+bool CFDE_CSSStyleSelector::SetStyleSheets(
+ FDE_CSSStyleSheetGroup eType,
+ const CFX_ArrayTemplate<CFDE_CSSStyleSheet*>* pArray) {
+ CFX_ArrayTemplate<CFDE_CSSStyleSheet*>& dest =
+ m_SheetGroups[static_cast<int32_t>(eType)];
+ if (pArray)
+ dest.Copy(*pArray);
+ else
+ dest.RemoveAt(0, dest.GetSize());
+ return true;
+}
+
+void CFDE_CSSStyleSelector::SetStylePriority(
+ FDE_CSSStyleSheetGroup eType,
+ FDE_CSSStyleSheetPriority ePriority) {
+ m_ePriorities[static_cast<int32_t>(ePriority)] = eType;
+}
+
+void CFDE_CSSStyleSelector::UpdateStyleIndex(uint32_t dwMediaList) {
+ Reset();
+
+ // TODO(dsinclair): Hard coded size bad. This should probably just be a map.
+ for (int32_t iGroup = 0; iGroup < 3; ++iGroup) {
+ CFDE_CSSRuleCollection& rules = m_RuleCollection[iGroup];
+ rules.AddRulesFrom(m_SheetGroups[iGroup], dwMediaList, m_pFontMgr);
+ }
+}
+
+void CFDE_CSSStyleSelector::Reset() {
+ // TODO(dsinclair): Hard coded size bad. This should probably just be a map.
+ for (int32_t iGroup = 0; iGroup < 3; ++iGroup) {
+ m_RuleCollection[iGroup].Clear();
+ }
+}
+
+int32_t CFDE_CSSStyleSelector::MatchDeclarations(
+ CXFA_CSSTagProvider* pTag,
+ CFX_ArrayTemplate<CFDE_CSSDeclaration*>& matchedDecls,
+ FDE_CSSPseudo ePseudoType) {
+ ASSERT(pTag);
+ CFDE_CSSTagCache* pCache = m_pAccelerator->top();
+ ASSERT(pCache && pCache->GetTag() == pTag);
+
+ matchedDecls.RemoveAt(0, matchedDecls.GetSize());
+ // TODO(dsinclair): Hard coded size bad ...
+ for (int32_t ePriority = 2; ePriority >= 0; --ePriority) {
+ FDE_CSSStyleSheetGroup eGroup = m_ePriorities[ePriority];
+ CFDE_CSSRuleCollection& rules =
+ m_RuleCollection[static_cast<int32_t>(eGroup)];
+ if (rules.CountSelectors() == 0)
+ continue;
+
+ if (ePseudoType == FDE_CSSPseudo::NONE) {
+ MatchRules(pCache, rules.GetUniversalRuleData(), ePseudoType);
+ if (pCache->HashTag()) {
+ MatchRules(pCache, rules.GetTagRuleData(pCache->HashTag()),
+ ePseudoType);
+ }
+ int32_t iCount = pCache->CountHashClass();
+ for (int32_t i = 0; i < iCount; i++) {
+ pCache->SetClassIndex(i);
+ MatchRules(pCache, rules.GetClassRuleData(pCache->HashClass()),
+ ePseudoType);
+ }
+ } else {
+ MatchRules(pCache, rules.GetPseudoRuleData(), ePseudoType);
+ }
+
+ std::sort(m_MatchedRules.begin(), m_MatchedRules.end(),
+ [](const CFDE_CSSRuleCollection::Data* p1,
+ const CFDE_CSSRuleCollection::Data* p2) {
+ return p1->dwPriority < p2->dwPriority;
+ });
+ for (const auto& rule : m_MatchedRules)
+ matchedDecls.Add(rule->pDeclaration);
+ m_MatchedRules.clear();
+ }
+ return matchedDecls.GetSize();
+}
+
+void CFDE_CSSStyleSelector::MatchRules(CFDE_CSSTagCache* pCache,
+ CFDE_CSSRuleCollection::Data* pList,
+ FDE_CSSPseudo ePseudoType) {
+ while (pList) {
+ if (MatchSelector(pCache, pList->pSelector, ePseudoType))
+ m_MatchedRules.push_back(pList);
+ pList = pList->pNext;
+ }
+}
+
+bool CFDE_CSSStyleSelector::MatchSelector(CFDE_CSSTagCache* pCache,
+ CFDE_CSSSelector* pSel,
+ FDE_CSSPseudo ePseudoType) {
+ uint32_t dwHash;
+ while (pSel && pCache) {
+ switch (pSel->GetType()) {
+ case FDE_CSSSelectorType::Descendant:
+ dwHash = pSel->GetNameHash();
+ while ((pCache = pCache->GetParent()) != nullptr) {
+ if (dwHash != FDE_CSSUNIVERSALHASH && dwHash != pCache->HashTag()) {
+ continue;
+ }
+ if (MatchSelector(pCache, pSel->GetNextSelector(), ePseudoType)) {
+ return true;
+ }
+ }
+ return false;
+ case FDE_CSSSelectorType::ID:
+ dwHash = pCache->HashID();
+ if (dwHash != pSel->GetNameHash()) {
+ return false;
+ }
+ break;
+ case FDE_CSSSelectorType::Class:
+ dwHash = pCache->HashClass();
+ if (dwHash != pSel->GetNameHash()) {
+ return false;
+ }
+ break;
+ case FDE_CSSSelectorType::Element:
+ dwHash = pSel->GetNameHash();
+ if (dwHash != FDE_CSSUNIVERSALHASH && dwHash != pCache->HashTag()) {
+ return false;
+ }
+ break;
+ case FDE_CSSSelectorType::Pseudo:
+ dwHash = FDE_GetCSSPseudoByEnum(ePseudoType)->dwHash;
+ if (dwHash != pSel->GetNameHash()) {
+ return false;
+ }
+ break;
+ default:
+ ASSERT(false);
+ break;
+ }
+ pSel = pSel->GetNextSelector();
+ }
+ return !pSel && pCache;
+}
+
+void CFDE_CSSStyleSelector::ComputeStyle(
+ CXFA_CSSTagProvider* pTag,
+ const CFDE_CSSDeclaration** ppDeclArray,
+ int32_t iDeclCount,
+ CFDE_CSSComputedStyle* pDestStyle) {
+ ASSERT(iDeclCount >= 0);
+ ASSERT(pDestStyle);
+
+ static const uint32_t s_dwStyleHash = FX_HashCode_GetW(L"style", true);
+ static const uint32_t s_dwAlignHash = FX_HashCode_GetW(L"align", true);
+
+ if (!pTag->empty()) {
+ CFDE_CSSDeclaration* pDecl = nullptr;
+ for (auto it : *pTag) {
+ CFX_WideString wsAttri = it.first;
+ CFX_WideString wsValue = it.second;
+ uint32_t dwAttriHash = FX_HashCode_GetW(wsAttri.AsStringC(), true);
+ if (dwAttriHash == s_dwStyleHash) {
+ if (!pDecl)
+ pDecl = new CFDE_CSSDeclaration;
+
+ AppendInlineStyle(pDecl, wsValue.c_str(), wsValue.GetLength());
+ } else if (dwAttriHash == s_dwAlignHash) {
+ if (!pDecl)
+ pDecl = new CFDE_CSSDeclaration;
+
+ FDE_CSSPropertyArgs args;
+ args.pStringCache = nullptr;
+ args.pProperty = FDE_GetCSSPropertyByEnum(FDE_CSSProperty::TextAlign);
+ pDecl->AddProperty(&args, wsValue.c_str(), wsValue.GetLength());
+ }
+ }
+
+ if (pDecl) {
+ CFX_ArrayTemplate<CFDE_CSSDeclaration*> decls;
+ decls.SetSize(iDeclCount + 1);
+ CFDE_CSSDeclaration** ppInline = decls.GetData();
+ FXSYS_memcpy(ppInline, ppDeclArray,
+ iDeclCount * sizeof(CFDE_CSSDeclaration*));
+ ppInline[iDeclCount++] = pDecl;
+ ApplyDeclarations(true, const_cast<const CFDE_CSSDeclaration**>(ppInline),
+ iDeclCount, pDestStyle);
+ ApplyDeclarations(false,
+ const_cast<const CFDE_CSSDeclaration**>(ppInline),
+ iDeclCount, pDestStyle);
+ return;
+ }
+ }
+
+ if (iDeclCount > 0) {
+ ASSERT(ppDeclArray);
+
+ ApplyDeclarations(true, ppDeclArray, iDeclCount, pDestStyle);
+ ApplyDeclarations(false, ppDeclArray, iDeclCount, pDestStyle);
+ }
+}
+
+void CFDE_CSSStyleSelector::ApplyDeclarations(
+ bool bPriority,
+ const CFDE_CSSDeclaration** ppDeclArray,
+ int32_t iDeclCount,
+ CFDE_CSSComputedStyle* pDestStyle) {
+ CFDE_CSSComputedStyle* pComputedStyle = pDestStyle;
+
+ int32_t i;
+ if (bPriority) {
+ CFDE_CSSValue* pLastest = nullptr;
+ CFDE_CSSValue* pImportant = nullptr;
+ for (i = 0; i < iDeclCount; ++i) {
+ bool bImportant;
+ CFDE_CSSValue* pVal =
+ ppDeclArray[i]->GetProperty(FDE_CSSProperty::FontSize, bImportant);
+ if (!pVal)
+ continue;
+
+ if (bImportant)
+ pImportant = pVal;
+ else
+ pLastest = pVal;
+ }
+ if (pImportant) {
+ ApplyProperty(FDE_CSSProperty::FontSize, pImportant, pComputedStyle);
+ } else if (pLastest) {
+ ApplyProperty(FDE_CSSProperty::FontSize, pLastest, pComputedStyle);
+ }
+ } else {
+ CFX_ArrayTemplate<CFDE_CSSDeclaration*> importants;
+ const CFDE_CSSDeclaration* pDecl = nullptr;
+
+ for (i = 0; i < iDeclCount; ++i) {
+ pDecl = ppDeclArray[i];
+ for (auto it = pDecl->begin(); it != pDecl->end(); it++) {
+ if ((*it)->eProperty == FDE_CSSProperty::FontSize)
+ continue;
+ if (!(*it)->bImportant) {
+ ApplyProperty((*it)->eProperty, (*it)->pValue.Get(), pComputedStyle);
+ } else if (importants.GetSize() == 0 ||
+ importants[importants.GetUpperBound()] != pDecl) {
+ importants.Add(const_cast<CFDE_CSSDeclaration*>(pDecl));
+ }
+ }
+ }
+
+ iDeclCount = importants.GetSize();
+ for (i = 0; i < iDeclCount; ++i) {
+ pDecl = importants[i];
+
+ for (auto it = pDecl->begin(); it != pDecl->end(); it++) {
+ if ((*it)->bImportant && (*it)->eProperty != FDE_CSSProperty::FontSize)
+ ApplyProperty((*it)->eProperty, (*it)->pValue.Get(), pComputedStyle);
+ }
+ }
+
+ for (auto it = pDecl->custom_begin(); it != pDecl->custom_end(); it++) {
+ pComputedStyle->AddCustomStyle((*it)->pwsName, (*it)->pwsValue);
+ }
+ }
+}
+
+void CFDE_CSSStyleSelector::AppendInlineStyle(CFDE_CSSDeclaration* pDecl,
+ const FX_WCHAR* psz,
+ int32_t iLen) {
+ ASSERT(pDecl && psz && iLen > 0);
+ auto pSyntax = pdfium::MakeUnique<CFDE_CSSSyntaxParser>();
+ if (!pSyntax->Init(psz, iLen, 32, true))
+ return;
+
+ int32_t iLen2 = 0;
+ const FX_WCHAR* psz2;
+ FDE_CSSPropertyArgs args;
+ args.pStringCache = nullptr;
+ args.pProperty = nullptr;
+ CFX_WideString wsName;
+ while (1) {
+ FDE_CSSSyntaxStatus eStatus = pSyntax->DoSyntaxParse();
+ if (eStatus == FDE_CSSSyntaxStatus::PropertyName) {
+ psz2 = pSyntax->GetCurrentString(iLen2);
+ args.pProperty = FDE_GetCSSPropertyByName(CFX_WideStringC(psz2, iLen2));
+ if (!args.pProperty)
+ wsName = CFX_WideStringC(psz2, iLen2);
+ } else if (eStatus == FDE_CSSSyntaxStatus::PropertyValue) {
+ if (args.pProperty) {
+ psz2 = pSyntax->GetCurrentString(iLen2);
+ if (iLen2 > 0)
+ pDecl->AddProperty(&args, psz2, iLen2);
+ } else if (iLen2 > 0) {
+ psz2 = pSyntax->GetCurrentString(iLen2);
+ if (iLen2 > 0) {
+ pDecl->AddProperty(&args, wsName.c_str(), wsName.GetLength(), psz2,
+ iLen2);
+ }
+ }
+ } else {
+ break;
+ }
+ }
+}
+
+void CFDE_CSSStyleSelector::ApplyProperty(
+ FDE_CSSProperty eProperty,
+ 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(ToValue<CFDE_CSSEnumValue>(pValue)->Value());
+ }
+ break;
+ case FDE_CSSProperty::FontSize: {
+ FX_FLOAT& fFontSize = pComputedStyle->m_InheritedData.m_fFontSize;
+ if (eType == FDE_CSSPrimitiveType::Number) {
+ fFontSize = ToValue<CFDE_CSSNumberValue>(pValue)->Apply(fFontSize);
+ } else if (eType == FDE_CSSPrimitiveType::Enum) {
+ fFontSize = ToFontSize(ToValue<CFDE_CSSEnumValue>(pValue)->Value(),
+ fFontSize);
+ }
+ } break;
+ case FDE_CSSProperty::LineHeight:
+ if (eType == FDE_CSSPrimitiveType::Number) {
+ const CFDE_CSSNumberValue* v = ToValue<CFDE_CSSNumberValue>(pValue);
+ 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(ToValue<CFDE_CSSEnumValue>(pValue)->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(ToValue<CFDE_CSSEnumValue>(pValue)->Value());
+ } else if (eType == FDE_CSSPrimitiveType::Number) {
+ int32_t iValue =
+ (int32_t)ToValue<CFDE_CSSNumberValue>(pValue)->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(ToValue<CFDE_CSSEnumValue>(pValue)->Value());
+ }
+ break;
+ case FDE_CSSProperty::Color:
+ if (eType == FDE_CSSPrimitiveType::RGB) {
+ pComputedStyle->m_InheritedData.m_dwFontColor =
+ ToValue<CFDE_CSSColorValue>(pValue)->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(ToValue<CFDE_CSSEnumValue>(pValue)->Value());
+ } else if (eType == FDE_CSSPrimitiveType::Number) {
+ pComputedStyle->m_NonInheritedData.m_eVerticalAlign =
+ FDE_CSSVerticalAlign::Number;
+ pComputedStyle->m_NonInheritedData.m_fVerticalAlign =
+ ToValue<CFDE_CSSNumberValue>(pValue)->Apply(
+ pComputedStyle->m_InheritedData.m_fFontSize);
+ }
+ break;
+ case FDE_CSSProperty::FontVariant:
+ if (eType == FDE_CSSPrimitiveType::Enum) {
+ pComputedStyle->m_InheritedData.m_eFontVariant =
+ ToFontVariant(ToValue<CFDE_CSSEnumValue>(pValue)->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 (ToValue<CFDE_CSSNumberValue>(pValue)->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 (ToValue<CFDE_CSSNumberValue>(pValue)->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) {
+ CFDE_CSSValueList* pList = ToValue<CFDE_CSSValueList>(pValue);
+ 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 {
+ ASSERT(false);
+ }
+}
+
+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,
+ CFDE_CSSValue* pValue,
+ FX_FLOAT fFontSize) {
+ if (eType == FDE_CSSPrimitiveType::Number) {
+ const CFDE_CSSNumberValue* v = ToValue<CFDE_CSSNumberValue>(pValue);
+ if (v->Kind() == FDE_CSSNumberType::Percent) {
+ width.Set(FDE_CSSLengthUnit::Percent,
+ ToValue<CFDE_CSSNumberValue>(pValue)->Value() / 100.0f);
+ return width.NonZero();
+ }
+
+ FX_FLOAT fValue = v->Apply(fFontSize);
+ width.Set(FDE_CSSLengthUnit::Point, fValue);
+ return width.NonZero();
+ } else if (eType == FDE_CSSPrimitiveType::Enum) {
+ switch (ToValue<CFDE_CSSEnumValue>(pValue)->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;
+}
+
+FX_FLOAT CFDE_CSSStyleSelector::ToFontSize(FDE_CSSPropertyValue eValue,
+ FX_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(CFDE_CSSValueList* pValue) {
+ uint32_t dwDecoration = 0;
+ for (int32_t i = pValue->CountValues() - 1; i >= 0; --i) {
+ CFDE_CSSValue* pVal = pValue->GetValue(i);
+ if (pVal->GetType() != FDE_CSSPrimitiveType::Enum)
+ continue;
+
+ switch (ToValue<CFDE_CSSEnumValue>(pVal)->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;
+}