• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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