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 fFont;
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
getAdvances(uint32_t start,uint32_t length) const197 std::vector<RSPoint> RunBaseImpl::getAdvances(uint32_t start, uint32_t length) const
198 {
199 if (fVisitorRun == nullptr) {
200 return {};
201 }
202 uint64_t actualLength = calculateActualLength(start, length);
203 if (actualLength == 0) {
204 return {};
205 }
206 SkSpan<const SkPoint> advanceSpan = fVisitorRun->advances();
207 SkSpan<const SkPoint> runAdvancesSpan = advanceSpan.subspan(fVisitorPos + start, actualLength);
208 std::vector<RSPoint> advances;
209 for (size_t i = 0; i < runAdvancesSpan.size(); i++) {
210 advances.emplace_back(runAdvancesSpan[i].fX, runAdvancesSpan[i].fY);
211 }
212 return advances;
213 }
214
getTextDirection() const215 TextDirection RunBaseImpl::getTextDirection() const
216 {
217 if (fVisitorRun == nullptr) {
218 return TextDirection::kLtr;
219 }
220 return fVisitorRun->getTextDirection();
221 }
222
getStringRange(uint64_t * location,uint64_t * length) const223 void RunBaseImpl::getStringRange(uint64_t* location, uint64_t* length) const
224 {
225 if (location == nullptr || length == nullptr) {
226 return;
227 } else if (!fVisitorRun) {
228 *location = 0;
229 *length = 0;
230 return;
231 }
232 *location = fVisitorGlobalPos;
233 *length = fVisitorSize;
234 }
235
getStringIndices(int64_t start,int64_t length) const236 std::vector<uint64_t> RunBaseImpl::getStringIndices(int64_t start, int64_t length) const
237 {
238 if (!fVisitorRun) {
239 return {};
240 }
241 uint64_t actualLength = calculateActualLength(start, length);
242 if (actualLength == 0) {
243 return {};
244 }
245 std::vector<uint64_t> indices;
246 for (size_t i = 0; i < actualLength; i++) {
247 indices.emplace_back(fVisitorGlobalPos + start + i);
248 }
249
250 return indices;
251 }
252
getAllGlyphRectInfo(SkSpan<const SkGlyphID> & runGlyphIdSpan,size_t startNotWhiteSpaceIndex,SkScalar startWhiteSpaceWidth,size_t endWhiteSpaceNum,SkScalar endAdvance) const253 SkRect RunBaseImpl::getAllGlyphRectInfo(SkSpan<const SkGlyphID>& runGlyphIdSpan, size_t startNotWhiteSpaceIndex,
254 SkScalar startWhiteSpaceWidth, size_t endWhiteSpaceNum, SkScalar endAdvance) const
255 {
256 SkRect rect = {0.0, 0.0, 0.0, 0.0};
257 SkScalar runNotWhiteSpaceWidth = 0.0;
258 #ifndef USE_SKIA_TXT
259 SkRect joinRect{0.0, 0.0, 0.0, 0.0};
260 SkRect endRect {0.0, 0.0, 0.0, 0.0};
261 SkRect startRect {0.0, 0.0, 0.0, 0.0};
262 #else
263 RSRect joinRect{0.0, 0.0, 0.0, 0.0};
264 RSRect endRect {0.0, 0.0, 0.0, 0.0};
265 RSRect startRect {0.0, 0.0, 0.0, 0.0};
266 #endif
267 size_t end = runGlyphIdSpan.size() - endWhiteSpaceNum;
268 for (size_t i = startNotWhiteSpaceIndex; i < end; i++) {
269 // Get the bounds of each glyph
270 #ifndef USE_SKIA_TXT
271 SkRect glyphBounds;
272 fVisitorRun->font().getBounds(&runGlyphIdSpan[i], 1, &glyphBounds, nullptr);
273 #else
274 RSRect glyphBounds;
275 fVisitorRun->font().GetWidths(&runGlyphIdSpan[i], 1, nullptr, &glyphBounds);
276 #endif
277 // Record the first non-blank glyph boundary
278 if (i == startNotWhiteSpaceIndex) {
279 startRect = glyphBounds;
280 }
281 if (i == end - 1) {
282 endRect = glyphBounds;
283 }
284 // Stitching removes glyph boundaries at the beginning and end of lines
285 joinRect.Join(glyphBounds);
286 auto& cluster = fVisitorRun->owner()->cluster(fVisitorGlobalPos + i);
287 // Calculates the width of the glyph with the beginning and end of the line removed
288 runNotWhiteSpaceWidth += fVisitorRun->usingAutoSpaceWidth(cluster);
289 }
290 #ifndef USE_SKIA_TXT
291 // If the first glyph of run is a blank glyph, you need to add startWhitespaceWidth
292 SkScalar x = fClipRect.fLeft + startRect.x() + startWhiteSpaceWidth;
293 SkScalar y = joinRect.bottom();
294 SkScalar width = runNotWhiteSpaceWidth - (endAdvance - endRect.x() - endRect.width()) - startRect.x();
295 SkScalar height = joinRect.height();
296 #else
297 SkScalar x = fClipRect.fLeft + startRect.GetLeft() + startWhiteSpaceWidth;
298 SkScalar y = joinRect.GetBottom();
299 SkScalar width = runNotWhiteSpaceWidth - (endAdvance - endRect.GetLeft() - endRect.GetWidth()) - startRect.GetLeft();
300 SkScalar height = joinRect.GetHeight();
301 #endif
302 rect.setXYWH(x, y, width, height);
303 return rect;
304 }
305
306 #ifndef USE_SKIA_TXT
getImageBounds() const307 SkRect RunBaseImpl::getImageBounds() const
308 #else
309 RSRect RunBaseImpl::getImageBounds() const
310 #endif
311 {
312 if (!fVisitorRun) {
313 return {};
314 }
315 SkSpan<const SkGlyphID> glyphIdSpan = fVisitorRun->glyphs();
316 SkSpan<const SkGlyphID> runGlyphIdSpan = glyphIdSpan.subspan(fVisitorPos, fVisitorSize);
317 if (runGlyphIdSpan.size() == 0) {
318 return {};
319 }
320 SkScalar endAdvance = 0.0;
321 SkScalar startWhiteSpaceWidth = 0.0;
322 size_t endWhiteSpaceNum = 0;
323 size_t startNotWhiteSpaceIndex = 0;
324 // Gets the width of the first non-blank glyph at the end
325 for (size_t i = runGlyphIdSpan.size() - 1; i >= 0; --i) {
326 auto& cluster = fVisitorRun->owner()->cluster(fVisitorGlobalPos + i);
327 if (!cluster.isWhitespaceBreak()) {
328 endAdvance = cluster.width();
329 break;
330 }
331 ++endWhiteSpaceNum;
332 if (i == 0) {
333 break;
334 }
335 }
336 // Gets the width of the first non-blank glyph at the end
337 for (size_t i = 0; i < runGlyphIdSpan.size(); ++i) {
338 auto& cluster = fVisitorRun->owner()->cluster(fVisitorGlobalPos + i);
339 if (!cluster.isWhitespaceBreak()) {
340 break;
341 }
342 startWhiteSpaceWidth += fVisitorRun->usingAutoSpaceWidth(cluster);
343 ++startNotWhiteSpaceIndex;
344 }
345 SkRect rect = getAllGlyphRectInfo(runGlyphIdSpan, startNotWhiteSpaceIndex, startWhiteSpaceWidth, endWhiteSpaceNum, endAdvance);
346 return {rect.fLeft, rect.fTop, rect.fRight, rect.fBottom};
347 }
348
getTypographicBounds(float * ascent,float * descent,float * leading) const349 float RunBaseImpl::getTypographicBounds(float* ascent, float* descent, float* leading) const
350 {
351 if (ascent == nullptr || descent == nullptr || leading == nullptr) {
352 return 0.0;
353 }
354 if (!fVisitorRun) {
355 *ascent = 0.0;
356 *descent = 0.0;
357 *leading = 0.0;
358 return 0.0;
359 }
360 *ascent = fVisitorRun->ascent() + fVisitorRun->getVerticalAlignShift();
361 *descent = fVisitorRun->descent() + fVisitorRun->getVerticalAlignShift();
362 *leading = fVisitorRun->leading();
363 return fClipRect.width() + calculateTrailSpacesWidth();
364 }
365
calculateTrailSpacesWidth() const366 float RunBaseImpl::calculateTrailSpacesWidth() const
367 {
368 // Calculates the width of the whitespace character at the end of the line
369 if (!fVisitorRun || fTrailSpaces == 0) {
370 return 0.0;
371 }
372 SkScalar spaceWidth = 0;
373 for (size_t i = 0; i < fTrailSpaces; i++) {
374 auto& cluster = fVisitorRun->owner()->cluster(fVisitorGlobalPos + fVisitorSize + i);
375 // doesn't calculate the width of a hard line wrap at the end of a line
376 if (cluster.isHardBreak()) {
377 break;
378 }
379 spaceWidth += fVisitorRun->usingAutoSpaceWidth(cluster);
380 }
381
382 return spaceWidth;
383 }
384
calculateActualLength(int64_t start,int64_t length) const385 uint64_t RunBaseImpl::calculateActualLength(int64_t start, int64_t length) const
386 {
387 // Calculate the actual size of the run,
388 // start and length equal to 0 means that the data is obtained from start to end, so no filtering is required
389 if (start < 0 || length < 0 || static_cast<size_t>(start) >= fVisitorSize) {
390 return 0;
391 }
392 uint64_t actualLength = static_cast<uint64_t>(fVisitorSize - static_cast<size_t>(start));
393 actualLength = (actualLength > static_cast<uint64_t>(length)) ? static_cast<uint64_t>(length)
394 : actualLength;
395 // If length is equal to 0, the end of the line is obtained
396 if (start >= 0 && length == 0) {
397 return fVisitorSize - static_cast<size_t>(start);
398 }
399
400 return actualLength;
401 }
402 #endif
403 } // namespace textlayout
404 } // namespace skia