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
16 #include "text_span.h"
17
18 #include <iomanip>
19 #include <stack>
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 #include "texgine/utils/trace.h"
34 #include "text_converter.h"
35 #include "word_breaker.h"
36
37 namespace OHOS {
38 namespace Rosen {
39 namespace TextEngine {
40 #define MAXRGB 255
41 #define OFFSETY 3
42 #define HALF 0.5f
43 #define WIDTH_SCALAR 5.0f
44 #define HEIGHT_SCALAR 5.0f
45 #define DOTTED_ADVANCE 10.0f
46 #define WAVY_ADVANCE 6.0f
47 #define PHASE 0.0f
48 #define COUNT 2
49 #define MAX_BLURRADIUS 64u
50 #define POINTX0 0
51 #define POINTX1 1
52 #define POINTX2 2
53 #define POINTX3 3
54 #define POINTX4 4
55 #define POINTX5 5
56 #define POINTX6 6
57 #define POINTY0 0
58 #define POINTY2 2
59 #define POINTY4 4
60 #define POINTY6 6
61
MakeEmpty()62 std::shared_ptr<TextSpan> TextSpan::MakeEmpty()
63 {
64 return std::make_shared<TextSpan>();
65 }
66
MakeFromText(const std::string & text)67 std::shared_ptr<TextSpan> TextSpan::MakeFromText(const std::string &text)
68 {
69 auto span = MakeEmpty();
70 auto decodeText = TextConverter::ToUTF16(text);
71 span->AddUTF16Text(decodeText);
72 return span;
73 }
74
MakeFromText(const std::u16string & text)75 std::shared_ptr<TextSpan> TextSpan::MakeFromText(const std::u16string &text)
76 {
77 auto span = MakeEmpty();
78 std::vector<uint16_t> u16;
79 for (const auto &t : text) {
80 u16.push_back(t);
81 }
82 span->AddUTF16Text(u16);
83 return span;
84 }
85
MakeFromText(const std::u32string & text)86 std::shared_ptr<TextSpan> TextSpan::MakeFromText(const std::u32string &text)
87 {
88 auto span = MakeEmpty();
89 std::vector<uint32_t> u32;
90 for (const auto &t : text) {
91 u32.push_back(t);
92 }
93 auto decodeText = TextConverter::ToUTF16(u32);
94 span->AddUTF16Text(decodeText);
95 return span;
96 }
97
MakeFromText(const std::vector<uint16_t> & text)98 std::shared_ptr<TextSpan> TextSpan::MakeFromText(const std::vector<uint16_t> &text)
99 {
100 auto span = MakeEmpty();
101 span->AddUTF16Text(text);
102 return span;
103 }
104
MakeFromText(const std::vector<uint32_t> & text)105 std::shared_ptr<TextSpan> TextSpan::MakeFromText(const std::vector<uint32_t> &text)
106 {
107 auto span = MakeEmpty();
108 auto decodeText = TextConverter::ToUTF16(text);
109 span->AddUTF16Text(decodeText);
110 return span;
111 }
112
MakeFromCharGroups(const CharGroups & cgs)113 std::shared_ptr<TextSpan> TextSpan::MakeFromCharGroups(const CharGroups &cgs)
114 {
115 auto span = MakeEmpty();
116 span->cgs_= cgs;
117 return span;
118 }
119
AddUTF16Text(const std::vector<uint16_t> & text)120 void TextSpan::AddUTF16Text(const std::vector<uint16_t> &text)
121 {
122 u16vect_.insert(u16vect_.end(), text.begin(), text.end());
123 }
124
CloneWithCharGroups(const CharGroups & cgs)125 std::shared_ptr<TextSpan> TextSpan::CloneWithCharGroups(const CharGroups &cgs)
126 {
127 auto span = MakeEmpty();
128 *span = *this;
129 span->cgs_ = cgs;
130 return span;
131 }
132
GetHeight() const133 double TextSpan::GetHeight() const
134 {
135 return *tmetrics_.fDescent_ - *tmetrics_.fAscent_;
136 }
137
GetWidth() const138 double TextSpan::GetWidth() const
139 {
140 return width_;
141 }
142
GetPreBreak() const143 double TextSpan::GetPreBreak() const
144 {
145 return preBreak_;
146 }
147
GetPostBreak() const148 double TextSpan::GetPostBreak() const
149 {
150 return postBreak_;
151 }
152
IsRTL() const153 bool TextSpan::IsRTL() const
154 {
155 return rtl_;
156 }
157
Paint(TexgineCanvas & canvas,double offsetX,double offsetY,const TextStyle & xs)158 void TextSpan::Paint(TexgineCanvas &canvas, double offsetX, double offsetY, const TextStyle &xs)
159 {
160 TexginePaint paint;
161 paint.SetAntiAlias(true);
162 paint.SetARGB(MAXRGB, MAXRGB, 0, 0);
163 paint.SetColor(xs.color);
164 paint.SetStyle(TexginePaint::FILL);
165 if (xs.background.has_value()) {
166 auto rect = TexgineRect::MakeXYWH(offsetX, offsetY + *tmetrics_.fAscent_, width_,
167 *tmetrics_.fDescent_ - *tmetrics_.fAscent_);
168 canvas.DrawRect(rect, xs.background.value());
169 }
170
171 if (xs.foreground.has_value()) {
172 paint = xs.foreground.value();
173 }
174 canvas.DrawTextBlob(textBlob_, offsetX, offsetY, paint);
175 PaintDecoration(canvas, offsetX, offsetY, xs);
176 }
177
PaintDecoration(TexgineCanvas & canvas,double offsetX,double offsetY,const TextStyle & xs)178 void TextSpan::PaintDecoration(TexgineCanvas &canvas, double offsetX, double offsetY, const TextStyle &xs)
179 {
180 double left = offsetX;
181 double right = left + GetWidth();
182
183 if ((xs.decoration & TextDecoration::UNDERLINE) == TextDecoration::UNDERLINE) {
184 double y = offsetY + *tmetrics_.fUnderlinePosition_;
185 PaintDecorationStyle(canvas, left, right, y, xs);
186 }
187 if ((xs.decoration & TextDecoration::OVERLINE) == TextDecoration::OVERLINE) {
188 double y = offsetY - abs(*tmetrics_.fAscent_);
189 PaintDecorationStyle(canvas, left, right, y, xs);
190 }
191 if ((xs.decoration & TextDecoration::LINE_THROUGH) == TextDecoration::LINE_THROUGH) {
192 double y = offsetY - (*tmetrics_.fCapHeight_ * HALF);
193 PaintDecorationStyle(canvas, left, right, y, xs);
194 }
195 if ((xs.decoration & TextDecoration::BASELINE) == TextDecoration::BASELINE) {
196 double y = offsetY;
197 PaintDecorationStyle(canvas, left, right, y, xs);
198 }
199 }
200
PaintDecorationStyle(TexgineCanvas & canvas,double left,double right,double y,const TextStyle & xs)201 void TextSpan::PaintDecorationStyle(TexgineCanvas &canvas, double left, double right, double y, const TextStyle &xs)
202 {
203 TexginePaint paint;
204 paint.SetAntiAlias(true);
205 paint.SetARGB(MAXRGB, MAXRGB, 0, 0);
206 paint.SetColor(xs.decorationColor.value_or(xs.color));
207 paint.SetStrokeWidth(xs.decorationThicknessScale);
208
209 switch (xs.decorationStyle) {
210 case TextDecorationStyle::SOLID:
211 break;
212 case TextDecorationStyle::DOUBLE:
213 canvas.DrawLine(left, y, right, y, paint);
214 y += OFFSETY;
215 break;
216 case TextDecorationStyle::DOTTED: {
217 TexginePath circle;
218 auto rect = TexgineRect::MakeWH(WIDTH_SCALAR, HEIGHT_SCALAR);
219 circle.AddOval(rect);
220 paint.SetPathEffect(TexginePath1DPathEffect::Make(circle, DOTTED_ADVANCE, PHASE,
221 TexginePath1DPathEffect::K_ROTATE_STYLE));
222 break;
223 }
224 case TextDecorationStyle::DASHED: {
225 const float intervals[2] = {WIDTH_SCALAR, HEIGHT_SCALAR};
226 paint.SetPathEffect(TexgineDashPathEffect::Make(intervals, COUNT, PHASE));
227 paint.SetStyle(TexginePaint::STROKE);
228 break;
229 }
230 case TextDecorationStyle::WAVY: {
231 TexginePath wavy;
232 float thickness = xs.decorationThicknessScale;
233 wavy.MoveTo({POINTX0, POINTY2 - thickness});
234 wavy.QuadTo({POINTX1, POINTY0 - thickness}, {POINTX2, POINTY2 - thickness});
235 wavy.LineTo({POINTX3, POINTY4 - thickness});
236 wavy.QuadTo({POINTX4, POINTY6 - thickness}, {POINTX5, POINTY4 - thickness});
237 wavy.LineTo({POINTX6, POINTY2 - thickness});
238 wavy.LineTo({POINTX6, POINTY2 + thickness});
239 wavy.LineTo({POINTX5, POINTY4 + thickness});
240 wavy.QuadTo({POINTX4, POINTY6 + thickness}, {POINTX3, POINTY4 + thickness});
241 wavy.LineTo({POINTX2, POINTY2 + thickness});
242 wavy.QuadTo({POINTX1, POINTY0 + thickness}, {POINTX0, POINTY2 + thickness});
243 wavy.LineTo({POINTX0, POINTY2 - thickness});
244 paint.SetPathEffect(TexginePath1DPathEffect::Make(wavy, WAVY_ADVANCE, PHASE,
245 TexginePath1DPathEffect::K_ROTATE_STYLE));
246 paint.SetStyle(TexginePaint::STROKE);
247 break;
248 }
249 }
250 canvas.DrawLine(left, y, right, y, paint);
251 }
252
PaintShadow(TexgineCanvas & canvas,double offsetX,double offsetY,const std::vector<TextShadow> & shadows)253 void TextSpan::PaintShadow(TexgineCanvas &canvas, double offsetX, double offsetY,
254 const std::vector<TextShadow> &shadows)
255 {
256 for (const auto &shadow : shadows) {
257 auto x = offsetX + shadow.offsetX;
258 auto y = offsetY + shadow.offsetY;
259 auto blurRadius = std::min(shadow.blurLeave, MAX_BLURRADIUS);
260
261 TexginePaint paint;
262 paint.SetAntiAlias(true);
263 paint.SetColor(shadow.color);
264 paint.SetMaskFilter(TexgineMaskFilter::MakeBlur(TexgineMaskFilter::K_NORMAL_SK_BLUR_STYLE, blurRadius));
265
266 canvas.DrawTextBlob(textBlob_, x, y, paint);
267 }
268 }
269 } // namespace TextEngine
270 } // namespace Rosen
271 } // namespace OHOS
272