1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "frameworks/bridge/declarative_frontend/jsview/js_shape.h"
17
18 #include "frameworks/bridge/declarative_frontend/jsview/js_utils.h"
19 #include "frameworks/bridge/declarative_frontend/view_stack_processor.h"
20
21 namespace OHOS::Ace::Framework {
22 namespace {
23 constexpr double DEFAULT_OPACITY = 1.0;
24 }
25
Create(const JSCallbackInfo & info)26 void JSShape::Create(const JSCallbackInfo& info)
27 {
28 std::list<RefPtr<OHOS::Ace::Component>> componentChildren;
29 RefPtr<OHOS::Ace::ShapeContainerComponent> component =
30 AceType::MakeRefPtr<OHOS::Ace::ShapeContainerComponent>(componentChildren);
31 ViewStackProcessor::GetInstance()->Push(component);
32 JSInteractableView::SetFocusable(true);
33 InitBox(info);
34 }
35
InitBox(const JSCallbackInfo & info)36 void JSShape::InitBox(const JSCallbackInfo& info)
37 {
38 auto box = ViewStackProcessor::GetInstance()->GetBoxComponent();
39 box->SetOverflow(Overflow::FORCE_CLIP);
40 auto clipPath = AceType::MakeRefPtr<ClipPath>();
41 clipPath->SetGeometryBoxType(GeometryBoxType::BORDER_BOX);
42 box->SetClipPath(clipPath);
43 if (info.Length() == 1 && info[0]->IsObject()) {
44 #if !defined(WINDOWS_PLATFORM) and !defined(MAC_PLATFORM)
45 box->SetPixelMap(CreatePixelMapFromNapiValue(info[0]));
46 #endif
47 }
48 }
49
SetViewPort(const JSCallbackInfo & info)50 void JSShape::SetViewPort(const JSCallbackInfo& info)
51 {
52 if (info.Length() < 1) {
53 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
54 return;
55 }
56 auto stack = ViewStackProcessor::GetInstance();
57 auto component = AceType::DynamicCast<OHOS::Ace::ShapeContainerComponent>(stack->GetMainComponent());
58 if (!component) {
59 LOGE("shape is null");
60 return;
61 }
62 if (info[0]->IsObject()) {
63 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
64 JSRef<JSVal> leftValue = obj->GetProperty("x");
65 JSRef<JSVal> topValue = obj->GetProperty("y");
66 JSRef<JSVal> widthValue = obj->GetProperty("width");
67 JSRef<JSVal> heightValue = obj->GetProperty("height");
68 AnimationOption option = stack->GetImplicitAnimationOption();
69 ShapeViewBox viewBox;
70 Dimension dimLeft;
71 if (ParseJsDimensionVp(leftValue, dimLeft)) {
72 viewBox.SetLeft(dimLeft, option);
73 }
74 Dimension dimTop;
75 if (ParseJsDimensionVp(topValue, dimTop)) {
76 viewBox.SetTop(dimTop, option);
77 }
78 Dimension dimWidth;
79 if (ParseJsDimensionVp(widthValue, dimWidth)) {
80 viewBox.SetWidth(dimWidth, option);
81 }
82 Dimension dimHeight;
83 if (ParseJsDimensionVp(heightValue, dimHeight)) {
84 viewBox.SetHeight(dimHeight, option);
85 }
86 component->SetViewBox(viewBox);
87 }
88 info.SetReturnValue(info.This());
89 }
90
JsWidth(const JSCallbackInfo & info)91 void JSShape::JsWidth(const JSCallbackInfo& info)
92 {
93 if (info.Length() < 1) {
94 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
95 return;
96 }
97
98 JsWidth(info[0]);
99 }
100
JsWidth(const JSRef<JSVal> & jsValue)101 void JSShape::JsWidth(const JSRef<JSVal>& jsValue)
102 {
103 JSViewAbstract::JsWidth(jsValue);
104 auto box = ViewStackProcessor::GetInstance()->GetBoxComponent();
105 if (!box->GetWidth().IsValid()) {
106 return;
107 }
108 auto stack = ViewStackProcessor::GetInstance();
109 auto component = AceType::DynamicCast<OHOS::Ace::ShapeContainerComponent>(stack->GetMainComponent());
110 if (component) {
111 component->SetWidthFlag(true);
112 }
113 }
114
JsHeight(const JSCallbackInfo & info)115 void JSShape::JsHeight(const JSCallbackInfo& info)
116 {
117 if (info.Length() < 1) {
118 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
119 return;
120 }
121
122 JsHeight(info[0]);
123 }
124
JsHeight(const JSRef<JSVal> & jsValue)125 void JSShape::JsHeight(const JSRef<JSVal>& jsValue)
126 {
127 JSViewAbstract::JsHeight(jsValue);
128 auto box = ViewStackProcessor::GetInstance()->GetBoxComponent();
129 if (!box->GetHeight().IsValid()) {
130 return;
131 }
132 auto stack = ViewStackProcessor::GetInstance();
133 auto component = AceType::DynamicCast<OHOS::Ace::ShapeContainerComponent>(stack->GetMainComponent());
134 if (component) {
135 component->SetHeightFlag(true);
136 }
137 }
138
JsSize(const JSCallbackInfo & info)139 void JSShape::JsSize(const JSCallbackInfo& info)
140 {
141 if (info.Length() < 1) {
142 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
143 return;
144 }
145
146 if (!info[0]->IsObject()) {
147 LOGE("arg is not Object or String.");
148 return;
149 }
150
151 JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
152 JsWidth(sizeObj->GetProperty("width"));
153 JsHeight(sizeObj->GetProperty("height"));
154 }
155
SetStrokeDashArray(const JSCallbackInfo & info)156 void JSShape::SetStrokeDashArray(const JSCallbackInfo& info)
157 {
158 if (info.Length() < 1 || !info[0]->IsArray()) {
159 LOGE("info is not array");
160 return;
161 }
162 auto stack = ViewStackProcessor::GetInstance();
163 auto component = AceType::DynamicCast<OHOS::Ace::ShapeContainerComponent>(stack->GetMainComponent());
164 if (!component) {
165 LOGE("component is null");
166 return;
167 }
168
169 JSRef<JSArray> array = JSRef<JSArray>::Cast(info[0]);
170 int32_t length = static_cast<int32_t>(array->Length());
171 if (length <= 0) {
172 LOGE("info is invalid");
173 return;
174 }
175 std::vector<Dimension> dashArray;
176 for (int32_t i = 0; i < length; i++) {
177 JSRef<JSVal> value = array->GetValueAt(i);
178 Dimension dim;
179 if (ParseJsDimensionVp(value, dim)) {
180 dashArray.emplace_back(dim);
181 }
182 }
183 if (length != static_cast<int32_t>(dashArray.size())) {
184 LOGE("ParseJsDimensionVp failed");
185 return;
186 }
187 // if odd,add twice
188 if ((static_cast<uint32_t>(length) & 1)) {
189 for (int32_t i = 0; i < length; i++) {
190 dashArray.emplace_back(dashArray[i]);
191 }
192 }
193 component->SetStrokeDashArray(dashArray);
194 info.SetReturnValue(info.This());
195 }
196
SetStroke(const JSCallbackInfo & info)197 void JSShape::SetStroke(const JSCallbackInfo& info)
198 {
199 if (info.Length() < 1) {
200 LOGE("The argv is wrong, it is supposed to have at least 1 argument");
201 return;
202 }
203 Color strokeColor = Color::TRANSPARENT;
204 ParseJsColor(info[0], strokeColor);
205 auto stack = ViewStackProcessor::GetInstance();
206 auto component = AceType::DynamicCast<OHOS::Ace::ShapeContainerComponent>(stack->GetMainComponent());
207 if (component) {
208 AnimationOption option = stack->GetImplicitAnimationOption();
209 component->SetStroke(strokeColor, option);
210 }
211 }
212
SetFill(const JSCallbackInfo & info)213 void JSShape::SetFill(const JSCallbackInfo& info)
214 {
215 if (info.Length() < 1) {
216 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
217 return;
218 }
219 auto stack = ViewStackProcessor::GetInstance();
220 auto component = AceType::DynamicCast<OHOS::Ace::ShapeContainerComponent>(stack->GetMainComponent());
221 if (!component) {
222 LOGE("component is null");
223 return;
224 }
225 AnimationOption option = stack->GetImplicitAnimationOption();
226 if (info[0]->IsString() && info[0]->ToString() == "none") {
227 component->SetFill(Color::TRANSPARENT, option);
228 } else {
229 Color fillColor;
230 if (ParseJsColor(info[0], fillColor)) {
231 component->SetFill(fillColor, option);
232 }
233 }
234 }
235
SetStrokeDashOffset(const JSCallbackInfo & info)236 void JSShape::SetStrokeDashOffset(const JSCallbackInfo& info)
237 {
238 if (info.Length() < 1) {
239 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
240 return;
241 }
242 Dimension offset;
243 if (!ParseJsDimensionVp(info[0], offset)) {
244 return;
245 }
246 auto stack = ViewStackProcessor::GetInstance();
247 auto component = AceType::DynamicCast<OHOS::Ace::ShapeContainerComponent>(stack->GetMainComponent());
248 if (component) {
249 AnimationOption option = stack->GetImplicitAnimationOption();
250 component->SetStrokeDashOffset(offset, option);
251 }
252 }
253
SetStrokeLineCap(int lineCap)254 void JSShape::SetStrokeLineCap(int lineCap)
255 {
256 auto stack = ViewStackProcessor::GetInstance();
257 auto component = AceType::DynamicCast<OHOS::Ace::ShapeContainerComponent>(stack->GetMainComponent());
258 if (!component) {
259 LOGE("ShapeComponent is null");
260 return;
261 }
262 if (static_cast<int>(LineCapStyle::SQUARE) == lineCap) {
263 component->SetStrokeLineCap(LineCapStyle::SQUARE);
264 } else if (static_cast<int>(LineCapStyle::ROUND) == lineCap) {
265 component->SetStrokeLineCap(LineCapStyle::ROUND);
266 } else {
267 component->SetStrokeLineCap(LineCapStyle::BUTT);
268 }
269 }
270
SetStrokeLineJoin(int lineJoin)271 void JSShape::SetStrokeLineJoin(int lineJoin)
272 {
273 auto stack = ViewStackProcessor::GetInstance();
274 auto component = AceType::DynamicCast<OHOS::Ace::ShapeContainerComponent>(stack->GetMainComponent());
275 if (!component) {
276 LOGE("ShapeComponent is null");
277 return;
278 }
279 if (static_cast<int>(LineJoinStyle::BEVEL) == lineJoin) {
280 component->SetStrokeLineJoin(LineJoinStyle::BEVEL);
281 } else if (static_cast<int>(LineJoinStyle::ROUND) == lineJoin) {
282 component->SetStrokeLineJoin(LineJoinStyle::ROUND);
283 } else {
284 component->SetStrokeLineJoin(LineJoinStyle::MITER);
285 }
286 }
287
SetStrokeMiterLimit(const JSCallbackInfo & info)288 void JSShape::SetStrokeMiterLimit(const JSCallbackInfo& info)
289 {
290 if (info.Length() < 1) {
291 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
292 return;
293 }
294 double miterLimit;
295 if (!ParseJsDouble(info[0], miterLimit)) {
296 return;
297 }
298 auto stack = ViewStackProcessor::GetInstance();
299 auto component = AceType::DynamicCast<OHOS::Ace::ShapeContainerComponent>(stack->GetMainComponent());
300 if (!component) {
301 LOGE("ShapeComponent is null");
302 return;
303 }
304 if (GreatOrEqual(miterLimit, 1.0)) {
305 component->SetStrokeMiterLimit(miterLimit);
306 }
307 }
308
SetStrokeOpacity(const JSCallbackInfo & info)309 void JSShape::SetStrokeOpacity(const JSCallbackInfo& info)
310 {
311 if (info.Length() < 1) {
312 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
313 return;
314 }
315 double strokeOpacity = DEFAULT_OPACITY;
316 ParseJsDouble(info[0], strokeOpacity);
317 auto stack = ViewStackProcessor::GetInstance();
318 auto component = AceType::DynamicCast<OHOS::Ace::ShapeContainerComponent>(stack->GetMainComponent());
319 if (component) {
320 AnimationOption option = stack->GetImplicitAnimationOption();
321 component->SetStrokeOpacity(strokeOpacity, option);
322 }
323 }
324
SetFillOpacity(const JSCallbackInfo & info)325 void JSShape::SetFillOpacity(const JSCallbackInfo& info)
326 {
327 if (info.Length() < 1) {
328 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
329 return;
330 }
331 double fillOpacity = DEFAULT_OPACITY;
332 ParseJsDouble(info[0], fillOpacity);
333 auto stack = ViewStackProcessor::GetInstance();
334 auto component = AceType::DynamicCast<OHOS::Ace::ShapeContainerComponent>(stack->GetMainComponent());
335 if (component) {
336 AnimationOption option = stack->GetImplicitAnimationOption();
337 component->SetFillOpacity(fillOpacity, option);
338 }
339 }
340
SetStrokeWidth(const JSCallbackInfo & info)341 void JSShape::SetStrokeWidth(const JSCallbackInfo& info)
342 {
343 if (info.Length() < 1) {
344 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
345 return;
346 }
347 Dimension lineWidth;
348 if (!ParseJsDimensionVp(info[0], lineWidth)) {
349 return;
350 }
351 auto stack = ViewStackProcessor::GetInstance();
352 auto component = AceType::DynamicCast<OHOS::Ace::ShapeContainerComponent>(stack->GetMainComponent());
353 if (!component) {
354 LOGE("ShapeComponent is null");
355 return;
356 }
357 if (GreatOrEqual(lineWidth.Value(), 0.0)) {
358 AnimationOption option = stack->GetImplicitAnimationOption();
359 component->SetStrokeWidth(lineWidth, option);
360 }
361 }
362
SetAntiAlias(bool antiAlias)363 void JSShape::SetAntiAlias(bool antiAlias)
364 {
365 auto stack = ViewStackProcessor::GetInstance();
366 auto component = AceType::DynamicCast<OHOS::Ace::ShapeContainerComponent>(stack->GetMainComponent());
367 if (component) {
368 component->SetAntiAlias(antiAlias);
369 }
370 }
371
SetBitmapMesh(const JSCallbackInfo & info)372 void JSShape::SetBitmapMesh(const JSCallbackInfo& info)
373 {
374 if (info.Length() != 3) {
375 LOGE("The arg is wrong, it is supposed to have at least 3 argument");
376 return;
377 }
378 std::vector<double> mesh;
379 JSRef<JSVal> meshValue = info[0];
380
381 if (meshValue->IsObject()) {
382 JSRef<JSObject> meshObj = JSRef<JSObject>::Cast(meshValue);
383 JSRef<JSArray> array = meshObj->GetPropertyNames();
384 for (size_t i = 0; i < array->Length(); i++) {
385 JSRef<JSVal> value = array->GetValueAt(i);
386 if (value->IsString()) {
387 std::string valueStr;
388 if (ParseJsString(value, valueStr)) {
389 double vert;
390 if (ParseJsDouble(meshObj->GetProperty(valueStr.c_str()), vert)) {
391 mesh.push_back(vert);
392 }
393 }
394 }
395 }
396 }
397 uint32_t column = 0;
398 uint32_t row = 0;
399 JSRef<JSVal> columnValue = info[1];
400 JSRef<JSVal> rowValue = info[2];
401 if (!ParseJsInteger(columnValue, column)) {
402 return;
403 }
404 if (!ParseJsInteger(rowValue, row)) {
405 return;
406 }
407 auto stack = ViewStackProcessor::GetInstance();
408 auto component = AceType::DynamicCast<OHOS::Ace::ShapeContainerComponent>(stack->GetMainComponent());
409 if (component) {
410 component->SetBitmapMesh(mesh, (int32_t)column, (int32_t)row);
411 }
412 }
413
JSBind(BindingTarget globalObj)414 void JSShape::JSBind(BindingTarget globalObj)
415 {
416 JSClass<JSShape>::Declare("Shape");
417 JSClass<JSShape>::StaticMethod("create", &JSShape::Create);
418 JSClass<JSShape>::StaticMethod("viewPort", &JSShape::SetViewPort);
419
420 JSClass<JSShape>::StaticMethod("width", &JSShape::JsWidth);
421 JSClass<JSShape>::StaticMethod("height", &JSShape::JsHeight);
422 JSClass<JSShape>::StaticMethod("size", &JSShape::JsSize);
423
424 JSClass<JSShape>::StaticMethod("stroke", &JSShape::SetStroke);
425 JSClass<JSShape>::StaticMethod("fill", &JSShape::SetFill);
426 JSClass<JSShape>::StaticMethod("strokeDashOffset", &JSShape::SetStrokeDashOffset);
427 JSClass<JSShape>::StaticMethod("strokeDashArray", &JSShape::SetStrokeDashArray);
428 JSClass<JSShape>::StaticMethod("strokeLineCap", &JSShape::SetStrokeLineCap);
429 JSClass<JSShape>::StaticMethod("strokeLineJoin", &JSShape::SetStrokeLineJoin);
430 JSClass<JSShape>::StaticMethod("strokeMiterLimit", &JSShape::SetStrokeMiterLimit);
431 JSClass<JSShape>::StaticMethod("strokeOpacity", &JSShape::SetStrokeOpacity);
432 JSClass<JSShape>::StaticMethod("fillOpacity", &JSShape::SetFillOpacity);
433 JSClass<JSShape>::StaticMethod("strokeWidth", &JSShape::SetStrokeWidth);
434 JSClass<JSShape>::StaticMethod("antiAlias", &JSShape::SetAntiAlias);
435 JSClass<JSShape>::StaticMethod("mesh", &JSShape::SetBitmapMesh);
436
437 JSClass<JSShape>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
438 JSClass<JSShape>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
439 JSClass<JSShape>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
440 JSClass<JSShape>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
441 JSClass<JSShape>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
442 JSClass<JSShape>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
443 JSClass<JSShape>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
444 JSClass<JSShape>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
445 JSClass<JSShape>::Inherit<JSContainerBase>();
446 JSClass<JSShape>::Inherit<JSViewAbstract>();
447 JSClass<JSShape>::Bind<>(globalObj);
448 }
449
450 } // namespace OHOS::Ace::Framework
451