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