1 /*
2 * Copyright (c) 2020-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 #include "component.h"
16 #include "ace_log.h"
17 #include "ace_mem_base.h"
18 #include "directive/descriptor_utils.h"
19 #include "fatal_handler.h"
20 #include "handler.h"
21 #include "js_ability_impl.h"
22 #include "js_app_context.h"
23 #include "js_app_environment.h"
24 #include "js_profiler.h"
25 #include "js_router.h"
26 #include "key_parser.h"
27 #include "keys.h"
28 #include "lazy_load_manager.h"
29 #include "securec.h"
30 #include "stylemgr/app_style.h"
31 #include "stylemgr/app_style_manager.h"
32 #include "time_util.h"
33 #include "wrapper/js.h"
34
35 namespace OHOS {
36 namespace ACELite {
37 static Component::AnimationsNode *g_animationListHead = nullptr;
38 static bool g_isAnimatorStarted = false;
HandlerAnimations()39 void Component::HandlerAnimations()
40 {
41 Component::AnimationsNode *point = g_animationListHead;
42 while (point != nullptr && point->transitionImpl != nullptr) {
43 point->transitionImpl->Start();
44 point = point->next;
45 }
46 g_isAnimatorStarted = true;
47 }
48
ReleaseAnimations()49 void Component::ReleaseAnimations()
50 {
51 Component::AnimationsNode *point = g_animationListHead;
52 while (point != nullptr) {
53 Component::AnimationsNode *temp = point->next;
54 if (point->transitionImpl) {
55 delete (point->transitionImpl);
56 point->transitionImpl = nullptr;
57 }
58 delete (point);
59 point = temp;
60 }
61 g_animationListHead = nullptr;
62 g_isAnimatorStarted = false;
63 }
64
Component(jerry_value_t options,jerry_value_t children,AppStyleManager * styleManager)65 Component::Component(jerry_value_t options, jerry_value_t children, AppStyleManager *styleManager)
66 : childHead_(nullptr),
67 nextSibling_(nullptr),
68 parent_(nullptr),
69 styleManager_(styleManager),
70 options_(options),
71 children_(UNDEFINED),
72 onClickListener_(nullptr),
73 onLongPressListener_(nullptr),
74 onTouchListener_(nullptr),
75 #ifdef JS_EXTRA_EVENT_SUPPORT
76 onTouchCancelListener_(nullptr),
77 keyBoardEventListener_(nullptr),
78 #endif
79 viewId_(nullptr),
80 componentName_(K_UNKNOWN),
81 rendered_(false),
82 isAnimationKeyFramesSet_(false),
83 curTransitionImpl_(nullptr),
84 trans_(nullptr),
85 descriptors_(jerry_acquire_value(children)),
86 watchersHead_(nullptr),
87 height_(-1, DimensionType::TYPE_UNKNOWN),
88 width_(-1, DimensionType::TYPE_UNKNOWN),
89 top_(-1, DimensionType::TYPE_UNKNOWN),
90 left_(-1, DimensionType::TYPE_UNKNOWN),
91 marginTop_(-1, DimensionType::TYPE_UNKNOWN),
92 marginLeft_(-1, DimensionType::TYPE_UNKNOWN),
93 marginRight_(-1, DimensionType::TYPE_UNKNOWN),
94 marginBottom_(-1, DimensionType::TYPE_UNKNOWN)
95 {
96 JSValue attrs = JSObject::Get(options, ATTR_ATTRS);
97 if (JSUndefined::Is(attrs)) {
98 freeze_ = false;
99 } else {
100 freeze_ = JSObject::GetBoolean(attrs, ATTR_FREEZE);
101 }
102 JSRelease(attrs);
103 // create native element object before combining styles, as style data binding need it
104 nativeElement_ = jerry_create_object();
105 jerry_value_t global = jerry_get_global_object();
106 viewModel_ = jerryx_get_property_str(global, ATTR_ROOT);
107 jerry_release_value(global);
108 }
109
110 /**
111 * @brief After construct a specific component, call this function to setup this component's native view
112 * and process attribute/events/style/children properly before binding it on an JS object.
113 * It generally calls a series of functions to complete the render work, some of which are needed to be
114 * implemented by child class. See step1~step6 function notes.
115 *
116 * NOTE: Caller should check the return result to decide if it's needed to recycle the component if the
117 * rendering failed.
118 *
119 * @return true if success, false if any error occurs
120 */
Render()121 bool Component::Render()
122 {
123 if (rendered_) {
124 HILOG_ERROR(HILOG_MODULE_ACE, "Render one component twice is not allowed.");
125 return false;
126 }
127
128 PreRender();
129 // step1: create native view/views
130 START_TRACING_WITH_COMPONENT_NAME(RENDER_CREATE_COMPONENT, componentName_);
131 bool renderResult = CreateNativeViews();
132 if (!renderResult) {
133 return false;
134 }
135 STOP_TRACING();
136
137 // The event bubbling mechanism is supported from API version 5, and events are bubbled by default.
138 // However, it should be compatible with the migrated old application (API version 4)
139 // so that it does not bubble by default.
140 const int32_t supportEventBubbleApiVersion = 5;
141 if (JsAppContext::GetInstance()->GetTargetApi() < supportEventBubbleApiVersion) {
142 UIView *view = GetComponentRootView();
143 if (view != nullptr) {
144 // make events non bubbling by default.
145 view->SetIntercept(true);
146 }
147 }
148
149 SetViewExtraMsg();
150
151 // step2: binding js object with this component
152 jerry_set_object_native_pointer(nativeElement_, this, nullptr);
153
154 // step3: parse options for attributes and events, will call child class's according methods
155 ParseOptions();
156
157 // step4:process this component's children
158 START_TRACING_WITH_COMPONENT_NAME(RENDER_PROCESS_CHILDREN, componentName_);
159 renderResult = ProcessChildren();
160 STOP_TRACING();
161 if (!renderResult) {
162 return false;
163 }
164 RecordAnimation();
165 PostRender();
166 rendered_ = true;
167
168 return renderResult;
169 }
170
SetViewExtraMsg()171 void Component::SetViewExtraMsg()
172 {
173 UIView *view = GetComponentRootView();
174 if (view == nullptr) {
175 HILOG_ERROR(HILOG_MODULE_ACE, "failed to set the extra message for view.");
176 return;
177 }
178 UIView::ViewExtraMsg *extraMsg = new UIView::ViewExtraMsg();
179 if (extraMsg == nullptr) {
180 HILOG_ERROR(HILOG_MODULE_ACE, "Failed to mapping native view with DOM element.");
181 return;
182 }
183 extraMsg->elementPtr = reinterpret_cast<void *>(&nativeElement_);
184 view->SetExtraMsg(extraMsg);
185 }
186
ReleaseViewExtraMsg()187 void Component::ReleaseViewExtraMsg()
188 {
189 UIView *view = GetComponentRootView();
190 if (view == nullptr) {
191 return;
192 }
193 UIView::ViewExtraMsg *extraMsg = view->GetExtraMsg();
194 ACE_DELETE(extraMsg);
195 view->SetExtraMsg(nullptr);
196 }
197
Release()198 void Component::Release()
199 {
200 // detach self from fatal handler monitoring
201 FatalHandler::GetInstance().DetachComponentNode(this);
202 RemoveAllChildren();
203 #if (FEATURE_LAZY_LOADING_MODULE == 1)
204 // detach from lazy pending list
205 JsAppContext *context = JsAppContext::GetInstance();
206 LazyLoadManager *lazyLoadManager = const_cast<LazyLoadManager *>(context->GetLazyLoadManager());
207 lazyLoadManager->RemoveLazyWatcher(nativeElement_);
208 #endif // FEATURE_LAZY_LOADING_MODULE
209 if (parent_ != nullptr) {
210 parent_->RemoveChild(this);
211 }
212
213 // stop view animation
214 if (curTransitionImpl_) {
215 curTransitionImpl_->Stop();
216 }
217 ReleaseViewExtraMsg();
218 jerry_delete_object_native_pointer(nativeElement_, nullptr);
219 // release all native views
220 ReleaseNativeViews();
221 // release transition param
222 ReleaseTransitionParam();
223 // release the common event listeners if any
224 ReleaseCommonEventListeners();
225 // release children = jerry_create_array() in Init()
226 ClearWatchersCommon(watchersHead_);
227 // free viewId string if it's set
228 ACE_FREE(viewId_);
229 // release js object
230 jerry_release_value(nativeElement_);
231 jerry_release_value(descriptors_);
232 jerry_release_value(children_);
233 jerry_release_value(viewModel_);
234 }
235
UpdateView(uint16_t attrKeyId,jerry_value_t attrValue)236 bool Component::UpdateView(uint16_t attrKeyId, jerry_value_t attrValue)
237 {
238 if (!KeyParser::IsKeyValid(attrKeyId)) {
239 return false;
240 }
241
242 START_TRACING_WITH_EXTRA_INFO(SET_ATTR_SET_TO_NATIVE, componentName_, attrKeyId);
243 PreUpdate();
244
245 // check if need to invalided self before changing in case component's area will be changed
246 InvalidateIfNeeded(attrKeyId, true);
247 bool updateResult = SetAttribute(attrKeyId, attrValue);
248 if (!updateResult) {
249 AppStyleItem *styleItem = AppStyleItem::CreateStyleItem(attrKeyId, attrValue);
250 if (styleItem != nullptr) {
251 updateResult = ApplyStyle(styleItem);
252 delete styleItem;
253 styleItem = nullptr;
254 }
255 }
256 // for root component case, it has no parent, need to use screen resolution as default
257 ConstrainedParameter parentParam(GetHorizontalResolution(), GetVerticalResolution());
258 if (parent_ != nullptr) {
259 parent_->GetConstrainedParam(parentParam);
260 }
261 AlignDimensions(parentParam);
262 AdaptBoxSizing(attrKeyId);
263 // force parent to relayout the children in case component's area is changed
264 InvalidateIfNeeded(attrKeyId, false);
265 if (updateResult) {
266 PostUpdate(attrKeyId);
267 }
268 StartAnimation();
269 STOP_TRACING();
270
271 return updateResult;
272 }
RegisterNamedFunction(const char * const name,jerry_external_handler_t handler) const273 void Component::RegisterNamedFunction(const char * const name, jerry_external_handler_t handler) const
274 {
275 JerrySetFuncProperty(nativeElement_, name, handler);
276 }
277 // default implementation
SetAttribute(uint16_t attrKeyId,jerry_value_t attrValue)278 bool Component::SetAttribute(uint16_t attrKeyId, jerry_value_t attrValue)
279 {
280 UIView *uiView = GetComponentRootView();
281 if ((uiView == nullptr) || !KeyParser::IsKeyValid(attrKeyId) || IS_UNDEFINED(attrValue)) {
282 return false;
283 }
284
285 // try private first
286 bool setResult = SetPrivateAttribute(attrKeyId, attrValue);
287 if (!setResult) {
288 // this means no private attributes matches, so need to try private ones
289 setResult = SetCommonAttribute(*uiView, attrKeyId, attrValue);
290 }
291
292 return setResult;
293 }
294
SetCommonAttribute(UIView & view,const uint16_t attrKeyId,const jerry_value_t attrValue)295 bool Component::SetCommonAttribute(UIView &view, const uint16_t attrKeyId, const jerry_value_t attrValue)
296 {
297 switch (attrKeyId) {
298 case K_ID: {
299 // this string in component itself.
300 ACE_FREE(viewId_);
301 viewId_ = MallocStringOf(attrValue);
302 if (viewId_ == nullptr) {
303 HILOG_ERROR(HILOG_MODULE_ACE, "failed to set `id` attribute.");
304 return false;
305 }
306 view.SetViewId(viewId_);
307 break;
308 }
309 case K_SHOW: {
310 view.SetVisible(BoolOf(attrValue));
311 break;
312 }
313 case K_REF: {
314 uint16_t length = 0;
315 char *refName = MallocStringOf(attrValue, &length);
316 if (refName == nullptr) {
317 HILOG_ERROR(HILOG_MODULE_ACE, "failed to set `ref` attribute.");
318 return false;
319 }
320 if (length != 0) {
321 jerry_value_t refs = jerryx_get_property_str(viewModel_, ATTR_REFS);
322 if (jerry_value_is_undefined(refs)) {
323 jerry_release_value(refs);
324 refs = jerry_create_object();
325 jerryx_set_property_str(viewModel_, ATTR_REFS, refs);
326 }
327 jerryx_set_property_str(refs, refName, nativeElement_);
328 jerry_release_value(refs);
329 }
330 ace_free(refName);
331 refName = nullptr;
332 break;
333 }
334 default: {
335 // this is not error case, just no one get matched
336 return false;
337 }
338 }
339
340 return true;
341 }
342
ApplyStyles(const jerry_value_t options,Component & currentComponent) const343 void Component::ApplyStyles(const jerry_value_t options, Component ¤tComponent) const
344 {
345 if (jerry_value_is_undefined(options)) {
346 return;
347 }
348 styleManager_->ApplyComponentStyles(options, currentComponent);
349 }
350
GetDimensionFromStyle(Dimension & dimension,const AppStyleItem & styleItem) const351 void Component::GetDimensionFromStyle(Dimension &dimension, const AppStyleItem &styleItem) const
352 {
353 if (styleItem.GetValueType() == STYLE_PROP_VALUE_TYPE_PERCENT) {
354 // percent format
355 dimension.value.percentage = styleItem.GetPercentValue();
356 dimension.type = DimensionType::TYPE_PERCENT;
357 return;
358 }
359 // number or string format
360 // use INT32_MIN as the impossible default value
361 int32_t pixelValue = GetStylePixelValue(&styleItem, INT32_MIN);
362 if (pixelValue == INT32_MIN) {
363 // get pixel failed, reset to unknown type
364 dimension.type = DimensionType::TYPE_UNKNOWN;
365 return;
366 }
367 dimension.value.pixel = (int16_t)(pixelValue);
368 dimension.type = DimensionType::TYPE_PIXEL;
369 }
370
CalculateDimensionPixel(Dimension & dimension,int16_t base) const371 void Component::CalculateDimensionPixel(Dimension &dimension, int16_t base) const
372 {
373 const uint8_t hundred = 100;
374 if (dimension.type == DimensionType::TYPE_PERCENT) {
375 dimension.value.pixel = (int16_t)((dimension.value.percentage * base) / hundred);
376 dimension.type = DimensionType::TYPE_PIXEL;
377 }
378 }
379
GetDimension(uint16_t keyNameId) const380 const Dimension &Component::GetDimension(uint16_t keyNameId) const
381 {
382 const static Dimension unknownDimension = {0, DimensionType::TYPE_UNKNOWN};
383 switch (keyNameId) {
384 case K_WIDTH:
385 return width_;
386 case K_HEIGHT:
387 return height_;
388 case K_TOP:
389 return top_;
390 case K_LEFT:
391 return left_;
392 case K_MARGIN_TOP:
393 return marginTop_;
394 case K_MARGIN_BOTTOM:
395 return marginBottom_;
396 case K_MARGIN_RIGHT:
397 return marginRight_;
398 case K_MARGIN_LEFT:
399 return marginLeft_;
400 default: {
401 return unknownDimension;
402 }
403 }
404 }
405
AlignDimensions(const ConstrainedParameter & param)406 void Component::AlignDimensions(const ConstrainedParameter ¶m)
407 {
408 // width
409 CalculateDimensionPixel(width_, param.maxWidth);
410 CalculateDimensionPixel(height_, param.maxHeight);
411 // top & left
412 CalculateDimensionPixel(top_, param.maxHeight);
413 CalculateDimensionPixel(left_, param.maxWidth);
414 // margin
415 CalculateDimensionPixel(marginTop_, param.maxHeight);
416 CalculateDimensionPixel(marginLeft_, param.maxHeight);
417 CalculateDimensionPixel(marginRight_, param.maxHeight);
418 CalculateDimensionPixel(marginBottom_, param.maxHeight);
419 // notify
420 OnDimensionsAligned();
421 }
422
EnableTransmitSwipe()423 void Component::EnableTransmitSwipe()
424 {
425 if (onTouchListener_ != nullptr) {
426 onTouchListener_->SetStopPropagation(false);
427 }
428 }
429
GetConstrainedParam(ConstrainedParameter & param) const430 void Component::GetConstrainedParam(ConstrainedParameter ¶m) const
431 {
432 param.maxWidth = width_.value.pixel;
433 param.maxHeight = height_.value.pixel;
434 }
435
ApplyAlignedMargin(UIView & uiView) const436 void Component::ApplyAlignedMargin(UIView &uiView) const
437 {
438 if (marginTop_.type == DimensionType::TYPE_PIXEL) {
439 uiView.SetStyle(STYLE_MARGIN_TOP, marginTop_.value.pixel);
440 }
441 if (marginBottom_.type == DimensionType::TYPE_PIXEL) {
442 uiView.SetStyle(STYLE_MARGIN_BOTTOM, marginBottom_.value.pixel);
443 }
444 if (marginLeft_.type == DimensionType::TYPE_PIXEL) {
445 uiView.SetStyle(STYLE_MARGIN_LEFT, marginLeft_.value.pixel);
446 }
447 if (marginRight_.type == DimensionType::TYPE_PIXEL) {
448 uiView.SetStyle(STYLE_MARGIN_RIGHT, marginRight_.value.pixel);
449 }
450 }
451
IsLayoutRelatedAttrs(uint16_t attrKeyId) const452 bool Component::IsLayoutRelatedAttrs(uint16_t attrKeyId) const
453 {
454 return (attrKeyId == K_HEIGHT || attrKeyId == K_WIDTH || attrKeyId == K_MARGIN || attrKeyId == K_MARGIN_BOTTOM ||
455 attrKeyId == K_MARGIN_LEFT || attrKeyId == K_MARGIN_RIGHT || attrKeyId == K_MARGIN_TOP ||
456 attrKeyId == K_PADDING || attrKeyId == K_PADDING_BOTTOM || attrKeyId == K_PADDING_LEFT ||
457 attrKeyId == K_PADDING_RIGHT || attrKeyId == K_PADDING_TOP || attrKeyId == K_BORDER_BOTTOM_WIDTH ||
458 attrKeyId == K_BORDER_LEFT_WIDTH || attrKeyId == K_BORDER_RIGHT_WIDTH || attrKeyId == K_BORDER_TOP_WIDTH ||
459 attrKeyId == K_BORDER_WIDTH || attrKeyId == K_BORDER_RADIUS || attrKeyId == K_LEFT || attrKeyId == K_TOP ||
460 attrKeyId == K_SHOW || attrKeyId == K_DISPLAY);
461 }
462
ApplyAlignedPosition(UIView & uiView) const463 void Component::ApplyAlignedPosition(UIView &uiView) const
464 {
465 if (top_.type == DimensionType::TYPE_PIXEL) {
466 uiView.SetY(top_.value.pixel);
467 }
468 if (left_.type == DimensionType::TYPE_PIXEL) {
469 uiView.SetX(left_.value.pixel);
470 }
471 }
472
AdapteBoxRectArea(UIView & uiView) const473 void Component::AdapteBoxRectArea(UIView &uiView) const
474 {
475 // set view height and width
476 uint8_t borderNum = 2;
477 int16_t height = (height_.type == DimensionType::TYPE_PIXEL) ? height_.value.pixel : -1;
478 int16_t width = (width_.type == DimensionType::TYPE_PIXEL) ? width_.value.pixel : -1;
479 if (height >= 0) {
480 // as uiView->GetStyle(STYLE_PADDING_TOP) and uiView->GetStyle(STYLE_PADDING_BOTTOM) is defined
481 // as uint16_t, so do not need to judge whether less than 0
482 if (uiView.GetStyle(STYLE_BORDER_WIDTH) < 0) {
483 HILOG_WARN(HILOG_MODULE_ACE, "border and padding size should not less than 0");
484 }
485 int16_t contentHeight = height - (uiView.GetStyle(STYLE_BORDER_WIDTH) * borderNum) -
486 uiView.GetStyle(STYLE_PADDING_TOP) - uiView.GetStyle(STYLE_PADDING_BOTTOM);
487 if (contentHeight <= 0) {
488 HILOG_WARN(HILOG_MODULE_ACE,
489 "component height can not include padding and border width, padding and border will be set 0");
490 uiView.SetStyle(STYLE_BORDER_WIDTH, 0);
491 uiView.SetStyle(STYLE_PADDING_TOP, 0);
492 uiView.SetStyle(STYLE_PADDING_BOTTOM, 0);
493 uiView.SetHeight(height);
494 } else {
495 uiView.SetHeight(contentHeight);
496 }
497 }
498 if (width >= 0) {
499 if (uiView.GetStyle(STYLE_BORDER_WIDTH) < 0) {
500 HILOG_WARN(HILOG_MODULE_ACE, "border and padding size should not less than 0");
501 }
502 int16_t contentWidth = width - (uiView.GetStyle(STYLE_BORDER_WIDTH) * borderNum) -
503 uiView.GetStyle(STYLE_PADDING_LEFT) - uiView.GetStyle(STYLE_PADDING_RIGHT);
504 if (contentWidth <= 0) {
505 HILOG_WARN(HILOG_MODULE_ACE,
506 "component width can not include padding and border width, padding and border will be set 0");
507 uiView.SetStyle(STYLE_BORDER_WIDTH, 0);
508 uiView.SetStyle(STYLE_PADDING_LEFT, 0);
509 uiView.SetStyle(STYLE_PADDING_RIGHT, 0);
510 uiView.SetWidth(width);
511 } else {
512 uiView.SetWidth(contentWidth);
513 }
514 }
515 }
516
AdaptBoxSizing(uint16_t attrKeyId) const517 bool Component::AdaptBoxSizing(uint16_t attrKeyId) const
518 {
519 UIView *uiView = GetComponentRootView();
520 if (uiView == nullptr) {
521 return false;
522 }
523 bool isNeedAlignedPosition = ((attrKeyId == K_UNKNOWN) ? true : IsLayoutRelatedAttrs(attrKeyId));
524 if (isNeedAlignedPosition) {
525 // apply aligned top and left
526 ApplyAlignedPosition(*uiView);
527 }
528 // apply aligned magin
529 ApplyAlignedMargin(*uiView);
530 // adjust the box sizing
531 AdapteBoxRectArea(*uiView);
532 return true;
533 }
534
ApplyStyle(const AppStyleItem * style)535 bool Component::ApplyStyle(const AppStyleItem *style)
536 {
537 UIView *uiView = GetComponentRootView();
538 if (uiView == nullptr) {
539 return false;
540 }
541
542 // Try private styles first
543 bool applyResult = ApplyPrivateStyle(style);
544 if (applyResult) {
545 // one private style get matched, no need to try private style ones
546 return true;
547 }
548 return ApplyCommonStyle(*uiView, style);
549 }
550
551 /*
552 * support common style items:
553 * [left|top]: number # flex layout not work
554 * 'width': number,
555 * 'height': number,
556 * 'margin': number, # flex layout work
557 * 'border-width': number,
558 * 'border-color':number,
559 * 'border-radius': number,
560 * 'background-color': number,
561 * 'opacity': number,
562 * 'visibility': bool,
563 *
564 * not suport common style item:
565 * border-[left|top|right|bottom]-width,
566 * border-[left|top|right|bottom]-color,
567 * border-[top|bottom]-[left|right]-radius,
568 * border-style,
569 * padding:number,
570 * right|bottom
571 */
ApplyCommonStyle(UIView & view,const AppStyleItem * style)572 bool Component::ApplyCommonStyle(UIView &view, const AppStyleItem *style)
573 {
574 uint16_t styleNameId = GetStylePropNameId(style);
575 if (!KeyParser::IsKeyValid(styleNameId)) {
576 return false;
577 }
578
579 // we do not support pseudo class for all styles, child must handle itself
580 if (style->IsPseudoClassItem()) {
581 return false;
582 }
583
584 switch (styleNameId) {
585 case K_HEIGHT: {
586 GetDimensionFromStyle(height_, *style);
587 break;
588 }
589 case K_WIDTH: {
590 GetDimensionFromStyle(width_, *style);
591 break;
592 }
593 case K_DISPLAY: {
594 SetVisible(view, style);
595 break;
596 }
597 case K_MARGIN: {
598 GetDimensionFromStyle(marginBottom_, *style);
599 GetDimensionFromStyle(marginLeft_, *style);
600 GetDimensionFromStyle(marginRight_, *style);
601 GetDimensionFromStyle(marginTop_, *style);
602 break;
603 }
604 case K_MARGIN_BOTTOM: {
605 GetDimensionFromStyle(marginBottom_, *style);
606 break;
607 }
608 case K_MARGIN_LEFT: {
609 GetDimensionFromStyle(marginLeft_, *style);
610 break;
611 }
612 case K_MARGIN_RIGHT: {
613 GetDimensionFromStyle(marginRight_, *style);
614 break;
615 }
616 case K_MARGIN_TOP: {
617 GetDimensionFromStyle(marginTop_, *style);
618 break;
619 }
620 case K_PADDING:
621 SetPadding(view, *style);
622 break;
623 case K_PADDING_BOTTOM:
624 SetBottomPadding(view, *style);
625 break;
626 case K_PADDING_LEFT:
627 SetLeftPadding(view, *style);
628 break;
629 case K_PADDING_RIGHT:
630 SetRightPadding(view, *style);
631 break;
632 case K_PADDING_TOP: {
633 SetTopPadding(view, *style);
634 break;
635 }
636 case K_BORDER_BOTTOM_WIDTH:
637 case K_BORDER_LEFT_WIDTH:
638 case K_BORDER_RIGHT_WIDTH:
639 case K_BORDER_TOP_WIDTH:
640 case K_BORDER_WIDTH: {
641 SetBorderWidth(view, *style);
642 break;
643 }
644 case K_BORDER_BOTTOM_COLOR:
645 case K_BORDER_LEFT_COLOR:
646 case K_BORDER_RIGHT_COLOR:
647 case K_BORDER_TOP_COLOR:
648 case K_BORDER_COLOR: {
649 SetBorderColor(view, *style);
650 break;
651 }
652 case K_BORDER_RADIUS: {
653 SetBorderRadius(view, *style);
654 break;
655 }
656 case K_BACKGROUND_COLOR: {
657 SetBackgroundColor(view, *style);
658 break;
659 }
660 case K_LEFT: {
661 GetDimensionFromStyle(left_, *style);
662 break;
663 }
664 case K_TOP: {
665 GetDimensionFromStyle(top_, *style);
666 break;
667 }
668 case K_ANIMATION_DURATION: {
669 SetAnimationStyle(view, style, K_ANIMATION_DURATION);
670 break;
671 }
672 case K_ANIMATION_TIMING_FUNCTION: {
673 SetAnimationStyle(view, style, K_ANIMATION_TIMING_FUNCTION);
674 break;
675 }
676 case K_ANIMATION_FILL_MODE: {
677 SetAnimationStyle(view, style, K_ANIMATION_FILL_MODE);
678 break;
679 }
680 case K_ANIMATION_DELAY: {
681 SetAnimationStyle(view, style, K_ANIMATION_DELAY);
682 break;
683 }
684 case K_ANIMATION_ITERATION_COUNT: {
685 SetAnimationStyle(view, style, K_ANIMATION_ITERATION_COUNT);
686 break;
687 }
688 case K_ANIMATION_NAME: {
689 SetAnimationKeyFrames(view, style);
690 break;
691 }
692 case K_OPACITY: {
693 SetOpacity(view, *style);
694 break;
695 }
696 default: {
697 return false;
698 }
699 }
700 return true;
701 }
702
Invalidate()703 void Component::Invalidate()
704 {
705 UIView *view = GetComponentRootView();
706 if (view == nullptr) {
707 return;
708 }
709 view->Invalidate();
710 }
711
ParseOptions()712 void Component::ParseOptions()
713 {
714 if (JSUndefined::Is(options_)) {
715 HILOG_WARN(HILOG_MODULE_ACE, "options is null");
716 return;
717 }
718
719 if (!JSObject::Is(options_)) {
720 HILOG_WARN(HILOG_MODULE_ACE, "options is not an object type.");
721 return;
722 }
723
724 START_TRACING_WITH_COMPONENT_NAME(RENDER_APPLY_STYLE, componentName_);
725 ApplyStyles(options_, *this);
726 STOP_TRACING();
727
728 START_TRACING(RENDER_PARSE_ATTR);
729 ParseAttrs();
730 STOP_TRACING();
731 START_TRACING(RENDER_PARSE_EVENT);
732 ParseEvents();
733 STOP_TRACING();
734 }
735
SetAnimationKeyFrames(const UIView & view,const AppStyleItem * styleItem)736 void Component::SetAnimationKeyFrames(const UIView &view, const AppStyleItem *styleItem)
737 {
738 if (trans_ == nullptr) {
739 trans_ = new TransitionParams();
740 if (trans_ == nullptr) {
741 HILOG_ERROR(HILOG_MODULE_ACE, "create TransitionParams object error");
742 return;
743 }
744 }
745
746 const char * const value = GetStyleStrValue(styleItem);
747 if (value == nullptr) {
748 HILOG_ERROR(HILOG_MODULE_ACE, "animation name is not string value");
749 return;
750 }
751
752 const AppStyleSheet *styleSheet = GetStyleManager()->GetStyleSheet();
753 if (styleSheet == nullptr) {
754 HILOG_ERROR(HILOG_MODULE_ACE, "styleSheet must set when you set animation attribute");
755 return;
756 }
757 AppStyle *style = styleSheet->GetStyleFromKeyFramesSelectors(value);
758
759 if (style) {
760 const AppStyleItem *item = style->GetFirst();
761 if (item == nullptr) {
762 HILOG_ERROR(HILOG_MODULE_ACE, "keyFrame style is not set!");
763 return;
764 }
765 SetAnimationKeyFrames(item);
766 }
767 }
768
SetAnimationKeyFrames(const AppStyleItem * item)769 void Component::SetAnimationKeyFrames(const AppStyleItem *item)
770 {
771 if (item == nullptr) {
772 HILOG_ERROR(HILOG_MODULE_ACE, "keyFrame style is not set!");
773 return;
774 }
775
776 const int8_t animatorFrom = 1;
777 const int8_t animatorTo = 2;
778
779 isAnimationKeyFramesSet_ = false;
780 while (item) {
781 const char * const itemValue = item->GetStrValue();
782
783 if ((itemValue == nullptr) || (strlen(itemValue) == 0)) {
784 return;
785 }
786 size_t valLength = strlen(itemValue);
787 if (valLength >= UINT8_MAX) {
788 item = item->GetNext();
789 continue;
790 }
791 char *animationValue = reinterpret_cast<char *>(ace_malloc(sizeof(char) * (valLength + 1)));
792 if (animationValue == nullptr) {
793 HILOG_ERROR(HILOG_MODULE_ACE, "malloc animationValue memory heap failed.");
794 return;
795 }
796 if (memcpy_s(animationValue, valLength, itemValue, valLength) != 0) {
797 ace_free(animationValue);
798 animationValue = nullptr;
799 return;
800 }
801 animationValue[valLength] = '\0';
802 int32_t valueTo;
803 int32_t valueFrom;
804 int16_t keyId = item->GetPropNameId();
805 if (keyId == K_OPACITY) {
806 valueTo = GetAnimatorValue(animationValue, animatorTo, true);
807 valueFrom = GetAnimatorValue(animationValue, animatorFrom, true);
808 } else {
809 valueTo = GetAnimatorValue(animationValue, animatorTo);
810 valueFrom = GetAnimatorValue(animationValue, animatorFrom);
811 }
812 ace_free(animationValue);
813 animationValue = nullptr;
814 SetAnimationKeyFrames(keyId, valueFrom, valueTo);
815 item = item->GetNext();
816 }
817 }
818
SetAnimationKeyFrames(int16_t keyId,int32_t valueFrom,int32_t valueTo)819 void Component::SetAnimationKeyFrames(int16_t keyId, int32_t valueFrom, int32_t valueTo)
820 {
821 switch (keyId) {
822 case K_ROTATE:
823 trans_->transformType = const_cast<char *>(TRANSITION_ROTATE);
824 trans_->transform_from = valueFrom;
825 trans_->transform_to = valueTo;
826 isAnimationKeyFramesSet_ = true;
827 break;
828 case K_TRANSLATE_X:
829 trans_->transformType = const_cast<char *>(TRANSITION_TRANSFORM_X);
830 trans_->transform_from = valueFrom;
831 trans_->transform_to = valueTo;
832 isAnimationKeyFramesSet_ = true;
833 break;
834 case K_TRANSLATE_Y:
835 trans_->transformType = const_cast<char *>(TRANSITION_TRANSFORM_Y);
836 trans_->transform_from = valueFrom;
837 trans_->transform_to = valueTo;
838 isAnimationKeyFramesSet_ = true;
839 break;
840 case K_HEIGHT:
841 trans_->height_from = valueFrom;
842 trans_->height_to = valueTo;
843 isAnimationKeyFramesSet_ = true;
844 break;
845 case K_WIDTH:
846 trans_->width_from = valueFrom;
847 trans_->width_to = valueTo;
848 isAnimationKeyFramesSet_ = true;
849 break;
850 case K_BACKGROUND_COLOR:
851 trans_->background_color_from = valueFrom;
852 trans_->background_color_to = valueTo;
853 isAnimationKeyFramesSet_ = true;
854 break;
855 case K_OPACITY:
856 trans_->opacity_from = valueFrom;
857 trans_->opacity_to = valueTo;
858 isAnimationKeyFramesSet_ = true;
859 break;
860 default:
861 break;
862 }
863 }
864
SetAnimationDuration(const AppStyleItem * styleItem,const char * strValue)865 void Component::SetAnimationDuration(const AppStyleItem *styleItem, const char *strValue)
866 {
867 if ((styleItem == nullptr) || (!const_cast<AppStyleItem *>(styleItem)->UpdateNumValToStr())
868 || strValue == nullptr) {
869 HILOG_ERROR(HILOG_MODULE_ACE, "SetAnimationDuration fail");
870 return;
871 }
872
873 if (!IsStyleValueTypeString(styleItem)) {
874 HILOG_ERROR(HILOG_MODULE_ACE, "style animation during value is invalid!");
875 return;
876 }
877 trans_->during = ParseToMilliseconds(strValue);
878 }
879
SetAnimationTimingFunction(const char * strValue,size_t strLen)880 void Component::SetAnimationTimingFunction(const char *strValue, size_t strLen)
881 {
882 if (strValue == nullptr) {
883 HILOG_ERROR(HILOG_MODULE_ACE, "SetAnimationTimingFunction fail");
884 return;
885 }
886
887 uint16_t animationTimingKeyId = KeyParser::ParseKeyId(strValue, strLen);
888 switch (animationTimingKeyId) {
889 case K_EASE_IN:
890 trans_->easing = EasingType::EASE_IN;
891 break;
892 case K_EASE_OUT:
893 trans_->easing = EasingType::EASE_OUT;
894 break;
895 case K_EASE_IN_OUT:
896 trans_->easing = EasingType::EASE_IN_OUT;
897 break;
898 default:
899 trans_->easing = EasingType::LINEAR;
900 break;
901 }
902 }
903
SetAnimationFillMode(const char * strValue,size_t strLen)904 void Component::SetAnimationFillMode(const char *strValue, size_t strLen)
905 {
906 if (strValue == nullptr) {
907 HILOG_ERROR(HILOG_MODULE_ACE, "SetAnimationFillMode fail");
908 return;
909 }
910
911 uint16_t animationFillKeyId = KeyParser::ParseKeyId(strValue, strLen);
912 switch (animationFillKeyId) {
913 case K_FORWARDS:
914 trans_->fill = OptionsFill::FORWARDS;
915 break;
916 default:
917 trans_->fill = OptionsFill::FNONE;
918 break;
919 }
920 }
921
SetAnimationDelay(const AppStyleItem * styleItem,const char * strValue)922 void Component::SetAnimationDelay(const AppStyleItem *styleItem, const char *strValue)
923 {
924 if ((styleItem == nullptr) || (!const_cast<AppStyleItem *>(styleItem)->UpdateNumValToStr())
925 || strValue == nullptr) {
926 HILOG_ERROR(HILOG_MODULE_ACE, "SetAnimationDelay fail");
927 return;
928 }
929
930 if (!IsStyleValueTypeString(styleItem)) {
931 HILOG_ERROR(HILOG_MODULE_ACE, "style animation delay value is invalid!");
932 return;
933 }
934 trans_->delay = ParseToMilliseconds(strValue);
935 }
936
SetAnimationIterationCount(const AppStyleItem * styleItem,const char * strValue)937 void Component::SetAnimationIterationCount(const AppStyleItem *styleItem, const char *strValue)
938 {
939 if ((styleItem == nullptr) || (!const_cast<AppStyleItem *>(styleItem)->UpdateNumValToStr())
940 || strValue == nullptr) {
941 HILOG_ERROR(HILOG_MODULE_ACE, "SetAnimationIterationCount fail");
942 return;
943 }
944
945 if (!IsStyleValueTypeString(styleItem)) {
946 HILOG_ERROR(HILOG_MODULE_ACE, "style iteration count value is invalid!");
947 return;
948 }
949 trans_->iterations = TransitionImpl::GetNumIterations(strValue);
950 }
951
SetAnimationStyle(const UIView & view,const AppStyleItem * styleItem,const int16_t keyId)952 void Component::SetAnimationStyle(const UIView &view, const AppStyleItem *styleItem, const int16_t keyId)
953 {
954 // special for "animation-iteration-count" which value could be a number or string "infinite"
955 if ((styleItem == nullptr) || (!const_cast<AppStyleItem *>(styleItem)->UpdateNumValToStr())) {
956 HILOG_ERROR(HILOG_MODULE_ACE, "SetAnimationStyle fail");
957 return;
958 }
959 if (trans_ == nullptr) {
960 trans_ = new TransitionParams();
961 if (trans_ == nullptr) {
962 HILOG_ERROR(HILOG_MODULE_ACE, "create TransitionParams object error");
963 return;
964 }
965 }
966
967 const char * const strValue = GetStyleStrValue(styleItem);
968 const size_t strLen = GetStyleStrValueLen(styleItem);
969 if (strValue == nullptr) {
970 HILOG_ERROR(HILOG_MODULE_ACE, "animation style item is null");
971 return;
972 }
973 switch (keyId) {
974 case K_ANIMATION_DURATION: {
975 SetAnimationDuration(styleItem, strValue);
976 break;
977 }
978 case K_ANIMATION_TIMING_FUNCTION: {
979 SetAnimationTimingFunction(strValue, strLen);
980 break;
981 }
982 case K_ANIMATION_FILL_MODE: {
983 SetAnimationFillMode(strValue, strLen);
984 break;
985 }
986 case K_ANIMATION_DELAY: {
987 SetAnimationDelay(styleItem, strValue);
988 break;
989 }
990 case K_ANIMATION_ITERATION_COUNT: {
991 SetAnimationIterationCount(styleItem, strValue);
992 break;
993 }
994 default:
995 break;
996 }
997 }
998
AddAnimationToList(const TransitionImpl * transitionImpl) const999 void Component::AddAnimationToList(const TransitionImpl *transitionImpl) const
1000 {
1001 AnimationsNode *animation = new AnimationsNode();
1002 if (animation == nullptr) {
1003 HILOG_ERROR(HILOG_MODULE_ACE, "create animation node error in startAnimation");
1004 return;
1005 }
1006 animation->transitionImpl = const_cast<TransitionImpl *>(transitionImpl);
1007 animation->next = g_animationListHead;
1008 g_animationListHead = animation;
1009 }
1010
RecordAnimation()1011 void Component::RecordAnimation()
1012 {
1013 if (trans_ == nullptr) {
1014 return;
1015 }
1016
1017 if (trans_->during > 0 && isAnimationKeyFramesSet_) {
1018 UIView *uiView = GetComponentRootView();
1019 if (uiView) {
1020 curTransitionImpl_ = new TransitionImpl(*trans_, uiView);
1021 if (curTransitionImpl_ == nullptr) {
1022 HILOG_ERROR(HILOG_MODULE_ACE, "create transitionImpl error");
1023 isAnimationKeyFramesSet_ = false;
1024 return;
1025 }
1026 curTransitionImpl_->Init();
1027 AddAnimationToList(curTransitionImpl_);
1028 isAnimationKeyFramesSet_ = false;
1029 // special for "if" situation, if g_isAnimatorStarted is started means the page has started all the
1030 // animators, and the current component is created by "if" situation, so the animator can start immediately
1031 if (g_isAnimatorStarted) {
1032 curTransitionImpl_->Start();
1033 }
1034 }
1035 }
1036 }
1037
StartAnimation()1038 void Component::StartAnimation()
1039 {
1040 if (trans_ == nullptr) {
1041 return;
1042 }
1043
1044 if (trans_->during > 0 && isAnimationKeyFramesSet_) {
1045 UIView *uiView = GetComponentRootView();
1046 if (uiView) {
1047 if (curTransitionImpl_ != nullptr) {
1048 curTransitionImpl_->Stop();
1049 }
1050 curTransitionImpl_ = new TransitionImpl(*trans_, uiView);
1051 if (curTransitionImpl_ == nullptr) {
1052 HILOG_ERROR(HILOG_MODULE_ACE, "create transitionImpl error!");
1053 isAnimationKeyFramesSet_ = false;
1054 return;
1055 }
1056 curTransitionImpl_->Init();
1057 AddAnimationToList(curTransitionImpl_);
1058 curTransitionImpl_->Start();
1059 isAnimationKeyFramesSet_ = false;
1060 }
1061 }
1062 }
1063
ReleaseTransitionParam()1064 void Component::ReleaseTransitionParam()
1065 {
1066 if (trans_) {
1067 delete trans_;
1068 trans_ = nullptr;
1069 }
1070 }
1071
GetAnimatorValue(char * animatorValue,const int8_t index,bool isOpacity) const1072 int32_t Component::GetAnimatorValue(char *animatorValue, const int8_t index, bool isOpacity) const
1073 {
1074 if ((animatorValue == nullptr) || (strlen(animatorValue) == 0) || (strlen(animatorValue) >= UINT8_MAX)) {
1075 return 0;
1076 }
1077 const int8_t animatorfrom = 1;
1078 const int8_t animatorTo = 2;
1079 if ((index != animatorfrom) && (index != animatorTo)) {
1080 return 0;
1081 }
1082
1083 char *next = nullptr;
1084 // try to get from part
1085 char *value = strtok_s(animatorValue, ANIMATION_VALUE_SEP, &next);
1086 if (index == animatorTo) {
1087 // get to part then if needed
1088 if (value != nullptr) {
1089 value = strtok_s(nullptr, ANIMATION_VALUE_SEP, &next);
1090 }
1091 }
1092 if (value == nullptr) {
1093 HILOG_ERROR(HILOG_MODULE_ACE, "GetAnimatorValue strtok_s failed.");
1094 return 0;
1095 }
1096
1097 int32_t convertedValue =
1098 isOpacity ? (strtod(value, nullptr) * ALPHA_MAX) : static_cast<int32_t>(strtol(value, nullptr, DEC));
1099 if (TransitionImpl::IsEndWith(value, "rad")) {
1100 uint8_t degConversionRate = 57;
1101 convertedValue = convertedValue * degConversionRate;
1102 }
1103 return convertedValue;
1104 }
1105
AddWatcherItem(const jerry_value_t attrKey,const jerry_value_t attrValue,bool isLazyLoading)1106 jerry_value_t Component::AddWatcherItem(const jerry_value_t attrKey, const jerry_value_t attrValue, bool isLazyLoading)
1107 {
1108 (void)(isLazyLoading); // for lazy cases, the process is same currently
1109 jerry_value_t options = jerry_create_object();
1110 JerrySetNamedProperty(options, ARG_WATCH_EL, nativeElement_);
1111 JerrySetNamedProperty(options, ARG_WATCH_ATTR, attrKey);
1112 jerry_value_t watcher = CallJSWatcher(attrValue, WatcherCallbackFunc, options);
1113 jerry_release_value(options);
1114 if (IS_UNDEFINED(watcher) || jerry_value_is_error(watcher)) {
1115 HILOG_ERROR(HILOG_MODULE_ACE, "Failed to create Watcher instance.");
1116 jerry_release_value(watcher); // release error case, note: release undefined is harmless
1117 return UNDEFINED;
1118 }
1119 // watcher is valide, insert it to the list
1120 InsertWatcherCommon(watchersHead_, watcher);
1121
1122 // return the lastValue and need to be released out of this function
1123 return jerryx_get_property_str(watcher, "_lastValue");
1124 }
1125
ParseAttrs()1126 void Component::ParseAttrs()
1127 {
1128 jerry_value_t attrs = jerryx_get_property_str(options_, ATTR_ATTRS);
1129 if (jerry_value_is_undefined(attrs)) {
1130 return;
1131 }
1132
1133 jerry_value_t attrKeys = jerry_get_object_keys(attrs);
1134 if (jerry_value_is_undefined(attrKeys)) {
1135 HILOG_ERROR(HILOG_MODULE_ACE, "None attributes to parse.");
1136 jerry_release_value(attrs);
1137 return;
1138 }
1139
1140 uint16_t length = jerry_get_array_length(attrKeys);
1141 for (uint32_t index = 0; index < length; ++index) {
1142 jerry_value_t attrKey = jerry_get_property_by_index(attrKeys, index);
1143 jerry_value_t attrValue = jerry_get_property(attrs, attrKey);
1144 jerry_value_t newAttrValue = attrValue;
1145 // calculate key ID
1146 uint16_t attrKeyId = ParseKeyIdFromJSString(attrKey);
1147 if (jerry_value_is_function(attrValue)) {
1148 START_TRACING_WITH_COMPONENT_NAME(SET_ATTR_PARSE_EXPRESSION, componentName_);
1149 if (freeze_) {
1150 newAttrValue = JSFunction::Call(attrValue, viewModel_, nullptr, 0);
1151 } else {
1152 #if (FEATURE_LAZY_LOADING_MODULE == 1)
1153 newAttrValue = CallJSFunction(attrValue, viewModel_, nullptr, 0);
1154 JsAppContext *context = JsAppContext::GetInstance();
1155 LazyLoadManager *lazyLoadManager = const_cast<LazyLoadManager *>(context->GetLazyLoadManager());
1156 lazyLoadManager->AddLazyLoadWatcher(nativeElement_, attrKey, attrValue, attrKeyId);
1157 #else
1158 newAttrValue = AddWatcherItem(attrKey, attrValue);
1159 #endif
1160 }
1161 STOP_TRACING();
1162 }
1163
1164 if (attrKeyId != K_UNKNOWN) {
1165 START_TRACING_WITH_EXTRA_INFO(SET_ATTR_SET_TO_NATIVE, componentName_, attrKeyId);
1166 SetAttribute(attrKeyId, newAttrValue);
1167 STOP_TRACING();
1168 }
1169 if (newAttrValue != attrValue) {
1170 // for watcher case, the attrValue is getter, and the newAttrValue is the real value
1171 jerry_release_value(newAttrValue);
1172 }
1173 ReleaseJerryValue(attrKey, attrValue, VA_ARG_END_FLAG);
1174 }
1175 jerry_release_value(attrKeys);
1176 jerry_release_value(attrs);
1177 }
1178
SetClickEventListener(UIView & view,const jerry_value_t eventFunc,bool isStopPropagation)1179 void Component::SetClickEventListener(UIView &view, const jerry_value_t eventFunc, bool isStopPropagation)
1180 {
1181 onClickListener_ = new ViewOnClickListener(viewModel_, eventFunc, isStopPropagation);
1182 if (onClickListener_ == nullptr) {
1183 HILOG_ERROR(HILOG_MODULE_ACE, "click listener create failed");
1184 return;
1185 }
1186
1187 view.SetOnClickListener(onClickListener_);
1188 view.SetTouchable(true);
1189 }
1190
1191 #ifdef JS_EXTRA_EVENT_SUPPORT
SetTouchCancelEventListener(UIView & view,jerry_value_t eventFunc,uint16_t eventTypeId)1192 void Component::SetTouchCancelEventListener(UIView &view, jerry_value_t eventFunc, uint16_t eventTypeId)
1193 {
1194 onTouchCancelListener_ = new ViewOnTouchCancelListener(eventFunc, eventTypeId);
1195 if (onTouchCancelListener_ == nullptr) {
1196 HILOG_ERROR(HILOG_MODULE_ACE, "touch cancel event listener create failed");
1197 return;
1198 }
1199
1200 view.SetOnTouchListener(onTouchCancelListener_);
1201 view.SetTouchable(true);
1202 view.SetDraggable(true);
1203 }
1204
SetKeyBoardEventListener(jerry_value_t eventFunc,uint16_t eventTypeId)1205 void Component::SetKeyBoardEventListener(jerry_value_t eventFunc, uint16_t eventTypeId)
1206 {
1207 RootView *rootView = RootView::GetInstance();
1208 if (rootView == nullptr) {
1209 HILOG_ERROR(HILOG_MODULE_ACE, "get rootView is nullptr");
1210 return;
1211 }
1212 keyBoardEventListener_ = new KeyBoardEventListener(eventFunc, eventTypeId);
1213 if (keyBoardEventListener_ == nullptr) {
1214 HILOG_ERROR(HILOG_MODULE_ACE, "on key borard event listener create failed");
1215 return;
1216 }
1217 rootView->SetOnKeyActListener(keyBoardEventListener_);
1218 }
1219 #endif
1220
SetLongPressEventListener(UIView & view,const jerry_value_t eventFunc,bool isStopPropagation)1221 void Component::SetLongPressEventListener(UIView &view, const jerry_value_t eventFunc, bool isStopPropagation)
1222 {
1223 onLongPressListener_ = new ViewOnLongPressListener(viewModel_, eventFunc, isStopPropagation);
1224 if (onLongPressListener_ == nullptr) {
1225 HILOG_ERROR(HILOG_MODULE_ACE, "long press listener create failed");
1226 return;
1227 }
1228
1229 view.SetOnLongPressListener(onLongPressListener_);
1230 view.SetTouchable(true);
1231 }
1232
SetSwipeEventListener(UIView & view,jerry_value_t eventFunc,bool isStopPropagation)1233 void Component::SetSwipeEventListener(UIView &view, jerry_value_t eventFunc, bool isStopPropagation)
1234 {
1235 if (onTouchListener_ == nullptr) {
1236 onTouchListener_ = new ViewOnTouchListener(viewModel_, isStopPropagation);
1237 }
1238 if (onTouchListener_ == nullptr) {
1239 HILOG_ERROR(HILOG_MODULE_ACE, "DragEnd listener create failed");
1240 return;
1241 }
1242
1243 view.SetOnDragListener(onTouchListener_);
1244 view.SetDraggable(true);
1245 view.SetTouchable(true);
1246
1247 onTouchListener_->SetBindSwipeFuncName(eventFunc);
1248 }
1249
SetTouchStartEventListener(UIView & view,jerry_value_t eventFunc,bool isStopPropagation)1250 void Component::SetTouchStartEventListener(UIView &view, jerry_value_t eventFunc, bool isStopPropagation)
1251 {
1252 if (onTouchListener_ == nullptr) {
1253 onTouchListener_ = new ViewOnTouchListener(viewModel_, isStopPropagation);
1254 }
1255 if (onTouchListener_ == nullptr) {
1256 HILOG_ERROR(HILOG_MODULE_ACE, "DragStart listener create failed");
1257 return;
1258 }
1259
1260 view.SetOnDragListener(onTouchListener_);
1261
1262 view.SetDraggable(true);
1263 view.SetTouchable(true);
1264
1265 onTouchListener_->SetBindTouchStartFuncName(eventFunc);
1266 }
1267
SetTouchMoveEventListener(UIView & view,jerry_value_t eventFunc,bool isStopPropagation)1268 void Component::SetTouchMoveEventListener(UIView &view, jerry_value_t eventFunc, bool isStopPropagation)
1269 {
1270 if (onTouchListener_ == nullptr) {
1271 onTouchListener_ = new ViewOnTouchListener(viewModel_, isStopPropagation);
1272 }
1273 if (onTouchListener_ == nullptr) {
1274 HILOG_ERROR(HILOG_MODULE_ACE, "Drag listener create failed");
1275 return;
1276 }
1277
1278 view.SetOnDragListener(onTouchListener_);
1279 view.SetDraggable(true);
1280 view.SetTouchable(true);
1281
1282 onTouchListener_->SetBindTouchMoveFuncName(eventFunc);
1283 }
1284
SetTouchEndEventListener(UIView & view,jerry_value_t eventFunc,bool isStopPropagation)1285 void Component::SetTouchEndEventListener(UIView &view, jerry_value_t eventFunc, bool isStopPropagation)
1286 {
1287 if (onTouchListener_ == nullptr) {
1288 onTouchListener_ = new ViewOnTouchListener(viewModel_, isStopPropagation);
1289 }
1290 if (onTouchListener_ == nullptr) {
1291 HILOG_ERROR(HILOG_MODULE_ACE, "DragEnd listener create failed");
1292 return;
1293 }
1294
1295 view.SetOnDragListener(onTouchListener_);
1296 view.SetDraggable(true);
1297 view.SetTouchable(true);
1298
1299 onTouchListener_->SetBindTouchEndFuncName(eventFunc);
1300 }
1301
1302 // default implementation
RegisterEventListener(uint16_t eventTypeId,jerry_value_t funcValue,bool isStopPropagation)1303 bool Component::RegisterEventListener(uint16_t eventTypeId, jerry_value_t funcValue, bool isStopPropagation)
1304 {
1305 if (!KeyParser::IsKeyValid(eventTypeId) || IS_UNDEFINED(funcValue)) {
1306 HILOG_ERROR(HILOG_MODULE_ACE, "register event listener failed cause by invalid attribute name or value.");
1307 return false;
1308 }
1309
1310 UIView *uiView = GetComponentRootView();
1311 if (uiView == nullptr) {
1312 HILOG_ERROR(HILOG_MODULE_ACE, "register event listener failed cause by empty view.");
1313 return false;
1314 }
1315
1316 bool registerResult = RegisterPrivateEventListener(eventTypeId, funcValue, isStopPropagation);
1317 if (registerResult) {
1318 return true;
1319 }
1320
1321 return RegisterCommonEventListener(*uiView, eventTypeId, funcValue, isStopPropagation);
1322 }
1323
RegisterCommonEventListener(UIView & view,const uint16_t eventTypeId,const jerry_value_t funcValue,bool isStopPropagation)1324 bool Component::RegisterCommonEventListener(UIView &view,
1325 const uint16_t eventTypeId,
1326 const jerry_value_t funcValue,
1327 bool isStopPropagation)
1328 {
1329 switch (eventTypeId) {
1330 case K_CLICK: {
1331 SetClickEventListener(view, funcValue, isStopPropagation);
1332 break;
1333 }
1334 case K_LONGPRESS: {
1335 SetLongPressEventListener(view, funcValue, isStopPropagation);
1336 break;
1337 }
1338 case K_SWIPE: {
1339 SetSwipeEventListener(view, funcValue, isStopPropagation);
1340 break;
1341 }
1342 case K_TOUCHSTART: {
1343 SetTouchStartEventListener(view, funcValue, isStopPropagation);
1344 break;
1345 }
1346 case K_TOUCHMOVE: {
1347 SetTouchMoveEventListener(view, funcValue, isStopPropagation);
1348 break;
1349 }
1350 case K_TOUCHEND: {
1351 SetTouchEndEventListener(view, funcValue, isStopPropagation);
1352 break;
1353 }
1354
1355 #ifdef JS_EXTRA_EVENT_SUPPORT
1356 case K_KEY: {
1357 SetKeyBoardEventListener(funcValue, eventTypeId);
1358 break;
1359 }
1360 case K_TOUCHCANCEL: {
1361 SetTouchCancelEventListener(view, funcValue, eventTypeId);
1362 break;
1363 }
1364 #endif
1365 default: {
1366 return false;
1367 }
1368 }
1369 return true;
1370 }
1371
ReleaseCommonEventListeners()1372 void Component::ReleaseCommonEventListeners()
1373 {
1374 ACE_DELETE(onClickListener_);
1375 ACE_DELETE(onLongPressListener_);
1376 #ifdef JS_EXTRA_EVENT_SUPPORT
1377 ACE_DELETE(keyBoardEventListener_);
1378 ACE_DELETE(onTouchCancelListener_);
1379 #endif
1380 ACE_DELETE(onTouchListener_);
1381 }
1382
AppendDescriptorOrElements(Component * parent,const JSValue descriptorOrElements)1383 void Component::AppendDescriptorOrElements(Component *parent, const JSValue descriptorOrElements)
1384 {
1385 if (!JSUndefined::Is(descriptorOrElements)) {
1386 uint16_t size = JSArray::Length(descriptorOrElements);
1387 for (uint16_t idx = 0; idx < size; ++idx) {
1388 JSValue descriptorOrElement = JSArray::Get(descriptorOrElements, idx);
1389 AppendDescriptorOrElement(parent, descriptorOrElement);
1390 JSRelease(descriptorOrElement);
1391 }
1392 }
1393 }
1394
InvalidateIfNeeded(uint16_t attrKeyId,bool invalidateSelf) const1395 void Component::InvalidateIfNeeded(uint16_t attrKeyId, bool invalidateSelf) const
1396 {
1397 UIView *uiView = GetComponentRootView();
1398 if ((uiView == nullptr) || !KeyParser::IsKeyValid(attrKeyId)) {
1399 return;
1400 }
1401
1402 if (IsLayoutRelatedAttrs(attrKeyId)) {
1403 if (invalidateSelf) {
1404 uiView->Invalidate();
1405 return;
1406 }
1407 UIView *parent = uiView->GetParent();
1408 if (parent != nullptr) {
1409 parent->LayoutChildren(true);
1410 }
1411 }
1412 }
1413
ParseEvents()1414 void Component::ParseEvents()
1415 {
1416 /*
1417 New JS bundle:
1418 _c('div', {
1419 catchBubbleEvents: {
1420 longpress: _vm.handleLongPress
1421 },
1422 onBubbleEvents: {
1423 swipe: _vm.handleSwipe
1424 }
1425 });
1426
1427 The events bound to 'catchBubbleEvents' field should be stoped propagation,
1428 but the events bound to 'onBubbleEvents' field should not.
1429
1430 Old JS bundle:
1431 _('div', {
1432 on: {
1433 click: _vm.handleClick
1434 },
1435 });
1436 The old framework does not support the event bubble mechanism.
1437 Therefore, the events bound to 'on' field are processed as bound to 'onBubbleEvents' field.
1438 */
1439 BindEvents("on", true);
1440 BindEvents("catchBubbleEvents", true);
1441 BindEvents("onBubbleEvents", false);
1442 }
1443
BindEvents(const char * type,bool isStopPropagation)1444 void Component::BindEvents(const char *type, bool isStopPropagation)
1445 {
1446 JSValue events = JSObject::Get(options_, type);
1447 if (JSUndefined::Is(events)) {
1448 JSRelease(events);
1449 return;
1450 }
1451 JSValue keys = JSObject::Keys(events);
1452 if (JSUndefined::Is(keys)) {
1453 JSRelease(keys);
1454 JSRelease(events);
1455 return;
1456 }
1457 uint16_t length = JSArray::Length(keys);
1458 if (length == 0) {
1459 JSRelease(keys);
1460 JSRelease(events);
1461 return;
1462 }
1463 for (uint16_t idx = 0; idx < length; ++idx) {
1464 JSValue key = JSArray::Get(keys, idx);
1465 JSValue func = JSObject::Get(events, key);
1466
1467 uint16_t keyLength = 0;
1468 char *keyName = MallocStringOf(key, &keyLength);
1469 if (keyLength != 0) {
1470 uint16_t keyId = KeyParser::ParseKeyId(keyName, keyLength);
1471 if (!RegisterEventListener(keyId, func, isStopPropagation)) {
1472 HILOG_ERROR(HILOG_MODULE_ACE, "Register event listener error.");
1473 }
1474 }
1475 ACE_FREE(keyName);
1476 JSRelease(func);
1477 JSRelease(key);
1478 }
1479 JSRelease(keys);
1480 JSRelease(events);
1481 }
1482
SetVisible(UIView & view,const AppStyleItem * styleItem) const1483 void Component::SetVisible(UIView &view, const AppStyleItem *styleItem) const
1484 {
1485 if (!IsStyleValueTypeString(styleItem)) {
1486 HILOG_ERROR(HILOG_MODULE_ACE, "Visible style value is invalid!");
1487 return;
1488 }
1489 const char * const strValue = GetStyleStrValue(styleItem);
1490 if (strValue == nullptr) {
1491 return;
1492 }
1493
1494 uint16_t valueId = KeyParser::ParseKeyId(strValue, GetStyleStrValueLen(styleItem));
1495 view.SetVisible(valueId != K_NONE);
1496 }
1497
SetBackgroundColor(UIView & view,const AppStyleItem & styleItem) const1498 void Component::SetBackgroundColor(UIView &view, const AppStyleItem &styleItem) const
1499 {
1500 uint32_t color = 0;
1501 uint8_t alpha = OPA_OPAQUE;
1502
1503 if (GetStyleColorValue(&styleItem, color, alpha)) {
1504 ColorType backgroundRGBColor = GetRGBColor(color);
1505 view.SetStyle(STYLE_BACKGROUND_COLOR, backgroundRGBColor.full);
1506 view.SetStyle(STYLE_BACKGROUND_OPA, alpha);
1507 }
1508 }
1509
SetOpacity(UIView & view,const AppStyleItem & styleItem) const1510 void Component::SetOpacity(UIView &view, const AppStyleItem &styleItem) const
1511 {
1512 if (styleItem.GetValueType() != STYLE_PROP_VALUE_TYPE_FLOATING) {
1513 return;
1514 }
1515 double opacity = styleItem.GetFloatingValue();
1516 const double opacityMin = 0.0;
1517 const double opacityMax = 1.0;
1518 if (opacity < opacityMin) {
1519 opacity = opacityMin;
1520 } else if (opacity > opacityMax) {
1521 opacity = opacityMax;
1522 }
1523 view.SetOpaScale(static_cast<uint8_t>(opacity * OPA_OPAQUE));
1524 }
1525
SetMargin(UIView & view) const1526 void Component::SetMargin(UIView &view) const
1527 {
1528 SetLeftMargin(view);
1529 SetTopMargin(view);
1530 SetRightMargin(view);
1531 SetBottomMargin(view);
1532 }
1533
SetLeftMargin(UIView & view) const1534 void Component::SetLeftMargin(UIView &view) const
1535 {
1536 if (marginLeft_.type == DimensionType::TYPE_PIXEL) {
1537 view.SetStyle(STYLE_MARGIN_LEFT, marginLeft_.value.pixel);
1538 }
1539 }
1540
SetTopMargin(UIView & view) const1541 void Component::SetTopMargin(UIView &view) const
1542 {
1543 if (marginTop_.type == DimensionType::TYPE_PIXEL) {
1544 view.SetStyle(STYLE_MARGIN_TOP, marginTop_.value.pixel);
1545 }
1546 }
1547
SetRightMargin(UIView & view) const1548 void Component::SetRightMargin(UIView &view) const
1549 {
1550 if (marginRight_.type == DimensionType::TYPE_PIXEL) {
1551 view.SetStyle(STYLE_MARGIN_RIGHT, marginRight_.value.pixel);
1552 }
1553 }
1554
SetBottomMargin(UIView & view) const1555 void Component::SetBottomMargin(UIView &view) const
1556 {
1557 if (marginBottom_.type == DimensionType::TYPE_PIXEL) {
1558 view.SetStyle(STYLE_MARGIN_BOTTOM, marginBottom_.value.pixel);
1559 }
1560 }
1561
SetPadding(UIView & view,const AppStyleItem & styleItem) const1562 void Component::SetPadding(UIView &view, const AppStyleItem &styleItem) const
1563 {
1564 SetLeftPadding(view, styleItem);
1565 SetTopPadding(view, styleItem);
1566 SetRightPadding(view, styleItem);
1567 SetBottomPadding(view, styleItem);
1568 }
1569
SetLeftPadding(UIView & view,const AppStyleItem & styleItem) const1570 void Component::SetLeftPadding(UIView &view, const AppStyleItem &styleItem) const
1571 {
1572 int32_t paddingLeft = GetStylePixelValue(&styleItem);
1573 if (paddingLeft >= 0) {
1574 view.SetStyle(STYLE_PADDING_LEFT, paddingLeft);
1575 }
1576 }
1577
SetTopPadding(UIView & view,const AppStyleItem & styleItem) const1578 void Component::SetTopPadding(UIView &view, const AppStyleItem &styleItem) const
1579 {
1580 int32_t paddingTop = GetStylePixelValue(&styleItem);
1581 if (paddingTop >= 0) {
1582 view.SetStyle(STYLE_PADDING_TOP, paddingTop);
1583 }
1584 }
1585
SetRightPadding(UIView & view,const AppStyleItem & styleItem) const1586 void Component::SetRightPadding(UIView &view, const AppStyleItem &styleItem) const
1587 {
1588 int32_t paddingRight = GetStylePixelValue(&styleItem);
1589 if (paddingRight >= 0) {
1590 view.SetStyle(STYLE_PADDING_RIGHT, paddingRight);
1591 }
1592 }
1593
SetBottomPadding(UIView & view,const AppStyleItem & styleItem) const1594 void Component::SetBottomPadding(UIView &view, const AppStyleItem &styleItem) const
1595 {
1596 int32_t paddingBottom = GetStylePixelValue(&styleItem);
1597 if (paddingBottom >= 0) {
1598 view.SetStyle(STYLE_PADDING_BOTTOM, paddingBottom);
1599 }
1600 }
1601
SetBorderColor(UIView & view,const AppStyleItem & styleItem) const1602 void Component::SetBorderColor(UIView &view, const AppStyleItem &styleItem) const
1603 {
1604 uint32_t color = 0;
1605 uint8_t alpha = OPA_OPAQUE;
1606 if (GetStyleColorValue(&styleItem, color, alpha)) {
1607 view.SetStyle(STYLE_BORDER_COLOR, GetRGBColor(color).full);
1608 view.SetStyle(STYLE_BORDER_OPA, alpha);
1609 }
1610 }
1611
SetBorderRadius(UIView & view,const AppStyleItem & styleItem) const1612 void Component::SetBorderRadius(UIView &view, const AppStyleItem &styleItem) const
1613 {
1614 view.SetStyle(STYLE_BORDER_RADIUS, GetStylePixelValue(&styleItem));
1615 }
1616
SetBorderWidth(UIView & view,const AppStyleItem & styleItem) const1617 void Component::SetBorderWidth(UIView &view, const AppStyleItem &styleItem) const
1618 {
1619 view.SetStyle(STYLE_BORDER_WIDTH, GetStylePixelValue(&styleItem));
1620 }
1621
SetListForWatcher(jerry_value_t getter,jerry_value_t children)1622 jerry_value_t Component::SetListForWatcher(jerry_value_t getter, jerry_value_t children)
1623 {
1624 jerry_value_t options = jerry_create_object();
1625 JerrySetNamedProperty(options, ARG_WATCH_EL, nativeElement_);
1626
1627 jerry_value_t watcher = CallJSWatcher(getter, ListForWatcherCallbackFunc, options);
1628 if (IS_UNDEFINED(watcher) || jerry_value_is_error(watcher)) {
1629 jerry_release_value(watcher); // release error case, note: release undefined is harmless
1630 HILOG_ERROR(HILOG_MODULE_ACE, "Failed to create ListForWatcher instance.");
1631 } else {
1632 InsertWatcherCommon(watchersHead_, watcher);
1633 }
1634 jerry_release_value(options);
1635 return UNDEFINED;
1636 }
1637
HandleListForDireactive()1638 void Component::HandleListForDireactive()
1639 {
1640 uint16_t childrenLength = jerry_get_array_length(descriptors_);
1641 for (uint16_t index = 0; index < childrenLength; index++) {
1642 jerry_value_t child = jerry_get_property_by_index(descriptors_, index);
1643 jerry_value_t getterName = jerry_create_string(reinterpret_cast<const jerry_char_t *>(DESCRIPTOR_ATTR_GETTER));
1644 // add watcher to the array which the getter function returned
1645 if (JerryHasProperty(child, getterName)) {
1646 jerry_value_t getter = jerry_get_property(child, getterName);
1647 SetListForWatcher(getter, descriptors_);
1648 jerry_release_value(getter);
1649 }
1650 ReleaseJerryValue(getterName, child, VA_ARG_END_FLAG);
1651 }
1652 }
1653
AppendChildren(Component * parent)1654 void Component::AppendChildren(Component *parent)
1655 {
1656 if (JSUndefined::Is(descriptors_)) {
1657 return;
1658 }
1659
1660 children_ = JSArray::Create(0);
1661 uint16_t size = JSArray::Length(descriptors_);
1662 for (uint16_t index = 0; index < size; ++index) {
1663 JSValue descriptorOrElement = JSArray::Get(descriptors_, index);
1664 if (!JSUndefined::Is(descriptorOrElement)) {
1665 bool isDescriptor = AppendDescriptorOrElement(parent, descriptorOrElement);
1666 if (isDescriptor) {
1667 CreateDirectiveWatcher(descriptorOrElement);
1668 }
1669 }
1670 JSRelease(descriptorOrElement);
1671 }
1672 }
1673
AppendDescriptorOrElement(Component * parent,const jerry_value_t descriptorOrElement)1674 bool Component::AppendDescriptorOrElement(Component *parent, const jerry_value_t descriptorOrElement)
1675 {
1676 if (DescriptorUtils::IsIfDescriptor(descriptorOrElement)) {
1677 AppendIfDescriptor(parent, descriptorOrElement);
1678 return true;
1679 }
1680
1681 if (DescriptorUtils::IsForDescriptor(descriptorOrElement)) {
1682 AppendForDescriptor(parent, descriptorOrElement);
1683 return true;
1684 }
1685 AppendElement(parent, descriptorOrElement);
1686 return false;
1687 }
1688
AppendIfDescriptor(Component * parent,const jerry_value_t descriptor)1689 void Component::AppendIfDescriptor(Component *parent, const jerry_value_t descriptor)
1690 {
1691 bool isShown = DescriptorUtils::IsIfDescriptorShown(descriptor);
1692 if (isShown) {
1693 JSValue decriptorOrElement = DescriptorUtils::GetDescriptorRendered(descriptor);
1694 if (!JSUndefined::Is(decriptorOrElement)) {
1695 AppendDescriptorOrElement(parent, decriptorOrElement);
1696 JSRelease(decriptorOrElement);
1697 } else {
1698 // Don't release decriptorOrElement
1699 // because decriptorOrElement is the result of jerry_create_object but jerry_get_property
1700 decriptorOrElement = DescriptorUtils::RenderIfDescriptor(descriptor);
1701 AppendDescriptorOrElement(parent, decriptorOrElement);
1702
1703 // does decriptorOrElement need to be release if decriptorOrElement is descriptor
1704 }
1705 } else {
1706 DescriptorUtils::DelIfDescriptorRendered(descriptor);
1707 }
1708 }
1709
AppendForDescriptor(Component * parent,const jerry_value_t descriptor)1710 void Component::AppendForDescriptor(Component *parent, const jerry_value_t descriptor)
1711 {
1712 JSValue descriptorOrelements = DescriptorUtils::GetDescriptorRendered(descriptor);
1713 if (!JSUndefined::Is(descriptorOrelements)) {
1714 AppendDescriptorOrElements(parent, descriptorOrelements);
1715 JSRelease(descriptorOrelements);
1716 } else {
1717 // Don't release decriptorOrElements
1718 // because decriptorOrElements is the result of jerry_create_object but jerry_get_property
1719 descriptorOrelements = DescriptorUtils::RenderForDescriptor(descriptor);
1720 AppendDescriptorOrElements(parent, descriptorOrelements);
1721 }
1722 }
1723
AppendElement(Component * parent,const jerry_value_t element)1724 void Component::AppendElement(Component *parent, const jerry_value_t element)
1725 {
1726 if (parent == nullptr) {
1727 return;
1728 }
1729 Component *component = nullptr;
1730 if (!JSObject::GetNativePointer(element, reinterpret_cast<void **>(&component))) {
1731 // if get binding component native pointer failed from a child element, just release that element
1732 HILOG_ERROR(HILOG_MODULE_ACE, "fatal error, no component is binded to the child element, not allowed.");
1733 // try to release this element and its children, it means we drop them all
1734 DescriptorUtils::ReleaseDescriptorOrElement(element);
1735 return;
1736 }
1737 JSArray::Push(children_, element);
1738 parent->AddChild(component);
1739 }
1740
1741 /*
1742 * NOTE: add one child will not attach the native view immediately, but
1743 * when removing one child, the child native view will be detached immediately
1744 */
AddChild(Component * childNode)1745 void Component::AddChild(Component *childNode)
1746 {
1747 if (childNode == nullptr) {
1748 return;
1749 }
1750
1751 if (childHead_ == nullptr) {
1752 childNode->SetParent(this);
1753 childNode->SetNextSibling(nullptr);
1754 childHead_ = childNode;
1755 return;
1756 }
1757
1758 // find the tail
1759 Component *temp = childHead_;
1760 while ((temp != nullptr) && (temp->GetNextSibling() != nullptr)) {
1761 if (temp == childNode) {
1762 // already added in the list, drop
1763 return;
1764 }
1765 temp = const_cast<Component *>(temp->GetNextSibling());
1766 }
1767 childNode->SetParent(this);
1768 temp->SetNextSibling(childNode);
1769 childNode->SetNextSibling(nullptr);
1770 }
1771
RemoveChild(Component * childNode)1772 void Component::RemoveChild(Component *childNode)
1773 {
1774 if ((childNode == nullptr) || (childHead_ == nullptr)) {
1775 return;
1776 }
1777
1778 UIView *childNativeView = childNode->GetComponentRootView();
1779 UIViewGroup *parentView = reinterpret_cast<UIViewGroup *>(GetComponentRootView());
1780 if (childNativeView == nullptr || parentView == nullptr) {
1781 return;
1782 }
1783
1784 if (childNode == childHead_) {
1785 // it is the head
1786 Component *next = const_cast<Component *>(childHead_->GetNextSibling());
1787 childNode->SetNextSibling(nullptr);
1788 childNode->SetParent(nullptr);
1789 childHead_ = next;
1790 parentView->Remove(childNativeView);
1791 return;
1792 }
1793
1794 // find the target node's pre one
1795 Component *temp = childHead_;
1796 while (temp != nullptr) {
1797 if (temp->GetNextSibling() == childNode) {
1798 // found it
1799 break;
1800 }
1801 temp = const_cast<Component *>(temp->GetNextSibling());
1802 }
1803 if (temp == nullptr) {
1804 // not found
1805 return;
1806 }
1807
1808 temp->SetNextSibling(childNode->GetNextSibling());
1809 childNode->SetNextSibling(nullptr);
1810 childNode->SetParent(nullptr);
1811 parentView->Remove(childNativeView);
1812 }
1813
RemoveAllChildren()1814 void Component::RemoveAllChildren()
1815 {
1816 while (childHead_ != nullptr) {
1817 RemoveChild(childHead_);
1818 }
1819 }
1820
CreateDirectiveWatcher(jerry_value_t descriptor)1821 void Component::CreateDirectiveWatcher(jerry_value_t descriptor)
1822 {
1823 JSValue watcher = DescriptorUtils::CreateDescriptorWatcher(nativeElement_, descriptor);
1824 if (!JSUndefined::Is(watcher)) {
1825 InsertWatcherCommon(watchersHead_, watcher);
1826 }
1827 }
1828
IsAttached() const1829 bool Component::IsAttached() const
1830 {
1831 UIView *nativeView = GetComponentRootView();
1832 if (nativeView == nullptr) {
1833 return false;
1834 }
1835 return (nativeView->GetParent() != nullptr);
1836 }
1837
BuildViewTree(Component * currComponent,Component * parent,const ConstrainedParameter & parentParameter)1838 void Component::BuildViewTree(Component *currComponent, Component *parent, const ConstrainedParameter &parentParameter)
1839 {
1840 if (currComponent == nullptr) {
1841 return;
1842 }
1843
1844 // align self dimension
1845 currComponent->AlignDimensions(parentParameter);
1846 // refresh rect (border box sizing -> content box sizing)
1847 currComponent->AdaptBoxSizing();
1848 // attach to parent, and avoid attaching repeatly
1849 if (parent != nullptr && !currComponent->IsAttached()) {
1850 parent->AttachView(currComponent);
1851 // notify view has been attached to tree, it means the parent's size is already calculated out
1852 currComponent->OnViewAttached();
1853 }
1854
1855 Component *child = const_cast<Component *>(currComponent->GetChildHead());
1856 if (child == nullptr) {
1857 return;
1858 }
1859 // the child only can layout in the content area of parent
1860 ConstrainedParameter alignParameter;
1861 currComponent->GetConstrainedParam(alignParameter);
1862 while (child != nullptr) {
1863 BuildViewTree(child, currComponent, alignParameter);
1864 child = const_cast<Component *>(child->GetNextSibling());
1865 }
1866 // consider how to avoid layout repeatly, for example: div - div -- div
1867 currComponent->LayoutChildren();
1868 }
1869
HandleChildrenChange(jerry_value_t descriptor)1870 void Component::HandleChildrenChange(jerry_value_t descriptor)
1871 {
1872 RemoveAllChildren();
1873 if (!JSUndefined::Is(children_)) {
1874 JSRelease(children_);
1875 children_ = JSArray::Create(0);
1876 }
1877
1878 uint16_t size = JSArray::Length(descriptors_);
1879 for (uint16_t idx = 0; idx < size; ++idx) {
1880 JSValue descriptorOrElement = JSArray::Get(descriptors_, idx);
1881 if (IS_UNDEFINED(descriptorOrElement)) {
1882 continue;
1883 }
1884 if (descriptorOrElement == descriptor) {
1885 UpdateDescriptor(this, descriptorOrElement);
1886 } else {
1887 ReappendDescriptorOrElement(this, descriptorOrElement);
1888 }
1889 JSRelease(descriptorOrElement);
1890 }
1891
1892 Component *parent = const_cast<Component *>(GetParent());
1893 ConstrainedParameter parentParam;
1894 Component *target = (parent == nullptr) ? this : parent;
1895 target->GetConstrainedParam(parentParam);
1896 BuildViewTree(this, nullptr, parentParam);
1897 target->LayoutChildren();
1898 target->Invalidate();
1899 }
1900
UpdateDescriptor(Component * parent,const jerry_value_t descriptor)1901 void Component::UpdateDescriptor(Component *parent, const jerry_value_t descriptor)
1902 {
1903 if (DescriptorUtils::IsIfDescriptor(descriptor)) {
1904 AppendIfDescriptor(parent, descriptor);
1905 } else if (DescriptorUtils::IsForDescriptor(descriptor)) {
1906 // Release descriptor last rendered
1907 DescriptorUtils::DelForDescriptorRendered(descriptor);
1908
1909 // Re-render descriptor
1910 JSValue descriptorOrElements = DescriptorUtils::RenderForDescriptor(descriptor);
1911 AppendDescriptorOrElements(parent, descriptorOrElements);
1912 } else {
1913 // never
1914 }
1915 }
1916
ReappendDescriptorOrElement(Component * parent,const jerry_value_t descriptor)1917 void Component::ReappendDescriptorOrElement(Component *parent, const jerry_value_t descriptor)
1918 {
1919 if (DescriptorUtils::IsIfDescriptor(descriptor)) {
1920 JSValue descriptorOrElement = DescriptorUtils::GetDescriptorRendered(descriptor);
1921 if (!JSUndefined::Is(descriptorOrElement)) {
1922 AppendDescriptorOrElement(parent, descriptor);
1923 }
1924 JSRelease(descriptorOrElement);
1925 } else if (DescriptorUtils::IsForDescriptor(descriptor)) {
1926 JSValue descriptorOrElements = DescriptorUtils::GetDescriptorRendered(descriptor);
1927 if (!JSUndefined::Is(descriptorOrElements)) {
1928 AppendDescriptorOrElements(parent, descriptorOrElements);
1929 }
1930 JSRelease(descriptorOrElements);
1931 } else {
1932 AppendElement(parent, descriptor);
1933 }
1934 }
1935
GetStylePixelValue(const AppStyleItem * style,int32_t defaultValue) const1936 int32_t Component::GetStylePixelValue(const AppStyleItem *style, int32_t defaultValue) const
1937 {
1938 if (style->GetValueType() == STYLE_PROP_VALUE_TYPE_NUMBER) {
1939 return style->GetNumValue();
1940 }
1941 if (style->GetValueType() == STYLE_PROP_VALUE_TYPE_STRING) {
1942 if (style->GetStrValue() == nullptr) {
1943 HILOG_WARN(HILOG_MODULE_ACE, "Get Style PixelValue failed, return default value!");
1944 return defaultValue;
1945 }
1946 return strtol(style->GetStrValue(), nullptr, DEC);
1947 }
1948 return defaultValue;
1949 }
1950
GetStyleDegValue(const AppStyleItem * style,int16_t defaultValue) const1951 int16_t Component::GetStyleDegValue(const AppStyleItem *style, int16_t defaultValue) const
1952 {
1953 if (style->GetValueType() == STYLE_PROP_VALUE_TYPE_NUMBER) {
1954 return style->GetNumValue();
1955 }
1956 if (style->GetValueType() == STYLE_PROP_VALUE_TYPE_STRING) {
1957 if (style->GetStrValue() == nullptr) {
1958 HILOG_WARN(HILOG_MODULE_ACE, "Get Style DegValue failed, return default value!");
1959 return defaultValue;
1960 }
1961 return strtol(style->GetStrValue(), nullptr, DEC);
1962 }
1963 return defaultValue;
1964 }
1965
GetStyleColorValue(const AppStyleItem * style,uint32_t & color,uint8_t & alpha) const1966 bool Component::GetStyleColorValue(const AppStyleItem *style, uint32_t &color, uint8_t &alpha) const
1967 {
1968 if (style->GetValueType() == STYLE_PROP_VALUE_TYPE_NUMBER) {
1969 color = style->GetNumValue();
1970 alpha = OPA_OPAQUE;
1971 return true;
1972 }
1973 if (style->GetValueType() == STYLE_PROP_VALUE_TYPE_STRING) {
1974 return ParseColor(style->GetStrValue(), color, alpha);
1975 }
1976 HILOG_ERROR(HILOG_MODULE_ACE, "invalid color format!");
1977 return false;
1978 }
1979
HandleBackgroundImg(const AppStyleItem & styleItem,char * & pressedImage,char * & normalImage) const1980 bool Component::HandleBackgroundImg(const AppStyleItem &styleItem, char *&pressedImage, char *&normalImage) const
1981 {
1982 bool result = false;
1983 if (styleItem.GetValueType() == STYLE_PROP_VALUE_TYPE_STRING) {
1984 const char * const url = styleItem.GetStrValue();
1985 char *filePath = CreatePathStrFromUrl(url);
1986 if (filePath != nullptr) {
1987 char *imagePath = JsAppContext::GetInstance()->GetResourcePath(filePath);
1988 if (imagePath == nullptr) {
1989 ace_free(filePath);
1990 filePath = nullptr;
1991 return result;
1992 }
1993 if ((styleItem.GetPseudoClassType() == PSEUDO_CLASS_ACTIVE) ||
1994 (styleItem.GetPseudoClassType() == PSEUDO_CLASS_CHECKED)) {
1995 // in case we don't free the buffer after using
1996 ACE_FREE(pressedImage);
1997 pressedImage = imagePath;
1998 } else {
1999 // in case we don't free the buffer after using
2000 ACE_FREE(normalImage);
2001 normalImage = imagePath;
2002 }
2003 ace_free(filePath);
2004 filePath = nullptr;
2005 result = true;
2006 }
2007 }
2008 return result;
2009 }
2010
2011 #if (FEATURE_ROTATION_API == 1)
HandleRotationRequest(const jerry_value_t func,const jerry_value_t dom,const jerry_value_t args[],const jerry_length_t size)2012 jerry_value_t Component::HandleRotationRequest(const jerry_value_t func,
2013 const jerry_value_t dom,
2014 const jerry_value_t args[],
2015 const jerry_length_t size)
2016 {
2017 UNUSED(func);
2018 UIView *bindedView = ComponentUtils::GetViewFromBindingObject(dom);
2019 if (bindedView == nullptr) {
2020 HILOG_ERROR(HILOG_MODULE_ACE, "bindedView is nullptr");
2021 return UNDEFINED;
2022 }
2023
2024 // default action is to request the focus even user do not pass the argument
2025 bool focusRequest = true;
2026 if (args != nullptr && size > 0) {
2027 if (!JerryGetBoolProperty(args[0], ATTR_NAME_FOCUS, focusRequest)) {
2028 HILOG_ERROR(HILOG_MODULE_ACE, "not bool argument passed, will clear the focus!");
2029 focusRequest = false;
2030 }
2031 }
2032 if (focusRequest) {
2033 bindedView->RequestFocus();
2034 } else {
2035 bindedView->ClearFocus();
2036 }
2037
2038 return UNDEFINED;
2039 }
2040 #endif // FEATURE_ROTATION_API
2041 } // namespace ACELite
2042 } // namespace OHOS
2043