• 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 
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