diff --git a/src/color/Gradient.js b/src/color/Gradient.js index 639cdc3c..1231e961 100644 --- a/src/color/Gradient.js +++ b/src/color/Gradient.js @@ -19,8 +19,8 @@ var Gradient = this.Gradient = Base.extend({ beans: true, - // TODO: Should type here be called 'radial' and have it - // receive a boolean value? + // TODO: Should type here be called 'radial' and have it receive a + // boolean value? /** * Creates a gradient object * diff --git a/src/item/Item.js b/src/item/Item.js index 56124cb0..0654fe64 100644 --- a/src/item/Item.js +++ b/src/item/Item.js @@ -1051,8 +1051,8 @@ var Item = this.Item = Base.extend({ */ transform: function(matrix, flags) { // TODO: Handle flags, add TransformFlag class and convert to bit mask - // for quicker checking - // TODO: Call transform on chidren only if 'children' flag is provided + // for quicker checking. + // TODO: Call transform on chidren only if 'children' flag is provided. if (this._transform) this._transform(matrix, flags); // Transform position as well. Do not modify _position directly, @@ -1093,7 +1093,7 @@ var Item = this.Item = Base.extend({ } }, - // TODO: Implement View into the drawing + // TODO: Implement View into the drawing. // TODO: Optimize temporary canvas drawing to ignore parts that are // outside of the visible view. draw: function(item, ctx, param) { @@ -1249,8 +1249,6 @@ var Item = this.Item = Base.extend({ moveBelow: move(false) }; }, new function() { - //DOCS: document removeOn(param) - /** * {@grouptitle Remove On Event} * Removes the item when the next {@link Tool#onMouseMove} event is fired. diff --git a/src/item/Raster.js b/src/item/Raster.js index 51020109..bb8cc9f7 100644 --- a/src/item/Raster.js +++ b/src/item/Raster.js @@ -19,9 +19,9 @@ var Raster = this.Raster = Item.extend({ beans: true, - // TODO: implement url / type, width, height - // TODO: have PlacedSymbol & Raster inherit from a shared class? - // DOCS: document Raster constructor + // TODO: Implement url / type, width, height. + // TODO: Have PlacedSymbol & Raster inherit from a shared class? + // DOCS: Document Raster constructor. /** * Creates a new raster item and places it in the active layer. * @@ -163,12 +163,12 @@ var Raster = this.Raster = Item.extend({ return this._image || this.getCanvas(); }, - // TODO: support string id of image element + // TODO: Support string id of image element. setImage: function(image) { if (this._canvas) CanvasProvider.returnCanvas(this._canvas); this._image = image; - // TODO: cross browser compatible? + // TODO: Cross browser compatible? this._size = new Size(image.naturalWidth, image.naturalHeight); this._canvas = null; this._context = null; @@ -216,8 +216,8 @@ var Raster = this.Raster = Item.extend({ object = this.getBounds(); var bounds, path; if (object instanceof PathItem) { - // TODO: what if the path is smaller than 1 px? - // TODO: how about rounding of bounds.size? + // TODO: What if the path is smaller than 1 px? + // TODO: How about rounding of bounds.size? path = object; bounds = object.getBounds(); } else if (object.width) { diff --git a/src/path/CompoundPath.js b/src/path/CompoundPath.js index bca3b713..4b03128c 100644 --- a/src/path/CompoundPath.js +++ b/src/path/CompoundPath.js @@ -54,7 +54,7 @@ var CompoundPath = this.CompoundPath = PathItem.extend({ // clockwise orientation when creating a compound path, so that they // appear as holes, but only if their orientation was not already // specified before (= _clockwise is defined). - // TODO: This should really be handled in appendTop / Bottom, right? + // TODO: Should this be handled in appendTop / Bottom instead? if (path._clockwise === undefined) path.setClockwise(i < l - 1); this.appendTop(path); diff --git a/src/project/Project.js b/src/project/Project.js index 589451eb..89e4bffd 100644 --- a/src/project/Project.js +++ b/src/project/Project.js @@ -20,7 +20,7 @@ var Project = this.Project = Base.extend({ beans: true, // TODO: Add arguments to define pages - // DOCS: document Project constructor and class + // DOCS: Document Project constructor and class /** * Creates a Paper.js project * @@ -90,7 +90,7 @@ var Project = this.Project = Base.extend({ }, setCurrentStyle: function(style) { - // TODO: style selected items with the style: + // TODO: Style selected items with the style: this._currentStyle.initialize(style); }, @@ -129,9 +129,9 @@ var Project = this.Project = Base.extend({ * @bean */ getSelectedItems: function() { - // TODO: return groups if their children are all selected, + // TODO: Return groups if their children are all selected, // and filter out their children from the list. - // TODO: the order of these items should be that of their + // TODO: The order of these items should be that of their // drawing order. var items = []; Base.each(this._selectedItems, function(item) { @@ -140,7 +140,7 @@ var Project = this.Project = Base.extend({ return items; }, - // TODO: implement setSelectedItems? + // TODO: Implement setSelectedItems? _selectItem: function(item, select) { if (select) { diff --git a/src/project/Symbol.js b/src/project/Symbol.js index 5ed4f5a4..f35de100 100644 --- a/src/project/Symbol.js +++ b/src/project/Symbol.js @@ -57,7 +57,7 @@ var Symbol = this.Symbol = Base.extend({ }, // TODO: Symbol#remove() - // TODO: Size#name (accessible by name through project#symbols) + // TODO: Symbol#name (accessible by name through project#symbols) /** * The project that this symbol belongs to. diff --git a/src/text/PointText.js b/src/text/PointText.js index 535cb2e3..1f341f6e 100644 --- a/src/text/PointText.js +++ b/src/text/PointText.js @@ -69,8 +69,8 @@ var PointText = this.PointText = TextItem.extend({ Point.read(arguments).subtract(this._point))); }, - // TODO: position should be the center point of the bounds - // but we currently don't support bounds for PointText. + // TODO: Position should be the center point of the bounds but we currently + // don't support bounds for PointText. getPosition: function() { return this._point; }, diff --git a/src/tool/ToolEvent.js b/src/tool/ToolEvent.js index f49a5ec6..b3d76363 100644 --- a/src/tool/ToolEvent.js +++ b/src/tool/ToolEvent.js @@ -172,7 +172,7 @@ var ToolEvent = this.ToolEvent = Base.extend({ return Key.modifiers; }, - // TODO: implement hitTest first + // TODO: Implement hitTest first // getItem: function() { // if (this.item == null) { // var result = Project.getActiveProject().hitTest(this.getPoint()); diff --git a/src/ui/Key.js b/src/ui/Key.js index fa0a645b..019e7c61 100644 --- a/src/ui/Key.js +++ b/src/ui/Key.js @@ -19,7 +19,7 @@ * @name Key */ var Key = this.Key = new function() { - // TODO: make sure the keys are called the same as in Scriptographer + // TODO: Make sure the keys are called the same as in Scriptographer // Missing: tab, cancel, clear, page-down, page-up, comma, minus, period, // slash, etc etc etc. diff --git a/src/util/BlendMode.js b/src/util/BlendMode.js index 7d462103..b5fc7d11 100644 --- a/src/util/BlendMode.js +++ b/src/util/BlendMode.js @@ -39,133 +39,135 @@ */ var BlendMode = { - // TODO: Should we remove the blend modes that are not in Scriptographer? - // TODO: Add missing blendmodes like hue / saturation / color / luminosity - // TODO: Clean up codespacing of original code, or keep it as is, so - // we can easily encorporate changes? process: function(blendMode, sourceContext, destContext, opacity, offset) { var sourceCanvas = sourceContext.canvas, - dstD = destContext.getImageData(offset.x, offset.y, + dstData = destContext.getImageData(offset.x, offset.y, sourceCanvas.width, sourceCanvas.height), - srcD = sourceContext.getImageData(0, 0, - sourceCanvas.width, sourceCanvas.height), - src = srcD.data, - dst = dstD.data, - sA, dA, len = dst.length, - sRA, sGA, sBA, dRA, dGA, dBA, dA2, - demultiply, - min = Math.min; + dst = dstData.data, + src = sourceContext.getImageData(0, 0, + sourceCanvas.width, sourceCanvas.height).data, + min = Math.min, + max = Math.max, + sA, dA, rA, sM, dM, rM, sRA, sGA, sBA, dRA, dGA, dBA; - for (var i = 0; i < len; i += 4) { - sA = src[i + 3] / 255 * opacity; - dA = dst[i + 3] / 255; - dA2 = sA + dA - sA * dA; - dst[i + 3] = dA2 * 255; + // TODO: Some blend modes seem broken at the moment, e.g. dodge, burn + var modes = { + normal: function(i) { + var sA1 = 1 - sA; + dst[i] = (sRA + dRA * sA1) * rM; + dst[i + 1] = (sGA + dGA * sA1) * rM; + dst[i + 2] = (sBA + dRA * sA1) * rM; + }, - sRA = src[i] / 255 * sA; - dRA = dst[i] / 255 * dA; - sGA = src[i + 1] / 255 * sA; - dGA = dst[i + 1] / 255 * dA; - sBA = src[i + 2] / 255 * sA; - dBA = dst[i + 2] / 255 * dA; + multiply: function(i) { + var sA1 = 1 - sA, dA1 = 1 - dA; + dst[i] = (sRA * dRA + sRA * dA1 + dRA * sA1) * rM; + dst[i + 1] = (sGA * dGA + sGA * dA1 + dGA * sA1) * rM; + dst[i + 2] = (sBA * dBA + sBA * dA1 + dBA * sA1) * rM; + }, - demultiply = 255 / dA2; + screen: function(i) { + dst[i] = (sRA + dRA - sRA * dRA) * rM; + dst[i + 1] = (sGA + dGA - sGA * dGA) * rM; + dst[i + 2] = (sBA + dBA - sBA * dBA) * rM; + }, - // TODO: Some blend modes seem broken at the moment, e.g. - // dodge, burn - // TODO: This could be optimised by not diving everything by 255 and - // keeping it integer instead, with one divide at the end. - - switch (blendMode) { - // Very close match to Photoshop - case 'normal': - case 'src-over': - dst[i] = (sRA + dRA - dRA * sA) * demultiply; - dst[i + 1] = (sGA + dGA - dGA * sA) * demultiply; - dst[i + 2] = (sBA + dBA - dBA * sA) * demultiply; - break; - case 'screen': - dst[i] = (sRA + dRA - sRA * dRA) * demultiply; - dst[i + 1] = (sGA + dGA - sGA * dGA) * demultiply; - dst[i + 2] = (sBA + dBA - sBA * dBA) * demultiply; - break; - case 'multiply': - dst[i] = (sRA * dRA + sRA * (1 - dA) + dRA * (1 - sA)) * demultiply; - dst[i + 1] = (sGA * dGA + sGA * (1 - dA) + dGA * (1 - sA)) * demultiply; - dst[i + 2] = (sBA * dBA + sBA * (1 - dA) + dBA * (1 - sA)) * demultiply; - break; - case 'difference': - dst[i] = (sRA + dRA - 2 * min(sRA * dA, dRA * sA)) * demultiply; - dst[i + 1] = (sGA + dGA - 2 * min(sGA * dA, dGA * sA)) * demultiply; - dst[i + 2] = (sBA + dBA - 2 * min(sBA * dA, dBA * sA)) * demultiply; - break; - // Slightly different from Photoshop, where alpha is concerned - case 'src-in': - // Only differs from Photoshop in low - opacity areas - dA2 = sA * dA; - demultiply = 255 / dA2; - dst[i + 3] = dA2 * 255; - dst[i] = sRA * dA * demultiply; - dst[i + 1] = sGA * dA * demultiply; - dst[i + 2] = sBA * dA * demultiply; - break; - case 'plus': - case 'add': - // Photoshop doesn't simply add the alpha channels; this might be correct wrt SVG 1.2 - dA2 = min(1, sA + dA); - dst[i + 3] = dA2 * 255; - demultiply = 255 / dA2; - dst[i] = min(sRA + dRA, 1) * demultiply; - dst[i + 1] = min(sGA + dGA, 1) * demultiply; - dst[i + 2] = min(sBA + dBA, 1) * demultiply; - break; - case 'overlay': + overlay: function(i) { + // = Reverse of hard-light // Correct for 100% opacity case; colors get clipped as opacity falls dst[i] = dRA <= 0.5 ? (2 * src[i] * dRA / dA) : 255 - (2 - 2 * dRA / dA) * (255 - src[i]); dst[i + 1] = dGA <= 0.5 ? (2 * src[i + 1] * dGA / dA) : 255 - (2 - 2 * dGA / dA) * (255 - src[i + 1]); dst[i + 2] = dBA <= 0.5 ? (2 * src[i + 2] * dBA / dA) : 255 - (2 - 2 * dBA / dA) * (255 - src[i + 2]); - break; - case 'hard-light': - dst[i] = sRA <= 0.5 ? (2 * dst[i] * sRA / dA) : 255 - (2 - 2 * sRA / sA) * (255 - dst[i]); + }, + + // TODO: Missing: soft-light + + 'hard-light': function(i) { + dst[i] = sRA <= 0.5 ? (2 * dst[i] * sRA / dA) : 255 - (2 - 2 * sRA / sA) * (255 - dst[i]); dst[i + 1] = sGA <= 0.5 ? (2 * dst[i + 1] * sGA / dA) : 255 - (2 - 2 * sGA / sA) * (255 - dst[i + 1]); dst[i + 2] = sBA <= 0.5 ? (2 * dst[i + 2] * sBA / dA) : 255 - (2 - 2 * sBA / sA) * (255 - dst[i + 2]); - break; - case 'color-dodge': - case 'dodge': - dst[i] = src[i] == 255 && dRA == 0 ? 255 : min(255, dst[i] / (255 - src[i] )) * demultiply; - dst[i + 1] = src[i + 1] == 255 && dGA == 0 ? 255 : min(255, dst[i + 1] / (255 - src[i + 1])) * demultiply; - dst[i + 2] = src[i + 2] == 255 && dBA == 0 ? 255 : min(255, dst[i + 2] / (255 - src[i + 2])) * demultiply; - break; - case 'color-burn': - case 'burn': - dst[i] = src[i] == 0 && dRA == 0 ? 0 : (1 - min(1, (1 - dRA) / sRA)) * demultiply; - dst[i + 1] = src[i + 1] == 0 && dGA == 0 ? 0 : (1 - min(1, (1 - dGA) / sGA)) * demultiply; - dst[i + 2] = src[i + 2] == 0 && dBA == 0 ? 0 : (1 - min(1, (1 - dBA) / sBA)) * demultiply; - break; - case 'darken': - case 'darker': - dst[i] = (sRA > dRA ? dRA : sRA) * demultiply; - dst[i + 1] = (sGA > dGA ? dGA : sGA) * demultiply; - dst[i + 2] = (sBA > dBA ? dBA : sBA) * demultiply; - break; - case 'lighten': - case 'lighter': - dst[i] = (sRA < dRA ? dRA : sRA) * demultiply; - dst[i + 1] = (sGA < dGA ? dGA : sGA) * demultiply; - dst[i + 2] = (sBA < dBA ? dBA : sBA) * demultiply; - break; - case 'exclusion': - dst[i] = (dRA + sRA - 2 * dRA * sRA) * demultiply; - dst[i + 1] = (dGA + sGA - 2 * dGA * sGA) * demultiply; - dst[i + 2] = (dBA + sBA - 2 * dBA * sBA) * demultiply; - break; - // Unsupported - default: - dst[i] = dst[i + 3] = 255; - dst[i + 1] = i % 8 == 0 ? 255 : 0; - dst[i + 2] = i % 8 == 0 ? 0 : 255; + }, + + 'color-dodge': function(i) { + dst[i] = src[i] == 255 && dRA == 0 ? 255 : min(255, dst[i] / (255 - src[i] )) * rM; + dst[i + 1] = src[i + 1] == 255 && dGA == 0 ? 255 : min(255, dst[i + 1] / (255 - src[i + 1])) * rM; + dst[i + 2] = src[i + 2] == 255 && dBA == 0 ? 255 : min(255, dst[i + 2] / (255 - src[i + 2])) * rM; + }, + + 'color-burn': function(i) { + dst[i] = src[i] == 0 && dRA == 0 ? 0 : (1 - min(1, (1 - dRA) / sRA)) * rM; + dst[i + 1] = src[i + 1] == 0 && dGA == 0 ? 0 : (1 - min(1, (1 - dGA) / sGA)) * rM; + dst[i + 2] = src[i + 2] == 0 && dBA == 0 ? 0 : (1 - min(1, (1 - dBA) / sBA)) * rM; + }, + + darken: function(i) { + dst[i] = min(sRA, dRA) * rM; + dst[i + 1] = min(sGA, dGA) * rM; + dst[i + 2] = min(sBA, dBA) * rM; + }, + + lighten: function(i) { + dst[i] = max(sRA, dRA) * rM; + dst[i + 1] = max(sGA, dGA) * rM; + dst[i + 2] = max(sBA, dBA) * rM; + }, + + difference: function(i) { + dst[i] = (sRA + dRA - 2 * min(sRA * dA, dRA * sA)) * rM; + dst[i + 1] = (sGA + dGA - 2 * min(sGA * dA, dGA * sA)) * rM; + dst[i + 2] = (sBA + dBA - 2 * min(sBA * dA, dBA * sA)) * rM; + }, + + exclusion: function(i) { + dst[i] = (dRA + sRA - 2 * dRA * sRA) * rM; + dst[i + 1] = (dGA + sGA - 2 * dGA * sGA) * rM; + dst[i + 2] = (dBA + sBA - 2 * dBA * sBA) * rM; + }, + + // TODO: Missing: hue, saturation, color, luminosity + + // Not in Illustrator: + + 'src-in': function(i) { + // Only differs from Photoshop in low - opacity areas + rA = sA * dA; + rM = 255 / rA; + dst[i] = sRA * dA * rM; + dst[i + 1] = sGA * dA * rM; + dst[i + 2] = sBA * dA * rM; + }, + + add: function(i) { + // Photoshop doesn't simply add the alpha channels, + // this might be correct wrt SVG 1.2 + rA = min(1, sA + dA); + rM = 255 / rA; + dst[i] = min(sRA + dRA, 1) * rM; + dst[i + 1] = min(sGA + dGA, 1) * rM; + dst[i + 2] = min(sBA + dBA, 1) * rM; } + }; + + var process = modes[blendMode]; + if (!process) + return; + opacity /= 255; + for (var i = 0, l = dst.length; i < l; i += 4) { + sA = src[i + 3] * opacity; + dA = dst[i + 3] / 255; + rA = sA + dA - sA * dA; + sM = sA / 255; + dM = dA / 255; + sRA = src[i] * sM; + dRA = dst[i] * dM; + sGA = src[i + 1] * sM; + dGA = dst[i + 1] * dM; + sBA = src[i + 2] * sM; + dBA = dst[i + 2] * dM; + rM = 255 / rA; + process(i); + dst[i + 3] = rA * 255; } - destContext.putImageData(dstD, offset.x, offset.y); + destContext.putImageData(dstData, offset.x, offset.y); } }; diff --git a/src/util/CanvasProvider.js b/src/util/CanvasProvider.js index 8bbdca93..49b352f8 100644 --- a/src/util/CanvasProvider.js +++ b/src/util/CanvasProvider.js @@ -14,8 +14,8 @@ * All rights reserved. */ -// TODO: it might be better to make a ContextProvider class, since you -// can always find the canvas through context.canvas. This saves code and +// TODO: It might be better to make a ContextProvider class, since you +// can always find the canvas through context.canvas. This saves code and // speed by not having to do canvas.getContext('2d') // TODO: Run through the canvas array to find a canvas with the requested // width / height, so we don't need to resize it?