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.
for (var layerKey in cache) {
if (hasOwnProperty.call(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) {
if (hasOwnProperty.call(layerCache, key)) {
var info = layerCache[key];
var info = styleCache[key];
if (!info.active) {
delete cache[key];
delete styleCache[key];
continue;
}
......@@ -79,8 +81,15 @@ browser, but needs to redraw with canvas text when exporting as an image.
lines = info.lines,
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.font = info.font.definition;
updateStyles = false;
}
// TODO: Comments in Ole's implementation indicate that
// 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.
}
}
}
}
}
context.restore();
};
......@@ -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);
}
var textStyle, cache, cacheKey, info;
var textStyle, layerCache, styleCache, info;
// 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.
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) {
cache = this._textCache[layer] = {};
if (layerCache == null) {
layerCache = this._textCache[layer] = {};
}
// The text + style + angle uniquely identify the text's dimensions
// 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.
styleCache = layerCache[textStyle];
cacheKey = textStyle + "|" + text;
if (styleCache == null) {
styleCache = layerCache[textStyle] = {};
}
info = cache[cacheKey];
info = styleCache[text];
if (info == null) {
......@@ -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
// zero so we can count them up line-by-line.
info = cache[cacheKey] = {
info = styleCache[text] = {
x: null,
y: null,
width: 0,
......
......@@ -180,24 +180,27 @@ Licensed under the MIT license.
layer.hide();
for (var key in layerCache) {
if (hasOwnProperty.call(layerCache, key)) {
var info = layerCache[key];
for (var styleKey in layerCache) {
if (hasOwnProperty.call(layerCache, styleKey)) {
var styleCache = layerCache[styleKey];
for (var key in styleCache) {
if (hasOwnProperty.call(styleCache, key)) {
var info = styleCache[key];
if (info.active) {
if (!info.rendered) {
layer.append(info.element);
info.rendered = true;
}
} else {
delete layerCache[key];
delete styleCache[key];
if (info.rendered) {
info.element.detach();
}
}
}
}
}
}
layer.show();
}
......@@ -258,7 +261,7 @@ Licensed under the MIT license.
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
......@@ -272,21 +275,21 @@ Licensed under the MIT license.
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) {
cache = this._textCache[layer] = {};
if (layerCache == null) {
layerCache = this._textCache[layer] = {};
}
// The text + style + angle uniquely identify the text's dimensions and
// 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.
styleCache = layerCache[textStyle];
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
......@@ -308,7 +311,7 @@ Licensed under the MIT license.
element.addClass(font);
}
info = cache[cacheKey] = {
info = styleCache[text] = {
active: false,
rendered: false,
element: element,
......@@ -387,11 +390,16 @@ Licensed under the MIT license.
Canvas.prototype.removeText = function(layer, text, font, angle) {
if (text == null) {
var cache = this._textCache[layer];
if (cache != null) {
for (var key in cache) {
if (hasOwnProperty.call(cache, key)) {
cache[key].active = false;
var layerCache = this._textCache[layer];
if (layerCache != null) {
for (var styleKey in layerCache) {
if (hasOwnProperty.call(layerCache, styleKey)) {
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