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 21namespace skia { 22namespace textlayout { 23RunBaseImpl::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 61const SkFont& RunBaseImpl::font() const 62#else 63const RSFont& RunBaseImpl::font() const 64#endif 65{ 66 if (!fVisitorRun) { 67 return {}; 68 } 69 return fVisitorRun->font(); 70} 71 72size_t RunBaseImpl::size() const 73{ 74 return fVisitorSize; 75} 76 77std::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 87std::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 104std::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 121void 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 136size_t RunBaseImpl::getVisitorPos() const 137{ 138 return fVisitorPos; 139} 140 141size_t RunBaseImpl::getVisitorSize() const 142{ 143 return fVisitorSize; 144} 145 146#ifdef OHOS_SUPPORT 147std::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 167std::vector<SkPoint> RunBaseImpl::getPositions(int64_t start, int64_t length) const 168#else 169std::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 197void 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 210std::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 227SkRect 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 281SkRect RunBaseImpl::getImageBounds() const 282#else 283RSRect 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 323float 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 340float 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 359uint64_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