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 "common/text.h"
17#include "common/typed_text.h"
18#include "draw/draw_label.h"
19#include "font/ui_font.h"
20#include "font/ui_font_adaptor.h"
21#include "font/ui_font_builder.h"
22#include "gfx_utils/graphic_log.h"
23#include "securec.h"
24
25namespace OHOS {
26Text::TextLine Text::textLine_[MAX_LINE_COUNT] = {{0}};
27
28Text::Text()
29    : text_(nullptr),
30      fontId_(0),
31      fontSize_(0),
32      textSize_({0, 0}),
33      needRefresh_(false),
34      expandWidth_(false),
35      expandHeight_(false),
36      baseLine_(true),
37      direct_(TEXT_DIRECT_LTR),
38      characterSize_(0),
39      spannableString_(nullptr),
40      horizontalAlign_(TEXT_ALIGNMENT_LEFT),
41      verticalAlign_(TEXT_ALIGNMENT_TOP),
42      eliminateTrailingSpaces_(false)
43{
44#if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
45    textStyles_ = nullptr;
46#endif
47    SetFont(DEFAULT_VECTOR_FONT_FILENAME, DEFAULT_VECTOR_FONT_SIZE);
48}
49
50Text::~Text()
51{
52    if (text_ != nullptr) {
53        UIFree(text_);
54        text_ = nullptr;
55    }
56#if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
57    if (textStyles_ != nullptr) {
58        UIFree(textStyles_);
59        textStyles_ = nullptr;
60    }
61#endif
62    if (spannableString_ != nullptr) {
63        delete spannableString_;
64        spannableString_ = nullptr;
65    }
66    if (backgroundColor_.Size() > 0) {
67        backgroundColor_.Clear();
68    }
69    if (linebackgroundColor_.Size() > 0) {
70        linebackgroundColor_.Clear();
71    }
72    if (foregroundColor_.Size() > 0) {
73        foregroundColor_.Clear();
74    }
75}
76
77void Text::SetSpannableString(const SpannableString* spannableString)
78{
79    if (spannableString_ == nullptr) {
80        spannableString_ = new SpannableString();
81    }
82    spannableString_->SetSpannableString(spannableString);
83    needRefresh_ = true;
84}
85
86void Text::SetText(const char* text)
87{
88    if (text == nullptr) {
89        return;
90    }
91    uint32_t textLen = static_cast<uint32_t>(strlen(text));
92    if (textLen > MAX_TEXT_LENGTH) {
93        textLen = MAX_TEXT_LENGTH;
94    }
95    if (text_ != nullptr) {
96        if (strcmp(text, text_) == 0) {
97            return;
98        }
99        UIFree(text_);
100        text_ = nullptr;
101    }
102    text_ = static_cast<char*>(UIMalloc(textLen + 1));
103    if (text_ == nullptr) {
104        return;
105    }
106    if (strncpy_s(text_, textLen + 1, text, textLen) != EOK) {
107        UIFree(text_);
108        text_ = nullptr;
109        return;
110    }
111#if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
112    if (textStyles_ != nullptr) {
113        UIFree(textStyles_);
114        textStyles_ = nullptr;
115    }
116#endif
117    needRefresh_ = true;
118}
119
120void Text::SetFont(const char* name, uint8_t size)
121{
122    if (name == nullptr) {
123        return;
124    }
125    UIFont* font = UIFont::GetInstance();
126    if (font->IsVectorFont()) {
127        uint16_t fontId = font->GetFontId(name);
128        if ((fontId != UIFontBuilder::GetInstance()->GetTotalFontId()) &&
129            ((fontId_ != fontId) || (fontSize_ != size))) {
130            fontId_ = fontId;
131            fontSize_ = size;
132            needRefresh_ = true;
133        }
134    } else {
135        uint16_t fontId = font->GetFontId(name, size);
136        SetFontId(fontId);
137    }
138}
139
140void Text::SetFont(const char* name, uint8_t size, char*& destName, uint8_t& destSize)
141{
142    if (name == nullptr) {
143        return;
144    }
145    uint32_t nameLen = static_cast<uint32_t>(strlen(name));
146    if (nameLen > MAX_TEXT_LENGTH) {
147        return;
148    }
149    if (destName != nullptr) {
150        if (strcmp(destName, name) == 0) {
151            destSize = size;
152            return;
153        }
154        UIFree(destName);
155        destName = nullptr;
156    }
157    if (nameLen != 0) {
158        /* one more to store '\0' */
159        destName = static_cast<char*>(UIMalloc(++nameLen));
160        if (destName == nullptr) {
161            return;
162        }
163        if (memcpy_s(destName, nameLen, name, nameLen) != EOK) {
164            UIFree(destName);
165            destName = nullptr;
166            return;
167        }
168        destSize = size;
169    }
170}
171
172void Text::SetFontId(uint16_t fontId)
173{
174    UIFontBuilder* fontBuilder = UIFontBuilder::GetInstance();
175    if (fontId >= fontBuilder->GetTotalFontId()) {
176        GRAPHIC_LOGE("Text::SetFontId invalid fontId(%hhd)", fontId);
177        return;
178    }
179    UIFont* font = UIFont::GetInstance();
180    if ((fontId_ == fontId) && (fontSize_ != 0) && !font->IsVectorFont()) {
181        GRAPHIC_LOGD("Text::SetFontId same font has already set");
182        return;
183    }
184
185    UITextLanguageFontParam* fontParam = fontBuilder->GetTextLangFontsTable(fontId);
186    if (fontParam == nullptr) {
187        return;
188    }
189    if (font->IsVectorFont()) {
190        uint16_t fontId = font->GetFontId(fontParam->ttfName);
191        if ((fontId != fontBuilder->GetTotalFontId()) && ((fontId_ != fontId) ||
192            (fontSize_ != fontParam->size))) {
193            fontId_ = fontId;
194            fontSize_ = fontParam->size;
195            needRefresh_ = true;
196        }
197    } else {
198        fontId_ = fontId;
199        fontSize_ = fontParam->size;
200        needRefresh_ = true;
201    }
202}
203
204void Text::ReMeasureTextSize(const Rect& textRect, const Style& style)
205{
206    if (fontSize_ == 0) {
207        return;
208    }
209    int16_t maxWidth = (expandWidth_ ? COORD_MAX : textRect.GetWidth());
210    if (maxWidth > 0) {
211        textSize_ = TypedText::GetTextSize(text_, fontId_, fontSize_, style.letterSpace_, style.lineHeight_, maxWidth,
212                                           style.lineSpace_, spannableString_, IsEliminateTrailingSpaces());
213        if (baseLine_) {
214            FontHeader head;
215            if (UIFont::GetInstance()->GetFontHeader(head, fontId_, fontSize_) != 0) {
216                return;
217            }
218            textSize_.y += fontSize_ - head.ascender;
219        }
220    }
221}
222
223void Text::ReMeasureTextWidthInEllipsisMode(const Rect& textRect, const Style& style, uint16_t ellipsisIndex)
224{
225    if (ellipsisIndex != TEXT_ELLIPSIS_END_INV) {
226        int16_t lineMaxWidth  = expandWidth_ ? textSize_.x : textRect.GetWidth();
227        uint32_t maxLineBytes = 0;
228        uint16_t lineCount = GetLine(lineMaxWidth, style.letterSpace_, ellipsisIndex, maxLineBytes);
229        if ((lineCount > 0) && (textSize_.x < textLine_[lineCount - 1].linePixelWidth)) {
230            textSize_.x = textLine_[lineCount - 1].linePixelWidth;
231        }
232    }
233}
234
235void Text::DrawEllipsis(BufferInfo& gfxDstBuffer, LabelLineInfo& labelLine, uint16_t& letterIndex)
236{
237    labelLine.offset.x = 0;
238    labelLine.text = TEXT_ELLIPSIS;
239    labelLine.lineLength = 1;
240    labelLine.length = 1;
241    DrawLabel::DrawTextOneLine(gfxDstBuffer, labelLine, letterIndex);
242}
243
244void Text::OnDraw(BufferInfo& gfxDstBuffer,
245                  const Rect& invalidatedArea,
246                  const Rect& viewOrigRect,
247                  const Rect& textRect,
248                  int16_t offsetX,
249                  const Style& style,
250                  uint16_t ellipsisIndex,
251                  OpacityType opaScale)
252{
253    if ((text_ == nullptr) || (strlen(text_) == 0) || (fontSize_ == 0)) {
254        return;
255    }
256    Rect mask = invalidatedArea;
257
258    if (mask.Intersect(mask, textRect)) {
259        Draw(gfxDstBuffer, mask, textRect, style, offsetX, ellipsisIndex, opaScale);
260    }
261}
262
263void Text::Draw(BufferInfo& gfxDstBuffer,
264                const Rect& mask,
265                const Rect& coords,
266                const Style& style,
267                int16_t offsetX,
268                uint16_t ellipsisIndex,
269                OpacityType opaScale)
270{
271    Point offset = {offsetX, 0};
272    int16_t lineMaxWidth = expandWidth_ ? textSize_.x : coords.GetWidth();
273    uint16_t lineBegin = 0;
274    uint32_t maxLineBytes = 0;
275    uint16_t lineCount = GetLine(lineMaxWidth, style.letterSpace_, ellipsisIndex, maxLineBytes);
276    int16_t lineHeight = style.lineHeight_;
277    int16_t curLineHeight;
278    UIFont* font = UIFont::GetInstance();
279    uint16_t fontHeight = font->GetHeight(fontId_, fontSize_);
280    uint16_t lineMaxHeight =
281        font->GetLineMaxHeight(text_, textLine_[0].lineBytes, fontId_, fontSize_, 0, spannableString_);
282    CalculatedCurLineHeight(lineHeight, curLineHeight, fontHeight, style, lineMaxHeight);
283    Point pos = GetPos(lineHeight, style, lineCount, coords);
284    OpacityType opa = DrawUtils::GetMixOpacity(opaScale, style.textOpa_);
285    uint16_t letterIndex = 0;
286    for (uint16_t i = 0; i < lineCount; i++) {
287        if (pos.y > mask.GetBottom()) {
288            return;
289        }
290        int16_t tempLetterIndex = letterIndex;
291        uint16_t lineBytes = textLine_[i].lineBytes;
292#if defined(ENABLE_ICU) && ENABLE_ICU
293        SetLineBytes(lineBytes, lineBegin);
294#endif
295        if ((style.lineHeight_ == 0) && (spannableString_ != nullptr)) {
296            curLineHeight = font->GetLineMaxHeight(
297                &text_[lineBegin], textLine_[i].lineBytes, fontId_, fontSize_,
298                tempLetterIndex, spannableString_);
299            if (lineCount > 1) {
300                curLineHeight += style.lineSpace_;
301            }
302        } else {
303            curLineHeight = lineHeight;
304            if (lineCount == 1) {
305                curLineHeight -= style.lineSpace_;
306            }
307        }
308        int16_t nextLine = pos.y + curLineHeight;
309        if (lineHeight != style.lineHeight_) {
310            nextLine -= style.lineSpace_;
311        }
312        Rect currentMask(mask.GetLeft(), pos.y, mask.GetRight(), pos.y + curLineHeight);
313        currentMask.Intersect(currentMask, mask);
314        if (nextLine >= mask.GetTop()) {
315            pos.x = LineStartPos(coords, textLine_[i].linePixelWidth);
316            LabelLineInfo labelLine {pos, offset, currentMask, curLineHeight, lineBytes,
317                                     0, opa, style, &text_[lineBegin], lineBytes,
318                                     lineBegin, fontId_, fontSize_, 0, static_cast<UITextLanguageDirect>(direct_),
319                                     nullptr, baseLine_,
320#if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
321                                     textStyles_,
322#endif
323                                     &backgroundColor_, &foregroundColor_, &linebackgroundColor_, spannableString_, 0};
324            uint16_t ellipsisOssetY = DrawLabel::DrawTextOneLine(gfxDstBuffer, labelLine, letterIndex);
325            if ((i == (lineCount - 1)) && (ellipsisIndex != TEXT_ELLIPSIS_END_INV)) {
326                labelLine.ellipsisOssetY = ellipsisOssetY;
327                DrawEllipsis(gfxDstBuffer, labelLine, letterIndex);
328            }
329        } else {
330            letterIndex = TypedText::GetUTF8CharacterSize(text_, lineBegin + lineBytes);
331        }
332        SetNextLineBegin(style, lineMaxHeight, curLineHeight, pos,
333                         tempLetterIndex, lineHeight, lineBegin, i);
334    }
335}
336
337
338void Text::CalculatedCurLineHeight(int16_t& lineHeight, int16_t& curLineHeight,
339                                   uint16_t fontHeight, const Style& style, uint16_t lineMaxHeight)
340{
341    if (lineHeight <= 0) {
342        lineHeight = fontHeight;
343        lineHeight += style.lineSpace_;
344    }
345    if ((style.lineSpace_ == 0) && (spannableString_ != nullptr)) {
346        curLineHeight = lineMaxHeight;
347        curLineHeight += style.lineSpace_;
348    } else {
349        curLineHeight = lineHeight;
350    }
351}
352
353Point Text::GetPos(int16_t& lineHeight, const Style& style, uint16_t& lineCount, const Rect& coords)
354{
355    Point pos;
356    if (lineHeight == style.lineHeight_) {
357        pos.y = TextPositionY(coords, (lineCount * lineHeight));
358    } else {
359        pos.y = TextPositionY(coords, (lineCount * lineHeight - style.lineSpace_));
360    }
361    return pos;
362}
363
364#if defined(ENABLE_ICU) && ENABLE_ICU
365void Text::SetLineBytes(uint16_t& lineBytes, uint16_t lineBegin)
366{
367    if (this->IsEliminateTrailingSpaces()) {
368        int j = lineBytes - 1;
369        while (j >= 0 && text_[lineBegin + j] == ' ') {
370            --j;
371        }
372        lineBytes = j + 1;
373    }
374}
375#endif
376
377void Text::SetNextLineBegin(const Style& style, uint16_t lineMaxHeight, int16_t& curLineHeight, Point& pos,
378                            int16_t& tempLetterIndex, int16_t& lineHeight, uint16_t& lineBegin, uint16_t letterIndex)
379{
380    lineBegin += textLine_[letterIndex].lineBytes;
381    pos.y += curLineHeight;
382}
383
384int16_t Text::TextPositionY(const Rect& textRect, int16_t textHeight)
385{
386    int16_t yOffset = 0;
387    if (!expandHeight_ && (verticalAlign_ != TEXT_ALIGNMENT_TOP) && (textRect.GetHeight() > textHeight)) {
388        if (verticalAlign_ == TEXT_ALIGNMENT_CENTER) {
389            yOffset = (textRect.GetHeight() - textHeight) >> 1;
390        } else if (verticalAlign_ == TEXT_ALIGNMENT_BOTTOM) {
391            yOffset = textRect.GetHeight() - textHeight;
392        }
393    }
394    return textRect.GetY() + yOffset;
395}
396
397int16_t Text::LineStartPos(const Rect& textRect, uint16_t lineWidth)
398{
399    int16_t xOffset = 0;
400    int16_t rectWidth = textRect.GetWidth();
401    if (horizontalAlign_ == TEXT_ALIGNMENT_CENTER) {
402        xOffset = (direct_ == TEXT_DIRECT_RTL) ? ((rectWidth + lineWidth + 1) >> 1) : ((rectWidth - lineWidth) >> 1);
403    } else if (horizontalAlign_ == TEXT_ALIGNMENT_RIGHT) {
404        xOffset = (direct_ == TEXT_DIRECT_RTL) ? rectWidth : (rectWidth - lineWidth);
405    } else {
406        xOffset = (direct_ == TEXT_DIRECT_RTL) ? rectWidth : 0;
407    }
408    return textRect.GetX() + xOffset;
409}
410
411uint16_t Text::GetLine(int16_t width, uint8_t letterSpace, uint16_t ellipsisIndex, uint32_t& maxLineBytes)
412{
413    if (text_ == nullptr) {
414        return 0;
415    }
416    uint16_t lineNum = 0;
417    uint32_t textLen = GetTextStrLen();
418    if ((ellipsisIndex != TEXT_ELLIPSIS_END_INV) && (ellipsisIndex < textLen)) {
419        textLen = ellipsisIndex;
420    }
421    uint32_t begin = 0;
422    uint16_t letterIndex = 0;
423    while ((begin < textLen) && (text_[begin] != '\0') && (lineNum < MAX_LINE_COUNT)) {
424        begin +=
425            GetTextLine(begin, textLen, width, lineNum, letterSpace, letterIndex, spannableString_, textLine_[lineNum]);
426        if (maxLineBytes < textLine_[lineNum].lineBytes) {
427            maxLineBytes = textLine_[lineNum].lineBytes;
428        }
429        lineNum++;
430    }
431    if ((lineNum != 0) && (ellipsisIndex != TEXT_ELLIPSIS_END_INV)) {
432        uint16_t ellipsisWidth =
433            UIFont::GetInstance()->GetWidth(TEXT_ELLIPSIS_UNICODE, fontId_, fontSize_, 0) + letterSpace;
434        textLine_[lineNum - 1].linePixelWidth += ellipsisWidth;
435        if (textLine_[lineNum - 1].linePixelWidth > width) {
436            int16_t newWidth = width - ellipsisWidth;
437            maxLineBytes = CalculateLineWithEllipsis(begin, textLen, newWidth, letterSpace, lineNum, letterIndex,
438                                                     spannableString_);
439            textLine_[lineNum - 1].linePixelWidth += ellipsisWidth;
440        }
441    }
442    return lineNum;
443}
444
445uint32_t Text::CalculateLineWithEllipsis(uint32_t begin, uint32_t textLen, int16_t width,
446                                         uint8_t letterSpace, uint16_t& lineNum,
447                                         uint16_t& letterIndex,
448                                         SpannableString* spannableString)
449{
450    begin -= textLine_[lineNum - 1].lineBytes;
451    lineNum--;
452    while ((begin < textLen) && (text_[begin] != '\0') && (lineNum < MAX_LINE_COUNT)) {
453        begin += GetTextLine(begin, textLen, width, lineNum, letterSpace, letterIndex, spannableString,
454            textLine_[lineNum]);
455        lineNum++;
456    }
457    uint32_t maxLineBytes = 0;
458    for (uint16_t i = 0; i < lineNum; i++) {
459        if (maxLineBytes < textLine_[i].lineBytes) {
460            maxLineBytes = textLine_[i].lineBytes;
461        }
462    }
463    return maxLineBytes;
464}
465
466uint32_t Text::GetTextStrLen()
467{
468    return (text_ != nullptr) ? (strlen(text_)) : 0;
469}
470
471uint32_t Text::GetTextLine(uint32_t begin, uint32_t textLen, int16_t width, uint16_t lineNum, uint8_t letterSpace,
472                           uint16_t& letterIndex, SpannableString* spannableString, TextLine& textLine)
473{
474    int16_t lineWidth = width;
475    int16_t lineHeight = 0;
476    uint16_t nextLineBytes = UIFontAdaptor::GetNextLineAndWidth(&text_[begin], fontId_, fontSize_, letterSpace,
477                                                                lineWidth, lineHeight, letterIndex, spannableString,
478                                                                false, textLen - begin, IsEliminateTrailingSpaces());
479    if (nextLineBytes + begin > textLen) {
480        nextLineBytes = textLen - begin;
481    }
482    textLine.lineBytes = nextLineBytes;
483    textLine.linePixelWidth = lineWidth;
484    return nextLineBytes;
485}
486
487uint16_t Text::GetEllipsisIndex(const Rect& textRect, const Style& style)
488{
489    if (textSize_.y <= textRect.GetHeight()) {
490        return TEXT_ELLIPSIS_END_INV;
491    }
492    UIFont* fontEngine = UIFont::GetInstance();
493    int16_t letterWidth = fontEngine->GetWidth(TEXT_ELLIPSIS_UNICODE, fontId_, fontSize_, 0) + style.letterSpace_;
494    Point p;
495    p.x = textRect.GetWidth() - letterWidth;
496    p.y = textRect.GetHeight();
497    int16_t height = style.lineHeight_;
498    if (height == 0) {
499        height = fontEngine->GetHeight(fontId_, fontSize_) + style.lineSpace_;
500    }
501    if (height) {
502        p.y -= p.y % height;
503    }
504    if (height != style.lineHeight_) {
505        p.y -= style.lineSpace_;
506    }
507    return GetLetterIndexByPosition(textRect, style, p);
508}
509
510uint16_t Text::GetLetterIndexByLinePosition(const Style& style, int16_t contentWidth,
511                                            const int16_t& posX, int16_t offsetX)
512{
513    uint16_t letterIndex = 0;
514    int16_t width = 0;
515    if (direct_ == UITextLanguageDirect::TEXT_DIRECT_LTR) {
516        width = posX - offsetX;
517    }
518
519    int16_t lineHeight = style.lineHeight_;
520    UIFontAdaptor::GetNextLineAndWidth(text_, fontId_, fontSize_, style.letterSpace_,
521                                       width, lineHeight, letterIndex, spannableString_,
522                                       false, 0xFFFF, IsEliminateTrailingSpaces());
523    return letterIndex;
524}
525
526uint16_t Text::GetPosXByLetterIndex(const Rect &textRect, const Style &style,
527                                    uint16_t beginIndex, uint16_t count)
528{
529    if (count == 0) {
530        return 0;
531    }
532
533    int16_t maxWidth = (expandWidth_ ? COORD_MAX : textRect.GetWidth());
534
535    int16_t textWidth = TypedText::GetTextWidth(text_, fontId_, fontSize_, GetTextStrLen(),
536        style.letterSpace_, beginIndex, count);
537
538    return static_cast<uint16_t>(textWidth > maxWidth ? maxWidth : textWidth);
539}
540
541uint16_t Text::GetLetterIndexByPosition(const Rect& textRect, const Style& style, const Point& pos)
542{
543    if (text_ == nullptr) {
544        return 0;
545    }
546    uint32_t lineStart = 0;
547    uint32_t nextLineStart = 0;
548    int16_t lineHeight = style.lineHeight_;
549    uint16_t letterHeight = UIFont::GetInstance()->GetHeight(fontId_, fontSize_);
550    if (lineHeight == 0) {
551        lineHeight = letterHeight + style.lineSpace_;
552    }
553    uint16_t height = 0;
554    if (lineHeight != style.lineHeight_) {
555        height = letterHeight;
556    } else {
557        height = lineHeight;
558    }
559    int16_t y = 0;
560    uint32_t textLen = static_cast<uint32_t>(strlen(text_));
561    int16_t width = 0;
562    uint16_t letterIndex = 0;
563    while ((lineStart < textLen) && (text_[lineStart] != '\0')) {
564        width = textRect.GetWidth();
565        nextLineStart += UIFontAdaptor::GetNextLineAndWidth(&text_[lineStart], fontId_, fontSize_, style.letterSpace_,
566                                                            width, lineHeight, letterIndex, spannableString_,
567                                                            false, 0xFFFF, IsEliminateTrailingSpaces());
568        if (nextLineStart == 0) {
569            break;
570        }
571        if (pos.y <= y + height) {
572            break;
573        }
574        y += lineHeight;
575        lineStart = nextLineStart;
576    }
577    if (nextLineStart == textLen) {
578        return TEXT_ELLIPSIS_END_INV;
579    }
580    /* Calculate the x coordinate */
581    width = pos.x;
582    lineStart +=
583        UIFontAdaptor::GetNextLineAndWidth(&text_[lineStart], fontId_, fontSize_, style.letterSpace_, width, lineHeight,
584                                           letterIndex, spannableString_, true, 0xFFFF, IsEliminateTrailingSpaces());
585    return (lineStart < textLen) ? lineStart : TEXT_ELLIPSIS_END_INV;
586}
587
588void Text::SetAbsoluteSizeSpan(uint16_t start, uint16_t end, uint8_t size)
589{
590#if defined(ENABLE_VECTOR_FONT) && ENABLE_VECTOR_FONT
591    if (fontId_ == FONT_ID_MAX) {
592        return;
593    }
594#else
595    if (fontId_ == UIFontBuilder::GetInstance()->GetBitmapFontIdMax()) {
596        return;
597    }
598#endif
599    uint16_t fontId = GetSpanFontIdBySize(size);
600#if defined(ENABLE_VECTOR_FONT) && !ENABLE_VECTOR_FONT
601    if (fontId == fontId_) {
602        return;
603    }
604#endif
605    if (text_ != nullptr && spannableString_ == nullptr) {
606        spannableString_ = new SpannableString();
607        if (spannableString_ == nullptr) {
608            GRAPHIC_LOGE("Text::SetAbsoluteSizeSpan invalid parameter");
609            return;
610        }
611    }
612    if (spannableString_ != nullptr) {
613        spannableString_->SetFontSize(size, start, end);
614        spannableString_->SetFontId(fontId, start, end);
615    }
616}
617
618void Text::SetRelativeSizeSpan(uint16_t start, uint16_t end, float size)
619{
620    uint8_t absoluteSize = 0;
621#if defined(ENABLE_VECTOR_FONT) && ENABLE_VECTOR_FONT
622    absoluteSize = static_cast<uint8_t>(size * fontSize_);
623#else
624    UITextLanguageFontParam* fontParam = UIFontBuilder::GetInstance()->GetTextLangFontsTable(fontId_);
625    if (fontParam == nullptr) {
626        GRAPHIC_LOGE("Text::SetRelativeSizeSpan invalid parameter");
627        return;
628    }
629    absoluteSize = static_cast<uint8_t>(size * fontParam->size);
630#endif
631    SetAbsoluteSizeSpan(start, end, absoluteSize);
632}
633
634uint16_t Text::GetSpanFontIdBySize(uint8_t size)
635{
636#if defined(ENABLE_VECTOR_FONT) && ENABLE_VECTOR_FONT
637    return fontId_;
638#else
639    UIFontBuilder* fontBuilder = UIFontBuilder::GetInstance();
640    UITextLanguageFontParam* fontParam = fontBuilder->GetTextLangFontsTable(fontId_);
641    if (fontParam == nullptr) {
642        return fontId_;
643    }
644
645    uint8_t ttfId = fontParam->ttfId;
646    for (uint16_t fontId = 0; fontId < fontBuilder->GetTotalFontId(); fontId++) {
647        UITextLanguageFontParam* tempFontParam = fontBuilder->GetTextLangFontsTable(fontId);
648        if (tempFontParam == nullptr) {
649            continue;
650        }
651        if (ttfId == tempFontParam->ttfId && size == tempFontParam->size) {
652            return fontId;
653        }
654    }
655    return fontId_;
656#endif
657}
658
659uint16_t Text::GetNextCharacterFullDispalyOffset(const Rect& textRect,
660    const Style& style, uint16_t beginIndex, uint16_t num)
661{
662    return GetPosXByLetterIndex(textRect, style, beginIndex, num);
663}
664
665int16_t Text::GetMetaTextWidth(const Style& style)
666{
667    return TypedText::GetTextWidth(text_, GetFontId(), GetFontSize(), strlen(text_), style.letterSpace_);
668}
669} // namespace OHOS
670