1 // Copyright 2014 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "fxjs/cjs_color.h"
8
9 #include <algorithm>
10 #include <vector>
11
12 #include "core/fxge/cfx_color.h"
13 #include "fxjs/cjs_event_context.h"
14 #include "fxjs/cjs_object.h"
15 #include "fxjs/cjs_runtime.h"
16 #include "fxjs/fxv8.h"
17 #include "fxjs/js_define.h"
18 #include "v8/include/v8-container.h"
19
20 const JSPropertySpec CJS_Color::PropertySpecs[] = {
21 {"black", get_black_static, set_black_static},
22 {"blue", get_blue_static, set_blue_static},
23 {"cyan", get_cyan_static, set_cyan_static},
24 {"dkGray", get_dark_gray_static, set_dark_gray_static},
25 {"gray", get_gray_static, set_gray_static},
26 {"green", get_green_static, set_green_static},
27 {"ltGray", get_light_gray_static, set_light_gray_static},
28 {"magenta", get_magenta_static, set_magenta_static},
29 {"red", get_red_static, set_red_static},
30 {"transparent", get_transparent_static, set_transparent_static},
31 {"white", get_white_static, set_white_static},
32 {"yellow", get_yellow_static, set_yellow_static}};
33
34 const JSMethodSpec CJS_Color::MethodSpecs[] = {{"convert", convert_static},
35 {"equal", equal_static}};
36
37 uint32_t CJS_Color::ObjDefnID = 0;
38 const char CJS_Color::kName[] = "color";
39
40 // static
GetObjDefnID()41 uint32_t CJS_Color::GetObjDefnID() {
42 return ObjDefnID;
43 }
44
45 // static
DefineJSObjects(CFXJS_Engine * pEngine)46 void CJS_Color::DefineJSObjects(CFXJS_Engine* pEngine) {
47 ObjDefnID = pEngine->DefineObj(CJS_Color::kName, FXJSOBJTYPE_STATIC,
48 JSConstructor<CJS_Color>, JSDestructor);
49 DefineProps(pEngine, ObjDefnID, PropertySpecs);
50 DefineMethods(pEngine, ObjDefnID, MethodSpecs);
51 }
52
53 // static
ConvertPWLColorToArray(CJS_Runtime * pRuntime,const CFX_Color & color)54 v8::Local<v8::Array> CJS_Color::ConvertPWLColorToArray(CJS_Runtime* pRuntime,
55 const CFX_Color& color) {
56 v8::Local<v8::Array> array;
57 switch (color.nColorType) {
58 case CFX_Color::Type::kTransparent:
59 array = pRuntime->NewArray();
60 pRuntime->PutArrayElement(array, 0, pRuntime->NewString("T"));
61 break;
62 case CFX_Color::Type::kGray:
63 array = pRuntime->NewArray();
64 pRuntime->PutArrayElement(array, 0, pRuntime->NewString("G"));
65 pRuntime->PutArrayElement(array, 1, pRuntime->NewNumber(color.fColor1));
66 break;
67 case CFX_Color::Type::kRGB:
68 array = pRuntime->NewArray();
69 pRuntime->PutArrayElement(array, 0, pRuntime->NewString("RGB"));
70 pRuntime->PutArrayElement(array, 1, pRuntime->NewNumber(color.fColor1));
71 pRuntime->PutArrayElement(array, 2, pRuntime->NewNumber(color.fColor2));
72 pRuntime->PutArrayElement(array, 3, pRuntime->NewNumber(color.fColor3));
73 break;
74 case CFX_Color::Type::kCMYK:
75 array = pRuntime->NewArray();
76 pRuntime->PutArrayElement(array, 0, pRuntime->NewString("CMYK"));
77 pRuntime->PutArrayElement(array, 1, pRuntime->NewNumber(color.fColor1));
78 pRuntime->PutArrayElement(array, 2, pRuntime->NewNumber(color.fColor2));
79 pRuntime->PutArrayElement(array, 3, pRuntime->NewNumber(color.fColor3));
80 pRuntime->PutArrayElement(array, 4, pRuntime->NewNumber(color.fColor4));
81 break;
82 }
83 return array;
84 }
85
86 // static
ConvertArrayToPWLColor(CJS_Runtime * pRuntime,v8::Local<v8::Array> array)87 CFX_Color CJS_Color::ConvertArrayToPWLColor(CJS_Runtime* pRuntime,
88 v8::Local<v8::Array> array) {
89 size_t nArrayLen = pRuntime->GetArrayLength(array);
90 if (nArrayLen == 0)
91 return CFX_Color();
92
93 WideString sSpace =
94 pRuntime->ToWideString(pRuntime->GetArrayElement(array, 0));
95 if (sSpace.EqualsASCII("T"))
96 return CFX_Color(CFX_Color::Type::kTransparent);
97
98 float d1 = 0;
99 if (nArrayLen > 1) {
100 d1 = static_cast<float>(
101 pRuntime->ToDouble(pRuntime->GetArrayElement(array, 1)));
102 }
103 if (sSpace.EqualsASCII("G"))
104 return CFX_Color(CFX_Color::Type::kGray, d1);
105
106 float d2 = 0;
107 float d3 = 0;
108 if (nArrayLen > 2) {
109 d2 = static_cast<float>(
110 pRuntime->ToDouble(pRuntime->GetArrayElement(array, 2)));
111 }
112 if (nArrayLen > 3) {
113 d3 = static_cast<float>(
114 pRuntime->ToDouble(pRuntime->GetArrayElement(array, 3)));
115 }
116 if (sSpace.EqualsASCII("RGB"))
117 return CFX_Color(CFX_Color::Type::kRGB, d1, d2, d3);
118
119 float d4 = 0;
120 if (nArrayLen > 4) {
121 d4 = static_cast<float>(
122 pRuntime->ToDouble(pRuntime->GetArrayElement(array, 4)));
123 }
124 if (sSpace.EqualsASCII("CMYK"))
125 return CFX_Color(CFX_Color::Type::kCMYK, d1, d2, d3, d4);
126
127 return CFX_Color();
128 }
129
CJS_Color(v8::Local<v8::Object> pObject,CJS_Runtime * pRuntime)130 CJS_Color::CJS_Color(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
131 : CJS_Object(pObject, pRuntime),
132 m_crTransparent(CFX_Color::Type::kTransparent),
133 m_crBlack(CFX_Color::Type::kGray, 0),
134 m_crWhite(CFX_Color::Type::kGray, 1),
135 m_crRed(CFX_Color::Type::kRGB, 1, 0, 0),
136 m_crGreen(CFX_Color::Type::kRGB, 0, 1, 0),
137 m_crBlue(CFX_Color::Type::kRGB, 0, 0, 1),
138 m_crCyan(CFX_Color::Type::kCMYK, 1, 0, 0, 0),
139 m_crMagenta(CFX_Color::Type::kCMYK, 0, 1, 0, 0),
140 m_crYellow(CFX_Color::Type::kCMYK, 0, 0, 1, 0),
141 m_crDKGray(CFX_Color::Type::kGray, 0.25),
142 m_crGray(CFX_Color::Type::kGray, 0.5),
143 m_crLTGray(CFX_Color::Type::kGray, 0.75) {}
144
145 CJS_Color::~CJS_Color() = default;
146
get_transparent(CJS_Runtime * pRuntime)147 CJS_Result CJS_Color::get_transparent(CJS_Runtime* pRuntime) {
148 return GetPropertyHelper(pRuntime, &m_crTransparent);
149 }
150
set_transparent(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)151 CJS_Result CJS_Color::set_transparent(CJS_Runtime* pRuntime,
152 v8::Local<v8::Value> vp) {
153 return SetPropertyHelper(pRuntime, vp, &m_crTransparent);
154 }
155
get_black(CJS_Runtime * pRuntime)156 CJS_Result CJS_Color::get_black(CJS_Runtime* pRuntime) {
157 return GetPropertyHelper(pRuntime, &m_crBlack);
158 }
159
set_black(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)160 CJS_Result CJS_Color::set_black(CJS_Runtime* pRuntime,
161 v8::Local<v8::Value> vp) {
162 return SetPropertyHelper(pRuntime, vp, &m_crBlack);
163 }
164
get_white(CJS_Runtime * pRuntime)165 CJS_Result CJS_Color::get_white(CJS_Runtime* pRuntime) {
166 return GetPropertyHelper(pRuntime, &m_crWhite);
167 }
168
set_white(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)169 CJS_Result CJS_Color::set_white(CJS_Runtime* pRuntime,
170 v8::Local<v8::Value> vp) {
171 return SetPropertyHelper(pRuntime, vp, &m_crWhite);
172 }
173
get_red(CJS_Runtime * pRuntime)174 CJS_Result CJS_Color::get_red(CJS_Runtime* pRuntime) {
175 return GetPropertyHelper(pRuntime, &m_crRed);
176 }
177
set_red(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)178 CJS_Result CJS_Color::set_red(CJS_Runtime* pRuntime, v8::Local<v8::Value> vp) {
179 return SetPropertyHelper(pRuntime, vp, &m_crRed);
180 }
181
get_green(CJS_Runtime * pRuntime)182 CJS_Result CJS_Color::get_green(CJS_Runtime* pRuntime) {
183 return GetPropertyHelper(pRuntime, &m_crGreen);
184 }
185
set_green(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)186 CJS_Result CJS_Color::set_green(CJS_Runtime* pRuntime,
187 v8::Local<v8::Value> vp) {
188 return SetPropertyHelper(pRuntime, vp, &m_crGreen);
189 }
190
get_blue(CJS_Runtime * pRuntime)191 CJS_Result CJS_Color::get_blue(CJS_Runtime* pRuntime) {
192 return GetPropertyHelper(pRuntime, &m_crBlue);
193 }
194
set_blue(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)195 CJS_Result CJS_Color::set_blue(CJS_Runtime* pRuntime, v8::Local<v8::Value> vp) {
196 return SetPropertyHelper(pRuntime, vp, &m_crBlue);
197 }
198
get_cyan(CJS_Runtime * pRuntime)199 CJS_Result CJS_Color::get_cyan(CJS_Runtime* pRuntime) {
200 return GetPropertyHelper(pRuntime, &m_crCyan);
201 }
202
set_cyan(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)203 CJS_Result CJS_Color::set_cyan(CJS_Runtime* pRuntime, v8::Local<v8::Value> vp) {
204 return SetPropertyHelper(pRuntime, vp, &m_crCyan);
205 }
206
get_magenta(CJS_Runtime * pRuntime)207 CJS_Result CJS_Color::get_magenta(CJS_Runtime* pRuntime) {
208 return GetPropertyHelper(pRuntime, &m_crMagenta);
209 }
210
set_magenta(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)211 CJS_Result CJS_Color::set_magenta(CJS_Runtime* pRuntime,
212 v8::Local<v8::Value> vp) {
213 return SetPropertyHelper(pRuntime, vp, &m_crMagenta);
214 }
215
get_yellow(CJS_Runtime * pRuntime)216 CJS_Result CJS_Color::get_yellow(CJS_Runtime* pRuntime) {
217 return GetPropertyHelper(pRuntime, &m_crYellow);
218 }
219
set_yellow(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)220 CJS_Result CJS_Color::set_yellow(CJS_Runtime* pRuntime,
221 v8::Local<v8::Value> vp) {
222 return SetPropertyHelper(pRuntime, vp, &m_crYellow);
223 }
224
get_dark_gray(CJS_Runtime * pRuntime)225 CJS_Result CJS_Color::get_dark_gray(CJS_Runtime* pRuntime) {
226 return GetPropertyHelper(pRuntime, &m_crDKGray);
227 }
228
set_dark_gray(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)229 CJS_Result CJS_Color::set_dark_gray(CJS_Runtime* pRuntime,
230 v8::Local<v8::Value> vp) {
231 return SetPropertyHelper(pRuntime, vp, &m_crDKGray);
232 }
233
get_gray(CJS_Runtime * pRuntime)234 CJS_Result CJS_Color::get_gray(CJS_Runtime* pRuntime) {
235 return GetPropertyHelper(pRuntime, &m_crGray);
236 }
237
set_gray(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)238 CJS_Result CJS_Color::set_gray(CJS_Runtime* pRuntime, v8::Local<v8::Value> vp) {
239 return SetPropertyHelper(pRuntime, vp, &m_crGray);
240 }
241
get_light_gray(CJS_Runtime * pRuntime)242 CJS_Result CJS_Color::get_light_gray(CJS_Runtime* pRuntime) {
243 return GetPropertyHelper(pRuntime, &m_crLTGray);
244 }
245
set_light_gray(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)246 CJS_Result CJS_Color::set_light_gray(CJS_Runtime* pRuntime,
247 v8::Local<v8::Value> vp) {
248 return SetPropertyHelper(pRuntime, vp, &m_crLTGray);
249 }
250
GetPropertyHelper(CJS_Runtime * pRuntime,CFX_Color * var)251 CJS_Result CJS_Color::GetPropertyHelper(CJS_Runtime* pRuntime, CFX_Color* var) {
252 v8::Local<v8::Value> array = ConvertPWLColorToArray(pRuntime, *var);
253 if (array.IsEmpty())
254 return CJS_Result::Success(pRuntime->NewArray());
255
256 return CJS_Result::Success(array);
257 }
258
SetPropertyHelper(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp,CFX_Color * var)259 CJS_Result CJS_Color::SetPropertyHelper(CJS_Runtime* pRuntime,
260 v8::Local<v8::Value> vp,
261 CFX_Color* var) {
262 if (vp.IsEmpty())
263 return CJS_Result::Failure(JSMessage::kParamError);
264
265 if (!vp->IsArray())
266 return CJS_Result::Failure(JSMessage::kTypeError);
267
268 *var = ConvertArrayToPWLColor(pRuntime, pRuntime->ToArray(vp));
269 return CJS_Result::Success();
270 }
271
convert(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)272 CJS_Result CJS_Color::convert(CJS_Runtime* pRuntime,
273 const std::vector<v8::Local<v8::Value>>& params) {
274 if (params.size() < 2)
275 return CJS_Result::Failure(JSMessage::kParamError);
276
277 if (!fxv8::IsArray(params[0]))
278 return CJS_Result::Failure(JSMessage::kTypeError);
279
280 WideString sDestSpace = pRuntime->ToWideString(params[1]);
281 CFX_Color::Type nColorType = CFX_Color::Type::kTransparent;
282 if (sDestSpace.EqualsASCII("T"))
283 nColorType = CFX_Color::Type::kTransparent;
284 else if (sDestSpace.EqualsASCII("G"))
285 nColorType = CFX_Color::Type::kGray;
286 else if (sDestSpace.EqualsASCII("RGB"))
287 nColorType = CFX_Color::Type::kRGB;
288 else if (sDestSpace.EqualsASCII("CMYK"))
289 nColorType = CFX_Color::Type::kCMYK;
290
291 CFX_Color color =
292 ConvertArrayToPWLColor(pRuntime, pRuntime->ToArray(params[0]));
293 v8::Local<v8::Value> array =
294 ConvertPWLColorToArray(pRuntime, color.ConvertColorType(nColorType));
295 if (array.IsEmpty())
296 return CJS_Result::Success(pRuntime->NewArray());
297
298 return CJS_Result::Success(array);
299 }
300
equal(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)301 CJS_Result CJS_Color::equal(CJS_Runtime* pRuntime,
302 const std::vector<v8::Local<v8::Value>>& params) {
303 if (params.size() < 2)
304 return CJS_Result::Failure(JSMessage::kParamError);
305
306 if (!fxv8::IsArray(params[0]) || !fxv8::IsArray(params[1]))
307 return CJS_Result::Failure(JSMessage::kTypeError);
308
309 CFX_Color color1 =
310 ConvertArrayToPWLColor(pRuntime, pRuntime->ToArray(params[0]));
311 CFX_Color color2 =
312 ConvertArrayToPWLColor(pRuntime, pRuntime->ToArray(params[1]));
313
314 // Relies on higher values having more components.
315 CFX_Color::Type best = std::max(color1.nColorType, color2.nColorType);
316 return CJS_Result::Success(pRuntime->NewBoolean(
317 color1.ConvertColorType(best) == color2.ConvertColorType(best)));
318 }
319