1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.. All rights reserved.
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 "drawing_painter_impl.h"
17
18 #include <array>
19 #include <memory>
20
21 #include "include/core/SkBlurTypes.h"
22 #include "include/core/SkMaskFilter.h"
23 #include "include/effects/SkDashPathEffect.h"
24 #include "include/effects/SkDiscretePathEffect.h"
25 #include "modules/skparagraph/include/drawing.h"
26 #include "paint_record.h"
27 #include "skia_adapter/skia_paint.h"
28 #include "skia_adapter/skia_path.h"
29 #include "skia_adapter/skia_text_blob.h"
30 #include "symbol_engine/hm_symbol_run.h"
31 #include "utils/text_trace.h"
32
33 #ifdef HM_SYMBOL_TXT_ENABLE
34 #include <parameters.h>
35
36 const bool G_IS_HM_SYMBOL_TXT_ENABLE =
37 (std::atoi(OHOS::system::GetParameter("persist.sys.graphic.hmsymboltxt.enable", "1").c_str()) != 0);
38 #else
39 const bool G_IS_HM_SYMBOL_TXT_ENABLE = true;
40 #endif
41
42
43 namespace OHOS {
44 namespace Rosen {
45 namespace SPText {
ConvertDecorStyle(const ParagraphPainter::DecorationStyle & decorStyle,Drawing::Paint::PaintStyle drawStyle=Drawing::Paint::PAINT_STROKE)46 static Drawing::Paint ConvertDecorStyle(const ParagraphPainter::DecorationStyle& decorStyle,
47 Drawing::Paint::PaintStyle drawStyle = Drawing::Paint::PAINT_STROKE)
48 {
49 Drawing::Paint paint;
50 paint.SetStyle(drawStyle);
51 paint.SetAntiAlias(true);
52 paint.SetColor(PaintRecord::ToRSColor(decorStyle.getColor()));
53 paint.SetWidth(decorStyle.getStrokeWidth());
54 if (decorStyle.getDashPathEffect().has_value()) {
55 auto dashPathEffect = decorStyle.getDashPathEffect().value();
56 Drawing::scalar intervals[] = {dashPathEffect.fOnLength, dashPathEffect.fOffLength,
57 dashPathEffect.fOnLength, dashPathEffect.fOffLength};
58 size_t count = sizeof(intervals) / sizeof(intervals[0]);
59 auto pathEffect1 = Drawing::PathEffect::CreateDashPathEffect(intervals, count, 0.0f);
60 auto pathEffect2 = Drawing::PathEffect::CreateDiscretePathEffect(0, 0);
61 auto pathEffect = Drawing::PathEffect::CreateComposePathEffect(*pathEffect1.get(), *pathEffect2.get());
62 paint.SetPathEffect(pathEffect);
63 }
64 return paint;
65 }
66
ToDrawingRect(const SkRect & skRect)67 static Drawing::Rect ToDrawingRect(const SkRect& skRect)
68 {
69 Drawing::Rect rect;
70 rect.SetLeft(skRect.fLeft);
71 rect.SetTop(skRect.fTop);
72 rect.SetRight(skRect.fRight);
73 rect.SetBottom(skRect.fBottom);
74 return rect;
75 }
76
ToDrawingRoundRect(const SkRRect & skRRect)77 static Drawing::RoundRect ToDrawingRoundRect(const SkRRect& skRRect)
78 {
79 Drawing::Rect rect;
80 rect.SetLeft(skRRect.rect().fLeft);
81 rect.SetTop(skRRect.rect().fTop);
82 rect.SetRight(skRRect.rect().fRight);
83 rect.SetBottom(skRRect.rect().fBottom);
84 Drawing::scalar ltRadius = skRRect.radii(SkRRect::Corner::kUpperLeft_Corner).x();
85 Drawing::scalar rtRadius = skRRect.radii(SkRRect::Corner::kUpperRight_Corner).x();
86 Drawing::scalar rbRadius = skRRect.radii(SkRRect::Corner::kLowerRight_Corner).x();
87 Drawing::scalar lbRadius = skRRect.radii(SkRRect::Corner::kLowerLeft_Corner).x();
88 Drawing::Point leftTop = {ltRadius, ltRadius};
89 Drawing::Point rightTop = {rtRadius, rtRadius};
90 Drawing::Point rightBottom = {rbRadius, rbRadius};
91 Drawing::Point leftBottom = {lbRadius, lbRadius};
92 Drawing::RoundRect roundRect(rect, {leftTop, rightTop, rightBottom, leftBottom});
93 return roundRect;
94 }
95
RSCanvasParagraphPainter(Drawing::Canvas * canvas,const std::vector<PaintRecord> & paints)96 RSCanvasParagraphPainter::RSCanvasParagraphPainter(Drawing::Canvas* canvas, const std::vector<PaintRecord>& paints)
97 : canvas_(canvas), paints_(paints)
98 {}
99
DrawSymbolSkiaTxt(const std::shared_ptr<RSTextBlob> & blob,const RSPoint & offset,const PaintRecord & pr)100 void RSCanvasParagraphPainter::DrawSymbolSkiaTxt(const std::shared_ptr<RSTextBlob>& blob, const RSPoint& offset,
101 const PaintRecord &pr)
102 {
103 std::shared_ptr<HMSymbolRun> hmSymbolRun = generateSymbolRun(blob, pr);
104 if (hmSymbolRun == nullptr) {
105 return;
106 }
107
108 if (pr.pen.has_value() && pr.brush.has_value()) {
109 canvas_->AttachBrush(pr.brush.value());
110 canvas_->AttachPen(pr.pen.value());
111 hmSymbolRun->DrawSymbol(canvas_, offset);
112 canvas_->DetachPen();
113 canvas_->DetachBrush();
114 } else if (pr.pen.has_value() && !pr.brush.has_value()) {
115 canvas_->AttachPen(pr.pen.value());
116 hmSymbolRun->DrawSymbol(canvas_, offset);
117 canvas_->DetachPen();
118 } else if (!pr.pen.has_value() && pr.brush.has_value()) {
119 canvas_->AttachBrush(pr.brush.value());
120 hmSymbolRun->DrawSymbol(canvas_, offset);
121 canvas_->DetachBrush();
122 } else {
123 Drawing::Brush brush;
124 brush.SetColor(pr.color);
125 brush.SetAntiAlias(true);
126 canvas_->AttachBrush(brush);
127 hmSymbolRun->DrawSymbol(canvas_, offset);
128 canvas_->DetachBrush();
129 }
130 }
131
drawTextBlob(const std::shared_ptr<RSTextBlob> & blob,SkScalar x,SkScalar y,const SkPaintOrID & paint)132 void RSCanvasParagraphPainter::drawTextBlob(const std::shared_ptr<RSTextBlob>& blob, SkScalar x, SkScalar y,
133 const SkPaintOrID& paint)
134 {
135 TEXT_TRACE_FUNC();
136 SkASSERT(!std::holds_alternative<SkPaint>(paint));
137 const PaintRecord& pr = paints_[std::get<PaintID>(paint)];
138
139 if (pr.isSymbolGlyph && G_IS_HM_SYMBOL_TXT_ENABLE) {
140 std::vector<RSPoint> points;
141 RSTextBlob::GetDrawingPointsForTextBlob(blob.get(), points);
142 RSPoint offset;
143 if (points.size() > 0) {
144 offset = RSPoint{ x + points[0].GetX(), y + points[0].GetY() };
145 } else {
146 offset = RSPoint{ x, y };
147 }
148 DrawSymbolSkiaTxt(blob, offset, pr);
149 } else if (pr.pen.has_value() && pr.brush.has_value()) {
150 canvas_->AttachPen(pr.pen.value());
151 canvas_->DrawTextBlob(blob.get(), x, y);
152 canvas_->DetachPen();
153 canvas_->AttachBrush(pr.brush.value());
154 canvas_->DrawTextBlob(blob.get(), x, y);
155 canvas_->DetachBrush();
156 } else if (pr.pen.has_value() && !pr.brush.has_value()) {
157 canvas_->AttachPen(pr.pen.value());
158 canvas_->DrawTextBlob(blob.get(), x, y);
159 canvas_->DetachPen();
160 } else if (!pr.pen.has_value() && pr.brush.has_value()) {
161 canvas_->AttachBrush(pr.brush.value());
162 canvas_->DrawTextBlob(blob.get(), x, y);
163 canvas_->DetachBrush();
164 } else {
165 Drawing::Brush brush;
166 if (blob != nullptr && blob->IsEmoji()) {
167 brush.SetBlenderEnabled(false);
168 }
169 brush.SetColor(pr.color);
170 canvas_->AttachBrush(brush);
171 canvas_->DrawTextBlob(blob.get(), x, y);
172 canvas_->DetachBrush();
173 }
174 }
175
SymbolAnimation(const PaintRecord & pr)176 void RSCanvasParagraphPainter::SymbolAnimation(const PaintRecord &pr)
177 {
178 auto painterSymbolAnimationConfig = std::make_shared<TextEngine::SymbolAnimationConfig>();
179 if (painterSymbolAnimationConfig == nullptr) {
180 return;
181 }
182 painterSymbolAnimationConfig->effectStrategy = pr.symbol.GetEffectStrategy();
183 if (animationFunc_ != nullptr) {
184 animationFunc_(painterSymbolAnimationConfig);
185 }
186 }
187
drawTextShadow(const std::shared_ptr<RSTextBlob> & blob,SkScalar x,SkScalar y,SkColor color,SkScalar blurSigma)188 void RSCanvasParagraphPainter::drawTextShadow(const std::shared_ptr<RSTextBlob>& blob, SkScalar x, SkScalar y,
189 SkColor color, SkScalar blurSigma)
190 {
191 Drawing::Filter filter;
192 filter.SetMaskFilter(Drawing::MaskFilter::CreateBlurMaskFilter(Drawing::BlurType::NORMAL, blurSigma, false));
193
194 Drawing::Brush brush;
195 brush.SetColor(PaintRecord::ToRSColor(color));
196 brush.SetAntiAlias(true);
197 brush.SetFilter(filter);
198
199 canvas_->AttachBrush(brush);
200 canvas_->DrawTextBlob(blob.get(), x, y);
201 canvas_->DetachBrush();
202 }
203
drawRect(const SkRect & rect,const SkPaintOrID & paint)204 void RSCanvasParagraphPainter::drawRect(const SkRect& rect, const SkPaintOrID& paint)
205 {
206 SkASSERT(!std::holds_alternative<SkPaint>(paint));
207 const PaintRecord& pr = paints_[std::get<PaintID>(paint)];
208 Drawing::Rect rsRect = ToDrawingRect(rect);
209
210 if (pr.pen.has_value()) {
211 canvas_->AttachPen(pr.pen.value());
212 canvas_->DrawRect(rsRect);
213 canvas_->DetachPen();
214 }
215 if (pr.brush.has_value()) {
216 canvas_->AttachBrush(pr.brush.value());
217 canvas_->DrawRect(rsRect);
218 canvas_->DetachBrush();
219 }
220 }
221
drawRRect(const SkRRect & rrect,const SkColor color)222 void RSCanvasParagraphPainter::drawRRect(const SkRRect& rrect, const SkColor color)
223 {
224 Drawing::RoundRect rsRRect = ToDrawingRoundRect(rrect);
225 Drawing::Brush brush;
226 brush.SetColor(PaintRecord::ToRSColor(color));
227 brush.SetAntiAlias(false);
228 canvas_->AttachBrush(brush);
229 canvas_->DrawRoundRect(rsRRect);
230 canvas_->DetachBrush();
231 }
232
drawFilledRect(const SkRect & rect,const DecorationStyle & decorStyle)233 void RSCanvasParagraphPainter::drawFilledRect(const SkRect& rect, const DecorationStyle& decorStyle)
234 {
235 Drawing::Paint paint = ConvertDecorStyle(decorStyle, Drawing::Paint::PAINT_FILL);
236 Drawing::Rect rsRect = ToDrawingRect(rect);
237
238 canvas_->AttachPaint(paint);
239 canvas_->DrawRect(rsRect);
240 canvas_->DetachPaint();
241 }
242
drawPath(const RSPath & path,const DecorationStyle & decorStyle)243 void RSCanvasParagraphPainter::drawPath(const RSPath& path, const DecorationStyle& decorStyle)
244 {
245 Drawing::Paint paint = ConvertDecorStyle(decorStyle);
246
247 canvas_->AttachPaint(paint);
248 canvas_->DrawPath(path);
249 canvas_->DetachPaint();
250 }
251
drawLine(SkScalar x0,SkScalar y0,SkScalar x1,SkScalar y1,const DecorationStyle & decorStyle)252 void RSCanvasParagraphPainter::drawLine(
253 SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const DecorationStyle& decorStyle)
254 {
255 Drawing::Paint paint = ConvertDecorStyle(decorStyle);
256 Drawing::Point point0(x0, y0);
257 Drawing::Point point1(x1, y1);
258
259 canvas_->AttachPaint(paint);
260 canvas_->DrawLine(point0, point1);
261 canvas_->DetachPaint();
262 }
263
clipRect(const SkRect & rect)264 void RSCanvasParagraphPainter::clipRect(const SkRect& rect)
265 {
266 Drawing::Rect rsRect = ToDrawingRect(rect);
267 canvas_->ClipRect(rsRect);
268 }
269
translate(SkScalar dx,SkScalar dy)270 void RSCanvasParagraphPainter::translate(SkScalar dx, SkScalar dy)
271 {
272 canvas_->Translate(dx, dy);
273 }
274
save()275 void RSCanvasParagraphPainter::save()
276 {
277 canvas_->Save();
278 }
279
restore()280 void RSCanvasParagraphPainter::restore()
281 {
282 canvas_->Restore();
283 }
284
generateSymbolRun(const std::shared_ptr<RSTextBlob> & blob,const PaintRecord & pr)285 std::shared_ptr<HMSymbolRun> RSCanvasParagraphPainter::generateSymbolRun(
286 const std::shared_ptr<RSTextBlob>& blob, const PaintRecord& pr)
287 {
288 for (const std::shared_ptr<HMSymbolRun>& hmSymbol : hmSymbols_) {
289 if (hmSymbol->GetSymbolUid() != pr.symbol.GetSymbolUid()) {
290 continue;
291 }
292
293 hmSymbol->SetTextBlob(blob);
294 hmSymbol->SetSymbolTxt(pr.symbol);
295 return hmSymbol;
296 }
297 return nullptr;
298 }
299 } // namespace SPText
300 } // namespace Rosen
301 } // namespace OHOS
302