1 /*
2  * Copyright (c) 2020-2022 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 
16 #include "text_component.h"
17 #include <stdlib.h>
18 #include <string.h>
19 #include "ace_log.h"
20 #include "font/ui_font_header.h"
21 #include "js_app_context.h"
22 #include "key_parser.h"
23 #include "keys.h"
24 #include "product_adapter.h"
25 
26 using namespace OHOS;
27 
28 namespace OHOS {
29 namespace ACELite {
TextComponent(jerry_value_t options,jerry_value_t children,AppStyleManager * styleManager)30 TextComponent::TextComponent(jerry_value_t options, jerry_value_t children, AppStyleManager *styleManager)
31     : Component(options, children, styleManager),
32       fontSize_(DEFAULT_FONT_SIZE),
33       fontFamily_(nullptr),
34       textValue_(nullptr),
35       overflowMode_(UILabel::LINE_BREAK_CLIP),
36       horizontalAlign_(UITextLanguageAlignment::TEXT_ALIGNMENT_LEFT)
37 {
38     SetComponentName(K_TEXT);
39     fontSize_ = ProductAdapter::GetDefaultFontSize();
40 #if FEATURE_COMPONENT_TEXT_SPANNABLE
41     backgroundColorSpan_.start = -1;
42     backgroundColorSpan_.end = -1;
43     foregroundColorSpan_.start = -1;
44     foregroundColorSpan_.end = -1;
45     lineBackgroundColorSpan_.start = -1;
46     lineBackgroundColorSpan_.end = -1;
47 #endif // FEATURE_COMPONENT_TEXT_SPANNABLE
48 }
49 
CreateNativeViews()50 bool TextComponent::CreateNativeViews()
51 {
52     /* set default text OverFlow clip */
53     uiLabel_.SetLineBreakMode(overflowMode_);
54     const int32_t supportBaseLineApiVersion = 5;
55     if (JsAppContext::GetInstance()->GetTargetApi() < supportBaseLineApiVersion) {
56         uiLabel_.SetAlign(UITextLanguageAlignment::TEXT_ALIGNMENT_LEFT, UITextLanguageAlignment::TEXT_ALIGNMENT_TOP);
57         uiLabel_.SetSupportBaseLine(false);
58     } else {
59         uiLabel_.SetAlign(UITextLanguageAlignment::TEXT_ALIGNMENT_LEFT, UITextLanguageAlignment::TEXT_ALIGNMENT_CENTER);
60         uiLabel_.SetSupportBaseLine(true);
61     }
62     return CopyFontFamily(fontFamily_, ProductAdapter::GetDefaultFontFamilyName());
63 }
64 
ReleaseNativeViews()65 void TextComponent::ReleaseNativeViews()
66 {
67     ACE_FREE(textValue_);
68     ACE_FREE(fontFamily_);
69 }
70 
GetComponentRootView() const71 inline UIView *TextComponent::GetComponentRootView() const
72 {
73     return const_cast<UI_LABEL_TYPE_WRAPPER *>(&uiLabel_);
74 }
75 
GetUILabelView() const76 UI_LABEL_TYPE_WRAPPER *TextComponent::GetUILabelView() const
77 {
78     return const_cast<UI_LABEL_TYPE_WRAPPER *>(&uiLabel_);
79 }
80 
SetPrivateAttribute(uint16_t attrKeyId,jerry_value_t attrValue)81 bool TextComponent::SetPrivateAttribute(uint16_t attrKeyId, jerry_value_t attrValue)
82 {
83     switch (attrKeyId) {
84         case K_VALUE: {
85             ACE_FREE(textValue_);
86             textValue_ = MallocStringOf(attrValue);
87             break;
88         }
89         default: {
90             return false;
91         }
92     }
93 
94     return true;
95 }
96 
ApplyPrivateStyle(const AppStyleItem * styleItem)97 bool TextComponent::ApplyPrivateStyle(const AppStyleItem *styleItem)
98 {
99     switch (GetStylePropNameId(styleItem)) {
100         case K_COLOR:
101             SetTextColor(uiLabel_, styleItem);
102             break;
103         case K_LETTER_SPACING:
104             SetTextLetterSpace(uiLabel_, styleItem);
105             break;
106         case K_TEXT_ALIGN:
107             SetTextAlign(uiLabel_, styleItem);
108             break;
109         case K_FONT_SIZE:
110             SetTextSize(styleItem);
111             break;
112         case K_FONT_FAMILY:
113             if (!IsStyleValueTypeString(styleItem)) {
114                 HILOG_ERROR(HILOG_MODULE_ACE, "text Family style value type is invalid!");
115                 return false;
116             }
117             CopyFontFamily(fontFamily_, GetStyleStrValue(styleItem));
118             break;
119         case K_TEXT_OVERFLOW:
120             SetTextOverflow(uiLabel_, styleItem);
121             break;
122         case K_LINE_HEIGHT:
123             SetTextLineHeight(uiLabel_, styleItem);
124             break;
125 #if FEATURE_COMPONENT_TEXT_SPANNABLE
126         case K_BACKGROUNDCOLORSPANCOLOR: {
127             uint32_t color = 0;
128             uint8_t alpha = OPA_OPAQUE;
129             if (GetStyleColorValue(styleItem, color, alpha)) {
130                 backgroundColorSpan_.backgroundColor = GetRGBColor(color);
131             }
132             break;
133         }
134         case K_BACKGROUNDCOLORSPANSTART: {
135             backgroundColorSpan_.start = styleItem->GetNumValue();
136             break;
137         }
138         case K_BACKGROUNDCOLORSPANEND: {
139             backgroundColorSpan_.end = styleItem->GetNumValue();
140             break;
141         }
142         case K_FOREGROUNDCOLORSPANCOLOR: {
143             uint32_t color = 0;
144             uint8_t alpha = OPA_OPAQUE;
145             if (GetStyleColorValue(styleItem, color, alpha)) {
146                 foregroundColorSpan_.fontColor = GetRGBColor(color);
147             }
148             break;
149         }
150         case K_FOREGROUNDCOLORSPANSTART: {
151             foregroundColorSpan_.start = styleItem->GetNumValue();
152             break;
153         }
154         case K_FOREGROUNDCOLORSPANEND: {
155             foregroundColorSpan_.end = styleItem->GetNumValue();
156             break;
157         }
158         case K_LINEBACKGROUNDCOLORSPANCOLOR: {
159             uint32_t color = 0;
160             uint8_t alpha = OPA_OPAQUE;
161             if (GetStyleColorValue(styleItem, color, alpha)) {
162                 lineBackgroundColorSpan_.linebackgroundColor = GetRGBColor(color);
163             }
164             break;
165         }
166         case K_LINEBACKGROUNDCOLORSPANSTART: {
167             lineBackgroundColorSpan_.start = styleItem->GetNumValue();
168             break;
169         }
170         case K_LINEBACKGROUNDCOLORSPANEND: {
171             lineBackgroundColorSpan_.end = styleItem->GetNumValue();
172             break;
173         }
174         case K_ABSOLUTESIZESPANSTART: {
175             absoluteSizeSpan_.start = styleItem->GetNumValue();
176             break;
177         }
178         case K_ABSOLUTESIZESPANEND: {
179             absoluteSizeSpan_.end = styleItem->GetNumValue();
180             break;
181         }
182         case K_ABSOLUTESIZESPANSIZE: {
183             absoluteSizeSpan_.size = GetStylePixelValue(styleItem);
184             break;
185         }
186         case K_RELATIVESIZESPANSTART: {
187             relativeSizeSpan_.start = styleItem->GetNumValue();
188             break;
189         }
190         case K_RELATIVESIZESPANEND: {
191             relativeSizeSpan_.end = styleItem->GetNumValue();
192             break;
193         }
194         case K_RELATIVESIZESPANSIZE: {
195             relativeSizeSpan_.size = styleItem->GetFloatingValue();
196             break;
197         }
198         case K_SPANNABLESTYLE: {
199             TextStyle style = TextStyle::TEXT_STYLE_NORMAL;
200             const char* styleStr = styleItem->GetStrValue();
201             if (!strcmp(styleStr, "bold")) {
202                 style = TextStyle::TEXT_STYLE_BOLD;
203             } else if (!strcmp(styleStr, "bold-italic")) {
204                 style = TextStyle::TEXT_STYLE_BOLD_ITALIC;
205             } else if (!strcmp(styleStr, "italic")) {
206                 style = TextStyle::TEXT_STYLE_ITALIC;
207             }
208             stringStyleSpan_.style = style;
209             break;
210         }
211         case K_SPANNABLESTART: {
212             stringStyleSpan_.start = styleItem->GetNumValue();
213             break;
214         }
215         case K_SPANNABLEEND: {
216             stringStyleSpan_.end = styleItem->GetNumValue();
217             break;
218         }
219 #endif // FEATURE_COMPONENT_TEXT_SPANNABLE
220         default:
221             return false;
222     }
223 
224     return true;
225 }
226 
SetTextLetterSpace(UI_LABEL_TYPE_WRAPPER & label,const AppStyleItem * styleItem) const227 void TextComponent::SetTextLetterSpace(UI_LABEL_TYPE_WRAPPER &label, const AppStyleItem *styleItem) const
228 {
229     label.SetStyle(STYLE_LETTER_SPACE, (int16_t)GetStylePixelValue(styleItem));
230 }
231 
SetTextLineHeight(UI_LABEL_TYPE_WRAPPER & label,const AppStyleItem * styleItem) const232 void TextComponent::SetTextLineHeight(UI_LABEL_TYPE_WRAPPER &label, const AppStyleItem *styleItem) const
233 {
234     label.SetStyle(STYLE_LINE_HEIGHT, (int16_t)GetStylePixelValue(styleItem));
235 }
236 
SetTextOverflow(UI_LABEL_TYPE_WRAPPER & label,const AppStyleItem * styleItem)237 void TextComponent::SetTextOverflow(UI_LABEL_TYPE_WRAPPER &label, const AppStyleItem *styleItem)
238 {
239     if (!IsStyleValueTypeString(styleItem)) {
240         HILOG_ERROR(HILOG_MODULE_ACE, "text overflow style value is invalid!");
241         return;
242     }
243     // set ui label text OverFlow, LINE_BREAK_CLIP, TEXT_OVERFLOW_ELLIPSIS and TEXT_OVERFLOW_EXPAND are support
244     uint16_t propNameId = KeyParser::ParseKeyId(GetStyleStrValue(styleItem), GetStyleStrValueLen(styleItem));
245 
246     switch (propNameId) {
247         case K_CLIP:
248             overflowMode_ = UILabel::LINE_BREAK_CLIP;
249             break;
250         case K_ELLIPSIS:
251             overflowMode_ = UILabel::LINE_BREAK_ELLIPSIS;
252             break;
253         case K_EXPAND:
254             overflowMode_ = UILabel::LINE_BREAK_ADAPT;
255             break;
256         case K_BREAK:
257             overflowMode_ = UILabel::LINE_BREAK_WRAP;
258             break;
259         default:
260             HILOG_WARN(HILOG_MODULE_ACE, "TextOverFlow id=%{public}d is invalid, using default instead", propNameId);
261             break;
262     }
263     label.SetLineBreakMode(overflowMode_);
264 }
265 
SetTextColor(UI_LABEL_TYPE_WRAPPER & label,const AppStyleItem * styleItem) const266 void TextComponent::SetTextColor(UI_LABEL_TYPE_WRAPPER &label, const AppStyleItem *styleItem) const
267 {
268     uint32_t color = 0;
269     uint8_t alpha = OPA_OPAQUE;
270     if (GetStyleColorValue(styleItem, color, alpha)) {
271         label.SetStyle(STYLE_TEXT_COLOR, GetRGBColor(color).full);
272         label.SetStyle(STYLE_TEXT_OPA, alpha);
273     }
274 }
275 
SetTextSize(const AppStyleItem * styleItem)276 void TextComponent::SetTextSize(const AppStyleItem *styleItem)
277 {
278     fontSize_ = GetStylePixelValue(styleItem);
279 }
280 
OnViewAttached()281 void TextComponent::OnViewAttached()
282 {
283     if (GetHeight() < 0 && GetWidth() < 0) {
284         /* component height & width adjust text context when not set text height & text width */
285         uiLabel_.SetLineBreakMode(UILabel::LINE_BREAK_ADAPT);
286     } else if (GetHeight() < 0 && GetWidth() >= 0) {
287         /* component height adjust text context when set width not set text height */
288         uiLabel_.SetLineBreakMode(UILabel::LINE_BREAK_WRAP);
289     } else if (GetHeight() >= 0 && GetWidth() < 0) {
290         /* component width adjust text context when not set text width */
291         uiLabel_.SetLineBreakMode(UILabel::LINE_BREAK_STRETCH);
292     }
293     if (textValue_ != nullptr && fontFamily_ != nullptr) {
294         uiLabel_.SetFont(fontFamily_, fontSize_);
295         uiLabel_.SetText(textValue_);
296         UpdateTextAlignToLabel(uiLabel_);
297 #if FEATURE_COMPONENT_TEXT_SPANNABLE
298         SetRichTextSpan();
299 #endif // FEATURE_COMPONENT_TEXT_SPANNABLE
300     }
301 }
302 
303 /* watchcallback update text context */
PostUpdate(uint16_t attrKeyId)304 void TextComponent::PostUpdate(uint16_t attrKeyId)
305 {
306     if (!KeyParser::IsKeyValid(attrKeyId)) {
307         HILOG_ERROR(HILOG_MODULE_ACE, "text component post update check args failed");
308         return;
309     }
310     switch (attrKeyId) {
311         case K_VALUE:
312             if (textValue_ != nullptr) {
313                 uiLabel_.SetText(textValue_);
314                 UpdateTextAlignToLabel(uiLabel_);
315 #if FEATURE_COMPONENT_TEXT_SPANNABLE
316                 SetRichTextSpan();
317 #endif // FEATURE_COMPONENT_TEXT_SPANNABLE
318             }
319             break;
320         case K_FONT_SIZE:
321         case K_FONT_FAMILY:
322             if (fontFamily_ != nullptr) {
323                 uiLabel_.SetFont(fontFamily_, fontSize_);
324             }
325             break;
326         default:
327             break;
328     }
329     UIView *parent = uiLabel_.GetParent();
330     if (parent != nullptr) {
331         parent->LayoutChildren(true);
332     }
333 }
334 
SetTextAlign(UI_LABEL_TYPE_WRAPPER & label,const AppStyleItem * styleItem)335 void TextComponent::SetTextAlign(UI_LABEL_TYPE_WRAPPER &label, const AppStyleItem *styleItem)
336 {
337     if (!IsStyleValueTypeString(styleItem)) {
338         HILOG_ERROR(HILOG_MODULE_ACE, "text text align style value is invalid!");
339         return;
340     }
341     // set ui label text align, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER are support.
342     const char * const stylePropValue = GetStyleStrValue(styleItem);
343     uint16_t alignId = KeyParser::ParseKeyId(stylePropValue, GetStyleStrValueLen(styleItem));
344     switch (alignId) {
345         case K_LEFT:
346             horizontalAlign_ = UITextLanguageAlignment::TEXT_ALIGNMENT_LEFT;
347             break;
348         case K_RIGHT:
349             horizontalAlign_ = UITextLanguageAlignment::TEXT_ALIGNMENT_RIGHT;
350             break;
351         case K_CENTER:
352             horizontalAlign_ = UITextLanguageAlignment::TEXT_ALIGNMENT_CENTER;
353             break;
354         default:
355             HILOG_WARN(HILOG_MODULE_ACE, "text textAlign style value =%{public}s is invalid, using default instead",
356                        stylePropValue);
357             break;
358     }
359     UpdateTextAlignToLabel(label);
360 }
361 
UpdateTextAlignToLabel(UI_LABEL_TYPE_WRAPPER & label)362 void TextComponent::UpdateTextAlignToLabel(UI_LABEL_TYPE_WRAPPER& label)
363 {
364     const int32_t defaultVerticalAlignCenterApiVersion = 5;
365     if (JsAppContext::GetInstance()->GetTargetApi() < defaultVerticalAlignCenterApiVersion) {
366         label.SetAlign(horizontalAlign_, UITextLanguageAlignment::TEXT_ALIGNMENT_TOP);
367     } else {
368         label.SetAlign(horizontalAlign_, UITextLanguageAlignment::TEXT_ALIGNMENT_CENTER);
369     }
370 }
371 
372 #if FEATURE_COMPONENT_TEXT_SPANNABLE
SetRichTextSpan()373 void TextComponent::SetRichTextSpan()
374 {
375     if (backgroundColorSpan_.start != -1 && backgroundColorSpan_.end != -1) {
376         uiLabel_.SetBackgroundColorSpan(backgroundColorSpan_.backgroundColor,
377                                         backgroundColorSpan_.start,
378                                         backgroundColorSpan_.end);
379     }
380     if (foregroundColorSpan_.start != -1 && foregroundColorSpan_.end != -1) {
381         uiLabel_.SetForegroundColorSpan(foregroundColorSpan_.fontColor,
382                                         foregroundColorSpan_.start,
383                                         foregroundColorSpan_.end);
384     }
385     if (lineBackgroundColorSpan_.start != -1 && lineBackgroundColorSpan_.end != -1) {
386         uiLabel_.SetLineBackgroundSpan(lineBackgroundColorSpan_.linebackgroundColor,
387                                        lineBackgroundColorSpan_.start,
388                                        lineBackgroundColorSpan_.end);
389     }
390     if (absoluteSizeSpan_.start != -1 && absoluteSizeSpan_.end != -1) {
391         uiLabel_.SetAbsoluteSizeSpan(absoluteSizeSpan_.start,
392                                      absoluteSizeSpan_.end,
393                                      absoluteSizeSpan_.size);
394     }
395     if (relativeSizeSpan_.start != -1 && relativeSizeSpan_.end != -1) {
396         uiLabel_.SetRelativeSizeSpan(relativeSizeSpan_.start,
397                                      relativeSizeSpan_.end,
398                                      relativeSizeSpan_.size);
399     }
400 #if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
401     if (stringStyleSpan_.start != -1 && stringStyleSpan_.end != -1) {
402         SpannableString spanString(textValue_);
403         spanString.SetTextStyle(stringStyleSpan_.style,
404                                 stringStyleSpan_.start,
405                                 stringStyleSpan_.end);
406         uiLabel_.SetText(&spanString);
407     }
408 #endif
409 }
410 #endif // FEATURE_COMPONENT_TEXT_SPANNABLE
411 } // namespace ACELite
412 } // namespace OHOS
413