Commit a2dd0645 authored by David Schnur's avatar David Schnur

Break text styles into their own cache tier.

Previously the cache was divided only by layer, with entries keyed on a
string built from the text and style.  Now the style has its own tier in
the cache, i.e. layers > styles > text > info.

This introduces some complexity, since the nested for loops are ugly,
but at the same time we avoid having to create the cache-key strings.
More importantly it solves the problem of uniqueness that exists when we
try to join strings that may contain arbitrary text.  It also allows a
further optimization in the canvas plugin, which can now set text style
and color just once per distinct style, instead of with every string.
parent 77e50b17
...@@ -61,16 +61,18 @@ browser, but needs to redraw with canvas text when exporting as an image. ...@@ -61,16 +61,18 @@ browser, but needs to redraw with canvas text when exporting as an image.
for (var layerKey in cache) { for (var layerKey in cache) {
if (hasOwnProperty.call(cache, layerKey)) { if (hasOwnProperty.call(cache, layerKey)) {
var layerCache = cache[layerKey]; var layerCache = cache[layerKey];
for (var styleKey in layerCache) {
if (hasOwnProperty.call(layerCache, styleKey)) {
var styleCache = layerCache[styleKey],
updateStyles = true;
for (var key in styleCache) {
if (hasOwnProperty.call(styleCache, key)) {
for (var key in layerCache) { var info = styleCache[key];
if (hasOwnProperty.call(layerCache, key)) {
var info = layerCache[key];
if (!info.active) { if (!info.active) {
delete cache[key]; delete styleCache[key];
continue; continue;
} }
...@@ -79,8 +81,15 @@ browser, but needs to redraw with canvas text when exporting as an image. ...@@ -79,8 +81,15 @@ browser, but needs to redraw with canvas text when exporting as an image.
lines = info.lines, lines = info.lines,
halign = info.halign; halign = info.halign;
// Since every element at this level of the cache have the
// same font and fill styles, we can just change them once
// using the values from the first element.
if (updateStyles) {
context.fillStyle = info.font.color; context.fillStyle = info.font.color;
context.font = info.font.definition; context.font = info.font.definition;
updateStyles = false;
}
// TODO: Comments in Ole's implementation indicate that // TODO: Comments in Ole's implementation indicate that
// some browsers differ in their interpretation of 'top'; // some browsers differ in their interpretation of 'top';
...@@ -129,6 +138,8 @@ browser, but needs to redraw with canvas text when exporting as an image. ...@@ -129,6 +138,8 @@ browser, but needs to redraw with canvas text when exporting as an image.
} }
} }
} }
}
}
context.restore(); context.restore();
}; };
...@@ -160,7 +171,7 @@ browser, but needs to redraw with canvas text when exporting as an image. ...@@ -160,7 +171,7 @@ browser, but needs to redraw with canvas text when exporting as an image.
return getTextInfo.call(this, layer, text, font, angle); return getTextInfo.call(this, layer, text, font, angle);
} }
var textStyle, cache, cacheKey, info; var textStyle, layerCache, styleCache, info;
// Cast the value to a string, in case we were given a number // Cast the value to a string, in case we were given a number
...@@ -174,21 +185,21 @@ browser, but needs to redraw with canvas text when exporting as an image. ...@@ -174,21 +185,21 @@ browser, but needs to redraw with canvas text when exporting as an image.
textStyle = font; textStyle = font;
} }
// Retrieve (or create) the cache for the text's layer // Retrieve (or create) the cache for the text's layer and styles
cache = this._textCache[layer]; layerCache = this._textCache[layer];
if (cache == null) { if (layerCache == null) {
cache = this._textCache[layer] = {}; layerCache = this._textCache[layer] = {};
} }
// The text + style + angle uniquely identify the text's dimensions styleCache = layerCache[textStyle];
// and content; we'll use them to build the entry's text cache key.
// NOTE: We don't support rotated text yet, so the angle is unused.
cacheKey = textStyle + "|" + text; if (styleCache == null) {
styleCache = layerCache[textStyle] = {};
}
info = cache[cacheKey]; info = styleCache[text];
if (info == null) { if (info == null) {
...@@ -224,7 +235,7 @@ browser, but needs to redraw with canvas text when exporting as an image. ...@@ -224,7 +235,7 @@ browser, but needs to redraw with canvas text when exporting as an image.
// Create a new info object, initializing the dimensions to // Create a new info object, initializing the dimensions to
// zero so we can count them up line-by-line. // zero so we can count them up line-by-line.
info = cache[cacheKey] = { info = styleCache[text] = {
x: null, x: null,
y: null, y: null,
width: 0, width: 0,
......
...@@ -180,24 +180,27 @@ Licensed under the MIT license. ...@@ -180,24 +180,27 @@ Licensed under the MIT license.
layer.hide(); layer.hide();
for (var key in layerCache) { for (var styleKey in layerCache) {
if (hasOwnProperty.call(layerCache, key)) { if (hasOwnProperty.call(layerCache, styleKey)) {
var styleCache = layerCache[styleKey];
var info = layerCache[key]; for (var key in styleCache) {
if (hasOwnProperty.call(styleCache, key)) {
var info = styleCache[key];
if (info.active) { if (info.active) {
if (!info.rendered) { if (!info.rendered) {
layer.append(info.element); layer.append(info.element);
info.rendered = true; info.rendered = true;
} }
} else { } else {
delete layerCache[key]; delete styleCache[key];
if (info.rendered) { if (info.rendered) {
info.element.detach(); info.element.detach();
} }
} }
} }
} }
}
}
layer.show(); layer.show();
} }
...@@ -258,7 +261,7 @@ Licensed under the MIT license. ...@@ -258,7 +261,7 @@ Licensed under the MIT license.
Canvas.prototype.getTextInfo = function(layer, text, font, angle) { Canvas.prototype.getTextInfo = function(layer, text, font, angle) {
var textStyle, cache, cacheKey, info; var textStyle, layerCache, styleCache, info;
// Cast the value to a string, in case we were given a number or such // Cast the value to a string, in case we were given a number or such
...@@ -272,21 +275,21 @@ Licensed under the MIT license. ...@@ -272,21 +275,21 @@ Licensed under the MIT license.
textStyle = font; textStyle = font;
} }
// Retrieve (or create) the cache for the text's layer // Retrieve (or create) the cache for the text's layer and styles
cache = this._textCache[layer]; layerCache = this._textCache[layer];
if (cache == null) { if (layerCache == null) {
cache = this._textCache[layer] = {}; layerCache = this._textCache[layer] = {};
} }
// The text + style + angle uniquely identify the text's dimensions and styleCache = layerCache[textStyle];
// content; we'll use them to build this entry's text cache key.
// NOTE: We don't support rotated text yet, so the angle is unused.
cacheKey = textStyle + "|" + text; if (styleCache == null) {
styleCache = layerCache[textStyle] = {};
}
info = cache[cacheKey]; info = styleCache[text];
// If we can't find a matching element in our cache, create a new one // If we can't find a matching element in our cache, create a new one
...@@ -308,7 +311,7 @@ Licensed under the MIT license. ...@@ -308,7 +311,7 @@ Licensed under the MIT license.
element.addClass(font); element.addClass(font);
} }
info = cache[cacheKey] = { info = styleCache[text] = {
active: false, active: false,
rendered: false, rendered: false,
element: element, element: element,
...@@ -387,11 +390,16 @@ Licensed under the MIT license. ...@@ -387,11 +390,16 @@ Licensed under the MIT license.
Canvas.prototype.removeText = function(layer, text, font, angle) { Canvas.prototype.removeText = function(layer, text, font, angle) {
if (text == null) { if (text == null) {
var cache = this._textCache[layer]; var layerCache = this._textCache[layer];
if (cache != null) { if (layerCache != null) {
for (var key in cache) { for (var styleKey in layerCache) {
if (hasOwnProperty.call(cache, key)) { if (hasOwnProperty.call(layerCache, styleKey)) {
cache[key].active = false; var styleCache = layerCache[styleKey]
for (var key in styleCache) {
if (hasOwnProperty.call(styleCache, key)) {
styleCache[key].active = false;
}
}
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment