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