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