1 /*
2 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "component.h"
16 #include "ace_log.h"
17 #include "ace_mem_base.h"
18 #include "directive/descriptor_utils.h"
19 #include "fatal_handler.h"
20 #include "handler.h"
21 #include "js_ability_impl.h"
22 #include "js_app_context.h"
23 #include "js_app_environment.h"
24 #include "js_profiler.h"
25 #include "js_router.h"
26 #include "key_parser.h"
27 #include "keys.h"
28 #include "lazy_load_manager.h"
29 #include "securec.h"
30 #include "stylemgr/app_style.h"
31 #include "stylemgr/app_style_manager.h"
32 #include "time_util.h"
33 #include "wrapper/js.h"
34
35 namespace OHOS {
36 namespace ACELite {
37 static Component::AnimationsNode *g_animationListHead = nullptr;
38 static bool g_isAnimatorStarted = false;
HandlerAnimations()39 void Component::HandlerAnimations()
40 {
41 Component::AnimationsNode *point = g_animationListHead;
42 while (point != nullptr && point->transitionImpl != nullptr) {
43 point->transitionImpl->Start();
44 point = point->next;
45 }
46 g_isAnimatorStarted = true;
47 }
48
ReleaseAnimations()49 void Component::ReleaseAnimations()
50 {
51 Component::AnimationsNode *point = g_animationListHead;
52 while (point != nullptr) {
53 Component::AnimationsNode *temp = point->next;
54 if (point->transitionImpl) {
55 delete (point->transitionImpl);
56 point->transitionImpl = nullptr;
57 }
58 delete (point);
59 point = temp;
60 }
61 g_animationListHead = nullptr;
62 g_isAnimatorStarted = false;
63 }
64
Component(jerry_value_t options,jerry_value_t children,AppStyleManager * styleManager)65 Component::Component(jerry_value_t options, jerry_value_t children, AppStyleManager *styleManager)
66 : childHead_(nullptr),
67 nextSibling_(nullptr),
68 parent_(nullptr),
69 styleManager_(styleManager),
70 options_(options),
71 children_(UNDEFINED),
72 onClickListener_(nullptr),
73 onLongPressListener_(nullptr),
74 onTouchListener_(nullptr),
75 #ifdef JS_EXTRA_EVENT_SUPPORT
76 onTouchCancelListener_(nullptr),
77 keyBoardEventListener_(nullptr),
78 #endif
79 viewId_(nullptr),
80 componentName_(K_UNKNOWN),
81 rendered_(false),
82 isAnimationKeyFramesSet_(false),
83 curTransitionImpl_(nullptr),
84 trans_(nullptr),
85 descriptors_(jerry_acquire_value(children)),
86 watchersHead_(nullptr),
87 height_(-1, DimensionType::TYPE_UNKNOWN),
88 width_(-1, DimensionType::TYPE_UNKNOWN),
89 top_(-1, DimensionType::TYPE_UNKNOWN),
90 left_(-1, DimensionType::TYPE_UNKNOWN),
91 marginTop_(-1, DimensionType::TYPE_UNKNOWN),
92 marginLeft_(-1, DimensionType::TYPE_UNKNOWN),
93 marginRight_(-1, DimensionType::TYPE_UNKNOWN),
94 marginBottom_(-1, DimensionType::TYPE_UNKNOWN)
95 {
96 JSValue attrs = JSObject::Get(options, ATTR_ATTRS);
97 if (JSUndefined::Is(attrs)) {
98 freeze_ = false;
99 } else {
100 freeze_ = JSObject::GetBoolean(attrs, ATTR_FREEZE);
101 }
102 JSRelease(attrs);
103 // create native element object before combining styles, as style data binding need it
104 nativeElement_ = jerry_create_object();
105 jerry_value_t global = jerry_get_global_object();
106 viewModel_ = jerryx_get_property_str(global, ATTR_ROOT);
107 jerry_release_value(global);
108 }
109
110 /**
111 * @brief After construct a specific component, call this function to setup this component's native view
112 * and process attribute/events/style/children properly before binding it on an JS object.
113 * It generally calls a series of functions to complete the render work, some of which are needed to be
114 * implemented by child class. See step1~step6 function notes.
115 *
116 * NOTE: Caller should check the return result to decide if it's needed to recycle the component if the
117 * rendering failed.
118 *
119 * @return true if success, false if any error occurs
120 */
Render()121 bool Component::Render()
122 {
123 if (rendered_) {
124 HILOG_ERROR(HILOG_MODULE_ACE, "Render one component twice is not allowed.");
125 return false;
126 }
127
128 PreRender();
129 // step1: create native view/views
130 START_TRACING_WITH_COMPONENT_NAME(RENDER_CREATE_COMPONENT, componentName_);
131 bool renderResult = CreateNativeViews();
132 if (!renderResult) {
133 return false;
134 }
135 STOP_TRACING();
136
137 // The event bubbling mechanism is supported from API version 5, and events are bubbled by default.
138 // However, it should be compatible with the migrated old application (API version 4)
139 // so that it does not bubble by default.
140 const int32_t supportEventBubbleApiVersion = 5;
141 if (JsAppContext::GetInstance()->GetTargetApi() < supportEventBubbleApiVersion) {
142 UIView *view = GetComponentRootView();
143 if (view != nullptr) {
144 // make events non bubbling by default.
145 view->SetIntercept(true);
146 }
147 }
148
149 SetViewExtraMsg();
150
151 // step2: binding js object with this component
152 jerry_set_object_native_pointer(nativeElement_, this, nullptr);
153
154 // step3: parse options for attributes and events, will call child class's according methods
155 ParseOptions();
156
157 // step4:process this component's children
158 START_TRACING_WITH_COMPONENT_NAME(RENDER_PROCESS_CHILDREN, componentName_);
159 renderResult = ProcessChildren();
160 STOP_TRACING();
161 if (!renderResult) {
162 return false;
163 }
164 RecordAnimation();
165 PostRender();
166 rendered_ = true;
167
168 return renderResult;
169 }
170
SetViewExtraMsg()171 void Component::SetViewExtraMsg()
172 {
173 UIView *view = GetComponentRootView();
174 if (view == nullptr) {
175 HILOG_ERROR(HILOG_MODULE_ACE, "failed to set the extra message for view.");
176 return;
177 }
178 UIView::ViewExtraMsg *extraMsg = new UIView::ViewExtraMsg();
179 if (extraMsg == nullptr) {
180 HILOG_ERROR(HILOG_MODULE_ACE, "Failed to mapping native view with DOM element.");
181 return;
182 }
183 extraMsg->elementPtr = reinterpret_cast<void *>(&nativeElement_);
184 view->SetExtraMsg(extraMsg);
185 }
186
ReleaseViewExtraMsg()187 void Component::ReleaseViewExtraMsg()
188 {
189 UIView *view = GetComponentRootView();
190 if (view == nullptr) {
191 return;
192 }
193 UIView::ViewExtraMsg *extraMsg = view->GetExtraMsg();
194 ACE_DELETE(extraMsg);
195 view->SetExtraMsg(nullptr);
196 }
197
Release()198 void Component::Release()
199 {
200 // detach self from fatal handler monitoring
201 FatalHandler::GetInstance().DetachComponentNode(this);
202 RemoveAllChildren();
203 #if (FEATURE_LAZY_LOADING_MODULE == 1)
204 // detach from lazy pending list
205 JsAppContext *context = JsAppContext::GetInstance();
206 LazyLoadManager *lazyLoadManager = const_cast<LazyLoadManager *>(context->GetLazyLoadManager());
207 lazyLoadManager->RemoveLazyWatcher(nativeElement_);
208 #endif // FEATURE_LAZY_LOADING_MODULE
209 if (parent_ != nullptr) {
210 parent_->RemoveChild(this);
211 }
212
213 // stop view animation
214 if (curTransitionImpl_) {
215 curTransitionImpl_->Stop();
216 }
217 ReleaseViewExtraMsg();
218 jerry_delete_object_native_pointer(nativeElement_, nullptr);
219 // release all native views
220 ReleaseNativeViews();
221 // release transition param
222 ReleaseTransitionParam();
223 // release the common event listeners if any
224 ReleaseCommonEventListeners();
225 // release children = jerry_create_array() in Init()
226 ClearWatchersCommon(watchersHead_);
227 // free viewId string if it's set
228 ACE_FREE(viewId_);
229 // release js object
230 jerry_release_value(nativeElement_);
231 jerry_release_value(descriptors_);
232 jerry_release_value(children_);
233 jerry_release_value(viewModel_);
234 }
235
UpdateView(uint16_t attrKeyId,jerry_value_t attrValue)236 bool Component::UpdateView(uint16_t attrKeyId, jerry_value_t attrValue)
237 {
238 if (!KeyParser::IsKeyValid(attrKeyId)) {
239 return false;
240 }
241
242 START_TRACING_WITH_EXTRA_INFO(SET_ATTR_SET_TO_NATIVE, componentName_, attrKeyId);
243 PreUpdate();
244
245 // check if need to invalided self before changing in case component's area will be changed
246 InvalidateIfNeeded(attrKeyId, true);
247 bool updateResult = SetAttribute(attrKeyId, attrValue);
248 if (!updateResult) {
249 AppStyleItem *styleItem = AppStyleItem::CreateStyleItem(attrKeyId, attrValue);
250 if (styleItem != nullptr) {
251 updateResult = ApplyStyle(styleItem);
252 delete styleItem;
253 styleItem = nullptr;
254 }
255 }
256 // for root component case, it has no parent, need to use screen resolution as default
257 ConstrainedParameter parentParam(GetHorizontalResolution(), GetVerticalResolution());
258 if (parent_ != nullptr) {
259 parent_->GetConstrainedParam(parentParam);
260 }
261 AlignDimensions(parentParam);
262 AdaptBoxSizing(attrKeyId);
263 // force parent to relayout the children in case component's area is changed
264 InvalidateIfNeeded(attrKeyId, false);
265 if (updateResult) {
266 PostUpdate(attrKeyId);
267 }
268 StartAnimation();
269 STOP_TRACING();
270
271 return updateResult;
272 }
RegisterNamedFunction(const char * const name,jerry_external_handler_t handler) const273 void Component::RegisterNamedFunction(const char * const name, jerry_external_handler_t handler) const
274 {
275 JerrySetFuncProperty(nativeElement_, name, handler);
276 }
277 // default implementation
SetAttribute(uint16_t attrKeyId,jerry_value_t attrValue)278 bool Component::SetAttribute(uint16_t attrKeyId, jerry_value_t attrValue)
279 {
280 UIView *uiView = GetComponentRootView();
281 if ((uiView == nullptr) || !KeyParser::IsKeyValid(attrKeyId) || IS_UNDEFINED(attrValue)) {
282 return false;
283 }
284
285 // try private first
286 bool setResult = SetPrivateAttribute(attrKeyId, attrValue);
287 if (!setResult) {
288 // this means no private attributes matches, so need to try private ones
289 setResult = SetCommonAttribute(*uiView, attrKeyId, attrValue);
290 }
291
292 return setResult;
293 }
294
SetCommonAttribute(UIView & view,const uint16_t attrKeyId,const jerry_value_t attrValue)295 bool Component::SetCommonAttribute(UIView &view, const uint16_t attrKeyId, const jerry_value_t attrValue)
296 {
297 switch (attrKeyId) {
298 case K_ID: {
299 // this string in component itself.
300 ACE_FREE(viewId_);
301 viewId_ = MallocStringOf(attrValue);
302 if (viewId_ == nullptr) {
303 HILOG_ERROR(HILOG_MODULE_ACE, "failed to set `id` attribute.");
304 return false;
305 }
306 view.SetViewId(viewId_);
307 break;
308 }
309 case K_SHOW: {
310 view.SetVisible(BoolOf(attrValue));
311 break;
312 }
313 case K_REF: {
314 uint16_t length = 0;
315 char *refName = MallocStringOf(attrValue, &length);
316 if (refName == nullptr) {
317 HILOG_ERROR(HILOG_MODULE_ACE, "failed to set `ref` attribute.");
318 return false;
319 }
320 if (length != 0) {
321 jerry_value_t refs = jerryx_get_property_str(viewModel_, ATTR_REFS);
322 if (jerry_value_is_undefined(refs)) {
323 jerry_release_value(refs);
324 refs = jerry_create_object();
325 jerryx_set_property_str(viewModel_, ATTR_REFS, refs);
326 }
327 jerryx_set_property_str(refs, refName, nativeElement_);
328 jerry_release_value(refs);
329 }
330 ace_free(refName);
331 refName = nullptr;
332 break;
333 }
334 default: {
335 // this is not error case, just no one get matched
336 return false;
337 }
338 }
339
340 return true;
341 }
342
ApplyStyles(const jerry_value_t options,Component & currentComponent) const343 void Component::ApplyStyles(const jerry_value_t options, Component ¤tComponent) const
344 {
345 if (jerry_value_is_undefined(options)) {
346 return;
347 }
348 styleManager_->ApplyComponentStyles(options, currentComponent);
349 }
350
GetDimensionFromStyle(Dimension & dimension,const AppStyleItem & styleItem) const351 void Component::GetDimensionFromStyle(Dimension &dimension, const AppStyleItem &styleItem) const
352 {
353 if (styleItem.GetValueType() == STYLE_PROP_VALUE_TYPE_PERCENT) {
354 // percent format
355 dimension.value.percentage = styleItem.GetPercentValue();
356 dimension.type = DimensionType::TYPE_PERCENT;
357 return;
358 }
359 // number or string format
360 // use INT32_MIN as the impossible default value
361 int32_t pixelValue = GetStylePixelValue(&styleItem, INT32_MIN);
362 if (pixelValue == INT32_MIN) {
363 // get pixel failed, reset to unknown type
364 dimension.type = DimensionType::TYPE_UNKNOWN;
365 return;
366 }
367 dimension.value.pixel = (int16_t)(pixelValue);
368 dimension.type = DimensionType::TYPE_PIXEL;
369 }
370
CalculateDimensionPixel(Dimension & dimension,int16_t base) const371 void Component::CalculateDimensionPixel(Dimension &dimension, int16_t base) const
372 {
373 const uint8_t hundred = 100;
374 if (dimension.type == DimensionType::TYPE_PERCENT) {
375 dimension.value.pixel = (int16_t)((dimension.value.percentage * base) / hundred);
376 dimension.type = DimensionType::TYPE_PIXEL;
377 }
378 }
379
GetDimension(uint16_t keyNameId) const380 const Dimension &Component::GetDimension(uint16_t keyNameId) const
381 {
382 const static Dimension unknownDimension = {0, DimensionType::TYPE_UNKNOWN};
383 switch (keyNameId) {
384 case K_WIDTH:
385 return width_;
386 case K_HEIGHT:
387 return height_;
388 case K_TOP:
389 return top_;
390 case K_LEFT:
391 return left_;
392 case K_MARGIN_TOP:
393 return marginTop_;
394 case K_MARGIN_BOTTOM:
395 return marginBottom_;
396 case K_MARGIN_RIGHT:
397 return marginRight_;
398 case K_MARGIN_LEFT:
399 return marginLeft_;
400 default: {
401 return unknownDimension;
402 }
403 }
404 }
405
AlignDimensions(const ConstrainedParameter & param)406 void Component::AlignDimensions(const ConstrainedParameter ¶m)
407 {
408 // width
409 CalculateDimensionPixel(width_, param.maxWidth);
410 CalculateDimensionPixel(height_, param.maxHeight);
411 // top & left
412 CalculateDimensionPixel(top_, param.maxHeight);
413 CalculateDimensionPixel(left_, param.maxWidth);
414 // margin
415 CalculateDimensionPixel(marginTop_, param.maxHeight);
416 CalculateDimensionPixel(marginLeft_, param.maxHeight);
417 CalculateDimensionPixel(marginRight_, param.maxHeight);
418 CalculateDimensionPixel(marginBottom_, param.maxHeight);
419 // notify
420 OnDimensionsAligned();
421 }
422
EnableTransmitSwipe()423 void Component::EnableTransmitSwipe()
424 {
425 if (onTouchListener_ != nullptr) {
426 onTouchListener_->SetStopPropagation(false);
427 }
428 }
429
GetConstrainedParam(ConstrainedParameter & param) const430 void Component::GetConstrainedParam(ConstrainedParameter ¶m) const
431 {
432 param.maxWidth = width_.value.pixel;
433 param.maxHeight = height_.value.pixel;
434 }
435
ApplyAlignedMargin(UIView & uiView) const436 void Component::ApplyAlignedMargin(UIView &uiView) const
437 {
438 if (marginTop_.type == DimensionType::TYPE_PIXEL) {
439 uiView.SetStyle(STYLE_MARGIN_TOP, marginTop_.value.pixel);
440 }
441 if (marginBottom_.type == DimensionType::TYPE_PIXEL) {
442 uiView.SetStyle(STYLE_MARGIN_BOTTOM, marginBottom_.value.pixel);
443 }
444 if (marginLeft_.type == DimensionType::TYPE_PIXEL) {
445 uiView.SetStyle(STYLE_MARGIN_LEFT, marginLeft_.value.pixel);
446 }
447 if (marginRight_.type == DimensionType::TYPE_PIXEL) {
448 uiView.SetStyle(STYLE_MARGIN_RIGHT, marginRight_.value.pixel);
449 }
450 }
451
IsLayoutRelatedAttrs(uint16_t attrKeyId) const452 bool Component::IsLayoutRelatedAttrs(uint16_t attrKeyId) const
453 {
454 return (attrKeyId == K_HEIGHT || attrKeyId == K_WIDTH || attrKeyId == K_MARGIN || attrKeyId == K_MARGIN_BOTTOM ||
455 attrKeyId == K_MARGIN_LEFT || attrKeyId == K_MARGIN_RIGHT || attrKeyId == K_MARGIN_TOP ||
456 attrKeyId == K_PADDING || attrKeyId == K_PADDING_BOTTOM || attrKeyId == K_PADDING_LEFT ||
457 attrKeyId == K_PADDING_RIGHT || attrKeyId == K_PADDING_TOP || attrKeyId == K_BORDER_BOTTOM_WIDTH ||
458 attrKeyId == K_BORDER_LEFT_WIDTH || attrKeyId == K_BORDER_RIGHT_WIDTH || attrKeyId == K_BORDER_TOP_WIDTH ||
459 attrKeyId == K_BORDER_WIDTH || attrKeyId == K_BORDER_RADIUS || attrKeyId == K_LEFT || attrKeyId == K_TOP ||
460 attrKeyId == K_SHOW || attrKeyId == K_DISPLAY);
461 }
462
ApplyAlignedPosition(UIView & uiView) const463 void Component::ApplyAlignedPosition(UIView &uiView) const
464 {
465 if (top_.type == DimensionType::TYPE_PIXEL) {
466 uiView.SetY(top_.value.pixel);
467 }
468 if (left_.type == DimensionType::TYPE_PIXEL) {
469 uiView.SetX(left_.value.pixel);
470 }
471 }
472
AdapteBoxRectArea(UIView & uiView) const473 void Component::AdapteBoxRectArea(UIView &uiView) const
474 {
475 // set view height and width
476 uint8_t borderNum = 2;
477 int16_t height = (height_.type == DimensionType::TYPE_PIXEL) ? height_.value.pixel : -1;
478 int16_t width = (width_.type == DimensionType::TYPE_PIXEL) ? width_.value.pixel : -1;
479 if (height >= 0) {
480 // as uiView->GetStyle(STYLE_PADDING_TOP) and uiView->GetStyle(STYLE_PADDING_BOTTOM) is defined
481 // as uint16_t, so do not need to judge whether less than 0
482 if (uiView.GetStyle(STYLE_BORDER_WIDTH) < 0) {
483 HILOG_WARN(HILOG_MODULE_ACE, "border and padding size should not less than 0");
484 }
485 int16_t contentHeight = height - (uiView.GetStyle(STYLE_BORDER_WIDTH) * borderNum) -
486 uiView.GetStyle(STYLE_PADDING_TOP) - uiView.GetStyle(STYLE_PADDING_BOTTOM);
487 if (contentHeight <= 0) {
488 HILOG_WARN(HILOG_MODULE_ACE,
489 "component height can not include padding and border width, padding and border will be set 0");
490 uiView.SetStyle(STYLE_BORDER_WIDTH, 0);
491 uiView.SetStyle(STYLE_PADDING_TOP, 0);
492 uiView.SetStyle(STYLE_PADDING_BOTTOM, 0);
493 uiView.SetHeight(height);
494 } else {
495 uiView.SetHeight(contentHeight);
496 }
497 }
498 if (width >= 0) {
499 if (uiView.GetStyle(STYLE_BORDER_WIDTH) < 0) {
500 HILOG_WARN(HILOG_MODULE_ACE, "border and padding size should not less than 0");
501 }
502 int16_t contentWidth = width - (uiView.GetStyle(STYLE_BORDER_WIDTH) * borderNum) -
503 uiView.GetStyle(STYLE_PADDING_LEFT) - uiView.GetStyle(STYLE_PADDING_RIGHT);
504 if (contentWidth <= 0) {
505 HILOG_WARN(HILOG_MODULE_ACE,
506 "component width can not include padding and border width, padding and border will be set 0");
507 uiView.SetStyle(STYLE_BORDER_WIDTH, 0);
508 uiView.SetStyle(STYLE_PADDING_LEFT, 0);
509 uiView.SetStyle(STYLE_PADDING_RIGHT, 0);
510 uiView.SetWidth(width);
511 } else {
512 uiView.SetWidth(contentWidth);
513 }
514 }
515 }
516
AdaptBoxSizing(uint16_t attrKeyId) const517 bool Component::AdaptBoxSizing(uint16_t attrKeyId) const
518 {
519 UIView *uiView = GetComponentRootView();
520 if (uiView == nullptr) {
521 return false;
522 }
523 bool isNeedAlignedPosition = ((attrKeyId == K_UNKNOWN) ? true : IsLayoutRelatedAttrs(attrKeyId));
524 if (isNeedAlignedPosition) {
525 // apply aligned top and left
526 ApplyAlignedPosition(*uiView);
527 }
528 // apply aligned magin
529 ApplyAlignedMargin(*uiView);
530 // adjust the box sizing
531 AdapteBoxRectArea(*uiView);
532 return true;
533 }
534
ApplyStyle(const AppStyleItem * style)535 bool Component::ApplyStyle(const AppStyleItem *style)
536 {
537 UIView *uiView = GetComponentRootView();
538 if (uiView == nullptr) {
539 return false;
540 }
541
542 // Try private styles first
543 bool applyResult = ApplyPrivateStyle(style);
544 if (applyResult) {
545 // one private style get matched, no need to try private style ones
546 return true;
547 }
548 return ApplyCommonStyle(*uiView, style);
549 }
550
551 /*
552 * support common style items:
553 * [left|top]: number # flex layout not work
554 * 'width': number,
555 * 'height': number,
556 * 'margin': number, # flex layout work
557 * 'border-width': number,
558 * 'border-color':number,
559 * 'border-radius': number,
560 * 'background-color': number,
561 * 'opacity': number,
562 * 'visibility': bool,
563 *
564 * not suport common style item:
565 * border-[left|top|right|bottom]-width,
566 * border-[left|top|right|bottom]-color,
567 * border-[top|bottom]-[left|right]-radius,
568 * border-style,
569 * padding:number,
570 * right|bottom
571 */
ApplyCommonStyle(UIView & view,const AppStyleItem * style)572 bool Component::ApplyCommonStyle(UIView &view, const AppStyleItem *style)
573 {
574 uint16_t styleNameId = GetStylePropNameId(style);
575 if (!KeyParser::IsKeyValid(styleNameId)) {
576 return false;
577 }
578
579 // we do not support pseudo class for all styles, child must handle itself
580 if (style->IsPseudoClassItem()) {
581 return false;
582 }
583
584 switch (styleNameId) {
585 case K_HEIGHT: {
586 GetDimensionFromStyle(height_, *style);
587 break;
588 }
589 case K_WIDTH: {
590 GetDimensionFromStyle(width_, *style);
591 break;
592 }
593 case K_DISPLAY: {
594 SetVisible(view, style);
595 break;
596 }
597 case K_MARGIN: {
598 GetDimensionFromStyle(marginBottom_, *style);
599 GetDimensionFromStyle(marginLeft_, *style);
600 GetDimensionFromStyle(marginRight_, *style);
601 GetDimensionFromStyle(marginTop_, *style);
602 break;
603 }
604 case K_MARGIN_BOTTOM: {
605 GetDimensionFromStyle(marginBottom_, *style);
606 break;
607 }
608 case K_MARGIN_LEFT: {
609 GetDimensionFromStyle(marginLeft_, *style);
610 break;
611 }
612 case K_MARGIN_RIGHT: {
613 GetDimensionFromStyle(marginRight_, *style);
614 break;
615 }
616 case K_MARGIN_TOP: {
617 GetDimensionFromStyle(marginTop_, *style);
618 break;
619 }
620 case K_PADDING:
621 SetPadding(view, *style);
622 break;
623 case K_PADDING_BOTTOM:
624 SetBottomPadding(view, *style);
625 break;
626 case K_PADDING_LEFT:
627 SetLeftPadding(view, *style);
628 break;
629 case K_PADDING_RIGHT:
630 SetRightPadding(view, *style);
631 break;
632 case K_PADDING_TOP: {
633 SetTopPadding(view, *style);
634 break;
635 }
636 case K_BORDER_BOTTOM_WIDTH:
637 case K_BORDER_LEFT_WIDTH:
638 case K_BORDER_RIGHT_WIDTH:
639 case K_BORDER_TOP_WIDTH:
640 case K_BORDER_WIDTH: {
641 SetBorderWidth(view, *style);
642 break;
643 }
644 case K_BORDER_BOTTOM_COLOR:
645 case K_BORDER_LEFT_COLOR:
646 case K_BORDER_RIGHT_COLOR:
647 case K_BORDER_TOP_COLOR:
648 case K_BORDER_COLOR: {
649 SetBorderColor(view, *style);
650 break;
651 }
652 case K_BORDER_RADIUS: {
653 SetBorderRadius(view, *style);
654 break;
655 }
656 case K_BACKGROUND_COLOR: {
657 SetBackgroundColor(view, *style);
658 break;
659 }
660 case K_LEFT: {
661 GetDimensionFromStyle(left_, *style);
662 break;
663 }
664 case K_TOP: {
665 GetDimensionFromStyle(top_, *style);
666 break;
667 }
668 case K_ANIMATION_DURATION: {
669 SetAnimationStyle(view, style, K_ANIMATION_DURATION);
670 break;
671 }
672 case K_ANIMATION_TIMING_FUNCTION: {
673 SetAnimationStyle(view, style, K_ANIMATION_TIMING_FUNCTION);
674 break;
675 }
676 case K_ANIMATION_FILL_MODE: {
677 SetAnimationStyle(view, style, K_ANIMATION_FILL_MODE);
678 break;
679 }
680 case K_ANIMATION_DELAY: {
681 SetAnimationStyle(view, style, K_ANIMATION_DELAY);
682 break;
683 }
684 case K_ANIMATION_ITERATION_COUNT: {
685 SetAnimationStyle(view, style, K_ANIMATION_ITERATION_COUNT);
686 break;
687 }
688 case K_ANIMATION_NAME: {
689 SetAnimationKeyFrames(view, style);
690 break;
691 }
692 case K_OPACITY: {
693 SetOpacity(view, *style);
694 break;
695 }
696 default: {
697 return false;
698 }
699 }
700 return true;
701 }
702
Invalidate()703 void Component::Invalidate()
704 {
705 UIView *view = GetComponentRootView();
706 if (view == nullptr) {
707 return;
708 }
709 view->Invalidate();
710 }
711
ParseOptions()712 void Component::ParseOptions()
713 {
714 if (JSUndefined::Is(options_)) {
715 HILOG_WARN(HILOG_MODULE_ACE, "options is null");
716 return;
717 }
718
719 if (!JSObject::Is(options_)) {
720 HILOG_WARN(HILOG_MODULE_ACE, "options is not an object type.");
721 return;
722 }
723
724 START_TRACING_WITH_COMPONENT_NAME(RENDER_APPLY_STYLE, componentName_);
725 ApplyStyles(options_, *this);
726 STOP_TRACING();
727
728 START_TRACING(RENDER_PARSE_ATTR);
729 ParseAttrs();
730 STOP_TRACING();
731 START_TRACING(RENDER_PARSE_EVENT);
732 ParseEvents();
733 STOP_TRACING();
734 }
735
SetAnimationKeyFrames(const UIView & view,const AppStyleItem * styleItem)736 void Component::SetAnimationKeyFrames(const UIView &view, const AppStyleItem *styleItem)
737 {
738 if (trans_ == nullptr) {
739 trans_ = new TransitionParams();
740 if (trans_ == nullptr) {
741 HILOG_ERROR(HILOG_MODULE_ACE, "create TransitionParams object error");
742 return;
743 }
744 }
745
746 const char * const value = GetStyleStrValue(styleItem);
747 if (value == nullptr) {
748 HILOG_ERROR(HILOG_MODULE_ACE, "animation name is not string value");
749 return;
750 }
751
752 const AppStyleSheet *styleSheet = GetStyleManager()->GetStyleSheet();
753 if (styleSheet == nullptr) {
754 HILOG_ERROR(HILOG_MODULE_ACE, "styleSheet must set when you set animation attribute");
755 return;
756 }
757 AppStyle *style = styleSheet->GetStyleFromKeyFramesSelectors(value);
758
759 if (style) {
760 const AppStyleItem *item = style->GetFirst();
761 if (item == nullptr) {
762 HILOG_ERROR(HILOG_MODULE_ACE, "keyFrame style is not set!");
763 return;
764 }
765 SetAnimationKeyFrames(item);
766 }
767 }
768
SetAnimationKeyFrames(const AppStyleItem * item)769 void Component::SetAnimationKeyFrames(const AppStyleItem *item)
770 {
771 if (item == nullptr) {
772 HILOG_ERROR(HILOG_MODULE_ACE, "keyFrame style is not set!");
773 return;
774 }
775
776 const int8_t animatorFrom = 1;
777 const int8_t animatorTo = 2;
778
779 isAnimationKeyFramesSet_ = false;
780 while (item) {
781 const char * const itemValue = item->GetStrValue();
782
783 if ((itemValue == nullptr) || (strlen(itemValue) == 0)) {
784 return;
785 }
786 size_t valLength = strlen(itemValue);
787 if (valLength >= UINT8_MAX) {
788 item = item->GetNext();
789 continue;
790 }
791 char *animationValue = reinterpret_cast<char *>(ace_malloc(sizeof(char) * (valLength + 1)));
792 if (animationValue == nullptr) {
793 HILOG_ERROR(HILOG_MODULE_ACE, "malloc animationValue memory heap failed.");
794 return;
795 }
796 if (memcpy_s(animationValue, valLength, itemValue, valLength) != 0) {
797 ace_free(animationValue);
798 animationValue = nullptr;
799 return;
800 }
801 animationValue[valLength] = '\0';
802 int32_t valueTo;
803 int32_t valueFrom;
804 int16_t keyId = item->GetPropNameId();
805 if (keyId == K_OPACITY) {
806 valueTo = GetAnimatorValue(animationValue, animatorTo, true);
807 valueFrom = GetAnimatorValue(animationValue, animatorFrom, true);
808 } else {
809 valueTo = GetAnimatorValue(animationValue, animatorTo);
810 valueFrom = GetAnimatorValue(animationValue, animatorFrom);
811 }
812 ace_free(animationValue);
813 animationValue = nullptr;
814 SetAnimationKeyFrames(keyId, valueFrom, valueTo);
815 item = item->GetNext();
816 }
817 }
818
SetAnimationKeyFrames(int16_t keyId,int32_t valueFrom,int32_t valueTo)819 void Component::SetAnimationKeyFrames(int16_t keyId, int32_t valueFrom, int32_t valueTo)
820 {
821 switch (keyId) {
822 case K_ROTATE:
823 trans_->transformType = const_cast<char *>(TRANSITION_ROTATE);
824 trans_->transform_from = valueFrom;
825 trans_->transform_to = valueTo;
826 isAnimationKeyFramesSet_ = true;
827 break;
828 case K_TRANSLATE_X:
829 trans_->transformType = const_cast<char *>(TRANSITION_TRANSFORM_X);
830 trans_->transform_from = valueFrom;
831 trans_->transform_to = valueTo;
832 isAnimationKeyFramesSet_ = true;
833 break;
834 case K_TRANSLATE_Y:
835 trans_->transformType = const_cast<char *>(TRANSITION_TRANSFORM_Y);
836 trans_->transform_from = valueFrom;
837 trans_->transform_to = valueTo;
838 isAnimationKeyFramesSet_ = true;
839 break;
840 case K_HEIGHT:
841 trans_->height_from = valueFrom;
842 trans_->height_to = valueTo;
843 isAnimationKeyFramesSet_ = true;
844 break;
845 case K_WIDTH:
846 trans_->width_from = valueFrom;
847 trans_->width_to = valueTo;
848 isAnimationKeyFramesSet_ = true;
849 break;
850 case K_BACKGROUND_COLOR:
851 trans_->background_color_from = valueFrom;
852 trans_->background_color_to = valueTo;
853 isAnimationKeyFramesSet_ = true;
854 break;
855 case K_OPACITY:
856 trans_->opacity_from = valueFrom;
857 trans_->opacity_to = valueTo;
858 isAnimationKeyFramesSet_ = true;
859 break;
860 default:
861 break;
862 }
863 }
864
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