Add support for canvas compositing modes to Item#blendMode.

Closes .
This commit is contained in:
Jürg Lehni 2013-07-19 15:23:16 -07:00
parent 175091a69f
commit 94c192495a
2 changed files with 27 additions and 15 deletions
src

View file

@ -215,13 +215,23 @@ var BlendMode = new function() {
}
};
// Build a lookup table for natively supported CSS blend-modes. Just seeing
// if globalCompositeOperation is actually sticky is not enough, as Chome 27
// pretends for blend-modes to work, but does not actually apply them.
// Build a lookup table for natively supported CSS composite- & blend-modes.
// The canvas composite modes are always natively supported:
var nativeModes = this.nativeModes = Base.each([
'source-over', 'source-in', 'source-out', 'source-atop',
'destination-over', 'destination-in', 'destination-out',
'destination-atop', 'lighter', 'darker', 'copy', 'xor'
], function(mode) {
this[mode] = true;
}, {});
// Now test for the new blend modes. Just seeing if globalCompositeOperation
// is sticky is not enough, as Chome 27 pretends for blend-modes to work,
// but does not actually apply them.
var ctx = CanvasProvider.getContext(1, 1);
// Blend #330000 (51) and #aa0000 (170). Multiplying should lead to
// #220000 (34)
function testMode(mode) {
Base.each(modes, function(func, mode) {
// Blend #330000 (51) and #aa0000 (170):
// Multiplying should lead to #220000 (34)
ctx.save();
// For darken we need to reverse color parameters in order to test mode.
var darken = mode === 'darken',
@ -234,20 +244,16 @@ var BlendMode = new function() {
ctx.fillRect(0, 0, 1, 1);
ok = ctx.getImageData(0, 0, 1, 1).data[0] !== (darken ? 170 : 51);
}
nativeModes[mode] = ok;
ctx.restore();
return ok;
}
this.nativeModes = testMode('multiply') && Base.each(modes,
function(func, mode) {
this[mode] = testMode(mode);
}, {});
});
CanvasProvider.release(ctx);
this.process = function(mode, srcContext, dstContext, alpha, offset) {
var srcCanvas = srcContext.canvas,
normal = mode === 'normal';
// Use native blend-modes if supported, and fall back to emulation.
if (normal || this.nativeModes[mode]) {
if (normal || nativeModes[mode]) {
dstContext.save();
// Reset transformations, since we're blitting and pixel scale and
// with a given offset.

View file

@ -449,13 +449,19 @@ var Item = Base.extend(Callback, /** @lends Item# */{
_visible: true,
/**
* The blend mode of the item.
* The blend mode with which the item is composited onto the canvas. Both
* the standard canvas compositing modes, as well as the new CSS blend modes
* are supported. If blend-modes cannot be rendered natively, they are
* emulated. Be aware that emulation can have an impact on performance.
*
* @name Item#blendMode
* @type String('normal', 'multiply', 'screen', 'overlay', 'soft-light',
* 'hard-light', 'color-dodge', 'color-burn', 'darken', 'lighten',
* 'difference', 'exclusion', 'hue', 'saturation', 'luminosity', 'color',
* 'add', 'subtract', 'average', 'pin-light', 'negation')
* 'add', 'subtract', 'average', 'pin-light', 'negation', 'source-over',
* 'source-in', 'source-out', 'source-atop', 'destination-over',
* 'destination-in', 'destination-out', 'destination-atop', 'lighter',
* 'darker', 'copy', 'xor')
* @default 'normal'
*
* @example {@paperscript}