summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjunov@chromium.org <junov@chromium.org>2015-07-21 16:54:23 +0000
committerjunov@chromium.org <junov@chromium.org>2015-07-21 16:54:23 +0000
commita0a14768abf019aa377fbcf9ea72d7c54c5fb45b (patch)
treeb445aecc756c797b6d65c2b4d6030fd98517ee6b
parent1ef39cf4a2a5a6276c0744a45c789f4cc01a2a74 (diff)
downloadchromium_src-a0a14768abf019aa377fbcf9ea72d7c54c5fb45b.zip
chromium_src-a0a14768abf019aa377fbcf9ea72d7c54c5fb45b.tar.gz
chromium_src-a0a14768abf019aa377fbcf9ea72d7c54c5fb45b.tar.bz2
Adding a canvas-specific cache for style-dependent font resolution
This change adds a cache very similar to the one added in https://src.chromium.org/viewvc/blink?view=rev&revision=198618 The difference is that this cache is specifically for canvases that are attached to the DOM. These canvases have font resolution logic that depends on the style of the canvas element. Therefore, the cache has to be element-specific rather than global to the document. BUG=497864 Review URL: https://codereview.chromium.org/1234503007 git-svn-id: svn://svn.chromium.org/blink/trunk@199230 bbb929c8-8fbe-4397-9dbb-9b2b20218538
-rw-r--r--third_party/WebKit/LayoutTests/fast/canvas/canvas-set-font-with-updated-style.html6
-rw-r--r--third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp6
-rw-r--r--third_party/WebKit/Source/core/html/HTMLCanvasElement.h2
-rw-r--r--third_party/WebKit/Source/core/html/canvas/CanvasFontCache.cpp1
-rw-r--r--third_party/WebKit/Source/core/html/canvas/CanvasFontCache.h4
-rw-r--r--third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h1
-rw-r--r--third_party/WebKit/Source/core/layout/LayoutHTMLCanvas.cpp6
-rw-r--r--third_party/WebKit/Source/core/layout/LayoutHTMLCanvas.h2
-rw-r--r--third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp92
-rw-r--r--third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h16
10 files changed, 118 insertions, 18 deletions
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-set-font-with-updated-style.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-set-font-with-updated-style.html
index a6b90fa..9290f32 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-set-font-with-updated-style.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-set-font-with-updated-style.html
@@ -13,6 +13,12 @@ function drawCanvasText(id, text)
{
var canvasElement = document.getElementById(id);
var context = canvasElement.getContext('2d');
+
+ // Pre-draw pass to add the font to the font cache. This way, the test also
+ // verifies that the style change correctly invalidates the font resolution cache.
+ context.font = '1em Calibri';
+ context.fillText(text, 0, 100);
+
canvasElement.style.fontSize = '64px';
context.font = '1em Calibri';
context.fillText(text, 0, 100);
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
index a6b3d95..65fcdde 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -826,6 +826,12 @@ void HTMLCanvasElement::didChangeVisibilityState(PageVisibilityState visibility)
}
}
+void HTMLCanvasElement::styleDidChange(const ComputedStyle* oldStyle, const ComputedStyle& newStyle)
+{
+ if (m_context)
+ m_context->styleDidChange(oldStyle, newStyle);
+}
+
void HTMLCanvasElement::didMoveToNewDocument(Document& oldDocument)
{
setObservedDocument(document());
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
index 73f6514..a3c45af 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
@@ -174,6 +174,8 @@ public:
static void registerRenderingContextFactory(PassOwnPtr<CanvasRenderingContextFactory>);
void updateExternallyAllocatedMemory() const;
+ void styleDidChange(const ComputedStyle* oldStyle, const ComputedStyle& newStyle);
+
protected:
void didMoveToNewDocument(Document& oldDocument) override;
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasFontCache.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasFontCache.cpp
index 9a4723a..2673c33 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasFontCache.cpp
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasFontCache.cpp
@@ -150,6 +150,7 @@ void CanvasFontCache::pruneAll()
{
m_fetchedFonts.clear();
m_fontLRUList.clear();
+ m_fontsResolvedUsingDefaultStyle.clear();
}
DEFINE_TRACE(CanvasFontCache)
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasFontCache.h b/third_party/WebKit/Source/core/html/canvas/CanvasFontCache.h
index 3ec90e9..9f32ce2 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasFontCache.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasFontCache.h
@@ -39,8 +39,8 @@ public:
bool getFontUsingDefaultStyle(const String&, Font&);
// TaskObserver implementation
- virtual void didProcessTask();
- virtual void willProcessTask() { }
+ void didProcessTask() override;
+ void willProcessTask() override { }
// For testing
bool isInCache(const String&);
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
index 3b77017..5ccb28c 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
@@ -106,6 +106,7 @@ public:
virtual void setShouldAntialias(bool) { }
virtual unsigned hitRegionsCount() const { return 0; }
virtual void setFont(const String&) { }
+ virtual void styleDidChange(const ComputedStyle* oldStyle, const ComputedStyle& newStyle) { }
// WebGL-specific interface
virtual bool is3d() const { return false; }
diff --git a/third_party/WebKit/Source/core/layout/LayoutHTMLCanvas.cpp b/third_party/WebKit/Source/core/layout/LayoutHTMLCanvas.cpp
index 519a946..284e683 100644
--- a/third_party/WebKit/Source/core/layout/LayoutHTMLCanvas.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutHTMLCanvas.cpp
@@ -98,4 +98,10 @@ CompositingReasons LayoutHTMLCanvas::additionalCompositingReasons() const
return CompositingReasonNone;
}
+void LayoutHTMLCanvas::styleDidChange(StyleDifference diff, const ComputedStyle* oldStyle)
+{
+ LayoutReplaced::styleDidChange(diff, oldStyle);
+ toHTMLCanvasElement(node())->styleDidChange(oldStyle, styleRef());
+}
+
} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutHTMLCanvas.h b/third_party/WebKit/Source/core/layout/LayoutHTMLCanvas.h
index 0517bf9..2b21d23 100644
--- a/third_party/WebKit/Source/core/layout/LayoutHTMLCanvas.h
+++ b/third_party/WebKit/Source/core/layout/LayoutHTMLCanvas.h
@@ -42,6 +42,8 @@ public:
void canvasSizeChanged();
+ void styleDidChange(StyleDifference, const ComputedStyle* oldStyle) override;
+
const char* name() const override { return "LayoutHTMLCanvas"; }
private:
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
index 57b5b39..a778072 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
@@ -66,6 +66,7 @@
#include "platform/graphics/StrokeData.h"
#include "platform/graphics/skia/SkiaUtils.h"
#include "platform/text/BidiTextRun.h"
+#include "public/platform/Platform.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkImageFilter.h"
#include "wtf/ArrayBufferContents.h"
@@ -127,6 +128,7 @@ CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, co
, m_dispatchContextLostEventTimer(this, &CanvasRenderingContext2D::dispatchContextLostEvent)
, m_dispatchContextRestoredEventTimer(this, &CanvasRenderingContext2D::dispatchContextRestoredEvent)
, m_tryRestoreContextEventTimer(this, &CanvasRenderingContext2D::tryRestoreContextEvent)
+ , m_pruneLocalFontCacheScheduled(false)
{
if (document.settings() && document.settings()->antialiasedClips2dCanvasEnabled())
m_clipAntialiasing = AntiAliased;
@@ -146,6 +148,9 @@ void CanvasRenderingContext2D::unwindStateStack()
CanvasRenderingContext2D::~CanvasRenderingContext2D()
{
+ if (m_pruneLocalFontCacheScheduled) {
+ Platform::current()->currentThread()->removeTaskObserver(this);
+ }
}
void CanvasRenderingContext2D::validateStateStack()
@@ -1703,32 +1708,50 @@ String CanvasRenderingContext2D::font() const
void CanvasRenderingContext2D::setFont(const String& newFont)
{
- if (newFont == state().unparsedFont() && state().hasRealizedFont())
- return;
-
// The style resolution required for rendering text is not available in frame-less documents.
if (!canvas()->document().frame())
return;
+ canvas()->document().updateLayoutTreeForNodeIfNeeded(canvas());
+
+ // The following early exit is dependent on the cache not being empty
+ // because an empty cache may indicate that a style change has occured
+ // which would require that the font be re-resolved. This check has to
+ // come after the layout tree update to flush pending style changes.
+ if (newFont == state().unparsedFont() && state().hasRealizedFont() && m_fontsResolvedUsingCurrentStyle.size() > 0)
+ return;
+
CanvasFontCache* canvasFontCache = canvas()->document().canvasFontCache();
// Map the <canvas> font into the text style. If the font uses keywords like larger/smaller, these will work
// relative to the canvas.
RefPtr<ComputedStyle> fontStyle;
- canvas()->document().updateLayoutTreeForNodeIfNeeded(canvas());
const ComputedStyle* computedStyle = canvas()->ensureComputedStyle();
if (computedStyle) {
- MutableStylePropertySet* parsedStyle = canvasFontCache->parseFont(newFont);
- if (!parsedStyle)
- return;
- fontStyle = ComputedStyle::create();
- FontDescription elementFontDescription(computedStyle->fontDescription());
- // Reset the computed size to avoid inheriting the zoom factor from the <canvas> element.
- elementFontDescription.setComputedSize(elementFontDescription.specifiedSize());
- fontStyle->setFontDescription(elementFontDescription);
- fontStyle->font().update(fontStyle->font().fontSelector());
- canvas()->document().ensureStyleResolver().computeFont(fontStyle.get(), *parsedStyle);
- modifiableState().setFont(fontStyle->font(), canvas()->document().styleEngine().fontSelector());
+ HashMap<String, Font>::iterator i = m_fontsResolvedUsingCurrentStyle.find(newFont);
+ if (i != m_fontsResolvedUsingCurrentStyle.end()) {
+ ASSERT(m_fontLRUList.contains(newFont));
+ m_fontLRUList.remove(newFont);
+ m_fontLRUList.add(newFont);
+ modifiableState().setFont(i->value, canvas()->document().styleEngine().fontSelector());
+ } else {
+ MutableStylePropertySet* parsedStyle = canvasFontCache->parseFont(newFont);
+ if (!parsedStyle)
+ return;
+ fontStyle = ComputedStyle::create();
+ FontDescription elementFontDescription(computedStyle->fontDescription());
+ // Reset the computed size to avoid inheriting the zoom factor from the <canvas> element.
+ elementFontDescription.setComputedSize(elementFontDescription.specifiedSize());
+ fontStyle->setFontDescription(elementFontDescription);
+ fontStyle->font().update(fontStyle->font().fontSelector());
+ canvas()->document().ensureStyleResolver().computeFont(fontStyle.get(), *parsedStyle);
+ m_fontsResolvedUsingCurrentStyle.add(newFont, fontStyle->font());
+ ASSERT(!m_fontLRUList.contains(newFont));
+ m_fontLRUList.add(newFont);
+ pruneLocalFontCache(canvasFontCache->hardMaxFonts()); // hard limit
+ schedulePruneLocalFontCacheIfNeeded(); // soft limit
+ modifiableState().setFont(fontStyle->font(), canvas()->document().styleEngine().fontSelector());
+ }
} else {
Font resolvedFont;
if (!canvasFontCache->getFontUsingDefaultStyle(newFont, resolvedFont))
@@ -1741,6 +1764,42 @@ void CanvasRenderingContext2D::setFont(const String& newFont)
modifiableState().setUnparsedFont(newFontSafeCopy);
}
+void CanvasRenderingContext2D::schedulePruneLocalFontCacheIfNeeded()
+{
+ if (m_pruneLocalFontCacheScheduled)
+ return;
+ m_pruneLocalFontCacheScheduled = true;
+ Platform::current()->currentThread()->addTaskObserver(this);
+}
+
+void CanvasRenderingContext2D::didProcessTask()
+{
+ pruneLocalFontCache(canvas()->document().canvasFontCache()->maxFonts());
+ m_pruneLocalFontCacheScheduled = false;
+ Platform::current()->currentThread()->removeTaskObserver(this);
+}
+
+void CanvasRenderingContext2D::pruneLocalFontCache(size_t targetSize)
+{
+ if (targetSize == 0) {
+ // Short cut: LRU does not matter when evicting everything
+ m_fontLRUList.clear();
+ m_fontsResolvedUsingCurrentStyle.clear();
+ return;
+ }
+ while (m_fontLRUList.size() > targetSize) {
+ m_fontsResolvedUsingCurrentStyle.remove(m_fontLRUList.first());
+ m_fontLRUList.removeFirst();
+ }
+}
+
+void CanvasRenderingContext2D::styleDidChange(const ComputedStyle* oldStyle, const ComputedStyle& newStyle)
+{
+ if (oldStyle && oldStyle->font() == newStyle.font())
+ return;
+ pruneLocalFontCache(0);
+}
+
String CanvasRenderingContext2D::textAlign() const
{
return textAlignName(state().textAlign());
@@ -2013,6 +2072,9 @@ void CanvasRenderingContext2D::setIsHidden(bool hidden)
{
if (canvas()->hasImageBuffer())
canvas()->buffer()->setIsHidden(hidden);
+ if (hidden) {
+ pruneLocalFontCache(0);
+ }
}
bool CanvasRenderingContext2D::isTransformInvertible() const
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h
index 9598217..43b83e4 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h
@@ -36,6 +36,7 @@
#include "modules/canvas2d/CanvasPathMethods.h"
#include "modules/canvas2d/CanvasRenderingContext2DState.h"
#include "platform/graphics/GraphicsTypes.h"
+#include "public/platform/WebThread.h"
#include "wtf/Vector.h"
#include "wtf/text/WTFString.h"
@@ -60,7 +61,7 @@ class TextMetrics;
typedef HTMLImageElementOrHTMLVideoElementOrHTMLCanvasElementOrImageBitmap CanvasImageSourceUnion;
-class MODULES_EXPORT CanvasRenderingContext2D final : public CanvasRenderingContext, public CanvasPathMethods {
+class MODULES_EXPORT CanvasRenderingContext2D final : public CanvasRenderingContext, public CanvasPathMethods, public WebThread::TaskObserver {
DEFINE_WRAPPERTYPEINFO();
public:
class Factory : public CanvasRenderingContextFactory {
@@ -217,6 +218,12 @@ public:
void restoreCanvasMatrixClipStack() override;
+ // TaskObserver implementation
+ void didProcessTask() override;
+ void willProcessTask() override { }
+
+ void styleDidChange(const ComputedStyle* oldStyle, const ComputedStyle& newStyle) override;
+
private:
friend class CanvasRenderingContext2DAutoRestoreSkCanvas;
@@ -240,6 +247,9 @@ private:
void unwindStateStack();
void realizeSaves();
+ void pruneLocalFontCache(size_t targetSize);
+ void schedulePruneLocalFontCacheIfNeeded();
+
bool shouldDrawImageAntialiased(const FloatRect& destRect) const;
template<typename DrawFunc, typename ContainsFunc>
@@ -302,6 +312,10 @@ private:
Timer<CanvasRenderingContext2D> m_dispatchContextLostEventTimer;
Timer<CanvasRenderingContext2D> m_dispatchContextRestoredEventTimer;
Timer<CanvasRenderingContext2D> m_tryRestoreContextEventTimer;
+
+ HashMap<String, Font> m_fontsResolvedUsingCurrentStyle;
+ bool m_pruneLocalFontCacheScheduled;
+ ListHashSet<String> m_fontLRUList;
};
DEFINE_TYPE_CASTS(CanvasRenderingContext2D, CanvasRenderingContext, context, context->is2d(), context.is2d());