Optimise handling and setting of fill and stroke styles.

Handle setting of fillColor and strokeColor in Item#_setStyles() instead of the various #draw() methods, directly access internal styles instead of using accessor calls and fix PointText#draw().
This commit is contained in:
Jürg Lehni 2011-12-19 22:40:14 +01:00
parent ea0eaf04ea
commit cc26fdc5d1
4 changed files with 66 additions and 68 deletions

View file

@ -2373,15 +2373,28 @@ function(name) {
* e.g. PointText.
*/
_setStyles: function(ctx) {
// We can access internal properties since we're only using this on
// items without children, where styles would be merged.
var style = this._style,
width = style.getStrokeWidth(),
join = style.getStrokeJoin(),
cap = style.getStrokeCap(),
limit = style.getMiterLimit();
width = style._strokeWidth,
join = style._strokeJoin,
cap = style._strokeCap,
limit = style._miterLimit,
fillColor = style._fillColor,
strokeColor = style._strokeColor;
if (width != null) ctx.lineWidth = width;
if (join) ctx.lineJoin = join;
if (cap) ctx.lineCap = cap;
if (limit) ctx.miterLimit = limit;
// Always set fillStyle and strokeStyle, so the code calling
// #_setStyles() can check them to see if we need to stroke / fill.
ctx.fillStyle = fillColor ? fillColor.getCanvasStyle(ctx) : null;
ctx.strokeStyle = strokeColor ? strokeColor.getCanvasStyle(ctx) : null;
// If the item only defines a strokeColor or a fillColor, draw it
// directly with the globalAlpha set, otherwise we will do it later when
// we composite the temporary canvas.
if (!fillColor || !strokeColor)
ctx.globalAlpha = this._opacity;
},
statics: {
@ -2414,8 +2427,8 @@ function(name) {
// first, since otherwise their stroke is drawn half transparent
// over their fill.
if (item._blendMode !== 'normal' || item._opacity < 1
&& !(item._segments && (!item.getFillColor()
|| !item.getStrokeColor()))) {
&& !(item._segments
&& (!item.getFillColor() || !item.getStrokeColor()))) {
var bounds = item.getStrokeBounds();
if (!bounds.width || !bounds.height)
return;

View file

@ -85,27 +85,20 @@ var CompoundPath = this.CompoundPath = PathItem.extend(/** @lends CompoundPath#
},
draw: function(ctx, param) {
var l = this._children.length;
var children = this._children;
// Return early if the compound path doesn't have any children:
if (l == 0) {
if (children.length == 0)
return;
}
var firstChild = this._children[0];
var firstChild = children[0];
ctx.beginPath();
param.compound = true;
for (var i = 0; i < l; i++)
Item.draw(this._children[i], ctx, param);
for (var i = 0, l = children.length; i < l; i++)
Item.draw(children[i], ctx, param);
firstChild._setStyles(ctx);
var fillColor = firstChild.getFillColor(),
strokeColor = firstChild.getStrokeColor();
if (fillColor) {
ctx.fillStyle = fillColor.getCanvasStyle(ctx);
if (ctx.fillStyle)
ctx.fill();
}
if (strokeColor) {
ctx.strokeStyle = strokeColor.getCanvasStyle(ctx);
if (ctx.strokeStyle)
ctx.stroke();
}
param.compound = false;
}
}, new function() { // Injection scope for PostScript-like drawing functions

View file

@ -211,9 +211,11 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
for (var i = 0, l = this._segments.length; i < l; i++) {
this._segments[i]._transformCoordinates(matrix, coords, true);
}
// TODO: Can't we access _style._fillColor, as we do in strokeBounds?
var fillColor = this.getFillColor(),
strokeColor = this.getStrokeColor();
// See #draw() for an explanation of why we can access _style properties
// directly here:
var style = this._style,
fillColor = style._fillColor,
strokeColor = style._strokeColor;
// Try calling transform on colors in case they are GradientColors.
if (fillColor && fillColor.transform)
fillColor.transform(matrix);
@ -1232,10 +1234,12 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
},
_hitTest: function(point, options, matrix) {
// TODO: Can't we access _style._strokeColor, as we do in strokeBounds?
var tolerance = options.tolerance || 0,
radius = (options.stroke && this.getStrokeColor()
? this.getStrokeWidth() / 2 : 0) + tolerance,
// See #draw() for an explanation of why we can access _style properties
// directly here:
var style = this._style,
tolerance = options.tolerance || 0,
radius = (options.stroke && style._strokeColor
? style._strokeWidth / 2 : 0) + tolerance,
loc,
res;
// If we're asked to query for segments, ends or handles, do all that
@ -1272,7 +1276,7 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
// in some cases. Simply skip fill query if we already have a matching
// stroke.
if (!(loc && loc._distance <= radius) && options.fill
&& this.getFillColor() && this.contains(point, matrix))
&& style._fillColor && this.contains(point, matrix))
return new HitResult('fill', this);
// Now query stroke if we haven't already
if (!loc && options.stroke && radius > 0)
@ -1390,13 +1394,17 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
if (!param.compound)
ctx.beginPath();
// TODO: Can't we access _style._strokeColor, as we do in
// strokeBounds?
var fillColor = this.getFillColor(),
strokeColor = this.getStrokeColor(),
dashArray = this.getDashArray() || [], // TODO: Always defined?
hasDash = !!dashArray.length;
// We can access styles directly on the internal _styles object,
// since Path items do not have children, thus do not need style
// accessors for merged styles.
var style = this._style,
fillColor = style._fillColor,
strokeColor = style._strokeColor,
dashArray = style._dashArray,
hasDash = strokeColor && dashArray && dashArray.length;
// Prepare the canvas path if we have any situation that requires it
// to be defined.
if (param.compound || param.selection || this._clipMask || fillColor
|| strokeColor && !hasDash) {
drawSegments(ctx, this);
@ -1414,23 +1422,14 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
// or stroke, there is no need to continue.
ctx.save();
this._setStyles(ctx);
// If the path only defines a strokeColor or a fillColor,
// draw it directly with the globalAlpha set, otherwise
// we will do it later when we composite the temporary
// canvas.
if (!fillColor || !strokeColor)
ctx.globalAlpha = this._opacity;
if (fillColor) {
ctx.fillStyle = fillColor.getCanvasStyle(ctx);
if (fillColor)
ctx.fill();
}
if (strokeColor) {
ctx.strokeStyle = strokeColor.getCanvasStyle(ctx);
if (hasDash) {
// We cannot use the path created by drawSegments above
// Use CurveFlatteners to draw dashed paths:
ctx.beginPath();
drawDashes(ctx, this, dashArray, this.getDashOffset());
drawDashes(ctx, this, dashArray, style._dashOffset);
}
ctx.stroke();
}
@ -1894,18 +1893,20 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
* Returns the bounding rectangle of the item including stroke width.
*/
function getStrokeBounds(matrix) {
// TODO: Should we access this.getStrokeColor, as we do in _transform?
// See #draw() for an explanation of why we can access _style
// properties directly here:
var style = this._style;
// TODO: Find a way to reuse 'bounds' cache instead?
if (!this._style._strokeColor || !this._style._strokeWidth)
if (!style._strokeColor || !style._strokeWidth)
return getBounds.call(this, matrix);
var width = this.getStrokeWidth(),
var width = style._strokeWidth,
radius = width / 2,
padding = getPenPadding(radius, matrix),
join = this.getStrokeJoin(),
cap = this.getStrokeCap(),
join = style._strokeJoin,
cap = style._strokeCap,
// miter is relative to width. Divide it by 2 since we're
// measuring half the distance below
miter = this.getMiterLimit() * width / 2,
miter = style._miterLimit * width / 2,
segments = this._segments,
length = segments.length,
// It seems to be compatible with Ai we need to pass pen padding
@ -2032,10 +2033,11 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
// Delegate to handleBounds, but pass on radius values for stroke and
// joins. Hanlde miter joins specially, by passing the largets radius
// possible.
var width = this.getStrokeWidth();
var style = this._style,
width = style._strokeWidth;
return getHandleBounds.call(this, matrix, width,
this.getStrokeJoin() == 'miter'
? width * this.getMiterLimit()
style._strokeJoin == 'miter'
? width * style._miterLimit
: width);
}

View file

@ -71,28 +71,18 @@ var PointText = this.PointText = TextItem.extend(/** @lends PointText# */{
draw: function(ctx) {
if (!this._content)
return;
ctx.save();
this._setStyles(ctx);
ctx.font = this.getFontSize() + 'px ' + this.getFont();
ctx.textAlign = this.getJustification();
this._matrix.applyToContext(ctx);
var fillColor = this.getFillColor(),
strokeColor = this.getStrokeColor(),
leading = this.getLeading();
if (!fillColor || !strokeColor)
ctx.globalAlpha = this._opacity;
if (fillColor)
ctx.fillStyle = fillColor.getCanvasStyle(ctx);
if (strokeColor)
ctx.strokeStyle = strokeColor.getCanvasStyle(ctx);
var leading = this.getLeading();
for (var i = 0, l = this._lines.length; i < l; i++) {
var line = this._lines[i];
if (fillColor)
if (ctx.fillStyle)
ctx.fillText(line, 0, 0);
if (strokeColor)
if (ctx.strokeStyle)
ctx.strokeText(line, 0, 0);
ctx.translate(0, leading);
}
ctx.restore();
}
}, new function() {
var context = null;