| OLD | NEW | 
|---|
| 1 | 1 | 
| 2 /* | 2 /* | 
| 3  * Copyright 2013 Google Inc. | 3  * Copyright 2013 Google Inc. | 
| 4  * | 4  * | 
| 5  * | 5  * | 
| 6  * Use of this source code is governed by a BSD-style license that can be | 6  * Use of this source code is governed by a BSD-style license that can be | 
| 7  * found in the LICENSE file. | 7  * found in the LICENSE file. | 
| 8  * | 8  * | 
| 9  */ | 9  */ | 
| 10 #include <v8.h> | 10 #include <v8.h> | 
| 11 | 11 | 
| 12 using namespace v8; | 12 using namespace v8; | 
| 13 | 13 | 
| 14 #include "Global.h" | 14 #include "Global.h" | 
| 15 #include "JsContext.h" | 15 #include "JsContext.h" | 
| 16 #include "Path2D.h" | 16 #include "Path2D.h" | 
| 17 #include "SkCanvas.h" | 17 #include "SkCanvas.h" | 
| 18 | 18 | 
| 19 | 19 | 
| 20 // Extracts a C string from a V8 Utf8Value. | 20 // Extracts a C string from a V8 Utf8Value. | 
| 21 // TODO(jcgregrio) Currently dup'd in two files, fix. | 21 // TODO(jcgregrio) Currently dup'd in two files, fix. | 
| 22 static const char* to_cstring(const v8::String::Utf8Value& value) { | 22 static const char* to_cstring(const v8::String::Utf8Value& value) { | 
| 23     return *value ? *value : "<string conversion failed>"; | 23     return *value ? *value : "<string conversion failed>"; | 
| 24 } | 24 } | 
| 25 | 25 | 
| 26 JsContext* JsContext::Unwrap(Handle<Object> obj) { |  | 
| 27     Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0)); |  | 
| 28     void* ptr = field->Value(); |  | 
| 29     return static_cast<JsContext*>(ptr); |  | 
| 30 } |  | 
| 31 |  | 
| 32 void JsContext::FillRect(const v8::FunctionCallbackInfo<Value>& args) { |  | 
| 33     JsContext* jsContext = Unwrap(args.This()); |  | 
| 34     SkCanvas* canvas = jsContext->fCanvas; |  | 
| 35 |  | 
| 36     if (args.Length() != 4) { |  | 
| 37         args.GetIsolate()->ThrowException( |  | 
| 38                 v8::String::NewFromUtf8( |  | 
| 39                         args.GetIsolate(), "Error: 4 arguments required.")); |  | 
| 40         return; |  | 
| 41     } |  | 
| 42     // TODO(jcgregorio) Really figure out the conversion from JS numbers to |  | 
| 43     // SkScalars. Maybe test if int first? Not sure of the performance impact. |  | 
| 44     double x = args[0]->NumberValue(); |  | 
| 45     double y = args[1]->NumberValue(); |  | 
| 46     double w = args[2]->NumberValue(); |  | 
| 47     double h = args[3]->NumberValue(); |  | 
| 48 |  | 
| 49     SkRect rect = { |  | 
| 50         SkDoubleToScalar(x), |  | 
| 51         SkDoubleToScalar(y), |  | 
| 52         SkDoubleToScalar(x) + SkDoubleToScalar(w), |  | 
| 53         SkDoubleToScalar(y) + SkDoubleToScalar(h) |  | 
| 54     }; |  | 
| 55     canvas->drawRect(rect, jsContext->fFillStyle); |  | 
| 56 } |  | 
| 57 |  | 
| 58 void JsContext::Save(const v8::FunctionCallbackInfo<Value>& args) { |  | 
| 59     JsContext* jsContext = Unwrap(args.This()); |  | 
| 60     SkCanvas* canvas = jsContext->fCanvas; |  | 
| 61 |  | 
| 62     canvas->save(); |  | 
| 63 } |  | 
| 64 |  | 
| 65 void JsContext::Restore(const v8::FunctionCallbackInfo<Value>& args) { |  | 
| 66     JsContext* jsContext = Unwrap(args.This()); |  | 
| 67     SkCanvas* canvas = jsContext->fCanvas; |  | 
| 68 |  | 
| 69     canvas->restore(); |  | 
| 70 } |  | 
| 71 |  | 
| 72 void JsContext::Rotate(const v8::FunctionCallbackInfo<Value>& args) { |  | 
| 73     JsContext* jsContext = Unwrap(args.This()); |  | 
| 74     SkCanvas* canvas = jsContext->fCanvas; |  | 
| 75 |  | 
| 76     if (args.Length() != 1) { |  | 
| 77         args.GetIsolate()->ThrowException( |  | 
| 78                 v8::String::NewFromUtf8( |  | 
| 79                         args.GetIsolate(), "Error: 1 arguments required.")); |  | 
| 80         return; |  | 
| 81     } |  | 
| 82     double angle = args[0]->NumberValue(); |  | 
| 83     canvas->rotate(SkRadiansToDegrees(angle)); |  | 
| 84 } |  | 
| 85 |  | 
| 86 void JsContext::Translate(const v8::FunctionCallbackInfo<Value>& args) { |  | 
| 87     JsContext* jsContext = Unwrap(args.This()); |  | 
| 88     SkCanvas* canvas = jsContext->fCanvas; |  | 
| 89 |  | 
| 90     if (args.Length() != 2) { |  | 
| 91         args.GetIsolate()->ThrowException( |  | 
| 92                 v8::String::NewFromUtf8( |  | 
| 93                         args.GetIsolate(), "Error: 2 arguments required.")); |  | 
| 94         return; |  | 
| 95     } |  | 
| 96     double dx = args[0]->NumberValue(); |  | 
| 97     double dy = args[1]->NumberValue(); |  | 
| 98     canvas->translate(SkDoubleToScalar(dx), SkDoubleToScalar(dy)); |  | 
| 99 } |  | 
| 100 |  | 
| 101 void JsContext::ResetTransform(const v8::FunctionCallbackInfo<Value>& args) { |  | 
| 102     JsContext* jsContext = Unwrap(args.This()); |  | 
| 103     SkCanvas* canvas = jsContext->fCanvas; |  | 
| 104 |  | 
| 105     canvas->resetMatrix(); |  | 
| 106 } |  | 
| 107 |  | 
| 108 void JsContext::Stroke(const v8::FunctionCallbackInfo<Value>& args) { |  | 
| 109     JsContext* jsContext = Unwrap(args.This()); |  | 
| 110     SkCanvas* canvas = jsContext->fCanvas; |  | 
| 111 |  | 
| 112     if (args.Length() != 1) { |  | 
| 113         args.GetIsolate()->ThrowException( |  | 
| 114                 v8::String::NewFromUtf8( |  | 
| 115                         args.GetIsolate(), "Error: 1 arguments required.")); |  | 
| 116         return; |  | 
| 117     } |  | 
| 118 |  | 
| 119     Handle<External> field = Handle<External>::Cast( |  | 
| 120             args[0]->ToObject()->GetInternalField(0)); |  | 
| 121     void* ptr = field->Value(); |  | 
| 122     Path2D* path = static_cast<Path2D*>(ptr); |  | 
| 123 |  | 
| 124     canvas->drawPath(path->getSkPath(), jsContext->fStrokeStyle); |  | 
| 125 } |  | 
| 126 |  | 
| 127 void JsContext::Fill(const v8::FunctionCallbackInfo<Value>& args) { |  | 
| 128     JsContext* jsContext = Unwrap(args.This()); |  | 
| 129     SkCanvas* canvas = jsContext->fCanvas; |  | 
| 130 |  | 
| 131     if (args.Length() != 1) { |  | 
| 132         args.GetIsolate()->ThrowException( |  | 
| 133                 v8::String::NewFromUtf8( |  | 
| 134                         args.GetIsolate(), "Error: 1 arguments required.")); |  | 
| 135         return; |  | 
| 136     } |  | 
| 137 |  | 
| 138     Handle<External> field = Handle<External>::Cast( |  | 
| 139             args[0]->ToObject()->GetInternalField(0)); |  | 
| 140     void* ptr = field->Value(); |  | 
| 141     Path2D* path = static_cast<Path2D*>(ptr); |  | 
| 142 |  | 
| 143     canvas->drawPath(path->getSkPath(), jsContext->fFillStyle); |  | 
| 144 } |  | 
| 145 |  | 
| 146 void JsContext::GetStyle(Local<String> name, |  | 
| 147                          const PropertyCallbackInfo<Value>& info, |  | 
| 148                          const SkPaint& style) { |  | 
| 149     char buf[8]; |  | 
| 150     SkColor color = style.getColor(); |  | 
| 151     sprintf(buf, "#%02X%02X%02X", SkColorGetR(color), SkColorGetG(color), |  | 
| 152             SkColorGetB(color)); |  | 
| 153 |  | 
| 154     info.GetReturnValue().Set(String::NewFromUtf8(info.GetIsolate(), buf)); |  | 
| 155 } |  | 
| 156 |  | 
| 157 void JsContext::SetStyle(Local<String> name, Local<Value> value, |  | 
| 158                          const PropertyCallbackInfo<void>& info, |  | 
| 159                          SkPaint& style) { |  | 
| 160     Local<String> s = value->ToString(); |  | 
| 161     if (s->Length() != 7 && s->Length() != 9) { |  | 
| 162         info.GetIsolate()->ThrowException( |  | 
| 163                 v8::String::NewFromUtf8( |  | 
| 164                         info.GetIsolate(), |  | 
| 165                         "Invalid fill style format length.")); |  | 
| 166         return; |  | 
| 167     } |  | 
| 168     char buf[10]; |  | 
| 169     s->WriteUtf8(buf, sizeof(buf)); |  | 
| 170 |  | 
| 171     if (buf[0] != '#') { |  | 
| 172         info.GetIsolate()->ThrowException( |  | 
| 173                 v8::String::NewFromUtf8( |  | 
| 174                         info.GetIsolate(), "Invalid fill style format.")); |  | 
| 175         return; |  | 
| 176     } |  | 
| 177 |  | 
| 178     // Colors can be RRGGBBAA, but SkColor uses ARGB. |  | 
| 179     long color = strtol(buf+1, NULL, 16); |  | 
| 180     uint32_t alpha = SK_AlphaOPAQUE; |  | 
| 181     if (s->Length() == 9) { |  | 
| 182         alpha = color & 0xFF; |  | 
| 183         color >>= 8; |  | 
| 184     } |  | 
| 185     style.setColor(SkColorSetA(SkColor(color), alpha)); |  | 
| 186 } |  | 
| 187 |  | 
| 188 void JsContext::GetFillStyle(Local<String> name, |  | 
| 189                              const PropertyCallbackInfo<Value>& info) { |  | 
| 190     JsContext* jsContext = Unwrap(info.This()); |  | 
| 191     GetStyle(name, info, jsContext->fFillStyle); |  | 
| 192 } |  | 
| 193 |  | 
| 194 void JsContext::GetStrokeStyle(Local<String> name, |  | 
| 195                                const PropertyCallbackInfo<Value>& info) { |  | 
| 196     JsContext* jsContext = Unwrap(info.This()); |  | 
| 197     GetStyle(name, info, jsContext->fStrokeStyle); |  | 
| 198 } |  | 
| 199 |  | 
| 200 void JsContext::SetFillStyle(Local<String> name, Local<Value> value, |  | 
| 201                             const PropertyCallbackInfo<void>& info) { |  | 
| 202     JsContext* jsContext = Unwrap(info.This()); |  | 
| 203     SetStyle(name, value, info, jsContext->fFillStyle); |  | 
| 204 } |  | 
| 205 |  | 
| 206 void JsContext::SetStrokeStyle(Local<String> name, Local<Value> value, |  | 
| 207                                const PropertyCallbackInfo<void>& info) { |  | 
| 208     JsContext* jsContext = Unwrap(info.This()); |  | 
| 209     SetStyle(name, value, info, jsContext->fStrokeStyle); |  | 
| 210 } |  | 
| 211 |  | 
| 212 |  | 
| 213 void JsContext::GetWidth(Local<String> name, |  | 
| 214                          const PropertyCallbackInfo<Value>& info) { |  | 
| 215     JsContext* jsContext = Unwrap(info.This()); |  | 
| 216     SkISize size = jsContext->fCanvas->getDeviceSize(); |  | 
| 217 |  | 
| 218     info.GetReturnValue().Set( |  | 
| 219             Int32::New(jsContext->fGlobal->getIsolate(), size.fWidth)); |  | 
| 220 } |  | 
| 221 |  | 
| 222 void JsContext::GetHeight(Local<String> name, |  | 
| 223                          const PropertyCallbackInfo<Value>& info) { |  | 
| 224     JsContext* jsContext = Unwrap(info.This()); |  | 
| 225     SkISize size = jsContext->fCanvas->getDeviceSize(); |  | 
| 226 |  | 
| 227     info.GetReturnValue().Set( |  | 
| 228             Int32::New(jsContext->fGlobal->getIsolate(), size.fHeight)); |  | 
| 229 } |  | 
| 230 |  | 
| 231 |  | 
| 232 Persistent<ObjectTemplate> JsContext::gContextTemplate; | 26 Persistent<ObjectTemplate> JsContext::gContextTemplate; | 
| 233 | 27 | 
| 234 #define ADD_METHOD(name, fn) \ |  | 
| 235     result->Set(String::NewFromUtf8( \ |  | 
| 236             fGlobal->getIsolate(), name, \ |  | 
| 237             String::kInternalizedString), \ |  | 
| 238                 FunctionTemplate::New(fGlobal->getIsolate(), fn)) |  | 
| 239 |  | 
| 240 Handle<ObjectTemplate> JsContext::makeContextTemplate() { |  | 
| 241     EscapableHandleScope handleScope(fGlobal->getIsolate()); |  | 
| 242 |  | 
| 243     Local<ObjectTemplate> result = ObjectTemplate::New(); |  | 
| 244 |  | 
| 245     // Add a field to store the pointer to a JsContext instance. |  | 
| 246     result->SetInternalFieldCount(1); |  | 
| 247 |  | 
| 248     // Add accessors for each of the fields of the context object. |  | 
| 249     result->SetAccessor(String::NewFromUtf8( |  | 
| 250             fGlobal->getIsolate(), "fillStyle", String::kInternalizedString), |  | 
| 251                         GetFillStyle, SetFillStyle); |  | 
| 252     result->SetAccessor(String::NewFromUtf8( |  | 
| 253             fGlobal->getIsolate(), "strokeStyle", String::kInternalizedString), |  | 
| 254                         GetStrokeStyle, SetStrokeStyle); |  | 
| 255     result->SetAccessor(String::NewFromUtf8( |  | 
| 256             fGlobal->getIsolate(), "width", String::kInternalizedString), |  | 
| 257                         GetWidth); |  | 
| 258     result->SetAccessor(String::NewFromUtf8( |  | 
| 259             fGlobal->getIsolate(), "height", String::kInternalizedString), |  | 
| 260                         GetHeight); |  | 
| 261 |  | 
| 262     // Add methods. |  | 
| 263     ADD_METHOD("fillRect", FillRect); |  | 
| 264     ADD_METHOD("stroke", Stroke); |  | 
| 265     ADD_METHOD("fill", Fill); |  | 
| 266     ADD_METHOD("rotate", Rotate); |  | 
| 267     ADD_METHOD("save", Save); |  | 
| 268     ADD_METHOD("restore", Restore); |  | 
| 269     ADD_METHOD("translate", Translate); |  | 
| 270     ADD_METHOD("resetTransform", ResetTransform); |  | 
| 271 |  | 
| 272     // Return the result through the current handle scope. |  | 
| 273     return handleScope.Escape(result); |  | 
| 274 } |  | 
| 275 |  | 
| 276 |  | 
| 277 // Wraps 'this' in a Javascript object. | 28 // Wraps 'this' in a Javascript object. | 
| 278 Handle<Object> JsContext::wrap() { | 29 Handle<Object> JsContext::wrap() { | 
| 279     // Handle scope for temporary handles. | 30     // Handle scope for temporary handles. | 
| 280     EscapableHandleScope handleScope(fGlobal->getIsolate()); | 31     EscapableHandleScope handleScope(fGlobal->getIsolate()); | 
| 281 | 32 | 
| 282     // Fetch the template for creating JavaScript JsContext wrappers. | 33     // Fetch the template for creating JavaScript JsContext wrappers. | 
| 283     // It only has to be created once, which we do on demand. | 34     // It only has to be created once, which we do on demand. | 
| 284     if (gContextTemplate.IsEmpty()) { | 35     if (gContextTemplate.IsEmpty()) { | 
| 285         Handle<ObjectTemplate> raw_template = this->makeContextTemplate(); | 36         Local<ObjectTemplate> localTemplate = ObjectTemplate::New(); | 
| 286         gContextTemplate.Reset(fGlobal->getIsolate(), raw_template); | 37 | 
|  | 38         // Add a field to store the pointer to a JsContext instance. | 
|  | 39         localTemplate->SetInternalFieldCount(1); | 
|  | 40 | 
|  | 41         this->addAttributesAndMethods(localTemplate); | 
|  | 42 | 
|  | 43         gContextTemplate.Reset(fGlobal->getIsolate(), localTemplate); | 
| 287     } | 44     } | 
| 288     Handle<ObjectTemplate> templ = | 45     Handle<ObjectTemplate> templ = | 
| 289             Local<ObjectTemplate>::New(fGlobal->getIsolate(), gContextTemplate); | 46             Local<ObjectTemplate>::New(fGlobal->getIsolate(), gContextTemplate); | 
| 290 | 47 | 
| 291     // Create an empty JsContext wrapper. | 48     // Create an empty JsContext wrapper. | 
| 292     Local<Object> result = templ->NewInstance(); | 49     Local<Object> result = templ->NewInstance(); | 
| 293 | 50 | 
| 294     // Wrap the raw C++ pointer in an External so it can be referenced | 51     // Wrap the raw C++ pointer in an External so it can be referenced | 
| 295     // from within JavaScript. | 52     // from within JavaScript. | 
| 296     Handle<External> contextPtr = External::New(fGlobal->getIsolate(), this); | 53     Handle<External> contextPtr = External::New(fGlobal->getIsolate(), this); | 
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 374 | 131 | 
| 375     // It is a function; cast it to a Function. | 132     // It is a function; cast it to a Function. | 
| 376     Handle<Function> fn_fun = Handle<Function>::Cast(fn_val); | 133     Handle<Function> fn_fun = Handle<Function>::Cast(fn_val); | 
| 377 | 134 | 
| 378     // Store the function in a Persistent handle, since we also want that to | 135     // Store the function in a Persistent handle, since we also want that to | 
| 379     // remain after this call returns. | 136     // remain after this call returns. | 
| 380     fOnDraw.Reset(fGlobal->getIsolate(), fn_fun); | 137     fOnDraw.Reset(fGlobal->getIsolate(), fn_fun); | 
| 381 | 138 | 
| 382     return true; | 139     return true; | 
| 383 } | 140 } | 
| OLD | NEW | 
|---|