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 <algorithm>
8 
9 #include "xfa/src/foxitlib.h"
10 #include "fde_csscache.h"
_FDE_CSSCACHEITEM(IFDE_CSSStyleSheet * p)11 _FDE_CSSCACHEITEM::_FDE_CSSCACHEITEM(IFDE_CSSStyleSheet* p)
12     : pStylesheet(p), dwActivity(0) {
13   FXSYS_assert(pStylesheet);
14   pStylesheet->AddRef();
15 }
~_FDE_CSSCACHEITEM()16 _FDE_CSSCACHEITEM::~_FDE_CSSCACHEITEM() {
17   pStylesheet->Release();
18 }
Create()19 IFDE_CSSStyleSheetCache* IFDE_CSSStyleSheetCache::Create() {
20   return new CFDE_CSSStyleSheetCache;
21 }
22 
CFDE_CSSStyleSheetCache()23 CFDE_CSSStyleSheetCache::CFDE_CSSStyleSheetCache()
24     : m_pFixedStore(NULL), m_iMaxItems(5) {}
25 
~CFDE_CSSStyleSheetCache()26 CFDE_CSSStyleSheetCache::~CFDE_CSSStyleSheetCache() {
27   for (const auto& pair : m_Stylesheets) {
28     FDE_DeleteWith(FDE_CSSCACHEITEM, m_pFixedStore, pair.second);
29   }
30   m_Stylesheets.clear();
31   if (m_pFixedStore) {
32     m_pFixedStore->Release();
33   }
34 }
AddStyleSheet(const CFX_ByteStringC & szKey,IFDE_CSSStyleSheet * pStyleSheet)35 void CFDE_CSSStyleSheetCache::AddStyleSheet(const CFX_ByteStringC& szKey,
36                                             IFDE_CSSStyleSheet* pStyleSheet) {
37   FXSYS_assert(pStyleSheet != NULL);
38   if (m_pFixedStore == NULL) {
39     m_pFixedStore =
40         FX_CreateAllocator(FX_ALLOCTYPE_Fixed, std::max(10, m_iMaxItems),
41                            sizeof(FDE_CSSCACHEITEM));
42     FXSYS_assert(m_pFixedStore != NULL);
43   }
44   auto it = m_Stylesheets.find(szKey);
45   if (it != m_Stylesheets.end()) {
46     FDE_LPCSSCACHEITEM pItem = it->second;
47     if (pItem->pStylesheet != pStyleSheet) {
48       pItem->pStylesheet->Release();
49       pItem->pStylesheet = pStyleSheet;
50       pItem->pStylesheet->AddRef();
51       pItem->dwActivity = 0;
52     }
53   } else {
54     while (static_cast<int32_t>(m_Stylesheets.size()) >= m_iMaxItems) {
55       RemoveLowestActivityItem();
56     }
57     m_Stylesheets[szKey] =
58         FDE_NewWith(m_pFixedStore) FDE_CSSCACHEITEM(pStyleSheet);
59   }
60 }
GetStyleSheet(const CFX_ByteStringC & szKey) const61 IFDE_CSSStyleSheet* CFDE_CSSStyleSheetCache::GetStyleSheet(
62     const CFX_ByteStringC& szKey) const {
63   auto it = m_Stylesheets.find(szKey);
64   if (it == m_Stylesheets.end()) {
65     return nullptr;
66   }
67   FDE_LPCSSCACHEITEM pItem = it->second;
68   pItem->dwActivity++;
69   pItem->pStylesheet->AddRef();
70   return pItem->pStylesheet;
71 }
RemoveStyleSheet(const CFX_ByteStringC & szKey)72 void CFDE_CSSStyleSheetCache::RemoveStyleSheet(const CFX_ByteStringC& szKey) {
73   auto it = m_Stylesheets.find(szKey);
74   if (it == m_Stylesheets.end()) {
75     return;
76   }
77   FDE_DeleteWith(FDE_CSSCACHEITEM, m_pFixedStore, it->second);
78   m_Stylesheets.erase(it);
79 }
RemoveLowestActivityItem()80 void CFDE_CSSStyleSheetCache::RemoveLowestActivityItem() {
81   auto found = m_Stylesheets.end();
82   for (auto it = m_Stylesheets.begin(); it != m_Stylesheets.end(); ++it) {
83     switch (it->first.GetID()) {
84       case FXBSTR_ID('#', 'U', 'S', 'E'):
85       case FXBSTR_ID('#', 'A', 'G', 'E'):
86         continue;
87     }
88     if (found == m_Stylesheets.end() ||
89         it->second->dwActivity > found->second->dwActivity) {
90       found = it;
91     }
92   }
93   if (found != m_Stylesheets.end()) {
94     FDE_DeleteWith(FDE_CSSCACHEITEM, m_pFixedStore, found->second);
95     m_Stylesheets.erase(found);
96   }
97 }
_FDE_CSSTAGCACHE(_FDE_CSSTAGCACHE * parent,IFDE_CSSTagProvider * tag)98 _FDE_CSSTAGCACHE::_FDE_CSSTAGCACHE(_FDE_CSSTAGCACHE* parent,
99                                    IFDE_CSSTagProvider* tag)
100     : pTag(tag),
101       pParent(parent),
102       dwIDHash(0),
103       dwTagHash(0),
104       iClassIndex(0),
105       dwClassHashs(1) {
106   FXSYS_assert(pTag != NULL);
107   CFX_WideStringC wsValue, wsName = pTag->GetTagName();
108   dwTagHash =
109       FX_HashCode_String_GetW(wsName.GetPtr(), wsName.GetLength(), TRUE);
110   FX_POSITION pos = pTag->GetFirstAttribute();
111   while (pos != NULL) {
112     pTag->GetNextAttribute(pos, wsName, wsValue);
113     FX_DWORD dwNameHash =
114         FX_HashCode_String_GetW(wsName.GetPtr(), wsName.GetLength(), TRUE);
115     static const FX_DWORD s_dwIDHash = FX_HashCode_String_GetW(L"id", 2, TRUE);
116     static const FX_DWORD s_dwClassHash =
117         FX_HashCode_String_GetW(L"class", 5, TRUE);
118     if (dwNameHash == s_dwClassHash) {
119       FX_DWORD dwHash =
120           FX_HashCode_String_GetW(wsValue.GetPtr(), wsValue.GetLength());
121       dwClassHashs.Add(dwHash);
122     } else if (dwNameHash == s_dwIDHash) {
123       dwIDHash = FX_HashCode_String_GetW(wsValue.GetPtr(), wsValue.GetLength());
124     }
125   }
126 }
_FDE_CSSTAGCACHE(const _FDE_CSSTAGCACHE & it)127 _FDE_CSSTAGCACHE::_FDE_CSSTAGCACHE(const _FDE_CSSTAGCACHE& it)
128     : pTag(it.pTag),
129       pParent(it.pParent),
130       dwIDHash(it.dwIDHash),
131       dwTagHash(it.dwTagHash),
132       iClassIndex(0),
133       dwClassHashs(1) {
134   if (it.dwClassHashs.GetSize() > 0) {
135     dwClassHashs.Copy(it.dwClassHashs);
136   }
137 }
OnEnterTag(IFDE_CSSTagProvider * pTag)138 void CFDE_CSSAccelerator::OnEnterTag(IFDE_CSSTagProvider* pTag) {
139   FDE_CSSTAGCACHE* pTop = GetTopElement();
140   FDE_CSSTAGCACHE item(pTop, pTag);
141   m_Stack.Push(item);
142 }
OnLeaveTag(IFDE_CSSTagProvider * pTag)143 void CFDE_CSSAccelerator::OnLeaveTag(IFDE_CSSTagProvider* pTag) {
144   FDE_CSSTAGCACHE* pItem = m_Stack.GetTopElement();
145   FXSYS_assert(pItem && pItem->GetTag() == pTag);
146   m_Stack.Pop();
147 }
148