From 4d4eed0e08870f5eeb937cdfcf3dba493e668a5d Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 14:08:20 -0800 Subject: [PATCH 01/19] removed hsl tests for now --- test/canvas.test.js | 67 --------------------------------------------- 1 file changed, 67 deletions(-) diff --git a/test/canvas.test.js b/test/canvas.test.js index b758395..b79674f 100644 --- a/test/canvas.test.js +++ b/test/canvas.test.js @@ -38,73 +38,6 @@ module.exports = { assert.equal(null, parseColor('rgba(2554,165 , 0 ,.6)')); assert.equal(null, parseColor('rgba()')); - // hsl() - assert.eql([255,0,0,1], parseColor('hsl(0,100.0,50.0)')); - assert.eql([255,0,0,1], parseColor('hsl(360,100.0,50.0)')); - assert.eql([0,255,0,1], parseColor('hsl(120,100.0,50.0)')); - assert.eql([0,0,255,1], parseColor('hsl(240,100.0,50.0)')); - assert.equal(null, parseColor('hsl()')); - - // adapted from tables at http://www.w3.org/TR/css3-color/#hsl-examples - // NB:- corrected rounded percents to precise percents - // e.g. 13% --> 12.5%, etc. - // ...presumably the precise values were used to generate the tables? - assert.eql(parseColor('#FFFFFF'), parseColor('hsl(0,100%,100%)')) - assert.eql(parseColor('#FFFFFF'), parseColor('hsl(0,75%,100%)')) - assert.eql(parseColor('#FFFFFF'), parseColor('hsl(0,50%,100%)')) - assert.eql(parseColor('#FFFFFF'), parseColor('hsl(0,25%,100%)')) - assert.eql(parseColor('#FFFFFF'), parseColor('hsl(0,0%,100%)')) - assert.eql(parseColor('#FFBFBF'), parseColor('hsl(0,100%,87.5%)')) - assert.eql(parseColor('#F7C7C7'), parseColor('hsl(0,75%,87.5%)')) - assert.eql(parseColor('#EFCFCF'), parseColor('hsl(0,50%,87.5%)')) - assert.eql(parseColor('#E7D7D7'), parseColor('hsl(0,25%,87.5%)')) - assert.eql(parseColor('#DFDFDF'), parseColor('hsl(0,0%,87.5%)')) - assert.eql(parseColor('#FF8080'), parseColor('hsl(0,100%,75%)')) - assert.eql(parseColor('#EF8F8F'), parseColor('hsl(0,75%,75%)')) - assert.eql(parseColor('#DF9F9F'), parseColor('hsl(0,50%,75%)')) - assert.eql(parseColor('#CFAFAF'), parseColor('hsl(0,25%,75%)')) - assert.eql(parseColor('#BFBFBF'), parseColor('hsl(0,0%,75%)')) - assert.eql(parseColor('#FF4040'), parseColor('hsl(0,100%,62.5%)')) - assert.eql(parseColor('#E75858'), parseColor('hsl(0,75%,62.5%)')) - assert.eql(parseColor('#CF7070'), parseColor('hsl(0,50%,62.5%)')) - assert.eql(parseColor('#B78787'), parseColor('hsl(0,25%,62.5%)')) - assert.eql(parseColor('#9F9F9F'), parseColor('hsl(0,0%,62.5%)')) - assert.eql(parseColor('#FF0000'), parseColor('hsl(0,100%,50%)')) - assert.eql(parseColor('#DF2020'), parseColor('hsl(0,75%,50%)')) - assert.eql(parseColor('#BF4040'), parseColor('hsl(0,50%,50%)')) - assert.eql(parseColor('#9F6060'), parseColor('hsl(0,25%,50%)')) - assert.eql(parseColor('#808080'), parseColor('hsl(0,0%,50%)')) - assert.eql(parseColor('#BF0000'), parseColor('hsl(0,100%,37.5%)')) - assert.eql(parseColor('#A71818'), parseColor('hsl(0,75%,37.5%)')) - assert.eql(parseColor('#8F3030'), parseColor('hsl(0,50%,37.5%)')) - assert.eql(parseColor('#784848'), parseColor('hsl(0,25%,37.5%)')) - assert.eql(parseColor('#606060'), parseColor('hsl(0,0%,37.5%)')) - assert.eql(parseColor('#800000'), parseColor('hsl(0,100%,25%)')) - assert.eql(parseColor('#701010'), parseColor('hsl(0,75%,25%)')) - assert.eql(parseColor('#602020'), parseColor('hsl(0,50%,25%)')) - assert.eql(parseColor('#503030'), parseColor('hsl(0,25%,25%)')) - assert.eql(parseColor('#404040'), parseColor('hsl(0,0%,25%)')) - assert.eql(parseColor('#400000'), parseColor('hsl(0,100%,12.5%)')) - assert.eql(parseColor('#380808'), parseColor('hsl(0,75%,12.5%)')) - assert.eql(parseColor('#301010'), parseColor('hsl(0,50%,12.5%)')) - assert.eql(parseColor('#281818'), parseColor('hsl(0,25%,12.5%)')) - assert.eql(parseColor('#202020'), parseColor('hsl(0,0%,12.5%)')) - assert.eql(parseColor('#000000'), parseColor('hsl(0,100%,0%)')) - assert.eql(parseColor('#000000'), parseColor('hsl(0,75%,0%)')) - assert.eql(parseColor('#000000'), parseColor('hsl(0,50%,0%)')) - assert.eql(parseColor('#000000'), parseColor('hsl(0,25%,0%)')) - assert.eql(parseColor('#000000'), parseColor('hsl(0,0%,0%)')) - - // TODO: there are 11 more tables to adapt from - // http://www.w3.org/TR/css3-color/#hsl-examples :) - - // hsla() - assert.eql([255,0,0,1], parseColor('hsla(0,100.0,50.0,1.0)')); - assert.eql([255,0,0,1], parseColor('hsla(360,100.0,50.0,1.0)')); - assert.eql([0,255,0,1], parseColor('hsla(120,100.0,50.0,1.0)')); - assert.eql([0,0,255,1], parseColor('hsla(240,100.0,50.0,1.0)')); - assert.equal(null, parseColor('hsl()')); - // hex assert.eql([165,89,89,1], parseColor('#A55959')); assert.eql([255,255,255,1], parseColor('#FFFFFF')); From ddf5c99bbff940bf8888b634b66b1149874394eb Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 14:09:40 -0800 Subject: [PATCH 02/19] removed color parser --- lib/colors.js | 153 ----------------------------------------------- lib/context2d.js | 139 +----------------------------------------- 2 files changed, 1 insertion(+), 291 deletions(-) delete mode 100644 lib/colors.js diff --git a/lib/colors.js b/lib/colors.js deleted file mode 100644 index 5ced002..0000000 --- a/lib/colors.js +++ /dev/null @@ -1,153 +0,0 @@ - -/*! - * Canvas - colors - * Copyright (c) 2010 LearnBoost - * MIT Licensed - */ - -module.exports = { - transparent: 'rgba(255,255,255,0)' - , aliceblue: '#f0f8ff' - , antiquewhite: '#faebd7' - , aqua: '#00ffff' - , aquamarine: '#7fffd4' - , azure: '#f0ffff' - , beige: '#f5f5dc' - , bisque: '#ffe4c4' - , black: '#000000' - , blanchedalmond: '#ffebcd' - , blue: '#0000ff' - , blueviolet: '#8a2be2' - , brown: '#a52a2a' - , burlywood: '#deb887' - , cadetblue: '#5f9ea0' - , chartreuse: '#7fff00' - , chocolate: '#d2691e' - , coral: '#ff7f50' - , cornflowerblue: '#6495ed' - , cornsilk: '#fff8dc' - , crimson: '#dc143c' - , cyan: '#00ffff' - , darkblue: '#00008b' - , darkcyan: '#008b8b' - , darkgoldenrod: '#b8860b' - , darkgray: '#a9a9a9' - , darkgreen: '#006400' - , darkkhaki: '#bdb76b' - , darkmagenta: '#8b008b' - , darkolivegreen: '#556b2f' - , darkorange: '#ff8c00' - , darkorchid: '#9932cc' - , darkred: '#8b0000' - , darksalmon: '#e9967a' - , darkseagreen: '#8fbc8f' - , darkslateblue: '#483d8b' - , darkslategray: '#2f4f4f' - , darkturquoise: '#00ced1' - , darkviolet: '#9400d3' - , deeppink: '#ff1493' - , deepskyblue: '#00bfff' - , dimgray: '#696969' - , dodgerblue: '#1e90ff' - , feldspar: '#d19275' - , firebrick: '#b22222' - , floralwhite: '#fffaf0' - , forestgreen: '#228b22' - , fuchsia: '#ff00ff' - , gainsboro: '#dcdcdc' - , ghostwhite: '#f8f8ff' - , gold: '#ffd700' - , goldenrod: '#daa520' - , gray: '#808080' - , green: '#008000' - , greenyellow: '#adff2f' - , honeydew: '#f0fff0' - , hotpink: '#ff69b4' - , indianred : '#cd5c5c' - , indigo : '#4b0082' - , ivory: '#fffff0' - , khaki: '#f0e68c' - , lavender: '#e6e6fa' - , lavenderblush: '#fff0f5' - , lawngreen: '#7cfc00' - , lemonchiffon: '#fffacd' - , lightblue: '#add8e6' - , lightcoral: '#f08080' - , lightcyan: '#e0ffff' - , lightgoldenrodyellow: '#fafad2' - , lightgrey: '#d3d3d3' - , lightgreen: '#90ee90' - , lightpink: '#ffb6c1' - , lightsalmon: '#ffa07a' - , lightseagreen: '#20b2aa' - , lightskyblue: '#87cefa' - , lightslateblue: '#8470ff' - , lightslategray: '#778899' - , lightsteelblue: '#b0c4de' - , lightyellow: '#ffffe0' - , lime: '#00ff00' - , limegreen: '#32cd32' - , linen: '#faf0e6' - , magenta: '#ff00ff' - , maroon: '#800000' - , mediumaquamarine: '#66cdaa' - , mediumblue: '#0000cd' - , mediumorchid: '#ba55d3' - , mediumpurple: '#9370d8' - , mediumseagreen: '#3cb371' - , mediumslateblue: '#7b68ee' - , mediumspringgreen: '#00fa9a' - , mediumturquoise: '#48d1cc' - , mediumvioletred: '#c71585' - , midnightblue: '#191970' - , mintcream: '#f5fffa' - , mistyrose: '#ffe4e1' - , moccasin: '#ffe4b5' - , navajowhite: '#ffdead' - , navy: '#000080' - , oldlace: '#fdf5e6' - , olive: '#808000' - , olivedrab: '#6b8e23' - , orange: '#ffa500' - , orangered: '#ff4500' - , orchid: '#da70d6' - , palegoldenrod: '#eee8aa' - , palegreen: '#98fb98' - , paleturquoise: '#afeeee' - , palevioletred: '#d87093' - , papayawhip: '#ffefd5' - , peachpuff: '#ffdab9' - , peru: '#cd853f' - , pink: '#ffc0cb' - , plum: '#dda0dd' - , powderblue: '#b0e0e6' - , purple: '#800080' - , red: '#ff0000' - , rosybrown: '#bc8f8f' - , royalblue: '#4169e1' - , saddlebrown: '#8b4513' - , salmon: '#fa8072' - , sandybrown: '#f4a460' - , seagreen: '#2e8b57' - , seashell: '#fff5ee' - , sienna: '#a0522d' - , silver: '#c0c0c0' - , skyblue: '#87ceeb' - , slateblue: '#6a5acd' - , slategray: '#708090' - , snow: '#fffafa' - , springgreen: '#00ff7f' - , steelblue: '#4682b4' - , tan: '#d2b48c' - , teal: '#008080' - , thistle: '#d8bfd8' - , tomato: '#ff6347' - , turquoise: '#40e0d0' - , violet: '#ee82ee' - , violetred: '#d02090' - , wheat: '#f5deb3' - , white: '#ffffff' - , whitesmoke: '#f5f5f5' - , yellow: '#ffff00' - , yellowgreen: '#9acd32' -}; \ No newline at end of file diff --git a/lib/context2d.js b/lib/context2d.js index f637416..fc435c9 100644 --- a/lib/context2d.js +++ b/lib/context2d.js @@ -13,8 +13,7 @@ var canvas = require('../build/default/canvas') , Context2d = canvas.CanvasRenderingContext2d , CanvasGradient = canvas.CanvasGradient , ImageData = canvas.ImageData - , PixelArray = canvas.CanvasPixelArray - , colors = require('./colors'); + , PixelArray = canvas.CanvasPixelArray; /** * Export `Context2d` as the module. @@ -107,142 +106,6 @@ var parseFont = exports.parseFont = function(str){ return font; }; -/** - * Parse the given color `str`. - * - * Current supports: - * - * - #nnn - * - #nnnnnn - * - rgb(r,g,b) - * - rgba(r,g,b,a) - * - color - * - * Examples - * - * - #fff - * - #FFF - * - #FFFFFF - * - rgb(255,255,5) - * - rgba(255,255,5,.8) - * - rgba(255,255,5,0.8) - * - hsl(300,100%,50%) - * - hsla(300,100%,50%,0.5) - * - white - * - red - * - * @param {String} str - * @return {Array} - * @api private - */ - -var parseColor = exports.parseColor = function(str){ - if (cache[str]) return cache[str]; - str = colors[str] || String(str); - // RGBA - if (0 == str.indexOf('rgba')) { - var captures = /rgba\((\d{1,3}) *, *(\d{1,3}) *, *(\d{1,3}) *, *(\d+\.\d+|\.\d+|\d+) *\)/.exec(str); - if (!captures) return; - return cache[str] = [ - parseInt(captures[1], 10) - , parseInt(captures[2], 10) - , parseInt(captures[3], 10) - , parseFloat(captures[4], 10) - ]; - // RGB - } else if (0 == str.indexOf('rgb')) { - var captures = /rgb\((\d{1,3}) *, *(\d{1,3}) *, *(\d{1,3}) *\)/.exec(str); - if (!captures) return; - return cache[str] = [ - parseInt(captures[1], 10) - , parseInt(captures[2], 10) - , parseInt(captures[3], 10) - , 1 - ]; - // #RRGGBB - } else if ('#' == str[0] && str.length > 4) { - var captures = /#([a-fA-F\d]{2})([a-fA-F\d]{2})([a-fA-F\d]{2})/.exec(str); - if (!captures) return; - return cache[str] = [ - parseInt(captures[1], 16) - , parseInt(captures[2], 16) - , parseInt(captures[3], 16) - , 1 - ]; - // #RGB - } else if ('#' == str[0]) { - var captures = /#([a-fA-F\d])([a-fA-F\d])([a-fA-F\d])/.exec(str); - if (!captures) return; - return cache[str] = [ - parseInt(captures[1] + captures[1], 16) - , parseInt(captures[2] + captures[2], 16) - , parseInt(captures[3] + captures[3], 16) - , 1 - ]; - // HSLA - } else if (0 == str.indexOf('hsla')) { - var captures = /hsla\((\d+\.\d+|\.\d+|\d+) *, *(\d+\.\d+|\.\d+|\d+)%? *, *(\d+\.\d+|\.\d+|\d+)%? *, *(\d+\.\d+|\.\d+|\d+) *\)/.exec(str); - if (!captures) return; - return cache[str] = hsl2rgb( - (((parseFloat(captures[1], 10) % 360) + 360) % 360) / 360 - , parseFloat(captures[2], 10) / 100.0 - , parseFloat(captures[3], 10) / 100.0 - , parseFloat(captures[4], 10) - ); - // HSL - } else if (0 == str.indexOf('hsl')) { - var captures = /hsl\((\d+\.\d+|\.\d+|\d+) *, *(\d+\.\d+|\.\d+|\d+)%? *, *(\d+\.\d+|\.\d+|\d+)%? *\)/.exec(str); - if (!captures) return; - return cache[str] = hsl2rgb( - (((parseFloat(captures[1], 10) % 360) + 360) % 360) / 360 - , parseFloat(captures[2], 10) / 100.0 - , parseFloat(captures[3], 10) / 100.0 - , 1 - ); - } -}; - -/** - * HSLA -> RGB. - * - * @param {Number} h - * @param {Number} s - * @param {Number} l - * @param {Number} a - * @return {Array} - * @api private - */ - -function hsl2rgb(h,s,l,a) { - var m2 = l <= 0.5 ? l*(s+1) : l+s-l*s - , m1 = l*2-m2; - return [ - Math.round(hue2rgb(m1, m2, h+1/3) * 255) - , Math.round(hue2rgb(m1, m2, h) * 255) - , Math.round(hue2rgb(m1, m2, h-1/3) * 255) - , a - ]; -} - -/** - * Hue to RGB - * - * @param {Number} m1 - * @param {Number} m2 - * @param {Number} h - * @return {Number} - * @api private - */ - -function hue2rgb(m1,m2,h) { - if (h<0) h = h+1; - if (h>1) h = h-1; - if (h*6<1) return m1+(m2-m1)*h*6; - if (h*2<1) return m2; - if (h*3<2) return m1+(m2-m1)*(2/3-h)*6; - return m1; -} - /** * Add `color` stop at the given `offset`. * From 1f82f638900c2e7141be324f259960cbfee23f5a Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 14:14:48 -0800 Subject: [PATCH 03/19] removed old parseColor dependants --- lib/context2d.js | 107 ++---------------------------------------- src/CanvasGradient.cc | 8 ++-- src/CanvasGradient.h | 2 +- 3 files changed, 9 insertions(+), 108 deletions(-) diff --git a/lib/context2d.js b/lib/context2d.js index fc435c9..b0ddef6 100644 --- a/lib/context2d.js +++ b/lib/context2d.js @@ -53,34 +53,6 @@ var fontre = new RegExp('^ *' + '((?:' + string + ')( *, *(?:' + string + '))*)' ); -/** - * Return a function used to normalize an RGBA color `prop` - * or the pattern previously set. - * - * @param {String} prop - * @return {Function} - * @api private - */ - -function getter(prop) { - return function(){ - var val = this[prop]; - if (val instanceof CanvasGradient) return val; - if (1 == val[3]) { - return '#' - + val[0].toString(16) - + val[1].toString(16) - + val[2].toString(16); - } else { - return 'rgba(' - + val[0] + ', ' - + val[1] + ', ' - + val[2] + ', ' - + val[3] + ')'; - } - } -} - /** * Parse font `str`. * @@ -106,26 +78,6 @@ var parseFont = exports.parseFont = function(str){ return font; }; -/** - * Add `color` stop at the given `offset`. - * - * @param {Number} offset - * @param {String} color - * @api public - */ - -CanvasGradient.prototype.addColorStop = function(offset, color){ - var rgba; - if (rgba = parseColor(color)) { - this.addColorStopRGBA( - offset - , rgba[0] - , rgba[1] - , rgba[2] - , rgba[3]); - } -}; - /** * Create a linear gradient at the given point `(x0, y0)` and `(x1, y1)`. * @@ -174,7 +126,6 @@ Context2d.prototype.setTransform = function(){ /** * Set the fill style with the given css color string. * - * @see exports.parseColor() * @api public */ @@ -183,30 +134,13 @@ Context2d.prototype.__defineSetter__('fillStyle', function(val){ this.lastFillStyle = val; this.setFillPattern(val); } else if ('string' == typeof val) { - var rgba; - if (rgba = parseColor(val)) { - this.lastFillStyle = rgba; - this.setFillRGBA( - rgba[0] - , rgba[1] - , rgba[2] - , rgba[3]); - } + this.setFillStyle(val); } }); -/** - * Get the current fill style string. - * - * @api public - */ - -Context2d.prototype.__defineGetter__('fillStyle', getter('lastFillStyle')); - /** * Set the stroke style with the given css color string. * - * @see exports.parseColor() * @api public */ @@ -215,55 +149,20 @@ Context2d.prototype.__defineSetter__('strokeStyle', function(val){ this.lastStrokeStyle = val; this.setStrokePattern(val); } else if ('string' == typeof val) { - var rgba; - if (rgba = parseColor(val)) { - this.lastStrokeStyle = rgba; - this.setStrokeRGBA( - rgba[0] - , rgba[1] - , rgba[2] - , rgba[3]); - } + this.setStrokeStyle(val); } }); -/** - * Get the current stroke style string. - * - * @api public - */ - -Context2d.prototype.__defineGetter__('strokeStyle', getter('lastStrokeStyle')); - /** * Set the shadow color with the given css color string. * - * @see exports.parseColor() * @api public */ Context2d.prototype.__defineSetter__('shadowColor', function(val){ - if ('string' == typeof val) { - var rgba; - if (rgba = parseColor(val)) { - this.lastShadowColor = rgba; - this.setShadowRGBA( - rgba[0] - , rgba[1] - , rgba[2] - , rgba[3]); - } - } + this.setShadowColor(val); }); -/** - * Get the current shadow color string. - * - * @api public - */ - -Context2d.prototype.__defineGetter__('shadowColor', getter('lastShadowColor')); - /** * Set font. * diff --git a/src/CanvasGradient.cc b/src/CanvasGradient.cc index cf99585..bd123f6 100644 --- a/src/CanvasGradient.cc +++ b/src/CanvasGradient.cc @@ -24,7 +24,7 @@ Gradient::Initialize(Handle target) { constructor->SetClassName(String::NewSymbol("CanvasGradient")); // Prototype - NODE_SET_PROTOTYPE_METHOD(constructor, "addColorStopRGBA", AddColorStopRGBA); + NODE_SET_PROTOTYPE_METHOD(constructor, "addColorStop", AddColorStop); target->Set(String::NewSymbol("CanvasGradient"), constructor->GetFunction()); } @@ -64,14 +64,16 @@ Gradient::New(const Arguments &args) { } /* - * Add RGBA color stop. + * Add color stop. */ Handle -Gradient::AddColorStopRGBA(const Arguments &args) { +Gradient::AddColorStop(const Arguments &args) { HandleScope scope; if (!args[0]->IsNumber()) return ThrowException(Exception::TypeError(String::New("offset required"))); + if (!args[1]->IsString()) + return ThrowException(Exception::TypeError(String::New("color string required"))); RGBA_ARGS(1); Gradient *grad = ObjectWrap::Unwrap(args.This()); cairo_pattern_add_color_stop_rgba( diff --git a/src/CanvasGradient.h b/src/CanvasGradient.h index adcf2bc..db17096 100644 --- a/src/CanvasGradient.h +++ b/src/CanvasGradient.h @@ -15,7 +15,7 @@ class Gradient: public node::ObjectWrap { static Persistent constructor; static void Initialize(Handle target); static Handle New(const Arguments &args); - static Handle AddColorStopRGBA(const Arguments &args); + static Handle AddColorStop(const Arguments &args); Gradient(double x0, double y0, double x1, double y1); Gradient(double x0, double y0, double r0, double x1, double y1, double r1); inline cairo_pattern_t *pattern(){ return _pattern; } From 97c7fe6dbd9429d888494cb500c65cf23576770a Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 14:21:19 -0800 Subject: [PATCH 04/19] prep for c color parser --- lib/context2d.js | 4 ++-- src/CanvasRenderingContext2d.cc | 24 +++++++++++++----------- src/CanvasRenderingContext2d.h | 6 +++--- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/lib/context2d.js b/lib/context2d.js index b0ddef6..ea461f0 100644 --- a/lib/context2d.js +++ b/lib/context2d.js @@ -134,7 +134,7 @@ Context2d.prototype.__defineSetter__('fillStyle', function(val){ this.lastFillStyle = val; this.setFillPattern(val); } else if ('string' == typeof val) { - this.setFillStyle(val); + this.setFillColor(val); } }); @@ -149,7 +149,7 @@ Context2d.prototype.__defineSetter__('strokeStyle', function(val){ this.lastStrokeStyle = val; this.setStrokePattern(val); } else if ('string' == typeof val) { - this.setStrokeStyle(val); + this.setStrokeColor(val); } }); diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 5ac2756..c8bac13 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -100,9 +100,9 @@ Context2d::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(constructor, "arc", Arc); NODE_SET_PROTOTYPE_METHOD(constructor, "arcTo", ArcTo); NODE_SET_PROTOTYPE_METHOD(constructor, "setFont", SetFont); - NODE_SET_PROTOTYPE_METHOD(constructor, "setShadowRGBA", SetShadowRGBA); - NODE_SET_PROTOTYPE_METHOD(constructor, "setFillRGBA", SetFillRGBA); - NODE_SET_PROTOTYPE_METHOD(constructor, "setStrokeRGBA", SetStrokeRGBA); + NODE_SET_PROTOTYPE_METHOD(constructor, "setShadowColor", SetShadowColor); + NODE_SET_PROTOTYPE_METHOD(constructor, "setFillColor", SetFillColor); + NODE_SET_PROTOTYPE_METHOD(constructor, "setStrokeColor", SetStrokeColor); NODE_SET_PROTOTYPE_METHOD(constructor, "setFillPattern", SetFillPattern); NODE_SET_PROTOTYPE_METHOD(constructor, "setStrokePattern", SetStrokePattern); proto->SetAccessor(String::NewSymbol("globalCompositeOperation"), GetGlobalCompositeOperation, SetGlobalCompositeOperation); @@ -997,11 +997,11 @@ Context2d::SetStrokePattern(const Arguments &args) { } /* - * Set shadow RGBA, used internally for shadowColor= + * Set shadow color, used internally for shadowColor= */ Handle -Context2d::SetShadowRGBA(const Arguments &args) { +Context2d::SetShadowColor(const Arguments &args) { HandleScope scope; RGBA_ARGS(0); Context2d *context = ObjectWrap::Unwrap(args.This()); @@ -1010,25 +1010,27 @@ Context2d::SetShadowRGBA(const Arguments &args) { } /* - * Set fill RGBA, used internally for fillStyle= + * Set fill color, used internally for fillStyle= */ Handle -Context2d::SetFillRGBA(const Arguments &args) { +Context2d::SetFillColor(const Arguments &args) { HandleScope scope; - RGBA_ARGS(0); + if (!args[0]->IsString()) return Undefined(); + String::AsciiValue str(args[0]); + printf("%s\n", *str); Context2d *context = ObjectWrap::Unwrap(args.This()); context->state->fillPattern = NULL; - RGBA(context->state->fill,r,g,b,a); + //RGBA(context->state->fill,r,g,b,a); return Undefined(); } /* - * Set stroke RGBA, used internally for strokeStyle= + * Set stroke color, used internally for strokeStyle= */ Handle -Context2d::SetStrokeRGBA(const Arguments &args) { +Context2d::SetStrokeColor(const Arguments &args) { HandleScope scope; RGBA_ARGS(0); Context2d *context = ObjectWrap::Unwrap(args.This()); diff --git a/src/CanvasRenderingContext2d.h b/src/CanvasRenderingContext2d.h index b11409a..da89432 100644 --- a/src/CanvasRenderingContext2d.h +++ b/src/CanvasRenderingContext2d.h @@ -67,9 +67,9 @@ class Context2d: public node::ObjectWrap { static Handle FillText(const Arguments &args); static Handle StrokeText(const Arguments &args); static Handle SetFont(const Arguments &args); - static Handle SetFillRGBA(const Arguments &args); - static Handle SetStrokeRGBA(const Arguments &args); - static Handle SetShadowRGBA(const Arguments &args); + static Handle SetFillColor(const Arguments &args); + static Handle SetStrokeColor(const Arguments &args); + static Handle SetShadowColor(const Arguments &args); static Handle SetFillPattern(const Arguments &args); static Handle SetStrokePattern(const Arguments &args); static Handle SetTextBaseline(const Arguments &args); From 2f6e63a8e45a97fe024fb72ed13fb36486c9305b Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 14:21:51 -0800 Subject: [PATCH 05/19] Added color.h --- src/color.h | 389 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 389 insertions(+) create mode 100644 src/color.h diff --git a/src/color.h b/src/color.h new file mode 100644 index 0000000..b1730f9 --- /dev/null +++ b/src/color.h @@ -0,0 +1,389 @@ + +// +// color.h +// +// Copyright (c) 2010 LearnBoost +// + +#include +#include +#include + +/* + * Consume whitespace. + */ + +#define WHITESPACE \ + while (' ' == *str) ++str; + +/* + * Parse color channel value + */ + +#define CHANNEL(NAME) \ + if (*str >= '0' && *str <= '9') { \ + do { \ + NAME *= 10; \ + NAME += *str++ - '0'; \ + } while (*str >= '0' && *str <= '9'); \ + } else { \ + return -1; \ + } \ + while (' ' == *str || ',' == *str) str++; + +/* + * Named colors. + */ + +static struct named_color { + char *name; + uint32_t val; +} named_colors[] = { + "transparent", 0xffffff00 + , "aliceblue", 0xf0f8ffff + , "antiquewhite", 0xfaebd7ff + , "aqua", 0x00ffffff + , "aquamarine", 0x7fffd4ff + , "azure", 0xf0ffffff + , "beige", 0xf5f5dcff + , "bisque", 0xffe4c4ff + , "black", 0x000000ff + , "blanchedalmond", 0xffebcdff + , "blue", 0x0000ffff + , "blueviolet", 0x8a2be2ff + , "brown", 0xa52a2aff + , "burlywood", 0xdeb887ff + , "cadetblue", 0x5f9ea0ff + , "chartreuse", 0x7fff00ff + , "chocolate", 0xd2691eff + , "coral", 0xff7f50ff + , "cornflowerblue", 0x6495edff + , "cornsilk", 0xfff8dcff + , "crimson", 0xdc143cff + , "cyan", 0x00ffffff + , "darkblue", 0x00008bff + , "darkcyan", 0x008b8bff + , "darkgoldenrod", 0xb8860bff + , "darkgray", 0xa9a9a9ff + , "darkgreen", 0x006400ff + , "darkkhaki", 0xbdb76bff + , "darkmagenta", 0x8b008bff + , "darkolivegreen", 0x556b2fff + , "darkorange", 0xff8c00ff + , "darkorchid", 0x9932ccff + , "darkred", 0x8b0000ff + , "darksalmon", 0xe9967aff + , "darkseagreen", 0x8fbc8fff + , "darkslateblue", 0x483d8bff + , "darkslategray", 0x2f4f4fff + , "darkturquoise", 0x00ced1ff + , "darkviolet", 0x9400d3ff + , "deeppink", 0xff1493ff + , "deepskyblue", 0x00bfffff + , "dimgray", 0x696969ff + , "dodgerblue", 0x1e90ffff + , "feldspar", 0xd19275ff + , "firebrick", 0xb22222ff + , "floralwhite", 0xfffaf0ff + , "forestgreen", 0x228b22ff + , "fuchsia", 0xff00ffff + , "gainsboro", 0xdcdcdcff + , "ghostwhite", 0xf8f8ffff + , "gold", 0xffd700ff + , "goldenrod", 0xdaa520ff + , "gray", 0x808080ff + , "green", 0x008000ff + , "greenyellow", 0xadff2fff + , "honeydew", 0xf0fff0ff + , "hotpink", 0xff69b4ff + , "indianred ", 0xcd5c5cff + , "indigo ", 0x4b0082ff + , "ivory", 0xfffff0ff + , "khaki", 0xf0e68cff + , "lavender", 0xe6e6faff + , "lavenderblush", 0xfff0f5ff + , "lawngreen", 0x7cfc00ff + , "lemonchiffon", 0xfffacdff + , "lightblue", 0xadd8e6ff + , "lightcoral", 0xf08080ff + , "lightcyan", 0xe0ffffff + , "lightgoldenrodyellow", 0xfafad2ff + , "lightgrey", 0xd3d3d3ff + , "lightgreen", 0x90ee90ff + , "lightpink", 0xffb6c1ff + , "lightsalmon", 0xffa07aff + , "lightseagreen", 0x20b2aaff + , "lightskyblue", 0x87cefaff + , "lightslateblue", 0x8470ffff + , "lightslategray", 0x778899ff + , "lightsteelblue", 0xb0c4deff + , "lightyellow", 0xffffe0ff + , "lime", 0x00ff00ff + , "limegreen", 0x32cd32ff + , "linen", 0xfaf0e6ff + , "magenta", 0xff00ffff + , "maroon", 0x800000ff + , "mediumaquamarine", 0x66cdaaff + , "mediumblue", 0x0000cdff + , "mediumorchid", 0xba55d3ff + , "mediumpurple", 0x9370d8ff + , "mediumseagreen", 0x3cb371ff + , "mediumslateblue", 0x7b68eeff + , "mediumspringgreen", 0x00fa9aff + , "mediumturquoise", 0x48d1ccff + , "mediumvioletred", 0xc71585ff + , "midnightblue", 0x191970ff + , "mintcream", 0xf5fffaff + , "mistyrose", 0xffe4e1ff + , "moccasin", 0xffe4b5ff + , "navajowhite", 0xffdeadff + , "navy", 0x000080ff + , "oldlace", 0xfdf5e6ff + , "olive", 0x808000ff + , "olivedrab", 0x6b8e23ff + , "orange", 0xffa500ff + , "orangered", 0xff4500ff + , "orchid", 0xda70d6ff + , "palegoldenrod", 0xeee8aaff + , "palegreen", 0x98fb98ff + , "paleturquoise", 0xafeeeeff + , "palevioletred", 0xd87093ff + , "papayawhip", 0xffefd5ff + , "peachpuff", 0xffdab9ff + , "peru", 0xcd853fff + , "pink", 0xffc0cbff + , "plum", 0xdda0ddff + , "powderblue", 0xb0e0e6ff + , "purple", 0x800080ff + , "red", 0xff0000ff + , "rosybrown", 0xbc8f8fff + , "royalblue", 0x4169e1ff + , "saddlebrown", 0x8b4513ff + , "salmon", 0xfa8072ff + , "sandybrown", 0xf4a460ff + , "seagreen", 0x2e8b57ff + , "seashell", 0xfff5eeff + , "sienna", 0xa0522dff + , "silver", 0xc0c0c0ff + , "skyblue", 0x87ceebff + , "slateblue", 0x6a5acdff + , "slategray", 0x708090ff + , "snow", 0xfffafaff + , "springgreen", 0x00ff7fff + , "steelblue", 0x4682b4ff + , "tan", 0xd2b48cff + , "teal", 0x008080ff + , "thistle", 0xd8bfd8ff + , "tomato", 0xff6347ff + , "turquoise", 0x40e0d0ff + , "violet", 0xee82eeff + , "violetred", 0xd02090ff + , "wheat", 0xf5deb3ff + , "white", 0xffffffff + , "whitesmoke", 0xf5f5f5ff + , "yellow", 0xffff00ff + , "yellowgreen", 0x9acd32ff + , NULL, NULL +}; + +/* + * Hex digit int val. + */ + +static int +h(char c) { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return c - '0'; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + return (c - 'a') + 10; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + return (c - 'A') + 10; + } + return 0; +} + +/* + * Return rgba from (r,g,b,a). + */ + +int32_t +rgba_from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + return + r << 24 + | g << 16 + | b << 8 + | a; +} + +/* + * Return rgba from (r,g,b). + */ + +int32_t +rgba_from_rgb(uint8_t r, uint8_t g, uint8_t b) { + return rgba_from_rgba(r, g, b, 0); +} + +/* + * Return rgb from "#RRGGBB". + */ + +int32_t +rgba_from_hex6_string(const char *str) { + return rgba_from_rgb( + (h(str[0]) << 4) + h(str[1]) + , (h(str[2]) << 4) + h(str[3]) + , (h(str[4]) << 4) + h(str[5]) + ); +} + +/* + * Return rgb from "#RGB" + */ + +int32_t +rgba_from_hex3_string(const char *str) { + return rgba_from_rgb( + (h(str[0]) << 4) + h(str[0]) + , (h(str[1]) << 4) + h(str[1]) + , (h(str[2]) << 4) + h(str[2]) + ); +} + +/* + * Return rgb from "rgb()" + */ + +int32_t +rgba_from_rgb_string(const char *str) { + if (str == strnstr(str, "rgb(", 4)) { + str += 4; + WHITESPACE; + uint8_t r = 0, g = 0, b = 0; + CHANNEL(r); + CHANNEL(g); + CHANNEL(b); + return rgba_from_rgb(r, g, b); + } + return -1; +} + +/* + * Return rgb from "rgba()" + */ + +int32_t +rgba_from_rgba_string(const char *str) { + if (str == strnstr(str, "rgba(", 5)) { + str += 5; + WHITESPACE; + uint8_t r = 0, g = 0, b = 0; + float a = 0; + CHANNEL(r); + CHANNEL(g); + CHANNEL(b); + // TODO: less strict + if ('1' == *str) { + a = 1; + } else { + if ('0' == *str) a = 0, ++str; + if ('.' == *str) { + ++str; + float n = .1; + while (*str >= '0' && *str <= '9') { + a += (*str++ - '0') * n; + n *= .1; + } + } + } + return rgba_from_rgba(r, g, b, a * 255); + } + return -1; +} + +/* + * Return rgb from: + * + * - "#RGB" + * - "#RRGGBB" + * + */ + +int32_t +rgba_from_hex_string(const char *str) { + size_t len = strlen(str); + if (6 == len) return rgba_from_hex6_string(str); + if (3 == len) return rgba_from_hex3_string(str); + return -1; +} + +/* + * Return named color value. + */ + +int32_t +rgba_from_name_string(const char *str) { + int i = 0; + struct named_color color; + while ((color = named_colors[i++]).name) { + if (*str == *color.name && 0 == strcmp(str, color.name)) + return color.val; + } + return -1; +} + +/* + * Return rgb from: + * + * - #RGB + * - #RRGGBB + * - rgb(r,g,b) + * - rgba(r,g,b,a) + * - name + * + */ + +int32_t +rgba_from_string(const char *str) { + if ('#' == str[0]) + return rgba_from_hex_string(++str); + if (str == strnstr(str, "rgba", 4)) + return rgba_from_rgba_string(str); + if (str == strnstr(str, "rgb", 3)) + return rgba_from_rgb_string(str); + return rgba_from_name_string(str); +} + +/* + * Inspect the given rgba color. + */ + +void +rgba_inspect(int32_t rgba) { + printf("rgba(%d,%d,%d,%d)\n" + , rgba >> 24 & 0xFF + , rgba >> 16 & 0xFF + , rgba >> 8 & 0xFF + , rgba & 0xFF + ); +} From 13e4ecf68ca8b841cea5268b587c8bb8b20b21bb Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 14:30:58 -0800 Subject: [PATCH 06/19] make g++ stop bitching --- src/CanvasRenderingContext2d.cc | 2 +- src/CanvasRenderingContext2d.h | 9 +- src/color.h | 314 +++++++++++++++++--------------- 3 files changed, 170 insertions(+), 155 deletions(-) diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index c8bac13..ece8639 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -1018,7 +1018,7 @@ Context2d::SetFillColor(const Arguments &args) { HandleScope scope; if (!args[0]->IsString()) return Undefined(); String::AsciiValue str(args[0]); - printf("%s\n", *str); + uint32_t color = rgba_from_string(*str); Context2d *context = ObjectWrap::Unwrap(args.This()); context->state->fillPattern = NULL; //RGBA(context->state->fill,r,g,b,a); diff --git a/src/CanvasRenderingContext2d.h b/src/CanvasRenderingContext2d.h index da89432..d5dd0e4 100644 --- a/src/CanvasRenderingContext2d.h +++ b/src/CanvasRenderingContext2d.h @@ -8,17 +8,10 @@ #ifndef __NODE_CONTEXT2D_H__ #define __NODE_CONTEXT2D_H__ +#include "color.h" #include "Canvas.h" #include "CanvasGradient.h" -/* - * RGBA struct used to retain values of fill/stroke. - */ - -typedef struct { - double r, g, b, a; -} rgba_t; - /* * State struct. * diff --git a/src/color.h b/src/color.h index b1730f9..e95af90 100644 --- a/src/color.h +++ b/src/color.h @@ -9,6 +9,14 @@ #include #include +/* + * RGBA struct. + */ + +typedef struct { + double r, g, b, a; +} rgba_t; + /* * Consume whitespace. */ @@ -36,154 +44,154 @@ */ static struct named_color { - char *name; + const char *name; uint32_t val; } named_colors[] = { - "transparent", 0xffffff00 - , "aliceblue", 0xf0f8ffff - , "antiquewhite", 0xfaebd7ff - , "aqua", 0x00ffffff - , "aquamarine", 0x7fffd4ff - , "azure", 0xf0ffffff - , "beige", 0xf5f5dcff - , "bisque", 0xffe4c4ff - , "black", 0x000000ff - , "blanchedalmond", 0xffebcdff - , "blue", 0x0000ffff - , "blueviolet", 0x8a2be2ff - , "brown", 0xa52a2aff - , "burlywood", 0xdeb887ff - , "cadetblue", 0x5f9ea0ff - , "chartreuse", 0x7fff00ff - , "chocolate", 0xd2691eff - , "coral", 0xff7f50ff - , "cornflowerblue", 0x6495edff - , "cornsilk", 0xfff8dcff - , "crimson", 0xdc143cff - , "cyan", 0x00ffffff - , "darkblue", 0x00008bff - , "darkcyan", 0x008b8bff - , "darkgoldenrod", 0xb8860bff - , "darkgray", 0xa9a9a9ff - , "darkgreen", 0x006400ff - , "darkkhaki", 0xbdb76bff - , "darkmagenta", 0x8b008bff - , "darkolivegreen", 0x556b2fff - , "darkorange", 0xff8c00ff - , "darkorchid", 0x9932ccff - , "darkred", 0x8b0000ff - , "darksalmon", 0xe9967aff - , "darkseagreen", 0x8fbc8fff - , "darkslateblue", 0x483d8bff - , "darkslategray", 0x2f4f4fff - , "darkturquoise", 0x00ced1ff - , "darkviolet", 0x9400d3ff - , "deeppink", 0xff1493ff - , "deepskyblue", 0x00bfffff - , "dimgray", 0x696969ff - , "dodgerblue", 0x1e90ffff - , "feldspar", 0xd19275ff - , "firebrick", 0xb22222ff - , "floralwhite", 0xfffaf0ff - , "forestgreen", 0x228b22ff - , "fuchsia", 0xff00ffff - , "gainsboro", 0xdcdcdcff - , "ghostwhite", 0xf8f8ffff - , "gold", 0xffd700ff - , "goldenrod", 0xdaa520ff - , "gray", 0x808080ff - , "green", 0x008000ff - , "greenyellow", 0xadff2fff - , "honeydew", 0xf0fff0ff - , "hotpink", 0xff69b4ff - , "indianred ", 0xcd5c5cff - , "indigo ", 0x4b0082ff - , "ivory", 0xfffff0ff - , "khaki", 0xf0e68cff - , "lavender", 0xe6e6faff - , "lavenderblush", 0xfff0f5ff - , "lawngreen", 0x7cfc00ff - , "lemonchiffon", 0xfffacdff - , "lightblue", 0xadd8e6ff - , "lightcoral", 0xf08080ff - , "lightcyan", 0xe0ffffff - , "lightgoldenrodyellow", 0xfafad2ff - , "lightgrey", 0xd3d3d3ff - , "lightgreen", 0x90ee90ff - , "lightpink", 0xffb6c1ff - , "lightsalmon", 0xffa07aff - , "lightseagreen", 0x20b2aaff - , "lightskyblue", 0x87cefaff - , "lightslateblue", 0x8470ffff - , "lightslategray", 0x778899ff - , "lightsteelblue", 0xb0c4deff - , "lightyellow", 0xffffe0ff - , "lime", 0x00ff00ff - , "limegreen", 0x32cd32ff - , "linen", 0xfaf0e6ff - , "magenta", 0xff00ffff - , "maroon", 0x800000ff - , "mediumaquamarine", 0x66cdaaff - , "mediumblue", 0x0000cdff - , "mediumorchid", 0xba55d3ff - , "mediumpurple", 0x9370d8ff - , "mediumseagreen", 0x3cb371ff - , "mediumslateblue", 0x7b68eeff - , "mediumspringgreen", 0x00fa9aff - , "mediumturquoise", 0x48d1ccff - , "mediumvioletred", 0xc71585ff - , "midnightblue", 0x191970ff - , "mintcream", 0xf5fffaff - , "mistyrose", 0xffe4e1ff - , "moccasin", 0xffe4b5ff - , "navajowhite", 0xffdeadff - , "navy", 0x000080ff - , "oldlace", 0xfdf5e6ff - , "olive", 0x808000ff - , "olivedrab", 0x6b8e23ff - , "orange", 0xffa500ff - , "orangered", 0xff4500ff - , "orchid", 0xda70d6ff - , "palegoldenrod", 0xeee8aaff - , "palegreen", 0x98fb98ff - , "paleturquoise", 0xafeeeeff - , "palevioletred", 0xd87093ff - , "papayawhip", 0xffefd5ff - , "peachpuff", 0xffdab9ff - , "peru", 0xcd853fff - , "pink", 0xffc0cbff - , "plum", 0xdda0ddff - , "powderblue", 0xb0e0e6ff - , "purple", 0x800080ff - , "red", 0xff0000ff - , "rosybrown", 0xbc8f8fff - , "royalblue", 0x4169e1ff - , "saddlebrown", 0x8b4513ff - , "salmon", 0xfa8072ff - , "sandybrown", 0xf4a460ff - , "seagreen", 0x2e8b57ff - , "seashell", 0xfff5eeff - , "sienna", 0xa0522dff - , "silver", 0xc0c0c0ff - , "skyblue", 0x87ceebff - , "slateblue", 0x6a5acdff - , "slategray", 0x708090ff - , "snow", 0xfffafaff - , "springgreen", 0x00ff7fff - , "steelblue", 0x4682b4ff - , "tan", 0xd2b48cff - , "teal", 0x008080ff - , "thistle", 0xd8bfd8ff - , "tomato", 0xff6347ff - , "turquoise", 0x40e0d0ff - , "violet", 0xee82eeff - , "violetred", 0xd02090ff - , "wheat", 0xf5deb3ff - , "white", 0xffffffff - , "whitesmoke", 0xf5f5f5ff - , "yellow", 0xffff00ff - , "yellowgreen", 0x9acd32ff - , NULL, NULL + {"transparent", 0xffffff00} + , {"aliceblue", 0xf0f8ffff} + , {"antiquewhite", 0xfaebd7ff} + , {"aqua", 0x00ffffff} + , {"aquamarine", 0x7fffd4ff} + , {"azure", 0xf0ffffff} + , {"beige", 0xf5f5dcff} + , {"bisque", 0xffe4c4ff} + , {"black", 0x000000ff} + , {"blanchedalmond", 0xffebcdff} + , {"blue", 0x0000ffff} + , {"blueviolet", 0x8a2be2ff} + , {"brown", 0xa52a2aff} + , {"burlywood", 0xdeb887ff} + , {"cadetblue", 0x5f9ea0ff} + , {"chartreuse", 0x7fff00ff} + , {"chocolate", 0xd2691eff} + , {"coral", 0xff7f50ff} + , {"cornflowerblue", 0x6495edff} + , {"cornsilk", 0xfff8dcff} + , {"crimson", 0xdc143cff} + , {"cyan", 0x00ffffff} + , {"darkblue", 0x00008bff} + , {"darkcyan", 0x008b8bff} + , {"darkgoldenrod", 0xb8860bff} + , {"darkgray", 0xa9a9a9ff} + , {"darkgreen", 0x006400ff} + , {"darkkhaki", 0xbdb76bff} + , {"darkmagenta", 0x8b008bff} + , {"darkolivegreen", 0x556b2fff} + , {"darkorange", 0xff8c00ff} + , {"darkorchid", 0x9932ccff} + , {"darkred", 0x8b0000ff} + , {"darksalmon", 0xe9967aff} + , {"darkseagreen", 0x8fbc8fff} + , {"darkslateblue", 0x483d8bff} + , {"darkslategray", 0x2f4f4fff} + , {"darkturquoise", 0x00ced1ff} + , {"darkviolet", 0x9400d3ff} + , {"deeppink", 0xff1493ff} + , {"deepskyblue", 0x00bfffff} + , {"dimgray", 0x696969ff} + , {"dodgerblue", 0x1e90ffff} + , {"feldspar", 0xd19275ff} + , {"firebrick", 0xb22222ff} + , {"floralwhite", 0xfffaf0ff} + , {"forestgreen", 0x228b22ff} + , {"fuchsia", 0xff00ffff} + , {"gainsboro", 0xdcdcdcff} + , {"ghostwhite", 0xf8f8ffff} + , {"gold", 0xffd700ff} + , {"goldenrod", 0xdaa520ff} + , {"gray", 0x808080ff} + , {"green", 0x008000ff} + , {"greenyellow", 0xadff2fff} + , {"honeydew", 0xf0fff0ff} + , {"hotpink", 0xff69b4ff} + , {"indianred ", 0xcd5c5cff} + , {"indigo ", 0x4b0082ff} + , {"ivory", 0xfffff0ff} + , {"khaki", 0xf0e68cff} + , {"lavender", 0xe6e6faff} + , {"lavenderblush", 0xfff0f5ff} + , {"lawngreen", 0x7cfc00ff} + , {"lemonchiffon", 0xfffacdff} + , {"lightblue", 0xadd8e6ff} + , {"lightcoral", 0xf08080ff} + , {"lightcyan", 0xe0ffffff} + , {"lightgoldenrodyellow", 0xfafa} + , {"lightgrey", 0xd3d3d3ff} + , {"lightgreen", 0x90ee90ff} + , {"lightpink", 0xffb6c1ff} + , {"lightsalmon", 0xffa07aff} + , {"lightseagreen", 0x20b2aaff} + , {"lightskyblue", 0x87cefaff} + , {"lightslateblue", 0x8470ffff} + , {"lightslategray", 0x778899ff} + , {"lightsteelblue", 0xb0c4deff} + , {"lightyellow", 0xffffe0ff} + , {"lime", 0x00ff00ff} + , {"limegreen", 0x32cd32ff} + , {"linen", 0xfaf0e6ff} + , {"magenta", 0xff00ffff} + , {"maroon", 0x800000ff} + , {"mediumaquamarine", 0x66cdaaff} + , {"mediumblue", 0x0000cdff} + , {"mediumorchid", 0xba55d3ff} + , {"mediumpurple", 0x9370d8ff} + , {"mediumseagreen", 0x3cb371ff} + , {"mediumslateblue", 0x7b68eeff} + , {"mediumspringgreen", 0x00fa9af} + , {"mediumturquoise", 0x48d1ccff} + , {"mediumvioletred", 0xc71585ff} + , {"midnightblue", 0x191970ff} + , {"mintcream", 0xf5fffaff} + , {"mistyrose", 0xffe4e1ff} + , {"moccasin", 0xffe4b5ff} + , {"navajowhite", 0xffdeadff} + , {"navy", 0x000080ff} + , {"oldlace", 0xfdf5e6ff} + , {"olive", 0x808000ff} + , {"olivedrab", 0x6b8e23ff} + , {"orange", 0xffa500ff} + , {"orangered", 0xff4500ff} + , {"orchid", 0xda70d6ff} + , {"palegoldenrod", 0xeee8aaff} + , {"palegreen", 0x98fb98ff} + , {"paleturquoise", 0xafeeeeff} + , {"palevioletred", 0xd87093ff} + , {"papayawhip", 0xffefd5ff} + , {"peachpuff", 0xffdab9ff} + , {"peru", 0xcd853fff} + , {"pink", 0xffc0cbff} + , {"plum", 0xdda0ddff} + , {"powderblue", 0xb0e0e6ff} + , {"purple", 0x800080ff} + , {"red", 0xff0000ff} + , {"rosybrown", 0xbc8f8fff} + , {"royalblue", 0x4169e1ff} + , {"saddlebrown", 0x8b4513ff} + , {"salmon", 0xfa8072ff} + , {"sandybrown", 0xf4a460ff} + , {"seagreen", 0x2e8b57ff} + , {"seashell", 0xfff5eeff} + , {"sienna", 0xa0522dff} + , {"silver", 0xc0c0c0ff} + , {"skyblue", 0x87ceebff} + , {"slateblue", 0x6a5acdff} + , {"slategray", 0x708090ff} + , {"snow", 0xfffafaff} + , {"springgreen", 0x00ff7fff} + , {"steelblue", 0x4682b4ff} + , {"tan", 0xd2b48cff} + , {"teal", 0x008080ff} + , {"thistle", 0xd8bfd8ff} + , {"tomato", 0xff6347ff} + , {"turquoise", 0x40e0d0ff} + , {"violet", 0xee82eeff} + , {"violetred", 0xd02090ff} + , {"wheat", 0xf5deb3ff} + , {"white", 0xffffffff} + , {"whitesmoke", 0xf5f5f5ff} + , {"yellow", 0xffff00ff} + , {"yellowgreen", 0x9acd32ff} + , {NULL, NULL} }; /* @@ -222,6 +230,20 @@ h(char c) { return 0; } +/* + * Return rgba_t from rgba. + */ + +rgba_t +rgba_create(uint32_t rgba) { + rgba_t color; + color.r = rgba >> 24; + color.g = rgba >> 16; + color.b = rgba >> 8; + color.a = rgba; + return color; +} + /* * Return rgba from (r,g,b,a). */ From 62a9f398fb1928bd178cd522086f500cd8d10434 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 14:33:45 -0800 Subject: [PATCH 07/19] wrap color.h --- src/color.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/color.h b/src/color.h index e95af90..03dbe7c 100644 --- a/src/color.h +++ b/src/color.h @@ -5,7 +5,9 @@ // Copyright (c) 2010 LearnBoost // -#include +#ifndef __COLOR_PARSER_H__ +#define __COLOR_PARSER_H__ + #include #include @@ -248,7 +250,7 @@ rgba_create(uint32_t rgba) { * Return rgba from (r,g,b,a). */ -int32_t +inline int32_t rgba_from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { return r << 24 @@ -409,3 +411,5 @@ rgba_inspect(int32_t rgba) { , rgba & 0xFF ); } + +#endif /* __COLOR_PARSER_H__ */ From c04f70e24096fa178040165a3ffa2367e27fc663 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 14:47:55 -0800 Subject: [PATCH 08/19] Added color.cc --- src/color.cc | 401 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/color.h | 381 ++---------------------------------------------- 2 files changed, 414 insertions(+), 368 deletions(-) create mode 100644 src/color.cc diff --git a/src/color.cc b/src/color.cc new file mode 100644 index 0000000..7865c6c --- /dev/null +++ b/src/color.cc @@ -0,0 +1,401 @@ + +// +// color.cc +// +// Copyright (c) 2010 LearnBoost +// + +#include "color.h" + +/* + * Consume whitespace. + */ + +#define WHITESPACE \ + while (' ' == *str) ++str; + +/* + * Parse color channel value + */ + +#define CHANNEL(NAME) \ + if (*str >= '0' && *str <= '9') { \ + do { \ + NAME *= 10; \ + NAME += *str++ - '0'; \ + } while (*str >= '0' && *str <= '9'); \ + } else { \ + return -1; \ + } \ + while (' ' == *str || ',' == *str) str++; + +/* + * Named colors. + */ + +static struct named_color { + const char *name; + uint32_t val; +} named_colors[] = { + {"transparent", 0xffffff00} + , {"aliceblue", 0xf0f8ffff} + , {"antiquewhite", 0xfaebd7ff} + , {"aqua", 0x00ffffff} + , {"aquamarine", 0x7fffd4ff} + , {"azure", 0xf0ffffff} + , {"beige", 0xf5f5dcff} + , {"bisque", 0xffe4c4ff} + , {"black", 0x000000ff} + , {"blanchedalmond", 0xffebcdff} + , {"blue", 0x0000ffff} + , {"blueviolet", 0x8a2be2ff} + , {"brown", 0xa52a2aff} + , {"burlywood", 0xdeb887ff} + , {"cadetblue", 0x5f9ea0ff} + , {"chartreuse", 0x7fff00ff} + , {"chocolate", 0xd2691eff} + , {"coral", 0xff7f50ff} + , {"cornflowerblue", 0x6495edff} + , {"cornsilk", 0xfff8dcff} + , {"crimson", 0xdc143cff} + , {"cyan", 0x00ffffff} + , {"darkblue", 0x00008bff} + , {"darkcyan", 0x008b8bff} + , {"darkgoldenrod", 0xb8860bff} + , {"darkgray", 0xa9a9a9ff} + , {"darkgreen", 0x006400ff} + , {"darkkhaki", 0xbdb76bff} + , {"darkmagenta", 0x8b008bff} + , {"darkolivegreen", 0x556b2fff} + , {"darkorange", 0xff8c00ff} + , {"darkorchid", 0x9932ccff} + , {"darkred", 0x8b0000ff} + , {"darksalmon", 0xe9967aff} + , {"darkseagreen", 0x8fbc8fff} + , {"darkslateblue", 0x483d8bff} + , {"darkslategray", 0x2f4f4fff} + , {"darkturquoise", 0x00ced1ff} + , {"darkviolet", 0x9400d3ff} + , {"deeppink", 0xff1493ff} + , {"deepskyblue", 0x00bfffff} + , {"dimgray", 0x696969ff} + , {"dodgerblue", 0x1e90ffff} + , {"feldspar", 0xd19275ff} + , {"firebrick", 0xb22222ff} + , {"floralwhite", 0xfffaf0ff} + , {"forestgreen", 0x228b22ff} + , {"fuchsia", 0xff00ffff} + , {"gainsboro", 0xdcdcdcff} + , {"ghostwhite", 0xf8f8ffff} + , {"gold", 0xffd700ff} + , {"goldenrod", 0xdaa520ff} + , {"gray", 0x808080ff} + , {"green", 0x008000ff} + , {"greenyellow", 0xadff2fff} + , {"honeydew", 0xf0fff0ff} + , {"hotpink", 0xff69b4ff} + , {"indianred ", 0xcd5c5cff} + , {"indigo ", 0x4b0082ff} + , {"ivory", 0xfffff0ff} + , {"khaki", 0xf0e68cff} + , {"lavender", 0xe6e6faff} + , {"lavenderblush", 0xfff0f5ff} + , {"lawngreen", 0x7cfc00ff} + , {"lemonchiffon", 0xfffacdff} + , {"lightblue", 0xadd8e6ff} + , {"lightcoral", 0xf08080ff} + , {"lightcyan", 0xe0ffffff} + , {"lightgoldenrodyellow", 0xfafa} + , {"lightgrey", 0xd3d3d3ff} + , {"lightgreen", 0x90ee90ff} + , {"lightpink", 0xffb6c1ff} + , {"lightsalmon", 0xffa07aff} + , {"lightseagreen", 0x20b2aaff} + , {"lightskyblue", 0x87cefaff} + , {"lightslateblue", 0x8470ffff} + , {"lightslategray", 0x778899ff} + , {"lightsteelblue", 0xb0c4deff} + , {"lightyellow", 0xffffe0ff} + , {"lime", 0x00ff00ff} + , {"limegreen", 0x32cd32ff} + , {"linen", 0xfaf0e6ff} + , {"magenta", 0xff00ffff} + , {"maroon", 0x800000ff} + , {"mediumaquamarine", 0x66cdaaff} + , {"mediumblue", 0x0000cdff} + , {"mediumorchid", 0xba55d3ff} + , {"mediumpurple", 0x9370d8ff} + , {"mediumseagreen", 0x3cb371ff} + , {"mediumslateblue", 0x7b68eeff} + , {"mediumspringgreen", 0x00fa9af} + , {"mediumturquoise", 0x48d1ccff} + , {"mediumvioletred", 0xc71585ff} + , {"midnightblue", 0x191970ff} + , {"mintcream", 0xf5fffaff} + , {"mistyrose", 0xffe4e1ff} + , {"moccasin", 0xffe4b5ff} + , {"navajowhite", 0xffdeadff} + , {"navy", 0x000080ff} + , {"oldlace", 0xfdf5e6ff} + , {"olive", 0x808000ff} + , {"olivedrab", 0x6b8e23ff} + , {"orange", 0xffa500ff} + , {"orangered", 0xff4500ff} + , {"orchid", 0xda70d6ff} + , {"palegoldenrod", 0xeee8aaff} + , {"palegreen", 0x98fb98ff} + , {"paleturquoise", 0xafeeeeff} + , {"palevioletred", 0xd87093ff} + , {"papayawhip", 0xffefd5ff} + , {"peachpuff", 0xffdab9ff} + , {"peru", 0xcd853fff} + , {"pink", 0xffc0cbff} + , {"plum", 0xdda0ddff} + , {"powderblue", 0xb0e0e6ff} + , {"purple", 0x800080ff} + , {"red", 0xff0000ff} + , {"rosybrown", 0xbc8f8fff} + , {"royalblue", 0x4169e1ff} + , {"saddlebrown", 0x8b4513ff} + , {"salmon", 0xfa8072ff} + , {"sandybrown", 0xf4a460ff} + , {"seagreen", 0x2e8b57ff} + , {"seashell", 0xfff5eeff} + , {"sienna", 0xa0522dff} + , {"silver", 0xc0c0c0ff} + , {"skyblue", 0x87ceebff} + , {"slateblue", 0x6a5acdff} + , {"slategray", 0x708090ff} + , {"snow", 0xfffafaff} + , {"springgreen", 0x00ff7fff} + , {"steelblue", 0x4682b4ff} + , {"tan", 0xd2b48cff} + , {"teal", 0x008080ff} + , {"thistle", 0xd8bfd8ff} + , {"tomato", 0xff6347ff} + , {"turquoise", 0x40e0d0ff} + , {"violet", 0xee82eeff} + , {"violetred", 0xd02090ff} + , {"wheat", 0xf5deb3ff} + , {"white", 0xffffffff} + , {"whitesmoke", 0xf5f5f5ff} + , {"yellow", 0xffff00ff} + , {"yellowgreen", 0x9acd32ff} + , {NULL, NULL} +}; + +/* + * Hex digit int val. + */ + +static int +h(char c) { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return c - '0'; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + return (c - 'a') + 10; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + return (c - 'A') + 10; + } + return 0; +} + +/* + * Return rgba_t from rgba. + */ + +rgba_t +rgba_create(uint32_t rgba) { + rgba_t color; + color.r = rgba >> 24; + color.g = rgba >> 16; + color.b = rgba >> 8; + color.a = rgba; + return color; +} + +/* + * Return rgba from (r,g,b,a). + */ + +inline int32_t +rgba_from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + return + r << 24 + | g << 16 + | b << 8 + | a; +} + +/* + * Return rgba from (r,g,b). + */ + +int32_t +rgba_from_rgb(uint8_t r, uint8_t g, uint8_t b) { + return rgba_from_rgba(r, g, b, 0); +} + +/* + * Return rgb from "#RRGGBB". + */ + +int32_t +rgba_from_hex6_string(const char *str) { + return rgba_from_rgb( + (h(str[0]) << 4) + h(str[1]) + , (h(str[2]) << 4) + h(str[3]) + , (h(str[4]) << 4) + h(str[5]) + ); +} + +/* + * Return rgb from "#RGB" + */ + +int32_t +rgba_from_hex3_string(const char *str) { + return rgba_from_rgb( + (h(str[0]) << 4) + h(str[0]) + , (h(str[1]) << 4) + h(str[1]) + , (h(str[2]) << 4) + h(str[2]) + ); +} + +/* + * Return rgb from "rgb()" + */ + +int32_t +rgba_from_rgb_string(const char *str) { + if (str == strnstr(str, "rgb(", 4)) { + str += 4; + WHITESPACE; + uint8_t r = 0, g = 0, b = 0; + CHANNEL(r); + CHANNEL(g); + CHANNEL(b); + return rgba_from_rgb(r, g, b); + } + return -1; +} + +/* + * Return rgb from "rgba()" + */ + +int32_t +rgba_from_rgba_string(const char *str) { + if (str == strnstr(str, "rgba(", 5)) { + str += 5; + WHITESPACE; + uint8_t r = 0, g = 0, b = 0; + float a = 0; + CHANNEL(r); + CHANNEL(g); + CHANNEL(b); + // TODO: less strict + if ('1' == *str) { + a = 1; + } else { + if ('0' == *str) a = 0, ++str; + if ('.' == *str) { + ++str; + float n = .1; + while (*str >= '0' && *str <= '9') { + a += (*str++ - '0') * n; + n *= .1; + } + } + } + return rgba_from_rgba(r, g, b, a * 255); + } + return -1; +} + +/* + * Return rgb from: + * + * - "#RGB" + * - "#RRGGBB" + * + */ + +int32_t +rgba_from_hex_string(const char *str) { + size_t len = strlen(str); + if (6 == len) return rgba_from_hex6_string(str); + if (3 == len) return rgba_from_hex3_string(str); + return -1; +} + +/* + * Return named color value. + */ + +int32_t +rgba_from_name_string(const char *str) { + int i = 0; + struct named_color color; + while ((color = named_colors[i++]).name) { + if (*str == *color.name && 0 == strcmp(str, color.name)) + return color.val; + } + return -1; +} + +/* + * Return rgb from: + * + * - #RGB + * - #RRGGBB + * - rgb(r,g,b) + * - rgba(r,g,b,a) + * - name + * + */ + +int32_t +rgba_from_string(const char *str) { + if ('#' == str[0]) + return rgba_from_hex_string(++str); + if (str == strnstr(str, "rgba", 4)) + return rgba_from_rgba_string(str); + if (str == strnstr(str, "rgb", 3)) + return rgba_from_rgb_string(str); + return rgba_from_name_string(str); +} + +/* + * Inspect the given rgba color. + */ + +void +rgba_inspect(int32_t rgba) { + printf("rgba(%d,%d,%d,%d)\n" + , rgba >> 24 & 0xFF + , rgba >> 16 & 0xFF + , rgba >> 8 & 0xFF + , rgba & 0xFF + ); +} diff --git a/src/color.h b/src/color.h index 03dbe7c..60eaf54 100644 --- a/src/color.h +++ b/src/color.h @@ -8,6 +8,7 @@ #ifndef __COLOR_PARSER_H__ #define __COLOR_PARSER_H__ +#include #include #include @@ -20,396 +21,40 @@ typedef struct { } rgba_t; /* - * Consume whitespace. - */ - -#define WHITESPACE \ - while (' ' == *str) ++str; - -/* - * Parse color channel value - */ - -#define CHANNEL(NAME) \ - if (*str >= '0' && *str <= '9') { \ - do { \ - NAME *= 10; \ - NAME += *str++ - '0'; \ - } while (*str >= '0' && *str <= '9'); \ - } else { \ - return -1; \ - } \ - while (' ' == *str || ',' == *str) str++; - -/* - * Named colors. - */ - -static struct named_color { - const char *name; - uint32_t val; -} named_colors[] = { - {"transparent", 0xffffff00} - , {"aliceblue", 0xf0f8ffff} - , {"antiquewhite", 0xfaebd7ff} - , {"aqua", 0x00ffffff} - , {"aquamarine", 0x7fffd4ff} - , {"azure", 0xf0ffffff} - , {"beige", 0xf5f5dcff} - , {"bisque", 0xffe4c4ff} - , {"black", 0x000000ff} - , {"blanchedalmond", 0xffebcdff} - , {"blue", 0x0000ffff} - , {"blueviolet", 0x8a2be2ff} - , {"brown", 0xa52a2aff} - , {"burlywood", 0xdeb887ff} - , {"cadetblue", 0x5f9ea0ff} - , {"chartreuse", 0x7fff00ff} - , {"chocolate", 0xd2691eff} - , {"coral", 0xff7f50ff} - , {"cornflowerblue", 0x6495edff} - , {"cornsilk", 0xfff8dcff} - , {"crimson", 0xdc143cff} - , {"cyan", 0x00ffffff} - , {"darkblue", 0x00008bff} - , {"darkcyan", 0x008b8bff} - , {"darkgoldenrod", 0xb8860bff} - , {"darkgray", 0xa9a9a9ff} - , {"darkgreen", 0x006400ff} - , {"darkkhaki", 0xbdb76bff} - , {"darkmagenta", 0x8b008bff} - , {"darkolivegreen", 0x556b2fff} - , {"darkorange", 0xff8c00ff} - , {"darkorchid", 0x9932ccff} - , {"darkred", 0x8b0000ff} - , {"darksalmon", 0xe9967aff} - , {"darkseagreen", 0x8fbc8fff} - , {"darkslateblue", 0x483d8bff} - , {"darkslategray", 0x2f4f4fff} - , {"darkturquoise", 0x00ced1ff} - , {"darkviolet", 0x9400d3ff} - , {"deeppink", 0xff1493ff} - , {"deepskyblue", 0x00bfffff} - , {"dimgray", 0x696969ff} - , {"dodgerblue", 0x1e90ffff} - , {"feldspar", 0xd19275ff} - , {"firebrick", 0xb22222ff} - , {"floralwhite", 0xfffaf0ff} - , {"forestgreen", 0x228b22ff} - , {"fuchsia", 0xff00ffff} - , {"gainsboro", 0xdcdcdcff} - , {"ghostwhite", 0xf8f8ffff} - , {"gold", 0xffd700ff} - , {"goldenrod", 0xdaa520ff} - , {"gray", 0x808080ff} - , {"green", 0x008000ff} - , {"greenyellow", 0xadff2fff} - , {"honeydew", 0xf0fff0ff} - , {"hotpink", 0xff69b4ff} - , {"indianred ", 0xcd5c5cff} - , {"indigo ", 0x4b0082ff} - , {"ivory", 0xfffff0ff} - , {"khaki", 0xf0e68cff} - , {"lavender", 0xe6e6faff} - , {"lavenderblush", 0xfff0f5ff} - , {"lawngreen", 0x7cfc00ff} - , {"lemonchiffon", 0xfffacdff} - , {"lightblue", 0xadd8e6ff} - , {"lightcoral", 0xf08080ff} - , {"lightcyan", 0xe0ffffff} - , {"lightgoldenrodyellow", 0xfafa} - , {"lightgrey", 0xd3d3d3ff} - , {"lightgreen", 0x90ee90ff} - , {"lightpink", 0xffb6c1ff} - , {"lightsalmon", 0xffa07aff} - , {"lightseagreen", 0x20b2aaff} - , {"lightskyblue", 0x87cefaff} - , {"lightslateblue", 0x8470ffff} - , {"lightslategray", 0x778899ff} - , {"lightsteelblue", 0xb0c4deff} - , {"lightyellow", 0xffffe0ff} - , {"lime", 0x00ff00ff} - , {"limegreen", 0x32cd32ff} - , {"linen", 0xfaf0e6ff} - , {"magenta", 0xff00ffff} - , {"maroon", 0x800000ff} - , {"mediumaquamarine", 0x66cdaaff} - , {"mediumblue", 0x0000cdff} - , {"mediumorchid", 0xba55d3ff} - , {"mediumpurple", 0x9370d8ff} - , {"mediumseagreen", 0x3cb371ff} - , {"mediumslateblue", 0x7b68eeff} - , {"mediumspringgreen", 0x00fa9af} - , {"mediumturquoise", 0x48d1ccff} - , {"mediumvioletred", 0xc71585ff} - , {"midnightblue", 0x191970ff} - , {"mintcream", 0xf5fffaff} - , {"mistyrose", 0xffe4e1ff} - , {"moccasin", 0xffe4b5ff} - , {"navajowhite", 0xffdeadff} - , {"navy", 0x000080ff} - , {"oldlace", 0xfdf5e6ff} - , {"olive", 0x808000ff} - , {"olivedrab", 0x6b8e23ff} - , {"orange", 0xffa500ff} - , {"orangered", 0xff4500ff} - , {"orchid", 0xda70d6ff} - , {"palegoldenrod", 0xeee8aaff} - , {"palegreen", 0x98fb98ff} - , {"paleturquoise", 0xafeeeeff} - , {"palevioletred", 0xd87093ff} - , {"papayawhip", 0xffefd5ff} - , {"peachpuff", 0xffdab9ff} - , {"peru", 0xcd853fff} - , {"pink", 0xffc0cbff} - , {"plum", 0xdda0ddff} - , {"powderblue", 0xb0e0e6ff} - , {"purple", 0x800080ff} - , {"red", 0xff0000ff} - , {"rosybrown", 0xbc8f8fff} - , {"royalblue", 0x4169e1ff} - , {"saddlebrown", 0x8b4513ff} - , {"salmon", 0xfa8072ff} - , {"sandybrown", 0xf4a460ff} - , {"seagreen", 0x2e8b57ff} - , {"seashell", 0xfff5eeff} - , {"sienna", 0xa0522dff} - , {"silver", 0xc0c0c0ff} - , {"skyblue", 0x87ceebff} - , {"slateblue", 0x6a5acdff} - , {"slategray", 0x708090ff} - , {"snow", 0xfffafaff} - , {"springgreen", 0x00ff7fff} - , {"steelblue", 0x4682b4ff} - , {"tan", 0xd2b48cff} - , {"teal", 0x008080ff} - , {"thistle", 0xd8bfd8ff} - , {"tomato", 0xff6347ff} - , {"turquoise", 0x40e0d0ff} - , {"violet", 0xee82eeff} - , {"violetred", 0xd02090ff} - , {"wheat", 0xf5deb3ff} - , {"white", 0xffffffff} - , {"whitesmoke", 0xf5f5f5ff} - , {"yellow", 0xffff00ff} - , {"yellowgreen", 0x9acd32ff} - , {NULL, NULL} -}; - -/* - * Hex digit int val. - */ - -static int -h(char c) { - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return c - '0'; - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - return (c - 'a') + 10; - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - return (c - 'A') + 10; - } - return 0; -} - -/* - * Return rgba_t from rgba. + * Prototypes. */ rgba_t -rgba_create(uint32_t rgba) { - rgba_t color; - color.r = rgba >> 24; - color.g = rgba >> 16; - color.b = rgba >> 8; - color.a = rgba; - return color; -} - -/* - * Return rgba from (r,g,b,a). - */ +rgba_create(uint32_t rgba); inline int32_t -rgba_from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return - r << 24 - | g << 16 - | b << 8 - | a; -} - -/* - * Return rgba from (r,g,b). - */ +rgba_from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a); int32_t -rgba_from_rgb(uint8_t r, uint8_t g, uint8_t b) { - return rgba_from_rgba(r, g, b, 0); -} - -/* - * Return rgb from "#RRGGBB". - */ +rgba_from_rgb(uint8_t r, uint8_t g, uint8_t b); int32_t -rgba_from_hex6_string(const char *str) { - return rgba_from_rgb( - (h(str[0]) << 4) + h(str[1]) - , (h(str[2]) << 4) + h(str[3]) - , (h(str[4]) << 4) + h(str[5]) - ); -} - -/* - * Return rgb from "#RGB" - */ +rgba_from_hex6_string(const char *str); int32_t -rgba_from_hex3_string(const char *str) { - return rgba_from_rgb( - (h(str[0]) << 4) + h(str[0]) - , (h(str[1]) << 4) + h(str[1]) - , (h(str[2]) << 4) + h(str[2]) - ); -} - -/* - * Return rgb from "rgb()" - */ +rgba_from_hex3_string(const char *str); int32_t -rgba_from_rgb_string(const char *str) { - if (str == strnstr(str, "rgb(", 4)) { - str += 4; - WHITESPACE; - uint8_t r = 0, g = 0, b = 0; - CHANNEL(r); - CHANNEL(g); - CHANNEL(b); - return rgba_from_rgb(r, g, b); - } - return -1; -} - -/* - * Return rgb from "rgba()" - */ +rgba_from_rgb_string(const char *str); int32_t -rgba_from_rgba_string(const char *str) { - if (str == strnstr(str, "rgba(", 5)) { - str += 5; - WHITESPACE; - uint8_t r = 0, g = 0, b = 0; - float a = 0; - CHANNEL(r); - CHANNEL(g); - CHANNEL(b); - // TODO: less strict - if ('1' == *str) { - a = 1; - } else { - if ('0' == *str) a = 0, ++str; - if ('.' == *str) { - ++str; - float n = .1; - while (*str >= '0' && *str <= '9') { - a += (*str++ - '0') * n; - n *= .1; - } - } - } - return rgba_from_rgba(r, g, b, a * 255); - } - return -1; -} - -/* - * Return rgb from: - * - * - "#RGB" - * - "#RRGGBB" - * - */ +rgba_from_rgba_string(const char *str); int32_t -rgba_from_hex_string(const char *str) { - size_t len = strlen(str); - if (6 == len) return rgba_from_hex6_string(str); - if (3 == len) return rgba_from_hex3_string(str); - return -1; -} - -/* - * Return named color value. - */ +rgba_from_hex_string(const char *str); int32_t -rgba_from_name_string(const char *str) { - int i = 0; - struct named_color color; - while ((color = named_colors[i++]).name) { - if (*str == *color.name && 0 == strcmp(str, color.name)) - return color.val; - } - return -1; -} - -/* - * Return rgb from: - * - * - #RGB - * - #RRGGBB - * - rgb(r,g,b) - * - rgba(r,g,b,a) - * - name - * - */ +rgba_from_name_string(const char *str); int32_t -rgba_from_string(const char *str) { - if ('#' == str[0]) - return rgba_from_hex_string(++str); - if (str == strnstr(str, "rgba", 4)) - return rgba_from_rgba_string(str); - if (str == strnstr(str, "rgb", 3)) - return rgba_from_rgb_string(str); - return rgba_from_name_string(str); -} - -/* - * Inspect the given rgba color. - */ +rgba_from_string(const char *str); void -rgba_inspect(int32_t rgba) { - printf("rgba(%d,%d,%d,%d)\n" - , rgba >> 24 & 0xFF - , rgba >> 16 & 0xFF - , rgba >> 8 & 0xFF - , rgba & 0xFF - ); -} +rgba_inspect(int32_t rgba); #endif /* __COLOR_PARSER_H__ */ From 82c8d562d6d5542c6dc47608d978fe49efdfe671 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 14:58:35 -0800 Subject: [PATCH 09/19] fixed rgba_create() --- src/CanvasRenderingContext2d.cc | 2 +- src/color.cc | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index ece8639..e142141 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -1018,7 +1018,7 @@ Context2d::SetFillColor(const Arguments &args) { HandleScope scope; if (!args[0]->IsString()) return Undefined(); String::AsciiValue str(args[0]); - uint32_t color = rgba_from_string(*str); + rgba_t color = rgba_create(rgba_from_string(*str)); Context2d *context = ObjectWrap::Unwrap(args.This()); context->state->fillPattern = NULL; //RGBA(context->state->fill,r,g,b,a); diff --git a/src/color.cc b/src/color.cc index 7865c6c..9a6a038 100644 --- a/src/color.cc +++ b/src/color.cc @@ -228,9 +228,9 @@ rgba_t rgba_create(uint32_t rgba) { rgba_t color; color.r = rgba >> 24; - color.g = rgba >> 16; - color.b = rgba >> 8; - color.a = rgba; + color.g = (rgba & 0x00ff0000) >> 16; + color.b = (rgba & 0x0000ff00) >> 8; + color.a = rgba & 0xff; return color; } From e2a95c9537dfb913571068620a794013cadab517 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 15:26:33 -0800 Subject: [PATCH 10/19] implementing color parser --- src/CanvasRenderingContext2d.cc | 37 ++++++++++++++++----------------- src/color.cc | 18 ++++++++-------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index e142141..77fb37c 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -17,16 +17,6 @@ Persistent Context2d::constructor; -/* - * Set RGBA. - */ - -#define RGBA(_,R,G,B,A) \ - _.r = R / 255 * 1; \ - _.g = G / 255 * 1; \ - _.b = B / 255 * 1; \ - _.a = A; \ - /* * Rectangle arg assertions. */ @@ -132,9 +122,11 @@ Context2d::Context2d(Canvas *canvas) { state->globalAlpha = 1; state->textAlignment = -1; state->fillPattern = state->strokePattern = NULL; - RGBA(state->fill,0,0,0,1); - RGBA(state->stroke,0,0,0,1); - RGBA(state->shadow,0,0,0,0); + rgba_t transparent = { 0,0,0,1 }; + rgba_t transparent_black = { 0,0,0,0 }; + state->fill = transparent; + state->stroke = transparent; + state->shadow = transparent_black; } /* @@ -1003,9 +995,12 @@ Context2d::SetStrokePattern(const Arguments &args) { Handle Context2d::SetShadowColor(const Arguments &args) { HandleScope scope; - RGBA_ARGS(0); + if (!args[0]->IsString()) return Undefined(); + String::AsciiValue str(args[0]); + uint32_t rgba = rgba_from_string(*str); + if (!rgba) return Undefined(); Context2d *context = ObjectWrap::Unwrap(args.This()); - RGBA(context->state->shadow,r,g,b,a); + context->state->shadow = rgba_create(rgba); return Undefined(); } @@ -1018,10 +1013,11 @@ Context2d::SetFillColor(const Arguments &args) { HandleScope scope; if (!args[0]->IsString()) return Undefined(); String::AsciiValue str(args[0]); - rgba_t color = rgba_create(rgba_from_string(*str)); + uint32_t rgba = rgba_from_string(*str); + if (!rgba) return Undefined(); Context2d *context = ObjectWrap::Unwrap(args.This()); context->state->fillPattern = NULL; - //RGBA(context->state->fill,r,g,b,a); + context->state->fill = rgba_create(rgba); return Undefined(); } @@ -1032,10 +1028,13 @@ Context2d::SetFillColor(const Arguments &args) { Handle Context2d::SetStrokeColor(const Arguments &args) { HandleScope scope; - RGBA_ARGS(0); + if (!args[0]->IsString()) return Undefined(); + String::AsciiValue str(args[0]); + uint32_t rgba = rgba_from_string(*str); + if (!rgba) return Undefined(); Context2d *context = ObjectWrap::Unwrap(args.This()); context->state->strokePattern = NULL; - RGBA(context->state->stroke,r,g,b,a); + context->state->stroke = rgba_create(rgba); return Undefined(); } diff --git a/src/color.cc b/src/color.cc index 9a6a038..0a05cbf 100644 --- a/src/color.cc +++ b/src/color.cc @@ -25,7 +25,7 @@ NAME += *str++ - '0'; \ } while (*str >= '0' && *str <= '9'); \ } else { \ - return -1; \ + return 0; \ } \ while (' ' == *str || ',' == *str) str++; @@ -227,10 +227,10 @@ h(char c) { rgba_t rgba_create(uint32_t rgba) { rgba_t color; - color.r = rgba >> 24; - color.g = (rgba & 0x00ff0000) >> 16; - color.b = (rgba & 0x0000ff00) >> 8; - color.a = rgba & 0xff; + color.r = (double) (rgba >> 24) / 255; + color.g = (double) ((rgba & 0x00ff0000) >> 16) / 255; + color.b = (double) ((rgba & 0x0000ff00) >> 8) / 255; + color.a = (double) (rgba & 0xff) / 255; return color; } @@ -297,7 +297,7 @@ rgba_from_rgb_string(const char *str) { CHANNEL(b); return rgba_from_rgb(r, g, b); } - return -1; + return 0; } /* @@ -330,7 +330,7 @@ rgba_from_rgba_string(const char *str) { } return rgba_from_rgba(r, g, b, a * 255); } - return -1; + return 0; } /* @@ -346,7 +346,7 @@ rgba_from_hex_string(const char *str) { size_t len = strlen(str); if (6 == len) return rgba_from_hex6_string(str); if (3 == len) return rgba_from_hex3_string(str); - return -1; + return 0; } /* @@ -361,7 +361,7 @@ rgba_from_name_string(const char *str) { if (*str == *color.name && 0 == strcmp(str, color.name)) return color.val; } - return -1; + return 0; } /* From 62fb1299a413478384afc1392401570e77ddd36b Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 15:54:13 -0800 Subject: [PATCH 11/19] rgba_from_string(const char *str, short *ok) --- src/CanvasRenderingContext2d.cc | 15 ++++++---- src/color.cc | 49 +++++++++++++++++---------------- src/color.h | 26 +---------------- 3 files changed, 35 insertions(+), 55 deletions(-) diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 77fb37c..63a1713 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -995,10 +995,11 @@ Context2d::SetStrokePattern(const Arguments &args) { Handle Context2d::SetShadowColor(const Arguments &args) { HandleScope scope; + short ok; if (!args[0]->IsString()) return Undefined(); String::AsciiValue str(args[0]); - uint32_t rgba = rgba_from_string(*str); - if (!rgba) return Undefined(); + uint32_t rgba = rgba_from_string(*str, &ok); + if (!ok) return Undefined(); Context2d *context = ObjectWrap::Unwrap(args.This()); context->state->shadow = rgba_create(rgba); return Undefined(); @@ -1011,10 +1012,11 @@ Context2d::SetShadowColor(const Arguments &args) { Handle Context2d::SetFillColor(const Arguments &args) { HandleScope scope; + short ok; if (!args[0]->IsString()) return Undefined(); String::AsciiValue str(args[0]); - uint32_t rgba = rgba_from_string(*str); - if (!rgba) return Undefined(); + uint32_t rgba = rgba_from_string(*str, &ok); + if (!ok) return Undefined(); Context2d *context = ObjectWrap::Unwrap(args.This()); context->state->fillPattern = NULL; context->state->fill = rgba_create(rgba); @@ -1028,10 +1030,11 @@ Context2d::SetFillColor(const Arguments &args) { Handle Context2d::SetStrokeColor(const Arguments &args) { HandleScope scope; + short ok; if (!args[0]->IsString()) return Undefined(); String::AsciiValue str(args[0]); - uint32_t rgba = rgba_from_string(*str); - if (!rgba) return Undefined(); + uint32_t rgba = rgba_from_string(*str, &ok); + if (!ok) return Undefined(); Context2d *context = ObjectWrap::Unwrap(args.This()); context->state->strokePattern = NULL; context->state->stroke = rgba_create(rgba); diff --git a/src/color.cc b/src/color.cc index 0a05cbf..3536fcc 100644 --- a/src/color.cc +++ b/src/color.cc @@ -238,7 +238,7 @@ rgba_create(uint32_t rgba) { * Return rgba from (r,g,b,a). */ -inline int32_t +static inline int32_t rgba_from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { return r << 24 @@ -251,7 +251,7 @@ rgba_from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { * Return rgba from (r,g,b). */ -int32_t +static int32_t rgba_from_rgb(uint8_t r, uint8_t g, uint8_t b) { return rgba_from_rgba(r, g, b, 0); } @@ -260,7 +260,7 @@ rgba_from_rgb(uint8_t r, uint8_t g, uint8_t b) { * Return rgb from "#RRGGBB". */ -int32_t +static int32_t rgba_from_hex6_string(const char *str) { return rgba_from_rgb( (h(str[0]) << 4) + h(str[1]) @@ -273,7 +273,7 @@ rgba_from_hex6_string(const char *str) { * Return rgb from "#RGB" */ -int32_t +static int32_t rgba_from_hex3_string(const char *str) { return rgba_from_rgb( (h(str[0]) << 4) + h(str[0]) @@ -286,8 +286,8 @@ rgba_from_hex3_string(const char *str) { * Return rgb from "rgb()" */ -int32_t -rgba_from_rgb_string(const char *str) { +static int32_t +rgba_from_rgb_string(const char *str, short *ok) { if (str == strnstr(str, "rgb(", 4)) { str += 4; WHITESPACE; @@ -295,17 +295,17 @@ rgba_from_rgb_string(const char *str) { CHANNEL(r); CHANNEL(g); CHANNEL(b); - return rgba_from_rgb(r, g, b); + return *ok = 1, rgba_from_rgb(r, g, b); } - return 0; + return *ok = 0; } /* * Return rgb from "rgba()" */ -int32_t -rgba_from_rgba_string(const char *str) { +static int32_t +rgba_from_rgba_string(const char *str, short *ok) { if (str == strnstr(str, "rgba(", 5)) { str += 5; WHITESPACE; @@ -328,9 +328,9 @@ rgba_from_rgba_string(const char *str) { } } } - return rgba_from_rgba(r, g, b, a * 255); + return *ok = 1, rgba_from_rgba(r, g, b, a * 255); } - return 0; + return *ok = 0; } /* @@ -341,27 +341,28 @@ rgba_from_rgba_string(const char *str) { * */ -int32_t -rgba_from_hex_string(const char *str) { +static int32_t +rgba_from_hex_string(const char *str, short *ok) { size_t len = strlen(str); + *ok = 1; if (6 == len) return rgba_from_hex6_string(str); if (3 == len) return rgba_from_hex3_string(str); - return 0; + return *ok = 0; } /* * Return named color value. */ -int32_t -rgba_from_name_string(const char *str) { +static int32_t +rgba_from_name_string(const char *str, short *ok) { int i = 0; struct named_color color; while ((color = named_colors[i++]).name) { if (*str == *color.name && 0 == strcmp(str, color.name)) - return color.val; + return *ok = 1, color.val; } - return 0; + return *ok = 0; } /* @@ -376,14 +377,14 @@ rgba_from_name_string(const char *str) { */ int32_t -rgba_from_string(const char *str) { +rgba_from_string(const char *str, short *ok) { if ('#' == str[0]) - return rgba_from_hex_string(++str); + return rgba_from_hex_string(++str, ok); if (str == strnstr(str, "rgba", 4)) - return rgba_from_rgba_string(str); + return rgba_from_rgba_string(str, ok); if (str == strnstr(str, "rgb", 3)) - return rgba_from_rgb_string(str); - return rgba_from_name_string(str); + return rgba_from_rgb_string(str, ok); + return rgba_from_name_string(str, ok); } /* diff --git a/src/color.h b/src/color.h index 60eaf54..4f7a0a6 100644 --- a/src/color.h +++ b/src/color.h @@ -27,32 +27,8 @@ typedef struct { rgba_t rgba_create(uint32_t rgba); -inline int32_t -rgba_from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a); - -int32_t -rgba_from_rgb(uint8_t r, uint8_t g, uint8_t b); - -int32_t -rgba_from_hex6_string(const char *str); - -int32_t -rgba_from_hex3_string(const char *str); - -int32_t -rgba_from_rgb_string(const char *str); - -int32_t -rgba_from_rgba_string(const char *str); - -int32_t -rgba_from_hex_string(const char *str); - -int32_t -rgba_from_name_string(const char *str); - int32_t -rgba_from_string(const char *str); +rgba_from_string(const char *str, short *ok); void rgba_inspect(int32_t rgba); From 0ff539c6913f3f8e8dfb7396c34e441ccb5c8671 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 16:04:49 -0800 Subject: [PATCH 12/19] setting up shadowColor accessors --- lib/context2d.js | 10 ---------- src/CanvasRenderingContext2d.cc | 30 +++++++++++++++++++----------- src/CanvasRenderingContext2d.h | 3 ++- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/lib/context2d.js b/lib/context2d.js index ea461f0..07fadaf 100644 --- a/lib/context2d.js +++ b/lib/context2d.js @@ -153,16 +153,6 @@ Context2d.prototype.__defineSetter__('strokeStyle', function(val){ } }); -/** - * Set the shadow color with the given css color string. - * - * @api public - */ - -Context2d.prototype.__defineSetter__('shadowColor', function(val){ - this.setShadowColor(val); -}); - /** * Set font. * diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 63a1713..156e381 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -90,13 +90,13 @@ Context2d::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(constructor, "arc", Arc); NODE_SET_PROTOTYPE_METHOD(constructor, "arcTo", ArcTo); NODE_SET_PROTOTYPE_METHOD(constructor, "setFont", SetFont); - NODE_SET_PROTOTYPE_METHOD(constructor, "setShadowColor", SetShadowColor); NODE_SET_PROTOTYPE_METHOD(constructor, "setFillColor", SetFillColor); NODE_SET_PROTOTYPE_METHOD(constructor, "setStrokeColor", SetStrokeColor); NODE_SET_PROTOTYPE_METHOD(constructor, "setFillPattern", SetFillPattern); NODE_SET_PROTOTYPE_METHOD(constructor, "setStrokePattern", SetStrokePattern); proto->SetAccessor(String::NewSymbol("globalCompositeOperation"), GetGlobalCompositeOperation, SetGlobalCompositeOperation); proto->SetAccessor(String::NewSymbol("globalAlpha"), GetGlobalAlpha, SetGlobalAlpha); + proto->SetAccessor(String::NewSymbol("shadowColor"), GetShadowColor, SetShadowColor); proto->SetAccessor(String::NewSymbol("miterLimit"), GetMiterLimit, SetMiterLimit); proto->SetAccessor(String::NewSymbol("lineWidth"), GetLineWidth, SetLineWidth); proto->SetAccessor(String::NewSymbol("lineCap"), GetLineCap, SetLineCap); @@ -989,20 +989,28 @@ Context2d::SetStrokePattern(const Arguments &args) { } /* - * Set shadow color, used internally for shadowColor= + * Set shadow color. */ -Handle -Context2d::SetShadowColor(const Arguments &args) { - HandleScope scope; +void +Context2d::SetShadowColor(Local prop, Local val, const AccessorInfo &info) { short ok; - if (!args[0]->IsString()) return Undefined(); - String::AsciiValue str(args[0]); + String::AsciiValue str(val->ToString()); uint32_t rgba = rgba_from_string(*str, &ok); - if (!ok) return Undefined(); - Context2d *context = ObjectWrap::Unwrap(args.This()); - context->state->shadow = rgba_create(rgba); - return Undefined(); + if (ok) { + Context2d *context = ObjectWrap::Unwrap(info.This()); + context->state->shadow = rgba_create(rgba); + } +} + +/* + * Get shadow color. + */ + +Handle +Context2d::GetShadowColor(Local prop, const AccessorInfo &info) { + Context2d *context = ObjectWrap::Unwrap(info.This()); + return Null(); } /* diff --git a/src/CanvasRenderingContext2d.h b/src/CanvasRenderingContext2d.h index d5dd0e4..6fbef7e 100644 --- a/src/CanvasRenderingContext2d.h +++ b/src/CanvasRenderingContext2d.h @@ -62,7 +62,6 @@ class Context2d: public node::ObjectWrap { static Handle SetFont(const Arguments &args); static Handle SetFillColor(const Arguments &args); static Handle SetStrokeColor(const Arguments &args); - static Handle SetShadowColor(const Arguments &args); static Handle SetFillPattern(const Arguments &args); static Handle SetStrokePattern(const Arguments &args); static Handle SetTextBaseline(const Arguments &args); @@ -80,6 +79,7 @@ class Context2d: public node::ObjectWrap { static Handle ArcTo(const Arguments &args); static Handle GetGlobalCompositeOperation(Local prop, const AccessorInfo &info); static Handle GetGlobalAlpha(Local prop, const AccessorInfo &info); + static Handle GetShadowColor(Local prop, const AccessorInfo &info); static Handle GetMiterLimit(Local prop, const AccessorInfo &info); static Handle GetLineCap(Local prop, const AccessorInfo &info); static Handle GetLineJoin(Local prop, const AccessorInfo &info); @@ -90,6 +90,7 @@ class Context2d: public node::ObjectWrap { static Handle GetAntiAlias(Local prop, const AccessorInfo &info); static void SetGlobalCompositeOperation(Local prop, Local val, const AccessorInfo &info); static void SetGlobalAlpha(Local prop, Local val, const AccessorInfo &info); + static void SetShadowColor(Local prop, Local val, const AccessorInfo &info); static void SetMiterLimit(Local prop, Local val, const AccessorInfo &info); static void SetLineCap(Local prop, Local val, const AccessorInfo &info); static void SetLineJoin(Local prop, Local val, const AccessorInfo &info); From ddeb6f3566e332a71d2151d101443e58369edd7d Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 16:20:23 -0800 Subject: [PATCH 13/19] Added rgba_to_string() --- src/CanvasRenderingContext2d.cc | 2 +- src/color.cc | 23 +++++++++++++++++++++++ src/color.h | 3 +++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 156e381..cedcfac 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -1010,7 +1010,7 @@ Context2d::SetShadowColor(Local prop, Local val, const AccessorIn Handle Context2d::GetShadowColor(Local prop, const AccessorInfo &info) { Context2d *context = ObjectWrap::Unwrap(info.This()); - return Null(); + return String::New(rgba_to_string(context->state->shadow)); } /* diff --git a/src/color.cc b/src/color.cc index 3536fcc..4341d78 100644 --- a/src/color.cc +++ b/src/color.cc @@ -6,6 +6,7 @@ // #include "color.h" +#include /* * Consume whitespace. @@ -234,6 +235,28 @@ rgba_create(uint32_t rgba) { return color; } +/* + * Return a string representation of the color. + */ + +char * +rgba_to_string(rgba_t rgba) { + char *buf = (char *) malloc(64); + if (1 == rgba.a) { + sprintf(buf, "#%.2X%.2X%.2X" + , (int) (rgba.r * 255) + , (int) (rgba.g * 255) + , (int) (rgba.b * 255)); + } else { + sprintf(buf, "rgba(%d, %d, %d, %.2f)" + , (int) (rgba.r * 255) + , (int) (rgba.g * 255) + , (int) (rgba.b * 255) + , rgba.a); + } + return buf; +} + /* * Return rgba from (r,g,b,a). */ diff --git a/src/color.h b/src/color.h index 4f7a0a6..4119316 100644 --- a/src/color.h +++ b/src/color.h @@ -30,6 +30,9 @@ rgba_create(uint32_t rgba); int32_t rgba_from_string(const char *str, short *ok); +char * +rgba_to_string(rgba_t rgba); + void rgba_inspect(int32_t rgba); From 54be6c057a5104254beb3cb3830fa893eef49f17 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 16:29:13 -0800 Subject: [PATCH 14/19] automatic rgba_to_string() --- src/CanvasRenderingContext2d.cc | 4 +++- src/color.cc | 6 ++---- src/color.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index cedcfac..437893a 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -1009,8 +1009,10 @@ Context2d::SetShadowColor(Local prop, Local val, const AccessorIn Handle Context2d::GetShadowColor(Local prop, const AccessorInfo &info) { + char buf[64]; Context2d *context = ObjectWrap::Unwrap(info.This()); - return String::New(rgba_to_string(context->state->shadow)); + rgba_to_string(context->state->shadow, buf); + return String::New(buf); } /* diff --git a/src/color.cc b/src/color.cc index 4341d78..ab4a8f1 100644 --- a/src/color.cc +++ b/src/color.cc @@ -239,9 +239,8 @@ rgba_create(uint32_t rgba) { * Return a string representation of the color. */ -char * -rgba_to_string(rgba_t rgba) { - char *buf = (char *) malloc(64); +void +rgba_to_string(rgba_t rgba, char *buf) { if (1 == rgba.a) { sprintf(buf, "#%.2X%.2X%.2X" , (int) (rgba.r * 255) @@ -254,7 +253,6 @@ rgba_to_string(rgba_t rgba) { , (int) (rgba.b * 255) , rgba.a); } - return buf; } /* diff --git a/src/color.h b/src/color.h index 4119316..10de606 100644 --- a/src/color.h +++ b/src/color.h @@ -30,8 +30,8 @@ rgba_create(uint32_t rgba); int32_t rgba_from_string(const char *str, short *ok); -char * -rgba_to_string(rgba_t rgba); +void +rgba_to_string(rgba_t rgba, char *buf); void rgba_inspect(int32_t rgba); From 85ae1c931ff20f67f07b208b371e93d258d9f2df Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 16:37:48 -0800 Subject: [PATCH 15/19] Added Context2d::Get{Fill,Stroke}Color() --- lib/context2d.js | 23 +++++++++++++++++++++++ src/CanvasRenderingContext2d.cc | 26 ++++++++++++++++++++++++++ src/CanvasRenderingContext2d.h | 2 ++ 3 files changed, 51 insertions(+) diff --git a/lib/context2d.js b/lib/context2d.js index 07fadaf..43fc6bf 100644 --- a/lib/context2d.js +++ b/lib/context2d.js @@ -138,6 +138,17 @@ Context2d.prototype.__defineSetter__('fillStyle', function(val){ } }); +/** + * Get previous fill style. + * + * @return {CanvasGradient|String} + * @api public + */ + +Context2d.prototype.__defineGetter__('fillStyle', function(){ + return this.lastFillStyle || this.fillColor; +}); + /** * Set the stroke style with the given css color string. * @@ -153,6 +164,18 @@ Context2d.prototype.__defineSetter__('strokeStyle', function(val){ } }); +/** + * Get previous stroke style. + * + * @return {CanvasGradient|String} + * @api public + */ + +Context2d.prototype.__defineGetter__('strokeStyle', function(){ + return this.lastStrokeStyle || this.strokeColor; +}); + + /** * Set font. * diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 437893a..96850fb 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -97,6 +97,8 @@ Context2d::Initialize(Handle target) { proto->SetAccessor(String::NewSymbol("globalCompositeOperation"), GetGlobalCompositeOperation, SetGlobalCompositeOperation); proto->SetAccessor(String::NewSymbol("globalAlpha"), GetGlobalAlpha, SetGlobalAlpha); proto->SetAccessor(String::NewSymbol("shadowColor"), GetShadowColor, SetShadowColor); + proto->SetAccessor(String::NewSymbol("fillColor"), GetFillColor); + proto->SetAccessor(String::NewSymbol("strokeColor"), GetStrokeColor); proto->SetAccessor(String::NewSymbol("miterLimit"), GetMiterLimit, SetMiterLimit); proto->SetAccessor(String::NewSymbol("lineWidth"), GetLineWidth, SetLineWidth); proto->SetAccessor(String::NewSymbol("lineCap"), GetLineCap, SetLineCap); @@ -1033,6 +1035,18 @@ Context2d::SetFillColor(const Arguments &args) { return Undefined(); } +/* + * Get fill color. + */ + +Handle +Context2d::GetFillColor(Local prop, const AccessorInfo &info) { + char buf[64]; + Context2d *context = ObjectWrap::Unwrap(info.This()); + rgba_to_string(context->state->fill, buf); + return String::New(buf); +} + /* * Set stroke color, used internally for strokeStyle= */ @@ -1051,6 +1065,18 @@ Context2d::SetStrokeColor(const Arguments &args) { return Undefined(); } +/* + * Get stroke color. + */ + +Handle +Context2d::GetStrokeColor(Local prop, const AccessorInfo &info) { + char buf[64]; + Context2d *context = ObjectWrap::Unwrap(info.This()); + rgba_to_string(context->state->stroke, buf); + return String::New(buf); +} + /* * Bezier curve. */ diff --git a/src/CanvasRenderingContext2d.h b/src/CanvasRenderingContext2d.h index 6fbef7e..32e88d2 100644 --- a/src/CanvasRenderingContext2d.h +++ b/src/CanvasRenderingContext2d.h @@ -80,6 +80,8 @@ class Context2d: public node::ObjectWrap { static Handle GetGlobalCompositeOperation(Local prop, const AccessorInfo &info); static Handle GetGlobalAlpha(Local prop, const AccessorInfo &info); static Handle GetShadowColor(Local prop, const AccessorInfo &info); + static Handle GetFillColor(Local prop, const AccessorInfo &info); + static Handle GetStrokeColor(Local prop, const AccessorInfo &info); static Handle GetMiterLimit(Local prop, const AccessorInfo &info); static Handle GetLineCap(Local prop, const AccessorInfo &info); static Handle GetLineJoin(Local prop, const AccessorInfo &info); From 4e501aa0176822fb47f92b8455ebfa3ca2cdd98c Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 16:39:05 -0800 Subject: [PATCH 16/19] removed parseColor() from tests --- test/canvas.test.js | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/test/canvas.test.js b/test/canvas.test.js index b79674f..24bcd51 100644 --- a/test/canvas.test.js +++ b/test/canvas.test.js @@ -5,7 +5,6 @@ var Canvas = require('canvas') , assert = require('assert') - , parseColor = Canvas.Context2d.parseColor , parseFont = Canvas.Context2d.parseFont , sys = require('sys') , fs = require('fs'); @@ -19,37 +18,6 @@ module.exports = { assert.match(Canvas.cairoVersion, /^\d+\.\d+\.\d+$/); }, - 'test .parseColor()': function(assert){ - assert.equal(null, parseColor()); - assert.equal(null, parseColor('')); - - // rgb() - assert.eql([255,165,0,1], parseColor('rgb(255,165,0)')); - assert.eql([255,165,0,1], parseColor('rgb(255, 165, 0)')); - assert.eql([255,165,0,1], parseColor('rgb(255 , 165 , 0)')); - assert.equal(null, parseColor('rgb()')); - - // rgba() - assert.eql([255,165,0,1], parseColor('rgba(255,165,0,1)')); - assert.eql([255,165,0,1], parseColor('rgba(255,165,0,1)')); - assert.eql([255,165,0,.6], parseColor('rgba(255,165,0,0.6)')); - assert.eql([255,165,0,.6], parseColor('rgba(255,165, 0, 0.6)')); - assert.eql([255,165,0,.6], parseColor('rgba(255,165 , 0 ,.6)')); - assert.equal(null, parseColor('rgba(2554,165 , 0 ,.6)')); - assert.equal(null, parseColor('rgba()')); - - // hex - assert.eql([165,89,89,1], parseColor('#A55959')); - assert.eql([255,255,255,1], parseColor('#FFFFFF')); - assert.eql([255,255,255,1], parseColor('#ffffff')); - assert.eql([255,255,255,1], parseColor('#FFF')); - assert.eql([255,255,255,1], parseColor('#fff')); - - // name - assert.eql([255,255,255,1], parseColor('white')); - assert.eql([0,0,0,1], parseColor('black')); - }, - 'test .parseFont()': function(assert){ var tests = [ '20px Arial' From 9c5a511051cd1e2b59f0266fa0691a9be38b3011 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 16:43:32 -0800 Subject: [PATCH 17/19] fixed hex parsing, defaulting alpha to 1 --- src/color.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/color.cc b/src/color.cc index ab4a8f1..4deb00c 100644 --- a/src/color.cc +++ b/src/color.cc @@ -274,7 +274,7 @@ rgba_from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { static int32_t rgba_from_rgb(uint8_t r, uint8_t g, uint8_t b) { - return rgba_from_rgba(r, g, b, 0); + return rgba_from_rgba(r, g, b, 255); } /* From f4cd85ad057ff04722ac9e043e2718e1b40ca0b9 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 16:45:13 -0800 Subject: [PATCH 18/19] lowercase rgba_to_string res for hex --- src/color.cc | 2 +- test/canvas.test.js | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/color.cc b/src/color.cc index 4deb00c..b5d81d5 100644 --- a/src/color.cc +++ b/src/color.cc @@ -242,7 +242,7 @@ rgba_create(uint32_t rgba) { void rgba_to_string(rgba_t rgba, char *buf) { if (1 == rgba.a) { - sprintf(buf, "#%.2X%.2X%.2X" + sprintf(buf, "#%.2x%.2x%.2x" , (int) (rgba.r * 255) , (int) (rgba.g * 255) , (int) (rgba.b * 255)); diff --git a/test/canvas.test.js b/test/canvas.test.js index 24bcd51..48065e0 100644 --- a/test/canvas.test.js +++ b/test/canvas.test.js @@ -92,7 +92,10 @@ module.exports = { assert.equal('#80c880', ctx[prop], prop + ' rgba(128, 200, 128, 1) -> #80c880, got ' + ctx[prop]); ctx[prop] = 'rgba(128,80,0,0.5)'; - assert.equal('rgba(128, 80, 0, 0.5)', ctx[prop], prop + ' rgba(128,80,0,0.5) -> rgba(128, 80, 0, 0.5), got ' + ctx[prop]); + assert.equal('rgba(128, 80, 0, 0.50)', ctx[prop], prop + ' rgba(128,80,0,0.5) -> rgba(128, 80, 0, 0.5), got ' + ctx[prop]); + + ctx[prop] = 'rgba(128,80,0,0.75)'; + assert.equal('rgba(128, 80, 0, 0.75)', ctx[prop], prop + ' rgba(128,80,0,0.75) -> rgba(128, 80, 0, 0.75), got ' + ctx[prop]); if ('shadowColor' == prop) return; From 9fddb25eb56e26848bc9b34382ff85258681bb29 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 23 Nov 2010 17:02:28 -0800 Subject: [PATCH 19/19] AddColorStop() using new color parser --- src/Canvas.h | 18 ------------------ src/CanvasGradient.cc | 25 +++++++++++++++++-------- 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/src/Canvas.h b/src/Canvas.h index 54797a3..a2c03b1 100644 --- a/src/Canvas.h +++ b/src/Canvas.h @@ -25,24 +25,6 @@ using namespace node; #define CANVAS_MAX_STATES 64 #endif -/* - * RGBA arg assertions. - */ - -#define RGBA_ARGS(N) \ - if (!args[N]->IsNumber()) \ - return ThrowException(Exception::TypeError(String::New("r required"))); \ - if (!args[N+1]->IsNumber()) \ - return ThrowException(Exception::TypeError(String::New("g required"))); \ - if (!args[N+2]->IsNumber()) \ - return ThrowException(Exception::TypeError(String::New("b required"))); \ - if (!args[N+3]->IsNumber()) \ - return ThrowException(Exception::TypeError(String::New("alpha required"))); \ - double r = args[N]->Int32Value(); \ - double g = args[N+1]->Int32Value(); \ - double b = args[N+2]->Int32Value(); \ - double a = args[N+3]->NumberValue(); - /* * Canvas. */ diff --git a/src/CanvasGradient.cc b/src/CanvasGradient.cc index bd123f6..32d26ad 100644 --- a/src/CanvasGradient.cc +++ b/src/CanvasGradient.cc @@ -5,6 +5,7 @@ // Copyright (c) 2010 LearnBoost // +#include "color.h" #include "Canvas.h" #include "CanvasGradient.h" @@ -74,15 +75,23 @@ Gradient::AddColorStop(const Arguments &args) { return ThrowException(Exception::TypeError(String::New("offset required"))); if (!args[1]->IsString()) return ThrowException(Exception::TypeError(String::New("color string required"))); - RGBA_ARGS(1); + Gradient *grad = ObjectWrap::Unwrap(args.This()); - cairo_pattern_add_color_stop_rgba( - grad->pattern() - , args[0]->NumberValue() - , r / 255 * 1 - , g / 255 * 1 - , b / 255 * 1 - , a); + short ok; + String::AsciiValue str(args[1]); + uint32_t rgba = rgba_from_string(*str, &ok); + + if (ok) { + rgba_t color = rgba_create(rgba); + cairo_pattern_add_color_stop_rgba( + grad->pattern() + , args[0]->NumberValue() + , color.r + , color.g + , color.b + , color.a); + } + return Undefined(); }