• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "text_span.h"
16 
17 #include <iomanip>
18 #include <stack>
19 #include <utility>
20 
21 #include <hb-icu.h>
22 #include <unicode/ubidi.h>
23 
24 #include "font_collection.h"
25 #include "font_styles.h"
26 #include "measurer.h"
27 #include "texgine_dash_path_effect.h"
28 #include "texgine_exception.h"
29 #include "texgine_mask_filter.h"
30 #include "texgine_path.h"
31 #include "texgine_path_1d_path_effect.h"
32 #include "texgine/utils/exlog.h"
33 #ifdef LOGGER_ENABLE_SCOPE
34 #include "texgine/utils/trace.h"
35 #endif
36 #include "text_converter.h"
37 #include "word_breaker.h"
38 #include "symbol_engine/hm_symbol_run.h"
39 #include "utils/system_properties.h"
40 
41 namespace OHOS {
42 namespace Rosen {
43 namespace TextEngine {
44 #define MAXRGB 255
45 #define MAXALPHA 255
46 #define OFFSETY 3
47 #define HALF 0.5f
48 #define DEFAULT_FONT_SIZE 14.0f
49 #define SCALE 0.7f
50 #define WIDTH_SCALAR 5.0f
51 #define HEIGHT_SCALAR 5.0f
52 #define DOTTED_ADVANCE 10.0f
53 #define WAVY_ADVANCE 6.0f
54 #define PHASE 0.0f
55 #define COUNT 2
56 #define MAX_BLURRADIUS 64u
57 #define POINTX0 0
58 #define POINTX1 1
59 #define POINTX2 2
60 #define POINTX3 3
61 #define POINTX4 4
62 #define POINTX5 5
63 #define POINTX6 6
64 #define POINTY0 0
65 #define POINTY2 2
66 #define POINTY4 4
67 #define POINTY6 6
68 
69 #ifdef BUILD_NON_SDK_VER
70 const bool G_IS_HMSYMBOL_ENABLE = Drawing::SystemProperties::GetHMSymbolEnable();
71 #else
72 const bool G_IS_HMSYMBOL_ENABLE = true;
73 #endif
74 
MakeEmpty()75 std::shared_ptr<TextSpan> TextSpan::MakeEmpty()
76 {
77     return std::make_shared<TextSpan>();
78 }
79 
MakeFromText(const std::string & text)80 std::shared_ptr<TextSpan> TextSpan::MakeFromText(const std::string &text)
81 {
82     auto span = MakeEmpty();
83     auto decodeText = TextConverter::ToUTF16(text);
84     span->AddUTF16Text(decodeText);
85     return span;
86 }
87 
MakeFromText(const std::u16string & text)88 std::shared_ptr<TextSpan> TextSpan::MakeFromText(const std::u16string &text)
89 {
90     auto span = MakeEmpty();
91     std::vector<uint16_t> u16;
92     for (const auto &t : text) {
93         u16.push_back(t);
94     }
95     span->AddUTF16Text(u16);
96     return span;
97 }
98 
MakeFromText(const std::u32string & text)99 std::shared_ptr<TextSpan> TextSpan::MakeFromText(const std::u32string &text)
100 {
101     auto span = MakeEmpty();
102     std::vector<uint32_t> u32;
103     for (const auto &t : text) {
104         u32.push_back(t);
105     }
106     auto decodeText = TextConverter::ToUTF16(u32);
107     span->AddUTF16Text(decodeText);
108     return span;
109 }
110 
MakeFromText(const std::vector<uint16_t> & text)111 std::shared_ptr<TextSpan> TextSpan::MakeFromText(const std::vector<uint16_t> &text)
112 {
113     auto span = MakeEmpty();
114     span->AddUTF16Text(text);
115     return span;
116 }
117 
MakeFromText(const std::vector<uint32_t> & text)118 std::shared_ptr<TextSpan> TextSpan::MakeFromText(const std::vector<uint32_t> &text)
119 {
120     auto span = MakeEmpty();
121     auto decodeText = TextConverter::ToUTF16(text);
122     span->AddUTF16Text(decodeText);
123     return span;
124 }
125 
MakeFromCharGroups(const CharGroups & cgs)126 std::shared_ptr<TextSpan> TextSpan::MakeFromCharGroups(const CharGroups &cgs)
127 {
128     auto span = MakeEmpty();
129     span->cgs_= cgs;
130     return span;
131 }
132 
AddUTF16Text(const std::vector<uint16_t> & text)133 void TextSpan::AddUTF16Text(const std::vector<uint16_t> &text)
134 {
135     u16vect_.insert(u16vect_.end(), text.begin(), text.end());
136 }
137 
CloneWithCharGroups(const CharGroups & cgs)138 std::shared_ptr<TextSpan> TextSpan::CloneWithCharGroups(const CharGroups &cgs)
139 {
140     auto span = MakeEmpty();
141     *span = *this;
142     span->cgs_ = cgs;
143     return span;
144 }
145 
GetHeight() const146 double TextSpan::GetHeight() const
147 {
148     return *tmetrics_->fDescent_ - *tmetrics_->fAscent_;
149 }
150 
GetWidth() const151 double TextSpan::GetWidth() const
152 {
153     return width_;
154 }
155 
GetPreBreak() const156 double TextSpan::GetPreBreak() const
157 {
158     return preBreak_;
159 }
160 
GetPostBreak() const161 double TextSpan::GetPostBreak() const
162 {
163     return postBreak_;
164 }
165 
IsRTL() const166 bool TextSpan::IsRTL() const
167 {
168     return rtl_;
169 }
170 
Paint(TexgineCanvas & canvas,double offsetX,double offsetY,const TextStyle & xs,const RoundRectType & rType)171 void TextSpan::Paint(TexgineCanvas &canvas, double offsetX, double offsetY, const TextStyle &xs,
172     const RoundRectType &rType)
173 {
174     TexginePaint paint;
175     paint.SetAntiAlias(true);
176 #ifndef USE_GRAPHIC_TEXT_GINE
177     paint.SetARGB(MAXRGB, MAXRGB, 0, 0);
178 #else
179     paint.SetAlpha(MAXALPHA);
180 #endif
181     if (xs.background.has_value()) {
182         auto rect = TexgineRect::MakeXYWH(offsetX, offsetY + *tmetrics_->fAscent_, width_,
183             *tmetrics_->fDescent_ - *tmetrics_->fAscent_);
184 #ifdef CROSS_PLATFORM
185         canvas.DrawRect(rect, xs.background.__get());
186 #else
187         canvas.DrawRect(rect, xs.background.value());
188 #endif
189     }
190 
191     if (xs.backgroundRect.color != 0) {
192         paint.SetColor(xs.backgroundRect.color);
193         double ltRadius = 0.0;
194         double rtRadius = 0.0;
195         double rbRadius = 0.0;
196         double lbRadius = 0.0;
197         if (rType == RoundRectType::ALL || rType == RoundRectType::LEFT_ONLY) {
198             ltRadius = std::fmin(xs.backgroundRect.leftTopRadius, maxRoundRectRadius_);
199             lbRadius = std::fmin(xs.backgroundRect.leftBottomRadius, maxRoundRectRadius_);
200         }
201         if (rType == RoundRectType::ALL || rType == RoundRectType::RIGHT_ONLY) {
202             rtRadius = std::fmin(xs.backgroundRect.rightTopRadius, maxRoundRectRadius_);
203             rbRadius = std::fmin(xs.backgroundRect.rightBottomRadius, maxRoundRectRadius_);
204         }
205         const SkVector fRadii[4] = {{ltRadius, ltRadius}, {rtRadius, rtRadius}, {rbRadius, rbRadius},
206             {lbRadius, lbRadius}};
207         auto rect = TexgineRect::MakeRRect(offsetX, offsetY + topInGroup_, width_,
208             bottomInGroup_ - topInGroup_, fRadii);
209         paint.SetAntiAlias(false);
210         canvas.DrawRRect(rect, paint);
211     }
212 
213     paint.SetAntiAlias(true);
214     paint.SetColor(xs.color);
215     if (xs.foreground.has_value()) {
216 #ifdef CROSS_PLATFORM
217         paint = xs.foreground.__get();
218 #else
219         paint = xs.foreground.value();
220 #endif
221     }
222 
223     PaintShadow(canvas, offsetX, offsetY, xs.shadows);
224     if (xs.isSymbolGlyph && G_IS_HMSYMBOL_ENABLE) {
225         std::pair<double, double> offset(offsetX, offsetY);
226         HMSymbolRun hmSymbolRun = HMSymbolRun();
227         hmSymbolRun.SetAnimation(animationFunc_);
228         hmSymbolRun.SetSymbolId(symbolId_);
229         hmSymbolRun.DrawSymbol(canvas, textBlob_, offset, paint, xs);
230     } else {
231         canvas.DrawTextBlob(textBlob_, offsetX, offsetY, paint);
232     }
233     PaintDecoration(canvas, offsetX, offsetY, xs);
234 }
235 
236 
SymbolAnimation(const TextStyle & xs)237 void TextSpan::SymbolAnimation(const TextStyle &xs)
238 {
239     if (animationFunc_ == nullptr) {
240         return;
241     }
242     auto spanSymbolAnimationConfig = std::make_shared<SymbolAnimationConfig>();
243     if (spanSymbolAnimationConfig == nullptr) {
244         return;
245     }
246     spanSymbolAnimationConfig->effectStrategy = SymbolAnimationEffectStrategy(xs.symbol.GetEffectStrategy());
247     if (spanSymbolAnimationConfig->effectStrategy == SymbolAnimationEffectStrategy::SYMBOL_HIERARCHICAL) {
248         animationFunc_(spanSymbolAnimationConfig);
249     }
250 }
251 
PaintDecoration(TexgineCanvas & canvas,double offsetX,double offsetY,const TextStyle & xs)252 void TextSpan::PaintDecoration(TexgineCanvas &canvas, double offsetX, double offsetY, const TextStyle &xs)
253 {
254     double left = offsetX;
255     double right = left + GetWidth();
256 
257     if ((xs.decoration & TextDecoration::UNDERLINE) == TextDecoration::UNDERLINE) {
258         double y = offsetY + *tmetrics_->fUnderlinePosition_;
259         PaintDecorationStyle(canvas, left, right, y, xs);
260     }
261     if ((xs.decoration & TextDecoration::OVERLINE) == TextDecoration::OVERLINE) {
262         double y = offsetY - abs(*tmetrics_->fAscent_);
263         PaintDecorationStyle(canvas, left, right, y, xs);
264     }
265     if ((xs.decoration & TextDecoration::LINE_THROUGH) == TextDecoration::LINE_THROUGH) {
266         double y = offsetY - (*tmetrics_->fCapHeight_ * HALF) +
267             (xs.fontSize / DEFAULT_FONT_SIZE * xs.decorationThicknessScale * HALF);
268         PaintDecorationStyle(canvas, left, right, y, xs);
269     }
270     if ((xs.decoration & TextDecoration::BASELINE) == TextDecoration::BASELINE) {
271         double y = offsetY;
272         PaintDecorationStyle(canvas, left, right, y, xs);
273     }
274 }
275 
PaintDecorationStyle(TexgineCanvas & canvas,double left,double right,double y,const TextStyle & xs)276 void TextSpan::PaintDecorationStyle(TexgineCanvas &canvas, double left, double right, double y, const TextStyle &xs)
277 {
278     TexginePaint paint;
279     paint.SetAntiAlias(true);
280     paint.SetARGB(MAXRGB, MAXRGB, 0, 0);
281     paint.SetColor(xs.decorationColor.value_or(xs.color));
282     paint.SetStrokeWidth(xs.fontSize / DEFAULT_FONT_SIZE * xs.decorationThicknessScale * SCALE);
283 
284     switch (xs.decorationStyle) {
285         case TextDecorationStyle::SOLID:
286             break;
287         case TextDecorationStyle::DOUBLE:
288             canvas.DrawLine(left, y, right, y, paint);
289             y += OFFSETY;
290             break;
291         case TextDecorationStyle::DOTTED: {
292             TexginePath circle;
293             auto rect = TexgineRect::MakeWH(WIDTH_SCALAR, HEIGHT_SCALAR);
294             circle.AddOval(rect);
295             paint.SetPathEffect(TexginePath1DPathEffect::Make(circle, DOTTED_ADVANCE, PHASE,
296                 TexginePath1DPathEffect::K_ROTATE_STYLE));
297             break;
298         }
299         case TextDecorationStyle::DASHED: {
300             const float intervals[2] = {WIDTH_SCALAR, HEIGHT_SCALAR};
301             paint.SetPathEffect(TexgineDashPathEffect::Make(intervals, COUNT, PHASE));
302             paint.SetStyle(TexginePaint::STROKE);
303             break;
304         }
305         case TextDecorationStyle::WAVY: {
306             TexginePath wavy;
307             float thickness = xs.decorationThicknessScale;
308             wavy.MoveTo({POINTX0, POINTY2 - thickness});
309             wavy.QuadTo({POINTX1, POINTY0 - thickness}, {POINTX2, POINTY2 - thickness});
310             wavy.LineTo({POINTX3, POINTY4 - thickness});
311             wavy.QuadTo({POINTX4, POINTY6 - thickness}, {POINTX5, POINTY4 - thickness});
312             wavy.LineTo({POINTX6, POINTY2 - thickness});
313             wavy.LineTo({POINTX6, POINTY2 + thickness});
314             wavy.LineTo({POINTX5, POINTY4 + thickness});
315             wavy.QuadTo({POINTX4, POINTY6 + thickness}, {POINTX3, POINTY4 + thickness});
316             wavy.LineTo({POINTX2, POINTY2 + thickness});
317             wavy.QuadTo({POINTX1, POINTY0 + thickness}, {POINTX0, POINTY2 + thickness});
318             wavy.LineTo({POINTX0, POINTY2 - thickness});
319             paint.SetPathEffect(TexginePath1DPathEffect::Make(wavy, WAVY_ADVANCE, PHASE,
320                 TexginePath1DPathEffect::K_ROTATE_STYLE));
321             paint.SetStyle(TexginePaint::STROKE);
322             break;
323         }
324     }
325     canvas.DrawLine(left, y, right, y, paint);
326 }
327 
PaintShadow(TexgineCanvas & canvas,double offsetX,double offsetY,const std::vector<TextShadow> & shadows)328 void TextSpan::PaintShadow(TexgineCanvas &canvas, double offsetX, double offsetY,
329     const std::vector<TextShadow> &shadows)
330 {
331     for (const auto &shadow : shadows) {
332         if (!shadow.HasShadow()) {
333             continue;
334         }
335         auto x = offsetX + shadow.offsetX;
336         auto y = offsetY + shadow.offsetY;
337         TexginePaint paint;
338         paint.SetAntiAlias(true);
339         paint.SetColor(shadow.color);
340         paint.SetMaskFilter(TexgineMaskFilter::MakeBlur(TexgineMaskFilter::K_NORMAL_SK_BLUR_STYLE,
341             shadow.blurLeave, false));
342 
343         canvas.DrawTextBlob(textBlob_, x, y, paint);
344     }
345 }
346 } // namespace TextEngine
347 } // namespace Rosen
348 } // namespace OHOS
349