blob: 3d3b040a87e41a116ee1cbc68e516c714bc66034 [file] [log] [blame]
// 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 <algorithm>
#include "xfa/src/foxitlib.h"
#include "fde_csscache.h"
_FDE_CSSCACHEITEM::_FDE_CSSCACHEITEM(IFDE_CSSStyleSheet* p)
: pStylesheet(p), dwActivity(0) {
FXSYS_assert(pStylesheet);
pStylesheet->AddRef();
}
_FDE_CSSCACHEITEM::~_FDE_CSSCACHEITEM() {
pStylesheet->Release();
}
IFDE_CSSStyleSheetCache* IFDE_CSSStyleSheetCache::Create() {
return new CFDE_CSSStyleSheetCache;
}
CFDE_CSSStyleSheetCache::CFDE_CSSStyleSheetCache()
: m_pFixedStore(NULL), m_iMaxItems(5) {}
CFDE_CSSStyleSheetCache::~CFDE_CSSStyleSheetCache() {
for (const auto& pair : m_Stylesheets) {
FDE_DeleteWith(FDE_CSSCACHEITEM, m_pFixedStore, pair.second);
}
m_Stylesheets.clear();
if (m_pFixedStore) {
m_pFixedStore->Release();
}
}
void CFDE_CSSStyleSheetCache::AddStyleSheet(const CFX_ByteStringC& szKey,
IFDE_CSSStyleSheet* pStyleSheet) {
FXSYS_assert(pStyleSheet != NULL);
if (m_pFixedStore == NULL) {
m_pFixedStore =
FX_CreateAllocator(FX_ALLOCTYPE_Fixed, std::max(10, m_iMaxItems),
sizeof(FDE_CSSCACHEITEM));
FXSYS_assert(m_pFixedStore != NULL);
}
auto it = m_Stylesheets.find(szKey);
if (it != m_Stylesheets.end()) {
FDE_LPCSSCACHEITEM pItem = it->second;
if (pItem->pStylesheet != pStyleSheet) {
pItem->pStylesheet->Release();
pItem->pStylesheet = pStyleSheet;
pItem->pStylesheet->AddRef();
pItem->dwActivity = 0;
}
} else {
while (static_cast<int32_t>(m_Stylesheets.size()) >= m_iMaxItems) {
RemoveLowestActivityItem();
}
m_Stylesheets[szKey] =
FDE_NewWith(m_pFixedStore) FDE_CSSCACHEITEM(pStyleSheet);
}
}
IFDE_CSSStyleSheet* CFDE_CSSStyleSheetCache::GetStyleSheet(
const CFX_ByteStringC& szKey) const {
auto it = m_Stylesheets.find(szKey);
if (it == m_Stylesheets.end()) {
return nullptr;
}
FDE_LPCSSCACHEITEM pItem = it->second;
pItem->dwActivity++;
pItem->pStylesheet->AddRef();
return pItem->pStylesheet;
}
void CFDE_CSSStyleSheetCache::RemoveStyleSheet(const CFX_ByteStringC& szKey) {
auto it = m_Stylesheets.find(szKey);
if (it == m_Stylesheets.end()) {
return;
}
FDE_DeleteWith(FDE_CSSCACHEITEM, m_pFixedStore, it->second);
m_Stylesheets.erase(it);
}
void CFDE_CSSStyleSheetCache::RemoveLowestActivityItem() {
auto found = m_Stylesheets.end();
for (auto it = m_Stylesheets.begin(); it != m_Stylesheets.end(); ++it) {
switch (it->first.GetID()) {
case FXBSTR_ID('#', 'U', 'S', 'E'):
case FXBSTR_ID('#', 'A', 'G', 'E'):
continue;
}
if (found == m_Stylesheets.end() ||
it->second->dwActivity > found->second->dwActivity) {
found = it;
}
}
if (found != m_Stylesheets.end()) {
FDE_DeleteWith(FDE_CSSCACHEITEM, m_pFixedStore, found->second);
m_Stylesheets.erase(found);
}
}
_FDE_CSSTAGCACHE::_FDE_CSSTAGCACHE(_FDE_CSSTAGCACHE* parent,
IFDE_CSSTagProvider* tag)
: pTag(tag),
pParent(parent),
dwIDHash(0),
dwTagHash(0),
iClassIndex(0),
dwClassHashs(1) {
FXSYS_assert(pTag != NULL);
CFX_WideStringC wsValue, wsName = pTag->GetTagName();
dwTagHash =
FX_HashCode_String_GetW(wsName.GetPtr(), wsName.GetLength(), TRUE);
FX_POSITION pos = pTag->GetFirstAttribute();
while (pos != NULL) {
pTag->GetNextAttribute(pos, wsName, wsValue);
FX_DWORD dwNameHash =
FX_HashCode_String_GetW(wsName.GetPtr(), wsName.GetLength(), TRUE);
static const FX_DWORD s_dwIDHash = FX_HashCode_String_GetW(L"id", 2, TRUE);
static const FX_DWORD s_dwClassHash =
FX_HashCode_String_GetW(L"class", 5, TRUE);
if (dwNameHash == s_dwClassHash) {
FX_DWORD dwHash =
FX_HashCode_String_GetW(wsValue.GetPtr(), wsValue.GetLength());
dwClassHashs.Add(dwHash);
} else if (dwNameHash == s_dwIDHash) {
dwIDHash = FX_HashCode_String_GetW(wsValue.GetPtr(), wsValue.GetLength());
}
}
}
_FDE_CSSTAGCACHE::_FDE_CSSTAGCACHE(const _FDE_CSSTAGCACHE& it)
: pTag(it.pTag),
pParent(it.pParent),
dwIDHash(it.dwIDHash),
dwTagHash(it.dwTagHash),
iClassIndex(0),
dwClassHashs(1) {
if (it.dwClassHashs.GetSize() > 0) {
dwClassHashs.Copy(it.dwClassHashs);
}
}
void CFDE_CSSAccelerator::OnEnterTag(IFDE_CSSTagProvider* pTag) {
FDE_CSSTAGCACHE* pTop = GetTopElement();
FDE_CSSTAGCACHE item(pTop, pTag);
m_Stack.Push(item);
}
void CFDE_CSSAccelerator::OnLeaveTag(IFDE_CSSTagProvider* pTag) {
FDE_CSSTAGCACHE* pItem = m_Stack.GetTopElement();
FXSYS_assert(pItem && pItem->GetTag() == pTag);
m_Stack.Pop();
}