API 0.9.5
AppKit/CoreGraphics/CGContextCanvas.j
Go to the documentation of this file.
00001 /*
00002  * CGContextCanvas.j
00003  * AppKit
00004  *
00005  * Created by Francisco Tolmasky.
00006  * Copyright 2008, 280 North, Inc.
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00021  */
00022 
00023 var CANVAS_LINECAP_TABLE    = [ "butt", "round", "square" ],
00024     CANVAS_LINEJOIN_TABLE   = [ "miter", "round", "bevel" ],
00025     CANVAS_COMPOSITE_TABLE  = [ "source-over", "source-over", "source-over", "source-over", "darker",
00026                                 "lighter", "source-over", "source-over", "source-over", "source-over",
00027                                 "source-over", "source-over", "source-over", "source-over", "source-over",
00028                                 "source-over", "source-over",
00029                                 "copy", "source-in", "source-out", "source-atop",
00030                                 "destination-over", "destination-in", "destination-out", "destination-atop",
00031                                 "xor", "source-over", "source-over" ];
00032 
00033 #define _CGContextAddArcCanvas(aContext, x, y, radius, startAngle, endAngle, anticlockwise) aContext.arc(x, y, radius, startAngle, endAngle, anticlockwise)
00034 #define _CGContextAddArcToPointCanvas(aContext, x1, y1, x2, y2, radius) aContext.arcTo(x1, y1, x2, y2, radius)
00035 #define _CGContextAddCurveToPointCanvas(aContext, cp1x, cp1y, cp2x, cp2y, x, y) aContext.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
00036 #define _CGContextAddQuadCurveToPointCanvas(aContext, cpx, cpy, x, y) aContext.quadraticCurveTo(cpx, cpy, x, y)
00037 #define _CGContextAddLineToPointCanvas(aContext, x, y) aContext.lineTo(x, y)
00038 #define _CGContextClosePathCanvas(aContext) aContext.closePath()
00039 #define _CGContextMoveToPointCanvas(aContext, x, y) aContext.moveTo(x, y)
00040 
00041 #define _CGContextAddRectCanvas(aContext, aRect) aContext.rect(_CGRectGetMinX(aRect), _CGRectGetMinY(aRect), _CGRectGetWidth(aRect), _CGRectGetHeight(aRect))
00042 #define _CGContextBeginPathCanvas(aContext) aContext.beginPath()
00043 #define _CGContextFillRectCanvas(aContext, aRect) aContext.fillRect(_CGRectGetMinX(aRect), _CGRectGetMinY(aRect), _CGRectGetWidth(aRect), _CGRectGetHeight(aRect))
00044 #define _CGContextClipCanvas(aContext) aContext.clip()
00045 
00046 function CGContextSaveGState(aContext)
00047 {
00048     aContext.save();
00049 }
00050 
00051 function CGContextRestoreGState(aContext)
00052 {
00053     aContext.restore();
00054 }
00055 
00056 function CGContextSetLineCap(aContext, aLineCap)
00057 {
00058     aContext.lineCap = CANVAS_LINECAP_TABLE[aLineCap];
00059 }
00060 
00061 function CGContextSetLineJoin(aContext, aLineJoin)
00062 {
00063     aContext.lineJoin = CANVAS_LINEJOIN_TABLE[aLineJoin];
00064 }
00065 
00066 function CGContextSetLineWidth(aContext, aLineWidth)
00067 {
00068     aContext.lineWidth = aLineWidth;
00069 }
00070 
00071 function CGContextSetMiterLimit(aContext, aMiterLimit)
00072 {
00073     aContext.miterLimit = aMiterLimit;
00074 }
00075 
00076 function CGContextSetBlendMode(aContext, aBlendMode)
00077 {
00078     aContext.globalCompositeOperation = CANVAS_COMPOSITE_TABLE[aBlendMode];
00079 }
00080 
00081 function CGContextAddArc(aContext, x, y, radius, startAngle, endAngle, clockwise)
00082 {
00083     // Despite the documentation saying otherwise, the last parameter is anti-clockwise not clockwise.
00084     // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes#Arcs
00085     _CGContextAddArcCanvas(aContext, x, y, radius, startAngle, endAngle, !clockwise);
00086 }
00087 
00088 function CGContextAddArcToPoint(aContext, x1, y1, x2, y2, radius)
00089 {
00090     _CGContextAddArcToPointCanvas(aContext, x1, y1, x2, y2, radius);
00091 }
00092 
00093 function CGContextAddCurveToPoint(aContext, cp1x, cp1y, cp2x, cp2y, x, y)
00094 {
00095     _CGContextAddCurveToPointCanvas(aContext, cp1x, cp1y, cp2x, cp2y, x, y);
00096 }
00097 
00098 function CGContextAddLineToPoint(aContext, x, y)
00099 {
00100     _CGContextAddLineToPointCanvas(aContext, x, y);
00101 }
00102 
00103 function CGContextAddPath(aContext, aPath)
00104 {
00105     if (!aContext || CGPathIsEmpty(aPath))
00106         return;
00107 
00108     var elements = aPath.elements,
00109 
00110         i = 0,
00111         count = aPath.count;
00112 
00113     for (; i < count; ++i)
00114     {
00115         var element = elements[i],
00116             type = element.type;
00117 
00118         switch (type)
00119         {
00120             case kCGPathElementMoveToPoint:         _CGContextMoveToPointCanvas(aContext, element.x, element.y);
00121                                                     break;
00122             case kCGPathElementAddLineToPoint:      _CGContextAddLineToPointCanvas(aContext, element.x, element.y);
00123                                                     break;
00124             case kCGPathElementAddQuadCurveToPoint: _CGContextAddQuadCurveToPointCanvas(aContext, element.cpx, element.cpy, element.x, element.y);
00125                                                     break;
00126             case kCGPathElementAddCurveToPoint:     _CGContextAddCurveToPointCanvas(aContext, element.cp1x, element.cp1y, element.cp2x, element.cp2y, element.x, element.y);
00127                                                     break;
00128             case kCGPathElementCloseSubpath:        _CGContextClosePathCanvas(aContext);
00129                                                     break;
00130             case kCGPathElementAddArc:              _CGContextAddArcCanvas(aContext, element.x, element.y, element.radius, element.startAngle, element.endAngle, element.clockwise);
00131                                                     break;
00132             case kCGPathElementAddArcTo:            //_CGContextAddArcToPointCanvas(aContext, element.cp1x, element.cp1.y, element.cp2.x, element.cp2y, element.radius);
00133                                                     break;
00134         }
00135     }
00136 }
00137 
00138 function CGContextAddRect(aContext, aRect)
00139 {
00140     _CGContextAddRectCanvas(aContext, aRect);
00141 }
00142 
00143 function CGContextAddRects(aContext, rects, count)
00144 {
00145     var i = 0;
00146 
00147     if (count === NULL)
00148         var count = rects.length;
00149 
00150     for (; i < count; ++i)
00151     {
00152         var rect = rects[i];
00153         _CGContextAddRectCanvas(aContext, rect);
00154     }
00155 }
00156 
00157 function CGContextBeginPath(aContext)
00158 {
00159     _CGContextBeginPathCanvas(aContext);
00160 }
00161 
00162 function CGContextClosePath(aContext)
00163 {
00164     _CGContextClosePathCanvas(aContext);
00165 }
00166 
00167 function CGContextMoveToPoint(aContext, x, y)
00168 {
00169     _CGContextMoveToPointCanvas(aContext, x, y);
00170 }
00171 
00172 function CGContextClearRect(aContext, aRect)
00173 {
00174     aContext.clearRect(_CGRectGetMinX(aRect), _CGRectGetMinY(aRect), _CGRectGetWidth(aRect), _CGRectGetHeight(aRect));
00175 }
00176 
00177 function CGContextDrawPath(aContext, aMode)
00178 {
00179     if (aMode == kCGPathFill || aMode == kCGPathFillStroke)
00180         aContext.fill();
00181     else if (aMode == kCGPathEOFill || aMode == kCGPathEOFillStroke)
00182         alert("not implemented!!!");
00183 
00184     if (aMode == kCGPathStroke || aMode == kCGPathFillStroke || aMode == kCGPathEOFillStroke)
00185         aContext.stroke();
00186 }
00187 
00188 function CGContextFillRect(aContext, aRect)
00189 {
00190     _CGContextFillRectCanvas(aContext, aRect);
00191 }
00192 
00193 function CGContextFillRects(aContext, rects, count)
00194 {
00195     var i = 0;
00196 
00197     if (count === NULL)
00198         var count = rects.length;
00199 
00200     for (; i < count; ++i)
00201     {
00202         var rect = rects[i];
00203         _CGContextFillRectCanvas(aContext, rect);
00204     }
00205 }
00206 
00207 function CGContextStrokeRect(aContext, aRect)
00208 {
00209     aContext.strokeRect(_CGRectGetMinX(aRect), _CGRectGetMinY(aRect), _CGRectGetWidth(aRect), _CGRectGetHeight(aRect));
00210 }
00211 
00212 function CGContextClip(aContext)
00213 {
00214     _CGContextClipCanvas(aContext);
00215 }
00216 
00217 function CGContextClipToRect(aContext, aRect)
00218 {
00219     _CGContextBeginPathCanvas(aContext);
00220     _CGContextAddRectCanvas(aContext, aRect);
00221     _CGContextClosePathCanvas(aContext);
00222 
00223     _CGContextClipCanvas(aContext);
00224 }
00225 
00226 function CGContextClipToRects(aContext, rects, count)
00227 {
00228     if (count === NULL)
00229         var count = rects.length;
00230 
00231     _CGContextBeginPathCanvas(aContext);
00232     CGContextAddRects(aContext, rects, count);
00233     _CGContextClipCanvas(aContext);
00234 }
00235 
00236 function CGContextSetAlpha(aContext, anAlpha)
00237 {
00238     aContext.globalAlpha = anAlpha;
00239 }
00240 
00241 function CGContextSetFillColor(aContext, aColor)
00242 {
00243     if ([aColor patternImage])
00244     {
00245         var patternImg = [aColor patternImage],
00246             size = [patternImg size],
00247             img;
00248 
00249         if (size)
00250             img = new Image(size.width, size.height);
00251         else
00252             img = new Image();
00253 
00254         img.src = [patternImg filename];
00255 
00256         var pattern = aContext.createPattern(img, "repeat");
00257 
00258         aContext.fillStyle = pattern;
00259     }
00260     else
00261         aContext.fillStyle = [aColor cssString];
00262 }
00263 
00264 function CGContextSetStrokeColor(aContext, aColor)
00265 {
00266     aContext.strokeStyle = [aColor cssString];
00267 }
00268 
00269 function CGContextSetShadow(aContext, aSize, aBlur)
00270 {
00271     aContext.shadowOffsetX = aSize.width;
00272     aContext.shadowOffsetY = aSize.height;
00273     aContext.shadowBlur = aBlur;
00274 }
00275 
00276 function CGContextSetShadowWithColor(aContext, aSize, aBlur, aColor)
00277 {
00278     aContext.shadowOffsetX = aSize.width;
00279     aContext.shadowOffsetY = aSize.height;
00280     aContext.shadowBlur = aBlur;
00281     aContext.shadowColor = [aColor cssString];
00282 }
00283 
00284 function CGContextRotateCTM(aContext, anAngle)
00285 {
00286     aContext.rotate(anAngle);
00287 }
00288 
00289 function CGContextScaleCTM(aContext, sx, sy)
00290 {
00291     aContext.scale(sx, sy);
00292 }
00293 
00294 function CGContextTranslateCTM(aContext, tx, ty)
00295 {
00296     aContext.translate(tx, ty);
00297 }
00298 
00299 #define scale_rotate(a, b, c, d) \
00300         var sign = (a * d < 0.0 || b * c > 0.0) ? -1.0 : 1.0, \
00301             a2 = (ATAN2(b, d) + ATAN2(-sign * c, sign * a)) / 2.0, \
00302             cos = COS(a2),\
00303             sin = SIN(a2);\
00304         \
00305         if (cos == 0)\
00306         {\
00307             sx = -c / sin;\
00308             sy = b / sin;\
00309         }\
00310         else if (sin == 0)\
00311         {\
00312             sx = a / cos;\
00313             sy = d / cos;\
00314         }\
00315         else\
00316         {\
00317             abs_cos = ABS(cos);\
00318             abs_sin = ABS(sin);\
00319             \
00320             sx = (abs_cos * a / cos + abs_sin * -c / sin) / (abs_cos + abs_sin);\
00321             sy = (abs_cos * d / cos + abs_sin * b / sin) / (abs_cos + abs_sin);\
00322         }\
00323 
00324 #define rotate_scale(a, b, c, d) \
00325         var sign = (a * d < 0.0 || b * c > 0.0) ? -1.0 : 1.0;\
00326             a1 = (Math.atan2(sign * b, sign * a) + Math.atan2(-c, d)) / 2.0,\
00327             cos = COS(a1),\
00328             sin = SIN(a1);\
00329                \
00330         if (cos == 0)\
00331         {\
00332             sx = b / sin;\
00333             sy = -c / sin;\
00334         }\
00335         else if (sin == 0)\
00336         {\
00337             sx = a / cos;\
00338             sy = d / cos;\
00339         }\
00340         else\
00341         {\
00342             abs_cos = ABS(cos);\
00343             abs_sin = ABS(sin);\
00344             \
00345             sx = (abs_cos * a / cos + abs_sin * b / sin) / (abs_cos + abs_sin);\
00346             sy = (abs_cos * d / cos + abs_sin * -c / sin) / (abs_cos + abs_sin);\
00347         }\
00348 
00349 function eigen(anAffineTransform)
00350 {
00351     alert("IMPLEMENT ME!");
00352 }
00353 
00354 
00355 if (CPFeatureIsCompatible(CPJavaScriptCanvasTransformFeature))
00356 {
00357 
00358 CGContextConcatCTM = function(aContext, anAffineTransform)
00359 {
00360     aContext.transform(anAffineTransform.a, anAffineTransform.b, anAffineTransform.c, anAffineTransform.d, anAffineTransform.tx, anAffineTransform.ty);
00361 }
00362 
00363 }
00364 else
00365 {
00366 
00367 CGContextConcatCTM = function(aContext, anAffineTransform)
00368 {
00369     var a = anAffineTransform.a,
00370         b = anAffineTransform.b,
00371         c = anAffineTransform.c,
00372         d = anAffineTransform.d,
00373         tx = anAffineTransform.tx,
00374         ty = anAffineTransform.ty,
00375         sx = 1.0,
00376         sy = 1.0,
00377         a1 = 0.0,
00378         a2 = 0.0;
00379 
00380     // Detect the simple case of just scaling.
00381     if (b == 0.0 && c == 0.0)
00382     {
00383         sx = a;
00384         sy = d;
00385     }
00386 
00387     // a scale followed by a rotate
00388     else if (a * b == -c * d)
00389     {
00390         scale_rotate(a, b, c, d)
00391     }
00392 
00393     // rotate, then scale.
00394     else if (a * c == -b * d)
00395     {
00396         rotate_scale(a, b, c, d)
00397     }
00398     else
00399     {
00400         var transpose = CGAffineTransformMake(a, c, b, d, 0.0, 0.0), // inline
00401             u = eigen(CGAffineTransformConcat(anAffineTransform, transpose)),
00402             v = eigen(CGAffineTransformConcat(transpose, anAffineTransform)),
00403             U = CGAffineTransformMake(u.vector_1.x, u.vector_2.x, u.vector_1.y, u.vector_2.y, 0.0, 0.0), // inline
00404             VT = CGAffineTransformMake(v.vector_1.x, v.vector_1.y, v.vector_2.x, v.vector_2.y, 0.0, 0.0),
00405             S = CGAffineTransformConcat(CGAffineTransformConcat(CGAffineTransformInvert(U), anAffineTransform), CGAffineTransformInvert(VT));
00406 
00407         a = VT.a;
00408         b = VT.b;
00409         c = VT.c;
00410         d = VT.d;
00411         scale_rotate(a, b, c, d)
00412         S.a *= sx;
00413         S.d *= sy;
00414         a = U.a;
00415         b = U.b;
00416         c = U.c;
00417         d = U.d;
00418         rotate_scale(a, b, c, d)
00419         sx = S.a * sx;
00420         sy = S.d * sy;
00421     }
00422 
00423     if (tx != 0 || ty != 0)
00424         CGContextTranslateCTM(aContext, tx, ty);
00425     if (a1 != 0.0)
00426         CGContextRotateCTM(aContext, a1);
00427     if (sx != 1.0 || sy != 1.0)
00428         CGContextScaleCTM(aContext, sx, sy);
00429     if (a2 != 0.0)
00430         CGContextRotateCTM(aContext, a2);
00431 }
00432 
00433 }
00434 
00435 function CGContextDrawImage(aContext, aRect, anImage)
00436 {
00437     aContext.drawImage(anImage._image, _CGRectGetMinX(aRect), _CGRectGetMinY(aRect), _CGRectGetWidth(aRect), _CGRectGetHeight(aRect));
00438 }
00439 
00440 function to_string(aColor)
00441 {
00442     return "rgba(" + ROUND(aColor.components[0] * 255) + ", " + ROUND(aColor.components[1] * 255) + ", " + ROUND(255 * aColor.components[2]) + ", " + aColor.components[3] + ")";
00443 }
00444 
00445 function CGContextDrawLinearGradient(aContext, aGradient, aStartPoint, anEndPoint, options)
00446 {
00447     var colors = aGradient.colors,
00448         count = colors.length,
00449 
00450         linearGradient = aContext.createLinearGradient(aStartPoint.x, aStartPoint.y, anEndPoint.x, anEndPoint.y);
00451 
00452     while (count--)
00453         linearGradient.addColorStop(aGradient.locations[count], to_string(colors[count]));
00454 
00455     aContext.fillStyle = linearGradient;
00456     aContext.fill();
00457 }
00458 
00459 function CGBitmapGraphicsContextCreate()
00460 {
00461     var DOMElement = document.createElement("canvas"),
00462         context = DOMElement.getContext("2d");
00463 
00464     context.DOMElement = DOMElement;
00465 
00466     return context;
00467 }
 All Classes Files Functions Variables Defines