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 #ifdef OHOS_SUPPORT
17 #include "ParagraphImpl.h"
18 #endif
19 #include "modules/skparagraph/src/RunBaseImpl.h"
20 
21 namespace skia {
22 namespace textlayout {
RunBaseImpl( sk_sp<SkTextBlob> blob, SkPoint offset, ParagraphPainter::SkPaintOrID paint, bool clippingNeeded, SkRect clipRect, const Run* visitorRun, size_t visitorPos, size_t visitorGlobalPos, size_t trailSpaces, size_t visitorSize)23 RunBaseImpl::RunBaseImpl(
24 #ifndef USE_SKIA_TXT
25     sk_sp<SkTextBlob> blob,
26 #else
27     std::shared_ptr<RSTextBlob> blob,
28 #endif
29     SkPoint offset,
30     ParagraphPainter::SkPaintOrID paint,
31     bool clippingNeeded,
32     SkRect clipRect,
33     const Run* visitorRun,
34     size_t visitorPos,
35 #ifdef OHOS_SUPPORT
36     size_t visitorGlobalPos,
37     size_t trailSpaces,
38 #endif
39     size_t visitorSize)
40     : fBlob(blob),
41     fOffset(offset),
42     fClippingNeeded(clippingNeeded),
43     fClipRect(clipRect),
44     fVisitorRun(visitorRun),
45     fVisitorPos(visitorPos),
46 #ifdef OHOS_SUPPORT
47     fVisitorGlobalPos(visitorGlobalPos),
48     fTrailSpaces(trailSpaces),
49 #endif
50     fVisitorSize(visitorSize)
51 {
52     if (std::holds_alternative<SkPaint>(paint)) {
53         fPaint = std::get<SkPaint>(paint);
54     } else if (std::holds_alternative<ParagraphPainter::PaintID>(paint)) {
55         fPaint = std::get<ParagraphPainter::PaintID>(paint);
56     }
57 
58 }
59 
60 #ifndef USE_SKIA_TXT
font() const61 const SkFont& RunBaseImpl::font() const
62 #else
63 const RSFont& RunBaseImpl::font() const
64 #endif
65 {
66     if (!fVisitorRun) {
67         return {};
68     }
69     return fVisitorRun->font();
70 }
71 
size() const72 size_t RunBaseImpl::size() const
73 {
74     return fVisitorSize;
75 }
76 
getGlyphs() const77 std::vector<uint16_t> RunBaseImpl::getGlyphs() const
78 {
79     if (!fVisitorRun) {
80         return {};
81     }
82     SkSpan<const SkGlyphID> glyphIDSpan = fVisitorRun->glyphs();
83     SkSpan<const SkGlyphID> runGlyphIDSpan = glyphIDSpan.subspan(fVisitorPos, fVisitorSize);
84     return std::vector<uint16_t>(runGlyphIDSpan.begin(), runGlyphIDSpan.end());
85 }
86 
getPositions() const87 std::vector<RSPoint> RunBaseImpl::getPositions() const
88 {
89     if (!fVisitorRun) {
90         return {};
91     }
92     SkSpan<const SkPoint> positionSpan = fVisitorRun->positions();
93     SkSpan<const SkPoint> runPositionSpan = positionSpan.subspan(fVisitorPos, fVisitorSize);
94     std::vector<RSPoint> positions;
95     for (size_t i = 0; i < runPositionSpan.size(); i++) {
96         RSPoint point(runPositionSpan[i].fX, runPositionSpan[i].fY);
97         positions.emplace_back(point);
98     }
99 
100     return positions;
101 
102 }
103 
getOffsets() const104 std::vector<RSPoint> RunBaseImpl::getOffsets() const
105 {
106     if (!fVisitorRun) {
107         return {};
108     }
109     SkSpan<const SkPoint> offsetSpan = fVisitorRun->offsets();
110     SkSpan<const SkPoint> runOffsetSpan = offsetSpan.subspan(fVisitorPos, fVisitorSize);
111     std::vector<RSPoint> offsets;
112     for (size_t i = 0; i < runOffsetSpan.size(); i++) {
113         RSPoint point(runOffsetSpan[i].fX, runOffsetSpan[i].fY);
114         offsets.emplace_back(point);
115     }
116 
117     return offsets;
118 
119 }
120 
paint(ParagraphPainter* painter, SkScalar x, SkScalar y)121 void RunBaseImpl::paint(ParagraphPainter* painter, SkScalar x, SkScalar y)
122 {
123     if (!painter) {
124         return;
125     }
126     if (fClippingNeeded) {
127         painter->save();
128         painter->clipRect(fClipRect.makeOffset(x, y));
129     }
130     painter->drawTextBlob(fBlob, x + fOffset.x(), y + fOffset.y(), fPaint);
131     if (fClippingNeeded) {
132         painter->restore();
133     }
134 }
135 
getVisitorPos() const136 size_t RunBaseImpl::getVisitorPos() const
137 {
138     return fVisitorPos;
139 }
140 
getVisitorSize() const141 size_t RunBaseImpl::getVisitorSize() const
142 {
143     return fVisitorSize;
144 }
145 
146 #ifdef OHOS_SUPPORT
getGlyphs(int64_t start, int64_t length) const147 std::vector<uint16_t> RunBaseImpl::getGlyphs(int64_t start, int64_t length) const
148 {
149     if (!fVisitorRun) {
150         return {};
151     }
152     uint64_t actualLength = calculateActualLength(start, length);
153     if (actualLength == 0) {
154         return {};
155     }
156     SkSpan<const SkGlyphID> glyphIdSpan = fVisitorRun->glyphs();
157     SkSpan<const SkGlyphID> runGlyphIdSpan = glyphIdSpan.subspan(fVisitorPos + start, actualLength);
158     std::vector<uint16_t> glyphs;
159     for (size_t i = 0; i < runGlyphIdSpan.size(); i++) {
160         glyphs.emplace_back(runGlyphIdSpan[i]);
161     }
162 
163     return glyphs;
164 }
165 
166 #ifndef USE_SKIA_TXT
getPositions(int64_t start, int64_t length) const167 std::vector<SkPoint> RunBaseImpl::getPositions(int64_t start, int64_t length) const
168 #else
169 std::vector<RSPoint> RunBaseImpl::getPositions(int64_t start, int64_t length) const
170 #endif
171 {
172     if (!fVisitorRun) {
173         return {};
174     }
175     uint64_t actualLength = calculateActualLength(start, length);
176     if (actualLength == 0) {
177         return {};
178     }
179     SkSpan<const SkPoint> positionSpan = fVisitorRun->positions();
180     SkSpan<const SkPoint> runPositionSpan = positionSpan.subspan(fVisitorPos + start, actualLength);
181 #ifndef USE_SKIA_TXT
182     std::vector<SkPoint> positions;
183 #else
184     std::vector<RSPoint> positions;
185 #endif
186     for (size_t i = 0; i < runPositionSpan.size(); i++) {
187 #ifndef USE_SKIA_TXT
188         positions.emplace_back(SkPoint::Make(runPositionSpan[i].fX, runPositionSpan[i].fY));
189 #else
190         positions.emplace_back(runPositionSpan[i].fX, runPositionSpan[i].fY);
191 #endif
192     }
193 
194     return positions;
195 }
196 
getStringRange(uint64_t* location, uint64_t* length) const197 void RunBaseImpl::getStringRange(uint64_t* location, uint64_t* length) const
198 {
199     if (location == nullptr || length == nullptr) {
200         return;
201     } else if (!fVisitorRun) {
202         *location = 0;
203         *length = 0;
204         return;
205     }
206     *location = fVisitorGlobalPos;
207     *length = fVisitorSize;
208 }
209 
getStringIndices(int64_t start, int64_t length) const210 std::vector<uint64_t> RunBaseImpl::getStringIndices(int64_t start, int64_t length) const
211 {
212     if (!fVisitorRun) {
213         return {};
214     }
215     uint64_t actualLength = calculateActualLength(start, length);
216     if (actualLength == 0) {
217         return {};
218     }
219     std::vector<uint64_t> indices;
220     for (size_t i = 0; i < actualLength; i++) {
221         indices.emplace_back(fVisitorGlobalPos + start + i);
222     }
223 
224     return indices;
225 }
226 
getAllGlyphRectInfo(SkSpan<const SkGlyphID>& runGlyphIdSpan, size_t startNotWhiteSpaceIndex, SkScalar startWhiteSpaceWidth, size_t endWhiteSpaceNum, SkScalar endAdvance) const227 SkRect RunBaseImpl::getAllGlyphRectInfo(SkSpan<const SkGlyphID>& runGlyphIdSpan, size_t startNotWhiteSpaceIndex,
228     SkScalar startWhiteSpaceWidth, size_t endWhiteSpaceNum, SkScalar endAdvance) const
229 {
230     SkRect rect = {0.0, 0.0, 0.0, 0.0};
231     SkScalar runNotWhiteSpaceWidth = 0.0;
232 #ifndef USE_SKIA_TXT
233     SkRect joinRect{0.0, 0.0, 0.0, 0.0};
234     SkRect endRect {0.0, 0.0, 0.0, 0.0};
235     SkRect startRect {0.0, 0.0, 0.0, 0.0};
236 #else
237     RSRect joinRect{0.0, 0.0, 0.0, 0.0};
238     RSRect endRect {0.0, 0.0, 0.0, 0.0};
239     RSRect startRect {0.0, 0.0, 0.0, 0.0};
240 #endif
241     size_t end = runGlyphIdSpan.size() - endWhiteSpaceNum;
242     for (size_t i = startNotWhiteSpaceIndex; i < end; i++) {
243     // Get the bounds of each glyph
244 #ifndef USE_SKIA_TXT
245         SkRect glyphBounds;
246         fVisitorRun->font().getBounds(&runGlyphIdSpan[i], 1, &glyphBounds, nullptr);
247 #else
248         RSRect glyphBounds;
249         fVisitorRun->font().GetWidths(&runGlyphIdSpan[i], 1, nullptr, &glyphBounds);
250 #endif
251         // Record the first non-blank glyph boundary
252         if (i == startNotWhiteSpaceIndex) {
253             startRect = glyphBounds;
254         }
255         if (i == end - 1) {
256             endRect = glyphBounds;
257         }
258         // Stitching removes glyph boundaries at the beginning and end of lines
259         joinRect.Join(glyphBounds);
260         auto& cluster = fVisitorRun->owner()->cluster(fVisitorGlobalPos + i);
261         // Calculates the width of the glyph with the beginning and end of the line removed
262         runNotWhiteSpaceWidth += cluster.width();
263     }
264 #ifndef USE_SKIA_TXT
265     // If the first glyph of run is a blank glyph, you need to add startWhitespaceWidth
266     SkScalar x = fClipRect.fLeft + startRect.x() + startWhiteSpaceWidth;
267     SkScalar y = joinRect.bottom();
268     SkScalar width = runNotWhiteSpaceWidth - (endAdvance - endRect.x() - endRect.width()) - startRect.x();
269     SkScalar height = joinRect.height();
270 #else
271     SkScalar x = fClipRect.fLeft + startRect.GetLeft() + startWhiteSpaceWidth;
272     SkScalar y = joinRect.GetBottom();
273     SkScalar width = runNotWhiteSpaceWidth - (endAdvance - endRect.GetLeft() - endRect.GetWidth()) - startRect.GetLeft();
274     SkScalar height = joinRect.GetHeight();
275 #endif
276      rect.setXYWH(x, y, width, height);
277      return rect;
278 }
279 
280 #ifndef USE_SKIA_TXT
getImageBounds() const281 SkRect RunBaseImpl::getImageBounds() const
282 #else
283 RSRect RunBaseImpl::getImageBounds() const
284 #endif
285 {
286     if (!fVisitorRun) {
287         return {};
288     }
289     SkSpan<const SkGlyphID> glyphIdSpan = fVisitorRun->glyphs();
290     SkSpan<const SkGlyphID> runGlyphIdSpan = glyphIdSpan.subspan(fVisitorPos, fVisitorSize);
291     if (runGlyphIdSpan.size() == 0) {
292         return {};
293     }
294     SkScalar endAdvance = 0.0;
295     SkScalar startWhiteSpaceWidth = 0.0;
296     size_t endWhiteSpaceNum = 0;
297     size_t startNotWhiteSpaceIndex = 0;
298     // Gets the width of the first non-blank glyph at the end
299     for (size_t i = runGlyphIdSpan.size() - 1; i >= 0; --i) {
300         auto& cluster = fVisitorRun->owner()->cluster(fVisitorGlobalPos + i);
301         if (!cluster.isWhitespaceBreak()) {
302             endAdvance = cluster.width();
303             break;
304         }
305         ++endWhiteSpaceNum;
306         if (i == 0) {
307             break;
308         }
309     }
310     // Gets the width of the first non-blank glyph at the end
311     for (size_t i = 0; i < runGlyphIdSpan.size(); ++i) {
312         auto& cluster = fVisitorRun->owner()->cluster(fVisitorGlobalPos + i);
313         if (!cluster.isWhitespaceBreak()) {
314             break;
315         }
316         startWhiteSpaceWidth += cluster.width();
317         ++startNotWhiteSpaceIndex;
318     }
319     SkRect rect = getAllGlyphRectInfo(runGlyphIdSpan, startNotWhiteSpaceIndex, startWhiteSpaceWidth, endWhiteSpaceNum, endAdvance);
320     return {rect.fLeft, rect.fTop, rect.fRight, rect.fBottom};
321 }
322 
getTypographicBounds(float* ascent, float* descent, float* leading) const323 float RunBaseImpl::getTypographicBounds(float* ascent, float* descent, float* leading) const
324 {
325     if (ascent == nullptr || descent == nullptr || leading == nullptr) {
326         return 0.0;
327     }
328     if (!fVisitorRun) {
329         *ascent = 0.0;
330         *descent = 0.0;
331         *leading = 0.0;
332         return 0.0;
333     }
334     *ascent = std::abs(fVisitorRun->ascent());
335     *descent = fVisitorRun->descent();
336     *leading = fVisitorRun->leading();
337     return fClipRect.width() + calculateTrailSpacesWidth();
338 }
339 
calculateTrailSpacesWidth() const340 float RunBaseImpl::calculateTrailSpacesWidth() const
341 {
342     // Calculates the width of the whitespace character at the end of the line
343     if (!fVisitorRun || fTrailSpaces == 0) {
344         return 0.0;
345     }
346     SkScalar spaceWidth = 0;
347     for (size_t i = 0; i < fTrailSpaces; i++) {
348         auto& cluster = fVisitorRun->owner()->cluster(fVisitorGlobalPos + fVisitorSize + i);
349         // doesn't calculate the width of a hard line wrap at the end of a line
350         if (cluster.isHardBreak()) {
351             break;
352         }
353         spaceWidth += cluster.width();
354     }
355 
356     return spaceWidth;
357 }
358 
calculateActualLength(int64_t start, int64_t length) const359 uint64_t RunBaseImpl::calculateActualLength(int64_t start, int64_t length) const
360 {
361     // Calculate the actual size of the run,
362     // start and length equal to 0 means that the data is obtained from start to end, so no filtering is required
363     if (start >= fVisitorSize || start < 0 || length < 0) {
364         return 0;
365     }
366     uint64_t actualLength = fVisitorSize - start;
367     actualLength = actualLength > length ? length: actualLength;
368     // If length is equal to 0, the end of the line is obtained
369     if (start >= 0 && length == 0) {
370         return fVisitorSize - start;
371     }
372 
373     return actualLength;
374 }
375 #endif
376 }  // namespace textlayout
377 }  // namespace skia