1 /*
2  * Copyright (c) 2023-2024 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 "skia_text_blob.h"
17 
18 #include <map>
19 #include "include/core/SkFontTypes.h"
20 #include "include/core/SkRSXform.h"
21 #include "include/core/SkSerialProcs.h"
22 
23 #include "skia_adapter/skia_convert_utils.h"
24 #include "skia_adapter/skia_data.h"
25 #include "skia_adapter/skia_font.h"
26 #include "skia_adapter/skia_path.h"
27 #include "skia_adapter/skia_typeface.h"
28 #include "utils/log.h"
29 #include "skia_adapter/skia_path_effect.h"
30 
31 namespace OHOS {
32 namespace Rosen {
33 namespace Drawing {
34 static const std::map<Drawing::Paint::PaintStyle, SkPaint::Style> PAINT_STYLE = {
35     {Drawing::Paint::PaintStyle::PAINT_FILL, SkPaint::kFill_Style},
36     {Drawing::Paint::PaintStyle::PAINT_STROKE, SkPaint::kStroke_Style},
37     {Drawing::Paint::PaintStyle::PAINT_FILL_STROKE, SkPaint::kStrokeAndFill_Style},
38 };
39 
SkiaTextBlob(sk_sp<SkTextBlob> skTextBlob)40 SkiaTextBlob::SkiaTextBlob(sk_sp<SkTextBlob> skTextBlob) : skTextBlob_(skTextBlob) {}
41 
GetTextBlob() const42 sk_sp<SkTextBlob> SkiaTextBlob::GetTextBlob() const
43 {
44     return skTextBlob_;
45 }
46 
MakeFromText(const void * text,size_t byteLength,const Font & font,TextEncoding encoding)47 std::shared_ptr<TextBlob> SkiaTextBlob::MakeFromText(const void* text, size_t byteLength,
48     const Font& font, TextEncoding encoding)
49 {
50     auto skiaFont = font.GetImpl<SkiaFont>();
51     if (!skiaFont) {
52         LOGD("skiaFont nullptr, %{public}s, %{public}d", __FUNCTION__, __LINE__);
53         return nullptr;
54     }
55     SkTextEncoding skEncoding = static_cast<SkTextEncoding>(encoding);
56     sk_sp<SkTextBlob> skTextBlob = SkTextBlob::MakeFromText(text, byteLength, skiaFont->GetFont(), skEncoding);
57     if (!skTextBlob) {
58         LOGD("skTextBlob nullptr, %{public}s, %{public}d", __FUNCTION__, __LINE__);
59         return nullptr;
60     }
61     std::shared_ptr<TextBlobImpl> textBlobImpl = std::make_shared<SkiaTextBlob>(skTextBlob);
62     return std::make_shared<TextBlob>(textBlobImpl);
63 }
64 
MakeFromPosText(const void * text,size_t byteLength,const Point pos[],const Font & font,TextEncoding encoding)65 std::shared_ptr<TextBlob> SkiaTextBlob::MakeFromPosText(const void* text, size_t byteLength,
66     const Point pos[], const Font& font, TextEncoding encoding)
67 {
68     auto skiaFont = font.GetImpl<SkiaFont>();
69     if (!skiaFont) {
70         LOGD("skiaFont nullptr, %{public}s, %{public}d", __FUNCTION__, __LINE__);
71         return nullptr;
72     }
73 
74     SkTextEncoding skEncoding = static_cast<SkTextEncoding>(encoding);
75     auto skFont = skiaFont->GetFont();
76     const int count = skFont.countText(text, byteLength, skEncoding);
77     SkPoint skPts[count];
78     for (int i = 0; i < count; ++i) {
79         skPts[i] = {pos[i].GetX(), pos[i].GetY()};
80     }
81     sk_sp<SkTextBlob> skTextBlob = SkTextBlob::MakeFromPosText(text, byteLength, skPts, skFont, skEncoding);
82     if (!skTextBlob) {
83         LOGD("skTextBlob nullptr, %{public}s, %{public}d", __FUNCTION__, __LINE__);
84         return nullptr;
85     }
86     std::shared_ptr<TextBlobImpl> textBlobImpl = std::make_shared<SkiaTextBlob>(skTextBlob);
87     return std::make_shared<TextBlob>(textBlobImpl);
88 }
89 
MakeFromRSXform(const void * text,size_t byteLength,const RSXform xform[],const Font & font,TextEncoding encoding)90 std::shared_ptr<TextBlob> SkiaTextBlob::MakeFromRSXform(const void* text, size_t byteLength,
91     const RSXform xform[], const Font& font, TextEncoding encoding)
92 {
93     auto skiaFont = font.GetImpl<SkiaFont>();
94     if (!skiaFont) {
95         LOGD("skiaFont nullptr, %{public}s, %{public}d", __FUNCTION__, __LINE__);
96         return nullptr;
97     }
98     SkTextEncoding skEncoding = static_cast<SkTextEncoding>(encoding);
99     SkRSXform skXform;
100     if (xform) {
101         SkiaConvertUtils::DrawingRSXformCastToSkXform(*xform, skXform);
102     }
103     sk_sp<SkTextBlob> skTextBlob =
104         SkTextBlob::MakeFromRSXform(text, byteLength, xform ? &skXform : nullptr, skiaFont->GetFont(), skEncoding);
105     if (!skTextBlob) {
106         LOGD("skTextBlob nullptr, %{public}s, %{public}d", __FUNCTION__, __LINE__);
107         return nullptr;
108     }
109     std::shared_ptr<TextBlobImpl> textBlobImpl = std::make_shared<SkiaTextBlob>(skTextBlob);
110     return std::make_shared<TextBlob>(textBlobImpl);
111 }
112 
Serialize(void * ctx) const113 std::shared_ptr<Data> SkiaTextBlob::Serialize(void* ctx) const
114 {
115     if (!skTextBlob_) {
116         LOGD("skTextBlob nullptr, %{public}s, %{public}d", __FUNCTION__, __LINE__);
117         return nullptr;
118     }
119     SkSerialProcs procs;
120     procs.fTypefaceProc = &SkiaTypeface::SerializeTypeface;
121     procs.fTypefaceCtx = ctx;
122     auto skData = skTextBlob_->serialize(procs);
123     auto data = std::make_shared<Data>();
124     auto skiaData = data->GetImpl<SkiaData>();
125     if (!skiaData) {
126         LOGD("skiaData nullptr, %{public}s, %{public}d", __FUNCTION__, __LINE__);
127         return nullptr;
128     }
129     skiaData->SetSkData(skData);
130     return data;
131 }
132 
Deserialize(const void * data,size_t size,void * ctx)133 std::shared_ptr<TextBlob> SkiaTextBlob::Deserialize(const void* data, size_t size, void* ctx)
134 {
135     SkDeserialProcs procs;
136     procs.fTypefaceProc = &SkiaTypeface::DeserializeTypeface;
137     procs.fTypefaceCtx = ctx;
138     sk_sp<SkTextBlob> skTextBlob = SkTextBlob::Deserialize(data, size, procs);
139     if (!skTextBlob) {
140         LOGD("skTextBlob nullptr, %{public}s, %{public}d", __FUNCTION__, __LINE__);
141         return nullptr;
142     }
143     std::shared_ptr<TextBlobImpl> textBlobImpl = std::make_shared<SkiaTextBlob>(skTextBlob);
144     return std::make_shared<TextBlob>(textBlobImpl);
145 }
146 
ConvertSkStyle(Paint::PaintStyle style)147 static SkPaint::Style ConvertSkStyle(Paint::PaintStyle style)
148 {
149     if (PAINT_STYLE.find(style) != PAINT_STYLE.end()) {
150         return PAINT_STYLE.at(style);
151     } else {
152         return SkPaint::kStrokeAndFill_Style;
153     }
154 }
155 
ConvertSkPaint(const Paint * drawingPaint,SkPaint & skPaint)156 static void ConvertSkPaint(const Paint* drawingPaint, SkPaint &skPaint)
157 {
158     if (drawingPaint == nullptr) {
159         return;
160     }
161     skPaint.setStyle(ConvertSkStyle(drawingPaint->GetStyle()));
162     skPaint.setAntiAlias(drawingPaint->IsAntiAlias());
163     Color color = drawingPaint->GetColor();
164     skPaint.setColor(Color::ColorQuadSetARGB(color.GetAlpha(), color.GetRed(), color.GetGreen(), color.GetGreen()));
165     skPaint.setStrokeWidth(drawingPaint->GetWidth());
166     const std::shared_ptr<PathEffect> effect = drawingPaint->GetPathEffect();
167     if (effect != nullptr) {
168         SkiaPathEffect *skiaEffect = effect->GetImpl<SkiaPathEffect>();
169         if (skiaEffect != nullptr) {
170             skPaint.setPathEffect(skiaEffect->GetPathEffect());
171         }
172     }
173 }
174 
GetIntercepts(const float bounds[],float intervals[],const Paint * paint) const175 int SkiaTextBlob::GetIntercepts(const float bounds[], float intervals[], const Paint* paint) const
176 {
177     if (skTextBlob_ && paint != nullptr) {
178         SkPaint skPaint;
179         ConvertSkPaint(paint, skPaint);
180         return skTextBlob_->getIntercepts(bounds, intervals, &skPaint);
181     }
182     return 0;
183 }
184 
GetDrawingGlyphIDforTextBlob(const TextBlob * blob,std::vector<uint16_t> & glyphIds)185 void SkiaTextBlob::GetDrawingGlyphIDforTextBlob(const TextBlob* blob, std::vector<uint16_t>& glyphIds)
186 {
187     SkTextBlob* skTextBlob = nullptr;
188     if (blob) {
189         auto skiaBlobImpl = blob->GetImpl<SkiaTextBlob>();
190         if (skiaBlobImpl != nullptr) {
191             skTextBlob = skiaBlobImpl->GetTextBlob().get();
192         }
193     }
194     GetGlyphIDforTextBlob(skTextBlob, glyphIds);
195 }
196 
GetDrawingPathforTextBlob(uint16_t glyphId,const TextBlob * blob)197 Path SkiaTextBlob::GetDrawingPathforTextBlob(uint16_t glyphId, const TextBlob* blob)
198 {
199     SkTextBlob* skTextBlob = nullptr;
200     if (blob) {
201         auto skiaBlobImpl = blob->GetImpl<SkiaTextBlob>();
202         if (skiaBlobImpl != nullptr) {
203             skTextBlob = skiaBlobImpl->GetTextBlob().get();
204         }
205     }
206     SkPath skPath = GetPathforTextBlob(glyphId, skTextBlob);
207     Path path;
208     path.GetImpl<SkiaPath>()->SetPath(skPath);
209     return path;
210 }
211 
GetDrawingPointsForTextBlob(const TextBlob * blob,std::vector<Point> & points)212 void SkiaTextBlob::GetDrawingPointsForTextBlob(const TextBlob* blob, std::vector<Point>& points)
213 {
214     if (blob == nullptr) {
215         return;
216     }
217     SkTextBlob* skTextBlob = nullptr;
218     if (blob) {
219         auto skiaBlobImpl = blob->GetImpl<SkiaTextBlob>();
220         if (skiaBlobImpl != nullptr) {
221             skTextBlob = skiaBlobImpl->GetTextBlob().get();
222         }
223     }
224     std::vector<SkPoint> skPoints;
225     GetPointsForTextBlob(skTextBlob, skPoints);
226 
227     points.reserve(skPoints.size());
228     for (const auto& p : skPoints) {
229         points.emplace_back(p.x(), p.y());
230     }
231 }
232 
Bounds() const233 std::shared_ptr<Rect> SkiaTextBlob::Bounds() const
234 {
235     if (skTextBlob_) {
236         auto bounds = skTextBlob_->bounds();
237         return std::make_shared<Rect>(bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
238     }
239     return nullptr;
240 }
241 
UniqueID() const242 uint32_t SkiaTextBlob::UniqueID() const
243 {
244     if (skTextBlob_) {
245         return skTextBlob_->uniqueID();
246     }
247     return 0;
248 }
249 } // namespace Drawing
250 } // namespace Rosen
251 } // namespace OHOS