mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-07-08 10:44:30 -04:00
Add support for direct drawing of native blendModes for items that allow it.
Bypassing compositing into separate canvases completely.
This commit is contained in:
parent
ad6124cf98
commit
75acdf1025
3 changed files with 41 additions and 28 deletions
src
|
@ -64,7 +64,8 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
||||||
// describe the support of various features.
|
// describe the support of various features.
|
||||||
var ctx = CanvasProvider.getContext(1, 1);
|
var ctx = CanvasProvider.getContext(1, 1);
|
||||||
PaperScope.prototype.support = {
|
PaperScope.prototype.support = {
|
||||||
dash: 'setLineDash' in ctx || 'mozDash' in ctx
|
nativeDash: 'setLineDash' in ctx || 'mozDash' in ctx,
|
||||||
|
nativeBlend: BlendMode.nativeModes
|
||||||
};
|
};
|
||||||
CanvasProvider.release(ctx);
|
CanvasProvider.release(ctx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2848,7 +2848,7 @@ var Item = Base.extend(Callback, /** @lends Item# */{
|
||||||
ctx.fillStyle = fillColor.toCanvasStyle(ctx);
|
ctx.fillStyle = fillColor.toCanvasStyle(ctx);
|
||||||
if (strokeColor) {
|
if (strokeColor) {
|
||||||
ctx.strokeStyle = strokeColor.toCanvasStyle(ctx);
|
ctx.strokeStyle = strokeColor.toCanvasStyle(ctx);
|
||||||
if (paper.support.dash && dashArray && dashArray.length) {
|
if (paper.support.nativeDash && dashArray && dashArray.length) {
|
||||||
if ('setLineDash' in ctx) {
|
if ('setLineDash' in ctx) {
|
||||||
ctx.setLineDash(dashArray);
|
ctx.setLineDash(dashArray);
|
||||||
ctx.lineDashOffset = dashOffset;
|
ctx.lineDashOffset = dashOffset;
|
||||||
|
@ -2858,11 +2858,6 @@ var Item = Base.extend(Callback, /** @lends Item# */{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 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;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO: Implement View into the drawing.
|
// TODO: Implement View into the drawing.
|
||||||
|
@ -2891,51 +2886,68 @@ var Item = Base.extend(Callback, /** @lends Item# */{
|
||||||
// Exclude Raster items since they never draw a stroke and handle
|
// Exclude Raster items since they never draw a stroke and handle
|
||||||
// opacity by themselves (they also don't call _setStyles)
|
// opacity by themselves (they also don't call _setStyles)
|
||||||
var blendMode = this._blendMode,
|
var blendMode = this._blendMode,
|
||||||
parentCtx, itemOffset, prevOffset;
|
opacity = this._opacity,
|
||||||
if (blendMode !== 'normal' || this._opacity < 1
|
type = this._type,
|
||||||
&& this._type !== 'raster' && (this._type !== 'path'
|
nativeBlend = BlendMode.nativeModes[blendMode],
|
||||||
|| this.hasFill() && this.hasStroke())) {
|
// Determine if we can draw directly, or if we need to draw into a
|
||||||
|
// separate canvas and then composite onto the main canvas.
|
||||||
|
direct = blendMode === 'normal' && opacity === 1
|
||||||
|
// If blending natively is possible, see if the type of item
|
||||||
|
// and its color settings allow it. A path with only a fill
|
||||||
|
// or a stroke can be directly blended, but if it has both,
|
||||||
|
// it needs to be drawn into a separate canvas first.
|
||||||
|
|| (nativeBlend || opacity < 1) && (type === 'raster'
|
||||||
|
|| (type === 'path' || type === 'compound-path')
|
||||||
|
&& !(this.hasFill() && this.hasStroke())),
|
||||||
|
mainCtx, itemOffset, prevOffset;
|
||||||
|
if (!direct) {
|
||||||
// Apply the paren't global matrix to the calculation of correct
|
// Apply the paren't global matrix to the calculation of correct
|
||||||
// bounds.
|
// bounds.
|
||||||
var bounds = this.getStrokeBounds(parentMatrix);
|
var bounds = this.getStrokeBounds(parentMatrix);
|
||||||
if (!bounds.width || !bounds.height)
|
if (!bounds.width || !bounds.height)
|
||||||
return;
|
return;
|
||||||
// Store previous offset and save the parent context, so we can
|
// Store previous offset and save the main context, so we can
|
||||||
// draw onto it later
|
// draw onto it later.
|
||||||
prevOffset = param.offset;
|
prevOffset = param.offset;
|
||||||
// Floor the offset and ceil the size, so we don't cut off any
|
// Floor the offset and ceil the size, so we don't cut off any
|
||||||
// antialiased pixels when drawing onto the temporary canvas.
|
// antialiased pixels when drawing onto the temporary canvas.
|
||||||
itemOffset = param.offset = bounds.getTopLeft().floor();
|
itemOffset = param.offset = bounds.getTopLeft().floor();
|
||||||
// Set ctx to the context of the temporary canvas,
|
// Set ctx to the context of the temporary canvas, so we draw onto
|
||||||
// so we draw onto it, instead of the parentCtx
|
// it, instead of the mainCtx.
|
||||||
parentCtx = ctx;
|
mainCtx = ctx;
|
||||||
ctx = CanvasProvider.getContext(
|
ctx = CanvasProvider.getContext(
|
||||||
bounds.getSize().ceil().add(new Size(1, 1)));
|
bounds.getSize().ceil().add(new Size(1, 1)));
|
||||||
}
|
}
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
// If drawing directly, handle opacity and native blending now,
|
||||||
|
// otherwise we will do it later when the temporary canvas is composited.
|
||||||
|
if (direct) {
|
||||||
|
ctx.globalAlpha = opacity;
|
||||||
|
if (nativeBlend)
|
||||||
|
ctx.globalCompositeOperation = blendMode;
|
||||||
|
} else {
|
||||||
// Translate the context so the topLeft of the item is at (0, 0)
|
// Translate the context so the topLeft of the item is at (0, 0)
|
||||||
// on the temporary canvas.
|
// on the temporary canvas.
|
||||||
if (parentCtx)
|
|
||||||
ctx.translate(-itemOffset.x, -itemOffset.y);
|
ctx.translate(-itemOffset.x, -itemOffset.y);
|
||||||
// Apply globalMatrix when blitting into temporary canvas.
|
}
|
||||||
(parentCtx ? globalMatrix : this._matrix).applyToContext(ctx);
|
// Apply globalMatrix when drawing into temporary canvas.
|
||||||
|
(direct ? this._matrix : globalMatrix).applyToContext(ctx);
|
||||||
// If we're drawing into a separate canvas and a clipItem is defined for
|
// If we're drawing into a separate canvas and a clipItem is defined for
|
||||||
// the current rendering loop, we need to draw the clip item again.
|
// the current rendering loop, we need to draw the clip item again.
|
||||||
if (parentCtx && param.clipItem)
|
if (!direct && param.clipItem)
|
||||||
param.clipItem.draw(ctx, param.extend({ clip: true }));
|
param.clipItem.draw(ctx, param.extend({ clip: true }));
|
||||||
this._draw(ctx, param);
|
this._draw(ctx, param);
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
transforms.pop();
|
transforms.pop();
|
||||||
if (param.clip)
|
if (param.clip)
|
||||||
ctx.clip();
|
ctx.clip();
|
||||||
// If a temporary canvas was created before, composite it onto the
|
// If a temporary canvas was created, composite it onto the main canvas:
|
||||||
// parent canvas:
|
if (!direct) {
|
||||||
if (parentCtx) {
|
|
||||||
// Use BlendMode.process even for processing normal blendMode with
|
// Use BlendMode.process even for processing normal blendMode with
|
||||||
// opacity.
|
// opacity.
|
||||||
BlendMode.process(blendMode, ctx, parentCtx, this._opacity,
|
BlendMode.process(blendMode, ctx, mainCtx, opacity,
|
||||||
// Calculate the pixel offset of the temporary canvas to the
|
// Calculate the pixel offset of the temporary canvas to the
|
||||||
// parent canvas.
|
// main canvas.
|
||||||
itemOffset.subtract(prevOffset));
|
itemOffset.subtract(prevOffset));
|
||||||
// Return the temporary context, so it can be reused
|
// Return the temporary context, so it can be reused
|
||||||
CanvasProvider.release(ctx);
|
CanvasProvider.release(ctx);
|
||||||
|
|
|
@ -1912,7 +1912,7 @@ var Path = PathItem.extend(/** @lends Path# */{
|
||||||
fillColor = style.getFillColor(),
|
fillColor = style.getFillColor(),
|
||||||
strokeColor = style.getStrokeColor(),
|
strokeColor = style.getStrokeColor(),
|
||||||
dashArray = style.getDashArray(),
|
dashArray = style.getDashArray(),
|
||||||
drawDash = !paper.support.dash && strokeColor
|
drawDash = !paper.support.nativeDash && strokeColor
|
||||||
&& dashArray && dashArray.length;
|
&& dashArray && dashArray.length;
|
||||||
|
|
||||||
// Prepare the canvas path if we have any situation that requires it
|
// Prepare the canvas path if we have any situation that requires it
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue