summaryrefslogtreecommitdiff
path: root/xfa/fde/css/cfde_cssrulecollection.cpp
blob: db3342cfc60d6bbc695b8f745083574f44265c1e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright 2016 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_cssrulecollection.h"

#include <algorithm>
#include <map>
#include <memory>

#include "xfa/fde/css/cfde_cssdeclaration.h"
#include "xfa/fde/css/cfde_cssselector.h"
#include "xfa/fde/css/cfde_cssstylerule.h"
#include "xfa/fde/css/cfde_cssstylesheet.h"
#include "xfa/fde/css/cfde_csssyntaxparser.h"
#include "xfa/fde/css/cfde_csstagcache.h"

#define FDE_CSSUNIVERSALHASH ('*')

void CFDE_CSSRuleCollection::Clear() {
  m_IDRules.clear();
  m_TagRules.clear();
  m_ClassRules.clear();
  m_pUniversalRules = nullptr;
  m_iSelectors = 0;
}

CFDE_CSSRuleCollection::CFDE_CSSRuleCollection()
    : m_pUniversalRules(nullptr), m_iSelectors(0) {}

CFDE_CSSRuleCollection::~CFDE_CSSRuleCollection() {
  Clear();
}

void CFDE_CSSRuleCollection::AddRulesFrom(const CFDE_CSSStyleSheet* sheet,
                                          CFGAS_FontMgr* pFontMgr) {
  int32_t iRules = sheet->CountRules();
  for (int32_t j = 0; j < iRules; j++)
    AddRulesFrom(sheet, sheet->GetRule(j), pFontMgr);
}

void CFDE_CSSRuleCollection::AddRulesFrom(const CFDE_CSSStyleSheet* pStyleSheet,
                                          CFDE_CSSStyleRule* pStyleRule,
                                          CFGAS_FontMgr* pFontMgr) {
  CFDE_CSSDeclaration* pDeclaration = pStyleRule->GetDeclaration();
  int32_t iSelectors = pStyleRule->CountSelectorLists();
  for (int32_t i = 0; i < iSelectors; ++i) {
    CFDE_CSSSelector* pSelector = pStyleRule->GetSelectorList(i);
    if (pSelector->GetNameHash() != FDE_CSSUNIVERSALHASH) {
      AddRuleTo(&m_TagRules, pSelector->GetNameHash(), pSelector, pDeclaration);
      continue;
    }
    CFDE_CSSSelector* pNext = pSelector->GetNextSelector();
    if (!pNext) {
      Data* pData = NewRuleData(pSelector, pDeclaration);
      AddRuleTo(&m_pUniversalRules, pData);
      continue;
    }
    switch (pNext->GetType()) {
      case FDE_CSSSelectorType::ID:
        AddRuleTo(&m_IDRules, pNext->GetNameHash(), pSelector, pDeclaration);
        break;
      case FDE_CSSSelectorType::Class:
        AddRuleTo(&m_ClassRules, pNext->GetNameHash(), pSelector, pDeclaration);
        break;
      case FDE_CSSSelectorType::Descendant:
      case FDE_CSSSelectorType::Element:
        AddRuleTo(&m_pUniversalRules, NewRuleData(pSelector, pDeclaration));
        break;
      default:
        ASSERT(false);
        break;
    }
  }
}

void CFDE_CSSRuleCollection::AddRuleTo(std::map<uint32_t, Data*>* pMap,
                                       uint32_t dwKey,
                                       CFDE_CSSSelector* pSel,
                                       CFDE_CSSDeclaration* pDecl) {
  Data* pData = NewRuleData(pSel, pDecl);
  Data* pList = (*pMap)[dwKey];
  if (!pList) {
    (*pMap)[dwKey] = pData;
  } else if (AddRuleTo(&pList, pData)) {
    (*pMap)[dwKey] = pList;
  }
}

bool CFDE_CSSRuleCollection::AddRuleTo(Data** pList, Data* pData) {
  if (*pList) {
    pData->pNext = (*pList)->pNext;
    (*pList)->pNext = pData;
    return false;
  }
  *pList = pData;
  return true;
}

CFDE_CSSRuleCollection::Data* CFDE_CSSRuleCollection::NewRuleData(
    CFDE_CSSSelector* pSel,
    CFDE_CSSDeclaration* pDecl) {
  return new Data(pSel, pDecl, ++m_iSelectors);
}

CFDE_CSSRuleCollection::Data::Data(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<int>(eType)];
    }
  }
}