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 &currentComponent) 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 &param)
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 &param) 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 
SetAnimationStyle(const UIView & view,const AppStyleItem * styleItem,const int16_t keyId)865 void Component::SetAnimationStyle(const UIView &view, const AppStyleItem *styleItem, const int16_t keyId)
866 {
867     // special for "animation-iteration-count" which value could be a number or string "infinite"
868     if ((styleItem == nullptr) || (!const_cast<AppStyleItem *>(styleItem)->UpdateNumValToStr())) {
869         HILOG_ERROR(HILOG_MODULE_ACE, "SetAnimationStyle fail");
870         return;
871     }
872     if (trans_ == nullptr) {
873         trans_ = new TransitionParams();
874         if (trans_ == nullptr) {
875             HILOG_ERROR(HILOG_MODULE_ACE, "create TransitionParams object error");
876             return;
877         }
878     }
879 
880     const char * const strValue = GetStyleStrValue(styleItem);
881     const size_t strLen = GetStyleStrValueLen(styleItem);
882     if (strValue == nullptr) {
883         HILOG_ERROR(HILOG_MODULE_ACE, "animation style item is null");
884         return;
885     }
886     switch (keyId) {
887         case K_ANIMATION_DURATION: {
888             if (!IsStyleValueTypeString(styleItem)) {
889                 HILOG_ERROR(HILOG_MODULE_ACE, "style animation during value is invalid!");
890                 return;
891             }
892             trans_->during = ParseToMilliseconds(strValue);
893             break;
894         }
895         case K_ANIMATION_TIMING_FUNCTION: {
896             uint16_t animationTimingKeyId = KeyParser::ParseKeyId(strValue, strLen);
897             switch (animationTimingKeyId) {
898                 case K_EASE_IN:
899                     trans_->easing = EasingType::EASE_IN;
900                     break;
901                 case K_EASE_OUT:
902                     trans_->easing = EasingType::EASE_OUT;
903                     break;
904                 case K_EASE_IN_OUT:
905                     trans_->easing = EasingType::EASE_IN_OUT;
906                     break;
907                 default:
908                     trans_->easing = EasingType::LINEAR;
909                     break;
910             }
911             break;
912         }
913         case K_ANIMATION_FILL_MODE: {
914             uint16_t animationFillKeyId = KeyParser::ParseKeyId(strValue, strLen);
915             switch (animationFillKeyId) {
916                 case K_FORWARDS:
917                     trans_->fill = OptionsFill::FORWARDS;
918                     break;
919                 default:
920                     trans_->fill = OptionsFill::FNONE;
921                     break;
922             }
923             break;
924         }
925         case K_ANIMATION_DELAY: {
926             if (!IsStyleValueTypeString(styleItem)) {
927                 HILOG_ERROR(HILOG_MODULE_ACE, "style animation delay value is invalid!");
928                 return;
929             }
930             trans_->delay = ParseToMilliseconds(strValue);
931             break;
932         }
933         case K_ANIMATION_ITERATION_COUNT: {
934             if (!IsStyleValueTypeString(styleItem)) {
935                 HILOG_ERROR(HILOG_MODULE_ACE, "style iteration count value is invalid!");
936                 return;
937             }
938             trans_->iterations = TransitionImpl::GetNumIterations(strValue);
939             break;
940         }
941         default:
942             break;
943     }
944 }
945 
AddAnimationToList(const TransitionImpl * transitionImpl) const946 void Component::AddAnimationToList(const TransitionImpl *transitionImpl) const
947 {
948     AnimationsNode *animation = new AnimationsNode();
949     if (animation == nullptr) {
950         HILOG_ERROR(HILOG_MODULE_ACE, "create animation node error in startAnimation");
951         return;
952     }
953     animation->transitionImpl = const_cast<TransitionImpl *>(transitionImpl);
954     animation->next = g_animationListHead;
955     g_animationListHead = animation;
956 }
957 
RecordAnimation()958 void Component::RecordAnimation()
959 {
960     if (trans_ == nullptr) {
961         return;
962     }
963 
964     if (trans_->during > 0 && isAnimationKeyFramesSet_) {
965         UIView *uiView = GetComponentRootView();
966         if (uiView) {
967             curTransitionImpl_ = new TransitionImpl(*trans_, uiView);
968             if (curTransitionImpl_ == nullptr) {
969                 HILOG_ERROR(HILOG_MODULE_ACE, "create transitionImpl error");
970                 isAnimationKeyFramesSet_ = false;
971                 return;
972             }
973             curTransitionImpl_->Init();
974             AddAnimationToList(curTransitionImpl_);
975             isAnimationKeyFramesSet_ = false;
976             // special for "if" situation, if g_isAnimatorStarted is started means the page has started all the
977             // animators, and the current component is created by "if" situation, so the animator can start immediately
978             if (g_isAnimatorStarted) {
979                 curTransitionImpl_->Start();
980             }
981         }
982     }
983 }
984 
StartAnimation()985 void Component::StartAnimation()
986 {
987     if (trans_ == nullptr) {
988         return;
989     }
990 
991     if (trans_->during > 0 && isAnimationKeyFramesSet_) {
992         UIView *uiView = GetComponentRootView();
993         if (uiView) {
994             if (curTransitionImpl_ != nullptr) {
995                 curTransitionImpl_->Stop();
996             }
997             curTransitionImpl_ = new TransitionImpl(*trans_, uiView);
998             if (curTransitionImpl_ == nullptr) {
999                 HILOG_ERROR(HILOG_MODULE_ACE, "create transitionImpl error!");
1000                 isAnimationKeyFramesSet_ = false;
1001                 return;
1002             }
1003             curTransitionImpl_->Init();
1004             AddAnimationToList(curTransitionImpl_);
1005             curTransitionImpl_->Start();
1006             isAnimationKeyFramesSet_ = false;
1007         }
1008     }
1009 }
1010 
ReleaseTransitionParam()1011 void Component::ReleaseTransitionParam()
1012 {
1013     if (trans_) {
1014         delete trans_;
1015         trans_ = nullptr;
1016     }
1017 }
1018 
GetAnimatorValue(char * animatorValue,const int8_t index,bool isOpacity) const1019 int32_t Component::GetAnimatorValue(char *animatorValue, const int8_t index, bool isOpacity) const
1020 {
1021     if ((animatorValue == nullptr) || (strlen(animatorValue) == 0) || (strlen(animatorValue) >= UINT8_MAX)) {
1022         return 0;
1023     }
1024     const int8_t animatorfrom = 1;
1025     const int8_t animatorTo = 2;
1026     if ((index != animatorfrom) && (index != animatorTo)) {
1027         return 0;
1028     }
1029 
1030     char *next = nullptr;
1031     // try to get from part
1032     char *value = strtok_s(animatorValue, ANIMATION_VALUE_SEP, &next);
1033     if (index == animatorTo) {
1034         // get to part then if needed
1035         if (value != nullptr) {
1036             value = strtok_s(nullptr, ANIMATION_VALUE_SEP, &next);
1037         }
1038     }
1039     if (value == nullptr) {
1040         HILOG_ERROR(HILOG_MODULE_ACE, "GetAnimatorValue strtok_s failed.");
1041         return 0;
1042     }
1043 
1044     int32_t convertedValue =
1045         isOpacity ? (strtod(value, nullptr) * ALPHA_MAX) : static_cast<int32_t>(strtol(value, nullptr, DEC));
1046     if (TransitionImpl::IsEndWith(value, "rad")) {
1047         uint8_t degConversionRate = 57;
1048         convertedValue = convertedValue * degConversionRate;
1049     }
1050     return convertedValue;
1051 }
1052 
AddWatcherItem(const jerry_value_t attrKey,const jerry_value_t attrValue,bool isLazyLoading)1053 jerry_value_t Component::AddWatcherItem(const jerry_value_t attrKey, const jerry_value_t attrValue, bool isLazyLoading)
1054 {
1055     (void)(isLazyLoading); // for lazy cases, the process is same currently
1056     jerry_value_t options = jerry_create_object();
1057     JerrySetNamedProperty(options, ARG_WATCH_EL, nativeElement_);
1058     JerrySetNamedProperty(options, ARG_WATCH_ATTR, attrKey);
1059     jerry_value_t watcher = CallJSWatcher(attrValue, WatcherCallbackFunc, options);
1060     jerry_release_value(options);
1061     if (IS_UNDEFINED(watcher) || jerry_value_is_error(watcher)) {
1062         HILOG_ERROR(HILOG_MODULE_ACE, "Failed to create Watcher instance.");
1063         jerry_release_value(watcher); // release error case, note: release undefined is harmless
1064         return UNDEFINED;
1065     }
1066     // watcher is valide, insert it to the list
1067     InsertWatcherCommon(watchersHead_, watcher);
1068 
1069     // return the lastValue and need to be released out of this function
1070     return jerryx_get_property_str(watcher, "_lastValue");
1071 }
1072 
ParseAttrs()1073 void Component::ParseAttrs()
1074 {
1075     jerry_value_t attrs = jerryx_get_property_str(options_, ATTR_ATTRS);
1076     if (jerry_value_is_undefined(attrs)) {
1077         return;
1078     }
1079 
1080     jerry_value_t attrKeys = jerry_get_object_keys(attrs);
1081     if (jerry_value_is_undefined(attrKeys)) {
1082         HILOG_ERROR(HILOG_MODULE_ACE, "None attributes to parse.");
1083         jerry_release_value(attrs);
1084         return;
1085     }
1086 
1087     uint16_t length = jerry_get_array_length(attrKeys);
1088     for (uint32_t index = 0; index < length; ++index) {
1089         jerry_value_t attrKey = jerry_get_property_by_index(attrKeys, index);
1090         jerry_value_t attrValue = jerry_get_property(attrs, attrKey);
1091         jerry_value_t newAttrValue = attrValue;
1092         // calculate key ID
1093         uint16_t attrKeyId = ParseKeyIdFromJSString(attrKey);
1094         if (jerry_value_is_function(attrValue)) {
1095             START_TRACING_WITH_COMPONENT_NAME(SET_ATTR_PARSE_EXPRESSION, componentName_);
1096             if (freeze_) {
1097                 newAttrValue = JSFunction::Call(attrValue, viewModel_, nullptr, 0);
1098             } else {
1099 #if (FEATURE_LAZY_LOADING_MODULE == 1)
1100                 newAttrValue = CallJSFunction(attrValue, viewModel_, nullptr, 0);
1101                 JsAppContext *context = JsAppContext::GetInstance();
1102                 LazyLoadManager *lazyLoadManager = const_cast<LazyLoadManager *>(context->GetLazyLoadManager());
1103                 lazyLoadManager->AddLazyLoadWatcher(nativeElement_, attrKey, attrValue, attrKeyId);
1104 #else
1105                 newAttrValue = AddWatcherItem(attrKey, attrValue);
1106 #endif
1107             }
1108             STOP_TRACING();
1109         }
1110 
1111         if (attrKeyId != K_UNKNOWN) {
1112             START_TRACING_WITH_EXTRA_INFO(SET_ATTR_SET_TO_NATIVE, componentName_, attrKeyId);
1113             SetAttribute(attrKeyId, newAttrValue);
1114             STOP_TRACING();
1115         }
1116         if (newAttrValue != attrValue) {
1117             // for watcher case, the attrValue is getter, and the newAttrValue is the real value
1118             jerry_release_value(newAttrValue);
1119         }
1120         ReleaseJerryValue(attrKey, attrValue, VA_ARG_END_FLAG);
1121     }
1122     jerry_release_value(attrKeys);
1123     jerry_release_value(attrs);
1124 }
1125 
SetClickEventListener(UIView & view,const jerry_value_t eventFunc,bool isStopPropagation)1126 void Component::SetClickEventListener(UIView &view, const jerry_value_t eventFunc, bool isStopPropagation)
1127 {
1128     onClickListener_ = new ViewOnClickListener(viewModel_, eventFunc, isStopPropagation);
1129     if (onClickListener_ == nullptr) {
1130         HILOG_ERROR(HILOG_MODULE_ACE, "click listener create failed");
1131         return;
1132     }
1133 
1134     view.SetOnClickListener(onClickListener_);
1135     view.SetTouchable(true);
1136 }
1137 
1138 #ifdef JS_EXTRA_EVENT_SUPPORT
SetTouchCancelEventListener(UIView & view,jerry_value_t eventFunc,uint16_t eventTypeId)1139 void Component::SetTouchCancelEventListener(UIView &view, jerry_value_t eventFunc, uint16_t eventTypeId)
1140 {
1141     onTouchCancelListener_ = new ViewOnTouchCancelListener(eventFunc, eventTypeId);
1142     if (onTouchCancelListener_ == nullptr) {
1143         HILOG_ERROR(HILOG_MODULE_ACE, "touch cancel event listener create failed");
1144         return;
1145     }
1146 
1147     view.SetOnTouchListener(onTouchCancelListener_);
1148     view.SetTouchable(true);
1149     view.SetDraggable(true);
1150 }
1151 
SetKeyBoardEventListener(jerry_value_t eventFunc,uint16_t eventTypeId)1152 void Component::SetKeyBoardEventListener(jerry_value_t eventFunc, uint16_t eventTypeId)
1153 {
1154     RootView *rootView = RootView::GetInstance();
1155     if (rootView == nullptr) {
1156         HILOG_ERROR(HILOG_MODULE_ACE, "get rootView is nullptr");
1157         return;
1158     }
1159     keyBoardEventListener_ = new KeyBoardEventListener(eventFunc, eventTypeId);
1160     if (keyBoardEventListener_ == nullptr) {
1161         HILOG_ERROR(HILOG_MODULE_ACE, "on key borard event listener create failed");
1162         return;
1163     }
1164     rootView->SetOnKeyActListener(keyBoardEventListener_);
1165 }
1166 #endif
1167 
SetLongPressEventListener(UIView & view,const jerry_value_t eventFunc,bool isStopPropagation)1168 void Component::SetLongPressEventListener(UIView &view, const jerry_value_t eventFunc, bool isStopPropagation)
1169 {
1170     onLongPressListener_ = new ViewOnLongPressListener(viewModel_, eventFunc, isStopPropagation);
1171     if (onLongPressListener_ == nullptr) {
1172         HILOG_ERROR(HILOG_MODULE_ACE, "long press listener create failed");
1173         return;
1174     }
1175 
1176     view.SetOnLongPressListener(onLongPressListener_);
1177     view.SetTouchable(true);
1178 }
1179 
SetSwipeEventListener(UIView & view,jerry_value_t eventFunc,bool isStopPropagation)1180 void Component::SetSwipeEventListener(UIView &view, jerry_value_t eventFunc, bool isStopPropagation)
1181 {
1182     if (onTouchListener_ == nullptr) {
1183         onTouchListener_ = new ViewOnTouchListener(viewModel_, isStopPropagation);
1184     }
1185     if (onTouchListener_ == nullptr) {
1186         HILOG_ERROR(HILOG_MODULE_ACE, "DragEnd listener create failed");
1187         return;
1188     }
1189 
1190     view.SetOnDragListener(onTouchListener_);
1191     view.SetDraggable(true);
1192     view.SetTouchable(true);
1193 
1194     onTouchListener_->SetBindSwipeFuncName(eventFunc);
1195 }
1196 
SetTouchStartEventListener(UIView & view,jerry_value_t eventFunc,bool isStopPropagation)1197 void Component::SetTouchStartEventListener(UIView &view, jerry_value_t eventFunc, bool isStopPropagation)
1198 {
1199     if (onTouchListener_ == nullptr) {
1200         onTouchListener_ = new ViewOnTouchListener(viewModel_, isStopPropagation);
1201     }
1202     if (onTouchListener_ == nullptr) {
1203         HILOG_ERROR(HILOG_MODULE_ACE, "DragStart listener create failed");
1204         return;
1205     }
1206 
1207     view.SetOnDragListener(onTouchListener_);
1208 
1209     view.SetDraggable(true);
1210     view.SetTouchable(true);
1211 
1212     onTouchListener_->SetBindTouchStartFuncName(eventFunc);
1213 }
1214 
SetTouchMoveEventListener(UIView & view,jerry_value_t eventFunc,bool isStopPropagation)1215 void Component::SetTouchMoveEventListener(UIView &view, jerry_value_t eventFunc, bool isStopPropagation)
1216 {
1217     if (onTouchListener_ == nullptr) {
1218         onTouchListener_ = new ViewOnTouchListener(viewModel_, isStopPropagation);
1219     }
1220     if (onTouchListener_ == nullptr) {
1221         HILOG_ERROR(HILOG_MODULE_ACE, "Drag listener create failed");
1222         return;
1223     }
1224 
1225     view.SetOnDragListener(onTouchListener_);
1226     view.SetDraggable(true);
1227     view.SetTouchable(true);
1228 
1229     onTouchListener_->SetBindTouchMoveFuncName(eventFunc);
1230 }
1231 
SetTouchEndEventListener(UIView & view,jerry_value_t eventFunc,bool isStopPropagation)1232 void Component::SetTouchEndEventListener(UIView &view, jerry_value_t eventFunc, bool isStopPropagation)
1233 {
1234     if (onTouchListener_ == nullptr) {
1235         onTouchListener_ = new ViewOnTouchListener(viewModel_, isStopPropagation);
1236     }
1237     if (onTouchListener_ == nullptr) {
1238         HILOG_ERROR(HILOG_MODULE_ACE, "DragEnd listener create failed");
1239         return;
1240     }
1241 
1242     view.SetOnDragListener(onTouchListener_);
1243     view.SetDraggable(true);
1244     view.SetTouchable(true);
1245 
1246     onTouchListener_->SetBindTouchEndFuncName(eventFunc);
1247 }
1248 
1249 // default implementation
RegisterEventListener(uint16_t eventTypeId,jerry_value_t funcValue,bool isStopPropagation)1250 bool Component::RegisterEventListener(uint16_t eventTypeId, jerry_value_t funcValue, bool isStopPropagation)
1251 {
1252     if (!KeyParser::IsKeyValid(eventTypeId) || IS_UNDEFINED(funcValue)) {
1253         HILOG_ERROR(HILOG_MODULE_ACE, "register event listener failed cause by invalid attribute name or value.");
1254         return false;
1255     }
1256 
1257     UIView *uiView = GetComponentRootView();
1258     if (uiView == nullptr) {
1259         HILOG_ERROR(HILOG_MODULE_ACE, "register event listener failed cause by empty view.");
1260         return false;
1261     }
1262 
1263     bool registerResult = RegisterPrivateEventListener(eventTypeId, funcValue, isStopPropagation);
1264     if (registerResult) {
1265         return true;
1266     }
1267 
1268     return RegisterCommonEventListener(*uiView, eventTypeId, funcValue, isStopPropagation);
1269 }
1270 
RegisterCommonEventListener(UIView & view,const uint16_t eventTypeId,const jerry_value_t funcValue,bool isStopPropagation)1271 bool Component::RegisterCommonEventListener(UIView &view,
1272                                             const uint16_t eventTypeId,
1273                                             const jerry_value_t funcValue,
1274                                             bool isStopPropagation)
1275 {
1276     switch (eventTypeId) {
1277         case K_CLICK: {
1278             SetClickEventListener(view, funcValue, isStopPropagation);
1279             break;
1280         }
1281         case K_LONGPRESS: {
1282             SetLongPressEventListener(view, funcValue, isStopPropagation);
1283             break;
1284         }
1285         case K_SWIPE: {
1286             SetSwipeEventListener(view, funcValue, isStopPropagation);
1287             break;
1288         }
1289         case K_TOUCHSTART: {
1290             SetTouchStartEventListener(view, funcValue, isStopPropagation);
1291             break;
1292         }
1293         case K_TOUCHMOVE: {
1294             SetTouchMoveEventListener(view, funcValue, isStopPropagation);
1295             break;
1296         }
1297         case K_TOUCHEND: {
1298             SetTouchEndEventListener(view, funcValue, isStopPropagation);
1299             break;
1300         }
1301 
1302 #ifdef JS_EXTRA_EVENT_SUPPORT
1303         case K_KEY: {
1304             SetKeyBoardEventListener(funcValue, eventTypeId);
1305             break;
1306         }
1307         case K_TOUCHCANCEL: {
1308             SetTouchCancelEventListener(view, funcValue, eventTypeId);
1309             break;
1310         }
1311 #endif
1312         default: {
1313             return false;
1314         }
1315     }
1316     return true;
1317 }
1318 
ReleaseCommonEventListeners()1319 void Component::ReleaseCommonEventListeners()
1320 {
1321     ACE_DELETE(onClickListener_);
1322     ACE_DELETE(onLongPressListener_);
1323 #ifdef JS_EXTRA_EVENT_SUPPORT
1324     ACE_DELETE(keyBoardEventListener_);
1325     ACE_DELETE(onTouchCancelListener_);
1326 #endif
1327     ACE_DELETE(onTouchListener_);
1328 }
1329 
AppendDescriptorOrElements(Component * parent,const JSValue descriptorOrElements)1330 void Component::AppendDescriptorOrElements(Component *parent, const JSValue descriptorOrElements)
1331 {
1332     if (!JSUndefined::Is(descriptorOrElements)) {
1333         uint16_t size = JSArray::Length(descriptorOrElements);
1334         for (uint16_t idx = 0; idx < size; ++idx) {
1335             JSValue descriptorOrElement = JSArray::Get(descriptorOrElements, idx);
1336             AppendDescriptorOrElement(parent, descriptorOrElement);
1337             JSRelease(descriptorOrElement);
1338         }
1339     }
1340 }
1341 
InvalidateIfNeeded(uint16_t attrKeyId,bool invalidateSelf) const1342 void Component::InvalidateIfNeeded(uint16_t attrKeyId, bool invalidateSelf) const
1343 {
1344     UIView *uiView = GetComponentRootView();
1345     if ((uiView == nullptr) || !KeyParser::IsKeyValid(attrKeyId)) {
1346         return;
1347     }
1348 
1349     if (IsLayoutRelatedAttrs(attrKeyId)) {
1350         if (invalidateSelf) {
1351             uiView->Invalidate();
1352             return;
1353         }
1354         UIView *parent = uiView->GetParent();
1355         if (parent != nullptr) {
1356             parent->LayoutChildren(true);
1357         }
1358     }
1359 }
1360 
ParseEvents()1361 void Component::ParseEvents()
1362 {
1363     /*
1364      New JS bundle:
1365      _c('div', {
1366          catchBubbleEvents: {
1367              longpress: _vm.handleLongPress
1368          },
1369          onBubbleEvents: {
1370              swipe: _vm.handleSwipe
1371          }
1372      });
1373 
1374      The events bound to 'catchBubbleEvents' field should be stoped propagation,
1375      but the events bound to 'onBubbleEvents' field should not.
1376 
1377      Old JS bundle:
1378      _('div', {
1379          on: {
1380              click: _vm.handleClick
1381          },
1382      });
1383      The old framework does not support the event bubble mechanism.
1384      Therefore, the events bound to 'on' field are processed as bound to 'onBubbleEvents' field.
1385     */
1386     BindEvents("on", true);
1387     BindEvents("catchBubbleEvents", true);
1388     BindEvents("onBubbleEvents", false);
1389 }
1390 
BindEvents(const char * type,bool isStopPropagation)1391 void Component::BindEvents(const char *type, bool isStopPropagation)
1392 {
1393     JSValue events = JSObject::Get(options_, type);
1394     if (JSUndefined::Is(events)) {
1395         JSRelease(events);
1396         return;
1397     }
1398     JSValue keys = JSObject::Keys(events);
1399     if (JSUndefined::Is(keys)) {
1400         JSRelease(keys);
1401         JSRelease(events);
1402         return;
1403     }
1404     uint16_t length = JSArray::Length(keys);
1405     if (length == 0) {
1406         JSRelease(keys);
1407         JSRelease(events);
1408         return;
1409     }
1410     for (uint16_t idx = 0; idx < length; ++idx) {
1411         JSValue key = JSArray::Get(keys, idx);
1412         JSValue func = JSObject::Get(events, key);
1413 
1414         uint16_t keyLength = 0;
1415         char *keyName = MallocStringOf(key, &keyLength);
1416         if (keyLength != 0) {
1417             uint16_t keyId = KeyParser::ParseKeyId(keyName, keyLength);
1418             if (!RegisterEventListener(keyId, func, isStopPropagation)) {
1419                 HILOG_ERROR(HILOG_MODULE_ACE, "Register event listener error.");
1420             }
1421         }
1422         ACE_FREE(keyName);
1423         JSRelease(func);
1424         JSRelease(key);
1425     }
1426     JSRelease(keys);
1427     JSRelease(events);
1428 }
1429 
SetVisible(UIView & view,const AppStyleItem * styleItem) const1430 void Component::SetVisible(UIView &view, const AppStyleItem *styleItem) const
1431 {
1432     if (!IsStyleValueTypeString(styleItem)) {
1433         HILOG_ERROR(HILOG_MODULE_ACE, "Visible style value is invalid!");
1434         return;
1435     }
1436     const char * const strValue = GetStyleStrValue(styleItem);
1437     if (strValue == nullptr) {
1438         return;
1439     }
1440 
1441     uint16_t valueId = KeyParser::ParseKeyId(strValue, GetStyleStrValueLen(styleItem));
1442     view.SetVisible(valueId != K_NONE);
1443 }
1444 
SetBackgroundColor(UIView & view,const AppStyleItem & styleItem) const1445 void Component::SetBackgroundColor(UIView &view, const AppStyleItem &styleItem) const
1446 {
1447     uint32_t color = 0;
1448     uint8_t alpha = OPA_OPAQUE;
1449 
1450     if (GetStyleColorValue(&styleItem, color, alpha)) {
1451         ColorType backgroundRGBColor = GetRGBColor(color);
1452         view.SetStyle(STYLE_BACKGROUND_COLOR, backgroundRGBColor.full);
1453         view.SetStyle(STYLE_BACKGROUND_OPA, alpha);
1454     }
1455 }
1456 
SetOpacity(UIView & view,const AppStyleItem & styleItem) const1457 void Component::SetOpacity(UIView &view, const AppStyleItem &styleItem) const
1458 {
1459     if (styleItem.GetValueType() != STYLE_PROP_VALUE_TYPE_FLOATING) {
1460         return;
1461     }
1462     double opacity = styleItem.GetFloatingValue();
1463     const double opacityMin = 0.0;
1464     const double opacityMax = 1.0;
1465     if (opacity < opacityMin) {
1466         opacity = opacityMin;
1467     } else if (opacity > opacityMax) {
1468         opacity = opacityMax;
1469     }
1470     view.SetOpaScale(static_cast<uint8_t>(opacity * OPA_OPAQUE));
1471 }
1472 
SetMargin(UIView & view) const1473 void Component::SetMargin(UIView &view) const
1474 {
1475     SetLeftMargin(view);
1476     SetTopMargin(view);
1477     SetRightMargin(view);
1478     SetBottomMargin(view);
1479 }
1480 
SetLeftMargin(UIView & view) const1481 void Component::SetLeftMargin(UIView &view) const
1482 {
1483     if (marginLeft_.type == DimensionType::TYPE_PIXEL) {
1484         view.SetStyle(STYLE_MARGIN_LEFT, marginLeft_.value.pixel);
1485     }
1486 }
1487 
SetTopMargin(UIView & view) const1488 void Component::SetTopMargin(UIView &view) const
1489 {
1490     if (marginTop_.type == DimensionType::TYPE_PIXEL) {
1491         view.SetStyle(STYLE_MARGIN_TOP, marginTop_.value.pixel);
1492     }
1493 }
1494 
SetRightMargin(UIView & view) const1495 void Component::SetRightMargin(UIView &view) const
1496 {
1497     if (marginRight_.type == DimensionType::TYPE_PIXEL) {
1498         view.SetStyle(STYLE_MARGIN_RIGHT, marginRight_.value.pixel);
1499     }
1500 }
1501 
SetBottomMargin(UIView & view) const1502 void Component::SetBottomMargin(UIView &view) const
1503 {
1504     if (marginBottom_.type == DimensionType::TYPE_PIXEL) {
1505         view.SetStyle(STYLE_MARGIN_BOTTOM, marginBottom_.value.pixel);
1506     }
1507 }
1508 
SetPadding(UIView & view,const AppStyleItem & styleItem) const1509 void Component::SetPadding(UIView &view, const AppStyleItem &styleItem) const
1510 {
1511     SetLeftPadding(view, styleItem);
1512     SetTopPadding(view, styleItem);
1513     SetRightPadding(view, styleItem);
1514     SetBottomPadding(view, styleItem);
1515 }
1516 
SetLeftPadding(UIView & view,const AppStyleItem & styleItem) const1517 void Component::SetLeftPadding(UIView &view, const AppStyleItem &styleItem) const
1518 {
1519     int32_t paddingLeft = GetStylePixelValue(&styleItem);
1520     if (paddingLeft >= 0) {
1521         view.SetStyle(STYLE_PADDING_LEFT, paddingLeft);
1522     }
1523 }
1524 
SetTopPadding(UIView & view,const AppStyleItem & styleItem) const1525 void Component::SetTopPadding(UIView &view, const AppStyleItem &styleItem) const
1526 {
1527     int32_t paddingTop = GetStylePixelValue(&styleItem);
1528     if (paddingTop >= 0) {
1529         view.SetStyle(STYLE_PADDING_TOP, paddingTop);
1530     }
1531 }
1532 
SetRightPadding(UIView & view,const AppStyleItem & styleItem) const1533 void Component::SetRightPadding(UIView &view, const AppStyleItem &styleItem) const
1534 {
1535     int32_t paddingRight = GetStylePixelValue(&styleItem);
1536     if (paddingRight >= 0) {
1537         view.SetStyle(STYLE_PADDING_RIGHT, paddingRight);
1538     }
1539 }
1540 
SetBottomPadding(UIView & view,const AppStyleItem & styleItem) const1541 void Component::SetBottomPadding(UIView &view, const AppStyleItem &styleItem) const
1542 {
1543     int32_t paddingBottom = GetStylePixelValue(&styleItem);
1544     if (paddingBottom >= 0) {
1545         view.SetStyle(STYLE_PADDING_BOTTOM, paddingBottom);
1546     }
1547 }
1548 
SetBorderColor(UIView & view,const AppStyleItem & styleItem) const1549 void Component::SetBorderColor(UIView &view, const AppStyleItem &styleItem) const
1550 {
1551     uint32_t color = 0;
1552     uint8_t alpha = OPA_OPAQUE;
1553     if (GetStyleColorValue(&styleItem, color, alpha)) {
1554         view.SetStyle(STYLE_BORDER_COLOR, GetRGBColor(color).full);
1555         view.SetStyle(STYLE_BORDER_OPA, alpha);
1556     }
1557 }
1558 
SetBorderRadius(UIView & view,const AppStyleItem & styleItem) const1559 void Component::SetBorderRadius(UIView &view, const AppStyleItem &styleItem) const
1560 {
1561     view.SetStyle(STYLE_BORDER_RADIUS, GetStylePixelValue(&styleItem));
1562 }
1563 
SetBorderWidth(UIView & view,const AppStyleItem & styleItem) const1564 void Component::SetBorderWidth(UIView &view, const AppStyleItem &styleItem) const
1565 {
1566     view.SetStyle(STYLE_BORDER_WIDTH, GetStylePixelValue(&styleItem));
1567 }
1568 
SetListForWatcher(jerry_value_t getter,jerry_value_t children)1569 jerry_value_t Component::SetListForWatcher(jerry_value_t getter, jerry_value_t children)
1570 {
1571     jerry_value_t options = jerry_create_object();
1572     JerrySetNamedProperty(options, ARG_WATCH_EL, nativeElement_);
1573 
1574     jerry_value_t watcher = CallJSWatcher(getter, ListForWatcherCallbackFunc, options);
1575     if (IS_UNDEFINED(watcher) || jerry_value_is_error(watcher)) {
1576         jerry_release_value(watcher); // release error case, note: release undefined is harmless
1577         HILOG_ERROR(HILOG_MODULE_ACE, "Failed to create ListForWatcher instance.");
1578     } else {
1579         InsertWatcherCommon(watchersHead_, watcher);
1580     }
1581     jerry_release_value(options);
1582     return UNDEFINED;
1583 }
1584 
HandleListForDireactive()1585 void Component::HandleListForDireactive()
1586 {
1587     uint16_t childrenLength = jerry_get_array_length(descriptors_);
1588     for (uint16_t index = 0; index < childrenLength; index++) {
1589         jerry_value_t child = jerry_get_property_by_index(descriptors_, index);
1590         jerry_value_t getterName = jerry_create_string(reinterpret_cast<const jerry_char_t *>(DESCRIPTOR_ATTR_GETTER));
1591         // add watcher to the array which the getter function returned
1592         if (JerryHasProperty(child, getterName)) {
1593             jerry_value_t getter = jerry_get_property(child, getterName);
1594             SetListForWatcher(getter, descriptors_);
1595             jerry_release_value(getter);
1596         }
1597         ReleaseJerryValue(getterName, child, VA_ARG_END_FLAG);
1598     }
1599 }
1600 
AppendChildren(Component * parent)1601 void Component::AppendChildren(Component *parent)
1602 {
1603     if (JSUndefined::Is(descriptors_)) {
1604         return;
1605     }
1606 
1607     children_ = JSArray::Create(0);
1608     uint16_t size = JSArray::Length(descriptors_);
1609     for (uint16_t index = 0; index < size; ++index) {
1610         JSValue descriptorOrElement = JSArray::Get(descriptors_, index);
1611         if (!JSUndefined::Is(descriptorOrElement)) {
1612             bool isDescriptor = AppendDescriptorOrElement(parent, descriptorOrElement);
1613             if (isDescriptor) {
1614                 CreateDirectiveWatcher(descriptorOrElement);
1615             }
1616         }
1617         JSRelease(descriptorOrElement);
1618     }
1619 }
1620 
AppendDescriptorOrElement(Component * parent,const jerry_value_t descriptorOrElement)1621 bool Component::AppendDescriptorOrElement(Component *parent, const jerry_value_t descriptorOrElement)
1622 {
1623     if (DescriptorUtils::IsIfDescriptor(descriptorOrElement)) {
1624         AppendIfDescriptor(parent, descriptorOrElement);
1625         return true;
1626     }
1627 
1628     if (DescriptorUtils::IsForDescriptor(descriptorOrElement)) {
1629         AppendForDescriptor(parent, descriptorOrElement);
1630         return true;
1631     }
1632     AppendElement(parent, descriptorOrElement);
1633     return false;
1634 }
1635 
AppendIfDescriptor(Component * parent,const jerry_value_t descriptor)1636 void Component::AppendIfDescriptor(Component *parent, const jerry_value_t descriptor)
1637 {
1638     bool isShown = DescriptorUtils::IsIfDescriptorShown(descriptor);
1639     if (isShown) {
1640         JSValue decriptorOrElement = DescriptorUtils::GetDescriptorRendered(descriptor);
1641         if (!JSUndefined::Is(decriptorOrElement)) {
1642             AppendDescriptorOrElement(parent, decriptorOrElement);
1643             JSRelease(decriptorOrElement);
1644         } else {
1645             // Don't release decriptorOrElement
1646             // because decriptorOrElement is the result of jerry_create_object but jerry_get_property
1647             decriptorOrElement = DescriptorUtils::RenderIfDescriptor(descriptor);
1648             AppendDescriptorOrElement(parent, decriptorOrElement);
1649 
1650             // does decriptorOrElement need to be release if decriptorOrElement is descriptor
1651         }
1652     } else {
1653         DescriptorUtils::DelIfDescriptorRendered(descriptor);
1654     }
1655 }
AppendForDescriptor(Component * parent,const jerry_value_t descriptor)1656 void Component::AppendForDescriptor(Component *parent, const jerry_value_t descriptor)
1657 {
1658     JSValue descriptorOrelements = DescriptorUtils::GetDescriptorRendered(descriptor);
1659     if (!JSUndefined::Is(descriptorOrelements)) {
1660         AppendDescriptorOrElements(parent, descriptorOrelements);
1661         JSRelease(descriptorOrelements);
1662     } else {
1663         // Don't release decriptorOrElements
1664         // because decriptorOrElements is the result of jerry_create_object but jerry_get_property
1665         descriptorOrelements = DescriptorUtils::RenderForDescriptor(descriptor);
1666         AppendDescriptorOrElements(parent, descriptorOrelements);
1667     }
1668 }
AppendElement(Component * parent,const jerry_value_t element)1669 void Component::AppendElement(Component *parent, const jerry_value_t element)
1670 {
1671     if (parent == nullptr) {
1672         return;
1673     }
1674     Component *component = nullptr;
1675     if (!JSObject::GetNativePointer(element, reinterpret_cast<void **>(&component))) {
1676         // if get binding component native pointer failed from a child element, just release that element
1677         HILOG_ERROR(HILOG_MODULE_ACE, "fatal error, no component is binded to the child element, not allowed.");
1678         // try to release this element and its children, it means we drop them all
1679         DescriptorUtils::ReleaseDescriptorOrElement(element);
1680         return;
1681     }
1682     JSArray::Push(children_, element);
1683     parent->AddChild(component);
1684 }
1685 
1686 /*
1687  * NOTE: add one child will not attach the native view immediately, but
1688  * when removing one child, the child native view will be detached immediately
1689  */
AddChild(Component * childNode)1690 void Component::AddChild(Component *childNode)
1691 {
1692     if (childNode == nullptr) {
1693         return;
1694     }
1695 
1696     if (childHead_ == nullptr) {
1697         childNode->SetParent(this);
1698         childNode->SetNextSibling(nullptr);
1699         childHead_ = childNode;
1700         return;
1701     }
1702 
1703     // find the tail
1704     Component *temp = childHead_;
1705     while ((temp != nullptr) && (temp->GetNextSibling() != nullptr)) {
1706         if (temp == childNode) {
1707             // already added in the list, drop
1708             return;
1709         }
1710         temp = const_cast<Component *>(temp->GetNextSibling());
1711     }
1712     childNode->SetParent(this);
1713     temp->SetNextSibling(childNode);
1714     childNode->SetNextSibling(nullptr);
1715 }
1716 
RemoveChild(Component * childNode)1717 void Component::RemoveChild(Component *childNode)
1718 {
1719     if ((childNode == nullptr) || (childHead_ == nullptr)) {
1720         return;
1721     }
1722 
1723     UIView *childNativeView = childNode->GetComponentRootView();
1724     UIViewGroup *parentView = reinterpret_cast<UIViewGroup *>(GetComponentRootView());
1725     if (childNativeView == nullptr || parentView == nullptr) {
1726         return;
1727     }
1728 
1729     if (childNode == childHead_) {
1730         // it is the head
1731         Component *next = const_cast<Component *>(childHead_->GetNextSibling());
1732         childNode->SetNextSibling(nullptr);
1733         childNode->SetParent(nullptr);
1734         childHead_ = next;
1735         parentView->Remove(childNativeView);
1736         return;
1737     }
1738 
1739     // find the target node's pre one
1740     Component *temp = childHead_;
1741     while (temp != nullptr) {
1742         if (temp->GetNextSibling() == childNode) {
1743             // found it
1744             break;
1745         }
1746         temp = const_cast<Component *>(temp->GetNextSibling());
1747     }
1748     if (temp == nullptr) {
1749         // not found
1750         return;
1751     }
1752 
1753     temp->SetNextSibling(childNode->GetNextSibling());
1754     childNode->SetNextSibling(nullptr);
1755     childNode->SetParent(nullptr);
1756     parentView->Remove(childNativeView);
1757 }
1758 
RemoveAllChildren()1759 void Component::RemoveAllChildren()
1760 {
1761     while (childHead_ != nullptr) {
1762         RemoveChild(childHead_);
1763     }
1764 }
1765 
CreateDirectiveWatcher(jerry_value_t descriptor)1766 void Component::CreateDirectiveWatcher(jerry_value_t descriptor)
1767 {
1768     JSValue watcher = DescriptorUtils::CreateDescriptorWatcher(nativeElement_, descriptor);
1769     if (!JSUndefined::Is(watcher)) {
1770         InsertWatcherCommon(watchersHead_, watcher);
1771     }
1772 }
1773 
IsAttached() const1774 bool Component::IsAttached() const
1775 {
1776     UIView *nativeView = GetComponentRootView();
1777     if (nativeView == nullptr) {
1778         return false;
1779     }
1780     return (nativeView->GetParent() != nullptr);
1781 }
1782 
BuildViewTree(Component * currComponent,Component * parent,const ConstrainedParameter & parentParameter)1783 void Component::BuildViewTree(Component *currComponent, Component *parent, const ConstrainedParameter &parentParameter)
1784 {
1785     if (currComponent == nullptr) {
1786         return;
1787     }
1788 
1789     // align self dimension
1790     currComponent->AlignDimensions(parentParameter);
1791     // refresh rect (border box sizing -> content box sizing)
1792     currComponent->AdaptBoxSizing();
1793     // attach to parent, and avoid attaching repeatly
1794     if (parent != nullptr && !currComponent->IsAttached()) {
1795         parent->AttachView(currComponent);
1796         // notify view has been attached to tree, it means the parent's size is already calculated out
1797         currComponent->OnViewAttached();
1798     }
1799 
1800     Component *child = const_cast<Component *>(currComponent->GetChildHead());
1801     if (child == nullptr) {
1802         return;
1803     }
1804     // the child only can layout in the content area of parent
1805     ConstrainedParameter alignParameter;
1806     currComponent->GetConstrainedParam(alignParameter);
1807     while (child != nullptr) {
1808         BuildViewTree(child, currComponent, alignParameter);
1809         child = const_cast<Component *>(child->GetNextSibling());
1810     }
1811     // consider how to avoid layout repeatly, for example: div - div -- div
1812     currComponent->LayoutChildren();
1813 }
1814 
HandleChildrenChange(jerry_value_t descriptor)1815 void Component::HandleChildrenChange(jerry_value_t descriptor)
1816 {
1817     RemoveAllChildren();
1818     if (!JSUndefined::Is(children_)) {
1819         JSRelease(children_);
1820         children_ = JSArray::Create(0);
1821     }
1822 
1823     uint16_t size = JSArray::Length(descriptors_);
1824     for (uint16_t idx = 0; idx < size; ++idx) {
1825         JSValue descriptorOrElement = JSArray::Get(descriptors_, idx);
1826         if (IS_UNDEFINED(descriptorOrElement)) {
1827             continue;
1828         }
1829         if (descriptorOrElement == descriptor) {
1830             UpdateDescriptor(this, descriptorOrElement);
1831         } else {
1832             ReappendDescriptorOrElement(this, descriptorOrElement);
1833         }
1834         JSRelease(descriptorOrElement);
1835     }
1836 
1837     Component *parent = const_cast<Component *>(GetParent());
1838     ConstrainedParameter parentParam;
1839     Component *target = (parent == nullptr) ? this : parent;
1840     target->GetConstrainedParam(parentParam);
1841     BuildViewTree(this, nullptr, parentParam);
1842     target->LayoutChildren();
1843     target->Invalidate();
1844 }
1845 
UpdateDescriptor(Component * parent,const jerry_value_t descriptor)1846 void Component::UpdateDescriptor(Component *parent, const jerry_value_t descriptor)
1847 {
1848     if (DescriptorUtils::IsIfDescriptor(descriptor)) {
1849         AppendIfDescriptor(parent, descriptor);
1850     } else if (DescriptorUtils::IsForDescriptor(descriptor)) {
1851         // Release descriptor last rendered
1852         DescriptorUtils::DelForDescriptorRendered(descriptor);
1853 
1854         // Re-render descriptor
1855         JSValue descriptorOrElements = DescriptorUtils::RenderForDescriptor(descriptor);
1856         AppendDescriptorOrElements(parent, descriptorOrElements);
1857     } else {
1858         // never
1859     }
1860 }
1861 
ReappendDescriptorOrElement(Component * parent,const jerry_value_t descriptor)1862 void Component::ReappendDescriptorOrElement(Component *parent, const jerry_value_t descriptor)
1863 {
1864     if (DescriptorUtils::IsIfDescriptor(descriptor)) {
1865         JSValue descriptorOrElement = DescriptorUtils::GetDescriptorRendered(descriptor);
1866         if (!JSUndefined::Is(descriptorOrElement)) {
1867             AppendDescriptorOrElement(parent, descriptor);
1868         }
1869         JSRelease(descriptorOrElement);
1870     } else if (DescriptorUtils::IsForDescriptor(descriptor)) {
1871         JSValue descriptorOrElements = DescriptorUtils::GetDescriptorRendered(descriptor);
1872         if (!JSUndefined::Is(descriptorOrElements)) {
1873             AppendDescriptorOrElements(parent, descriptorOrElements);
1874         }
1875         JSRelease(descriptorOrElements);
1876     } else {
1877         AppendElement(parent, descriptor);
1878     }
1879 }
1880 
GetStylePixelValue(const AppStyleItem * style,int32_t defaultValue) const1881 int32_t Component::GetStylePixelValue(const AppStyleItem *style, int32_t defaultValue) const
1882 {
1883     if (style->GetValueType() == STYLE_PROP_VALUE_TYPE_NUMBER) {
1884         return style->GetNumValue();
1885     }
1886     if (style->GetValueType() == STYLE_PROP_VALUE_TYPE_STRING) {
1887         if (style->GetStrValue() == nullptr) {
1888             HILOG_WARN(HILOG_MODULE_ACE, "Get Style PixelValue failed, return default value!");
1889             return defaultValue;
1890         }
1891         return strtol(style->GetStrValue(), nullptr, DEC);
1892     }
1893     return defaultValue;
1894 }
1895 
GetStyleDegValue(const AppStyleItem * style,int16_t defaultValue) const1896 int16_t Component::GetStyleDegValue(const AppStyleItem *style, int16_t defaultValue) const
1897 {
1898     if (style->GetValueType() == STYLE_PROP_VALUE_TYPE_NUMBER) {
1899         return style->GetNumValue();
1900     }
1901     if (style->GetValueType() == STYLE_PROP_VALUE_TYPE_STRING) {
1902         if (style->GetStrValue() == nullptr) {
1903             HILOG_WARN(HILOG_MODULE_ACE, "Get Style DegValue failed, return default value!");
1904             return defaultValue;
1905         }
1906         return strtol(style->GetStrValue(), nullptr, DEC);
1907     }
1908     return defaultValue;
1909 }
1910 
GetStyleColorValue(const AppStyleItem * style,uint32_t & color,uint8_t & alpha) const1911 bool Component::GetStyleColorValue(const AppStyleItem *style, uint32_t &color, uint8_t &alpha) const
1912 {
1913     if (style->GetValueType() == STYLE_PROP_VALUE_TYPE_NUMBER) {
1914         color = style->GetNumValue();
1915         alpha = OPA_OPAQUE;
1916         return true;
1917     }
1918     if (style->GetValueType() == STYLE_PROP_VALUE_TYPE_STRING) {
1919         return ParseColor(style->GetStrValue(), color, alpha);
1920     }
1921     HILOG_ERROR(HILOG_MODULE_ACE, "invalid color format!");
1922     return false;
1923 }
1924 
HandleBackgroundImg(const AppStyleItem & styleItem,char * & pressedImage,char * & normalImage) const1925 bool Component::HandleBackgroundImg(const AppStyleItem &styleItem, char *&pressedImage, char *&normalImage) const
1926 {
1927     bool result = false;
1928     if (styleItem.GetValueType() == STYLE_PROP_VALUE_TYPE_STRING) {
1929         const char * const url = styleItem.GetStrValue();
1930         char *filePath = CreatePathStrFromUrl(url);
1931         if (filePath != nullptr) {
1932             char *imagePath = JsAppContext::GetInstance()->GetResourcePath(filePath);
1933             if (imagePath == nullptr) {
1934                 ace_free(filePath);
1935                 filePath = nullptr;
1936                 return result;
1937             }
1938             if ((styleItem.GetPseudoClassType() == PSEUDO_CLASS_ACTIVE) ||
1939                 (styleItem.GetPseudoClassType() == PSEUDO_CLASS_CHECKED)) {
1940                 // in case we don't free the buffer after using
1941                 ACE_FREE(pressedImage);
1942                 pressedImage = imagePath;
1943             } else {
1944                 // in case we don't free the buffer after using
1945                 ACE_FREE(normalImage);
1946                 normalImage = imagePath;
1947             }
1948             ace_free(filePath);
1949             filePath = nullptr;
1950             result = true;
1951         }
1952     }
1953     return result;
1954 }
1955 
1956 #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)1957 jerry_value_t Component::HandleRotationRequest(const jerry_value_t func,
1958                                                const jerry_value_t dom,
1959                                                const jerry_value_t args[],
1960                                                const jerry_length_t size)
1961 {
1962     UNUSED(func);
1963     UIView *bindedView = ComponentUtils::GetViewFromBindingObject(dom);
1964     if (bindedView == nullptr) {
1965         return UNDEFINED;
1966     }
1967 
1968     // default action is to request the focus even user do not pass the argument
1969     bool focusRequest = true;
1970     if (args != nullptr && size > 0) {
1971         if (!JerryGetBoolProperty(args[0], ATTR_NAME_FOCUS, focusRequest)) {
1972             HILOG_ERROR(HILOG_MODULE_ACE, "not bool argument passed, will clear the focus!");
1973             focusRequest = false;
1974         }
1975     }
1976     if (focusRequest) {
1977         bindedView->RequestFocus();
1978     } else {
1979         bindedView->ClearFocus();
1980     }
1981 
1982     return UNDEFINED;
1983 }
1984 #endif // FEATURE_ROTATION_API
1985 } // namespace ACELite
1986 } // namespace OHOS
1987