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