![]() |
API 0.9.5
|
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 }