// 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/fde_cssstyleselector.h" #include #include #include "third_party/base/ptr_util.h" #include "third_party/base/stl_util.h" #include "xfa/fde/css/fde_csscache.h" #include "xfa/fde/css/fde_cssdeclaration.h" #include "xfa/fde/css/fde_cssstylesheet.h" #include "xfa/fde/css/fde_csssyntax.h" #include "xfa/fxfa/app/cxfa_csstagprovider.h" #define FDE_CSSUNIVERSALHASH ('*') FDE_CSSRuleData::FDE_CSSRuleData(CFDE_CSSSelector* pSel, CFDE_CSSDeclaration* pDecl, uint32_t dwPos) : pSelector(pSel), pDeclaration(pDecl), dwPriority(dwPos), pNext(nullptr) { static const uint32_t s_Specific[5] = {0x00010000, 0x00010000, 0x00100000, 0x00100000, 0x01000000}; for (; pSel; pSel = pSel->GetNextSelector()) { FDE_CSSSelectorType eType = pSel->GetType(); if (eType > FDE_CSSSelectorType::Descendant || pSel->GetNameHash() != FDE_CSSUNIVERSALHASH) { dwPriority += s_Specific[static_cast(eType)]; } } } CFDE_CSSStyleSelector::CFDE_CSSStyleSelector(CFGAS_FontMgr* pFontMgr) : m_pFontMgr(pFontMgr), m_fDefFontSize(12.0f) { m_ePriorities[static_cast(FDE_CSSStyleSheetPriority::High)] = FDE_CSSStyleSheetGroup::Author; m_ePriorities[static_cast(FDE_CSSStyleSheetPriority::Mid)] = FDE_CSSStyleSheetGroup::User; m_ePriorities[static_cast(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(); m_pAccelerator->Clear(); return m_pAccelerator.get(); } IFDE_CSSComputedStyle* CFDE_CSSStyleSelector::CreateComputedStyle( IFDE_CSSComputedStyle* pParentStyle) { CFDE_CSSComputedStyle* pStyle = new CFDE_CSSComputedStyle(); if (pParentStyle) { pStyle->m_InheritedData = static_cast(pParentStyle)->m_InheritedData; } return pStyle; } bool CFDE_CSSStyleSelector::SetStyleSheet(FDE_CSSStyleSheetGroup eType, IFDE_CSSStyleSheet* pSheet) { CFX_ArrayTemplate& dest = m_SheetGroups[static_cast(eType)]; dest.RemoveAt(0, dest.GetSize()); if (pSheet) dest.Add(pSheet); return true; } bool CFDE_CSSStyleSelector::SetStyleSheets( FDE_CSSStyleSheetGroup eType, const CFX_ArrayTemplate* pArray) { CFX_ArrayTemplate& dest = m_SheetGroups[static_cast(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(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, CFDE_CSSDeclarationArray& matchedDecls, FDE_CSSPseudo ePseudoType) { ASSERT(pTag); FDE_CSSTagCache* pCache = m_pAccelerator->GetTopElement(); 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(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 FDE_CSSRuleData* p1, const FDE_CSSRuleData* 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(FDE_CSSTagCache* pCache, FDE_CSSRuleData* pList, FDE_CSSPseudo ePseudoType) { while (pList) { if (MatchSelector(pCache, pList->pSelector, ePseudoType)) m_MatchedRules.push_back(pList); pList = pList->pNext; } } bool CFDE_CSSStyleSelector::MatchSelector(FDE_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, IFDE_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) { CFDE_CSSDeclarationArray 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(ppInline), iDeclCount, pDestStyle); ApplyDeclarations(false, const_cast(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, IFDE_CSSComputedStyle* pDestStyle) { CFDE_CSSComputedStyle* pComputedStyle = static_cast(pDestStyle); IFDE_CSSValue* pVal; bool bImportant; int32_t i; if (bPriority) { IFDE_CSSValue* pLastest = nullptr; IFDE_CSSValue* pImportant = nullptr; for (i = 0; i < iDeclCount; ++i) { 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 { CFDE_CSSDeclarationArray importants; const CFDE_CSSDeclaration* pDecl = nullptr; FDE_CSSProperty eProp; FX_POSITION pos; for (i = 0; i < iDeclCount; ++i) { pDecl = ppDeclArray[i]; pos = pDecl->GetStartPosition(); while (pos) { pDecl->GetNextProperty(pos, eProp, pVal, bImportant); if (eProp == FDE_CSSProperty::FontSize) { continue; } else if (!bImportant) { ApplyProperty(eProp, pVal, pComputedStyle); } else if (importants.GetSize() == 0 || importants[importants.GetUpperBound()] != pDecl) { importants.Add(const_cast(pDecl)); } } } iDeclCount = importants.GetSize(); for (i = 0; i < iDeclCount; ++i) { pDecl = importants[i]; pos = pDecl->GetStartPosition(); while (pos) { pDecl->GetNextProperty(pos, eProp, pVal, bImportant); if (bImportant && eProp != FDE_CSSProperty::FontSize) { ApplyProperty(eProp, pVal, pComputedStyle); } } } CFX_WideString wsName, wsValue; pos = pDecl->GetStartCustom(); while (pos) { pDecl->GetNextCustom(pos, wsName, wsValue); pComputedStyle->AddCustomStyle(wsName, wsValue); } } } void CFDE_CSSStyleSelector::AppendInlineStyle(CFDE_CSSDeclaration* pDecl, const FX_WCHAR* psz, int32_t iLen) { ASSERT(pDecl && psz && iLen > 0); auto pSyntax = pdfium::MakeUnique(); 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, IFDE_CSSValue* pValue, CFDE_CSSComputedStyle* pComputedStyle) { if (pValue->GetType() == FDE_CSSVALUETYPE_Primitive) { IFDE_CSSPrimitiveValue* pPrimitive = static_cast(pValue); FDE_CSSPrimitiveType eType = pPrimitive->GetPrimitiveType(); switch (eProperty) { case FDE_CSSProperty::Display: if (eType == FDE_CSSPrimitiveType::Enum) { pComputedStyle->m_NonInheritedData.m_eDisplay = ToDisplay(pPrimitive->GetEnum()); } break; case FDE_CSSProperty::FontSize: { FX_FLOAT& fFontSize = pComputedStyle->m_InheritedData.m_fFontSize; if (eType >= FDE_CSSPrimitiveType::Number && eType <= FDE_CSSPrimitiveType::Picas) { fFontSize = ApplyNumber(eType, pPrimitive->GetFloat(), fFontSize); } else if (eType == FDE_CSSPrimitiveType::Enum) { fFontSize = ToFontSize(pPrimitive->GetEnum(), fFontSize); } } break; case FDE_CSSProperty::LineHeight: if (eType == FDE_CSSPrimitiveType::Number) { pComputedStyle->m_InheritedData.m_fLineHeight = pPrimitive->GetFloat() * pComputedStyle->m_InheritedData.m_fFontSize; } else if (eType > FDE_CSSPrimitiveType::Number && eType <= FDE_CSSPrimitiveType::Picas) { pComputedStyle->m_InheritedData.m_fLineHeight = ApplyNumber(eType, pPrimitive->GetFloat(), pComputedStyle->m_InheritedData.m_fFontSize); } break; case FDE_CSSProperty::TextAlign: if (eType == FDE_CSSPrimitiveType::Enum) { pComputedStyle->m_InheritedData.m_eTextAlign = ToTextAlign(pPrimitive->GetEnum()); } break; case FDE_CSSProperty::TextIndent: SetLengthWithPercent(pComputedStyle->m_InheritedData.m_TextIndent, eType, pPrimitive, pComputedStyle->m_InheritedData.m_fFontSize); break; case FDE_CSSProperty::FontWeight: if (eType == FDE_CSSPrimitiveType::Enum) { pComputedStyle->m_InheritedData.m_wFontWeight = ToFontWeight(pPrimitive->GetEnum()); } else if (eType == FDE_CSSPrimitiveType::Number) { int32_t iValue = (int32_t)pPrimitive->GetFloat() / 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(pPrimitive->GetEnum()); } break; case FDE_CSSProperty::Color: if (eType == FDE_CSSPrimitiveType::RGB) { pComputedStyle->m_InheritedData.m_dwFontColor = pPrimitive->GetRGBColor(); } break; case FDE_CSSProperty::MarginLeft: if (SetLengthWithPercent( pComputedStyle->m_NonInheritedData.m_MarginWidth.left, eType, pPrimitive, 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, pPrimitive, 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, pPrimitive, 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, pPrimitive, 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, pPrimitive, 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, pPrimitive, 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, pPrimitive, 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, pPrimitive, 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, pPrimitive, 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, pPrimitive, 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, pPrimitive, 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, pPrimitive, 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(pPrimitive->GetEnum()); } else if (eType >= FDE_CSSPrimitiveType::Number && eType <= FDE_CSSPrimitiveType::Picas) { pComputedStyle->m_NonInheritedData.m_eVerticalAlign = FDE_CSSVerticalAlign::Number; pComputedStyle->m_NonInheritedData.m_fVerticalAlign = ApplyNumber(eType, pPrimitive->GetFloat(), pComputedStyle->m_InheritedData.m_fFontSize); } break; case FDE_CSSProperty::FontVariant: if (eType == FDE_CSSPrimitiveType::Enum) { pComputedStyle->m_InheritedData.m_eFontVariant = ToFontVariant(pPrimitive->GetEnum()); } break; case FDE_CSSProperty::LetterSpacing: if (eType == FDE_CSSPrimitiveType::Percent) { break; } else if (eType == FDE_CSSPrimitiveType::Enum) { pComputedStyle->m_InheritedData.m_LetterSpacing.Set( FDE_CSSLengthUnit::Normal); } else if (eType >= FDE_CSSPrimitiveType::Number && eType <= FDE_CSSPrimitiveType::Picas) { SetLengthWithPercent(pComputedStyle->m_InheritedData.m_LetterSpacing, eType, pPrimitive, pComputedStyle->m_InheritedData.m_fFontSize); } break; case FDE_CSSProperty::WordSpacing: if (eType == FDE_CSSPrimitiveType::Percent) { break; } else if (eType == FDE_CSSPrimitiveType::Enum) { pComputedStyle->m_InheritedData.m_WordSpacing.Set( FDE_CSSLengthUnit::Normal); } else if (eType >= FDE_CSSPrimitiveType::Number && eType <= FDE_CSSPrimitiveType::Picas) { SetLengthWithPercent(pComputedStyle->m_InheritedData.m_WordSpacing, eType, pPrimitive, pComputedStyle->m_InheritedData.m_fFontSize); } break; case FDE_CSSProperty::Top: SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Top, eType, pPrimitive, pComputedStyle->m_InheritedData.m_fFontSize); break; case FDE_CSSProperty::Bottom: SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Bottom, eType, pPrimitive, pComputedStyle->m_InheritedData.m_fFontSize); break; case FDE_CSSProperty::Left: SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Left, eType, pPrimitive, pComputedStyle->m_InheritedData.m_fFontSize); break; case FDE_CSSProperty::Right: SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Right, eType, pPrimitive, pComputedStyle->m_InheritedData.m_fFontSize); break; case FDE_CSSProperty::BorderLeftStyle: case FDE_CSSProperty::BorderTopStyle: case FDE_CSSProperty::BorderRightStyle: case FDE_CSSProperty::BorderBottomStyle: case FDE_CSSProperty::BorderLeftColor: case FDE_CSSProperty::BorderTopColor: case FDE_CSSProperty::BorderRightColor: case FDE_CSSProperty::BorderBottomColor: case FDE_CSSProperty::ListStyleType: case FDE_CSSProperty::ListStylePosition: case FDE_CSSProperty::BackgroundColor: case FDE_CSSProperty::Visibility: case FDE_CSSProperty::Width: case FDE_CSSProperty::Height: case FDE_CSSProperty::MinWidth: case FDE_CSSProperty::MinHeight: case FDE_CSSProperty::MaxWidth: case FDE_CSSProperty::MaxHeight: case FDE_CSSProperty::WhiteSpace: case FDE_CSSProperty::TextTransform: case FDE_CSSProperty::Float: case FDE_CSSProperty::Clear: case FDE_CSSProperty::WritingMode: case FDE_CSSProperty::WordBreak: case FDE_CSSProperty::Widows: case FDE_CSSProperty::Orphans: case FDE_CSSProperty::TextEmphasisColor: case FDE_CSSProperty::PageBreakBefore: case FDE_CSSProperty::PageBreakAfter: case FDE_CSSProperty::PageBreakInside: case FDE_CSSProperty::OverflowX: case FDE_CSSProperty::OverflowY: case FDE_CSSProperty::LineBreak: case FDE_CSSProperty::ColumnCount: case FDE_CSSProperty::ColumnGap: case FDE_CSSProperty::ColumnRuleColor: case FDE_CSSProperty::ColumnRuleStyle: case FDE_CSSProperty::ColumnRuleWidth: case FDE_CSSProperty::ColumnWidth: case FDE_CSSProperty::BackgroundImage: case FDE_CSSProperty::Position: case FDE_CSSProperty::ListStyleImage: case FDE_CSSProperty::CaptionSide: case FDE_CSSProperty::BackgroundRepeat: case FDE_CSSProperty::BackgroundAttachment: case FDE_CSSProperty::RubyAlign: case FDE_CSSProperty::RubyOverhang: case FDE_CSSProperty::RubyPosition: case FDE_CSSProperty::RubySpan: default: break; } } else if (pValue->GetType() == FDE_CSSVALUETYPE_List) { IFDE_CSSValueList* pList = static_cast(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; case FDE_CSSProperty::CounterIncrement: case FDE_CSSProperty::CounterReset: case FDE_CSSProperty::Content: case FDE_CSSProperty::Quotes: case FDE_CSSProperty::TextCombine: case FDE_CSSProperty::TextEmphasisStyle: default: break; } } } else { ASSERT(false); } } FX_FLOAT CFDE_CSSStyleSelector::ApplyNumber(FDE_CSSPrimitiveType eUnit, FX_FLOAT fValue, FX_FLOAT fPercentBase) { switch (eUnit) { case FDE_CSSPrimitiveType::Pixels: case FDE_CSSPrimitiveType::Number: return fValue * 72 / 96; case FDE_CSSPrimitiveType::EMS: case FDE_CSSPrimitiveType::EXS: return fValue * fPercentBase; case FDE_CSSPrimitiveType::Percent: return fValue * fPercentBase / 100.0f; case FDE_CSSPrimitiveType::CentiMeters: return fValue * 28.3464f; case FDE_CSSPrimitiveType::MilliMeters: return fValue * 2.8346f; case FDE_CSSPrimitiveType::Inches: return fValue * 72.0f; case FDE_CSSPrimitiveType::Picas: return fValue / 12.0f; case FDE_CSSPrimitiveType::Points: default: return fValue; } } 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, IFDE_CSSPrimitiveValue* pPrimitive, FX_FLOAT fFontSize) { if (eType == FDE_CSSPrimitiveType::Percent) { width.Set(FDE_CSSLengthUnit::Percent, pPrimitive->GetFloat() / 100.0f); return width.NonZero(); } else if (eType >= FDE_CSSPrimitiveType::Number && eType <= FDE_CSSPrimitiveType::Picas) { FX_FLOAT fValue = ApplyNumber(eType, pPrimitive->GetFloat(), fFontSize); width.Set(FDE_CSSLengthUnit::Point, fValue); return width.NonZero(); } else if (eType == FDE_CSSPrimitiveType::Enum) { switch (pPrimitive->GetEnum()) { 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(IFDE_CSSValueList* pValue) { uint32_t dwDecoration = 0; for (int32_t i = pValue->CountValues() - 1; i >= 0; --i) { IFDE_CSSPrimitiveValue* pPrimitive = static_cast(pValue->GetValue(i)); if (pPrimitive->GetPrimitiveType() == FDE_CSSPrimitiveType::Enum) { switch (pPrimitive->GetEnum()) { 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; } CFDE_CSSComputedStyle::CFDE_CSSComputedStyle() : m_dwRefCount(1) {} CFDE_CSSComputedStyle::~CFDE_CSSComputedStyle() {} uint32_t CFDE_CSSComputedStyle::Retain() { return ++m_dwRefCount; } uint32_t CFDE_CSSComputedStyle::Release() { uint32_t dwRefCount = --m_dwRefCount; if (dwRefCount == 0) delete this; return dwRefCount; } IFDE_CSSFontStyle* CFDE_CSSComputedStyle::GetFontStyles() { return static_cast(this); } IFDE_CSSBoundaryStyle* CFDE_CSSComputedStyle::GetBoundaryStyles() { return static_cast(this); } IFDE_CSSPositionStyle* CFDE_CSSComputedStyle::GetPositionStyles() { return static_cast(this); } IFDE_CSSParagraphStyle* CFDE_CSSComputedStyle::GetParagraphStyles() { return static_cast(this); } bool CFDE_CSSComputedStyle::GetCustomStyle(const CFX_WideStringC& wsName, CFX_WideString& wsValue) const { for (int32_t i = pdfium::CollectionSize(m_CustomProperties) - 2; i > -1; i -= 2) { if (wsName == m_CustomProperties[i]) { wsValue = m_CustomProperties[i + 1]; return true; } } return false; } int32_t CFDE_CSSComputedStyle::CountFontFamilies() const { return m_InheritedData.m_pFontFamily ? m_InheritedData.m_pFontFamily->CountValues() : 0; } const FX_WCHAR* CFDE_CSSComputedStyle::GetFontFamily(int32_t index) const { return (static_cast( m_InheritedData.m_pFontFamily->GetValue(index))) ->GetString(index); } uint16_t CFDE_CSSComputedStyle::GetFontWeight() const { return m_InheritedData.m_wFontWeight; } FDE_CSSFontVariant CFDE_CSSComputedStyle::GetFontVariant() const { return static_cast(m_InheritedData.m_eFontVariant); } FDE_CSSFontStyle CFDE_CSSComputedStyle::GetFontStyle() const { return static_cast(m_InheritedData.m_eFontStyle); } FX_FLOAT CFDE_CSSComputedStyle::GetFontSize() const { return m_InheritedData.m_fFontSize; } FX_ARGB CFDE_CSSComputedStyle::GetColor() const { return m_InheritedData.m_dwFontColor; } void CFDE_CSSComputedStyle::SetFontWeight(uint16_t wFontWeight) { m_InheritedData.m_wFontWeight = wFontWeight; } void CFDE_CSSComputedStyle::SetFontVariant(FDE_CSSFontVariant eFontVariant) { m_InheritedData.m_eFontVariant = eFontVariant; } void CFDE_CSSComputedStyle::SetFontStyle(FDE_CSSFontStyle eFontStyle) { m_InheritedData.m_eFontStyle = eFontStyle; } void CFDE_CSSComputedStyle::SetFontSize(FX_FLOAT fFontSize) { m_InheritedData.m_fFontSize = fFontSize; } void CFDE_CSSComputedStyle::SetColor(FX_ARGB dwFontColor) { m_InheritedData.m_dwFontColor = dwFontColor; } const FDE_CSSRECT* CFDE_CSSComputedStyle::GetBorderWidth() const { return m_NonInheritedData.m_bHasBorder ? &(m_NonInheritedData.m_BorderWidth) : nullptr; } const FDE_CSSRECT* CFDE_CSSComputedStyle::GetMarginWidth() const { return m_NonInheritedData.m_bHasMargin ? &(m_NonInheritedData.m_MarginWidth) : nullptr; } const FDE_CSSRECT* CFDE_CSSComputedStyle::GetPaddingWidth() const { return m_NonInheritedData.m_bHasPadding ? &(m_NonInheritedData.m_PaddingWidth) : nullptr; } void CFDE_CSSComputedStyle::SetMarginWidth(const FDE_CSSRECT& rect) { m_NonInheritedData.m_MarginWidth = rect; m_NonInheritedData.m_bHasMargin = true; } void CFDE_CSSComputedStyle::SetPaddingWidth(const FDE_CSSRECT& rect) { m_NonInheritedData.m_PaddingWidth = rect; m_NonInheritedData.m_bHasPadding = true; } FDE_CSSDisplay CFDE_CSSComputedStyle::GetDisplay() const { return static_cast(m_NonInheritedData.m_eDisplay); } FX_FLOAT CFDE_CSSComputedStyle::GetLineHeight() const { return m_InheritedData.m_fLineHeight; } const FDE_CSSLENGTH& CFDE_CSSComputedStyle::GetTextIndent() const { return m_InheritedData.m_TextIndent; } FDE_CSSTextAlign CFDE_CSSComputedStyle::GetTextAlign() const { return static_cast(m_InheritedData.m_eTextAlign); } FDE_CSSVerticalAlign CFDE_CSSComputedStyle::GetVerticalAlign() const { return static_cast(m_NonInheritedData.m_eVerticalAlign); } FX_FLOAT CFDE_CSSComputedStyle::GetNumberVerticalAlign() const { return m_NonInheritedData.m_fVerticalAlign; } uint32_t CFDE_CSSComputedStyle::GetTextDecoration() const { return m_NonInheritedData.m_dwTextDecoration; } const FDE_CSSLENGTH& CFDE_CSSComputedStyle::GetLetterSpacing() const { return m_InheritedData.m_LetterSpacing; } void CFDE_CSSComputedStyle::SetLineHeight(FX_FLOAT fLineHeight) { m_InheritedData.m_fLineHeight = fLineHeight; } void CFDE_CSSComputedStyle::SetTextIndent(const FDE_CSSLENGTH& textIndent) { m_InheritedData.m_TextIndent = textIndent; } void CFDE_CSSComputedStyle::SetTextAlign(FDE_CSSTextAlign eTextAlign) { m_InheritedData.m_eTextAlign = eTextAlign; } void CFDE_CSSComputedStyle::SetNumberVerticalAlign(FX_FLOAT fAlign) { m_NonInheritedData.m_eVerticalAlign = FDE_CSSVerticalAlign::Number, m_NonInheritedData.m_fVerticalAlign = fAlign; } void CFDE_CSSComputedStyle::SetTextDecoration(uint32_t dwTextDecoration) { m_NonInheritedData.m_dwTextDecoration = dwTextDecoration; } void CFDE_CSSComputedStyle::SetLetterSpacing( const FDE_CSSLENGTH& letterSpacing) { m_InheritedData.m_LetterSpacing = letterSpacing; } void CFDE_CSSComputedStyle::AddCustomStyle(const CFX_WideString& wsName, const CFX_WideString& wsValue) { m_CustomProperties.push_back(wsName); m_CustomProperties.push_back(wsValue); } CFDE_CSSInheritedData::CFDE_CSSInheritedData() : m_LetterSpacing(FDE_CSSLengthUnit::Normal), m_WordSpacing(FDE_CSSLengthUnit::Normal), m_TextIndent(FDE_CSSLengthUnit::Point, 0), m_pFontFamily(nullptr), m_fFontSize(12.0f), m_fLineHeight(14.0f), m_dwFontColor(0xFF000000), m_wFontWeight(400), m_eFontVariant(FDE_CSSFontVariant::Normal), m_eFontStyle(FDE_CSSFontStyle::Normal), m_eTextAlign(FDE_CSSTextAlign::Left) {} CFDE_CSSNonInheritedData::CFDE_CSSNonInheritedData() : m_MarginWidth(FDE_CSSLengthUnit::Point, 0), m_BorderWidth(FDE_CSSLengthUnit::Point, 0), m_PaddingWidth(FDE_CSSLengthUnit::Point, 0), m_fVerticalAlign(0.0f), m_eDisplay(FDE_CSSDisplay::Inline), m_eVerticalAlign(FDE_CSSVerticalAlign::Baseline), m_dwTextDecoration(0), m_bHasMargin(false), m_bHasBorder(false), m_bHasPadding(false) {}