1 2/* 3 * Copyright 2006 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10#include <jsapi.h> 11#include "SkJS.h" 12#include "SkDisplayType.h" 13//#include "SkAnimateColor.h" 14#include "SkAnimateMaker.h" 15#include "SkAnimateSet.h" 16//#include "SkAnimateTransform.h" 17#include "SkCanvas.h" 18//#include "SkDimensions.h" 19#include "SkDisplayAdd.h" 20#include "SkDisplayApply.h" 21//#include "SkDisplayBefore.h" 22#include "SkDisplayEvent.h" 23//#include "SkDisplayFocus.h" 24#include "SkDisplayInclude.h" 25#include "SkDisplayPost.h" 26#include "SkDisplayRandom.h" 27#include "SkDraw3D.h" 28#include "SkDrawBitmap.h" 29#include "SkDrawClip.h" 30#include "SkDrawDash.h" 31#include "SkDrawDiscrete.h" 32#include "SkDrawEmboss.h" 33//#include "SkDrawFont.h" 34#include "SkDrawFull.h" 35#include "SkDrawGradient.h" 36#include "SkDrawLine.h" 37//#include "SkDrawMaskFilter.h" 38#include "SkDrawMatrix.h" 39#include "SkDrawOval.h" 40#include "SkDrawPaint.h" 41#include "SkDrawPath.h" 42#include "SkDrawPoint.h" 43// #include "SkDrawStroke.h" 44#include "SkDrawText.h" 45#include "SkDrawTo.h" 46//#include "SkDrawTransferMode.h" 47#include "SkDrawTransparentShader.h" 48//#include "SkDrawUse.h" 49#include "SkMatrixParts.h" 50#include "SkPathParts.h" 51#include "SkPostParts.h" 52#include "SkScript.h" 53#include "SkSnapshot.h" 54#include "SkTextOnPath.h" 55#include "SkTextToPath.h" 56 57 58class SkJSDisplayable { 59public: 60 SkJSDisplayable() : fDisplayable(NULL) {} 61 ~SkJSDisplayable() { delete fDisplayable; } 62 static void Destructor(JSContext *cx, JSObject *obj); 63 static JSBool GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); 64 static JSBool SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); 65 static SkCanvas* gCanvas; 66 static SkPaint* gPaint; 67 static JSBool Draw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); 68 SkDisplayable* fDisplayable; 69}; 70 71SkCanvas* SkJSDisplayable::gCanvas; 72SkPaint* SkJSDisplayable::gPaint; 73 74JSBool SkJSDisplayable::Draw(JSContext *cx, JSObject *obj, uintN argc, 75 jsval *argv, jsval *rval) 76{ 77 SkJSDisplayable *p = (SkJSDisplayable*) JS_GetPrivate(cx, obj); 78 SkASSERT(p->fDisplayable->isDrawable()); 79 SkDrawable* drawable = (SkDrawable*) p->fDisplayable; 80 SkAnimateMaker maker(NULL, gCanvas, gPaint); 81 drawable->draw(maker); 82 return JS_TRUE; 83} 84 85 86JSFunctionSpec SkJSDisplayable_methods[] = 87{ 88 { "draw", SkJSDisplayable::Draw, 1, 0, 0 }, 89 { 0 } 90}; 91 92static JSPropertySpec* gDisplayableProperties[kNumberOfTypes]; 93static JSClass gDisplayableClasses[kNumberOfTypes]; 94 95#define JS_INIT(_prefix, _class) \ 96static JSBool _class##Constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { \ 97 SkJSDisplayable* jsDisplayable = new SkJSDisplayable(); \ 98 jsDisplayable->fDisplayable = new _prefix##_class(); \ 99 JS_SetPrivate(cx, obj, (void*) jsDisplayable); \ 100 return JS_TRUE; \ 101} \ 102 \ 103static JSObject* _class##Init(JSContext *cx, JSObject *obj, JSObject *proto) { \ 104 JSObject *newProtoObj = JS_InitClass(cx, obj, proto, &gDisplayableClasses[SkType_##_class], \ 105 _class##Constructor, 0, \ 106 NULL, SkJSDisplayable_methods , \ 107 NULL, NULL); \ 108 JS_DefineProperties(cx, newProtoObj, gDisplayableProperties[SkType_##_class]); \ 109 return newProtoObj; \ 110} 111 112JS_INIT(Sk, Add) 113JS_INIT(Sk, AddCircle) 114JS_INIT(Sk, AddOval) 115JS_INIT(Sk, AddPath) 116JS_INIT(Sk, AddRectangle) 117JS_INIT(Sk, AddRoundRect) 118//JS_INIT(Sk, After) 119JS_INIT(Sk, Apply) 120// JS_INIT(Sk, Animate) 121//JS_INIT(Sk, AnimateColor) 122JS_INIT(Sk, AnimateField) 123//JS_INIT(Sk, AnimateRotate) 124//JS_INIT(Sk, AnimateScale) 125//JS_INIT(Sk, AnimateTranslate) 126JS_INIT(SkDraw, Bitmap) 127JS_INIT(Sk, BaseBitmap) 128//JS_INIT(Sk, Before) 129JS_INIT(SkDraw, BitmapShader) 130JS_INIT(SkDraw, Blur) 131JS_INIT(SkDraw, Clip) 132JS_INIT(SkDraw, Color) 133JS_INIT(Sk, CubicTo) 134JS_INIT(Sk, Dash) 135JS_INIT(Sk, Data) 136//JS_INIT(Sk, Dimensions) 137JS_INIT(Sk, Discrete) 138JS_INIT(Sk, DrawTo) 139JS_INIT(SkDraw, Emboss) 140JS_INIT(SkDisplay, Event) 141// JS_INIT(SkDraw, Font) 142// JS_INIT(Sk, Focus) 143JS_INIT(Sk, Image) 144JS_INIT(Sk, Include) 145// JS_INIT(Sk, Input) 146JS_INIT(Sk, Line) 147JS_INIT(Sk, LinearGradient) 148JS_INIT(Sk, LineTo) 149JS_INIT(SkDraw, Matrix) 150JS_INIT(Sk, Move) 151JS_INIT(Sk, MoveTo) 152JS_INIT(Sk, Oval) 153JS_INIT(SkDraw, Path) 154JS_INIT(SkDraw, Paint) 155JS_INIT(Sk, DrawPoint) 156JS_INIT(Sk, PolyToPoly) 157JS_INIT(Sk, Polygon) 158JS_INIT(Sk, Polyline) 159JS_INIT(Sk, Post) 160JS_INIT(Sk, QuadTo) 161JS_INIT(Sk, RadialGradient) 162JS_INIT(SkDisplay, Random) 163JS_INIT(Sk, RectToRect) 164JS_INIT(Sk, Rectangle) 165JS_INIT(Sk, Remove) 166JS_INIT(Sk, Replace) 167JS_INIT(Sk, Rotate) 168JS_INIT(Sk, RoundRect) 169JS_INIT(Sk, Scale) 170JS_INIT(Sk, Set) 171JS_INIT(Sk, Skew) 172// JS_INIT(Sk, 3D_Camera) 173// JS_INIT(Sk, 3D_Patch) 174JS_INIT(Sk, Snapshot) 175// JS_INIT(SkDraw, Stroke) 176JS_INIT(Sk, Text) 177JS_INIT(Sk, TextOnPath) 178JS_INIT(Sk, TextToPath) 179JS_INIT(Sk, Translate) 180//JS_INIT(Sk, Use) 181 182#if SK_USE_CONDENSED_INFO == 0 183static void GenerateTables() { 184 for (int index = 0; index < kTypeNamesSize; index++) { 185 int infoCount; 186 SkDisplayTypes type = gTypeNames[index].fType; 187 const SkMemberInfo* info = SkDisplayType::GetMembers(NULL /* fMaker */, type, &infoCount); 188 if (info == NULL) 189 continue; 190 gDisplayableProperties[type] = new JSPropertySpec[infoCount + 1]; 191 JSPropertySpec* propertySpec = gDisplayableProperties[type]; 192 memset(propertySpec, 0, sizeof (JSPropertySpec) * (infoCount + 1)); 193 for (int inner = 0; inner < infoCount; inner++) { 194 if (info[inner].fType == SkType_BaseClassInfo) 195 continue; 196 propertySpec[inner].name = info[inner].fName; 197 propertySpec[inner].tinyid = inner; 198 propertySpec[inner].flags = JSPROP_ENUMERATE; 199 } 200 gDisplayableClasses[type].name = gTypeNames[index].fName; 201 gDisplayableClasses[type].flags = JSCLASS_HAS_PRIVATE; 202 gDisplayableClasses[type].addProperty = JS_PropertyStub; 203 gDisplayableClasses[type].delProperty = JS_PropertyStub; 204 gDisplayableClasses[type].getProperty = SkJSDisplayable::GetProperty; 205 gDisplayableClasses[type].setProperty = SkJSDisplayable::SetProperty; 206 gDisplayableClasses[type].enumerate = JS_EnumerateStub; 207 gDisplayableClasses[type].resolve = JS_ResolveStub; 208 gDisplayableClasses[type].convert = JS_ConvertStub; 209 gDisplayableClasses[type].finalize = SkJSDisplayable::Destructor; 210 } 211} 212#endif 213 214void SkJSDisplayable::Destructor(JSContext *cx, JSObject *obj) { 215 delete (SkJSDisplayable*) JS_GetPrivate(cx, obj); 216} 217 218JSBool SkJSDisplayable::GetProperty(JSContext *cx, JSObject *obj, jsval id, 219 jsval *vp) 220{ 221 if (JSVAL_IS_INT(id) == 0) 222 return JS_TRUE; 223 SkJSDisplayable *p = (SkJSDisplayable *) JS_GetPrivate(cx, obj); 224 SkDisplayable* displayable = p->fDisplayable; 225 SkDisplayTypes displayableType = displayable->getType(); 226 int members; 227 const SkMemberInfo* info = SkDisplayType::GetMembers(NULL /* fMaker */, displayableType, &members); 228 int idIndex = JSVAL_TO_INT(id); 229 SkASSERT(idIndex >= 0 && idIndex < members); 230 info = &info[idIndex]; 231 SkDisplayTypes infoType = (SkDisplayTypes) info->fType; 232 SkScalar scalar = 0; 233 S32 s32 = 0; 234 SkString* string= NULL; 235 JSString *str; 236 if (infoType == SkType_MemberProperty) { 237 infoType = info->propertyType(); 238 switch (infoType) { 239 case SkType_Scalar: { 240 SkScriptValue scriptValue; 241 bool success = displayable->getProperty(info->propertyIndex(), &scriptValue); 242 SkASSERT(scriptValue.fType == SkType_Scalar); 243 scalar = scriptValue.fOperand.fScalar; 244 } break; 245 default: 246 SkASSERT(0); // !!! unimplemented 247 } 248 } else { 249 SkASSERT(info->fCount == 1); 250 switch (infoType) { 251 case SkType_Boolean: 252 case SkType_Color: 253 case SkType_S32: 254 s32 = *(S32*) info->memberData(displayable); 255 break; 256 case SkType_String: 257 info->getString(displayable, &string); 258 break; 259 case SkType_Scalar: 260 SkOperand operand; 261 info->getValue(displayable, &operand, 1); 262 scalar = operand.fScalar; 263 break; 264 default: 265 SkASSERT(0); // !!! unimplemented 266 } 267 } 268 switch (infoType) { 269 case SkType_Boolean: 270 *vp = BOOLEAN_TO_JSVAL(s32); 271 break; 272 case SkType_Color: 273 case SkType_S32: 274 *vp = INT_TO_JSVAL(s32); 275 break; 276 case SkType_Scalar: 277 if (SkScalarFraction(scalar) == 0) 278 *vp = INT_TO_JSVAL(SkScalarFloor(scalar)); 279 else 280#ifdef SK_SCALAR_IS_FLOAT 281 *vp = DOUBLE_TO_JSVAL(scalar); 282#else 283 *vp = DOUBLE_TO_JSVAL(scalar / 65536.0f ); 284#endif 285 break; 286 case SkType_String: 287 str = JS_NewStringCopyN(cx, string->c_str(), string->size()); 288 *vp = STRING_TO_JSVAL(str); 289 break; 290 default: 291 SkASSERT(0); // !!! unimplemented 292 } 293 return JS_TRUE; 294} 295 296JSBool SkJSDisplayable::SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { 297 if (JSVAL_IS_INT(id) == 0) 298 return JS_TRUE; 299 SkJSDisplayable *p = (SkJSDisplayable *) JS_GetPrivate(cx, obj); 300 SkDisplayable* displayable = p->fDisplayable; 301 SkDisplayTypes displayableType = displayable->getType(); 302 int members; 303 const SkMemberInfo* info = SkDisplayType::GetMembers(NULL /* fMaker */, displayableType, &members); 304 int idIndex = JSVAL_TO_INT(id); 305 SkASSERT(idIndex >= 0 && idIndex < members); 306 info = &info[idIndex]; 307 SkDisplayTypes infoType = info->getType(); 308 SkScalar scalar = 0; 309 S32 s32 = 0; 310 SkString string; 311 JSString* str; 312 jsval value = *vp; 313 switch (infoType) { 314 case SkType_Boolean: 315 s32 = JSVAL_TO_BOOLEAN(value); 316 break; 317 case SkType_Color: 318 case SkType_S32: 319 s32 = JSVAL_TO_INT(value); 320 break; 321 case SkType_Scalar: 322 if (JSVAL_IS_INT(value)) 323 scalar = SkIntToScalar(JSVAL_TO_INT(value)); 324 else { 325 SkASSERT(JSVAL_IS_DOUBLE(value)); 326#ifdef SK_SCALAR_IS_FLOAT 327 scalar = (float) *(double*) JSVAL_TO_DOUBLE(value); 328#else 329 scalar = (SkFixed) (*(double*)JSVAL_TO_DOUBLE(value) * 65536.0); 330#endif 331 } 332 break; 333 case SkType_String: 334 str = JS_ValueToString(cx, value); 335 string.set(JS_GetStringBytes(str)); 336 break; 337 default: 338 SkASSERT(0); // !!! unimplemented 339 } 340 if (info->fType == SkType_MemberProperty) { 341 switch (infoType) { 342 case SkType_Scalar: { 343 SkScriptValue scriptValue; 344 scriptValue.fType = SkType_Scalar; 345 scriptValue.fOperand.fScalar = scalar; 346 displayable->setProperty(-1 - (int) info->fOffset, scriptValue); 347 } break; 348 default: 349 SkASSERT(0); // !!! unimplemented 350 } 351 } else { 352 SkASSERT(info->fCount == 1); 353 switch (infoType) { 354 case SkType_Boolean: 355 case SkType_Color: 356 case SkType_S32: 357 s32 = *(S32*) ((const char*) displayable + info->fOffset); 358 break; 359 case SkType_String: 360 info->setString(displayable, &string); 361 break; 362 case SkType_Scalar: 363 SkOperand operand; 364 operand.fScalar = scalar; 365 info->setValue(displayable, &operand, 1); 366 break; 367 default: 368 SkASSERT(0); // !!! unimplemented 369 } 370 } 371 return JS_TRUE; 372} 373 374void SkJS::InitializeDisplayables(const SkBitmap& bitmap, JSContext *cx, JSObject *obj, JSObject *proto) { 375 SkJSDisplayable::gCanvas = new SkCanvas(bitmap); 376 SkJSDisplayable::gPaint = new SkPaint(); 377#if SK_USE_CONDENSED_INFO == 0 378 GenerateTables(); 379#else 380 SkASSERT(0); // !!! compressed version hasn't been implemented 381#endif 382 AddInit(cx, obj, proto); 383 AddCircleInit(cx, obj, proto); 384 AddOvalInit(cx, obj, proto); 385 AddPathInit(cx, obj, proto); 386 AddRectangleInit(cx, obj, proto); 387 AddRoundRectInit(cx, obj, proto); 388// AfterInit(cx, obj, proto); 389 ApplyInit(cx, obj, proto); 390 // AnimateInit(cx, obj, proto); 391// AnimateColorInit(cx, obj, proto); 392 AnimateFieldInit(cx, obj, proto); 393// AnimateRotateInit(cx, obj, proto); 394// AnimateScaleInit(cx, obj, proto); 395// AnimateTranslateInit(cx, obj, proto); 396 BitmapInit(cx, obj, proto); 397// BaseBitmapInit(cx, obj, proto); 398// BeforeInit(cx, obj, proto); 399 BitmapShaderInit(cx, obj, proto); 400 BlurInit(cx, obj, proto); 401 ClipInit(cx, obj, proto); 402 ColorInit(cx, obj, proto); 403 CubicToInit(cx, obj, proto); 404 DashInit(cx, obj, proto); 405 DataInit(cx, obj, proto); 406// DimensionsInit(cx, obj, proto); 407 DiscreteInit(cx, obj, proto); 408 DrawToInit(cx, obj, proto); 409 EmbossInit(cx, obj, proto); 410 EventInit(cx, obj, proto); 411// FontInit(cx, obj, proto); 412// FocusInit(cx, obj, proto); 413 ImageInit(cx, obj, proto); 414 IncludeInit(cx, obj, proto); 415// InputInit(cx, obj, proto); 416 LineInit(cx, obj, proto); 417 LinearGradientInit(cx, obj, proto); 418 LineToInit(cx, obj, proto); 419 MatrixInit(cx, obj, proto); 420 MoveInit(cx, obj, proto); 421 MoveToInit(cx, obj, proto); 422 OvalInit(cx, obj, proto); 423 PathInit(cx, obj, proto); 424 PaintInit(cx, obj, proto); 425 DrawPointInit(cx, obj, proto); 426 PolyToPolyInit(cx, obj, proto); 427 PolygonInit(cx, obj, proto); 428 PolylineInit(cx, obj, proto); 429 PostInit(cx, obj, proto); 430 QuadToInit(cx, obj, proto); 431 RadialGradientInit(cx, obj, proto); 432 RandomInit(cx, obj, proto); 433 RectToRectInit(cx, obj, proto); 434 RectangleInit(cx, obj, proto); 435 RemoveInit(cx, obj, proto); 436 ReplaceInit(cx, obj, proto); 437 RotateInit(cx, obj, proto); 438 RoundRectInit(cx, obj, proto); 439 ScaleInit(cx, obj, proto); 440 SetInit(cx, obj, proto); 441 SkewInit(cx, obj, proto); 442 // 3D_CameraInit(cx, obj, proto); 443 // 3D_PatchInit(cx, obj, proto); 444 SnapshotInit(cx, obj, proto); 445// StrokeInit(cx, obj, proto); 446 TextInit(cx, obj, proto); 447 TextOnPathInit(cx, obj, proto); 448 TextToPathInit(cx, obj, proto); 449 TranslateInit(cx, obj, proto); 450// UseInit(cx, obj, proto); 451} 452 453void SkJS::DisposeDisplayables() { 454 delete SkJSDisplayable::gPaint; 455 delete SkJSDisplayable::gCanvas; 456 for (int index = 0; index < kTypeNamesSize; index++) { 457 SkDisplayTypes type = gTypeNames[index].fType; 458 delete[] gDisplayableProperties[type]; 459 } 460} 461