diff --git a/CMakeLists.txt b/CMakeLists.txt index d11b7d0206..924c3c247a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,8 +13,9 @@ option(PREFER_SYSTEM_LIBRARIES "Prefer to use system libraries over bundled." "O option(DISABLE_DEBUG_MODE "Disable debugging mode." "OFF") # OFF for backward compatibility -option(SUPPORT_DUKTAPE "SUPPORT_DUKTAPE" ON) -option(SUPPORT_NODE "SUPPORT_NODE" ON) +option(SUPPORT_DUKTAPE "SUPPORT_DUKTAPE" OFF) +option(SUPPORT_NODE "SUPPORT_NODE" OFF) +option(SUPPORT_V8 "SUPPORT_V8" ON) option(ENABLE_THREAD_SANITIZER "ENABLE_THREAD_SANITIZER" OFF) option(ENABLE_ADDRESS_SANITIZER "ENABLE_ADDRESS_SANITIZER" OFF) diff --git a/cmake/NodeDeps.cmake b/cmake/NodeDeps.cmake index 21d5972180..cd23c89c5d 100644 --- a/cmake/NodeDeps.cmake +++ b/cmake/NodeDeps.cmake @@ -94,4 +94,6 @@ if (SUPPORT_NODE) add_definitions(-DRTSCRIPT_SUPPORT_NODE) else (SUPPORT_NODE) unset(NODE_LIBRARIES) + unset(NODE_INCLUDE_DIRS) + unset(NODE_LIBRARY_DIRS) endif (SUPPORT_NODE) diff --git a/cmake/V8Deps.cmake b/cmake/V8Deps.cmake new file mode 100644 index 0000000000..534873ca11 --- /dev/null +++ b/cmake/V8Deps.cmake @@ -0,0 +1,78 @@ +set(NODEDIR "${EXTDIR}/libnode-v6.9.0/") +set(V8DIR "${EXTDIR}/v8/") +set(V8_INCLUDE_DIRS ${V8DIR}/include + ${NODEDIR}/deps/uv/include + ${NODEDIR}/deps/cares/include + ${NODEDIR}/deps/openssl/openssl/include + ${NODEDIR}/deps/icu-small/source/common/unicode + ${NODEDIR}/deps/icu-small/source/common) + +if (WIN32) + set(V8_LIBDIR ${V8DIR}/out.gn/ia32.release) + set(V8_LIBRARY_DIRS ${V8_LIBDIR} ${NODEDIR}build/Release/lib ${NODEDIR}Release/lib ${NODEDIR}Release) + set(V8_LIBRARIES + v8.dll.lib v8_libbase.dll.lib v8_libplatform.dll.lib + icutools.lib icustubdata.lib icudata.lib icuucx.lib icui18n.lib + winmm.lib dbghelp.lib shlwapi.lib + libuv.lib openssl.lib) + set(V8_BUILD_PATH_CHECK ${V8_LIBDIR}/v8.dll.lib) + set(V8_SOURCES ${V8_LIBDIR}/v8_binfile.cpp) +elseif (APPLE) + set(V8_LIBDIR ${V8DIR}/out.gn/x64.release/obj) + set (V8_INCLUDE_DIRS ${V8_INCLUDE_DIRS} ${NODEDIR}/deps/icu-small/source/common/) + set(V8_LIBRARY_DIRS + ${V8_LIBDIR} + ${NODEDIR}) + set(V8_LIBRARIES + v8_base + v8_external_snapshot + v8_libplatform + v8_libsampler + v8_libbase + node) + set(V8_BUILD_PATH_CHECK ${V8_LIBDIR}/libv8_base.a) + set(V8_SOURCES ${V8_LIBDIR}/../v8_binfile.cpp) +else () + set(V8_LIBDIR ${V8DIR}/out.gn/x64.release/obj) + set (V8_INCLUDE_DIRS ${V8_INCLUDE_DIRS} ${NODEDIR}/deps/icu-small/source/common/) + set(V8_LIBRARY_DIRS + ${V8_LIBDIR} + ${NODEDIR}/out/Release/obj.target + ${NODEDIR}/out/Release/obj.target/deps/uv + ${NODEDIR}/out/Release/obj.target/deps/v8/tools/gyp + ${NODEDIR}/out/Release/obj.target/deps/cares + ${NODEDIR}/out/Release/obj.target/deps/zlib + ${NODEDIR}/out/Release/obj.target/deps/http_parser + ${NODEDIR}out/Release/obj.target/tools/icu + ) + set(V8_LIBRARIES + v8_base + v8_external_snapshot + v8_libplatform + v8_libsampler + v8_libbase + uv + cares + zlib + http_parser + icustubdata + icudata + icuucx + icui18n + ) + set(V8_BUILD_PATH_CHECK ${V8_LIBDIR}/libv8_base.a) + set(V8_SOURCES ${V8_LIBDIR}/../v8_binfile.cpp) +endif () + +if (SUPPORT_V8) + if(EXISTS ${V8_BUILD_PATH_CHECK}) + message("external/v8 library is built successfully") + else () + message(FATAL_ERROR "external/v8 library is not built, please build it first") + endif () +else (SUPPORT_V8) + unset(V8_INCLUDE_DIRS) + unset(V8_LIBRARY_DIRS) + unset(V8_LIBRARIES) + unset(V8_SOURCES) +endif (SUPPORT_V8) diff --git a/examples/pxScene2d/README.md b/examples/pxScene2d/README.md index 31d55799df..59fa048bc9 100644 --- a/examples/pxScene2d/README.md +++ b/examples/pxScene2d/README.md @@ -6,7 +6,7 @@ ## Minimum requirements >macOS -> * OS : Macbook Pro (macOS Sierra) +> * OS : Macbook Pro (macOS Sierra >=10.12) > * RAM Size : 256 MB > * Disk space : 24 MB > * Processor speed : 1 GHz @@ -32,7 +32,7 @@ ## macOS Setup >Install Xcode, CMake and quilt -> * Download the latest version of Xcode from https://developer.apple.com/xcode/download/ +> * Download the latest version of Xcode (>=9.2) from https://developer.apple.com/xcode/download/ > * Download and install the latest version of brew from https://brew.sh/ > * From terminal install dependencies: cmake, pkg-config, quilt, java. @@ -44,7 +44,7 @@ >Setup Windows 10 > * Windows 10 > * Visual Studio 2017 community with `Desktop development with C++` workload -> * [windows sdk 10.0.16299.0](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk),it is included in VS2017 with above workload and only necessary if you have issue to install with VS2017) +> * [windows sdk 10.0.16299 and windows sdk 10.0.17134(aka 1803)] (https://developer.microsoft.com/en-us/windows/downloads/sdk-archive) > * python 2.7.x , make sure python can work in cmd (setup environment variables depending on install location) > * git for windows , make sure git can work in cmd (setup environment variables depending on install location) > * patch utility for windows (this comes with git. setup environment variables depending on install location of patch.exe) diff --git a/examples/pxScene2d/V8_README.md b/examples/pxScene2d/V8_README.md new file mode 100644 index 0000000000..24fdc4a67e --- /dev/null +++ b/examples/pxScene2d/V8_README.md @@ -0,0 +1,49 @@ +# Description + +pxScene / Spark is a wrapper around the pxCore libraries that can run as a stand-along application on OS X, Windows, and Linux. The wrapper provides Javascript bindings to allow for easy consumption of the low-level pxCore functionality. + +Initially, and in the production builds, pxScene / spark supports Node as the Javascript engine for the application. Node provides lots of nice features that are useful for pxScene development, but it has quite a bit of overhead, so we've been asked to investigate replacing the Node Javascript engine in pxScene with other Javascript engines. + +The first implementation we did involved stripping out Node and replacing it with Duktape (http://duktape.org/). Duktape worked well and the memory overhead was reduced significantly. The problem with duktape is that it is a little *too* small. It lacks a lot of nice features that Node currently supports and that are used in the existing pxScene examples, including some ES6 features like: + +* `let` +* `const` +* `arrow functions` +* promises +* proxy object support + +We investigated adding support for these via a couple of different paths. Our members had trouble with modifying the duktape parsing path because it's complex, making it hard to add new functionality. I also got in touch with the main duktape developer and suggested to the client that maybe we contract with him directly to prioritise features, but that didn't really go too far. + +# V8 + +More recently, the client has asked us to investigate supporting the Chrome JS engine called V8 (https://developers.google.com/v8/) as a replacement for Node. I've worked primarily with Alexey Kuts (kruntuid) to implement the V8 build, since he did a lot of work on the duktape build. He presented a stepped plan that we approved and worked on directly. + +To date, we've been able to build the V8 integration pretty much completely, to the point where it runs the pxScene test suite the same as the Node version, with memory reduction. The memory reduction isn't as much as we'd probably like so we've been looking at turning off specific features in the V8 build to see if that will help. We've identified some items of reduction, but nothing overly significant. + +# Challenges + +One challenge we've had is supporting both Node and V8 in the same executable. This was possible in the duktape integration - the executable could use either interpreter and would default to one or the other based on files in the user's home directory. + +This is not currently possible with the V8 build because Node includes an old version of V8 and the linking of both the old version and the current version causes linker errors. + +# Build + +Here's instructions for building pxScene with V8 instead of Node. The biggest change is the `-DSUPPORT_V8=ON` flag in the first call to `cmake` + +### Setup for V8 specific build on Linux + +* `sudo apt-get install git libglew-dev freeglut3 freeglut3-dev libgcrypt11-dev zlib1g-dev g++ libssl-dev nasm autoconf libtool cmake gnutls-bin libgnutls-dev autoconf libtool nasm` +* `git clone git@github.com:topcoderinc/pxCore.git` +* `cd pxCore` +* `git checkout duktape_proof_of_concept` +* `cd examples/pxScene2d/external` +* `./build.sh` +* `cd ../../../` +* `mkdir temp` +* `cd temp` +* `cmake -DSUPPORT_V8=ON ..` +* `cmake --build . --config Release -- -j1` +* `cd ../examples/pxScene2d/src` +* `./pxscene about.js` + +At this point the `engine` field in about.js should say V8. diff --git a/examples/pxScene2d/external/binfile2cpp.py b/examples/pxScene2d/external/binfile2cpp.py new file mode 100644 index 0000000000..5d1533e9b6 --- /dev/null +++ b/examples/pxScene2d/external/binfile2cpp.py @@ -0,0 +1,31 @@ +#!/usr/bin/python + +import sys +import os + +(src, dst_h, dst_cpp) = sys.argv[1:4] + +out_fd_h = open(dst_h, "a+") +out_fd_cpp = open(dst_cpp, "a+") + +with open(src, "r") as fd: + name = os.path.basename(src).replace(".", "_") + symbol_name_header_data = "extern unsigned char %s_data[];\n" % (name) + symbol_name_header_sz_data = "extern int %s_size;\n" % (name) + + out_fd_h.write(symbol_name_header_data) + out_fd_h.write(symbol_name_header_sz_data) + + sz = os.stat(src).st_size + + symbol_name_cpp_data = "unsigned char %s_data[] = {\n" % (name) + contents = fd.read() + for i in xrange(len(contents)): + symbol_name_cpp_data += ("0x%x" % ord(contents[i])) + ", " + if i > 0 and i % 16 == 0: + symbol_name_cpp_data += "\n" + symbol_name_cpp_data += "};\n" + + symbol_name_cpp_data += "int %s_size = %d;\n" % (name, sz) + + out_fd_cpp.write(symbol_name_cpp_data) diff --git a/examples/pxScene2d/external/build.sh b/examples/pxScene2d/external/build.sh index 41f755ab52..816f2d93c7 100755 --- a/examples/pxScene2d/external/build.sh +++ b/examples/pxScene2d/external/build.sh @@ -139,6 +139,9 @@ then fi +# v8 +bash buildV8.sh + #-------- BREAKPAD (Non -macOS) if [ "$(uname)" != "Darwin" ]; then diff --git a/examples/pxScene2d/external/buildV8.bat b/examples/pxScene2d/external/buildV8.bat new file mode 100644 index 0000000000..2e249ace58 --- /dev/null +++ b/examples/pxScene2d/external/buildV8.bat @@ -0,0 +1,27 @@ +@where msbuild 2> nul +@if %errorlevel% neq 0 ( + @echo. + @echo Please execute this file from inside Visual Studio's Developer Command Prompt + @echo. + pause + goto :eof +) + +cmd /c git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git depot_tools +set PATH=%cd%\depot_tools;%PATH% + +cmd.exe /c gclient + +cmd /c fetch v8 +cd v8 + +cmd /c gclient sync --no-history --with_tags -r 6.9.351 +cmd /c python tools/dev/v8gen.py ia32.release -- is_debug=false v8_enable_i18n_support=false target_cpu=\"x86\" is_component_build=true v8_static_library=true + +cmd /c ninja -C out.gn/ia32.release + +cmd /c python ..\binfile2cpp.py out.gn\ia32.release\natives_blob.bin out.gn\ia32.release\v8_binfile.h out.gn\ia32.release\v8_binfile.cpp +cmd /c python ..\binfile2cpp.py out.gn\ia32.release\snapshot_blob.bin out.gn\ia32.release\v8_binfile.h out.gn\ia32.release\v8_binfile.cpp + +cd .. + diff --git a/examples/pxScene2d/external/buildV8.sh b/examples/pxScene2d/external/buildV8.sh new file mode 100644 index 0000000000..be325a3759 --- /dev/null +++ b/examples/pxScene2d/external/buildV8.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git depot_tools +export PATH=$PWD/depot_tools/:$PATH + +gclient + +fetch v8 +cd v8 + +gclient sync --no-history --with_tags -r 6.9.351 +python tools/dev/v8gen.py x64.release -- is_debug=false v8_enable_i18n_support=false target_cpu=\"x64\" is_component_build=false v8_static_library=true use_custom_libcxx = false use_custom_libcxx_for_host = false + +ninja -C out.gn/x64.release v8 + +python ../binfile2cpp.py out.gn/x64.release/natives_blob.bin out.gn/x64.release/v8_binfile.h out.gn/x64.release/v8_binfile.cpp +python ../binfile2cpp.py out.gn/x64.release/snapshot_blob.bin out.gn/x64.release/v8_binfile.h out.gn/x64.release/v8_binfile.cpp + +cd .. diff --git a/examples/pxScene2d/external/buildWindows.bat b/examples/pxScene2d/external/buildWindows.bat index 84d9989e04..128e8ed6e9 100644 --- a/examples/pxScene2d/external/buildWindows.bat +++ b/examples/pxScene2d/external/buildWindows.bat @@ -16,6 +16,8 @@ cd vc.build\ msbuild external.sln /p:Configuration=Release /p:Platform=Win32 /m cd .. +CALL buildV8.bat + cd breakpad-chrome_55 CALL gyp\gyp.bat src\client\windows\breakpad_client.gyp --no-circular-check cd src\client\windows diff --git a/examples/pxScene2d/external/libnode-v6.9.0/buildNode.sh b/examples/pxScene2d/external/libnode-v6.9.0/buildNode.sh index 4872e4c182..4991935791 100755 --- a/examples/pxScene2d/external/libnode-v6.9.0/buildNode.sh +++ b/examples/pxScene2d/external/libnode-v6.9.0/buildNode.sh @@ -1,4 +1,4 @@ ./configure --shared -make +make -j ln -sf libnode.so.48 out/Release/obj.target/libnode.so ln -sf libnode.48.dylib out/Release/libnode.dylib diff --git a/examples/pxScene2d/src/CMakeLists.txt b/examples/pxScene2d/src/CMakeLists.txt index 088a91e802..cdec7fe476 100644 --- a/examples/pxScene2d/src/CMakeLists.txt +++ b/examples/pxScene2d/src/CMakeLists.txt @@ -14,6 +14,7 @@ include(${PXCOREDIR}/cmake/CommDeps.cmake) include(${PXCOREDIR}/cmake/NodeDeps.cmake) include(${PXCOREDIR}/cmake/DukeDeps.cmake) include(${PXCOREDIR}/cmake/SManDeps.cmake) +include(${PXCOREDIR}/cmake/V8Deps.cmake) set(WESTEROSINC ${EXTDIR}/westeros/external/install/include) set(WESTEROSSTUBINC ${EXTDIR}/westeros-stub) @@ -91,8 +92,8 @@ if (APPLE) set(PXSCENE_LINKER_OPTIONS "${PXSCENE_LINKER_OPTIONS} -fsanitize=address") endif (ENABLE_ADDRESS_SANITIZER) set(PXSCENE_LINK_LIBRARIES) - set(PXSCENE_LINK_DIRECTORIES ${PXSCENE_LINK_DIRECTORIES} ${NODE_LIBRARY_DIRS} ${DUKE_LIBRARY_DIRS} ${COMM_DEPS_LIBRARY_DIRS}) - set(PLATFORM_LIBRARIES pxCore rtCore_s pthread ${NODE_LIBRARIES} ${DUKE_LIBRARIES} ${COMM_DEPS_LIBRARIES}) + set(PXSCENE_LINK_DIRECTORIES ${PXSCENE_LINK_DIRECTORIES} ${NODE_LIBRARY_DIRS} ${V8_LIBRARY_DIRS} ${DUKE_LIBRARY_DIRS} ${COMM_DEPS_LIBRARY_DIRS}) + set(PLATFORM_LIBRARIES pxCore rtCore_s pthread ${NODE_LIBRARIES} ${V8_LIBRARIES} ${DUKE_LIBRARIES} ${COMM_DEPS_LIBRARIES}) include_directories(AFTER ${NODE_INCLUDE_DIRS} ${DUKE_INCLUDE_DIRS} ${COMM_DEPS_INCLUDE_DIRS}) if (DEFINED ENV{CODE_COVERAGE}) message("enabling code coverage support") @@ -115,6 +116,7 @@ elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") add_definitions(${COMM_DEPS_DEFINITIONS}) include_directories(AFTER + ${V8_INCLUDE_DIRS} ${NODE_INCLUDE_DIRS} ${DUKE_INCLUDE_DIRS} ${COMM_DEPS_INCLUDE_DIRS} @@ -122,11 +124,13 @@ elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") set(PXSCENE_LINK_DIRECTORIES ${PXSCENE_LINK_DIRECTORIES} ${NODE_LIBRARY_DIRS} + ${V8_LIBRARY_DIRS} ${DUKE_LIBRARY_DIRS} ${COMM_DEPS_LIBRARY_DIRS} ) set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} ${NODE_LIBRARIES} + ${V8_LIBRARIES} ${DUKE_LIBRARIES} ${COMM_DEPS_LIBRARIES} pthread rt dl m) @@ -272,13 +276,14 @@ elseif (WIN32) -DU_HAVE_STD_STRING=0 -DUCONFIG_NO_BREAK_ITERATION=0 -DUCONFIG_NO_LEGACY_CONVERSION=1 -DUCONFIG_NO_CONVERSION=1 -DHTTP_PARSER_STRICT=0 -DUSE_RENDER_STATS -D_HAS_EXCEPTIONS=0) add_definitions(${COMM_DEPS_DEFINITIONS}) - include_directories(AFTER ${COMM_DEPS_INCLUDE_DIRS} ${NODE_INCLUDE_DIRS} ${DUKE_INCLUDE_DIRS}) + include_directories(AFTER ${COMM_DEPS_INCLUDE_DIRS} ${NODE_INCLUDE_DIRS} ${V8_INCLUDE_DIRS} ${DUKE_INCLUDE_DIRS}) include_directories(AFTER "${EXTDIR}/pthread-2.9" ${WINSPARKLEINC} ${EXTDIR}/breakpad-chrome_55/src/) - set(PXSCENE_LINK_DIRECTORIES ${PXSCENE_LINK_DIRECTORIES} ${COMM_DEPS_LIBRARY_DIRS} ${NODE_LIBRARY_DIRS} ${DUKE_LIBRARY_DIRS}) + set(PXSCENE_LINK_DIRECTORIES ${PXSCENE_LINK_DIRECTORIES} ${COMM_DEPS_LIBRARY_DIRS} ${NODE_LIBRARY_DIRS} + ${V8_LIBRARY_DIRS} ${DUKE_LIBRARY_DIRS}) set(PLATFORM_LIBRARIES pxCore.lib) - set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} ${COMM_DEPS_LIBRARIES} ${NODE_LIBRARIES} ${DUKE_LIBRARIES}) + set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} ${COMM_DEPS_LIBRARIES} ${NODE_LIBRARIES} ${V8_LIBRARIES} ${DUKE_LIBRARIES}) set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} pthreadVC2.lib opengl32.lib Winmm.lib Ws2_32.lib Wldap32.lib msvcrt.lib psapi.lib @@ -319,7 +324,7 @@ set(PXSCENE_DEFINITIONS ${PXSCENE_DEFINITIONS} -D${PX_PLATFORM} -DENABLE_RT_NODE #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") #set(PXSCENE_LINKER_OPTIONS "${PXSCENE_LINKER_OPTIONS} -lgcov") -include_directories(AFTER ${NODE_INCLUDE_DIRS} ${DUKE_INCLUDE_DIRS}) +include_directories(AFTER ${NODE_INCLUDE_DIRS} ${V8_INCLUDE_DIRS} ${DUKE_INCLUDE_DIRS}) include_directories(AFTER ${WESTEROSINC} ${WESTEROSSTUBINC} ${TURBO_JPEG_INCLUDE_DIRS} ${BREAKPADINC} ${RTREMOTEINC} ${PXCOREDIR}/src) include_directories(AFTER ${CMAKE_CURRENT_SOURCE_DIR}) include_directories(AFTER ${CMAKE_CURRENT_SOURCE_DIR}/rasterizer) @@ -457,6 +462,7 @@ if (BUILD_PXSCENE_APP) install(TARGETS pxscene_app RUNTIME DESTINATION . COMPONENT pxscene) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/browser DESTINATION . COMPONENT pxscene) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/node_modules DESTINATION . COMPONENT pxscene) + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/v8_modules DESTINATION . COMPONENT pxscene) if (SUPPORT_DUKTAPE) install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/rcvrcore/" DESTINATION rcvrcore COMPONENT pxscene) install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/duk_modules/" DESTINATION duk_modules COMPONENT pxscene) @@ -469,7 +475,9 @@ if (BUILD_PXSCENE_APP) file(GLOB PXSCENE_INSTALL_FILES "${CMAKE_CURRENT_SOURCE_DIR}/FreeSans.ttf" "${CMAKE_CURRENT_SOURCE_DIR}/*.json" "${CMAKE_CURRENT_SOURCE_DIR}/*.conf" - "${CMAKE_CURRENT_SOURCE_DIR}/../external/vc.build/builds/*.dll" "${CMAKE_CURRENT_SOURCE_DIR}/Release/") + "${CMAKE_CURRENT_SOURCE_DIR}/../external/vc.build/builds/*.dll" + "${CMAKE_CURRENT_SOURCE_DIR}/../external/v8/out.gn/ia32.release/v8*.dll" + "${CMAKE_CURRENT_SOURCE_DIR}/Release/") if (SUPPORT_DUKTAPE) message("installing additional duktape files") install(FILES ${PXSCENE_INSTALL_FILES_JS2} DESTINATION . COMPONENT pxscene) diff --git a/examples/pxScene2d/src/init.js b/examples/pxScene2d/src/init.js index 2bde966d76..db67020aa7 100644 --- a/examples/pxScene2d/src/init.js +++ b/examples/pxScene2d/src/init.js @@ -17,6 +17,7 @@ limitations under the License. */ var isDuk = (typeof Duktape != "undefined")?true:false; +var isV8 = (typeof _isV8 != "undefined")?true:false; if (isDuk) { global.console = require('console'); @@ -41,6 +42,15 @@ global.constructPromise = function (obj) { }); } } +else if (isV8) { +console = require('console'); +timers = require('timers'); + +setTimeout = timers.setTimeout; +clearTimeout = timers.clearTimeout; +setInterval = timers.setInterval; +clearInterval = timers.clearInterval; +} var AppSceneContext = require('rcvrcore/AppSceneContext'); var RPCController = require('rcvrcore/rpcController'); diff --git a/examples/pxScene2d/src/mkapp.sh b/examples/pxScene2d/src/mkapp.sh index 424ef8cfb8..ee4d7037f7 100755 --- a/examples/pxScene2d/src/mkapp.sh +++ b/examples/pxScene2d/src/mkapp.sh @@ -29,6 +29,7 @@ cp $externalDir/curl/lib/.libs/libcurl.4.dylib $bundleLib cp $externalDir/libnode-v6.9.0/out/Release/libnode*.dylib $bundleLib cp $externalDir/ft/objs/.libs/libfreetype.6.dylib $bundleLib cp $externalDir/jpg/.libs/libjpeg.9.dylib $bundleLib +cp $externalDir/v8/out.gn/x64.release/*.bin $bundleBin # Copy OTHER to Bundle... # @@ -67,6 +68,10 @@ ${minJS} shell.js $bundleRes/shell.js ${minJS} browser.js $bundleRes/browser.js ${minJS} about.js $bundleRes/about.js ${minJS} browser/editbox.js $bundleRes/browser/editbox.js +${minJS} test_binding.js $bundleRes/test_binding.js +${minJS} test_module_loading.js $bundleRes/test_module_loading.js +${minJS} test_module_binding.js $bundleRes/test_module_binding.js +${minJS} test_promises.js $bundleRes/test_promises.js #./jsMinFolder.sh browser $bundleRes/browser @@ -74,6 +79,9 @@ ${minJS} browser/editbox.js $bundleRes/browser/editbox.js cp -a duk_modules $bundleRes/duk_modules # Copy node modules cp -a node_modules $bundleRes/node_modules +# Copy v8 modules +cp -a v8_modules $bundleRes/v8_modules + # Copy OTHER to Resources... # diff --git a/examples/pxScene2d/src/pxScene.cpp b/examples/pxScene2d/src/pxScene.cpp index b9eee3831a..3dda3147c7 100644 --- a/examples/pxScene2d/src/pxScene.cpp +++ b/examples/pxScene2d/src/pxScene.cpp @@ -177,6 +177,7 @@ class sceneWindow : public pxWindow, public pxIViewContainer else { snprintf(buffer,sizeof(buffer),"shell.js?url=%s",escapedUrl.c_str()); } + #ifdef RUNINMAIN setView( new pxScriptView(buffer,"javascript/node/v8")); #else diff --git a/examples/pxScene2d/src/pxScene2d.cpp b/examples/pxScene2d/src/pxScene2d.cpp index f8f21f906c..fbec9a9f12 100644 --- a/examples/pxScene2d/src/pxScene2d.cpp +++ b/examples/pxScene2d/src/pxScene2d.cpp @@ -3804,10 +3804,12 @@ void pxScriptView::runScript() if (mCtx) { + mPrintFunc = new rtFunctionCallback(printFunc, this); mGetScene = new rtFunctionCallback(getScene, this); mMakeReady = new rtFunctionCallback(makeReady, this); mGetContextID = new rtFunctionCallback(getContextID, this); + mCtx->add("print", mPrintFunc.getPtr()); mCtx->add("getScene", mGetScene.getPtr()); mCtx->add("makeReady", mMakeReady.getPtr()); mCtx->add("getContextID", mGetContextID.getPtr()); @@ -3815,6 +3817,7 @@ void pxScriptView::runScript() #ifdef RUNINMAIN mReady = new rtPromise(); #endif + mCtx->runFile("init.js"); char buffer[MAX_URL_SIZE + 50]; @@ -3842,10 +3845,29 @@ void pxScriptView::runScript() #endif mCtx->runScript(buffer); rtLogInfo("pxScriptView::runScript() ending\n"); +//#endif } #endif //ENABLE_RT_NODE } +rtError pxScriptView::printFunc(int numArgs, const rtValue* args, rtValue* result, void* ctx) +{ + rtLogInfo(__FUNCTION__); + + if (ctx) + { + pxScriptView* v = (pxScriptView*)ctx; + + if (numArgs > 0 && !args[0].isEmpty()) + { + rtString toPrint = args[0].toString(); + rtLogWarn("%s", toPrint.cString()); + } + } + + return RT_OK; +} + rtError pxScriptView::getScene(int numArgs, const rtValue* args, rtValue* result, void* ctx) { rtLogInfo(__FUNCTION__); diff --git a/examples/pxScene2d/src/pxScene2d.h b/examples/pxScene2d/src/pxScene2d.h index a4df2e7b2e..50661db509 100644 --- a/examples/pxScene2d/src/pxScene2d.h +++ b/examples/pxScene2d/src/pxScene2d.h @@ -1154,6 +1154,8 @@ class pxScriptView: public pxIView protected: + static rtError printFunc(int /*numArgs*/, const rtValue* /*args*/, rtValue* result, void* ctx); + static rtError getScene(int /*numArgs*/, const rtValue* /*args*/, rtValue* result, void* ctx); static rtError makeReady(int /*numArgs*/, const rtValue* /*args*/, rtValue* result, void* ctx); @@ -1270,6 +1272,7 @@ class pxScriptView: public pxIView rtObjectRef mReady; rtObjectRef mScene; rtRef mView; + rtRef mPrintFunc; rtRef mGetScene; rtRef mMakeReady; rtRef mGetContextID; diff --git a/examples/pxScene2d/src/rcvrcore/AppSceneContext.js b/examples/pxScene2d/src/rcvrcore/AppSceneContext.js index fbfe386ee9..d2089f1496 100644 --- a/examples/pxScene2d/src/rcvrcore/AppSceneContext.js +++ b/examples/pxScene2d/src/rcvrcore/AppSceneContext.js @@ -18,7 +18,8 @@ limitations under the License. //"use strict"; -var isDuk=(typeof timers != "undefined")?true:false; +var isDuk=(typeof Duktape != "undefined")?true:false; +var isV8=(typeof _isV8 != "undefined")?true:false; var url = require('url'); var path = require('path'); @@ -36,15 +37,15 @@ var WrapObj = require('rcvrcore/utils/WrapObj'); var log = new Logger('AppSceneContext'); //overriding original timeout and interval functions -var SetTimeout = isDuk?timers.setTimeout:setTimeout; -var ClearTimeout = isDuk?timers.clearTimeout:clearTimeout; -var SetInterval = isDuk?timers.setInterval:setInterval; -var ClearInterval = isDuk?timers.clearInterval:clearInterval; +var SetTimeout = (isDuk || isV8)?timers.setTimeout:setTimeout; +var ClearTimeout = (isDuk || isV8)?timers.clearTimeout:clearTimeout; +var SetInterval = (isDuk || isV8)?timers.setInterval:setInterval; +var ClearInterval = (isDuk || isV8)?timers.clearInterval:clearInterval; var http_wrap = require('rcvrcore/http_wrap'); var https_wrap = require('rcvrcore/https_wrap'); -var ws_wrap = (isDuk)?"":require('rcvrcore/ws_wrap'); +var ws_wrap = (isDuk || isV8)?"":require('rcvrcore/ws_wrap'); function AppSceneContext(params) { @@ -71,7 +72,7 @@ function AppSceneContext(params) { this.xmoduleMap = {}; this.asyncFileAcquisition = new AsyncFileAcquisition(params.scene); this.accessControl = new AccessControl(params.scene); - this.lastHrTime = isDuk?uv.hrtime():process.hrtime(); + this.lastHrTime = isDuk?uv.hrtime():(isV8?uv_hrtime():process.hrtime()); this.resizeTimer = null; this.topXModule = null; this.jarFileMap = new JarFileMap(); @@ -88,7 +89,7 @@ AppSceneContext.prototype.loadScene = function() { //log.info("loadScene() - begins on ctx: " + getContextID() ); var urlParts = url.parse(this.packageUrl, true); var fullPath = this.packageUrl; - var platform = (isDuk)?uv.platform:process.platform; + var platform = (isDuk)?uv.platform:(isV8?uv_platform():process.platform); if (fullPath.substring(0, 4) !== "http") { if( fullPath.charAt(0) === '.' ) { // local file system @@ -335,7 +336,7 @@ AppSceneContext.prototype.runScriptInNewVMContext = function (packageUri, module var self = this; var newSandbox; try { - if (!isDuk) { + if (!isDuk && !isV8) { var requireMethod = function (pkg) { log.message(3, "old use of require not supported: " + pkg); // TODO: remove @@ -359,7 +360,7 @@ AppSceneContext.prototype.runScriptInNewVMContext = function (packageUri, module } } - if (!isDuk) { + if (!isDuk && !isV8) { var processWrap = WrapObj(process, {"binding":function() { throw new Error("process.binding is not supported"); }}); var globalWrap = WrapObj(global, {"process":processWrap}); @@ -405,6 +406,36 @@ AppSceneContext.prototype.runScriptInNewVMContext = function (packageUri, module importTracking: {} }; } + else if (isV8) + { + newSandbox = { + sandboxName: "InitialSandbox", + xmodule: xModule, + console: console, + timers: timers, + global: global, + isV8: isV8, + setTimeout: setTimeout, + clearTimeout: clearTimeout, + setInterval: setInterval, + clearInterval: clearInterval, + runtime: apiForChild, + urlModule: require("url"), + require: require, + loadUrl: loadUrl, + queryStringModule: require("querystring"), + theNamedContext: "Sandbox: " + uri, + //Buffer: Buffer, + importTracking: {}, + print: print, + getScene: getScene, + makeReady: makeReady, + getContextID: getContextID + }; // end sandbox + + queryStringModule = require("querystring"); + urlModule = require("url"); + } else { newSandbox = { @@ -415,7 +446,7 @@ AppSceneContext.prototype.runScriptInNewVMContext = function (packageUri, module urlModule: require("url"), queryStringModule: require("querystring"), theNamedContext: "Sandbox: " + uri, - Buffer: Buffer, + //Buffer: Buffer, importTracking: {} }; // end sandbox } @@ -440,6 +471,14 @@ AppSceneContext.prototype.runScriptInNewVMContext = function (packageUri, module filename: path.normalize(fname), displayErrors: true }, px, xModule, fname, this.basePackageUri); + } else if (isV8) { + var moduleFunc = vm.runInNewContext(sourceCode, newSandbox, { + filename: path.normalize(fname), + displayErrors: true + }, px, xModule, fname, this.basePackageUri); + + moduleFunc(px, xModule, fname, this.basePackageUri); + } else { var moduleFunc = vm.runInNewContext(sourceCode, newSandbox, { filename: path.normalize(fname), @@ -526,7 +565,7 @@ if (false) { AppSceneContext.prototype.getPackageBaseFilePath = function() { var fullPath; var pkgPart; - var platform = (isDuk)?uv.platform:process.platform; + var platform = (isDuk)?uv.platform:(isV8?uv_platform():process.platform); if (this.basePackageUri.substring(0, 4) !== "http") { if (this.basePackageUri.charAt(0) == '.') { pkgPart = this.basePackageUri.substring(1); @@ -646,8 +685,9 @@ AppSceneContext.prototype.include = function(filePath, currentXModule) { modData = require('rcvrcore/' + filePath + '_wrap'); onImportComplete([modData, origFilePath]); return; - } else if( filePath === 'http' || filePath === 'https' ) { - modData = filePath === 'http' ? new http_wrap(_this.accessControl) : new https_wrap(_this.accessControl); + } else if (filePath === 'http' || filePath === 'https') { + var accessControl = _this.accessControl; + modData = filePath === 'http' ? new http_wrap(accessControl) : new https_wrap(accessControl); onImportComplete([modData, origFilePath]); return; } else if( filePath.substring(0, 9) === "px:scene.") { @@ -767,8 +807,12 @@ AppSceneContext.prototype.processCodeBuffer = function(origFilePath, filePath, c if (isDuk) { vm.runInNewContext(sourceCode, _this.sandbox, { filename: filePath, displayErrors: true }, px, xModule, filePath, filePath); - } - else { + } else if (isV8) { + var moduleFunc = vm.runInNewContext(sourceCode, _this.sandbox, { filename: filePath, displayErrors: true }, + px, xModule, filePath, filePath); + + moduleFunc(px, xModule, filePath, filePath); + } else { var moduleFunc = vm.runInContext(sourceCode, _this.sandbox, {filename:filePath, displayErrors:true}); moduleFunc(px, xModule, filePath, filePath); } @@ -804,9 +848,9 @@ AppSceneContext.prototype.processCodeBuffer = function(origFilePath, filePath, c }; AppSceneContext.prototype.onResize = function(resizeEvent) { - var hrTime = isDuk?uv.hrtime():process.hrtime(this.lastHrTime); + var hrTime = isDuk?uv.hrtime():(isV8?uv_hrtime():process.hrtime(this.lastHrTime)); var deltaMillis = (hrTime[0] * 1000 + hrTime[1] / 1000000); - this.lastHrTime = isDuk?uv.hrtime():process.hrtime(); + this.lastHrTime = isDuk?uv.hrtime():(isV8?uv_hrtime():process.hrtime()); if( deltaMillis > 300 ) { if( this.resizeTimer !== null ) { clearTimeout(this.resizeTimer); diff --git a/examples/pxScene2d/src/rcvrcore/SceneModuleLoader.js b/examples/pxScene2d/src/rcvrcore/SceneModuleLoader.js index 9a1796f5b1..ad0998054f 100644 --- a/examples/pxScene2d/src/rcvrcore/SceneModuleLoader.js +++ b/examples/pxScene2d/src/rcvrcore/SceneModuleLoader.js @@ -49,7 +49,7 @@ SceneModuleLoader.prototype.loadScenePackage = function(scene, fileSpec) { } else { - log.message(4, "loadScenePackage: loadArchive succeeded for (",filePath,")."); + log.message(4, "loadScenePackage: loadArchive succeeded for ("+filePath+")."); _this.fileArchive = new FileArchive(filePath, a); log.message(4, "Number of files: " + a.fileNames.length); diff --git a/examples/pxScene2d/src/rcvrcore/scene.1.js b/examples/pxScene2d/src/rcvrcore/scene.1.js index e5cf11f4be..444a8b6ff1 100644 --- a/examples/pxScene2d/src/rcvrcore/scene.1.js +++ b/examples/pxScene2d/src/rcvrcore/scene.1.js @@ -16,7 +16,7 @@ limitations under the License. */ -var isDuk = (typeof timers != "undefined")?true:false; +var isDuk=(typeof Duktape != "undefined")?true:false; var RPCContext = require('rcvrcore/rpcContext'); diff --git a/examples/pxScene2d/src/rcvrcore/utils/AsyncFileAcquisition.js b/examples/pxScene2d/src/rcvrcore/utils/AsyncFileAcquisition.js index c64b8d6233..043dac14f4 100644 --- a/examples/pxScene2d/src/rcvrcore/utils/AsyncFileAcquisition.js +++ b/examples/pxScene2d/src/rcvrcore/utils/AsyncFileAcquisition.js @@ -18,6 +18,8 @@ limitations under the License. "use strict"; +var isDuk=(typeof Duktape != "undefined")?true:false; +var isV8=(typeof _isV8 != "undefined")?true:false; var Logger = require('rcvrcore/Logger').Logger; var SceneModuleLoader = require('rcvrcore/SceneModuleLoader'); var log = new Logger('AsyncFileAcquisition'); @@ -58,7 +60,9 @@ AsyncFileAcquisition.prototype.acquire = function(uri) { } self.requestMap[uri].listeners = null; delete self.requestMap[uri]; - process._tickCallback(); + if (!isDuk && !isV8) { + process._tickCallback(); + } }) .catch(function(error){ console.error("Error"); diff --git a/examples/pxScene2d/src/rcvrcore/utils/FileArchive.js b/examples/pxScene2d/src/rcvrcore/utils/FileArchive.js index 07d137000a..6cef130e65 100644 --- a/examples/pxScene2d/src/rcvrcore/utils/FileArchive.js +++ b/examples/pxScene2d/src/rcvrcore/utils/FileArchive.js @@ -19,13 +19,14 @@ limitations under the License. "use strict"; var isDuk = (typeof timers != "undefined")?true:false; +var isV8 = (typeof _isV8 != "undefined")?true:false; var fs = require('fs'); var url = require('url'); var http = require('http'); // FIXME !!!!!!!!!! duktape merge hack -if (!isDuk) { +if (!isDuk && !isV8) { var JSZip = require("jszip"); } diff --git a/examples/pxScene2d/src/rcvrcore/utils/FileUtils.js b/examples/pxScene2d/src/rcvrcore/utils/FileUtils.js index 3c309d46f4..74b6a13e72 100644 --- a/examples/pxScene2d/src/rcvrcore/utils/FileUtils.js +++ b/examples/pxScene2d/src/rcvrcore/utils/FileUtils.js @@ -18,6 +18,9 @@ limitations under the License. "use strict"; +var isDuk=(typeof Duktape != "undefined")?true:false; +var isV8=(typeof _isV8 != "undefined")?true:false; + var fs = require("fs"); var http = require("http"); var https = require("https"); @@ -70,17 +73,15 @@ function loadFile(fileUri) { fileUri = fileUri.substring(1); } } - var infile = fs.createReadStream(fileUri); - infile.on('data', function (data) { - code += data; - }); - infile.on('end', function () { - log.message(3, "Got file[" + fileUri + "] from file system"); - resolve(code); - }); - infile.on('error', function (err) { - log.error("FAILED to read file[" + fileUri + "] from file system"); - reject(err); + + fs.readFile(fileUri, function (err, data) { + if (err) { + log.error("FAILED to read file[" + fileUri + "] from file system (error=" + err + ")"); + reject(err); + } else { + log.message(3, "Got file[" + fileUri + "] from file system"); + resolve(data); + } }); } }); diff --git a/examples/pxScene2d/src/shell.js b/examples/pxScene2d/src/shell.js index 4b8ce0779f..2d4a6c76db 100644 --- a/examples/pxScene2d/src/shell.js +++ b/examples/pxScene2d/src/shell.js @@ -17,6 +17,7 @@ limitations under the License. */ var isDuk=(typeof Duktape != "undefined")?true:false; +var isV8 = (typeof _isV8 != "undefined")?true:false; px.import({ scene: 'px:scene.1.js', keys: 'px:tools.keys.js' @@ -26,22 +27,22 @@ px.import({ scene: 'px:scene.1.js', var keys = imports.keys; function uncaughtException(err) { - if (!isDuk) { + if (!isDuk && !isV8) { console.log("Received uncaught exception " + err.stack); } } function unhandledRejection(err) { - if (!isDuk) { + if (!isDuk && !isV8) { console.log("Received uncaught rejection.... " + err); } } - if (!isDuk) { + if (!isDuk && !isV8) { process.on('uncaughtException', uncaughtException); process.on('unhandledRejection', unhandledRejection); } - // JRJR TODO had to add more modules + // JRJR TODO had to add more modules var url = queryStringModule.parse(urlModule.parse(module.appSceneContext.packageUrl).query).url; var originalURL = (!url || url==="") ? "browser.js":url; console.log("url:",originalURL); @@ -131,7 +132,7 @@ if (false) else if (code == keys.S) // ctrl-alt-s { - if (!isDuk) { + if (!isDuk && !isV8) { // This returns a data URI string with the image data var dataURI = scene.screenshot('image/png;base64'); @@ -296,7 +297,7 @@ if (false) */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function releaseResources() { - if (!isDuk) { + if (!isDuk && !isV8) { process.removeListener("uncaughtException", uncaughtException); process.removeListener("unhandledRejection", unhandledRejection); } diff --git a/examples/pxScene2d/src/test_binding.js b/examples/pxScene2d/src/test_binding.js new file mode 100644 index 0000000000..8d6eb93b5e --- /dev/null +++ b/examples/pxScene2d/src/test_binding.js @@ -0,0 +1,43 @@ +{ + var vArr = _testArrayReturnFunc(); + print('length=' + vArr.length); + for (i = 0; i < vArr.length; ++i ){ + print('idx[' + i + '] ' +vArr[i]); + } + + vArr[3] = 4; + + print('length=' + vArr.length); + for (i = 0; i < vArr.length; ++i ){ + print('idx[' + i + '] ' +vArr[i]); + } +} + +{ + var vMap = _testMapReturnFunc(); + print("a1: " + vMap["a1"]); + print("a2: " + vMap["a2"]); + print("a3: " + vMap.a3); + vMap["a4"] = 4; + print("a4: " + vMap.a4); +} + +{ + var vObj = _testObjectReturnFunc(); + print("propA: " + vObj.propA); + print("propB: " + vObj.propB); + vObj.propA = 3; + print("propA: " + vObj.propA); + vObj.propC = function () { print("propC()"); return 1; }; + print("propC: " + vObj.propC); + var func = vObj.propC; + func(); + vObj.propC(); + vObj.methodA(); + print('methodB: ' + vObj.methodB()); + print('methodC: ' + vObj.methodC("hi")); +} + +var vObj = _testObjectReturnFunc(); +vObj.methodD = function() {}; +print('methodD: ' + vObj.methodD); diff --git a/examples/pxScene2d/src/test_module_binding.js b/examples/pxScene2d/src/test_module_binding.js new file mode 100644 index 0000000000..a83056996b --- /dev/null +++ b/examples/pxScene2d/src/test_module_binding.js @@ -0,0 +1,20 @@ +print(uv_platform()); +var hr = uv_hrtime() +print(hr[0] + " " + hr[1]); +print("0:"+uv_fs_access('C:\\windows\\notepad.exe', 'r')); +print("1:"+uv_fs_access('C:\\windows\\notepad1.exe', 'r')); +print("size:"+uv_fs_size('C:\\windows\\notepad.exe')); +var fd = uv_fs_open('C:\\windows\\notepad.exe', 'r', 420); +var buf = uv_fs_read(fd, 32, 0); +print(buf.byteLength+""); +uv_fs_close(fd); +var tm = uv_timer_new(); +uv_timer_stop(tm); +var tm2 = uv_timer_new(); +uv_timer_start(tm2, 1000, 1000, function () { print("OK2"); }); +var tm1 = uv_timer_new(); +uv_timer_start(tm1, 5000, 0, function () { print("OK1"); uv_timer_stop(tm2); }); + +uv_run_in_context("print(\"in eval context\");"); + +print("isV8 " + _isV8); diff --git a/examples/pxScene2d/src/test_module_loading.js b/examples/pxScene2d/src/test_module_loading.js new file mode 100644 index 0000000000..765c316b8a --- /dev/null +++ b/examples/pxScene2d/src/test_module_loading.js @@ -0,0 +1,4 @@ +var mod = require("test_module"); +mod.info("hi"); +var mod2 = require("test_module"); +mod2.info("hi2"); diff --git a/examples/pxScene2d/src/test_promises.js b/examples/pxScene2d/src/test_promises.js new file mode 100644 index 0000000000..082005d904 --- /dev/null +++ b/examples/pxScene2d/src/test_promises.js @@ -0,0 +1,43 @@ + + +var promise1 = Promise.resolve(3); +var promise2 = _testPromiseResolvedReturnFunc(); +var promise3 = _testPromiseReturnFunc(); + +Promise.all([promise1, promise2, promise3]).then(function (values) { + print("OK"); +}); + +var promise4 = _testPromiseRejectedReturnFunc(); + +promise4.then(function (val) { + print("resolved2"); +}).catch(function (val) { + print("rejected2"); +}); + +var promise5 = _testPromiseReturnRejectFunc(); + +promise5.then(function (val) { + print("resolved3"); +}).catch(function (val) { + print("rejected3"); +}); + +var promise6 = _testPromiseReturnFunc(); + +new Promise((resolve, reject) => { + promise6.then(function (val) { + resolve(val); + }).catch(function (val) { + reject(val); + }); +}).then(function (val) { + print("resolved4"); +}, +function (val) { + print("rejected4"); +} +); + + diff --git a/examples/pxScene2d/src/v8_modules/console.js b/examples/pxScene2d/src/v8_modules/console.js new file mode 100644 index 0000000000..9e092903b8 --- /dev/null +++ b/examples/pxScene2d/src/v8_modules/console.js @@ -0,0 +1,47 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +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. + +*/ + +"use strict"; + +function trace(msg) { + print("[LOG TRACE] " + msg); +} + +function warn(msg) { + print("[LOG WARN] " + msg); +} + +function error(msg) { + print("[LOG ERROR] " + msg); +} + +function log(msg) { + print("[LOG LOG] " + msg); +} + +function info(msg) { + print("[LOG INFO] " + msg); +} + +module.exports = { + trace: trace, + warn: warn, + error: error, + log: log, + info: info, +} diff --git a/examples/pxScene2d/src/v8_modules/fs.js b/examples/pxScene2d/src/v8_modules/fs.js new file mode 100644 index 0000000000..5a99972c12 --- /dev/null +++ b/examples/pxScene2d/src/v8_modules/fs.js @@ -0,0 +1,36 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +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. + +*/ + +"use strict"; + +function readFile(filePath, cb) { + var ares = uv_fs_access(filePath, 'r'); + if (ares < 0) { + cb(ares, ""); + return; + } + var fd = uv_fs_open(filePath, 'r', 420); + var size = uv_fs_size(filePath); + var res = uv_fs_read(fd, size, 0); + uv_fs_close(fd); + cb(0, res); +} + +module.exports = { + 'readFile': readFile, +} diff --git a/examples/pxScene2d/src/v8_modules/http.js b/examples/pxScene2d/src/v8_modules/http.js new file mode 100644 index 0000000000..5a4171ee63 --- /dev/null +++ b/examples/pxScene2d/src/v8_modules/http.js @@ -0,0 +1,28 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +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. + +*/ + +"use strict"; + +function get(url, cb) { + return httpGet(url, cb); +} + +module.exports = { + 'get': get, + 'request': get, +} diff --git a/examples/pxScene2d/src/v8_modules/http_test.js b/examples/pxScene2d/src/v8_modules/http_test.js new file mode 100644 index 0000000000..6d548ab9b1 --- /dev/null +++ b/examples/pxScene2d/src/v8_modules/http_test.js @@ -0,0 +1,52 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +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. + +*/ + + +px.import({ scene: 'px:scene.1', http: 'http', url: 'url' }).then( function importsAreReady(imports) +{ + var http = imports.http; + var url = imports.url; + + var fetchCb = function (opt) { + var respData = ''; + + http.get(opt, function (resp) { + console.log('http in func cb'); + + resp.on('data', function (chunk) { + console.log('http on data'); + respData += chunk; + }); + + resp.on('end', function () { + console.log('http done. status_code = ' + resp.statusCode + + ' response size = ' + respData.length); + }); + }).on('error', function (e) { + console.log('error fetching data: ' + e.message); + }); + }; + + var fetchUrl = 'https://bellard.org/pi/pi2700e9'; + + fetchCb(fetchUrl); + fetchCb(url.parse(fetchUrl)); + +}).catch( function importFailed(err){ + console.error("Import failed for http_test.js: " + err); +}); diff --git a/examples/pxScene2d/src/v8_modules/https.js b/examples/pxScene2d/src/v8_modules/https.js new file mode 100644 index 0000000000..5a4171ee63 --- /dev/null +++ b/examples/pxScene2d/src/v8_modules/https.js @@ -0,0 +1,28 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +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. + +*/ + +"use strict"; + +function get(url, cb) { + return httpGet(url, cb); +} + +module.exports = { + 'get': get, + 'request': get, +} diff --git a/examples/pxScene2d/src/v8_modules/net.js b/examples/pxScene2d/src/v8_modules/net.js new file mode 100644 index 0000000000..1084611610 --- /dev/null +++ b/examples/pxScene2d/src/v8_modules/net.js @@ -0,0 +1,28 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +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. + +*/ + +"use strict"; + +module.exports = { + 'connect': function () {}, + 'createConnection': function () { }, + 'Socket': function () { }, + 'isIP': function () { return 1; }, + 'isIPv4': function () { return 1; }, + 'isIPv6': function () { return 1; }, +} diff --git a/examples/pxScene2d/src/v8_modules/path.js b/examples/pxScene2d/src/v8_modules/path.js new file mode 100644 index 0000000000..2f92945ca8 --- /dev/null +++ b/examples/pxScene2d/src/v8_modules/path.js @@ -0,0 +1,307 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +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. + +*/ + +"use strict"; + +function normalizeStringWin32(path, allowAboveRoot) { + var res = ''; + var lastSlash = -1; + var dots = 0; + var code; + for (var i = 0; i <= path.length; ++i) { + if (i < path.length) + code = path.charCodeAt(i); + else if (code === 47/*/*/ || code === 92/*\*/) + break; + else + code = 47/*/*/; + if (code === 47/*/*/ || code === 92/*\*/) { + if (lastSlash === i - 1 || dots === 1) { + // NOOP + } else if (lastSlash !== i - 1 && dots === 2) { + if (res.length < 2 || + res.charCodeAt(res.length - 1) !== 46/*.*/ || + res.charCodeAt(res.length - 2) !== 46/*.*/) { + if (res.length > 2) { + const start = res.length - 1; + var j = start; + for (; j >= 0; --j) { + if (res.charCodeAt(j) === 92/*\*/) + break; + } + if (j !== start) { + if (j === -1) + res = ''; + else + res = res.slice(0, j); + lastSlash = i; + dots = 0; + continue; + } + } else if (res.length === 2 || res.length === 1) { + res = ''; + lastSlash = i; + dots = 0; + continue; + } + } + if (allowAboveRoot) { + if (res.length > 0) + res += '\\..'; + else + res = '..'; + } + } else { + if (res.length > 0) + res += '\\' + path.slice(lastSlash + 1, i); + else + res = path.slice(lastSlash + 1, i); + } + lastSlash = i; + dots = 0; + } else if (code === 46/*.*/ && dots !== -1) { + ++dots; + } else { + dots = -1; + } + } + return res; +} + +function normalizeStringPosix(path, allowAboveRoot) { + var res = ''; + var lastSlash = -1; + var dots = 0; + var code; + for (var i = 0; i <= path.length; ++i) { + if (i < path.length) + code = path.charCodeAt(i); + else if (code === 47/*/*/) + break; + else + code = 47/*/*/; + if (code === 47/*/*/) { + if (lastSlash === i - 1 || dots === 1) { + // NOOP + } else if (lastSlash !== i - 1 && dots === 2) { + if (res.length < 2 || + res.charCodeAt(res.length - 1) !== 46/*.*/ || + res.charCodeAt(res.length - 2) !== 46/*.*/) { + if (res.length > 2) { + const start = res.length - 1; + var j = start; + for (; j >= 0; --j) { + if (res.charCodeAt(j) === 47/*/*/) + break; + } + if (j !== start) { + if (j === -1) + res = ''; + else + res = res.slice(0, j); + lastSlash = i; + dots = 0; + continue; + } + } else if (res.length === 2 || res.length === 1) { + res = ''; + lastSlash = i; + dots = 0; + continue; + } + } + if (allowAboveRoot) { + if (res.length > 0) + res += '/..'; + else + res = '..'; + } + } else { + if (res.length > 0) + res += '/' + path.slice(lastSlash + 1, i); + else + res = path.slice(lastSlash + 1, i); + } + lastSlash = i; + dots = 0; + } else if (code === 46/*.*/ && dots !== -1) { + ++dots; + } else { + dots = -1; + } + } + return res; +} + + +win32 = { + normalize: function normalize(path) { + const len = path.length; + if (len === 0) + return '.'; + var rootEnd = 0; + var code = path.charCodeAt(0); + var device; + var isAbsolute = false; + + // Try to match a root + if (len > 1) { + if (code === 47/*/*/ || code === 92/*\*/) { + // Possible UNC root + + // If we started with a separator, we know we at least have an absolute + // path of some kind (UNC or otherwise) + isAbsolute = true; + + code = path.charCodeAt(1); + if (code === 47/*/*/ || code === 92/*\*/) { + // Matched double path separator at beginning + var j = 2; + var last = j; + // Match 1 or more non-path separators + for (; j < len; ++j) { + code = path.charCodeAt(j); + if (code === 47/*/*/ || code === 92/*\*/) + break; + } + if (j < len && j !== last) { + const firstPart = path.slice(last, j); + // Matched! + last = j; + // Match 1 or more path separators + for (; j < len; ++j) { + code = path.charCodeAt(j); + if (code !== 47/*/*/ && code !== 92/*\*/) + break; + } + if (j < len && j !== last) { + // Matched! + last = j; + // Match 1 or more non-path separators + for (; j < len; ++j) { + code = path.charCodeAt(j); + if (code === 47/*/*/ || code === 92/*\*/) + break; + } + if (j === len) { + // We matched a UNC root only + // Return the normalized version of the UNC root since there + // is nothing left to process + + return '\\\\' + firstPart + '\\' + path.slice(last) + '\\'; + } else if (j !== last) { + // We matched a UNC root with leftovers + + device = '\\\\' + firstPart + '\\' + path.slice(last, j); + rootEnd = j; + } + } + } + } else { + rootEnd = 1; + } + } else if ((code >= 65/*A*/ && code <= 90/*Z*/) || + (code >= 97/*a*/ && code <= 122/*z*/)) { + // Possible device root + + code = path.charCodeAt(1); + if (path.charCodeAt(1) === 58/*:*/) { + device = path.slice(0, 2); + rootEnd = 2; + if (len > 2) { + code = path.charCodeAt(2); + if (code === 47/*/*/ || code === 92/*\*/) { + // Treat separator following drive name as an absolute path + // indicator + isAbsolute = true; + rootEnd = 3; + } + } + } + } + } else if (code === 47/*/*/ || code === 92/*\*/) { + // `path` contains just a path separator, exit early to avoid unnecessary + // work + return '\\'; + } + + code = path.charCodeAt(len - 1); + var trailingSeparator = (code === 47/*/*/ || code === 92/*\*/); + var tail; + if (rootEnd < len) + tail = normalizeStringWin32(path.slice(rootEnd), !isAbsolute); + else + tail = ''; + if (tail.length === 0 && !isAbsolute) + tail = '.'; + if (tail.length > 0 && trailingSeparator) + tail += '\\'; + if (device === undefined) { + if (isAbsolute) { + if (tail.length > 0) + return '\\' + tail; + else + return '\\'; + } else if (tail.length > 0) { + return tail; + } else { + return ''; + } + } else { + if (isAbsolute) { + if (tail.length > 0) + return device + '\\' + tail; + else + return device + '\\'; + } else if (tail.length > 0) { + return device + tail; + } else { + return device; + } + } + }, +} + +posix = { + sep: '/', + delimiter: ':', + normalize: function normalize(path) { + if (path.length === 0) + return '.'; + + const isAbsolute = path.charCodeAt(0) === 47/*/*/; + const trailingSeparator = path.charCodeAt(path.length - 1) === 47/*/*/; + + // Normalize the path + path = normalizeStringPosix(path, !isAbsolute); + + if (path.length === 0 && !isAbsolute) + path = '.'; + if (path.length > 0 && trailingSeparator) + path += '/'; + + if (isAbsolute) + return '/' + path; + return path; + }, +} + +if (uv_platform() === 'win32') + module.exports = win32; +else + module.exports = posix; diff --git a/examples/pxScene2d/src/v8_modules/punycode.js b/examples/pxScene2d/src/v8_modules/punycode.js new file mode 100644 index 0000000000..59f3538e40 --- /dev/null +++ b/examples/pxScene2d/src/v8_modules/punycode.js @@ -0,0 +1,459 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +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. + +*/ + +'use strict'; + +/** Highest positive signed 32-bit float value */ +const maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1 + +/** Bootstring parameters */ +const base = 36; +const tMin = 1; +const tMax = 26; +const skew = 38; +const damp = 700; +const initialBias = 72; +const initialN = 128; // 0x80 +const delimiter = '-'; // '\x2D' + +/** Regular expressions */ +const regexPunycode = /^xn--/; +const regexNonASCII = /[^\x20-\x7E]/; // unprintable ASCII chars + non-ASCII chars +const regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators + +/** Error messages */ +const errors = { + 'overflow': 'Overflow: input needs wider integers to process', + 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', + 'invalid-input': 'Invalid input' +}; + +/** Convenience shortcuts */ +const baseMinusTMin = base - tMin; +const floor = Math.floor; +const stringFromCharCode = String.fromCharCode; + +/*--------------------------------------------------------------------------*/ + +/** + * A generic error utility function. + * @private + * @param {String} type The error type. + * @returns {Error} Throws a `RangeError` with the applicable error message. + */ +function error(type) { + throw new RangeError(errors[type]); +} + +/** + * A generic `Array#map` utility function. + * @private + * @param {Array} array The array to iterate over. + * @param {Function} callback The function that gets called for every array + * item. + * @returns {Array} A new array of values returned by the callback function. + */ +function map(array, fn) { + const result = []; + length = array.length; + while (length--) { + result[length] = fn(array[length]); + } + return result; +} + +/** + * A simple `Array#map`-like wrapper to work with domain name strings or email + * addresses. + * @private + * @param {String} domain The domain name or email address. + * @param {Function} callback The function that gets called for every + * character. + * @returns {Array} A new string of characters returned by the callback + * function. + */ +function mapDomain(string, fn) { + const parts = string.split('@'); + result = ''; + if (parts.length > 1) { + // In email addresses, only the domain name should be punycoded. Leave + // the local part (i.e. everything up to `@`) intact. + result = parts[0] + '@'; + string = parts[1]; + } + // Avoid `split(regex)` for IE8 compatibility. See #17. + string = string.replace(regexSeparators, '\x2E'); + const labels = string.split('.'); + const encoded = map(labels, fn).join('.'); + return result + encoded; +} + +/** + * Creates an array containing the numeric code points of each Unicode + * character in the string. While JavaScript uses UCS-2 internally, + * this function will convert a pair of surrogate halves (each of which + * UCS-2 exposes as separate characters) into a single code point, + * matching UTF-16. + * @see `punycode.ucs2.encode` + * @see + * @memberOf punycode.ucs2 + * @name decode + * @param {String} string The Unicode input string (UCS-2). + * @returns {Array} The new array of code points. + */ +function ucs2decode(string) { + const output = []; + counter = 0; + const length = string.length; + while (counter < length) { + const value = string.charCodeAt(counter++); + if (value >= 0xD800 && value <= 0xDBFF && counter < length) { + // It's a high surrogate, and there is a next character. + const extra = string.charCodeAt(counter++); + if ((extra & 0xFC00) == 0xDC00) { // Low surrogate. + output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); + } else { + // It's an unmatched surrogate; only append this code unit, in case the + // next code unit is the high surrogate of a surrogate pair. + output.push(value); + counter--; + } + } else { + output.push(value); + } + } + return output; +} + +/** + * Creates a string based on an array of numeric code points. + * @see `punycode.ucs2.decode` + * @memberOf punycode.ucs2 + * @name encode + * @param {Array} codePoints The array of numeric code points. + * @returns {String} The new Unicode string (UCS-2). + */ +/** + * Converts a basic code point into a digit/integer. + * @see `digitToBasic()` + * @private + * @param {Number} codePoint The basic numeric code point value. + * @returns {Number} The numeric value of a basic code point (for use in + * representing integers) in the range `0` to `base - 1`, or `base` if + * the code point does not represent a value. + */ +const basicToDigit = function(codePoint) { + if (codePoint - 0x30 < 0x0A) { + return codePoint - 0x16; + } + if (codePoint - 0x41 < 0x1A) { + return codePoint - 0x41; + } + if (codePoint - 0x61 < 0x1A) { + return codePoint - 0x61; + } + return base; +}; + +/** + * Converts a digit/integer into a basic code point. + * @see `basicToDigit()` + * @private + * @param {Number} digit The numeric value of a basic code point. + * @returns {Number} The basic code point whose value (when used for + * representing integers) is `digit`, which needs to be in the range + * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is + * used; else, the lowercase form is used. The behavior is undefined + * if `flag` is non-zero and `digit` has no uppercase form. + */ +const digitToBasic = function(digit, flag) { + // 0..25 map to ASCII a..z or A..Z + // 26..35 map to ASCII 0..9 + return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); +}; + +/** + * Bias adaptation function as per section 3.4 of RFC 3492. + * https://tools.ietf.org/html/rfc3492#section-3.4 + * @private + */ +const adapt = function(delta, numPoints, firstTime) { + k = 0; + delta = firstTime ? floor(delta / damp) : delta >> 1; + delta += floor(delta / numPoints); + for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) { + delta = floor(delta / baseMinusTMin); + } + return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); +}; + +/** + * Converts a Punycode string of ASCII-only symbols to a string of Unicode + * symbols. + * @memberOf punycode + * @param {String} input The Punycode string of ASCII-only symbols. + * @returns {String} The resulting string of Unicode symbols. + */ +//const decode = function(input) { +// // Don't use UCS-2. +// const output = []; +// const inputLength = input.length; +// var i = 0; +// var n = initialN; +// var bias = initialBias; + +// // Handle the basic code points: let `basic` be the number of input code +// // points before the last delimiter, or `0` if there is none, then copy +// // the first basic code points to the output. + +// var basic = input.lastIndexOf(delimiter); +// if (basic < 0) { +// basic = 0; +// } + +// for (var j = 0; j < basic; ++j) { +// // if it's not a basic code point +// if (input.charCodeAt(j) >= 0x80) { +// error('not-basic'); +// } +// output.push(input.charCodeAt(j)); +// } + +// // Main decoding loop: start just after the last delimiter if any basic code +// // points were copied; start at the beginning otherwise. + +// for (var index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { + +// // `index` is the index of the next character to be consumed. +// // Decode a generalized variable-length integer into `delta`, +// // which gets added to `i`. The overflow checking is easier +// // if we increase `i` as we go, then subtract off its starting +// // value at the end to obtain `delta`. +// var oldi = i; +// for (var w = 1, k = base; /* no condition */; k += base) { + +// if (index >= inputLength) { +// error('invalid-input'); +// } + +// const digit = basicToDigit(input.charCodeAt(index++)); + +// if (digit >= base || digit > floor((maxInt - i) / w)) { +// error('overflow'); +// } + +// i += digit * w; +// const t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); + +// if (digit < t) { +// break; +// } + +// const baseMinusT = base - t; +// if (w > floor(maxInt / baseMinusT)) { +// error('overflow'); +// } + +// w *= baseMinusT; + +// } + +// const out = output.length + 1; +// bias = adapt(i - oldi, out, oldi == 0); + +// // `i` was supposed to wrap around from `out` to `0`, +// // incrementing `n` each time, so we'll fix that now: +// if (floor(i / out) > maxInt - n) { +// error('overflow'); +// } + +// n += floor(i / out); +// i %= out; + +// // Insert `n` at position `i` of the output. +// output.splice(i++, 0, n); + +// } + +// return String.fromCodePoint(...output); +//}; + +/** + * Converts a string of Unicode symbols (e.g. a domain name label) to a + * Punycode string of ASCII-only symbols. + * @memberOf punycode + * @param {String} input The string of Unicode symbols. + * @returns {String} The resulting Punycode string of ASCII-only symbols. + */ +const encode = function(input) { + const output = []; + + // Convert the input in UCS-2 to an array of Unicode code points. + input = ucs2decode(input); + + // Cache the length. + var inputLength = input.length; + + // Initialize the state. + var n = initialN; + var delta = 0; + var bias = initialBias; + + // Handle the basic code points. + const length = input.length; + var counter = 0; + while (counter < length) { + const currentValue = input.charCodeAt(counter++); + if (currentValue < 0x80) { + output.push(stringFromCharCode(currentValue)); + } + } + + var basicLength = output.length; + var handledCPCount = basicLength; + + // `handledCPCount` is the number of code points that have been handled; + // `basicLength` is the number of basic code points. + + // Finish the basic string with a delimiter unless it's empty. + if (basicLength) { + output.push(delimiter); + } + + // Main encoding loop: + while (handledCPCount < inputLength) { + + // All non-basic code points < n have been handled already. Find the next + // larger one: + var m = maxInt; + var counter = 0; + while (counter < length) { + const currentValue = input.charCodeAt(counter++); + if (currentValue >= n && currentValue < m) { + m = currentValue; + } + } + + // Increase `delta` enough to advance the decoder's state to , + // but guard against overflow. + const handledCPCountPlusOne = handledCPCount + 1; + if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { + error('overflow'); + } + + delta += (m - n) * handledCPCountPlusOne; + n = m; + + var counter1 = 0; + while (counter1 < length) { + const currentValue = input.charCodeAt(counter1++); + if (currentValue < n && ++delta > maxInt) { + error('overflow'); + } + if (currentValue == n) { + // Represent delta as a generalized variable-length integer. + var q = delta; + for (var k = base; /* no condition */; k += base) { + const t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); + if (q < t) { + break; + } + const qMinusT = q - t; + const baseMinusT = base - t; + output.push( + stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) + ); + q = floor(qMinusT / baseMinusT); + } + + output.push(stringFromCharCode(digitToBasic(q, 0))); + bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); + delta = 0; + ++handledCPCount; + } + } + + ++delta; + ++n; + + } + return output.join(''); +}; + +/** + * Converts a Punycode string representing a domain name or an email address + * to Unicode. Only the Punycoded parts of the input will be converted, i.e. + * it doesn't matter if you call it on a string that has already been + * converted to Unicode. + * @memberOf punycode + * @param {String} input The Punycoded domain name or email address to + * convert to Unicode. + * @returns {String} The Unicode representation of the given Punycode + * string. + */ +const toUnicode = function(input) { + return mapDomain(input, function(string) { + return regexPunycode.test(string) + ? decode(string.slice(4).toLowerCase()) + : string; + }); +}; + +/** + * Converts a Unicode string representing a domain name or an email address to + * Punycode. Only the non-ASCII parts of the domain name will be converted, + * i.e. it doesn't matter if you call it with a domain that's already in + * ASCII. + * @memberOf punycode + * @param {String} input The domain name or email address to convert, as a + * Unicode string. + * @returns {String} The Punycode representation of the given domain name or + * email address. + */ +const toASCII = function(input) { + return mapDomain(input, function(string) { + return regexNonASCII.test(string) + ? 'xn--' + encode(string) + : string; + }); +}; + +/*--------------------------------------------------------------------------*/ + +/** Define the public API */ +const punycode = { + /** + * A string representing the current Punycode.js version number. + * @memberOf punycode + * @type String + */ + 'version': '2.0.0', + /** + * An object of methods to convert from JavaScript's internal character + * representation (UCS-2) to Unicode code points, and back. + * @see + * @memberOf punycode + * @type Object + */ + //'decode': decode, + //'encode': encode, + 'toASCII': toASCII, + //'toUnicode': toUnicode +}; + +module.exports = punycode; diff --git a/examples/pxScene2d/src/v8_modules/querystring.js b/examples/pxScene2d/src/v8_modules/querystring.js new file mode 100644 index 0000000000..097f1f8564 --- /dev/null +++ b/examples/pxScene2d/src/v8_modules/querystring.js @@ -0,0 +1,359 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +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. + +*/ + +// Query String Utilities + +'use strict'; + +const QueryString = exports; + +// This constructor is used to store parsed query string values. Instantiating +// this is faster than explicitly calling `Object.create(null)` to get a +// "clean" empty object (tested with v8 v4.9). +function ParsedQueryString() {} +ParsedQueryString.prototype = Object.create(null); + +function qsUnescape(s, decodeSpaces) { + print(s); + return decodeURIComponent(s); +} +QueryString.unescape = qsUnescape; + + +var hexTable = new Array(256); +for (var i = 0; i < 256; ++i) + hexTable[i] = '%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase(); +QueryString.escape = function(str) { + // replaces encodeURIComponent + // http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3.4 + if (typeof str !== 'string') { + if (typeof str === 'object') + str = String(str); + else + str += ''; + } + var out = ''; + var lastPos = 0; + + for (var i = 0; i < str.length; ++i) { + var c = str.charCodeAt(i); + + // These characters do not need escaping (in order): + // ! - . _ ~ + // ' ( ) * + // digits + // alpha (uppercase) + // alpha (lowercase) + if (c === 0x21 || c === 0x2D || c === 0x2E || c === 0x5F || c === 0x7E || + (c >= 0x27 && c <= 0x2A) || + (c >= 0x30 && c <= 0x39) || + (c >= 0x41 && c <= 0x5A) || + (c >= 0x61 && c <= 0x7A)) { + continue; + } + + if (i - lastPos > 0) + out += str.slice(lastPos, i); + + // Other ASCII characters + if (c < 0x80) { + lastPos = i + 1; + out += hexTable[c]; + continue; + } + + // Multi-byte characters ... + if (c < 0x800) { + lastPos = i + 1; + out += hexTable[0xC0 | (c >> 6)] + hexTable[0x80 | (c & 0x3F)]; + continue; + } + if (c < 0xD800 || c >= 0xE000) { + lastPos = i + 1; + out += hexTable[0xE0 | (c >> 12)] + + hexTable[0x80 | ((c >> 6) & 0x3F)] + + hexTable[0x80 | (c & 0x3F)]; + continue; + } + // Surrogate pair + ++i; + var c2; + if (i < str.length) + c2 = str.charCodeAt(i) & 0x3FF; + else + throw new URIError('URI malformed'); + lastPos = i + 1; + c = 0x10000 + (((c & 0x3FF) << 10) | c2); + out += hexTable[0xF0 | (c >> 18)] + + hexTable[0x80 | ((c >> 12) & 0x3F)] + + hexTable[0x80 | ((c >> 6) & 0x3F)] + + hexTable[0x80 | (c & 0x3F)]; + } + if (lastPos === 0) + return str; + if (lastPos < str.length) + return out + str.slice(lastPos); + return out; +}; + +var stringifyPrimitive = function(v) { + if (typeof v === 'string') + return v; + if (typeof v === 'number' && isFinite(v)) + return '' + v; + if (typeof v === 'boolean') + return v ? 'true' : 'false'; + return ''; +}; + + +QueryString.stringify = QueryString.encode = function(obj, sep, eq, options) { + sep = sep || '&'; + eq = eq || '='; + + var encode = QueryString.escape; + if (options && typeof options.encodeURIComponent === 'function') { + encode = options.encodeURIComponent; + } + + if (obj !== null && typeof obj === 'object') { + var keys = Object.keys(obj); + var len = keys.length; + var flast = len - 1; + var fields = ''; + for (var i = 0; i < len; ++i) { + var k = keys[i]; + var v = obj[k]; + var ks = encode(stringifyPrimitive(k)) + eq; + + if (Array.isArray(v)) { + var vlen = v.length; + var vlast = vlen - 1; + for (var j = 0; j < vlen; ++j) { + fields += ks + encode(stringifyPrimitive(v[j])); + if (j < vlast) + fields += sep; + } + if (vlen && i < flast) + fields += sep; + } else { + fields += ks + encode(stringifyPrimitive(v)); + if (i < flast) + fields += sep; + } + } + return fields; + } + return ''; +}; + +// Parse a key/val string. +QueryString.parse = QueryString.decode = function(qs, sep, eq, options) { + sep = sep || '&'; + eq = eq || '='; + + const obj = new ParsedQueryString(); + + if (typeof qs !== 'string' || qs.length === 0) { + return obj; + } + + if (typeof sep !== 'string') + sep += ''; + + const eqLen = eq.length; + const sepLen = sep.length; + + var maxKeys = 1000; + if (options && typeof options.maxKeys === 'number') { + maxKeys = options.maxKeys; + } + + var pairs = Infinity; + if (maxKeys > 0) + pairs = maxKeys; + + var decode = QueryString.unescape; + if (options && typeof options.decodeURIComponent === 'function') { + decode = options.decodeURIComponent; + } + const customDecode = (decode !== qsUnescape); + + + const keys = []; + var lastPos = 0; + var sepIdx = 0; + var eqIdx = 0; + var key = ''; + var value = ''; + var keyEncoded = customDecode; + var valEncoded = customDecode; + var encodeCheck = 0; + for (var i = 0; i < qs.length; ++i) { + const code = qs.charCodeAt(i); + + // Try matching key/value pair separator (e.g. '&') + if (code === sep.charCodeAt(sepIdx)) { + if (++sepIdx === sepLen) { + // Key/value pair separator match! + const end = i - sepIdx + 1; + if (eqIdx < eqLen) { + // If we didn't find the key/value separator, treat the substring as + // part of the key instead of the value + if (lastPos < end) + key += qs.slice(lastPos, end); + } else if (lastPos < end) + value += qs.slice(lastPos, end); + if (keyEncoded) + key = decodeStr(key, decode); + if (valEncoded) + value = decodeStr(value, decode); + // Use a key array lookup instead of using hasOwnProperty(), which is + // slower + if (keys.indexOf(key) === -1) { + obj[key] = value; + keys[keys.length] = key; + } else { + const curValue = obj[key]; + // `instanceof Array` is used instead of Array.isArray() because it + // is ~15-20% faster with v8 4.7 and is safe to use because we are + // using it with values being created within this function + if (curValue instanceof Array) + curValue[curValue.length] = value; + else + obj[key] = [curValue, value]; + } + if (--pairs === 0) + break; + keyEncoded = valEncoded = customDecode; + encodeCheck = 0; + key = value = ''; + lastPos = i + 1; + sepIdx = eqIdx = 0; + } + continue; + } else { + sepIdx = 0; + if (!valEncoded) { + // Try to match an (valid) encoded byte (once) to minimize unnecessary + // calls to string decoding functions + if (code === 37/*%*/) { + encodeCheck = 1; + } else if (encodeCheck > 0 && + ((code >= 48/*0*/ && code <= 57/*9*/) || + (code >= 65/*A*/ && code <= 70/*F*/) || + (code >= 97/*a*/ && code <= 102/*f*/))) { + if (++encodeCheck === 3) + valEncoded = true; + } else { + encodeCheck = 0; + } + } + } + + // Try matching key/value separator (e.g. '=') if we haven't already + if (eqIdx < eqLen) { + if (code === eq.charCodeAt(eqIdx)) { + if (++eqIdx === eqLen) { + // Key/value separator match! + const end = i - eqIdx + 1; + if (lastPos < end) + key += qs.slice(lastPos, end); + encodeCheck = 0; + lastPos = i + 1; + } + continue; + } else { + eqIdx = 0; + if (!keyEncoded) { + // Try to match an (valid) encoded byte once to minimize unnecessary + // calls to string decoding functions + if (code === 37/*%*/) { + encodeCheck = 1; + } else if (encodeCheck > 0 && + ((code >= 48/*0*/ && code <= 57/*9*/) || + (code >= 65/*A*/ && code <= 70/*F*/) || + (code >= 97/*a*/ && code <= 102/*f*/))) { + if (++encodeCheck === 3) + keyEncoded = true; + } else { + encodeCheck = 0; + } + } + } + } + + if (code === 43/*+*/) { + if (eqIdx < eqLen) { + if (i - lastPos > 0) + key += qs.slice(lastPos, i); + key += '%20'; + keyEncoded = true; + } else { + if (i - lastPos > 0) + value += qs.slice(lastPos, i); + value += '%20'; + valEncoded = true; + } + lastPos = i + 1; + } + } + + // Check if we have leftover key or value data + if (pairs > 0 && (lastPos < qs.length || eqIdx > 0)) { + if (lastPos < qs.length) { + if (eqIdx < eqLen) + key += qs.slice(lastPos); + else if (sepIdx < sepLen) + value += qs.slice(lastPos); + } + if (keyEncoded) + key = decodeStr(key, decode); + if (valEncoded) + value = decodeStr(value, decode); + // Use a key array lookup instead of using hasOwnProperty(), which is + // slower + if (keys.indexOf(key) === -1) { + obj[key] = value; + keys[keys.length] = key; + } else { + const curValue = obj[key]; + // `instanceof Array` is used instead of Array.isArray() because it + // is ~15-20% faster with v8 4.7 and is safe to use because we are + // using it with values being created within this function + if (curValue instanceof Array) + curValue[curValue.length] = value; + else + obj[key] = [curValue, value]; + } + } + + return obj; +}; + + +// v8 does not optimize functions with try-catch blocks, so we isolate them here +// to minimize the damage +function decodeStr(s, decoder) { + try { + return decoder(s); + } catch (e) { + return QueryString.unescape(s, true); + } +} + diff --git a/examples/pxScene2d/src/v8_modules/test_module.js b/examples/pxScene2d/src/v8_modules/test_module.js new file mode 100644 index 0000000000..c036f7a9fc --- /dev/null +++ b/examples/pxScene2d/src/v8_modules/test_module.js @@ -0,0 +1,8 @@ + +function info(msg) { + print(msg); +} + +module.exports = { + info: info, +} diff --git a/examples/pxScene2d/src/v8_modules/timers.js b/examples/pxScene2d/src/v8_modules/timers.js new file mode 100644 index 0000000000..9f3e5cd9f5 --- /dev/null +++ b/examples/pxScene2d/src/v8_modules/timers.js @@ -0,0 +1,46 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +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. + +*/ + +"use strict"; + +function setTimeout(cb, delay, a1, a2, a3) { + var tid = uv_timer_new(); + uv_timer_start(tid, delay, 0, function () { cb(a1, a2, a3); }); + return tid; +} + +function clearTimeout(tid) { + uv_timer_stop(tid); +} + +function setInterval(cb, delay, a1, a2, a3) { + var tid = uv_timer_new(); + uv_timer_start(tid, delay, delay, function () { cb(a1, a2, a3); }); + return tid; +} + +function clearInterval(tid) { + uv_timer_stop(tid); +} + +module.exports = { + setTimeout: setTimeout, + clearTimeout: clearTimeout, + setInterval: setInterval, + clearInterval: clearInterval, +} diff --git a/examples/pxScene2d/src/v8_modules/url.js b/examples/pxScene2d/src/v8_modules/url.js new file mode 100644 index 0000000000..418b270a1e --- /dev/null +++ b/examples/pxScene2d/src/v8_modules/url.js @@ -0,0 +1,1015 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +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. + +*/ + +'use strict'; + +toASCII = require('punycode').toASCII; + +exports.parse = urlParse; +exports.resolve = urlResolve; +exports.resolveObject = urlResolveObject; +exports.format = urlFormat; + +exports.Url = Url; + +function Url() { + this.protocol = null; + this.slashes = null; + this.auth = null; + this.host = null; + this.port = null; + this.hostname = null; + this.hash = null; + this.search = null; + this.query = null; + this.pathname = null; + this.path = null; + this.href = null; +} + +// Reference: RFC 3986, RFC 1808, RFC 2396 + +// define these here so at least they only have to be +// compiled once on the first module load. +const protocolPattern = /^([a-z0-9.+-]+:)/i; +const portPattern = /:[0-9]*$/; + +// Special case for a simple path URL +const simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/; + +const hostnameMaxLen = 255; +// protocols that can allow "unsafe" and "unwise" chars. +const unsafeProtocol = { + 'javascript': true, + 'javascript:': true +}; +// protocols that never have a hostname. +const hostlessProtocol = { + 'javascript': true, + 'javascript:': true +}; +// protocols that always contain a // bit. +const slashedProtocol = { + 'http': true, + 'http:': true, + 'https': true, + 'https:': true, + 'ftp': true, + 'ftp:': true, + 'gopher': true, + 'gopher:': true, + 'file': true, + 'file:': true +}; +const querystring = require('querystring.js'); + +// This constructor is used to store parsed query string values. Instantiating +// this is faster than explicitly calling `Object.create(null)` to get a +// "clean" empty object (tested with v8 v4.9). +function ParsedQueryString() {} +ParsedQueryString.prototype = Object.create(null); + +function urlParse(url, parseQueryString, slashesDenoteHost) { + if (url instanceof Url) return url; + + var u = new Url(); + u.parse(url, parseQueryString, slashesDenoteHost); + return u; +} + +Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) { + if (typeof url !== 'string') { + throw new TypeError('Parameter "url" must be a string, not ' + typeof url); + } + + // Copy chrome, IE, opera backslash-handling behavior. + // Back slashes before the query string get converted to forward slashes + // See: https://code.google.com/p/chromium/issues/detail?id=25916 + var hasHash = false; + var start = -1; + var end = -1; + var rest = ''; + var lastPos = 0; + var i = 0; + for (var inWs = false, split = false; i < url.length; ++i) { + const code = url.charCodeAt(i); + + // Find first and last non-whitespace characters for trimming + const isWs = code === 32/* */ || + code === 9/*\t*/ || + code === 13/*\r*/ || + code === 10/*\n*/ || + code === 12/*\f*/ || + code === 160/*\u00A0*/ || + code === 65279/*\uFEFF*/; + if (start === -1) { + if (isWs) + continue; + lastPos = start = i; + } else { + if (inWs) { + if (!isWs) { + end = -1; + inWs = false; + } + } else if (isWs) { + end = i; + inWs = true; + } + } + + // Only convert backslashes while we haven't seen a split character + if (!split) { + switch (code) { + case 35: // '#' + hasHash = true; + // Fall through + case 63: // '?' + split = true; + break; + case 92: // '\\' + if (i - lastPos > 0) + rest += url.slice(lastPos, i); + rest += '/'; + lastPos = i + 1; + break; + } + } else if (!hasHash && code === 35/*#*/) { + hasHash = true; + } + } + + // Check if string was non-empty (including strings with only whitespace) + if (start !== -1) { + if (lastPos === start) { + // We didn't convert any backslashes + + if (end === -1) { + if (start === 0) + rest = url; + else + rest = url.slice(start); + } else { + rest = url.slice(start, end); + } + } else if (end === -1 && lastPos < url.length) { + // We converted some backslashes and have only part of the entire string + rest += url.slice(lastPos); + } else if (end !== -1 && lastPos < end) { + // We converted some backslashes and have only part of the entire string + rest += url.slice(lastPos, end); + } + } + + if (!slashesDenoteHost && !hasHash) { + // Try fast path regexp + const simplePath = simplePathPattern.exec(rest); + if (simplePath) { + this.path = rest; + this.href = rest; + this.pathname = simplePath[1]; + if (simplePath[2]) { + this.search = simplePath[2]; + if (parseQueryString) { + this.query = querystring.parse(this.search.slice(1)); + } else { + this.query = this.search.slice(1); + } + } else if (parseQueryString) { + this.search = ''; + this.query = new ParsedQueryString(); + } + return this; + } + } + + var proto = protocolPattern.exec(rest); + if (proto) { + proto = proto[0]; + var lowerProto = proto.toLowerCase(); + this.protocol = lowerProto; + rest = rest.slice(proto.length); + } + + // figure out if it's got a host + // user@server is *always* interpreted as a hostname, and url + // resolution will treat //foo/bar as host=foo,path=bar because that's + // how the browser resolves relative URLs. + if (slashesDenoteHost || proto || /^\/\/[^@\/]+@[^@\/]+/.test(rest)) { + var slashes = rest.charCodeAt(0) === 47/*/*/ && + rest.charCodeAt(1) === 47/*/*/; + if (slashes && !(proto && hostlessProtocol[proto])) { + rest = rest.slice(2); + this.slashes = true; + } + } + + if (!hostlessProtocol[proto] && + (slashes || (proto && !slashedProtocol[proto]))) { + + // there's a hostname. + // the first instance of /, ?, ;, or # ends the host. + // + // If there is an @ in the hostname, then non-host chars *are* allowed + // to the left of the last @ sign, unless some host-ending character + // comes *before* the @-sign. + // URLs are obnoxious. + // + // ex: + // http://a@b@c/ => user:a@b host:c + // http://a@b?@c => user:a host:b path:/?@c + + // v0.12 TODO(isaacs): This is not quite how Chrome does things. + // Review our test case against browsers more comprehensively. + + var hostEnd = -1; + var atSign = -1; + var nonHost = -1; + for (i = 0; i < rest.length; ++i) { + switch (rest.charCodeAt(i)) { + case 9: // '\t' + case 10: // '\n' + case 13: // '\r' + case 32: // ' ' + case 34: // '"' + case 37: // '%' + case 39: // '\'' + case 59: // ';' + case 60: // '<' + case 62: // '>' + case 92: // '\\' + case 94: // '^' + case 96: // '`' + case 123: // '{' + case 124: // '|' + case 125: // '}' + // Characters that are never ever allowed in a hostname from RFC 2396 + if (nonHost === -1) + nonHost = i; + break; + case 35: // '#' + case 47: // '/' + case 63: // '?' + // Find the first instance of any host-ending characters + if (nonHost === -1) + nonHost = i; + hostEnd = i; + break; + case 64: // '@' + // At this point, either we have an explicit point where the + // auth portion cannot go past, or the last @ char is the decider. + atSign = i; + nonHost = -1; + break; + } + if (hostEnd !== -1) + break; + } + start = 0; + if (atSign !== -1) { + this.auth = decodeURIComponent(rest.slice(0, atSign)); + start = atSign + 1; + } + if (nonHost === -1) { + this.host = rest.slice(start); + rest = ''; + } else { + this.host = rest.slice(start, nonHost); + rest = rest.slice(nonHost); + } + + // pull out port. + this.parseHost(); + + // we've indicated that there is a hostname, + // so even if it's empty, it has to be present. + if (typeof this.hostname !== 'string') + this.hostname = ''; + + var hostname = this.hostname; + + // if hostname begins with [ and ends with ] + // assume that it's an IPv6 address. + var ipv6Hostname = hostname.charCodeAt(0) === 91/*[*/ && + hostname.charCodeAt(hostname.length - 1) === 93/*]*/; + + // validate a little. + if (!ipv6Hostname) { + const result = validateHostname(this, rest, hostname); + if (result !== undefined) + rest = result; + } + + if (this.hostname.length > hostnameMaxLen) { + this.hostname = ''; + } else { + // hostnames are always lower case. + this.hostname = this.hostname.toLowerCase(); + } + + if (!ipv6Hostname) { + // IDNA Support: Returns a punycoded representation of "domain". + // It only converts parts of the domain name that + // have non-ASCII characters, i.e. it doesn't matter if + // you call it with a domain that already is ASCII-only. + this.hostname = toASCII(this.hostname); + } + + var p = this.port ? ':' + this.port : ''; + var h = this.hostname || ''; + this.host = h + p; + + // strip [ and ] from the hostname + // the host field still retains them, though + if (ipv6Hostname) { + this.hostname = this.hostname.slice(1, -1); + if (rest[0] !== '/') { + rest = '/' + rest; + } + } + } + + // now rest is set to the post-host stuff. + // chop off any delim chars. + if (!unsafeProtocol[lowerProto]) { + // First, make 100% sure that any "autoEscape" chars get + // escaped, even if encodeURIComponent doesn't think they + // need to be. + const result = autoEscapeStr(rest); + if (result !== undefined) + rest = result; + } + + var questionIdx = -1; + var hashIdx = -1; + for (i = 0; i < rest.length; ++i) { + const code = rest.charCodeAt(i); + if (code === 35/*#*/) { + this.hash = rest.slice(i); + hashIdx = i; + break; + } else if (code === 63/*?*/ && questionIdx === -1) { + questionIdx = i; + } + } + + if (questionIdx !== -1) { + if (hashIdx === -1) { + this.search = rest.slice(questionIdx); + this.query = rest.slice(questionIdx + 1); + } else { + this.search = rest.slice(questionIdx, hashIdx); + this.query = rest.slice(questionIdx + 1, hashIdx); + } + if (parseQueryString) { + this.query = querystring.parse(this.query); + } + } else if (parseQueryString) { + // no query string, but parseQueryString still requested + this.search = ''; + this.query = new ParsedQueryString(); + } + + var firstIdx = (questionIdx !== -1 && + (hashIdx === -1 || questionIdx < hashIdx) + ? questionIdx + : hashIdx); + if (firstIdx === -1) { + if (rest.length > 0) + this.pathname = rest; + } else if (firstIdx > 0) { + this.pathname = rest.slice(0, firstIdx); + } + if (slashedProtocol[lowerProto] && + this.hostname && !this.pathname) { + this.pathname = '/'; + } + + // to support http.request + if (this.pathname || this.search) { + const p = this.pathname || ''; + const s = this.search || ''; + this.path = p + s; + } + + // finally, reconstruct the href based on what has been validated. + this.href = this.format(); + return this; +}; + +function validateHostname(self, rest, hostname) { + for (var i = 0, lastPos; i <= hostname.length; ++i) { + var code; + if (i < hostname.length) + code = hostname.charCodeAt(i); + if (code === 46/*.*/ || i === hostname.length) { + if (i - lastPos > 0) { + if (i - lastPos > 63) { + self.hostname = hostname.slice(0, lastPos + 63); + return '/' + hostname.slice(lastPos + 63) + rest; + } + } + lastPos = i + 1; + continue; + } else if ((code >= 48/*0*/ && code <= 57/*9*/) || + (code >= 97/*a*/ && code <= 122/*z*/) || + code === 45/*-*/ || + (code >= 65/*A*/ && code <= 90/*Z*/) || + code === 43/*+*/ || + code === 95/*_*/ || + code > 127) { + continue; + } + // Invalid host character + self.hostname = hostname.slice(0, i); + if (i < hostname.length) + return '/' + hostname.slice(i) + rest; + break; + } +} + +function autoEscapeStr(rest) { + var newRest = ''; + var lastPos = 0; + for (var i = 0; i < rest.length; ++i) { + // Automatically escape all delimiters and unwise characters from RFC 2396 + // Also escape single quotes in case of an XSS attack + switch (rest.charCodeAt(i)) { + case 9: // '\t' + if (i - lastPos > 0) + newRest += rest.slice(lastPos, i); + newRest += '%09'; + lastPos = i + 1; + break; + case 10: // '\n' + if (i - lastPos > 0) + newRest += rest.slice(lastPos, i); + newRest += '%0A'; + lastPos = i + 1; + break; + case 13: // '\r' + if (i - lastPos > 0) + newRest += rest.slice(lastPos, i); + newRest += '%0D'; + lastPos = i + 1; + break; + case 32: // ' ' + if (i - lastPos > 0) + newRest += rest.slice(lastPos, i); + newRest += '%20'; + lastPos = i + 1; + break; + case 34: // '"' + if (i - lastPos > 0) + newRest += rest.slice(lastPos, i); + newRest += '%22'; + lastPos = i + 1; + break; + case 39: // '\'' + if (i - lastPos > 0) + newRest += rest.slice(lastPos, i); + newRest += '%27'; + lastPos = i + 1; + break; + case 60: // '<' + if (i - lastPos > 0) + newRest += rest.slice(lastPos, i); + newRest += '%3C'; + lastPos = i + 1; + break; + case 62: // '>' + if (i - lastPos > 0) + newRest += rest.slice(lastPos, i); + newRest += '%3E'; + lastPos = i + 1; + break; + case 92: // '\\' + if (i - lastPos > 0) + newRest += rest.slice(lastPos, i); + newRest += '%5C'; + lastPos = i + 1; + break; + case 94: // '^' + if (i - lastPos > 0) + newRest += rest.slice(lastPos, i); + newRest += '%5E'; + lastPos = i + 1; + break; + case 96: // '`' + if (i - lastPos > 0) + newRest += rest.slice(lastPos, i); + newRest += '%60'; + lastPos = i + 1; + break; + case 123: // '{' + if (i - lastPos > 0) + newRest += rest.slice(lastPos, i); + newRest += '%7B'; + lastPos = i + 1; + break; + case 124: // '|' + if (i - lastPos > 0) + newRest += rest.slice(lastPos, i); + newRest += '%7C'; + lastPos = i + 1; + break; + case 125: // '}' + if (i - lastPos > 0) + newRest += rest.slice(lastPos, i); + newRest += '%7D'; + lastPos = i + 1; + break; + } + } + if (lastPos === 0) + return; + if (lastPos < rest.length) + return newRest + rest.slice(lastPos); + else + return newRest; +} + +// format a parsed object into a url string +function urlFormat(obj) { + // ensure it's an object, and not a string url. + // If it's an obj, this is a no-op. + // this way, you can call url_format() on strings + // to clean up potentially wonky urls. + if (typeof obj === 'string') obj = urlParse(obj); + + else if (typeof obj !== 'object' || obj === null) + throw new TypeError('Parameter "urlObj" must be an object, not ' + + obj === null ? 'null' : typeof obj); + + else if (!(obj instanceof Url)) return Url.prototype.format.call(obj); + + return obj.format(); +} + +Url.prototype.format = function() { + var auth = this.auth || ''; + if (auth) { + auth = encodeAuth(auth); + auth += '@'; + } + + var protocol = this.protocol || ''; + var pathname = this.pathname || ''; + var hash = this.hash || ''; + var host = false; + var query = ''; + + if (this.host) { + host = auth + this.host; + } else if (this.hostname) { + host = auth + (this.hostname.indexOf(':') === -1 ? + this.hostname : + '[' + this.hostname + ']'); + if (this.port) { + host += ':' + this.port; + } + } + + if (this.query !== null && typeof this.query === 'object') + query = querystring.stringify(this.query); + + var search = this.search || (query && ('?' + query)) || ''; + + if (protocol && protocol.charCodeAt(protocol.length - 1) !== 58/*:*/) + protocol += ':'; + + var newPathname = ''; + var lastPos = 0; + for (var i = 0; i < pathname.length; ++i) { + switch (pathname.charCodeAt(i)) { + case 35: // '#' + if (i - lastPos > 0) + newPathname += pathname.slice(lastPos, i); + newPathname += '%23'; + lastPos = i + 1; + break; + case 63: // '?' + if (i - lastPos > 0) + newPathname += pathname.slice(lastPos, i); + newPathname += '%3F'; + lastPos = i + 1; + break; + } + } + if (lastPos > 0) { + if (lastPos !== pathname.length) + pathname = newPathname + pathname.slice(lastPos); + else + pathname = newPathname; + } + + // only the slashedProtocols get the //. Not mailto:, xmpp:, etc. + // unless they had them to begin with. + if (this.slashes || + (!protocol || slashedProtocol[protocol]) && host !== false) { + host = '//' + (host || ''); + if (pathname && pathname.charCodeAt(0) !== 47/*/*/) + pathname = '/' + pathname; + } else if (!host) { + host = ''; + } + + search = search.replace(/#/g, '%23'); + + if (hash && hash.charCodeAt(0) !== 35/*#*/) hash = '#' + hash; + if (search && search.charCodeAt(0) !== 63/*?*/) search = '?' + search; + + return protocol + host + pathname + search + hash; +}; + +function urlResolve(source, relative) { + return urlParse(source, false, true).resolve(relative); +} + +Url.prototype.resolve = function(relative) { + return this.resolveObject(urlParse(relative, false, true)).format(); +}; + +function urlResolveObject(source, relative) { + if (!source) return relative; + return urlParse(source, false, true).resolveObject(relative); +} + +Url.prototype.resolveObject = function(relative) { + if (typeof relative === 'string') { + var rel = new Url(); + rel.parse(relative, false, true); + relative = rel; + } + + var result = new Url(); + var tkeys = Object.keys(this); + for (var tk = 0; tk < tkeys.length; tk++) { + var tkey = tkeys[tk]; + result[tkey] = this[tkey]; + } + + // hash is always overridden, no matter what. + // even href="" will remove it. + result.hash = relative.hash; + + // if the relative url is empty, then there's nothing left to do here. + if (relative.href === '') { + result.href = result.format(); + return result; + } + + // hrefs like //foo/bar always cut to the protocol. + if (relative.slashes && !relative.protocol) { + // take everything except the protocol from relative + var rkeys = Object.keys(relative); + for (var rk = 0; rk < rkeys.length; rk++) { + var rkey = rkeys[rk]; + if (rkey !== 'protocol') + result[rkey] = relative[rkey]; + } + + //urlParse appends trailing / to urls like http://www.example.com + if (slashedProtocol[result.protocol] && + result.hostname && !result.pathname) { + result.path = result.pathname = '/'; + } + + result.href = result.format(); + return result; + } + + if (relative.protocol && relative.protocol !== result.protocol) { + // if it's a known url protocol, then changing + // the protocol does weird things + // first, if it's not file:, then we MUST have a host, + // and if there was a path + // to begin with, then we MUST have a path. + // if it is file:, then the host is dropped, + // because that's known to be hostless. + // anything else is assumed to be absolute. + if (!slashedProtocol[relative.protocol]) { + var keys = Object.keys(relative); + for (var v = 0; v < keys.length; v++) { + var k = keys[v]; + result[k] = relative[k]; + } + result.href = result.format(); + return result; + } + + result.protocol = relative.protocol; + if (!relative.host && + !/^file:?$/.test(relative.protocol) && + !hostlessProtocol[relative.protocol]) { + const relPath = (relative.pathname || '').split('/'); + while (relPath.length && !(relative.host = relPath.shift())); + if (!relative.host) relative.host = ''; + if (!relative.hostname) relative.hostname = ''; + if (relPath[0] !== '') relPath.unshift(''); + if (relPath.length < 2) relPath.unshift(''); + result.pathname = relPath.join('/'); + } else { + result.pathname = relative.pathname; + } + result.search = relative.search; + result.query = relative.query; + result.host = relative.host || ''; + result.auth = relative.auth; + result.hostname = relative.hostname || relative.host; + result.port = relative.port; + // to support http.request + if (result.pathname || result.search) { + var p = result.pathname || ''; + var s = result.search || ''; + result.path = p + s; + } + result.slashes = result.slashes || relative.slashes; + result.href = result.format(); + return result; + } + + var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'); + var isRelAbs = ( + relative.host || + relative.pathname && relative.pathname.charAt(0) === '/' + ); + var mustEndAbs = (isRelAbs || isSourceAbs || + (result.host && relative.pathname)); + var removeAllDots = mustEndAbs; + var srcPath = result.pathname && result.pathname.split('/') || []; + var relPath = relative.pathname && relative.pathname.split('/') || []; + var psychotic = result.protocol && !slashedProtocol[result.protocol]; + + // if the url is a non-slashed url, then relative + // links like ../.. should be able + // to crawl up to the hostname, as well. This is strange. + // result.protocol has already been set by now. + // Later on, put the first path part into the host field. + if (psychotic) { + result.hostname = ''; + result.port = null; + if (result.host) { + if (srcPath[0] === '') srcPath[0] = result.host; + else srcPath.unshift(result.host); + } + result.host = ''; + if (relative.protocol) { + relative.hostname = null; + relative.port = null; + result.auth = null; + if (relative.host) { + if (relPath[0] === '') relPath[0] = relative.host; + else relPath.unshift(relative.host); + } + relative.host = null; + } + mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === ''); + } + + if (isRelAbs) { + // it's absolute. + if (relative.host || relative.host === '') { + if (result.host !== relative.host) result.auth = null; + result.host = relative.host; + result.port = relative.port; + } + if (relative.hostname || relative.hostname === '') { + if (result.hostname !== relative.hostname) result.auth = null; + result.hostname = relative.hostname; + } + result.search = relative.search; + result.query = relative.query; + srcPath = relPath; + // fall through to the dot-handling below. + } else if (relPath.length) { + // it's relative + // throw away the existing file, and take the new path instead. + if (!srcPath) srcPath = []; + srcPath.pop(); + srcPath = srcPath.concat(relPath); + result.search = relative.search; + result.query = relative.query; + } else if (relative.search !== null && relative.search !== undefined) { + // just pull out the search. + // like href='?foo'. + // Put this after the other two cases because it simplifies the booleans + if (psychotic) { + result.hostname = result.host = srcPath.shift(); + //occasionally the auth can get stuck only in host + //this especially happens in cases like + //url.resolveObject('mailto:local1@domain1', 'local2@domain2') + const authInHost = result.host && result.host.indexOf('@') > 0 ? + result.host.split('@') : false; + if (authInHost) { + result.auth = authInHost.shift(); + result.host = result.hostname = authInHost.shift(); + } + } + result.search = relative.search; + result.query = relative.query; + //to support http.request + if (result.pathname !== null || result.search !== null) { + result.path = (result.pathname ? result.pathname : '') + + (result.search ? result.search : ''); + } + result.href = result.format(); + return result; + } + + if (!srcPath.length) { + // no path at all. easy. + // we've already handled the other stuff above. + result.pathname = null; + //to support http.request + if (result.search) { + result.path = '/' + result.search; + } else { + result.path = null; + } + result.href = result.format(); + return result; + } + + // if a url ENDs in . or .., then it must get a trailing slash. + // however, if it ends in anything else non-slashy, + // then it must NOT get a trailing slash. + var last = srcPath.slice(-1)[0]; + var hasTrailingSlash = ( + (result.host || relative.host || srcPath.length > 1) && + (last === '.' || last === '..') || last === ''); + + // strip single dots, resolve double dots to parent dir + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = srcPath.length - 1; i >= 0; i--) { + last = srcPath[i]; + if (last === '.') { + spliceOne(srcPath, i); + } else if (last === '..') { + spliceOne(srcPath, i); + up++; + } else if (up) { + spliceOne(srcPath, i); + up--; + } + } + + // if the path is allowed to go above the root, restore leading ..s + if (!mustEndAbs && !removeAllDots) { + for (; up--; up) { + srcPath.unshift('..'); + } + } + + if (mustEndAbs && srcPath[0] !== '' && + (!srcPath[0] || srcPath[0].charAt(0) !== '/')) { + srcPath.unshift(''); + } + + if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) { + srcPath.push(''); + } + + var isAbsolute = srcPath[0] === '' || + (srcPath[0] && srcPath[0].charAt(0) === '/'); + + // put the host back + if (psychotic) { + result.hostname = result.host = isAbsolute ? '' : + srcPath.length ? srcPath.shift() : ''; + //occasionally the auth can get stuck only in host + //this especially happens in cases like + //url.resolveObject('mailto:local1@domain1', 'local2@domain2') + const authInHost = result.host && result.host.indexOf('@') > 0 ? + result.host.split('@') : false; + if (authInHost) { + result.auth = authInHost.shift(); + result.host = result.hostname = authInHost.shift(); + } + } + + mustEndAbs = mustEndAbs || (result.host && srcPath.length); + + if (mustEndAbs && !isAbsolute) { + srcPath.unshift(''); + } + + if (!srcPath.length) { + result.pathname = null; + result.path = null; + } else { + result.pathname = srcPath.join('/'); + } + + //to support request.http + if (result.pathname !== null || result.search !== null) { + result.path = (result.pathname ? result.pathname : '') + + (result.search ? result.search : ''); + } + result.auth = relative.auth || result.auth; + result.slashes = result.slashes || relative.slashes; + result.href = result.format(); + return result; +}; + +Url.prototype.parseHost = function() { + var host = this.host; + var port = portPattern.exec(host); + if (port) { + port = port[0]; + if (port !== ':') { + this.port = port.slice(1); + } + host = host.slice(0, host.length - port.length); + } + if (host) this.hostname = host; +}; + +// About 1.5x faster than the two-arg version of Array#splice(). +function spliceOne(list, index) { + for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1) + list[i] = list[k]; + list.pop(); +} + +var hexTable = new Array(256); +for (var i = 0; i < 256; ++i) + hexTable[i] = '%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase(); +function encodeAuth(str) { + // faster encodeURIComponent alternative for encoding auth uri components + var out = ''; + var lastPos = 0; + for (var i = 0; i < str.length; ++i) { + var c = str.charCodeAt(i); + + // These characters do not need escaping: + // ! - . _ ~ + // ' ( ) * : + // digits + // alpha (uppercase) + // alpha (lowercase) + if (c === 0x21 || c === 0x2D || c === 0x2E || c === 0x5F || c === 0x7E || + (c >= 0x27 && c <= 0x2A) || + (c >= 0x30 && c <= 0x3A) || + (c >= 0x41 && c <= 0x5A) || + (c >= 0x61 && c <= 0x7A)) { + continue; + } + + if (i - lastPos > 0) + out += str.slice(lastPos, i); + + lastPos = i + 1; + + // Other ASCII characters + if (c < 0x80) { + out += hexTable[c]; + continue; + } + + // Multi-byte characters ... + if (c < 0x800) { + out += hexTable[0xC0 | (c >> 6)] + hexTable[0x80 | (c & 0x3F)]; + continue; + } + if (c < 0xD800 || c >= 0xE000) { + out += hexTable[0xE0 | (c >> 12)] + + hexTable[0x80 | ((c >> 6) & 0x3F)] + + hexTable[0x80 | (c & 0x3F)]; + continue; + } + // Surrogate pair + ++i; + var c2; + if (i < str.length) + c2 = str.charCodeAt(i) & 0x3FF; + else + c2 = 0; + c = 0x10000 + (((c & 0x3FF) << 10) | c2); + out += hexTable[0xF0 | (c >> 18)] + + hexTable[0x80 | ((c >> 12) & 0x3F)] + + hexTable[0x80 | ((c >> 6) & 0x3F)] + + hexTable[0x80 | (c & 0x3F)]; + } + if (lastPos === 0) + return str; + if (lastPos < str.length) + return out + str.slice(lastPos); + return out; +} diff --git a/examples/pxScene2d/src/v8_modules/vm.js b/examples/pxScene2d/src/v8_modules/vm.js new file mode 100644 index 0000000000..69a6cc9b2d --- /dev/null +++ b/examples/pxScene2d/src/v8_modules/vm.js @@ -0,0 +1,32 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +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. + +*/ + +"use strict"; + +function runInNewContext(code, sandbox, options, px, xModule, filename, dirname) { + return uv_run_in_context(code, sandbox, options, px, xModule, filename, dirname); +} + +function runInContext(code, sandbox, options, px, xModule, filename, dirname) { + return uv_run_in_context(code, sandbox, options, px, xModule, filename, dirname); +} + +module.exports = { + runInNewContext: runInNewContext, + runInContext: runInContext, +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cfdf2a83fd..3393179bc1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,265 +1,273 @@ -cmake_minimum_required(VERSION 2.8) -project(pxcore) -find_package(PkgConfig) - -set(CMAKE_CXX_STANDARD 11) - -option(WINDOWLESS_EGL "WINDOWLESS_EGL" OFF) -option(PXCORE_WAYLAND_EGL "PXCORE_WAYLAND_EGL" OFF) -option(PXCORE_ESSOS "PXCORE_ESSOS" OFF) -option(PXCORE_MATRIX_HELPERS "PXCORE_MATRIX_HELPERS" ON) -option(PXCORE_ACCESS_CONTROL_CHECK "PXCORE_ACCESS_CONTROL_CHECK" ON) -option(PXCORE_PERMISSIONS_CHECK "PXCORE_PERMISSIONS_CHECK" ON) -option(BUILD_RTCORE_LIBS "BUILD_RTCORE_LIBS" ON) -option(BUILD_PXCORE_LIBS "BUILD_PXCORE_LIBS" ON) -option(OUTPUT_LIBS_LOCAL "OUTPUT_LIBS_LOCAL" OFF) -option(PXCORE_WAYLAND_DISPLAY_READ_EVENTS "PXCORE_WAYLAND_DISPLAY_READ_EVENTS" ON) -if(WIN32) - option(PXCORE_COMPILE_WARNINGS_AS_ERRORS "PXCORE_COMPILE_WARNINGS_AS_ERRORS" OFF) -elseif (APPLE) - option(PXCORE_COMPILE_WARNINGS_AS_ERRORS "PXCORE_COMPILE_WARNINGS_AS_ERRORS" ON) -else() - option(PXCORE_COMPILE_WARNINGS_AS_ERRORS "PXCORE_COMPILE_WARNINGS_AS_ERRORS" ON) -endif(WIN32) - -set(EXTDIR "${CMAKE_CURRENT_SOURCE_DIR}/../examples/pxScene2d/external") -set(NODEDIR "${EXTDIR}/node/") -include(../cmake/CommOpts.cmake) -include(../cmake/CommDeps.cmake) -include(../cmake/NodeDeps.cmake) - -set(BUILD_RTCORE_SHARED_LIBRARY 1) - -if (APPLE) - message("Building pxcore for mac") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -g") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -fPIC -g") - set(CMAKE_MACOSX_RPATH 1) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/mac) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/mac) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/mac) - add_definitions(-DPX_PLATFORM_MAC -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN) - add_definitions(-D_DARWIN_USE_64_BIT_INODE=1 -DNODE_ARCH="x64" -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS= -DNODE_SHARED_MODE - -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 - -DV8_INSPECTOR_USE_OLD_STL=1 -DHAVE_OPENSSL=1 -DHAVE_DTRACE=1 -D__POSIX__ -DNODE_PLATFORM=darwin - -DUCONFIG_NO_TRANSLITERATION=1 -DUCONFIG_NO_SERVICE=1 -DUCONFIG_NO_REGULAR_EXPRESSIONS=1 -DU_ENABLE_DYLOAD=0 - -DU_STATIC_IMPLEMENTATION=1 -DU_HAVE_STD_STRING=0 -DUCONFIG_NO_BREAK_ITERATION=0 -DUCONFIG_NO_LEGACY_CONVERSION=1 - -DUCONFIG_NO_CONVERSION=1 -DHTTP_PARSER_STRICT=0 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 - -DRT_PLATFORM_LINUX -DENABLE_NODE_V_6_9) - set(PXCORE_FILES mac/pxBufferNative.mm mac/pxOffscreenNative.mm mac/pxWindowNative.mm - mac/pxEventLoopNative.mm mac/pxTimerNative.mm mac/pxTimerNative.mm - mac/pxClipboardNative.mm mac/window.mm - unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp - rtFileCache.cpp rtHttpCache.cpp) - set(PLATFORM_LINKER_FLAGS "-framework Cocoa -framework Foundation") - add_definitions(${COMM_DEPS_DEFINITIONS}) - include_directories(AFTER ${COMM_DEPS_INCLUDE_DIRS}) - if (DEFINED ENV{CODE_COVERAGE}) - message("enabling code coverage support") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") - add_definitions(-DENABLE_CODE_COVERAGE=1) - endif () -elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -g") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -fPIC -g") - execute_process(COMMAND "hostname" OUTPUT_VARIABLE HOSTNAME) - string(STRIP ${HOSTNAME} HOSTNAME) - - add_definitions(${COMM_DEPS_DEFINITIONS}) - - include_directories(AFTER - ${NODE_INCLUDE_DIRS} - ${COMM_DEPS_INCLUDE_DIRS} - ) - - if (HOSTNAME STREQUAL "raspberrypi") - message("Building pxcore for raspberry pi") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) - add_definitions(-DENABLE_NODE_V_6_9 -DNODE_PLATFORM=linux -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1) - add_definitions(-DPX_PLATFORM_GENERIC_EGL -DRT_PLATFORM_LINUX -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN) - set(PXCORE_FILES gles/pxBufferNative.cpp gles/pxOffscreenNative.cpp gles/pxWindowNative.cpp - gles/pxEventLoopNative.cpp gles/pxTimerNative.cpp - gles/pxClipboardNative.cpp gles/pxEGLProviderRPi.cpp gles/LinuxInputEventDispatcher.cpp pxViewWindow.cpp - unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp - rtFileCache.cpp rtHttpCache.cpp) - set(PLATFORM_LINKER_FLAGS) - include_directories(AFTER /opt/vc/include /opt/vc/include/interface/vcos/pthreads - /opt/vc/include/interface/vmcs_host/linux /opt/vc/include) - include_directories(AFTER ${ZLIBINC} ${CURLINC} ${JPGINC} ${JPGTURBOINC} ${PNGINC}) - elseif (WINDOWLESS_EGL OR PXCORE_WAYLAND_EGL OR PXCORE_ESSOS) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) - add_definitions(-DENABLE_NODE_V_6_9 -DNODE_PLATFORM=linux -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1) - add_definitions(-DRT_PLATFORM_LINUX -DPX_NO_WINDOW -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN -DRAPIDJSON_HAS_STDSTRING) - set(PXCORE_FILES unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp - rtFileCache.cpp rtHttpCache.cpp) - - if (PXCORE_ESSOS) - message("Building pxcore for essos windows") - add_definitions(-DPX_PLATFORM_ESSOS -DPX_PLATFORM_WAYLAND_EGL) - set(PXCORE_FILES ${PXCORE_FILES} essos/pxWindowNative.cpp essos/pxBufferNative.cpp essos/pxOffscreenNative.cpp - essos/pxEventLoopNative.cpp essos/pxTimerNative.cpp essos/pxClipboardNative.cpp) - elseif (PXCORE_WAYLAND_EGL) - message("Building pxcore for wayland windows") - add_definitions(-DPX_PLATFORM_WAYLAND_EGL) - if (PXCORE_WAYLAND_DISPLAY_READ_EVENTS) - message("Enabling wayland display read events") - add_definitions(-DPXCORE_WL_DISPLAY_READ_EVENTS) - endif(PXCORE_WAYLAND_DISPLAY_READ_EVENTS) - set(PXCORE_FILES ${PXCORE_FILES} wayland_egl/pxWindowNative.cpp wayland_egl/pxBufferNative.cpp wayland_egl/pxOffscreenNative.cpp - wayland_egl/pxEventLoopNative.cpp wayland_egl/pxTimerNative.cpp wayland_egl/pxClipboardNative.cpp) - elseif (WINDOWLESS_EGL) - message("Building pxcore for windowless egl") - add_definitions(-DPX_PLATFORM_GENERIC_EGL) - set(PXCORE_FILES ${PXCORE_FILES} gles/pxBufferNative.cpp gles/pxOffscreenNative.cpp - gles/pxEventLoopNative.cpp gles/pxTimerNative.cpp gles/pxClipboardNative.cpp) - endif (PXCORE_ESSOS) - set(PLATFORM_LINKER_FLAGS) - elseif (PXCORE_DFB) - message("Building pxcore for dfb ") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/dfb) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/dfb) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/dfb) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") - set(PXCORE_INCLUDES $ENV{PXCORE_INCLUDES}) - separate_arguments(PXCORE_INCLUDES) - include_directories(BEFORE ${PXCORE_INCLUDES}) - add_definitions(-DRT_PLATFORM_LINUX -DPX_NO_WINDOW -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN -DRAPIDJSON_HAS_STDSTRING -DENABLE_DFB -DENABLE_DFB_GENERIC -DBSTD_CPU_ENDIAN=BSTD_ENDIAN_LITTLE -DPX_PLATFORM_GENERIC_DFB) - set(PXCORE_FILES x11/pxBufferNativeDfb.cpp x11/pxOffscreenNativeDfb.cpp x11/pxEventLoopNative.cpp x11/pxTimerNative.cpp x11/pxClipboardNative.cpp unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp rtFileCache.cpp rtHttpCache.cpp) - else () - message("Building pxcore for glut") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/glut) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/glut) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/glut) - add_definitions(-DENABLE_NODE_V_6_9 -DNODE_PLATFORM=linux -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1) - add_definitions(-DPX_PLATFORM_GLUT -DRT_PLATFORM_LINUX -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN) - set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} glut) - set(PXCORE_FILES glut/pxBufferNative.cpp glut/pxOffscreenNative.cpp glut/pxWindowNative.cpp - glut/pxEventLoopNative.cpp glut/pxTimerNative.cpp glut/pxClipboardNative.cpp pxViewWindow.cpp - unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp - rtFileCache.cpp rtHttpCache.cpp) - set(PLATFORM_LINKER_FLAGS) - if (DEFINED ENV{CODE_COVERAGE}) - message("enabling code coverage support") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") - add_definitions(-DENABLE_CODE_COVERAGE=1) - endif () - endif (HOSTNAME STREQUAL "raspberrypi") -elseif(WIN32) - message("Building pxcore for Windows") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT /Zi /DEBUG") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/win) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/win) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/win) - add_definitions(-DENABLE_NODE_V_6_9 -DNODE_PLATFORM=win32 -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1) - add_definitions(-DENABLE_RT_NODE -DRUNINMAIN) - add_definitions(-DPX_PLATFORM_WIN -DRT_PLATFORM_WINDOWS -DWIN32 -DWIN32_LEAN_AND_MEAN -DGLEW_STATIC -D_TIMESPEC_DEFINED -D_CONSOLE - -DCURL_STATICLIB -DRUNINMAIN -DENABLE_RT_NODE -DDISABLE_WAYLAND -DNODE_WANT_INTERNALS=1 - -DENABLE_NODE_V_6_9 -DENABLE_V8_HEAP_PARAMS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DHAVE_INSPECTOR=1 - -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1 -DENABLE_MAX_TEXTURE_SIZE - -DHAVE_OPENSSL -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -D_HAS_EXCEPTIONS=0 -DBUILDING_V8_SHARED=1 - -DBUILDING_UV_SHARED=1 -DNODE_ARCH="ia32" -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 - -DHAVE_OPENSSL=1 -DHAVE_ETW=1 -DHAVE_PERFCTR=1 -DFD_SETSIZE=1024 -DNODE_PLATFORM="win32" -D_UNICODE=1 -DUCONFIG_NO_TRANSLITERATION=1 - -DUCONFIG_NO_SERVICE=1 -DUCONFIG_NO_REGULAR_EXPRESSIONS=1 -DU_ENABLE_DYLOAD=0 -DU_STATIC_IMPLEMENTATION=1 - -DU_HAVE_STD_STRING=0 -DUCONFIG_NO_BREAK_ITERATION=0 -DUCONFIG_NO_LEGACY_CONVERSION=1 -DUCONFIG_NO_CONVERSION=1 - -DHTTP_PARSER_STRICT=0 -DUSE_RENDER_STATS -D_HAS_EXCEPTIONS=0) - add_definitions(-DWIN32 -D_LIB -DNDEBUG -DPX_PLATFORM_WIN -DRT_PLATFORM_WINDOWS) - add_definitions(${COMM_DEPS_DEFINITIONS}) - include_directories(AFTER ${COMM_DEPS_INCLUDE_DIRS}) - include_directories(AFTER "${EXTDIR}/pthread-2.9") - set(PXCORE_FILES win/pxBufferNative.cpp win/pxOffscreenNative.cpp win/pxWindowNative.cpp - win/pxEventLoopNative.cpp win/pxTimerNative.cpp win/pxClipboardNative.cpp pxViewWindow.cpp - win/rtMutexNative.cpp win/rtThreadPoolNative.cpp) - set_source_files_properties(utf8.c PROPERTIES LANGUAGE CXX) - set(BUILD_RTCORE_SHARED_LIBRARY 0) -else () - message(FATAL_ERROR "Cannot build pxcore. Unknown platform") -endif (APPLE) - -if (NOT PXCORE_DFB) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -std=c++11") -endif (NOT PXCORE_DFB) - -if (PXCORE_COMPILE_WARNINGS_AS_ERRORS) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") -endif (PXCORE_COMPILE_WARNINGS_AS_ERRORS) - -include_directories(AFTER ${NODE_INCLUDE_DIRS}) -include_directories(AFTER ${CMAKE_CURRENT_SOURCE_DIR}) - -set(PXCORE_FILES ${PXCORE_FILES} pxOffscreen.cpp pxWindowUtil.cpp - - rtFile.cpp rtLibrary.cpp rtPathUtils.cpp rtTest.cpp rtThreadPool.cpp - rtThreadQueue.cpp rtThreadTask.cpp rtUrlUtils.cpp - rtZip.cpp pxInterpolators.cpp pxUtil.cpp - rtFileDownloader.cpp unzip.c ioapi.c - rtScript.cpp rtSettings.cpp) - -if (SUPPORT_DUKTAPE) - message("Adding Duktape scripting support") - add_definitions(-DRTSCRIPT_SUPPORT_DUKTAPE) - set(PXCORE_FILES ${PXCORE_FILES} rtScriptDuk/rtScriptDuk.cpp rtScriptDuk/rtFunctionWrapperDuk.cpp rtScriptDuk/rtObjectWrapperDuk.cpp - rtScriptDuk/rtWrapperUtilsDuk.cpp rtScriptDuk/rtJsModules.cpp) -endif() - -if (SUPPORT_NODE) - message("Adding Node scripting support") - add_definitions(-DRTSCRIPT_SUPPORT_NODE) - set(PXCORE_FILES ${PXCORE_FILES} rtScriptNode/rtScriptNode.cpp rtScriptNode/jsCallback.cpp rtScriptNode/rtFunctionWrapper.cpp - rtScriptNode/rtObjectWrapper.cpp rtScriptNode/rtWrapperUtils.cpp) -endif() - - -if (PXCORE_MATRIX_HELPERS) - set(PXCORE_FILES ${PXCORE_FILES} pxMatrix4T.cpp) -endif(PXCORE_MATRIX_HELPERS) - -if (PXCORE_ACCESS_CONTROL_CHECK) - add_definitions(-DENABLE_ACCESS_CONTROL_CHECK) - set(PXCORE_FILES ${PXCORE_FILES} rtCORSUtils.cpp) -endif (PXCORE_ACCESS_CONTROL_CHECK) - -if (PXCORE_PERMISSIONS_CHECK) - add_definitions(-DENABLE_PERMISSIONS_CHECK) - set(PXCORE_FILES ${PXCORE_FILES} rtPermissions.cpp) -endif (PXCORE_PERMISSIONS_CHECK) - -set(RTCORE_FILES utf8.c rtString.cpp rtLog.cpp rtValue.cpp rtError.cpp ioapi_mem.c) - -set(RTCORE_FILES ${RTCORE_FILES} rtPromise.cpp) - -set(RTCORE_FILES ${RTCORE_FILES} rtObject.cpp) - -include_directories(AFTER ${EXTDIR}/nanosvg/src) - -if (OUTPUT_LIBS_LOCAL) - message("Output pxCore and rtCore libs locally") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) -endif (OUTPUT_LIBS_LOCAL) - -#if (USE_DUKTAPE) - include_directories(AFTER ${EXTDIR}/dukluv/lib/duktape/src) - include_directories(AFTER ${EXTDIR}/dukluv/lib/uv/include) - include_directories(AFTER ${EXTDIR}/dukluv/src) -#endif(USE_DUKTAPE) - -if (BUILD_PXCORE_LIBS) - message("Building pxcore libs") - add_library(pxCore ${PXCORE_FILES}) -endif (BUILD_PXCORE_LIBS) -if (BUILD_RTCORE_LIBS) - message("Building rtcore libs") - add_library(rtCore_s ${RTCORE_FILES}) - if (BUILD_RTCORE_SHARED_LIBRARY GREATER 0) - add_library(rtCore SHARED ${RTCORE_FILES}) - endif(BUILD_RTCORE_SHARED_LIBRARY GREATER 0) -endif (BUILD_RTCORE_LIBS) +cmake_minimum_required(VERSION 2.8) +project(pxcore) +find_package(PkgConfig) + +set(CMAKE_CXX_STANDARD 11) + +option(WINDOWLESS_EGL "WINDOWLESS_EGL" OFF) +option(PXCORE_WAYLAND_EGL "PXCORE_WAYLAND_EGL" OFF) +option(PXCORE_ESSOS "PXCORE_ESSOS" OFF) +option(PXCORE_MATRIX_HELPERS "PXCORE_MATRIX_HELPERS" ON) +option(PXCORE_ACCESS_CONTROL_CHECK "PXCORE_ACCESS_CONTROL_CHECK" ON) +option(PXCORE_PERMISSIONS_CHECK "PXCORE_PERMISSIONS_CHECK" ON) +option(BUILD_RTCORE_LIBS "BUILD_RTCORE_LIBS" ON) +option(BUILD_PXCORE_LIBS "BUILD_PXCORE_LIBS" ON) +option(OUTPUT_LIBS_LOCAL "OUTPUT_LIBS_LOCAL" OFF) +option(PXCORE_WAYLAND_DISPLAY_READ_EVENTS "PXCORE_WAYLAND_DISPLAY_READ_EVENTS" ON) +if(WIN32) + option(PXCORE_COMPILE_WARNINGS_AS_ERRORS "PXCORE_COMPILE_WARNINGS_AS_ERRORS" OFF) +elseif (APPLE) + option(PXCORE_COMPILE_WARNINGS_AS_ERRORS "PXCORE_COMPILE_WARNINGS_AS_ERRORS" ON) +else() + option(PXCORE_COMPILE_WARNINGS_AS_ERRORS "PXCORE_COMPILE_WARNINGS_AS_ERRORS" ON) +endif(WIN32) + +set(EXTDIR "${CMAKE_CURRENT_SOURCE_DIR}/../examples/pxScene2d/external") +set(NODEDIR "${EXTDIR}/node/") +include(../cmake/CommOpts.cmake) +include(../cmake/CommDeps.cmake) +include(../cmake/NodeDeps.cmake) +include(../cmake/V8Deps.cmake) + +set(BUILD_RTCORE_SHARED_LIBRARY 1) + +if (APPLE) + message("Building pxcore for mac") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -g") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -fPIC -g") + set(CMAKE_MACOSX_RPATH 1) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/mac) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/mac) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/mac) + add_definitions(-DPX_PLATFORM_MAC -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN) + add_definitions(-D_DARWIN_USE_64_BIT_INODE=1 -DNODE_ARCH="x64" -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS= -DNODE_SHARED_MODE + -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 + -DV8_INSPECTOR_USE_OLD_STL=1 -DHAVE_OPENSSL=1 -DHAVE_DTRACE=1 -D__POSIX__ -DNODE_PLATFORM=darwin + -DUCONFIG_NO_TRANSLITERATION=1 -DUCONFIG_NO_SERVICE=1 -DUCONFIG_NO_REGULAR_EXPRESSIONS=1 -DU_ENABLE_DYLOAD=0 + -DU_STATIC_IMPLEMENTATION=1 -DU_HAVE_STD_STRING=0 -DUCONFIG_NO_BREAK_ITERATION=0 -DUCONFIG_NO_LEGACY_CONVERSION=1 + -DUCONFIG_NO_CONVERSION=1 -DHTTP_PARSER_STRICT=0 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 + -DRT_PLATFORM_LINUX -DENABLE_NODE_V_6_9) + set(PXCORE_FILES mac/pxBufferNative.mm mac/pxOffscreenNative.mm mac/pxWindowNative.mm + mac/pxEventLoopNative.mm mac/pxTimerNative.mm mac/pxTimerNative.mm + mac/pxClipboardNative.mm mac/window.mm + unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp + rtFileCache.cpp rtHttpCache.cpp) + set(PLATFORM_LINKER_FLAGS "-framework Cocoa -framework Foundation") + add_definitions(${COMM_DEPS_DEFINITIONS}) + include_directories(AFTER ${COMM_DEPS_INCLUDE_DIRS}) + if (DEFINED ENV{CODE_COVERAGE}) + message("enabling code coverage support") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") + add_definitions(-DENABLE_CODE_COVERAGE=1) + endif () +elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -g") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations -Wno-deprecated -fPIC -g") + execute_process(COMMAND "hostname" OUTPUT_VARIABLE HOSTNAME) + string(STRIP ${HOSTNAME} HOSTNAME) + + add_definitions(${COMM_DEPS_DEFINITIONS}) + + include_directories(AFTER + ${NODE_INCLUDE_DIRS} ${V8_INCLUDE_DIRS} + ${COMM_DEPS_INCLUDE_DIRS} + ) + + if (HOSTNAME STREQUAL "raspberrypi") + message("Building pxcore for raspberry pi") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) + add_definitions(-DENABLE_NODE_V_6_9 -DNODE_PLATFORM=linux -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1) + add_definitions(-DPX_PLATFORM_GENERIC_EGL -DRT_PLATFORM_LINUX -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN) + set(PXCORE_FILES gles/pxBufferNative.cpp gles/pxOffscreenNative.cpp gles/pxWindowNative.cpp + gles/pxEventLoopNative.cpp gles/pxTimerNative.cpp + gles/pxClipboardNative.cpp gles/pxEGLProviderRPi.cpp gles/LinuxInputEventDispatcher.cpp pxViewWindow.cpp + unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp + rtFileCache.cpp rtHttpCache.cpp) + set(PLATFORM_LINKER_FLAGS) + include_directories(AFTER /opt/vc/include /opt/vc/include/interface/vcos/pthreads + /opt/vc/include/interface/vmcs_host/linux /opt/vc/include) + include_directories(AFTER ${ZLIBINC} ${CURLINC} ${JPGINC} ${JPGTURBOINC} ${PNGINC}) + elseif (WINDOWLESS_EGL OR PXCORE_WAYLAND_EGL OR PXCORE_ESSOS) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) + add_definitions(-DENABLE_NODE_V_6_9 -DNODE_PLATFORM=linux -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1) + add_definitions(-DRT_PLATFORM_LINUX -DPX_NO_WINDOW -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN -DRAPIDJSON_HAS_STDSTRING) + set(PXCORE_FILES unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp + rtFileCache.cpp rtHttpCache.cpp) + + if (PXCORE_ESSOS) + message("Building pxcore for essos windows") + add_definitions(-DPX_PLATFORM_ESSOS -DPX_PLATFORM_WAYLAND_EGL) + set(PXCORE_FILES ${PXCORE_FILES} essos/pxWindowNative.cpp essos/pxBufferNative.cpp essos/pxOffscreenNative.cpp + essos/pxEventLoopNative.cpp essos/pxTimerNative.cpp essos/pxClipboardNative.cpp) + elseif (PXCORE_WAYLAND_EGL) + message("Building pxcore for wayland windows") + add_definitions(-DPX_PLATFORM_WAYLAND_EGL) + if (PXCORE_WAYLAND_DISPLAY_READ_EVENTS) + message("Enabling wayland display read events") + add_definitions(-DPXCORE_WL_DISPLAY_READ_EVENTS) + endif(PXCORE_WAYLAND_DISPLAY_READ_EVENTS) + set(PXCORE_FILES ${PXCORE_FILES} wayland_egl/pxWindowNative.cpp wayland_egl/pxBufferNative.cpp wayland_egl/pxOffscreenNative.cpp + wayland_egl/pxEventLoopNative.cpp wayland_egl/pxTimerNative.cpp wayland_egl/pxClipboardNative.cpp) + elseif (WINDOWLESS_EGL) + message("Building pxcore for windowless egl") + add_definitions(-DPX_PLATFORM_GENERIC_EGL) + set(PXCORE_FILES ${PXCORE_FILES} gles/pxBufferNative.cpp gles/pxOffscreenNative.cpp + gles/pxEventLoopNative.cpp gles/pxTimerNative.cpp gles/pxClipboardNative.cpp) + endif (PXCORE_ESSOS) + set(PLATFORM_LINKER_FLAGS) + elseif (PXCORE_DFB) + message("Building pxcore for dfb ") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/dfb) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/dfb) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/dfb) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") + set(PXCORE_INCLUDES $ENV{PXCORE_INCLUDES}) + separate_arguments(PXCORE_INCLUDES) + include_directories(BEFORE ${PXCORE_INCLUDES}) + add_definitions(-DRT_PLATFORM_LINUX -DPX_NO_WINDOW -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN -DRAPIDJSON_HAS_STDSTRING -DENABLE_DFB -DENABLE_DFB_GENERIC -DBSTD_CPU_ENDIAN=BSTD_ENDIAN_LITTLE -DPX_PLATFORM_GENERIC_DFB) + set(PXCORE_FILES x11/pxBufferNativeDfb.cpp x11/pxOffscreenNativeDfb.cpp x11/pxEventLoopNative.cpp x11/pxTimerNative.cpp x11/pxClipboardNative.cpp unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp rtFileCache.cpp rtHttpCache.cpp) + else () + message("Building pxcore for glut") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/glut) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/glut) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/glut) + add_definitions(-DENABLE_NODE_V_6_9 -DNODE_PLATFORM=linux -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1) + add_definitions(-DPX_PLATFORM_GLUT -DRT_PLATFORM_LINUX -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN) + set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} glut) + set(PXCORE_FILES glut/pxBufferNative.cpp glut/pxOffscreenNative.cpp glut/pxWindowNative.cpp + glut/pxEventLoopNative.cpp glut/pxTimerNative.cpp glut/pxClipboardNative.cpp pxViewWindow.cpp + unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp + rtFileCache.cpp rtHttpCache.cpp) + set(PLATFORM_LINKER_FLAGS) + if (DEFINED ENV{CODE_COVERAGE}) + message("enabling code coverage support") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") + add_definitions(-DENABLE_CODE_COVERAGE=1) + endif () + endif (HOSTNAME STREQUAL "raspberrypi") +elseif(WIN32) + message("Building pxcore for Windows") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT /Zi /DEBUG") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/win) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/win) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/win) + add_definitions(-DENABLE_NODE_V_6_9 -DNODE_PLATFORM=win32 -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1) + add_definitions(-DENABLE_RT_NODE -DRUNINMAIN) + add_definitions(-DPX_PLATFORM_WIN -DRT_PLATFORM_WINDOWS -DWIN32 -DWIN32_LEAN_AND_MEAN -DGLEW_STATIC -D_TIMESPEC_DEFINED -D_CONSOLE + -DCURL_STATICLIB -DRUNINMAIN -DENABLE_RT_NODE -DDISABLE_WAYLAND -DNODE_WANT_INTERNALS=1 + -DENABLE_NODE_V_6_9 -DENABLE_V8_HEAP_PARAMS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DHAVE_INSPECTOR=1 + -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1 -DENABLE_MAX_TEXTURE_SIZE + -DHAVE_OPENSSL -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -D_HAS_EXCEPTIONS=0 -DBUILDING_V8_SHARED=1 + -DBUILDING_UV_SHARED=1 -DNODE_ARCH="ia32" -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 + -DHAVE_OPENSSL=1 -DHAVE_ETW=1 -DHAVE_PERFCTR=1 -DFD_SETSIZE=1024 -DNODE_PLATFORM="win32" -D_UNICODE=1 -DUCONFIG_NO_TRANSLITERATION=1 + -DUCONFIG_NO_SERVICE=1 -DUCONFIG_NO_REGULAR_EXPRESSIONS=1 -DU_ENABLE_DYLOAD=0 -DU_STATIC_IMPLEMENTATION=1 + -DU_HAVE_STD_STRING=0 -DUCONFIG_NO_BREAK_ITERATION=0 -DUCONFIG_NO_LEGACY_CONVERSION=1 -DUCONFIG_NO_CONVERSION=1 + -DHTTP_PARSER_STRICT=0 -DUSE_RENDER_STATS -D_HAS_EXCEPTIONS=0) + add_definitions(-DWIN32 -D_LIB -DNDEBUG -DPX_PLATFORM_WIN -DRT_PLATFORM_WINDOWS) + add_definitions(${COMM_DEPS_DEFINITIONS}) + include_directories(AFTER ${COMM_DEPS_INCLUDE_DIRS}) + include_directories(AFTER "${EXTDIR}/pthread-2.9") + set(PXCORE_FILES win/pxBufferNative.cpp win/pxOffscreenNative.cpp win/pxWindowNative.cpp + win/pxEventLoopNative.cpp win/pxTimerNative.cpp win/pxClipboardNative.cpp pxViewWindow.cpp + win/rtMutexNative.cpp win/rtThreadPoolNative.cpp) + set_source_files_properties(utf8.c PROPERTIES LANGUAGE CXX) + set(BUILD_RTCORE_SHARED_LIBRARY 0) +else () + message(FATAL_ERROR "Cannot build pxcore. Unknown platform") +endif (APPLE) + +if (NOT PXCORE_DFB) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -std=c++11") +endif (NOT PXCORE_DFB) + +if (PXCORE_COMPILE_WARNINGS_AS_ERRORS) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") +endif (PXCORE_COMPILE_WARNINGS_AS_ERRORS) + +include_directories(AFTER ${V8_INCLUDE_DIRS}) +include_directories(AFTER ${NODE_INCLUDE_DIRS}) +include_directories(AFTER ${CMAKE_CURRENT_SOURCE_DIR}) + +set(PXCORE_FILES ${PXCORE_FILES} pxOffscreen.cpp pxWindowUtil.cpp + + rtFile.cpp rtLibrary.cpp rtPathUtils.cpp rtTest.cpp rtThreadPool.cpp + rtThreadQueue.cpp rtThreadTask.cpp rtUrlUtils.cpp + rtZip.cpp pxInterpolators.cpp pxUtil.cpp + rtFileDownloader.cpp unzip.c ioapi.c + rtScript.cpp rtSettings.cpp) + +if (SUPPORT_DUKTAPE) + message("Adding Duktape scripting support") + add_definitions(-DRTSCRIPT_SUPPORT_DUKTAPE) + set(PXCORE_FILES ${PXCORE_FILES} rtScriptDuk/rtScriptDuk.cpp rtScriptDuk/rtFunctionWrapperDuk.cpp rtScriptDuk/rtObjectWrapperDuk.cpp + rtScriptDuk/rtWrapperUtilsDuk.cpp rtScriptDuk/rtJsModules.cpp) +endif() + +if (SUPPORT_NODE) + message("Adding Node scripting support") + add_definitions(-DRTSCRIPT_SUPPORT_NODE) + set(PXCORE_FILES ${PXCORE_FILES} rtScriptV8/rtScriptNode.cpp rtScriptV8/jsCallback.cpp rtScriptV8/rtFunctionWrapper.cpp + rtScriptV8/rtObjectWrapper.cpp rtScriptV8/rtWrapperUtils.cpp) +endif() + +if (SUPPORT_V8) + message("Adding V8 scripting support") + add_definitions(-DRTSCRIPT_SUPPORT_V8) + set(PXCORE_FILES ${PXCORE_FILES} rtScriptV8/rtScriptV8.cpp rtScriptV8/jsCallback.cpp rtScriptV8/rtFunctionWrapper.cpp + rtScriptV8/rtObjectWrapper.cpp rtScriptV8/rtWrapperUtils.cpp ${V8_SOURCES}) +endif() + +if (PXCORE_MATRIX_HELPERS) + set(PXCORE_FILES ${PXCORE_FILES} pxMatrix4T.cpp) +endif(PXCORE_MATRIX_HELPERS) + +if (PXCORE_ACCESS_CONTROL_CHECK) + add_definitions(-DENABLE_ACCESS_CONTROL_CHECK) + set(PXCORE_FILES ${PXCORE_FILES} rtCORSUtils.cpp) +endif (PXCORE_ACCESS_CONTROL_CHECK) + +if (PXCORE_PERMISSIONS_CHECK) + add_definitions(-DENABLE_PERMISSIONS_CHECK) + set(PXCORE_FILES ${PXCORE_FILES} rtPermissions.cpp) +endif (PXCORE_PERMISSIONS_CHECK) + +set(RTCORE_FILES utf8.c rtString.cpp rtLog.cpp rtValue.cpp rtError.cpp ioapi_mem.c) + +set(RTCORE_FILES ${RTCORE_FILES} rtPromise.cpp) + +set(RTCORE_FILES ${RTCORE_FILES} rtObject.cpp) + +include_directories(AFTER ${EXTDIR}/nanosvg/src) + +if (OUTPUT_LIBS_LOCAL) + message("Output pxCore and rtCore libs locally") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) +endif (OUTPUT_LIBS_LOCAL) + +#if (USE_DUKTAPE) + include_directories(AFTER ${EXTDIR}/dukluv/lib/duktape/src) + include_directories(AFTER ${EXTDIR}/dukluv/lib/uv/include) + include_directories(AFTER ${EXTDIR}/dukluv/src) +#endif(USE_DUKTAPE) + +if (BUILD_PXCORE_LIBS) + message("Building pxcore libs") + add_library(pxCore ${PXCORE_FILES}) +endif (BUILD_PXCORE_LIBS) +if (BUILD_RTCORE_LIBS) + message("Building rtcore libs") + add_library(rtCore_s ${RTCORE_FILES}) + if (BUILD_RTCORE_SHARED_LIBRARY GREATER 0) + add_library(rtCore SHARED ${RTCORE_FILES}) + endif(BUILD_RTCORE_SHARED_LIBRARY GREATER 0) +endif (BUILD_RTCORE_LIBS) diff --git a/src/rtScript.cpp b/src/rtScript.cpp index 539418110a..cd0e660149 100644 --- a/src/rtScript.cpp +++ b/src/rtScript.cpp @@ -26,8 +26,8 @@ #include "assert.h" -#ifdef RTSCRIPT_SUPPORT_NODE -#include "rtScriptNode/rtScriptNode.h" +#if defined RTSCRIPT_SUPPORT_NODE || defined RTSCRIPT_SUPPORT_V8 +#include "rtScriptV8/rtScriptV8Node.h" #endif #ifdef RTSCRIPT_SUPPORT_DUKTAPE @@ -192,6 +192,8 @@ rtError rtScript::init() createScriptDuk(mScript); else createScriptNode(mScript); + #elif defined(RTSCRIPT_SUPPORT_V8) + createScriptV8(mScript); #elif defined(RTSCRIPT_SUPPORT_DUKTAPE) createScriptDuk(mScript); #elif defined(RTSCRIPT_SUPPORT_NODE) diff --git a/src/rtScriptNode/node_headers.h b/src/rtScriptV8/headers.h similarity index 95% rename from src/rtScriptNode/node_headers.h rename to src/rtScriptV8/headers.h index f48fe6b6f8..da177062ac 100644 --- a/src/rtScriptNode/node_headers.h +++ b/src/rtScriptV8/headers.h @@ -21,8 +21,11 @@ limitations under the License. #include +#ifdef RTSCRIPT_SUPPORT_NODE #include #include +#endif + #include #include #include diff --git a/src/rtScriptNode/jsCallback.cpp b/src/rtScriptV8/jsCallback.cpp similarity index 97% rename from src/rtScriptNode/jsCallback.cpp rename to src/rtScriptV8/jsCallback.cpp index d19d0f2d5a..c61bf1e3ea 100644 --- a/src/rtScriptNode/jsCallback.cpp +++ b/src/rtScriptV8/jsCallback.cpp @@ -22,7 +22,7 @@ limitations under the License. using namespace v8; -namespace rtScriptNodeUtils +namespace rtScriptV8NodeUtils { jsCallback::jsCallback(v8::Local& ctx) @@ -129,7 +129,7 @@ rtValue jsCallback::run() Local val; -#ifdef ENABLE_NODE_V_6_9 +#if defined ENABLE_NODE_V_6_9 || defined RTSCRIPT_SUPPORT_V8 TryCatch tryCatch(mIsolate); #else TryCatch tryCatch; diff --git a/src/rtScriptNode/jsCallback.h b/src/rtScriptV8/jsCallback.h similarity index 97% rename from src/rtScriptNode/jsCallback.h rename to src/rtScriptV8/jsCallback.h index 84344649c3..03df1a4fcd 100644 --- a/src/rtScriptNode/jsCallback.h +++ b/src/rtScriptV8/jsCallback.h @@ -20,11 +20,11 @@ limitations under the License. #define RT_JAVASCRIPT_CALLBACK_H -#include "node_headers.h" +#include "headers.h" #include #include -namespace rtScriptNodeUtils +namespace rtScriptV8NodeUtils { typedef void (*jsCallbackCompletionFunc)(void* argp, rtValue const& result); diff --git a/src/rtScriptNode/rtFunctionWrapper.cpp b/src/rtScriptV8/rtFunctionWrapper.cpp similarity index 98% rename from src/rtScriptNode/rtFunctionWrapper.cpp rename to src/rtScriptV8/rtFunctionWrapper.cpp index b95c7a39a8..e223261a37 100644 --- a/src/rtScriptNode/rtFunctionWrapper.cpp +++ b/src/rtScriptV8/rtFunctionWrapper.cpp @@ -26,7 +26,7 @@ extern bool gIsPumpingJavaScript; #endif using namespace v8; -namespace rtScriptNodeUtils +namespace rtScriptV8NodeUtils { static const char* kClassName = "Function"; @@ -107,7 +107,7 @@ void rtResolverFunction::afterWorkCallback(uv_work_t* req, int /* status */) Local local_context = resolver->CreationContext(); Context::Scope context_scope(local_context); -#ifdef ENABLE_NODE_V_6_9 +#if defined ENABLE_NODE_V_6_9 || defined RTSCRIPT_SUPPORT_V8 TryCatch tryCatch(resolverFunc->mIsolate); #else TryCatch tryCatch; @@ -194,7 +194,7 @@ void rtFunctionWrapper::create(const FunctionCallbackInfo& args) wrapper->Wrap(args.This()); } -#ifdef ENABLE_NODE_V_6_9 +#if defined ENABLE_NODE_V_6_9 || defined RTSCRIPT_SUPPORT_V8 Handle rtFunctionWrapper::createFromFunctionReference(v8::Local& ctx, Isolate* isolate, const rtFunctionRef& func) #else Handle rtFunctionWrapper::createFromFunctionReference(Isolate* isolate, const rtFunctionRef& func) diff --git a/src/rtScriptNode/rtFunctionWrapper.h b/src/rtScriptV8/rtFunctionWrapper.h similarity index 97% rename from src/rtScriptNode/rtFunctionWrapper.h rename to src/rtScriptV8/rtFunctionWrapper.h index 09672df66f..007e86bbba 100644 --- a/src/rtScriptNode/rtFunctionWrapper.h +++ b/src/rtScriptV8/rtFunctionWrapper.h @@ -27,7 +27,7 @@ limitations under the License. # include #endif -namespace rtScriptNodeUtils +namespace rtScriptV8NodeUtils { class rtAbstractFunction : public rtIFunction @@ -63,7 +63,7 @@ class rtFunctionWrapper : public rtWrapper public: static void exportPrototype(v8::Isolate* isolate, v8::Handle exports); static void destroyPrototype(); -#ifdef ENABLE_NODE_V_6_9 +#if defined ENABLE_NODE_V_6_9 || defined RTSCRIPT_SUPPORT_V8 static v8::Handle createFromFunctionReference(v8::Local& ctx, v8::Isolate* isolate, const rtFunctionRef& func); #else static v8::Handle createFromFunctionReference(v8::Isolate* isolate, const rtFunctionRef& func); diff --git a/src/rtScriptNode/rtObjectWrapper.cpp b/src/rtScriptV8/rtObjectWrapper.cpp similarity index 96% rename from src/rtScriptNode/rtObjectWrapper.cpp rename to src/rtScriptV8/rtObjectWrapper.cpp index 5964e9fac4..5b9c539721 100644 --- a/src/rtScriptNode/rtObjectWrapper.cpp +++ b/src/rtScriptV8/rtObjectWrapper.cpp @@ -24,7 +24,7 @@ limitations under the License. using namespace v8; -namespace rtScriptNodeUtils +namespace rtScriptV8NodeUtils { static const char* kClassName = "rtObject"; @@ -173,7 +173,7 @@ Handle rtObjectWrapper::createFromObjectReference(v8::Local }; Local func = PersistentToLocal(isolate, ctor); -#ifdef ENABLE_NODE_V_6_9 +#if defined ENABLE_NODE_V_6_9 || defined RTSCRIPT_SUPPORT_V8 obj = (func->NewInstance(ctx, 1, argv)).FromMaybe(Local()); #else obj = func->NewInstance(1, argv); @@ -198,7 +198,7 @@ void rtObjectWrapper::getProperty(const T& prop, const PropertyCallbackInfo ctx = info.This()->CreationContext(); - rtObjectWrapper* wrapper = node::ObjectWrap::Unwrap(info.This()); + rtObjectWrapper* wrapper = OBJECT_WRAP_CLASS::Unwrap(info.This()); if (!wrapper) return; @@ -252,7 +252,7 @@ void rtObjectWrapper::setProperty(const T& prop, Local val, const Propert void rtObjectWrapper::getEnumerable(const PropertyCallbackInfo& info, enumerable_item_creator_t create) { - rtObjectWrapper* wrapper = node::ObjectWrap::Unwrap(info.This()); + rtObjectWrapper* wrapper = OBJECT_WRAP_CLASS::Unwrap(info.This()); if (!wrapper) return; @@ -295,7 +295,7 @@ void rtObjectWrapper::queryProperty(const T& prop, const PropertyCallbackInfo(info.This()); + rtObjectWrapper* wrapper = OBJECT_WRAP_CLASS::Unwrap(info.This()); if (!wrapper) { info.GetReturnValue().Set(64); @@ -436,7 +436,7 @@ rtError jsObjectWrapper::Get(const char* name, rtValue* value) const if (!strcmp(name, "length")) *value = rtValue(Array::Cast(*self)->Length()); else -#ifdef ENABLE_NODE_V_6_9 +#if defined ENABLE_NODE_V_6_9 || defined RTSCRIPT_SUPPORT_V8 err = Get((s->ToArrayIndex(ctx)).FromMaybe(Local())->Value(), value); #else err = Get(s->ToArrayIndex()->Value(), value); @@ -471,7 +471,7 @@ rtError jsObjectWrapper::Get(uint32_t i, rtValue* value) const Local self = PersistentToLocal(mIsolate, mObject); Local ctx = self->CreationContext(); -#ifdef ENABLE_NODE_V_6_9 +#if defined ENABLE_NODE_V_6_9 || defined RTSCRIPT_SUPPORT_V8 if (!(self->Has(ctx,i).FromMaybe(false))) #else if (!self->Has(i)) @@ -503,7 +503,7 @@ rtError jsObjectWrapper::Set(const char* name, const rtValue* value) if (mIsArray) { -#ifdef ENABLE_NODE_V_6_9 +#if defined ENABLE_NODE_V_6_9 || defined RTSCRIPT_SUPPORT_V8 Local idx = (s->ToArrayIndex(ctx)).FromMaybe(Local()); #else Local idx = s->ToArrayIndex(); diff --git a/src/rtScriptNode/rtObjectWrapper.h b/src/rtScriptV8/rtObjectWrapper.h similarity index 97% rename from src/rtScriptNode/rtObjectWrapper.h rename to src/rtScriptV8/rtObjectWrapper.h index 864c3eb88f..2776e4fc02 100644 --- a/src/rtScriptNode/rtObjectWrapper.h +++ b/src/rtScriptV8/rtObjectWrapper.h @@ -23,7 +23,7 @@ limitations under the License. using namespace v8; -namespace rtScriptNodeUtils +namespace rtScriptV8NodeUtils { class rtObjectWrapper : public rtWrapper @@ -109,14 +109,12 @@ class jsObjectWrapper : public rtIObject #ifndef RT_WRAPPER_UTILS #define RT_WRAPPER_UTILS -#include -#include - +#include "headers.h" #include #include #include -namespace rtScriptNodeUtils +namespace rtScriptV8NodeUtils { inline rtString toString(const v8::Handle& obj) diff --git a/src/rtScriptNode/rtScriptNode.cpp b/src/rtScriptV8/rtScriptNode.cpp similarity index 99% rename from src/rtScriptNode/rtScriptNode.cpp rename to src/rtScriptV8/rtScriptNode.cpp index c1c5c6c5b0..e344783492 100644 --- a/src/rtScriptNode/rtScriptNode.cpp +++ b/src/rtScriptV8/rtScriptNode.cpp @@ -18,6 +18,8 @@ // rtNode.cpp +#ifdef RTSCRIPT_SUPPORT_NODE + #if defined WIN32 #include #include @@ -57,7 +59,7 @@ #pragma GCC diagnostic pop #endif -#include "rtScriptNode.h" +#include "rtScriptV8Node.h" #include "rtCore.h" @@ -86,7 +88,7 @@ #include "rtObjectWrapper.h" #include "rtFunctionWrapper.h" -using namespace rtScriptNodeUtils; +using namespace rtScriptV8NodeUtils; #define SANDBOX_IDENTIFIER ( (const char*) "_sandboxStuff" ) @@ -1366,3 +1368,5 @@ rtError createScriptNode(rtScriptRef& script) script = new rtScriptNode(false); return RT_OK; } + +#endif // RTSCRIPT_SUPPORT_NODE \ No newline at end of file diff --git a/src/rtScriptV8/rtScriptV8.cpp b/src/rtScriptV8/rtScriptV8.cpp new file mode 100644 index 0000000000..dc65da8232 --- /dev/null +++ b/src/rtScriptV8/rtScriptV8.cpp @@ -0,0 +1,1468 @@ +/* + + pxCore Copyright 2005-2018 John Robinson + + 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. + +*/ + +#ifdef RTSCRIPT_SUPPORT_V8 + +extern unsigned char natives_blob_bin_data[]; +extern int natives_blob_bin_size; +extern unsigned char snapshot_blob_bin_data[]; +extern int snapshot_blob_bin_size; + +#if defined WIN32 +#include +#include +#define __PRETTY_FUNCTION__ __FUNCTION__ +#else +#include +#endif + +#include +#include + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +/* if this is defined, we have a 'secondary' entry point. +compare following to utypes.h defs for U_ICUDATA_ENTRY_POINT */ +#define SMALL_ICUDATA_ENTRY_POINT \ + SMALL_DEF2(U_ICU_VERSION_MAJOR_NUM, U_LIB_SUFFIX_C_NAME) +#define SMALL_DEF2(major, suff) SMALL_DEF(major, suff) +#ifndef U_LIB_SUFFIX_C_NAME +#define SMALL_DEF(major, suff) icusmdt##major##_dat +#else +#define SMALL_DEF(major, suff) icusmdt##suff##major##_dat +#endif + +extern "C" const char U_DATA_API SMALL_ICUDATA_ENTRY_POINT[]; + +#ifndef WIN32 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#include "rtWrapperUtils.h" + + +#ifndef WIN32 +#pragma GCC diagnostic pop +#endif + +#include "rtScriptV8Node.h" + +#include "rtCore.h" +#include "rtObject.h" +#include "rtValue.h" +#include "rtAtomic.h" +#include "rtScript.h" +#include "rtPromise.h" +#include "rtFunctionWrapper.h" +#include "rtObjectWrapper.h" + +#include +#include + +#include "rtFileDownloader.h" +#include + +#include +#include +#include + +#if defined(USE_STD_THREADS) +#include +#include +#endif + +#if !defined(_WIN32) +#include +#endif + +#if defined(_WIN32) +#include +#include +#include +#ifndef S_ISREG +# define S_ISREG(x) (((x) & _S_IFMT) == _S_IFREG) +#endif +#ifndef S_ISDIR +# define S_ISDIR(x) (((x) & _S_IFMT) == _S_IFDIR) +#endif +#ifndef S_ISFIFO +# define S_ISFIFO(x) (((x) & _S_IFMT) == _S_IFIFO) +#endif +#ifndef S_ISCHR +# define S_ISCHR(x) (((x) & _S_IFMT) == _S_IFCHR) +#endif +#ifndef S_ISBLK +# define S_ISBLK(x) 0 +#endif +#ifndef S_ISLINK +# define S_ISLNK(x) 0 +#endif +#ifndef S_ISSOCK +# define S_ISSOCK(x) 0 +#endif +#endif + +#if !defined(WIN32) && !defined(ENABLE_DFB) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" + +#pragma GCC diagnostic ignored "-Wall" +#endif + +#include "headers.h" +#include "libplatform/libplatform.h" + +#include "rtObjectWrapper.h" +#include "rtFunctionWrapper.h" +#include "rtWrapperUtils.h" + +#if !defined(WIN32) & !defined(ENABLE_DFB) +#pragma GCC diagnostic pop +#endif + +static rtAtomic sNextId = 100; + +bool gIsPumpingJavaScript = false; + +bool rtIsMainThreadNode() +{ + return true; +} + +namespace rtScriptV8NodeUtils +{ + extern rtV8FunctionItem v8ModuleBindings[]; + + rtError rtHttpGetBinding(int numArgs, const rtValue* args, rtValue* result, void* context); +} + +class V8ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { +public: + virtual void* Allocate(size_t size) + { + void *ret = AllocateUninitialized(size); + if (!ret) { + return NULL; + } + memset(ret, 0, size); + return ret; + } + virtual void* AllocateUninitialized(size_t size) + { + return malloc(size); + } + virtual void Free(void* data, size_t) { free(data); } +}; + +V8ArrayBufferAllocator* array_buffer_allocator = NULL; + +#if 0 +template +inline v8::Local V8StrongPersistentToLocal( + const v8::Persistent& persistent) { + return *reinterpret_cast*>( + const_cast*>(&persistent)); +} + +template +inline v8::Local V8WeakPersistentToLocal( + v8::Isolate* isolate, + const v8::Persistent& persistent) { + return v8::Local::New(isolate, persistent); +} + +template +inline v8::Local V8PersistentToLocal( + v8::Isolate* isolate, + const v8::Persistent& persistent) { + if (persistent.IsWeak()) { + return V8WeakPersistentToLocal(isolate, persistent); + } + else { + return V8StrongPersistentToLocal(persistent); + } +} +#endif + +using namespace rtScriptV8NodeUtils; + + +class rtV8Context; + +typedef rtRef rtV8ContextRef; + +class rtV8Context: rtIScriptContext // V8 +{ +public: + rtV8Context(v8::Isolate *isolate, v8::Platform* platform, uv_loop_t *loop); + + virtual ~rtV8Context(); + + virtual rtError add(const char *name, const rtValue& val); + virtual rtValue get(const char *name); + + virtual bool has(const char *name); + + virtual rtError runScript(const char *script, rtValue* retVal = NULL, const char *args = NULL); + virtual rtError runFile(const char *file, rtValue* retVal = NULL, const char *args = NULL); + + unsigned long AddRef() + { + return rtAtomicInc(&mRefCount); + } + + unsigned long Release(); + + Local loadV8Module(const rtString &name); + +private: + void addMethod(const char *name, v8::FunctionCallback callback, void *data = NULL); + void setupModuleLoading(); + void setupModuleBindings(); + +private: + v8::Isolate *mIsolate; + v8::Platform *mPlatform; + v8::Persistent mContext; + uv_loop_t *mUvLoop; + + std::map *> mLoadedModuleCache; + + rtRef mHttpGetBinding; + + int mRefCount; + + rtAtomic mId; + + const char *js_file; + std::string js_script; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef std::map rtV8Contexts; +typedef std::map::const_iterator rtV8Contexts_iterator; + +class rtScriptV8: public rtIScript +{ +public: + rtScriptV8(); + virtual ~rtScriptV8(); + + unsigned long AddRef() + { + return rtAtomicInc(&mRefCount); + } + + unsigned long Release(); + + rtError init(); + rtError term(); + + rtString engine() { return "v8"; } + + rtV8ContextRef createContext(); + rtError createContext(const char *lang, rtScriptContextRef& ctx); + + rtError pump(); + + v8::Isolate *getIsolate() + { + return mIsolate; + } + v8::Platform *getPlatform() + { + return mPlatform; + } + + rtError collectGarbage(); + void* getParameter(rtString param); + +private: + v8::Isolate *mIsolate; + v8::Persistent mContext; + v8::Platform *mPlatform; + uv_loop_t *mUvLoop; + + bool mV8Initialized; + + int mRefCount; +}; + + +using namespace v8; + +rtV8Context::rtV8Context(Isolate *isolate, Platform *platform, uv_loop_t *loop) : + mIsolate(isolate), mRefCount(0), mPlatform(platform), mUvLoop(loop) +{ + rtLogInfo(__FUNCTION__); + Locker locker(mIsolate); + Isolate::Scope isolate_scope(mIsolate); + HandleScope handle_scope(mIsolate); + + mId = rtAtomicInc(&sNextId); + + // Create a new context. + Local localContext = Context::New(mIsolate); + + localContext->SetEmbedderData(HandleMap::kContextIdIndex, Integer::New(mIsolate, mId)); + + mContext.Reset(mIsolate, localContext); // local to persistent + + Context::Scope contextScope(localContext); + + Handle global = localContext->Global(); + global->Set(String::NewFromUtf8(mIsolate, "_isV8", NewStringType::kNormal).ToLocalChecked(), + v8::Integer::New(isolate, 1)); + global->Set(String::NewFromUtf8(mIsolate, "global", NewStringType::kNormal).ToLocalChecked(), + v8::Object::New(isolate)); + + rtObjectWrapper::exportPrototype(mIsolate, global); + rtFunctionWrapper::exportPrototype(mIsolate, global); + + setupModuleLoading(); + setupModuleBindings(); + + v8::platform::PumpMessageLoop(mPlatform, mIsolate); + + mHttpGetBinding = new rtFunctionCallback(rtHttpGetBinding, loop); + + add("httpGet", mHttpGetBinding.getPtr()); +} + +rtV8Context::~rtV8Context() +{ + if (!mLoadedModuleCache.empty()) { + for (auto it = mLoadedModuleCache.begin(); it != mLoadedModuleCache.end(); ++it) { + delete (*it).second; + } + } +} + + +static bool bloatFileFromPath(uv_loop_t *loop, const rtString &path, rtString &data) +{ + uv_fs_t req; + int fd = 0; + uint64_t size; + char* chunk; + uv_buf_t buf; + + if (uv_fs_open(loop, &req, path.cString(), 0, 0644, NULL) < 0) { + goto fail; + } + uv_fs_req_cleanup(&req); + fd = req.result; + if (uv_fs_fstat(loop, &req, fd, NULL) < 0) { + goto fail; + } + uv_fs_req_cleanup(&req); + size = req.statbuf.st_size; + chunk = (char*)malloc(size); + buf = uv_buf_init(chunk, static_cast(size)); + if (uv_fs_read(loop, &req, fd, &buf, 1, 0, NULL) < 0) { + free(chunk); + goto fail; + } + uv_fs_req_cleanup(&req); + data = rtString(chunk, size); + free(chunk); + return true; + +fail: + uv_fs_req_cleanup(&req); + if (fd) { + uv_fs_close(loop, &req, fd, NULL); + } + uv_fs_req_cleanup(&req); + return false; +} + +static rtString getTryCatchResult(Local context, const TryCatch &tryCatch) +{ + if (tryCatch.HasCaught()) { + MaybeLocal val = tryCatch.StackTrace(context); + if (val.IsEmpty()) { + return rtString(); + } + Local ret = val.ToLocalChecked(); + String::Utf8Value trace(ret); + return rtString(*trace); + } + return rtString(); +} + +Local rtV8Context::loadV8Module(const rtString &name) +{ + rtString path = name; + if (!name.endsWith(".js")) { + path.append(".js"); + } + + rtString contents; + if (!bloatFileFromPath(mUvLoop, path, contents)) { + rtString path1("v8_modules/"); + path1.append(path.cString()); + path = path1; + if (!bloatFileFromPath(mUvLoop, path, contents)) { + rtLogWarn("module '%s' not found", name.cString()); + return Local(); + } + } + + Locker locker(mIsolate); + Isolate::Scope isolate_scope(mIsolate); + EscapableHandleScope handle_scope(mIsolate); + + Local localContext = PersistentToLocal(mIsolate, mContext); + Context::Scope context_scope(localContext); + + // check in cache + if (mLoadedModuleCache.find(path) != mLoadedModuleCache.end()) { + Persistent *loadedModule = mLoadedModuleCache[path]; + return handle_scope.Escape(PersistentToLocal(mIsolate, *loadedModule)); + } + + rtString contents1 = "(function(){var module=this; var exports=(this.exports = new Object());"; + contents1.append(contents.cString()); + contents1.append(" return this.exports; })"); + + v8::Local source = + v8::String::NewFromUtf8(mIsolate, contents1.cString(), v8::NewStringType::kNormal).ToLocalChecked(); + + TryCatch tryCatch(mIsolate); + + v8::MaybeLocal script = v8::Script::Compile(localContext, source); + + if (script.IsEmpty()) { + rtLogWarn("module '%s' compilation failed (%s)", name.cString(), getTryCatchResult(localContext, tryCatch).cString()); + return Local(); + } + + v8::MaybeLocal result = script.ToLocalChecked()->Run(localContext); + + if (result.IsEmpty() || !result.ToLocalChecked()->IsFunction()) { + rtLogWarn("module '%s' unexpected result (%s)", name.cString(), getTryCatchResult(localContext, tryCatch).cString()); + return Local(); + } + + v8::Function *func = v8::Function::Cast(*result.ToLocalChecked()); + MaybeLocal ret = func->Call(localContext, result.ToLocalChecked(), 0, NULL); + + if (ret.IsEmpty()) { + rtLogWarn("module '%s' unexpected call result (%s)", name.cString(), getTryCatchResult(localContext, tryCatch).cString()); + return Local(); + } + + Local toRet = ret.ToLocalChecked(); + Persistent *toRetPersistent = new Persistent(mIsolate, toRet); + + // store in cache + mLoadedModuleCache[path] = toRetPersistent; + + return handle_scope.Escape(toRet); +} + + +static void requireCallback(const v8::FunctionCallbackInfo& args) +{ + assert(args.Data()->IsExternal()); + v8::External *val = v8::External::Cast(*args.Data()); + assert(val != NULL); + rtV8Context *ctx = (rtV8Context *)val->Value(); + assert(args.Length() == 1); + assert(args[0]->IsString()); + + rtString moduleName = toString(args[0]->ToString()); + args.GetReturnValue().Set(ctx->loadV8Module(moduleName)); +} + + +void rtV8Context::addMethod(const char *name, v8::FunctionCallback callback, void *data) +{ + Locker locker(mIsolate); + Isolate::Scope isolate_scope(mIsolate); + HandleScope handle_scope(mIsolate); + + Local fTemplate = v8::FunctionTemplate::New(mIsolate, callback, v8::External::New(mIsolate, data)); + Local localContext = PersistentToLocal(mIsolate, mContext); + Context::Scope context_scope(localContext); + localContext->Global()->Set( + String::NewFromUtf8(mIsolate, name, NewStringType::kNormal).ToLocalChecked(), + fTemplate->GetFunction() + ); +} + +void rtV8Context::setupModuleLoading() +{ + addMethod("require", &requireCallback, (void*)this); +} + +void rtV8Context::setupModuleBindings() +{ + for (int i = 0; v8ModuleBindings[i].mName != NULL; ++i) { + const rtV8FunctionItem &item = v8ModuleBindings[i]; + addMethod(item.mName, item.mCallback, (void*)mUvLoop); + } +} + +rtError rtV8Context::add(const char *name, const rtValue& val) +{ + if (name == NULL) { + rtLogDebug(" rtNodeContext::add() - no symbolic name for rtValue"); + return RT_FAIL; + } + else if (this->has(name)) { + rtLogDebug(" rtNodeContext::add() - ALREADY HAS '%s' ... over-writing.", name); + // return; // Allow for "Null"-ing erasure. + } + + if (val.isEmpty()) { + rtLogDebug(" rtNodeContext::add() - rtValue is empty"); + return RT_FAIL; + } + + Locker locker(mIsolate); + Isolate::Scope isolate_scope(mIsolate); + HandleScope handle_scope(mIsolate); // Create a stack-allocated handle scope. + + // Get a Local context... + Local local_context = PersistentToLocal(mIsolate, mContext); + Context::Scope context_scope(local_context); + + local_context->Global()->Set(String::NewFromUtf8(mIsolate, name), rt2js(local_context, val)); + + return RT_OK; +} + +rtValue rtV8Context::get(const char *name) +{ + if (name == NULL) { + rtLogError(" rtNodeContext::get() - no symbolic name for rtValue"); + return rtValue(); + } + + Locker locker(mIsolate); + Isolate::Scope isolate_scope(mIsolate); + HandleScope handle_scope(mIsolate); // Create a stack-allocated handle scope. + + // Get a Local context... + Local local_context = PersistentToLocal(mIsolate, mContext); + Context::Scope context_scope(local_context); + + Handle global = local_context->Global(); + + // Get the object + Local object = global->Get(String::NewFromUtf8(mIsolate, name)); + + if (object->IsUndefined() || object->IsNull()) { + rtLogError("FATAL: '%s' is Undefined ", name); + return rtValue(); + } + else { + rtWrapperError error; // TODO - handle error + return js2rt(local_context, object, &error); + } +} + +bool rtV8Context::has(const char *name) +{ + if (name == NULL) { + rtLogError(" rtNodeContext::has() - no symbolic name for rtValue"); + return false; + } + + Locker locker(mIsolate); + Isolate::Scope isolate_scope(mIsolate); + HandleScope handle_scope(mIsolate); // Create a stack-allocated handle scope. + + // Get a Local context... + Local local_context = PersistentToLocal(mIsolate, mContext); + Context::Scope context_scope(local_context); + + Handle global = local_context->Global(); + + TryCatch try_catch(mIsolate); + Handle value = global->Get(String::NewFromUtf8(mIsolate, name)); + + if (try_catch.HasCaught()) { + rtLogError("\n ## has() - HasCaught() ... ERROR"); + return false; + } + + // No need to check if |value| is empty because it's taken care of + // by TryCatch above. + + return (!value->IsUndefined() && !value->IsNull()); +} + +rtError rtV8Context::runScript(const char *script, rtValue* retVal /*= NULL*/, const char *args /*= NULL*/) +{ + rtLogInfo(__FUNCTION__); + if (!script || strlen(script) == 0) { + rtLogError(" %s ... no script given.", __PRETTY_FUNCTION__); + + return RT_FAIL; + } + + {//scope + Locker locker(mIsolate); + Isolate::Scope isolate_scope(mIsolate); + HandleScope handle_scope(mIsolate); // Create a stack-allocated handle scope. + + // Get a Local context... + Local local_context = PersistentToLocal(mIsolate, mContext); + Context::Scope context_scope(local_context); + // !CLF TODO: TEST FOR MT + TryCatch tryCatch(mIsolate); + Local source = String::NewFromUtf8(mIsolate, script); + + // Compile the source code. + Local