1 // Copyright 2015 The Chromium 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.
7 #include "core/html/canvas/CanvasFontCache.h"
9 #include "core/css/parser/CSSParser.h"
10 #include "core/css/resolver/StyleResolver.h"
11 #include "core/dom/Document.h"
12 #include "core/style/ComputedStyle.h"
13 #include "platform/fonts/FontCache.h"
14 #include "public/platform/Platform.h"
18 const unsigned CanvasFontCacheMaxFonts
= 50;
19 const unsigned CanvasFontCacheHardMaxFonts
= 250;
20 const unsigned CanvasFontCacheHiddenMaxFonts
= 1;
21 const int defaultFontSize
= 10;
22 const char defaultFontFamily
[] = "sans-serif";
28 CanvasFontCache::CanvasFontCache(Document
& document
)
29 : m_document(&document
)
30 , m_pruningScheduled(false)
32 FontFamily fontFamily
;
33 fontFamily
.setFamily(defaultFontFamily
);
34 FontDescription defaultFontDescription
;
35 defaultFontDescription
.setFamily(fontFamily
);
36 defaultFontDescription
.setSpecifiedSize(defaultFontSize
);
37 defaultFontDescription
.setComputedSize(defaultFontSize
);
38 m_defaultFontStyle
= ComputedStyle::create();
39 m_defaultFontStyle
->setFontDescription(defaultFontDescription
);
40 m_defaultFontStyle
->font().update(m_defaultFontStyle
->font().fontSelector());
43 CanvasFontCache::~CanvasFontCache()
45 m_mainCachePurgePreventer
.clear();
46 if (m_pruningScheduled
) {
47 Platform::current()->currentThread()->removeTaskObserver(this);
51 unsigned CanvasFontCache::maxFonts()
53 return CanvasFontCacheMaxFonts
;
56 unsigned CanvasFontCache::hardMaxFonts()
58 return m_document
->hidden() ? CanvasFontCacheHiddenMaxFonts
: CanvasFontCacheHardMaxFonts
;
61 bool CanvasFontCache::getFontUsingDefaultStyle(const String
& fontString
, Font
& resolvedFont
)
63 HashMap
<String
, Font
>::iterator i
= m_fontsResolvedUsingDefaultStyle
.find(fontString
);
64 if (i
!= m_fontsResolvedUsingDefaultStyle
.end()) {
65 ASSERT(m_fontLRUList
.contains(fontString
));
66 m_fontLRUList
.remove(fontString
);
67 m_fontLRUList
.add(fontString
);
68 resolvedFont
= i
->value
;
72 // Addition to LRU list taken care of inside parseFont
73 MutableStylePropertySet
* parsedStyle
= parseFont(fontString
);
77 RefPtr
<ComputedStyle
> fontStyle
= ComputedStyle::clone(*m_defaultFontStyle
.get());
78 m_document
->ensureStyleResolver().computeFont(fontStyle
.get(), *parsedStyle
);
79 m_fontsResolvedUsingDefaultStyle
.add(fontString
, fontStyle
->font());
80 resolvedFont
= m_fontsResolvedUsingDefaultStyle
.find(fontString
)->value
;
84 MutableStylePropertySet
* CanvasFontCache::parseFont(const String
& fontString
)
86 RefPtrWillBeRawPtr
<MutableStylePropertySet
> parsedStyle
;
87 MutableStylePropertyMap::iterator i
= m_fetchedFonts
.find(fontString
);
88 if (i
!= m_fetchedFonts
.end()) {
89 ASSERT(m_fontLRUList
.contains(fontString
));
90 parsedStyle
= i
->value
;
91 m_fontLRUList
.remove(fontString
);
92 m_fontLRUList
.add(fontString
);
94 parsedStyle
= MutableStylePropertySet::create();
95 CSSParser::parseValue(parsedStyle
.get(), CSSPropertyFont
, fontString
, true, HTMLStandardMode
, 0);
96 if (parsedStyle
->isEmpty())
98 // According to http://lists.w3.org/Archives/Public/public-html/2009Jul/0947.html,
99 // the "inherit" and "initial" values must be ignored.
100 RefPtrWillBeRawPtr
<CSSValue
> fontValue
= parsedStyle
->getPropertyCSSValue(CSSPropertyFontSize
);
101 if (fontValue
&& (fontValue
->isInitialValue() || fontValue
->isInheritedValue()))
103 m_fetchedFonts
.add(fontString
, parsedStyle
);
104 m_fontLRUList
.add(fontString
);
105 // Hard limit is applied here, on the fly, while the soft limit is
106 // applied at the end of the task.
107 if (m_fetchedFonts
.size() > hardMaxFonts()) {
108 ASSERT(m_fetchedFonts
.size() == hardMaxFonts() + 1);
109 ASSERT(m_fontLRUList
.size() == hardMaxFonts() + 1);
110 m_fetchedFonts
.remove(m_fontLRUList
.first());
111 m_fontsResolvedUsingDefaultStyle
.remove(m_fontLRUList
.first());
112 m_fontLRUList
.removeFirst();
115 schedulePruningIfNeeded();
117 return parsedStyle
.get(); // In non-oilpan builds: ref in m_fetchedFonts keeps object alive after return.
120 void CanvasFontCache::didProcessTask()
122 ASSERT(m_pruningScheduled
);
123 ASSERT(m_mainCachePurgePreventer
);
124 while (m_fetchedFonts
.size() > maxFonts()) {
125 m_fetchedFonts
.remove(m_fontLRUList
.first());
126 m_fontsResolvedUsingDefaultStyle
.remove(m_fontLRUList
.first());
127 m_fontLRUList
.removeFirst();
129 m_mainCachePurgePreventer
.clear();
130 Platform::current()->currentThread()->removeTaskObserver(this);
131 m_pruningScheduled
= false;
134 void CanvasFontCache::schedulePruningIfNeeded()
136 if (m_pruningScheduled
)
138 ASSERT(!m_mainCachePurgePreventer
);
139 m_mainCachePurgePreventer
= adoptPtr(new FontCachePurgePreventer
);
140 Platform::current()->currentThread()->addTaskObserver(this);
141 m_pruningScheduled
= true;
144 bool CanvasFontCache::isInCache(const String
& fontString
)
146 return m_fetchedFonts
.find(fontString
) != m_fetchedFonts
.end();
149 void CanvasFontCache::pruneAll()
151 m_fetchedFonts
.clear();
152 m_fontLRUList
.clear();
153 m_fontsResolvedUsingDefaultStyle
.clear();
156 DEFINE_TRACE(CanvasFontCache
)
159 visitor
->trace(m_fetchedFonts
);
160 visitor
->trace(m_document
);