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 
25 namespace OHOS {
26 Text::TextLine Text::textLine_[MAX_LINE_COUNT] = {{0}};
27 
Text()28 Text::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 
~Text()50 Text::~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         UIFree(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 
SetSpannableString(const SpannableString * spannableString)77 void Text::SetSpannableString(const SpannableString* spannableString)
78 {
79     if (spannableString_ == nullptr) {
80         spannableString_ = new SpannableString();
81     }
82     spannableString_->SetSpannableString(spannableString);
83     needRefresh_ = true;
84 }
85 
SetText(const char * text)86 void 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 
SetFont(const char * name,uint8_t size)120 void 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 
SetFont(const char * name,uint8_t size,char * & destName,uint8_t & destSize)140 void 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 
SetFontId(uint16_t fontId)172 void 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 
ReMeasureTextSize(const Rect & textRect,const Style & style)204 void 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 
ReMeasureTextWidthInEllipsisMode(const Rect & textRect,const Style & style,uint16_t ellipsisIndex)223 void 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 
DrawEllipsis(BufferInfo & gfxDstBuffer,LabelLineInfo & labelLine,uint16_t & letterIndex)235 void 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 
OnDraw(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea,const Rect & viewOrigRect,const Rect & textRect,int16_t offsetX,const Style & style,uint16_t ellipsisIndex,OpacityType opaScale)244 void 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 
Draw(BufferInfo & gfxDstBuffer,const Rect & mask,const Rect & coords,const Style & style,int16_t offsetX,uint16_t ellipsisIndex,OpacityType opaScale)263 void 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 
CalculatedCurLineHeight(int16_t & lineHeight,int16_t & curLineHeight,uint16_t fontHeight,const Style & style,uint16_t lineMaxHeight)338 void 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 
GetPos(int16_t & lineHeight,const Style & style,uint16_t & lineCount,const Rect & coords)353 Point 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
SetLineBytes(uint16_t & lineBytes,uint16_t lineBegin)365 void 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 
SetNextLineBegin(const Style & style,uint16_t lineMaxHeight,int16_t & curLineHeight,Point & pos,int16_t & tempLetterIndex,int16_t & lineHeight,uint16_t & lineBegin,uint16_t letterIndex)377 void 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 
TextPositionY(const Rect & textRect,int16_t textHeight)384 int16_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 
LineStartPos(const Rect & textRect,uint16_t lineWidth)397 int16_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 
GetLine(int16_t width,uint8_t letterSpace,uint16_t ellipsisIndex,uint32_t & maxLineBytes)411 uint16_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 
CalculateLineWithEllipsis(uint32_t begin,uint32_t textLen,int16_t width,uint8_t letterSpace,uint16_t & lineNum,uint16_t & letterIndex,SpannableString * spannableString)445 uint32_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 
GetTextStrLen()466 uint32_t Text::GetTextStrLen()
467 {
468     return (text_ != nullptr) ? (strlen(text_)) : 0;
469 }
470 
GetTextLine(uint32_t begin,uint32_t textLen,int16_t width,uint16_t lineNum,uint8_t letterSpace,uint16_t & letterIndex,SpannableString * spannableString,TextLine & textLine)471 uint32_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 
GetEllipsisIndex(const Rect & textRect,const Style & style)487 uint16_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 
GetLetterIndexByLinePosition(const Style & style,int16_t contentWidth,const int16_t & posX,int16_t offsetX)510 uint16_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 
GetPosXByLetterIndex(const Rect & textRect,const Style & style,uint16_t beginIndex,uint16_t count)526 uint16_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 
GetLetterIndexByPosition(const Rect & textRect,const Style & style,const Point & pos)541 uint16_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 
SetAbsoluteSizeSpan(uint16_t start,uint16_t end,uint8_t size)588 void 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 
SetRelativeSizeSpan(uint16_t start,uint16_t end,float size)618 void 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 
GetSpanFontIdBySize(uint8_t size)634 uint16_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 
GetNextCharacterFullDispalyOffset(const Rect & textRect,const Style & style,uint16_t beginIndex,uint16_t num)659 uint16_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 
GetMetaTextWidth(const Style & style)665 int16_t Text::GetMetaTextWidth(const Style& style)
666 {
667     return TypedText::GetTextWidth(text_, GetFontId(), GetFontSize(), strlen(text_), style.letterSpace_);
668 }
669 } // namespace OHOS
670