• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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