diff --git a/CMakeLists.txt b/CMakeLists.txt index b8ad24df55..98d437ae4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,6 +171,17 @@ renderers/agg/src/agg_line_aa_basics.cpp renderers/agg/src/clipper.cpp ) include_directories(renderers/agg/include) + +set(v8_SOURCES + mapscript/v8/v8_object_wrap.hpp + mapscript/v8/point.cpp + mapscript/v8/line.cpp + mapscript/v8/shape.cpp + mapscript/v8/v8_mapscript.cpp + mapv8.cpp +) +include_directories(mapscript/v8/) + #add_definitions(-DHASH_DEBUG=1) if(WIN32) set(REGEX_SOURCES ${REGEX_DIR}/regex.c) @@ -201,10 +212,10 @@ mapogcfiltercommon.c maprendering.c mapwcs20.c mapogcsld.c mapresample.c mapwfs.c mapgdal.c mapogcsos.c mapscale.c mapwfs11.c mapgeomtransform.c mapogroutput.c mapsde.c mapwfslayer.c mapagg.cpp mapkml.cpp mapgeomutil.cpp mapkmlrenderer.cpp fontcache.c textlayout.c -mapogr.cpp mapcontour.c mapsmoothing.c mapv8.cpp ${REGEX_SOURCES}) +mapogr.cpp mapcontour.c mapsmoothing.c ${REGEX_SOURCES}) if(BUILD_DYNAMIC) - add_library(mapserver SHARED ${mapserver_SOURCES} ${agg_SOURCES}) + add_library(mapserver SHARED ${mapserver_SOURCES} ${agg_SOURCES} ${v8_SOURCES}) set_target_properties( mapserver PROPERTIES VERSION ${MapServer_VERSION_STRING} SOVERSION 1 @@ -212,7 +223,7 @@ if(BUILD_DYNAMIC) endif(BUILD_DYNAMIC) if(BUILD_STATIC) - add_library(mapserver_static STATIC ${mapserver_SOURCES} ${agg_SOURCES}) + add_library(mapserver_static STATIC ${mapserver_SOURCES} ${agg_SOURCES} ${v8_SOURCES}) set_target_properties( mapserver_static PROPERTIES VERSION ${MapServer_VERSION_STRING} SOVERSION 1 @@ -732,18 +743,18 @@ if(WITH_PYTHON) endif(WITH_PYTHON) if(WITH_V8) - find_package(V8) - if(V8_FOUND EQUAL 1) - set(USE_V8 1) - include_directories(${V8_INCLUDE}) - ms_link_libraries( ${V8_LIBS}) - else(V8_FOUND) - message(SEND_ERROR "V8 JavaScript support requested but not found. + FIND_PACKAGE(V8) + IF(V8_FOUND EQUAL 1) + SET(USE_V8_MAPSCRIPT 1) + INCLUDE_DIRECTORIES(${V8_INCLUDE}) + MS_LINK_LIBRARIES( ${V8_LIBS}) + ELSE(V8_FOUND) + MESSAGE(SEND_ERROR "V8 JavaScript support requested but not found. HINTS: - set V8_ROOT environment variable to the installation path of V8. - add the V8 install directory to the CMAKE_PREFIX_PATH variable (-DCMAKE_PREFIX_PATH=\"/path/to/${component}-install-dir;/path/to/other/dirs\") ") - endif() -endif(WITH_V8) + ENDIF() +ENDIF(WITH_V8) if(WITH_PHP) add_subdirectory("mapscript/php") @@ -867,7 +878,6 @@ status_optional_feature("Thread-safety support" "${USE_THREAD}") status_optional_feature("KML output" "${USE_KML}") status_optional_feature("Z+M point coordinate support" "${USE_POINT_Z_M}") status_optional_feature("XML Mapfile support" "${USE_XMLMAPFILE}") -status_optional_feature("V8 JavaScript" "${USE_V8}") message(STATUS " * Mapscripts") status_optional_feature("Python" "${USE_PYTHON_MAPSCRIPT}") @@ -876,6 +886,7 @@ status_optional_feature("PERL" "${USE_PERL_MAPSCRIPT}") status_optional_feature("RUBY" "${USE_RUBY_MAPSCRIPT}") status_optional_feature("JAVA" "${USE_JAVA_MAPSCRIPT}") status_optional_feature("C#" "${USE_CSHARP_MAPSCRIPT}") +status_optional_feature("V8 Javascript" "${USE_V8_MAPSCRIPT}") status_optional_feature("Apache Module (Experimental)" "${USE_APACHE_MODULE}") message(STATUS "") diff --git a/maperror.c b/maperror.c index 99d9862918..19bc298356 100644 --- a/maperror.c +++ b/maperror.c @@ -572,7 +572,7 @@ char *msGetVersion() #ifdef USE_POINT_Z_M strcat(version, " SUPPORTS=POINT_Z_M"); #endif -#ifdef USE_V8 +#ifdef USE_V8_MAPSCRIPT strcat(version, " SUPPORTS=V8"); #endif #ifdef USE_JPEG diff --git a/mapfile.c b/mapfile.c index 532a55c6ac..768a9240bb 100644 --- a/mapfile.c +++ b/mapfile.c @@ -5896,7 +5896,7 @@ int initMap(mapObj *map) msInitQuery(&(map->query)); -#ifdef USE_V8 +#ifdef USE_V8_MAPSCRIPT map->v8context = NULL; #endif diff --git a/mapgeomtransform.c b/mapgeomtransform.c index da8ebb1f64..1458017757 100644 --- a/mapgeomtransform.c +++ b/mapgeomtransform.c @@ -221,8 +221,21 @@ int msDrawTransformedShape(mapObj *map, imageObj *image, shapeObj *shape, styleO int msGeomTransformShape(mapObj *map, layerObj *layer, shapeObj *shape) { int i; - expressionObj *e = &layer->_geomtransform; - + expressionObj *e = &layer->_geomtransform; + +#ifdef USE_V8_MAPSCRIPT + if (!map->v8context) { + msV8CreateContext(map); + if (!map->v8context) + { + msSetError(MS_V8ERR, "Unable to create v8 context.", "msGeomTransformShape()"); + return MS_FAILURE; + } + } + + msV8ContextSetLayer(map, layer); +#endif + switch(e->type) { case MS_GEOMTRANSFORM_EXPRESSION: { int status; diff --git a/maplayer.c b/maplayer.c index 0a053fb6b7..7854a83826 100644 --- a/maplayer.c +++ b/maplayer.c @@ -271,6 +271,14 @@ int msLayerNextShape(layerObj *layer, shapeObj *shape) return rv; } +#ifdef USE_V8_MAPSCRIPT + /* we need to force the GetItems for the geomtransform attributes */ + if(!layer->items && + layer->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION && + strstr(layer->_geomtransform.string, "javascript")) + msLayerGetItems(layer); +#endif + /* At the end of switch case (default -> break; -> return MS_FAILURE), * was following TODO ITEM: */ @@ -868,7 +876,7 @@ int msLayerGetFeatureStyle(mapObj *map, layerObj *layer, classObj *c, shapeObj* stylestring = msStrdup(shape->values[layer->styleitemindex]); } else if (strncasecmp(layer->styleitem,"javascript://",13) == 0) { -#ifdef USE_V8 +#ifdef USE_V8_MAPSCRIPT char *filename = layer->styleitem+13; if (!map->v8context) { diff --git a/maplexer.l b/maplexer.l index db8a08888e..d1d01b7621 100644 --- a/maplexer.l +++ b/maplexer.l @@ -189,6 +189,7 @@ char path[MS_MAXPATHLEN]; simplifypt { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_SIMPLIFYPT); } generalize { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_GENERALIZE); } smoothsia { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_SMOOTHSIA); } +javascript { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_JAVASCRIPT); } intersects { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_INTERSECTS); } disjoint { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_DISJOINT); } diff --git a/mapobject.c b/mapobject.c index 19cdf49402..255b47cc52 100644 --- a/mapobject.c +++ b/mapobject.c @@ -137,7 +137,7 @@ void msFreeMap(mapObj *map) msFreeQuery(&(map->query)); -#ifdef USE_V8 +#ifdef USE_V8_MAPSCRIPT if (map->v8context) msV8FreeContext(map); #endif diff --git a/mapparser.y b/mapparser.y index ea9b5f062a..428cbb06f8 100644 --- a/mapparser.y +++ b/mapparser.y @@ -46,7 +46,7 @@ int yyerror(parseObj *, const char *); %left INTERSECTS DISJOINT TOUCHES OVERLAPS CROSSES WITHIN CONTAINS BEYOND DWITHIN %left AREA LENGTH COMMIFY ROUND %left TOSTRING -%left YYBUFFER DIFFERENCE SIMPLIFY SIMPLIFYPT GENERALIZE SMOOTHSIA +%left YYBUFFER DIFFERENCE SIMPLIFY SIMPLIFYPT GENERALIZE SMOOTHSIA JAVASCRIPT %left '+' '-' %left '*' '/' '%' %left NEG @@ -629,6 +629,17 @@ shape_exp: SHAPE s->scratch = MS_TRUE; $$ = s; } + | JAVASCRIPT '(' shape_exp ',' string_exp ')' { + shapeObj *s; + s = msV8TransformShape($3, $5); + free($5); + if(!s) { + yyerror(p, "Executing javascript failed."); + return(-1); + } + s->scratch = MS_TRUE; + $$ = s; + } ; string_exp: STRING @@ -752,7 +763,8 @@ int yylex(YYSTYPE *lvalp, parseObj *p) case MS_TOKEN_FUNCTION_SIMPLIFY: token = SIMPLIFY; break; case MS_TOKEN_FUNCTION_SIMPLIFYPT: token = SIMPLIFYPT; break; case MS_TOKEN_FUNCTION_GENERALIZE: token = GENERALIZE; break; - case MS_TOKEN_FUNCTION_SMOOTHSIA: token = SMOOTHSIA; break; + case MS_TOKEN_FUNCTION_SMOOTHSIA: token = SMOOTHSIA; break; + case MS_TOKEN_FUNCTION_JAVASCRIPT: token = JAVASCRIPT; break; default: break; diff --git a/mapscript/v8/line.cpp b/mapscript/v8/line.cpp new file mode 100644 index 0000000000..19ce4d018d --- /dev/null +++ b/mapscript/v8/line.cpp @@ -0,0 +1,238 @@ +/********************************************************************** + * + * Project: MapServer + * Purpose: V8 JavaScript Engine Support + * Author: Alan Boudreault (aboudreault@mapgears.com) + * + ********************************************************************** + * Copyright (c) 2013, Alan Boudreault, MapGears + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + **********************************************************************/ + +#include "mapserver-config.h" +#ifdef USE_V8_MAPSCRIPT + +#include "v8_mapscript.h" + +using namespace v8; + +Persistent Line::constructor; + +void Line::Initialize(Handle target) +{ + HandleScope scope; + + Handle c = FunctionTemplate::New(Line::New); + c->InstanceTemplate()->SetInternalFieldCount(1); + c->SetClassName(String::NewSymbol("lineObj")); + + SET_ATTRIBUTE_RO(c, "numpoints", getProp); + + NODE_SET_PROTOTYPE_METHOD(c, "point", getPoint); + NODE_SET_PROTOTYPE_METHOD(c, "addXY", addXY); + NODE_SET_PROTOTYPE_METHOD(c, "addXYZ", addXYZ); + NODE_SET_PROTOTYPE_METHOD(c, "add", addPoint); + + target->Set(String::NewSymbol("lineObj"), c->GetFunction()); + + constructor.Reset(Isolate::GetCurrent(), c); +} + +void Line::Dispose() +{ + Line::constructor.Dispose(); + Line::constructor.Clear(); +} + +Line::~Line() +{ + if (this->freeInternal) { + msFree(this->this_->point); + msFree(this->this_); + } +} + +Handle Line::Constructor() +{ + return (*Line::constructor)->GetFunction(); +} + +void Line::New(const v8::FunctionCallbackInfo& args) +{ + HandleScope scope; + + if (args[0]->IsExternal()) + { + Local ext = Local::Cast(args[0]); + void *ptr = ext->Value(); + Line *line = static_cast(ptr); + Handle self = args.Holder(); + line->Wrap(self); + if (line->parent_) { + self->SetHiddenValue(String::New("__parent__"), line->parent_->handle()); + line->disableMemoryHandler(); + } + } + else + { + lineObj *l = (lineObj *)msSmallMalloc(sizeof(lineObj)); + + l->numpoints=0; + l->point=NULL; + + Line *line = new Line(l); + line->Wrap(args.Holder()); + } + +} + +Line::Line(lineObj *l, ObjectWrap *p): + ObjectWrap() +{ + this->this_ = l; + this->parent_ = p; + this->freeInternal = true; +} + +void Line::getProp(Local property, + const PropertyCallbackInfo& info) +{ + HandleScope scope; + Line* l = ObjectWrap::Unwrap(info.Holder()); + std::string name = TOSTR(property); + Handle value = Undefined(); + + if (name == "numpoints") + value = Integer::New(l->get()->numpoints); + + info.GetReturnValue().Set(value); +} + +void Line::getPoint(const v8::FunctionCallbackInfo& args) +{ + HandleScope scope; + + if (args.Length() < 1 || !args[0]->IsInt32()) { + ThrowException(String::New("Invalid argument")); + return; + } + + Line* l = ObjectWrap::Unwrap(args.Holder()); + lineObj* line = l->get(); + + int index = args[0]->Int32Value(); + + if (index < 0 || index >= line->numpoints) + { + ThrowException(String::New("Invalid point index.")); + return; + } + + Point *point = new Point(&line->point[index], l); + Handle ext = External::New(point); + args.GetReturnValue().Set(Point::Constructor()->NewInstance(1, &ext)); +} + +void Line::addXY(const v8::FunctionCallbackInfo& args) +{ + HandleScope scope; + + if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsNumber()) { + ThrowException(String::New("Invalid argument")); + return; + } + + Line* l = ObjectWrap::Unwrap(args.Holder()); + lineObj* line = l->get(); + + if(line->numpoints == 0) /* new */ + line->point = (pointObj *)msSmallMalloc(sizeof(pointObj)); + else /* extend array */ + line->point = (pointObj *)msSmallRealloc(line->point, sizeof(pointObj)*(line->numpoints+1)); + + line->point[line->numpoints].x = args[0]->NumberValue(); + line->point[line->numpoints].y = args[1]->NumberValue(); +#ifdef USE_POINT_Z_M + if (args.Length() > 2 && args[2]->IsNumber()) + line->point[line->numpoints].m = args[2]->NumberValue(); +#endif + + line->numpoints++; +} + +void Line::addXYZ(const v8::FunctionCallbackInfo& args) +{ + HandleScope scope; + + if (args.Length() < 3 || !args[0]->IsNumber() || + !args[1]->IsNumber() || !args[2]->IsNumber()) { + ThrowException(String::New("Invalid argument")); + return; + } + + Line* l = ObjectWrap::Unwrap(args.Holder()); + lineObj* line = l->get(); + + if(line->numpoints == 0) /* new */ + line->point = (pointObj *)msSmallMalloc(sizeof(pointObj)); + else /* extend array */ + line->point = (pointObj *)msSmallRealloc(line->point, sizeof(pointObj)*(line->numpoints+1)); + + line->point[line->numpoints].x = args[0]->NumberValue(); + line->point[line->numpoints].y = args[1]->NumberValue(); +#ifdef USE_POINT_Z_M + line->point[line->numpoints].z = args[2]->NumberValue(); + if (args.Length() > 3 && args[3]->IsNumber()) + line->point[line->numpoints].m = args[3]->NumberValue(); +#endif + line->numpoints++; +} + +void Line::addPoint(const v8::FunctionCallbackInfo& args) +{ + HandleScope scope; + + if (args.Length() < 1 || !args[0]->IsObject() || + !args[0]->ToObject()->GetConstructorName()->Equals(String::New("pointObj"))) { + ThrowException(String::New("Invalid argument")); + return; + } + + Line* l = ObjectWrap::Unwrap(args.Holder()); + lineObj* line = l->get(); + Point* p = ObjectWrap::Unwrap(args[0]->ToObject()); + pointObj* point = p->get(); + + if(line->numpoints == 0) /* new */ + line->point = (pointObj *)msSmallMalloc(sizeof(pointObj)); + else /* extend array */ + line->point = (pointObj *)msSmallRealloc(line->point, sizeof(pointObj)*(line->numpoints+1)); + + line->point[line->numpoints].x = point->x; + line->point[line->numpoints].y = point->y; +#ifdef USE_POINT_Z_M + line->point[line->numpoints].z = point->z; + if (args.Length() > 3 && args[3]->IsNumber()) + line->point[line->numpoints].m = point->m; +#endif + line->numpoints++; +} + +#endif diff --git a/mapscript/v8/line.hpp b/mapscript/v8/line.hpp new file mode 100644 index 0000000000..b08016505f --- /dev/null +++ b/mapscript/v8/line.hpp @@ -0,0 +1,66 @@ +/********************************************************************** + * + * Project: MapServer + * Purpose: V8 JavaScript Engine Support + * Author: Alan Boudreault (aboudreault@mapgears.com) + * + ********************************************************************** + * Copyright (c) 2013, Alan Boudreault, MapGears + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + **********************************************************************/ + +#ifndef LINE_H_ +#define LINE_H_ + +#include + +using namespace v8; + +class Line: public ObjectWrap +{ +public: + static void Initialize(Handle target); + static void New(const v8::FunctionCallbackInfo& args); + static void Dispose(); + static Handle Constructor(); + + Line(lineObj *l, ObjectWrap *p = NULL); + ~Line(); + inline lineObj* get() { return this_; } + inline void disableMemoryHandler() { this->freeInternal = false; } + + static void getProp(Local property, + const PropertyCallbackInfo& info); + static void setProp(Local property, + Local value, + const PropertyCallbackInfo& info); + + static void getPoint(const v8::FunctionCallbackInfo& args); + static void addXY(const v8::FunctionCallbackInfo& args); + static void addXYZ(const v8::FunctionCallbackInfo& args); + static void addPoint(const v8::FunctionCallbackInfo& args); +private: + static Persistent constructor; + lineObj *this_; + ObjectWrap *parent_; + bool freeInternal; +}; + +#endif diff --git a/mapscript/v8/point.cpp b/mapscript/v8/point.cpp new file mode 100644 index 0000000000..4915fdab18 --- /dev/null +++ b/mapscript/v8/point.cpp @@ -0,0 +1,206 @@ +/********************************************************************** + * + * Project: MapServer + * Purpose: V8 JavaScript Engine Support + * Author: Alan Boudreault (aboudreault@mapgears.com) + * + ********************************************************************** + * Copyright (c) 2013, Alan Boudreault, MapGears + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + **********************************************************************/ + +#include "mapserver-config.h" +#ifdef USE_V8_MAPSCRIPT + +#include "v8_mapscript.h" + +using namespace v8; + +Persistent Point::constructor; + +void Point::Initialize(Handle target) +{ + HandleScope scope; + + Handle c = FunctionTemplate::New(Point::New); + c->InstanceTemplate()->SetInternalFieldCount(1); + c->SetClassName(String::NewSymbol("pointObj")); + + SET_ATTRIBUTE(c, "x", getProp, setProp); + SET_ATTRIBUTE(c, "y", getProp, setProp); +#ifdef USE_POINT_Z_M + SET_ATTRIBUTE(c, "z", getProp, setProp); + SET_ATTRIBUTE(c, "m", getProp, setProp); +#endif + + NODE_SET_PROTOTYPE_METHOD(c, "setXY", setXY); + NODE_SET_PROTOTYPE_METHOD(c, "setXYZ", setXYZ); + + target->Set(String::NewSymbol("pointObj"), c->GetFunction()); + + constructor.Reset(Isolate::GetCurrent(), c); +} + +void Point::Dispose() +{ + Point::constructor.Dispose(); + Point::constructor.Clear(); +} + +Point::~Point() +{ + if (this->freeInternal) { + msFree(this->get()); + } +} + +Handle Point::Constructor() +{ + return (*Point::constructor)->GetFunction(); +} + +void Point::New(const v8::FunctionCallbackInfo& args) +{ + HandleScope scope; + + if (args[0]->IsExternal()) + { + Local ext = Local::Cast(args[0]); + void *ptr = ext->Value(); + Point *point = static_cast(ptr); + Handle self = args.Holder(); + point->Wrap(self); + if (point->parent_) { + self->SetHiddenValue(String::New("__parent__"), point->parent_->handle()); + point->disableMemoryHandler(); + } + } + else + { + pointObj *p = (pointObj *)msSmallMalloc(sizeof(pointObj)); + + p->x = 0; + p->y = 0; +#ifdef USE_POINT_Z_M + p->z = 0; + p->m = 0; +#endif + + Point *point = new Point(p); + point->Wrap(args.Holder()); + } +} + + Point::Point(pointObj *p, ObjectWrap *pa): + ObjectWrap() +{ + this->this_ = p; + this->parent_ = pa; + this->freeInternal = true; +} + +void Point::getProp(Local property, + const PropertyCallbackInfo& info) +{ + HandleScope scope; + Point* p = ObjectWrap::Unwrap(info.Holder()); + std::string name = TOSTR(property); + Handle value = Undefined(); + + if (name == "x") + value = Number::New(p->get()->x); + else if (name == "y") + value = Number::New(p->get()->y); +#ifdef USE_POINT_Z_M + else if (name == "z") + value = Number::New(p->get()->z); + else if (name == "m") + value = Number::New(p->get()->m); +#endif + + info.GetReturnValue().Set(value); +} + +void Point::setProp(Local property, + Local value, + const PropertyCallbackInfo& info) +{ + HandleScope scope; + Point* p = ObjectWrap::Unwrap(info.Holder()); + std::string name = TOSTR(property); + if (!value->IsNumber()) + ThrowException(Exception::TypeError( + String::New("point value must be a number"))); + if (name == "x") { + p->get()->x = value->NumberValue(); + } else if (name == "y") { + p->get()->y = value->NumberValue(); + } +#ifdef USE_POINT_Z_M + else if (name == "z") { + p->get()->z = value->NumberValue(); + } else if (name == "m") { + p->get()->m = value->NumberValue(); + } +#endif + +} + +void Point::setXY(const v8::FunctionCallbackInfo& args) +{ + HandleScope scope; + + if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsNumber()) { + ThrowException(String::New("Invalid argument")); + return; + } + + Point* p = ObjectWrap::Unwrap(args.Holder()); + + p->get()->x = args[0]->NumberValue(); + p->get()->y = args[1]->NumberValue(); + +} + +void Point::setXYZ(const v8::FunctionCallbackInfo& args) +{ + HandleScope scope; + + if (args.Length() < 3 || + !args[0]->IsNumber() || !args[1]->IsNumber() || !args[2]->IsNumber()) { + ThrowException(String::New("Invalid argument")); + return; + } + + Point* p = ObjectWrap::Unwrap(args.Holder()); + + p->get()->x = args[0]->NumberValue(); + p->get()->y = args[1]->NumberValue(); + +#ifdef USE_POINT_Z_M + p->get()->z = args[2]->NumberValue(); + if (args.Length() > 3 && args[3]->IsNumber()) { + p->get()->m = args[3]->NumberValue(); + } +#endif + +} + +#endif diff --git a/mapscript/v8/point.hpp b/mapscript/v8/point.hpp new file mode 100644 index 0000000000..b8e173d551 --- /dev/null +++ b/mapscript/v8/point.hpp @@ -0,0 +1,64 @@ +/********************************************************************** + * + * Project: MapServer + * Purpose: V8 JavaScript Engine Support + * Author: Alan Boudreault (aboudreault@mapgears.com) + * + ********************************************************************** + * Copyright (c) 2013, Alan Boudreault, MapGears + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + **********************************************************************/ + +#ifndef POINT_H_ +#define POINT_H_ + +#include + +using namespace v8; + +class Point: public ObjectWrap +{ +public: + static void Initialize(Handle target); + static void New(const v8::FunctionCallbackInfo& args); + static void Dispose(); + static Handle Constructor(); + + Point(pointObj *p, ObjectWrap *pa = NULL); + ~Point(); + inline pointObj* get() { return this_; } + inline void disableMemoryHandler() { this->freeInternal = false; } + + static void getProp(Local property, + const PropertyCallbackInfo& info); + static void setProp(Local property, + Local value, + const PropertyCallbackInfo& info); + + static void setXY(const v8::FunctionCallbackInfo& args); + static void setXYZ(const v8::FunctionCallbackInfo& args); +private: + static Persistent constructor; + pointObj *this_; + ObjectWrap *parent_; + bool freeInternal; +}; + +#endif diff --git a/mapscript/v8/shape.cpp b/mapscript/v8/shape.cpp new file mode 100644 index 0000000000..bfd5f7e545 --- /dev/null +++ b/mapscript/v8/shape.cpp @@ -0,0 +1,354 @@ +/********************************************************************** + * + * Project: MapServer + * Purpose: V8 JavaScript Engine Support + * Author: Alan Boudreault (aboudreault@mapgears.com) + * + ********************************************************************** + * Copyright (c) 2013, Alan Boudreault, MapGears + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + **********************************************************************/ + +#include "mapserver-config.h" +#ifdef USE_V8_MAPSCRIPT + +#include "v8_mapscript.h" +#include + +using namespace v8; +using std::map; +using std::string; + +Persistent Shape::constructor; + +void Shape::Initialize(Handle target) +{ + HandleScope scope; + + Handle c = FunctionTemplate::New(Shape::New); + c->InstanceTemplate()->SetInternalFieldCount(1); + c->SetClassName(String::NewSymbol("shapeObj")); + + SET_ATTRIBUTE_RO(c, "numvalues", getProp); + SET_ATTRIBUTE_RO(c, "numlines", getProp); + SET_ATTRIBUTE_RO(c, "index", getProp); + SET_ATTRIBUTE_RO(c, "type", getProp); + SET_ATTRIBUTE_RO(c, "tileindex", getProp); + SET_ATTRIBUTE_RO(c, "classindex", getProp); + SET_ATTRIBUTE(c, "text", getProp, setProp); + + NODE_SET_PROTOTYPE_METHOD(c, "clone", clone); + NODE_SET_PROTOTYPE_METHOD(c, "line", getLine); + NODE_SET_PROTOTYPE_METHOD(c, "add", addLine); + NODE_SET_PROTOTYPE_METHOD(c, "setGeometry", setGeometry); + + target->Set(String::NewSymbol("shapeObj"), c->GetFunction()); + + constructor.Reset(Isolate::GetCurrent(), c); +} + +void Shape::Dispose() +{ + Shape::constructor.Dispose(); + Shape::constructor.Clear(); +} + +Shape::~Shape() +{ + /* this is set to false if the shapeObj is owned by mapserver and not v8 */ + if (freeInternal) { + msFreeShape(this->get()); + msFree(this->get()); + } +} + +Handle Shape::Constructor() +{ + return (*Shape::constructor)->GetFunction(); +} + +void Shape::New(const v8::FunctionCallbackInfo& args) +{ + HandleScope scope; + Handle self = args.Holder(); + Shape *shape; + + if (args[0]->IsExternal()) + { + Local ext = Local::Cast(args[0]); + void *ptr = ext->Value(); + shape = static_cast(ptr); + shape->Wrap(args.Holder()); + } + else + { + shapeObj *s = (shapeObj *)msSmallMalloc(sizeof(shapeObj)); + + msInitShape(s); + if(args.Length() >= 1) { + s->type = args[0]->Int32Value(); + } + else { + s->type = MS_SHAPE_NULL; + } + + shape = new Shape(s); + shape->Wrap(self); + } + + /* create the attribute template. should use ObjectWrap in future */ + Handle attributes_templ = ObjectTemplate::New(); + attributes_templ->SetInternalFieldCount(2); + attributes_templ->SetNamedPropertyHandler(attributeGetValue, + attributeSetValue); + Handle attributes = attributes_templ->NewInstance(); + map *attributes_map = new map(); + attributes->SetInternalField(0, External::New(attributes_map)); + attributes->SetInternalField(1, External::New(shape->get()->values)); + attributes->SetHiddenValue(String::New("__parent__"), self); + + if (shape->layer) { + for (int i=0; ilayer->numitems; ++i) { + (*attributes_map)[string(shape->layer->items[i])] = i; + } + } + + Persistent pattributes; + pattributes.Reset(Isolate::GetCurrent(), attributes); + pattributes.MakeWeak(attributes_map, attributeWeakCallback); + pattributes.MarkIndependent(); + + self->Set(String::New("attributes"), attributes); +} + +Shape::Shape(shapeObj *s): + ObjectWrap() +{ + this->this_ = s; + this->layer = NULL; + this->freeInternal = true; +} + +void Shape::getProp(Local property, + const PropertyCallbackInfo& info) +{ + HandleScope scope; + Shape* s = ObjectWrap::Unwrap(info.Holder()); + std::string name = TOSTR(property); + Handle value = Undefined(); + + if (name == "numvalues") + value = Integer::New(s->get()->numvalues); + else if (name == "numlines") + value = Integer::New(s->get()->numlines); + else if (name == "index") + value = Number::New(s->get()->index); + else if (name == "type") + value = Integer::New(s->get()->type); + else if (name == "tileindex") + value = Integer::New(s->get()->tileindex); + else if (name == "classindex") + value = Integer::New(s->get()->classindex); + else if (name == "text") + value = String::New(s->get()->text); + + info.GetReturnValue().Set(value); +} + +void Shape::setProp(Local property, + Local value, + const PropertyCallbackInfo& info) +{ + HandleScope scope; + Shape* s = ObjectWrap::Unwrap(info.Holder()); + std::string name = TOSTR(property); + + if (name == "text") { + if (s->get()->text) + msFree(s->get()->text); + s->get()->text = getStringValue(value); + } +} + +void Shape::clone(const v8::FunctionCallbackInfo& args) +{ + HandleScope scope; + Shape* s = ObjectWrap::Unwrap(args.Holder()); + shapeObj *shape = s->get(); + + shapeObj *new_shape = (shapeObj *)msSmallMalloc(sizeof(shapeObj)); + msInitShape(new_shape); + msCopyShape(shape, new_shape); + + Shape *ns = new Shape(new_shape); + Handle ext = External::New(ns); + Handle clone = Shape::Constructor()->NewInstance(1, &ext); + + /* we need this to copy shape attributes */ + Handle self = s->handle(); + Handle self_attributes = self->Get(String::New("attributes"))->ToObject(); + Local wrap = Local::Cast(self_attributes->GetInternalField(0)); + void *ptr = wrap->Value(); + map *self_attributes_map = static_cast *>(ptr); + + Handle clone_attributes = clone->Get(String::New("attributes"))->ToObject(); + wrap = Local::Cast(clone_attributes->GetInternalField(0)); + ptr = wrap->Value(); + map *clone_attributes_map = static_cast *>(ptr); + + clone_attributes_map->insert(self_attributes_map->begin(), + self_attributes_map->end()); + + args.GetReturnValue().Set(clone); +} + +void Shape::getLine(const v8::FunctionCallbackInfo& args) +{ + HandleScope scope; + + if (args.Length() < 1 || !args[0]->IsInt32()) { + ThrowException(String::New("Invalid argument")); + return; + } + + int index = args[0]->Int32Value(); + + Shape* s = ObjectWrap::Unwrap(args.Holder()); + shapeObj *shape = s->get(); + + if (index < 0 || index >= shape->numlines) + { + ThrowException(String::New("Invalid line index.")); + return; + } + + Line *line = new Line(&shape->line[index], s); + Handle ext = External::New(line); + args.GetReturnValue().Set(Line::Constructor()->NewInstance(1, &ext)); +} + +void Shape::addLine(const v8::FunctionCallbackInfo& args) +{ + HandleScope scope; + + if (args.Length() < 1 || !args[0]->IsObject() || + !args[0]->ToObject()->GetConstructorName()->Equals(String::New("lineObj"))) { + ThrowException(String::New("Invalid argument")); + return; + } + + Shape* s = ObjectWrap::Unwrap(args.Holder()); + shapeObj *shape = s->get(); + + Line* l = ObjectWrap::Unwrap(args[0]->ToObject()); + lineObj *line = l->get(); + + msAddLine(shape, line); +} + +void Shape::setGeometry(const v8::FunctionCallbackInfo& args) +{ + HandleScope scope; + + if (args.Length() < 1 || !args[0]->IsObject() || + !args[0]->ToObject()->GetConstructorName()->Equals(String::New("shapeObj"))) { + ThrowException(String::New("Invalid argument")); + return; + } + + Shape* s = ObjectWrap::Unwrap(args.Holder()); + shapeObj *shape = s->get(); + Shape* ns = ObjectWrap::Unwrap(args[0]->ToObject()); + shapeObj *new_shape = ns->get(); + + /* clean current shape */ + for (int i = 0; i < shape->numlines; i++) { + free(shape->line[i].point); + } + if (shape->line) free(shape->line); + shape->line = NULL; + shape->numlines = 0; + + for (int i = 0; i < new_shape->numlines; i++) { + msAddLine(shape, &(new_shape->line[i])); + } + + return; +} + +void Shape::attributeWeakCallback(v8::Isolate* isolate, + v8::Persistent* pobj, + map *map) { + v8::HandleScope scope(isolate); + pobj->Dispose(); + pobj->Clear(); + delete map; +} + +void Shape::attributeGetValue(Local name, + const PropertyCallbackInfo &info) +{ + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + void *ptr = wrap->Value(); + map *indexes = static_cast *>(ptr); + wrap = Local::Cast(self->GetInternalField(1)); + ptr = wrap->Value(); + char **values = static_cast(ptr); + + String::Utf8Value utf8_value(name); + string key = string(*utf8_value); + map::iterator iter = indexes->find(key); + + if (iter != indexes->end()) { + const int &index = (*iter).second; + info.GetReturnValue().Set(String::New(values[index])); + } +} + +void Shape::attributeSetValue(Local name, + Local value, + const PropertyCallbackInfo &info) +{ + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + void *ptr = wrap->Value(); + map *indexes = static_cast *>(ptr); + wrap = Local::Cast(self->GetInternalField(1)); + ptr = wrap->Value(); + char **values = static_cast(ptr); + + String::Utf8Value utf8_name(name), utf8_value(value); + string key = string(*utf8_name); + + map::iterator iter = indexes->find(key); + + if (iter == indexes->end()) { + ThrowException(String::New("Invalid value name.")); + } + else + { + const int &index = (*iter).second; + msFree(values[index]); + values[index] = msStrdup(*utf8_value); + } +} + +#endif diff --git a/mapscript/v8/shape.hpp b/mapscript/v8/shape.hpp new file mode 100644 index 0000000000..3f9bdc01ef --- /dev/null +++ b/mapscript/v8/shape.hpp @@ -0,0 +1,85 @@ +/********************************************************************** + * + * Project: MapServer + * Purpose: V8 JavaScript Engine Support + * Author: Alan Boudreault (aboudreault@mapgears.com) + * + ********************************************************************** + * Copyright (c) 2013, Alan Boudreault, MapGears + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + **********************************************************************/ + +#ifndef SHAPE_H_ +#define SHAPE_H_ + +#include +#include +#include + +using namespace v8; +using std::map; +using std::string; + +class Shape: public ObjectWrap +{ +public: + static void Initialize(Handle target); + static void New(const v8::FunctionCallbackInfo& args); + static void Dispose(); + static Handle Constructor(); + + Shape(shapeObj *p); + ~Shape(); + inline shapeObj* get() { return this_; } + inline void disableMemoryHandler() { this->freeInternal = false; } + + inline void setLayer(layerObj *layer) { this->layer = layer; }; + + static void getProp(Local property, + const PropertyCallbackInfo& info); + static void setProp(Local property, + Local value, + const PropertyCallbackInfo& info); + + static void clone(const v8::FunctionCallbackInfo& args); + static void getLine(const v8::FunctionCallbackInfo& args); + static void addLine(const v8::FunctionCallbackInfo& args); + static void setGeometry(const v8::FunctionCallbackInfo& args); + + /* This could be generic in the future.. */ + static void attributeWeakCallback(v8::Isolate* isolate, + v8::Persistent* pobj, + map *map); + static void attributeGetValue(Local name, + const PropertyCallbackInfo &info); + static void attributeSetValue(Local name, + Local value, + const PropertyCallbackInfo &info); + static void attributeMapDestroy(Isolate *isolate, + Persistent *object, + map *map); +private: + static Persistent constructor; + bool freeInternal; + layerObj *layer; /* for attributes names */ + shapeObj *this_; +}; + +#endif diff --git a/mapscript/v8/v8_mapscript.cpp b/mapscript/v8/v8_mapscript.cpp new file mode 100644 index 0000000000..ea3d8aadd8 --- /dev/null +++ b/mapscript/v8/v8_mapscript.cpp @@ -0,0 +1,48 @@ +/********************************************************************** + * + * Project: MapServer + * Purpose: V8 JavaScript Engine Support + * Author: Alan Boudreault (aboudreault@mapgears.com) + * + ********************************************************************** + * Copyright (c) 2013, Alan Boudreault, MapGears + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + **********************************************************************/ + +#include "mapserver-config.h" +#ifdef USE_V8_MAPSCRIPT + +#include "mapserver.h" +#include "v8_mapscript.h" + +char* getStringValue(Local value, const char *fallback) +{ + if (value->IsString()) { + String::AsciiValue string(value); + char *str = (char *) malloc(string.length() + 1); + strcpy(str, *string); + return str; + } + char *str = (char *) malloc(strlen(fallback) + 1); + strcpy(str, fallback); + return str; +} + +#endif diff --git a/mapscript/v8/v8_mapscript.h b/mapscript/v8/v8_mapscript.h new file mode 100644 index 0000000000..b38d36d9eb --- /dev/null +++ b/mapscript/v8/v8_mapscript.h @@ -0,0 +1,108 @@ +/********************************************************************** + * + * Project: MapServer + * Purpose: V8 JavaScript Engine Support + * Author: Alan Boudreault (aboudreault@mapgears.com) + * + ********************************************************************** + * Copyright (c) 2013, Alan Boudreault, MapGears + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + **********************************************************************/ + +#ifndef V8_MAPSCRIPT_H +#define V8_MAPSCRIPT_H + +#include "mapserver-config.h" +#ifdef USE_V8_MAPSCRIPT + +/* This need should be removed in future v8 version */ +#define V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR 1 +#define V8_USE_UNSAFE_HANDLES 1 + +#include "mapserver.h" +#include +#include +#include +#include +#include "v8_object_wrap.hpp" +#include "point.hpp" +#include "line.hpp" +#include "shape.hpp" + +using namespace v8; + +using std::string; +using std::stack; +using std::map; + +class V8Context +{ +public: + V8Context(Isolate *isolate) + : isolate(isolate) {} + Isolate *isolate; + stack paths; /* for relative paths and the require function */ + map > scripts; + Persistent context; + layerObj *layer; /* current layer, used in geomtransform */ +}; + +#define V8CONTEXT(map) ((V8Context*) (map)->v8context) + +inline void NODE_SET_PROTOTYPE_METHOD(v8::Handle recv, + const char* name, + v8::FunctionCallback callback) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); + v8::Local t = v8::FunctionTemplate::New(callback); + recv->InstanceTemplate()->Set(v8::String::NewFromUtf8(isolate, name), + t->GetFunction()); +} +#define NODE_SET_PROTOTYPE_METHOD NODE_SET_PROTOTYPE_METHOD + +#define TOSTR(obj) (*String::Utf8Value((obj)->ToString())) + +#define SET(target, name, value) \ + (target)->PrototypeTemplate()->Set(String::NewSymbol(name), value); + +#define SET_ATTRIBUTE(t, name, get, set) \ + t->InstanceTemplate()->SetAccessor(String::NewSymbol(name), get, set) + +#define SET_ATTRIBUTE_RO(t, name, get) \ + t->InstanceTemplate()->SetAccessor( \ + String::NewSymbol(name), \ + get, 0, \ + Handle(), \ + DEFAULT, \ + static_cast( \ + ReadOnly|DontDelete)) + +#define NODE_DEFINE_CONSTANT(target, name, constant) \ + (target)->Set(String::NewSymbol(name), \ + Integer::New(constant), \ + static_cast( \ + ReadOnly|DontDelete)); + +char* getStringValue(Local value, const char *fallback=""); + + +#endif + +#endif diff --git a/mapscript/v8/v8_object_wrap.hpp b/mapscript/v8/v8_object_wrap.hpp new file mode 100644 index 0000000000..b451266527 --- /dev/null +++ b/mapscript/v8/v8_object_wrap.hpp @@ -0,0 +1,129 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +#ifndef V8_OBJECT_WRAP_H_ +#define V8_OBJECT_WRAP_H_ + +#include "v8.h" +#include + +class ObjectWrap { + public: + ObjectWrap() { + refs_ = 0; + } + + virtual ~ObjectWrap() { + if (persistent().IsEmpty()) + return; + assert(persistent().IsNearDeath()); + persistent().ClearWeak(); + persistent().Dispose(); + } + + + template + static inline T* Unwrap(v8::Handle handle) { + assert(!handle.IsEmpty()); + assert(handle->InternalFieldCount() > 0); + // Cast to ObjectWrap before casting to T. A direct cast from void + // to T won't work right when T has more than one base class. + void* ptr = handle->GetAlignedPointerFromInternalField(0); + ObjectWrap* wrap = static_cast(ptr); + return static_cast(wrap); + } + + + inline v8::Local handle() { + return handle(v8::Isolate::GetCurrent()); + } + + + inline v8::Local handle(v8::Isolate* isolate) { + return v8::Local::New(isolate, persistent()); + } + + + inline v8::Persistent& persistent() { + return handle_; + } + + + protected: + inline void Wrap(v8::Handle handle) { + assert(persistent().IsEmpty()); + assert(handle->InternalFieldCount() > 0); + handle->SetAlignedPointerInInternalField(0, this); + persistent().Reset(v8::Isolate::GetCurrent(), handle); + MakeWeak(); + } + + + inline void MakeWeak(void) { + persistent().MakeWeak(this, WeakCallback); + persistent().MarkIndependent(); + } + + /* Ref() marks the object as being attached to an event loop. + * Refed objects will not be garbage collected, even if + * all references are lost. + */ + virtual void Ref() { + assert(!persistent().IsEmpty()); + persistent().ClearWeak(); + refs_++; + } + + /* Unref() marks an object as detached from the event loop. This is its + * default state. When an object with a "weak" reference changes from + * attached to detached state it will be freed. Be careful not to access + * the object after making this call as it might be gone! + * (A "weak reference" means an object that only has a + * persistant handle.) + * + * DO NOT CALL THIS FROM DESTRUCTOR + */ + virtual void Unref() { + assert(!persistent().IsEmpty()); + assert(!persistent().IsWeak()); + assert(refs_ > 0); + if (--refs_ == 0) + MakeWeak(); + } + + int refs_; // ro + + private: + static void WeakCallback(v8::Isolate* isolate, + v8::Persistent* pobj, + ObjectWrap* wrap) { + v8::HandleScope scope(isolate); + assert(wrap->refs_ == 0); + assert(*pobj == wrap->persistent()); + assert((*pobj).IsNearDeath()); + delete wrap; + } + + v8::Persistent handle_; +}; + + +#endif // v8_OBJECT_WRAP_H_ diff --git a/mapserver-config.h b/mapserver-config.h new file mode 100644 index 0000000000..1099f40609 --- /dev/null +++ b/mapserver-config.h @@ -0,0 +1,64 @@ +#ifndef _MAPSERVER_CONFIG_H +#define _MAPSERVER_CONFIG_H + +#define USE_PROJ 1 +#define USE_POSTGIS 1 +#define USE_GDAL 1 +#define USE_OGR 1 +#define USE_WMS_SVR 1 +#define USE_WCS_SVR 1 +#define USE_WFS_SVR 1 +/* #undef USE_SOS_SVR */ +/* #undef USE_WFS_LYR */ +#define USE_WMS_LYR 1 +#define USE_CURL 1 +#define USE_CAIRO 1 +#define USE_GEOS 1 +#define USE_GIF 1 +#define USE_JPEG 1 +#define USE_PNG 1 +#define USE_ICONV 1 +/* #undef USE_FRIBIDI */ +/* #undef USE_HARFBUZZ */ +#define USE_LIBXML2 1 +#define USE_FASTCGI 1 +/* #undef USE_MYSQL */ +/* #undef USE_THREAD */ +/* #undef USE_KML */ +/* #undef USE_POINT_Z_M */ +/* #undef USE_ORACLESPATIAL */ +/* #undef USE_EXEMPI */ +/* #undef USE_XMLMAPFILE */ +/* #undef USE_GENERIC_MS_NINT */ +#define POSTGIS_HAS_SERVER_VERSION 1 +/* #undef USE_SVG_CAIRO */ +/* #undef USE_RSVG */ +/* #undef USE_SDE */ +/* #undef SDE64 */ +#define USE_EXTENDED_DEBUG 1 +#define USE_V8_MAPSCRIPT 1 + +/*windows specific hacks*/ +#if defined(_WIN32) +/* #undef REGEX_MALLOC */ +/* #undef USE_GENERIC_MS_NINT */ +#endif + + +/* #undef HAVE_STRRSTR */ +#define HAVE_STRCASECMP 1 +#define HAVE_STRCASESTR 1 +#define HAVE_STRDUP 1 +/* #undef HAVE_STRLCAT */ +/* #undef HAVE_STRLCPY */ +#define HAVE_STRLEN 1 +#define HAVE_STRNCASECMP 1 +#define HAVE_VSNPRINTF 1 +#define HAVE_DLFCN_H 1 + +#define HAVE_LRINTF 1 +#define HAVE_LRINT 1 +#define HAVE_SYNC_FETCH_AND_ADD 1 + + +#endif diff --git a/mapserver-config.h.in b/mapserver-config.h.in index 87d8455f8d..d9bfd4f39c 100644 --- a/mapserver-config.h.in +++ b/mapserver-config.h.in @@ -36,7 +36,7 @@ #cmakedefine USE_SDE 1 #cmakedefine SDE64 1 #cmakedefine USE_EXTENDED_DEBUG 1 -#cmakedefine USE_V8 1 +#cmakedefine USE_V8_MAPSCRIPT 1 /*windows specific hacks*/ #if defined(_WIN32) diff --git a/mapserver.h b/mapserver.h index 26dff4f247..dcce00a6f3 100644 --- a/mapserver.h +++ b/mapserver.h @@ -656,7 +656,7 @@ extern "C" { }; enum MS_TOKEN_FUNCTION_ENUM { MS_TOKEN_FUNCTION_LENGTH=340, MS_TOKEN_FUNCTION_TOSTRING, MS_TOKEN_FUNCTION_COMMIFY, MS_TOKEN_FUNCTION_AREA, MS_TOKEN_FUNCTION_ROUND, MS_TOKEN_FUNCTION_FROMTEXT, - MS_TOKEN_FUNCTION_BUFFER, MS_TOKEN_FUNCTION_DIFFERENCE, MS_TOKEN_FUNCTION_SIMPLIFY, MS_TOKEN_FUNCTION_SIMPLIFYPT, MS_TOKEN_FUNCTION_GENERALIZE, MS_TOKEN_FUNCTION_SMOOTHSIA + MS_TOKEN_FUNCTION_BUFFER, MS_TOKEN_FUNCTION_DIFFERENCE, MS_TOKEN_FUNCTION_SIMPLIFY, MS_TOKEN_FUNCTION_SIMPLIFYPT, MS_TOKEN_FUNCTION_GENERALIZE, MS_TOKEN_FUNCTION_SMOOTHSIA, MS_TOKEN_FUNCTION_JAVASCRIPT }; enum MS_TOKEN_BINDING_ENUM { MS_TOKEN_BINDING_DOUBLE=360, MS_TOKEN_BINDING_INTEGER, MS_TOKEN_BINDING_STRING, MS_TOKEN_BINDING_TIME, MS_TOKEN_BINDING_SHAPE, MS_TOKEN_BINDING_MAP_CELLSIZE, MS_TOKEN_BINDING_DATA_CELLSIZE }; enum MS_PARSE_TYPE_ENUM { MS_PARSE_TYPE_BOOLEAN, MS_PARSE_TYPE_STRING, MS_PARSE_TYPE_SHAPE }; @@ -1825,7 +1825,7 @@ void msPopulateTextSymbolForLabelAndString(textSymbolObj *ts, labelObj *l, char queryObj query; #endif -#ifdef USE_V8 +#ifdef USE_V8_MAPSCRIPT void *v8context; #endif }; @@ -2792,11 +2792,14 @@ void msPopulateTextSymbolForLabelAndString(textSymbolObj *ts, labelObj *l, char /* ==================================================================== */ /* prototypes for functions in mapv8.cpp */ /* ==================================================================== */ -#ifdef USE_V8 - MS_DLL_EXPORT char* msV8GetFeatureStyle(mapObj *map, const char *filename, - layerObj *layer, shapeObj *shape); +#ifdef USE_V8_MAPSCRIPT MS_DLL_EXPORT void msV8CreateContext(mapObj *map); + MS_DLL_EXPORT void msV8ContextSetLayer(mapObj *map, layerObj *layer); MS_DLL_EXPORT void msV8FreeContext(mapObj *map); + MS_DLL_EXPORT char* msV8GetFeatureStyle(mapObj *map, const char *filename, + layerObj *layer, shapeObj *shape); + MS_DLL_EXPORT shapeObj *msV8TransformShape(shapeObj *shape, + const char* filename); #endif /* ==================================================================== */ /* end of prototypes for functions in mapv8.cpp */ diff --git a/mapv8.cpp b/mapv8.cpp index 2d80af7c85..5bb5118a89 100644 --- a/mapv8.cpp +++ b/mapv8.cpp @@ -27,118 +27,13 @@ **********************************************************************/ #include "mapserver-config.h" -#ifdef USE_V8 +#ifdef USE_V8_MAPSCRIPT #include "mapserver.h" -#include -#include -#include -#include - -using std::string; -using std::stack; -using v8::Isolate; -using v8::Context; -using v8::Persistent; -using v8::HandleScope; -using v8::Handle; -using v8::Script; -using v8::Local; -using v8::Object; -using v8::Value; -using v8::String; -using v8::Integer; -using v8::Undefined; -using v8::FunctionTemplate; -using v8::ObjectTemplate; -using v8::AccessorInfo; -using v8::External; -using v8::Arguments; -using v8::TryCatch; -using v8::Message; -using v8::ThrowException; - -class V8Context -{ -public: - V8Context(Isolate *isolate) - : isolate(isolate) {} - Isolate *isolate; - stack paths; /* for relative paths and the require function */ - Persistent context; -}; - -#define V8CONTEXT(map) ((V8Context*) (map)->v8context) - -/* MAPSERVER OBJECT WRAPPERS */ - -/* This is currently only an example how to wrap a C object to expose it to - * JavaScript. This needs to be investigated more if we decide to create a - * complete MS object binding for v8. */ - -static void msV8WeakShapeObjCallback(Isolate *isolate, Persistent *object, shapeObj *shape) -{ - msFreeShape(shape); - object->Dispose(); - object->Clear(); -} - -static Handle msV8ShapeObjGetNumValues(Local property, - const AccessorInfo &info) -{ - Local self = info.Holder(); - Local wrap = Local::Cast(self->GetInternalField(0)); - void *ptr = wrap->Value(); - shapeObj *shape = static_cast(ptr); - return Integer::New(shape->numvalues); -} - -/* Simple shape object wrapper. Maybe we could create a generic template class - * that would handle that stuff */ -static Handle msV8WrapShapeObj(Isolate *isolate, layerObj *layer, shapeObj *shape, Persistent *po) -{ - Handle shape_templ = ObjectTemplate::New(); - shape_templ->SetInternalFieldCount(1); - - /* accessor example */ - shape_templ->SetAccessor(String::New("numvalues"), msV8ShapeObjGetNumValues); - - /* both accessor and direct object have their pros/cons for this - * case. Currently ok since it's read-only */ - Handle attributes = ObjectTemplate::New(); - for (int i=0; inumitems; ++i) { - attributes->Set(String::New(layer->items[i]), - String::New(shape->values[i])); - } - shape_templ->Set(String::New("attributes"), attributes); - - Handle obj = shape_templ->NewInstance(); - obj->SetInternalField(0, External::New(shape)); - - if (po) { /* A Persistent object have to be passed if v8 have to free some memory */ - po->Reset(isolate, obj); - po->MakeWeak(shape, msV8WeakShapeObjCallback); - } - - return obj; -} - -/* END OF MAPSERVER OBJECT WRAPPERS */ +#include "v8_mapscript.h" -/* INTERNAL JAVASCRIPT FUNCTIONS */ - -/* Get C char from a v8 string. Caller has to free the returned value. */ -// static char *msV8GetCString(Local value, const char *fallback = "") { -// if (value->IsString()) { -// String::AsciiValue string(value); -// char *str = (char *) malloc(string.length() + 1); -// strcpy(str, *string); -// return str; -// } -// char *str = (char *) malloc(strlen(fallback) + 1); -// strcpy(str, fallback); -// return str; -// } +/* This file could be refactored in the future to encapsulate the global + functions and internal use functions in a class. */ /* Handler for Javascript Exceptions. Not exposed to JavaScript, used internally. Most of the code from v8 shell example. @@ -178,16 +73,8 @@ void msV8ReportException(TryCatch* try_catch, const char *msg = "") } /* This function load a javascript file in memory. */ -static Handle msV8ReadFile(V8Context *v8context, const char *name) +static Handle msV8ReadFile(V8Context *v8context, const char *path) { - char path[MS_MAXPATHLEN]; - - /* construct the path */ - msBuildPath(path, v8context->paths.top().c_str(), name); - char *filepath = msGetPath(path); - v8context->paths.push(filepath); - free(filepath); - FILE* file = fopen(path, "rb"); if (file == NULL) { char err[MS_MAXPATHLEN+21]; @@ -204,6 +91,10 @@ static Handle msV8ReadFile(V8Context *v8context, const char *name) chars[size] = '\0'; for (int i = 0; i < size;) { int read = static_cast(fread(&chars[i], 1, size - i, file)); + if (read == 0) { + msDebug("msV8ReadFile: error while reading file '%s'\n", path); + return Undefined(); + } i += read; } @@ -252,17 +143,35 @@ static Handle msV8RunScript(Handle