John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 1 | // Copyright 2014 PDFium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
Lei Zhang | a6d9f0e | 2015-06-13 00:48:38 -0700 | [diff] [blame] | 4 | |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 5 | // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| 6 | |
Dan Sinclair | e0345a4 | 2017-10-30 20:20:42 +0000 | [diff] [blame] | 7 | #ifndef FXJS_JS_DEFINE_H_ |
| 8 | #define FXJS_JS_DEFINE_H_ |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 9 | |
Dan Sinclair | 3ebd121 | 2016-03-09 09:59:23 -0500 | [diff] [blame] | 10 | #include <vector> |
| 11 | |
Tom Sepez | 82999fa | 2018-07-16 22:17:46 +0000 | [diff] [blame] | 12 | #include "core/fxcrt/unowned_ptr.h" |
Tom Sepez | b7c7df6 | 2018-02-09 19:08:59 +0000 | [diff] [blame] | 13 | #include "fxjs/cfxjs_engine.h" |
Tom Sepez | 3a6d058 | 2018-08-17 19:28:52 +0000 | [diff] [blame] | 14 | #include "fxjs/cjs_result.h" |
Lei Zhang | 31beedc | 2018-10-18 21:09:55 +0000 | [diff] [blame] | 15 | #include "fxjs/cjs_runtime.h" |
Dan Sinclair | e0345a4 | 2017-10-30 20:20:42 +0000 | [diff] [blame] | 16 | #include "fxjs/js_resources.h" |
Tom Sepez | 2108e57 | 2018-01-30 20:15:10 +0000 | [diff] [blame] | 17 | #include "third_party/base/ptr_util.h" |
Tom Sepez | a116045 | 2015-02-19 10:00:55 -0800 | [diff] [blame] | 18 | |
Lei Zhang | 31beedc | 2018-10-18 21:09:55 +0000 | [diff] [blame] | 19 | class CJS_Object; |
| 20 | |
Dan Sinclair | a146507 | 2017-10-30 17:05:31 +0000 | [diff] [blame] | 21 | double JS_DateParse(const WideString& str); |
Dan Sinclair | a146507 | 2017-10-30 17:05:31 +0000 | [diff] [blame] | 22 | |
| 23 | // Some JS methods have the bizarre convention that they may also be called |
| 24 | // with a single argument which is an object containing the actual arguments |
| 25 | // as its properties. The varying arguments to this method are the property |
| 26 | // names as wchar_t string literals corresponding to each positional argument. |
Tom Sepez | 0e5bab1 | 2018-10-18 21:39:40 +0000 | [diff] [blame] | 27 | // The result will always contain |nKeywords| value, check for the unspecified |
| 28 | // ones in the result using IsExpandedParamKnown() below. |
Dan Sinclair | a146507 | 2017-10-30 17:05:31 +0000 | [diff] [blame] | 29 | std::vector<v8::Local<v8::Value>> ExpandKeywordParams( |
| 30 | CJS_Runtime* pRuntime, |
| 31 | const std::vector<v8::Local<v8::Value>>& originals, |
| 32 | size_t nKeywords, |
| 33 | ...); |
| 34 | |
Tom Sepez | 0e5bab1 | 2018-10-18 21:39:40 +0000 | [diff] [blame] | 35 | bool IsExpandedParamKnown(v8::Local<v8::Value> value); |
| 36 | |
Dan Sinclair | 89d26c8 | 2017-10-26 12:21:28 -0400 | [diff] [blame] | 37 | // All JS classes have a name, an object defintion ID, and the ability to |
| 38 | // register themselves with FXJS_V8. We never make a BASE class on its own |
| 39 | // because it can't really do anything. |
| 40 | |
| 41 | // Rich JS classes provide constants, methods, properties, and the ability |
| 42 | // to construct native object state. |
| 43 | |
Dan Sinclair | 998fee3 | 2018-02-05 21:43:19 +0000 | [diff] [blame] | 44 | template <class T> |
Dan Sinclair | d808dfd | 2017-10-26 15:04:17 -0400 | [diff] [blame] | 45 | static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj) { |
Tom Sepez | 83b259e | 2018-06-08 20:43:55 +0000 | [diff] [blame] | 46 | pEngine->SetObjectPrivate( |
| 47 | obj, pdfium::MakeUnique<T>(obj, static_cast<CJS_Runtime*>(pEngine))); |
Dan Sinclair | d808dfd | 2017-10-26 15:04:17 -0400 | [diff] [blame] | 48 | } |
Tom Sepez | 04557b8 | 2017-02-16 09:43:10 -0800 | [diff] [blame] | 49 | |
Lei Zhang | b1a4db5 | 2018-07-11 13:02:54 +0000 | [diff] [blame] | 50 | // CJS_Object has virtual dtor, template not required. |
Tom Sepez | b3f1046 | 2018-02-08 20:16:09 +0000 | [diff] [blame] | 51 | void JSDestructor(v8::Local<v8::Object> obj); |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 52 | |
Lei Zhang | ad1f7b4 | 2018-07-11 13:04:43 +0000 | [diff] [blame] | 53 | template <class C> |
Tom Sepez | 82999fa | 2018-07-16 22:17:46 +0000 | [diff] [blame] | 54 | UnownedPtr<C> JSGetObject(v8::Local<v8::Object> obj) { |
Lei Zhang | ad1f7b4 | 2018-07-11 13:04:43 +0000 | [diff] [blame] | 55 | if (CFXJS_Engine::GetObjDefnID(obj) != C::GetObjDefnID()) |
| 56 | return nullptr; |
| 57 | |
| 58 | CJS_Object* pJSObj = CFXJS_Engine::GetObjectPrivate(obj); |
| 59 | if (!pJSObj) |
| 60 | return nullptr; |
| 61 | |
Tom Sepez | 82999fa | 2018-07-16 22:17:46 +0000 | [diff] [blame] | 62 | return UnownedPtr<C>(static_cast<C*>(pJSObj)); |
Lei Zhang | ad1f7b4 | 2018-07-11 13:04:43 +0000 | [diff] [blame] | 63 | } |
| 64 | |
Tom Sepez | 3a6d058 | 2018-08-17 19:28:52 +0000 | [diff] [blame] | 65 | template <class C, CJS_Result (C::*M)(CJS_Runtime*)> |
Tom Sepez | a116045 | 2015-02-19 10:00:55 -0800 | [diff] [blame] | 66 | void JSPropGetter(const char* prop_name_string, |
| 67 | const char* class_name_string, |
| 68 | v8::Local<v8::String> property, |
| 69 | const v8::PropertyCallbackInfo<v8::Value>& info) { |
Tom Sepez | 82999fa | 2018-07-16 22:17:46 +0000 | [diff] [blame] | 70 | auto pObj = JSGetObject<C>(info.Holder()); |
Lei Zhang | ad1f7b4 | 2018-07-11 13:04:43 +0000 | [diff] [blame] | 71 | if (!pObj) |
Tom Sepez | a25fd09 | 2015-09-28 09:06:03 -0700 | [diff] [blame] | 72 | return; |
dan sinclair | cbe23db | 2017-10-19 14:29:33 -0400 | [diff] [blame] | 73 | |
Lei Zhang | ad1f7b4 | 2018-07-11 13:04:43 +0000 | [diff] [blame] | 74 | CJS_Runtime* pRuntime = pObj->GetRuntime(); |
Tom Sepez | ddaa40f | 2018-06-06 18:30:15 +0000 | [diff] [blame] | 75 | if (!pRuntime) |
Tom Sepez | c5a1472 | 2017-02-24 15:31:12 -0800 | [diff] [blame] | 76 | return; |
dan sinclair | cbe23db | 2017-10-19 14:29:33 -0400 | [diff] [blame] | 77 | |
Tom Sepez | 3a6d058 | 2018-08-17 19:28:52 +0000 | [diff] [blame] | 78 | CJS_Result result = (pObj.Get()->*M)(pRuntime); |
Dan Sinclair | 8f524d6 | 2017-10-25 13:30:31 -0400 | [diff] [blame] | 79 | if (result.HasError()) { |
| 80 | pRuntime->Error(JSFormatErrorString(class_name_string, prop_name_string, |
| 81 | result.Error())); |
Tom Sepez | a116045 | 2015-02-19 10:00:55 -0800 | [diff] [blame] | 82 | return; |
| 83 | } |
Dan Sinclair | 8f524d6 | 2017-10-25 13:30:31 -0400 | [diff] [blame] | 84 | |
| 85 | if (result.HasReturn()) |
| 86 | info.GetReturnValue().Set(result.Return()); |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 87 | } |
| 88 | |
Tom Sepez | 3a6d058 | 2018-08-17 19:28:52 +0000 | [diff] [blame] | 89 | template <class C, CJS_Result (C::*M)(CJS_Runtime*, v8::Local<v8::Value>)> |
Tom Sepez | a116045 | 2015-02-19 10:00:55 -0800 | [diff] [blame] | 90 | void JSPropSetter(const char* prop_name_string, |
| 91 | const char* class_name_string, |
| 92 | v8::Local<v8::String> property, |
| 93 | v8::Local<v8::Value> value, |
| 94 | const v8::PropertyCallbackInfo<void>& info) { |
Tom Sepez | 82999fa | 2018-07-16 22:17:46 +0000 | [diff] [blame] | 95 | auto pObj = JSGetObject<C>(info.Holder()); |
Lei Zhang | ad1f7b4 | 2018-07-11 13:04:43 +0000 | [diff] [blame] | 96 | if (!pObj) |
Tom Sepez | a25fd09 | 2015-09-28 09:06:03 -0700 | [diff] [blame] | 97 | return; |
dan sinclair | cbe23db | 2017-10-19 14:29:33 -0400 | [diff] [blame] | 98 | |
Lei Zhang | ad1f7b4 | 2018-07-11 13:04:43 +0000 | [diff] [blame] | 99 | CJS_Runtime* pRuntime = pObj->GetRuntime(); |
Tom Sepez | ddaa40f | 2018-06-06 18:30:15 +0000 | [diff] [blame] | 100 | if (!pRuntime) |
Tom Sepez | c5a1472 | 2017-02-24 15:31:12 -0800 | [diff] [blame] | 101 | return; |
dan sinclair | cbe23db | 2017-10-19 14:29:33 -0400 | [diff] [blame] | 102 | |
Tom Sepez | 3a6d058 | 2018-08-17 19:28:52 +0000 | [diff] [blame] | 103 | CJS_Result result = (pObj.Get()->*M)(pRuntime, value); |
Dan Sinclair | 8f524d6 | 2017-10-25 13:30:31 -0400 | [diff] [blame] | 104 | if (result.HasError()) { |
| 105 | pRuntime->Error(JSFormatErrorString(class_name_string, prop_name_string, |
| 106 | result.Error())); |
Tom Sepez | a116045 | 2015-02-19 10:00:55 -0800 | [diff] [blame] | 107 | } |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 108 | } |
| 109 | |
Nico Weber | 9d8ec5a | 2015-08-04 13:00:21 -0700 | [diff] [blame] | 110 | template <class C, |
Tom Sepez | 3a6d058 | 2018-08-17 19:28:52 +0000 | [diff] [blame] | 111 | CJS_Result (C::*M)(CJS_Runtime*, |
Dan Sinclair | 8f524d6 | 2017-10-25 13:30:31 -0400 | [diff] [blame] | 112 | const std::vector<v8::Local<v8::Value>>&)> |
Tom Sepez | a116045 | 2015-02-19 10:00:55 -0800 | [diff] [blame] | 113 | void JSMethod(const char* method_name_string, |
| 114 | const char* class_name_string, |
| 115 | const v8::FunctionCallbackInfo<v8::Value>& info) { |
Tom Sepez | 82999fa | 2018-07-16 22:17:46 +0000 | [diff] [blame] | 116 | auto pObj = JSGetObject<C>(info.Holder()); |
Lei Zhang | ad1f7b4 | 2018-07-11 13:04:43 +0000 | [diff] [blame] | 117 | if (!pObj) |
Tom Sepez | a25fd09 | 2015-09-28 09:06:03 -0700 | [diff] [blame] | 118 | return; |
Dan Sinclair | e497492 | 2017-10-24 09:36:16 -0400 | [diff] [blame] | 119 | |
Lei Zhang | ad1f7b4 | 2018-07-11 13:04:43 +0000 | [diff] [blame] | 120 | CJS_Runtime* pRuntime = pObj->GetRuntime(); |
Tom Sepez | ddaa40f | 2018-06-06 18:30:15 +0000 | [diff] [blame] | 121 | if (!pRuntime) |
Tom Sepez | c5a1472 | 2017-02-24 15:31:12 -0800 | [diff] [blame] | 122 | return; |
Dan Sinclair | e497492 | 2017-10-24 09:36:16 -0400 | [diff] [blame] | 123 | |
Dan Sinclair | 8f524d6 | 2017-10-25 13:30:31 -0400 | [diff] [blame] | 124 | std::vector<v8::Local<v8::Value>> parameters; |
| 125 | for (unsigned int i = 0; i < (unsigned int)info.Length(); i++) |
| 126 | parameters.push_back(info[i]); |
| 127 | |
Tom Sepez | 3a6d058 | 2018-08-17 19:28:52 +0000 | [diff] [blame] | 128 | CJS_Result result = (pObj.Get()->*M)(pRuntime, parameters); |
Dan Sinclair | 8f524d6 | 2017-10-25 13:30:31 -0400 | [diff] [blame] | 129 | if (result.HasError()) { |
| 130 | pRuntime->Error(JSFormatErrorString(class_name_string, method_name_string, |
| 131 | result.Error())); |
Tom Sepez | a116045 | 2015-02-19 10:00:55 -0800 | [diff] [blame] | 132 | return; |
| 133 | } |
Dan Sinclair | 8f524d6 | 2017-10-25 13:30:31 -0400 | [diff] [blame] | 134 | |
| 135 | if (result.HasReturn()) |
| 136 | info.GetReturnValue().Set(result.Return()); |
John Abd-El-Malek | 3f3b45c | 2014-05-23 17:28:10 -0700 | [diff] [blame] | 137 | } |
| 138 | |
Dan Sinclair | 89d26c8 | 2017-10-26 12:21:28 -0400 | [diff] [blame] | 139 | #define JS_STATIC_PROP(err_name, prop_name, class_name) \ |
| 140 | static void get_##prop_name##_static( \ |
| 141 | v8::Local<v8::String> property, \ |
| 142 | const v8::PropertyCallbackInfo<v8::Value>& info) { \ |
| 143 | JSPropGetter<class_name, &class_name::get_##prop_name>( \ |
Dan Sinclair | f743552 | 2018-02-05 22:27:22 +0000 | [diff] [blame] | 144 | #err_name, class_name::kName, property, info); \ |
Dan Sinclair | 89d26c8 | 2017-10-26 12:21:28 -0400 | [diff] [blame] | 145 | } \ |
| 146 | static void set_##prop_name##_static( \ |
| 147 | v8::Local<v8::String> property, v8::Local<v8::Value> value, \ |
| 148 | const v8::PropertyCallbackInfo<void>& info) { \ |
| 149 | JSPropSetter<class_name, &class_name::set_##prop_name>( \ |
Dan Sinclair | f743552 | 2018-02-05 22:27:22 +0000 | [diff] [blame] | 150 | #err_name, class_name::kName, property, value, info); \ |
Dan Sinclair | 89d26c8 | 2017-10-26 12:21:28 -0400 | [diff] [blame] | 151 | } |
| 152 | |
Dan Sinclair | f743552 | 2018-02-05 22:27:22 +0000 | [diff] [blame] | 153 | #define JS_STATIC_METHOD(method_name, class_name) \ |
| 154 | static void method_name##_static( \ |
| 155 | const v8::FunctionCallbackInfo<v8::Value>& info) { \ |
| 156 | JSMethod<class_name, &class_name::method_name>(#method_name, \ |
| 157 | class_name::kName, info); \ |
Tom Sepez | a116045 | 2015-02-19 10:00:55 -0800 | [diff] [blame] | 158 | } |
| 159 | |
Dan Sinclair | e0345a4 | 2017-10-30 20:20:42 +0000 | [diff] [blame] | 160 | #endif // FXJS_JS_DEFINE_H_ |