/* libs/graphics/xml/SkJSDisplayable.cpp ** ** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #include <jsapi.h> #include "SkJS.h" #include "SkDisplayType.h" //#include "SkAnimateColor.h" #include "SkAnimateMaker.h" #include "SkAnimateSet.h" //#include "SkAnimateTransform.h" #include "SkCanvas.h" //#include "SkDimensions.h" #include "SkDisplayAdd.h" #include "SkDisplayApply.h" //#include "SkDisplayBefore.h" #include "SkDisplayEvent.h" //#include "SkDisplayFocus.h" #include "SkDisplayInclude.h" #include "SkDisplayPost.h" #include "SkDisplayRandom.h" #include "SkDraw3D.h" #include "SkDrawBitmap.h" #include "SkDrawClip.h" #include "SkDrawDash.h" #include "SkDrawDiscrete.h" #include "SkDrawEmboss.h" //#include "SkDrawFont.h" #include "SkDrawFull.h" #include "SkDrawGradient.h" #include "SkDrawLine.h" //#include "SkDrawMaskFilter.h" #include "SkDrawMatrix.h" #include "SkDrawOval.h" #include "SkDrawPaint.h" #include "SkDrawPath.h" #include "SkDrawPoint.h" // #include "SkDrawStroke.h" #include "SkDrawText.h" #include "SkDrawTo.h" //#include "SkDrawTransferMode.h" #include "SkDrawTransparentShader.h" //#include "SkDrawUse.h" #include "SkMatrixParts.h" #include "SkPathParts.h" #include "SkPostParts.h" #include "SkScript.h" #include "SkSnapshot.h" #include "SkTextOnPath.h" #include "SkTextToPath.h" class SkJSDisplayable { public: SkJSDisplayable() : fDisplayable(NULL) {} ~SkJSDisplayable() { delete fDisplayable; } static void Destructor(JSContext *cx, JSObject *obj); static JSBool GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); static JSBool SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); static SkCanvas* gCanvas; static SkPaint* gPaint; static JSBool Draw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); SkDisplayable* fDisplayable; }; SkCanvas* SkJSDisplayable::gCanvas; SkPaint* SkJSDisplayable::gPaint; JSBool SkJSDisplayable::Draw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { SkJSDisplayable *p = (SkJSDisplayable*) JS_GetPrivate(cx, obj); SkASSERT(p->fDisplayable->isDrawable()); SkDrawable* drawable = (SkDrawable*) p->fDisplayable; SkAnimateMaker maker(NULL, gCanvas, gPaint); drawable->draw(maker); return JS_TRUE; } JSFunctionSpec SkJSDisplayable_methods[] = { { "draw", SkJSDisplayable::Draw, 1, 0, 0 }, { 0 } }; static JSPropertySpec* gDisplayableProperties[kNumberOfTypes]; static JSClass gDisplayableClasses[kNumberOfTypes]; #define JS_INIT(_prefix, _class) \ static JSBool _class##Constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { \ SkJSDisplayable* jsDisplayable = new SkJSDisplayable(); \ jsDisplayable->fDisplayable = new _prefix##_class(); \ JS_SetPrivate(cx, obj, (void*) jsDisplayable); \ return JS_TRUE; \ } \ \ static JSObject* _class##Init(JSContext *cx, JSObject *obj, JSObject *proto) { \ JSObject *newProtoObj = JS_InitClass(cx, obj, proto, &gDisplayableClasses[SkType_##_class], \ _class##Constructor, 0, \ NULL, SkJSDisplayable_methods , \ NULL, NULL); \ JS_DefineProperties(cx, newProtoObj, gDisplayableProperties[SkType_##_class]); \ return newProtoObj; \ } JS_INIT(Sk, Add) JS_INIT(Sk, AddCircle) JS_INIT(Sk, AddOval) JS_INIT(Sk, AddPath) JS_INIT(Sk, AddRectangle) JS_INIT(Sk, AddRoundRect) //JS_INIT(Sk, After) JS_INIT(Sk, Apply) // JS_INIT(Sk, Animate) //JS_INIT(Sk, AnimateColor) JS_INIT(Sk, AnimateField) //JS_INIT(Sk, AnimateRotate) //JS_INIT(Sk, AnimateScale) //JS_INIT(Sk, AnimateTranslate) JS_INIT(SkDraw, Bitmap) JS_INIT(Sk, BaseBitmap) //JS_INIT(Sk, Before) JS_INIT(SkDraw, BitmapShader) JS_INIT(SkDraw, Blur) JS_INIT(SkDraw, Clip) JS_INIT(SkDraw, Color) JS_INIT(Sk, CubicTo) JS_INIT(Sk, Dash) JS_INIT(Sk, Data) //JS_INIT(Sk, Dimensions) JS_INIT(Sk, Discrete) JS_INIT(Sk, DrawTo) JS_INIT(SkDraw, Emboss) JS_INIT(SkDisplay, Event) // JS_INIT(SkDraw, Font) // JS_INIT(Sk, Focus) JS_INIT(Sk, Image) JS_INIT(Sk, Include) // JS_INIT(Sk, Input) JS_INIT(Sk, Line) JS_INIT(Sk, LinearGradient) JS_INIT(Sk, LineTo) JS_INIT(SkDraw, Matrix) JS_INIT(Sk, Move) JS_INIT(Sk, MoveTo) JS_INIT(Sk, Oval) JS_INIT(SkDraw, Path) JS_INIT(SkDraw, Paint) JS_INIT(Sk, DrawPoint) JS_INIT(Sk, PolyToPoly) JS_INIT(Sk, Polygon) JS_INIT(Sk, Polyline) JS_INIT(Sk, Post) JS_INIT(Sk, QuadTo) JS_INIT(Sk, RadialGradient) JS_INIT(SkDisplay, Random) JS_INIT(Sk, RectToRect) JS_INIT(Sk, Rectangle) JS_INIT(Sk, Remove) JS_INIT(Sk, Replace) JS_INIT(Sk, Rotate) JS_INIT(Sk, RoundRect) JS_INIT(Sk, Scale) JS_INIT(Sk, Set) JS_INIT(Sk, Skew) // JS_INIT(Sk, 3D_Camera) // JS_INIT(Sk, 3D_Patch) JS_INIT(Sk, Snapshot) // JS_INIT(SkDraw, Stroke) JS_INIT(Sk, Text) JS_INIT(Sk, TextOnPath) JS_INIT(Sk, TextToPath) JS_INIT(Sk, Translate) //JS_INIT(Sk, Use) #if SK_USE_CONDENSED_INFO == 0 static void GenerateTables() { for (int index = 0; index < kTypeNamesSize; index++) { int infoCount; SkDisplayTypes type = gTypeNames[index].fType; const SkMemberInfo* info = SkDisplayType::GetMembers(NULL /* fMaker */, type, &infoCount); if (info == NULL) continue; gDisplayableProperties[type] = new JSPropertySpec[infoCount + 1]; JSPropertySpec* propertySpec = gDisplayableProperties[type]; memset(propertySpec, 0, sizeof (JSPropertySpec) * (infoCount + 1)); for (int inner = 0; inner < infoCount; inner++) { if (info[inner].fType == SkType_BaseClassInfo) continue; propertySpec[inner].name = info[inner].fName; propertySpec[inner].tinyid = inner; propertySpec[inner].flags = JSPROP_ENUMERATE; } gDisplayableClasses[type].name = gTypeNames[index].fName; gDisplayableClasses[type].flags = JSCLASS_HAS_PRIVATE; gDisplayableClasses[type].addProperty = JS_PropertyStub; gDisplayableClasses[type].delProperty = JS_PropertyStub; gDisplayableClasses[type].getProperty = SkJSDisplayable::GetProperty; gDisplayableClasses[type].setProperty = SkJSDisplayable::SetProperty; gDisplayableClasses[type].enumerate = JS_EnumerateStub; gDisplayableClasses[type].resolve = JS_ResolveStub; gDisplayableClasses[type].convert = JS_ConvertStub; gDisplayableClasses[type].finalize = SkJSDisplayable::Destructor; } } #endif void SkJSDisplayable::Destructor(JSContext *cx, JSObject *obj) { delete (SkJSDisplayable*) JS_GetPrivate(cx, obj); } JSBool SkJSDisplayable::GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { if (JSVAL_IS_INT(id) == 0) return JS_TRUE; SkJSDisplayable *p = (SkJSDisplayable *) JS_GetPrivate(cx, obj); SkDisplayable* displayable = p->fDisplayable; SkDisplayTypes displayableType = displayable->getType(); int members; const SkMemberInfo* info = SkDisplayType::GetMembers(NULL /* fMaker */, displayableType, &members); int idIndex = JSVAL_TO_INT(id); SkASSERT(idIndex >= 0 && idIndex < members); info = &info[idIndex]; SkDisplayTypes infoType = (SkDisplayTypes) info->fType; SkScalar scalar = 0; S32 s32 = 0; SkString* string= NULL; JSString *str; if (infoType == SkType_MemberProperty) { infoType = info->propertyType(); switch (infoType) { case SkType_Scalar: { SkScriptValue scriptValue; bool success = displayable->getProperty(info->propertyIndex(), &scriptValue); SkASSERT(scriptValue.fType == SkType_Scalar); scalar = scriptValue.fOperand.fScalar; } break; default: SkASSERT(0); // !!! unimplemented } } else { SkASSERT(info->fCount == 1); switch (infoType) { case SkType_Boolean: case SkType_Color: case SkType_S32: s32 = *(S32*) info->memberData(displayable); break; case SkType_String: info->getString(displayable, &string); break; case SkType_Scalar: SkOperand operand; info->getValue(displayable, &operand, 1); scalar = operand.fScalar; break; default: SkASSERT(0); // !!! unimplemented } } switch (infoType) { case SkType_Boolean: *vp = BOOLEAN_TO_JSVAL(s32); break; case SkType_Color: case SkType_S32: *vp = INT_TO_JSVAL(s32); break; case SkType_Scalar: if (SkScalarFraction(scalar) == 0) *vp = INT_TO_JSVAL(SkScalarFloor(scalar)); else #ifdef SK_SCALAR_IS_FLOAT *vp = DOUBLE_TO_JSVAL(scalar); #else *vp = DOUBLE_TO_JSVAL(scalar / 65536.0f ); #endif break; case SkType_String: str = JS_NewStringCopyN(cx, string->c_str(), string->size()); *vp = STRING_TO_JSVAL(str); break; default: SkASSERT(0); // !!! unimplemented } return JS_TRUE; } JSBool SkJSDisplayable::SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { if (JSVAL_IS_INT(id) == 0) return JS_TRUE; SkJSDisplayable *p = (SkJSDisplayable *) JS_GetPrivate(cx, obj); SkDisplayable* displayable = p->fDisplayable; SkDisplayTypes displayableType = displayable->getType(); int members; const SkMemberInfo* info = SkDisplayType::GetMembers(NULL /* fMaker */, displayableType, &members); int idIndex = JSVAL_TO_INT(id); SkASSERT(idIndex >= 0 && idIndex < members); info = &info[idIndex]; SkDisplayTypes infoType = info->getType(); SkScalar scalar = 0; S32 s32 = 0; SkString string; JSString* str; jsval value = *vp; switch (infoType) { case SkType_Boolean: s32 = JSVAL_TO_BOOLEAN(value); break; case SkType_Color: case SkType_S32: s32 = JSVAL_TO_INT(value); break; case SkType_Scalar: if (JSVAL_IS_INT(value)) scalar = SkIntToScalar(JSVAL_TO_INT(value)); else { SkASSERT(JSVAL_IS_DOUBLE(value)); #ifdef SK_SCALAR_IS_FLOAT scalar = (float) *(double*) JSVAL_TO_DOUBLE(value); #else scalar = (SkFixed) (*(double*)JSVAL_TO_DOUBLE(value) * 65536.0); #endif } break; case SkType_String: str = JS_ValueToString(cx, value); string.set(JS_GetStringBytes(str)); break; default: SkASSERT(0); // !!! unimplemented } if (info->fType == SkType_MemberProperty) { switch (infoType) { case SkType_Scalar: { SkScriptValue scriptValue; scriptValue.fType = SkType_Scalar; scriptValue.fOperand.fScalar = scalar; displayable->setProperty(-1 - (int) info->fOffset, scriptValue); } break; default: SkASSERT(0); // !!! unimplemented } } else { SkASSERT(info->fCount == 1); switch (infoType) { case SkType_Boolean: case SkType_Color: case SkType_S32: s32 = *(S32*) ((const char*) displayable + info->fOffset); break; case SkType_String: info->setString(displayable, &string); break; case SkType_Scalar: SkOperand operand; operand.fScalar = scalar; info->setValue(displayable, &operand, 1); break; default: SkASSERT(0); // !!! unimplemented } } return JS_TRUE; } void SkJS::InitializeDisplayables(const SkBitmap& bitmap, JSContext *cx, JSObject *obj, JSObject *proto) { SkJSDisplayable::gCanvas = new SkCanvas(bitmap); SkJSDisplayable::gPaint = new SkPaint(); #if SK_USE_CONDENSED_INFO == 0 GenerateTables(); #else SkASSERT(0); // !!! compressed version hasn't been implemented #endif AddInit(cx, obj, proto); AddCircleInit(cx, obj, proto); AddOvalInit(cx, obj, proto); AddPathInit(cx, obj, proto); AddRectangleInit(cx, obj, proto); AddRoundRectInit(cx, obj, proto); // AfterInit(cx, obj, proto); ApplyInit(cx, obj, proto); // AnimateInit(cx, obj, proto); // AnimateColorInit(cx, obj, proto); AnimateFieldInit(cx, obj, proto); // AnimateRotateInit(cx, obj, proto); // AnimateScaleInit(cx, obj, proto); // AnimateTranslateInit(cx, obj, proto); BitmapInit(cx, obj, proto); // BaseBitmapInit(cx, obj, proto); // BeforeInit(cx, obj, proto); BitmapShaderInit(cx, obj, proto); BlurInit(cx, obj, proto); ClipInit(cx, obj, proto); ColorInit(cx, obj, proto); CubicToInit(cx, obj, proto); DashInit(cx, obj, proto); DataInit(cx, obj, proto); // DimensionsInit(cx, obj, proto); DiscreteInit(cx, obj, proto); DrawToInit(cx, obj, proto); EmbossInit(cx, obj, proto); EventInit(cx, obj, proto); // FontInit(cx, obj, proto); // FocusInit(cx, obj, proto); ImageInit(cx, obj, proto); IncludeInit(cx, obj, proto); // InputInit(cx, obj, proto); LineInit(cx, obj, proto); LinearGradientInit(cx, obj, proto); LineToInit(cx, obj, proto); MatrixInit(cx, obj, proto); MoveInit(cx, obj, proto); MoveToInit(cx, obj, proto); OvalInit(cx, obj, proto); PathInit(cx, obj, proto); PaintInit(cx, obj, proto); DrawPointInit(cx, obj, proto); PolyToPolyInit(cx, obj, proto); PolygonInit(cx, obj, proto); PolylineInit(cx, obj, proto); PostInit(cx, obj, proto); QuadToInit(cx, obj, proto); RadialGradientInit(cx, obj, proto); RandomInit(cx, obj, proto); RectToRectInit(cx, obj, proto); RectangleInit(cx, obj, proto); RemoveInit(cx, obj, proto); ReplaceInit(cx, obj, proto); RotateInit(cx, obj, proto); RoundRectInit(cx, obj, proto); ScaleInit(cx, obj, proto); SetInit(cx, obj, proto); SkewInit(cx, obj, proto); // 3D_CameraInit(cx, obj, proto); // 3D_PatchInit(cx, obj, proto); SnapshotInit(cx, obj, proto); // StrokeInit(cx, obj, proto); TextInit(cx, obj, proto); TextOnPathInit(cx, obj, proto); TextToPathInit(cx, obj, proto); TranslateInit(cx, obj, proto); // UseInit(cx, obj, proto); } void SkJS::DisposeDisplayables() { delete SkJSDisplayable::gPaint; delete SkJSDisplayable::gCanvas; for (int index = 0; index < kTypeNamesSize; index++) { SkDisplayTypes type = gTypeNames[index].fType; delete[] gDisplayableProperties[type]; } }