1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include <jsapi.h>
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkJS.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkString.h"
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef _WIN32_WCE
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comextern "C" {
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void abort() {
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(0);
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned int _control87(unsigned int _new, unsigned int mask ) {
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(0);
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 0;
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    time_t mktime(struct tm *timeptr ) {
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(0);
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 0;
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//  int errno;
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    char *strdup(const char *) {
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(0);
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 0;
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    char *strerror(int errnum) {
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(0);
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 0;
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int isatty(void* fd) {
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(0);
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 0;
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int putenv(const char *envstring) {
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(0);
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 0;
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    char *getenv(const char *varname) {
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(0);
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 0;
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime) {
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(0);
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    struct tm * localtime(const time_t *timer) {
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(0);
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 0;
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    size_t strftime(char *strDest, size_t maxsize, const char *format,
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const struct tm *timeptr ) {
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(0);
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 0;
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic JSBool
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comglobal_enumerate(JSContext *cx, JSObject *obj)
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef LAZY_STANDARD_CLASSES
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return JS_EnumerateStandardClasses(cx, obj);
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return JS_TRUE;
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic JSBool
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comglobal_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp)
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef LAZY_STANDARD_CLASSES
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((flags & JSRESOLVE_ASSIGNING) == 0) {
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        JSBool resolved;
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return JS_FALSE;
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (resolved) {
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            *objp = obj;
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return JS_TRUE;
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX)
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((flags & (JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING)) == 0) {
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        /*
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         * Do this expensive hack only for unoptimized Unix builds, which are
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         * not used for benchmarking.
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         */
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        char *path, *comp, *full;
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const char *name;
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        JSBool ok, found;
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        JSFunction *fun;
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (!JSVAL_IS_STRING(id))
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return JS_TRUE;
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        path = getenv("PATH");
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (!path)
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return JS_TRUE;
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        path = JS_strdup(cx, path);
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (!path)
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return JS_FALSE;
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        name = JS_GetStringBytes(JSVAL_TO_STRING(id));
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        ok = JS_TRUE;
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        for (comp = strtok(path, ":"); comp; comp = strtok(NULL, ":")) {
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (*comp != '\0') {
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                full = JS_smprintf("%s/%s", comp, name);
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (!full) {
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    JS_ReportOutOfMemory(cx);
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    ok = JS_FALSE;
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    break;
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } else {
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                full = (char *)name;
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            found = (access(full, X_OK) == 0);
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (*comp != '\0')
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                free(full);
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (found) {
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fun = JS_DefineFunction(cx, obj, name, Exec, 0, JSPROP_ENUMERATE);
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                ok = (fun != NULL);
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (ok)
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    *objp = obj;
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        JS_free(cx, path);
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return ok;
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return JS_TRUE;
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comJSClass global_class = {
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    "global", JSCLASS_NEW_RESOLVE,
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    JS_PropertyStub,  JS_PropertyStub,
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    JS_PropertyStub,  JS_PropertyStub,
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    global_enumerate, (JSResolveOp) global_resolve,
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    JS_ConvertStub,   JS_FinalizeStub
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkJS::SkJS(void* hwnd) : SkOSWindow(hwnd) {
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((fRuntime = JS_NewRuntime(0x100000)) == NULL) {
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(0);
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((fContext = JS_NewContext(fRuntime, 0x1000)) == NULL) {
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(0);
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ;
1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((fGlobal = JS_NewObject(fContext, &global_class, NULL, NULL)) == NULL) {
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(0);
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (JS_InitStandardClasses(fContext, fGlobal) == NULL) {
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(0);
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    setConfig(SkBitmap::kARGB32_Config);
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    updateSize();
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    setVisibleP(true);
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    InitializeDisplayables(getBitmap(), fContext, fGlobal, NULL);
1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkJS::~SkJS() {
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DisposeDisplayables();
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    JS_DestroyContext(fContext);
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    JS_DestroyRuntime(fRuntime);
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    JS_ShutDown();
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkBool SkJS::EvaluateScript(const char* script, jsval* rVal) {
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return JS_EvaluateScript(fContext, fGlobal, script, strlen(script),
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        "memory" /* no file name */, 0 /* no line number */, rVal);
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkBool SkJS::ValueToString(jsval value, SkString* string) {
1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com     JSString* str = JS_ValueToString(fContext, value);
1998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com     if (str == NULL)
2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         return false;
2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com     string->set(JS_GetStringBytes(str));
2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com     return true;
2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkJS::Test(void* hwnd) {
2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkJS js(hwnd);
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    jsval val;
2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkBool success = js.EvaluateScript("22/7", &val);
2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(success);
2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkString string;
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    success = js.ValueToString(val, &string);
2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(success);
2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(strcmp(string.c_str(), "3.142857142857143") == 0);
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    success = js.EvaluateScript(
2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        "var rect = new rectangle();"
2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        "rect.left = 4;"
2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        "rect.top = 10;"
2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        "rect.right = 20;"
2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        "rect.bottom = 30;"
2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        "rect.width = rect.height + 20;"
2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        "rect.draw();"
2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        , &val);
2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(success);
2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    success = js.ValueToString(val, &string);
2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(success);
2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endifASSERT(success);
229