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            *vp = DOUBLE_TO_JSVAL(scalar);
281            break;
282        case SkType_String:
283            str = JS_NewStringCopyN(cx, string->c_str(), string->size());
284            *vp = STRING_TO_JSVAL(str);
285            break;
286        default:
287            SkASSERT(0); // !!! unimplemented
288    }
289    return JS_TRUE;
290}
291
292JSBool SkJSDisplayable::SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) {
293    if (JSVAL_IS_INT(id) == 0)
294        return JS_TRUE;
295    SkJSDisplayable *p = (SkJSDisplayable *) JS_GetPrivate(cx, obj);
296    SkDisplayable* displayable = p->fDisplayable;
297    SkDisplayTypes displayableType = displayable->getType();
298    int members;
299    const SkMemberInfo* info = SkDisplayType::GetMembers(NULL /* fMaker */, displayableType, &members);
300    int idIndex = JSVAL_TO_INT(id);
301    SkASSERT(idIndex >= 0 && idIndex < members);
302    info = &info[idIndex];
303    SkDisplayTypes infoType = info->getType();
304    SkScalar scalar = 0;
305    S32 s32 = 0;
306    SkString string;
307    JSString* str;
308    jsval value = *vp;
309    switch (infoType) {
310        case SkType_Boolean:
311            s32 = JSVAL_TO_BOOLEAN(value);
312            break;
313        case SkType_Color:
314        case SkType_S32:
315            s32 = JSVAL_TO_INT(value);
316            break;
317        case SkType_Scalar:
318            if (JSVAL_IS_INT(value))
319                scalar = SkIntToScalar(JSVAL_TO_INT(value));
320            else {
321                SkASSERT(JSVAL_IS_DOUBLE(value));
322                scalar = (float) *(double*) JSVAL_TO_DOUBLE(value);
323            }
324            break;
325        case SkType_String:
326            str = JS_ValueToString(cx, value);
327            string.set(JS_GetStringBytes(str));
328            break;
329        default:
330            SkASSERT(0); // !!! unimplemented
331    }
332    if (info->fType == SkType_MemberProperty) {
333        switch (infoType) {
334            case SkType_Scalar: {
335                SkScriptValue scriptValue;
336                scriptValue.fType = SkType_Scalar;
337                scriptValue.fOperand.fScalar = scalar;
338                displayable->setProperty(-1 - (int) info->fOffset, scriptValue);
339                } break;
340            default:
341                SkASSERT(0); // !!! unimplemented
342        }
343    } else {
344        SkASSERT(info->fCount == 1);
345        switch (infoType) {
346            case SkType_Boolean:
347            case SkType_Color:
348            case SkType_S32:
349                s32 = *(S32*) ((const char*) displayable + info->fOffset);
350                break;
351            case SkType_String:
352                info->setString(displayable, &string);
353                break;
354            case SkType_Scalar:
355                SkOperand operand;
356                operand.fScalar = scalar;
357                info->setValue(displayable, &operand, 1);
358                break;
359            default:
360                SkASSERT(0); // !!! unimplemented
361        }
362    }
363    return JS_TRUE;
364}
365
366void SkJS::InitializeDisplayables(const SkBitmap& bitmap, JSContext *cx, JSObject *obj, JSObject *proto) {
367    SkJSDisplayable::gCanvas = new SkCanvas(bitmap);
368    SkJSDisplayable::gPaint = new SkPaint();
369#if SK_USE_CONDENSED_INFO == 0
370    GenerateTables();
371#else
372    SkASSERT(0); // !!! compressed version hasn't been implemented
373#endif
374    AddInit(cx, obj, proto);
375    AddCircleInit(cx, obj, proto);
376    AddOvalInit(cx, obj, proto);
377    AddPathInit(cx, obj, proto);
378    AddRectangleInit(cx, obj, proto);
379    AddRoundRectInit(cx, obj, proto);
380//  AfterInit(cx, obj, proto);
381    ApplyInit(cx, obj, proto);
382    // AnimateInit(cx, obj, proto);
383//  AnimateColorInit(cx, obj, proto);
384    AnimateFieldInit(cx, obj, proto);
385//  AnimateRotateInit(cx, obj, proto);
386//  AnimateScaleInit(cx, obj, proto);
387//  AnimateTranslateInit(cx, obj, proto);
388    BitmapInit(cx, obj, proto);
389//  BaseBitmapInit(cx, obj, proto);
390//  BeforeInit(cx, obj, proto);
391    BitmapShaderInit(cx, obj, proto);
392    BlurInit(cx, obj, proto);
393    ClipInit(cx, obj, proto);
394    ColorInit(cx, obj, proto);
395    CubicToInit(cx, obj, proto);
396    DashInit(cx, obj, proto);
397    DataInit(cx, obj, proto);
398//  DimensionsInit(cx, obj, proto);
399    DiscreteInit(cx, obj, proto);
400    DrawToInit(cx, obj, proto);
401    EmbossInit(cx, obj, proto);
402    EventInit(cx, obj, proto);
403//  FontInit(cx, obj, proto);
404//  FocusInit(cx, obj, proto);
405    ImageInit(cx, obj, proto);
406    IncludeInit(cx, obj, proto);
407//  InputInit(cx, obj, proto);
408    LineInit(cx, obj, proto);
409    LinearGradientInit(cx, obj, proto);
410    LineToInit(cx, obj, proto);
411    MatrixInit(cx, obj, proto);
412    MoveInit(cx, obj, proto);
413    MoveToInit(cx, obj, proto);
414    OvalInit(cx, obj, proto);
415    PathInit(cx, obj, proto);
416    PaintInit(cx, obj, proto);
417    DrawPointInit(cx, obj, proto);
418    PolyToPolyInit(cx, obj, proto);
419    PolygonInit(cx, obj, proto);
420    PolylineInit(cx, obj, proto);
421    PostInit(cx, obj, proto);
422    QuadToInit(cx, obj, proto);
423    RadialGradientInit(cx, obj, proto);
424    RandomInit(cx, obj, proto);
425    RectToRectInit(cx, obj, proto);
426    RectangleInit(cx, obj, proto);
427    RemoveInit(cx, obj, proto);
428    ReplaceInit(cx, obj, proto);
429    RotateInit(cx, obj, proto);
430    RoundRectInit(cx, obj, proto);
431    ScaleInit(cx, obj, proto);
432    SetInit(cx, obj, proto);
433    SkewInit(cx, obj, proto);
434    // 3D_CameraInit(cx, obj, proto);
435    // 3D_PatchInit(cx, obj, proto);
436    SnapshotInit(cx, obj, proto);
437//  StrokeInit(cx, obj, proto);
438    TextInit(cx, obj, proto);
439    TextOnPathInit(cx, obj, proto);
440    TextToPathInit(cx, obj, proto);
441    TranslateInit(cx, obj, proto);
442//  UseInit(cx, obj, proto);
443}
444
445void SkJS::DisposeDisplayables() {
446    delete SkJSDisplayable::gPaint;
447    delete SkJSDisplayable::gCanvas;
448    for (int index = 0; index < kTypeNamesSize; index++) {
449        SkDisplayTypes type = gTypeNames[index].fType;
450        delete[] gDisplayableProperties[type];
451    }
452}
453