1// Copyright 2014 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "xfa/fde/css/cfde_cssstylesheet.h"
8
9#include <utility>
10
11#include "third_party/base/ptr_util.h"
12#include "third_party/base/stl_util.h"
13#include "xfa/fde/css/cfde_cssdeclaration.h"
14#include "xfa/fde/css/cfde_cssstylerule.h"
15#include "xfa/fde/css/fde_cssdatatable.h"
16#include "xfa/fgas/crt/fgas_codepage.h"
17
18CFDE_CSSStyleSheet::CFDE_CSSStyleSheet() {}
19
20CFDE_CSSStyleSheet::~CFDE_CSSStyleSheet() {
21  Reset();
22}
23
24void CFDE_CSSStyleSheet::Reset() {
25  m_RuleArray.clear();
26  m_StringCache.clear();
27}
28
29int32_t CFDE_CSSStyleSheet::CountRules() const {
30  return pdfium::CollectionSize<int32_t>(m_RuleArray);
31}
32
33CFDE_CSSStyleRule* CFDE_CSSStyleSheet::GetRule(int32_t index) const {
34  return m_RuleArray[index].get();
35}
36
37bool CFDE_CSSStyleSheet::LoadBuffer(const FX_WCHAR* pBuffer, int32_t iBufSize) {
38  ASSERT(pBuffer && iBufSize > 0);
39
40  auto pSyntax = pdfium::MakeUnique<CFDE_CSSSyntaxParser>();
41  if (!pSyntax->Init(pBuffer, iBufSize))
42    return false;
43
44  Reset();
45  FDE_CSSSyntaxStatus eStatus;
46  do {
47    switch (eStatus = pSyntax->DoSyntaxParse()) {
48      case FDE_CSSSyntaxStatus::StyleRule:
49        eStatus = LoadStyleRule(pSyntax.get(), &m_RuleArray);
50        break;
51      default:
52        break;
53    }
54  } while (eStatus >= FDE_CSSSyntaxStatus::None);
55
56  m_StringCache.clear();
57  return eStatus != FDE_CSSSyntaxStatus::Error;
58}
59
60FDE_CSSSyntaxStatus CFDE_CSSStyleSheet::LoadStyleRule(
61    CFDE_CSSSyntaxParser* pSyntax,
62    std::vector<std::unique_ptr<CFDE_CSSStyleRule>>* ruleArray) {
63  std::vector<std::unique_ptr<CFDE_CSSSelector>> selectors;
64
65  CFDE_CSSStyleRule* pStyleRule = nullptr;
66  int32_t iValueLen = 0;
67  const FDE_CSSPropertyTable* propertyTable = nullptr;
68  CFX_WideString wsName;
69  while (1) {
70    switch (pSyntax->DoSyntaxParse()) {
71      case FDE_CSSSyntaxStatus::Selector: {
72        CFX_WideStringC strValue = pSyntax->GetCurrentString();
73        auto pSelector = CFDE_CSSSelector::FromString(strValue);
74        if (pSelector)
75          selectors.push_back(std::move(pSelector));
76        break;
77      }
78      case FDE_CSSSyntaxStatus::PropertyName: {
79        CFX_WideStringC strValue = pSyntax->GetCurrentString();
80        propertyTable = FDE_GetCSSPropertyByName(strValue);
81        if (!propertyTable)
82          wsName = CFX_WideString(strValue);
83        break;
84      }
85      case FDE_CSSSyntaxStatus::PropertyValue: {
86        if (propertyTable || iValueLen > 0) {
87          CFX_WideStringC strValue = pSyntax->GetCurrentString();
88          auto decl = pStyleRule->GetDeclaration();
89          if (!strValue.IsEmpty()) {
90            if (propertyTable) {
91              decl->AddProperty(propertyTable, strValue);
92            } else {
93              decl->AddProperty(wsName, CFX_WideString(strValue));
94            }
95          }
96        }
97        break;
98      }
99      case FDE_CSSSyntaxStatus::DeclOpen: {
100        if (!pStyleRule && !selectors.empty()) {
101          auto rule = pdfium::MakeUnique<CFDE_CSSStyleRule>();
102          pStyleRule = rule.get();
103          pStyleRule->SetSelector(&selectors);
104          ruleArray->push_back(std::move(rule));
105        } else {
106          SkipRuleSet(pSyntax);
107          return FDE_CSSSyntaxStatus::None;
108        }
109        break;
110      }
111      case FDE_CSSSyntaxStatus::DeclClose: {
112        if (pStyleRule && pStyleRule->GetDeclaration()->empty()) {
113          ruleArray->pop_back();
114          pStyleRule = nullptr;
115        }
116        return FDE_CSSSyntaxStatus::None;
117      }
118      case FDE_CSSSyntaxStatus::EOS:
119        return FDE_CSSSyntaxStatus::EOS;
120      case FDE_CSSSyntaxStatus::Error:
121      default:
122        return FDE_CSSSyntaxStatus::Error;
123    }
124  }
125}
126
127void CFDE_CSSStyleSheet::SkipRuleSet(CFDE_CSSSyntaxParser* pSyntax) {
128  while (1) {
129    switch (pSyntax->DoSyntaxParse()) {
130      case FDE_CSSSyntaxStatus::Selector:
131      case FDE_CSSSyntaxStatus::DeclOpen:
132      case FDE_CSSSyntaxStatus::PropertyName:
133      case FDE_CSSSyntaxStatus::PropertyValue:
134        break;
135      case FDE_CSSSyntaxStatus::DeclClose:
136      case FDE_CSSSyntaxStatus::EOS:
137      case FDE_CSSSyntaxStatus::Error:
138      default:
139        return;
140    }
141  }
142}
143