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