1cb93a386Sopenharmony_ci// Copyright 2019 Google LLC. 2cb93a386Sopenharmony_ci 3cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 4cb93a386Sopenharmony_ci#include "include/core/SkFontMetrics.h" 5cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h" 6cb93a386Sopenharmony_ci#include "include/core/SkPictureRecorder.h" 7cb93a386Sopenharmony_ci#include "include/core/SkSpan.h" 8cb93a386Sopenharmony_ci#include "include/core/SkTypeface.h" 9cb93a386Sopenharmony_ci#include "include/private/SkTFitsIn.h" 10cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 11cb93a386Sopenharmony_ci#include "modules/skparagraph/include/Metrics.h" 12cb93a386Sopenharmony_ci#include "modules/skparagraph/include/Paragraph.h" 13cb93a386Sopenharmony_ci#include "modules/skparagraph/include/ParagraphPainter.h" 14cb93a386Sopenharmony_ci#include "modules/skparagraph/include/ParagraphStyle.h" 15cb93a386Sopenharmony_ci#include "modules/skparagraph/include/TextStyle.h" 16cb93a386Sopenharmony_ci#include "modules/skparagraph/src/OneLineShaper.h" 17cb93a386Sopenharmony_ci#include "modules/skparagraph/src/ParagraphImpl.h" 18cb93a386Sopenharmony_ci#include "modules/skparagraph/src/ParagraphPainterImpl.h" 19cb93a386Sopenharmony_ci#include "modules/skparagraph/src/Run.h" 20cb93a386Sopenharmony_ci#include "modules/skparagraph/src/TextLine.h" 21cb93a386Sopenharmony_ci#include "modules/skparagraph/src/TextWrapper.h" 22cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 23cb93a386Sopenharmony_ci#include "utils/text_trace.h" 24cb93a386Sopenharmony_ci#endif 25cb93a386Sopenharmony_ci#include "src/utils/SkUTF.h" 26cb93a386Sopenharmony_ci#include <math.h> 27cb93a386Sopenharmony_ci#include <algorithm> 28cb93a386Sopenharmony_ci#include <utility> 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 31cb93a386Sopenharmony_ci#include "log.h" 32cb93a386Sopenharmony_ci#include "modules/skparagraph/src/TextLineBaseImpl.h" 33cb93a386Sopenharmony_ci#include "TextParameter.h" 34cb93a386Sopenharmony_ci#endif 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_cinamespace skia { 37cb93a386Sopenharmony_cinamespace textlayout { 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_cinamespace { 40cb93a386Sopenharmony_ciconstexpr int PARAM_DOUBLE = 2; 41cb93a386Sopenharmony_ciconstexpr ParagraphPainter::PaintID INVALID_PAINT_ID = -1; 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ciSkScalar littleRound(SkScalar a) { 44cb93a386Sopenharmony_ci // This rounding is done to match Flutter tests. Must be removed.. 45cb93a386Sopenharmony_ci auto val = std::fabs(a); 46cb93a386Sopenharmony_ci if (val < 10000) { 47cb93a386Sopenharmony_ci return SkScalarRoundToScalar(a * 100.0)/100.0; 48cb93a386Sopenharmony_ci } else if (val < 100000) { 49cb93a386Sopenharmony_ci return SkScalarRoundToScalar(a * 10.0)/10.0; 50cb93a386Sopenharmony_ci } else { 51cb93a386Sopenharmony_ci return SkScalarFloorToScalar(a); 52cb93a386Sopenharmony_ci } 53cb93a386Sopenharmony_ci} 54cb93a386Sopenharmony_ci} // namespace 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ciTextRange operator*(const TextRange& a, const TextRange& b) { 57cb93a386Sopenharmony_ci if (a.start == b.start && a.end == b.end) return a; 58cb93a386Sopenharmony_ci auto begin = std::max(a.start, b.start); 59cb93a386Sopenharmony_ci auto end = std::min(a.end, b.end); 60cb93a386Sopenharmony_ci return end > begin ? TextRange(begin, end) : EMPTY_TEXT; 61cb93a386Sopenharmony_ci} 62cb93a386Sopenharmony_ci 63cb93a386Sopenharmony_ciTextRange textRangeMergeBtoA(const TextRange& a, const TextRange& b) { 64cb93a386Sopenharmony_ci if (a.width() <= 0 || b.width() <= 0 || a.end < b.start || a.start > b.end) { 65cb93a386Sopenharmony_ci return a; 66cb93a386Sopenharmony_ci } 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ci return TextRange(std::min(a.start, b.start), std::max(a.end, b.end)); 69cb93a386Sopenharmony_ci} 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_cistd::vector<SkUnichar> ParagraphImpl::convertUtf8ToUnicode(const SkString& utf8) 72cb93a386Sopenharmony_ci{ 73cb93a386Sopenharmony_ci fUnicodeIndexForUTF8Index.reset(); 74cb93a386Sopenharmony_ci std::vector<SkUnichar> result; 75cb93a386Sopenharmony_ci auto p = utf8.c_str(); 76cb93a386Sopenharmony_ci auto end = p + utf8.size(); 77cb93a386Sopenharmony_ci while (p < end) { 78cb93a386Sopenharmony_ci auto tmp = p; 79cb93a386Sopenharmony_ci auto unichar = SkUTF::NextUTF8(&p, end); 80cb93a386Sopenharmony_ci for (auto i = 0; i < p - tmp; ++i) { 81cb93a386Sopenharmony_ci fUnicodeIndexForUTF8Index.emplace_back(result.size()); 82cb93a386Sopenharmony_ci } 83cb93a386Sopenharmony_ci result.emplace_back(unichar); 84cb93a386Sopenharmony_ci } 85cb93a386Sopenharmony_ci fUnicodeIndexForUTF8Index.emplace_back(result.size()); 86cb93a386Sopenharmony_ci return result; 87cb93a386Sopenharmony_ci} 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ciParagraph::Paragraph() 90cb93a386Sopenharmony_ci{ } 91cb93a386Sopenharmony_ci 92cb93a386Sopenharmony_ciParagraph::Paragraph(ParagraphStyle style, sk_sp<FontCollection> fonts) 93cb93a386Sopenharmony_ci : fFontCollection(std::move(fonts)) 94cb93a386Sopenharmony_ci , fParagraphStyle(std::move(style)) 95cb93a386Sopenharmony_ci , fAlphabeticBaseline(0) 96cb93a386Sopenharmony_ci , fIdeographicBaseline(0) 97cb93a386Sopenharmony_ci , fHeight(0) 98cb93a386Sopenharmony_ci , fWidth(0) 99cb93a386Sopenharmony_ci , fMaxIntrinsicWidth(0) 100cb93a386Sopenharmony_ci , fMinIntrinsicWidth(0) 101cb93a386Sopenharmony_ci , fLongestLine(0) 102cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 103cb93a386Sopenharmony_ci , fLongestLineWithIndent(0) 104cb93a386Sopenharmony_ci#endif 105cb93a386Sopenharmony_ci , fExceededMaxLines(0) 106cb93a386Sopenharmony_ci{ } 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_ciParagraphImpl::ParagraphImpl() 109cb93a386Sopenharmony_ci{ } 110cb93a386Sopenharmony_ci 111cb93a386Sopenharmony_ciParagraphImpl::ParagraphImpl(const SkString& text, 112cb93a386Sopenharmony_ci ParagraphStyle style, 113cb93a386Sopenharmony_ci SkTArray<Block, true> blocks, 114cb93a386Sopenharmony_ci SkTArray<Placeholder, true> placeholders, 115cb93a386Sopenharmony_ci sk_sp<FontCollection> fonts, 116cb93a386Sopenharmony_ci std::shared_ptr<SkUnicode> unicode) 117cb93a386Sopenharmony_ci : Paragraph(std::move(style), std::move(fonts)) 118cb93a386Sopenharmony_ci , fTextStyles(std::move(blocks)) 119cb93a386Sopenharmony_ci , fPlaceholders(std::move(placeholders)) 120cb93a386Sopenharmony_ci , fText(text) 121cb93a386Sopenharmony_ci , fState(kUnknown) 122cb93a386Sopenharmony_ci , fUnresolvedGlyphs(0) 123cb93a386Sopenharmony_ci , fPicture(nullptr) 124cb93a386Sopenharmony_ci , fStrutMetrics(false) 125cb93a386Sopenharmony_ci , fOldWidth(0) 126cb93a386Sopenharmony_ci , fOldHeight(0) 127cb93a386Sopenharmony_ci , fUnicode(std::move(unicode)) 128cb93a386Sopenharmony_ci , fHasLineBreaks(false) 129cb93a386Sopenharmony_ci , fHasWhitespacesInside(false) 130cb93a386Sopenharmony_ci , fTrailingSpaces(0) 131cb93a386Sopenharmony_ci{ 132cb93a386Sopenharmony_ci SkASSERT(fUnicode); 133cb93a386Sopenharmony_ci} 134cb93a386Sopenharmony_ci 135cb93a386Sopenharmony_ciParagraphImpl::ParagraphImpl(const std::u16string& utf16text, 136cb93a386Sopenharmony_ci ParagraphStyle style, 137cb93a386Sopenharmony_ci SkTArray<Block, true> blocks, 138cb93a386Sopenharmony_ci SkTArray<Placeholder, true> placeholders, 139cb93a386Sopenharmony_ci sk_sp<FontCollection> fonts, 140cb93a386Sopenharmony_ci std::shared_ptr<SkUnicode> unicode) 141cb93a386Sopenharmony_ci : ParagraphImpl(SkString(), 142cb93a386Sopenharmony_ci std::move(style), 143cb93a386Sopenharmony_ci std::move(blocks), 144cb93a386Sopenharmony_ci std::move(placeholders), 145cb93a386Sopenharmony_ci std::move(fonts), 146cb93a386Sopenharmony_ci std::move(unicode)) 147cb93a386Sopenharmony_ci{ 148cb93a386Sopenharmony_ci SkASSERT(fUnicode); 149cb93a386Sopenharmony_ci fText = SkUnicode::convertUtf16ToUtf8(utf16text); 150cb93a386Sopenharmony_ci} 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ciParagraphImpl::~ParagraphImpl() = default; 153cb93a386Sopenharmony_ci 154cb93a386Sopenharmony_ciint32_t ParagraphImpl::unresolvedGlyphs() { 155cb93a386Sopenharmony_ci if (fState < kShaped) { 156cb93a386Sopenharmony_ci return -1; 157cb93a386Sopenharmony_ci } 158cb93a386Sopenharmony_ci 159cb93a386Sopenharmony_ci return fUnresolvedGlyphs; 160cb93a386Sopenharmony_ci} 161cb93a386Sopenharmony_ci 162cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 163cb93a386Sopenharmony_cibool ParagraphImpl::GetLineFontMetrics(const size_t lineNumber, size_t& charNumber, 164cb93a386Sopenharmony_ci std::vector<SkFontMetrics>& fontMetrics) { 165cb93a386Sopenharmony_ci#else 166cb93a386Sopenharmony_cibool ParagraphImpl::GetLineFontMetrics(const size_t lineNumber, size_t& charNumber, 167cb93a386Sopenharmony_ci std::vector<RSFontMetrics>& fontMetrics) { 168cb93a386Sopenharmony_ci#endif 169cb93a386Sopenharmony_ci if (lineNumber > fLines.size() || !lineNumber || 170cb93a386Sopenharmony_ci !fLines[lineNumber - 1].getLineAllRuns().size()) { 171cb93a386Sopenharmony_ci return false; 172cb93a386Sopenharmony_ci } 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ci size_t textRange = 0; 175cb93a386Sopenharmony_ci size_t lineCharCount = fLines[lineNumber - 1].clusters().end - 176cb93a386Sopenharmony_ci fLines[lineNumber - 1].clusters().start; 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ci for (auto& runIndex : fLines[lineNumber - 1].getLineAllRuns()) { 179cb93a386Sopenharmony_ci Run& targetRun = this->run(runIndex); 180cb93a386Sopenharmony_ci size_t runClock = 0; 181cb93a386Sopenharmony_ci size_t currentRunCharNumber = targetRun.clusterRange().end - 182cb93a386Sopenharmony_ci targetRun.clusterRange().start; 183cb93a386Sopenharmony_ci for (;textRange < lineCharCount; textRange++) { 184cb93a386Sopenharmony_ci if (++runClock > currentRunCharNumber) { 185cb93a386Sopenharmony_ci break; 186cb93a386Sopenharmony_ci } 187cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 188cb93a386Sopenharmony_ci SkFontMetrics newFontMetrics; 189cb93a386Sopenharmony_ci targetRun.fFont.getMetrics(&newFontMetrics); 190cb93a386Sopenharmony_ci#else 191cb93a386Sopenharmony_ci RSFontMetrics newFontMetrics; 192cb93a386Sopenharmony_ci targetRun.fFont.GetMetrics(&newFontMetrics); 193cb93a386Sopenharmony_ci#endif 194cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 195cb93a386Sopenharmony_ci auto decompressFont = targetRun.fFont; 196cb93a386Sopenharmony_ci scaleFontWithCompressionConfig(decompressFont, ScaleOP::DECOMPRESS); 197cb93a386Sopenharmony_ci metricsIncludeFontPadding(&newFontMetrics, decompressFont); 198cb93a386Sopenharmony_ci#endif 199cb93a386Sopenharmony_ci fontMetrics.emplace_back(newFontMetrics); 200cb93a386Sopenharmony_ci } 201cb93a386Sopenharmony_ci } 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_ci charNumber = lineCharCount; 204cb93a386Sopenharmony_ci return true; 205cb93a386Sopenharmony_ci} 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_cistd::unordered_set<SkUnichar> ParagraphImpl::unresolvedCodepoints() { 208cb93a386Sopenharmony_ci return fUnresolvedCodepoints; 209cb93a386Sopenharmony_ci} 210cb93a386Sopenharmony_ci 211cb93a386Sopenharmony_civoid ParagraphImpl::addUnresolvedCodepoints(TextRange textRange) { 212cb93a386Sopenharmony_ci fUnicode->forEachCodepoint( 213cb93a386Sopenharmony_ci &fText[textRange.start], textRange.width(), 214cb93a386Sopenharmony_ci [&](SkUnichar unichar, int32_t start, int32_t end, int32_t count) { 215cb93a386Sopenharmony_ci fUnresolvedCodepoints.emplace(unichar); 216cb93a386Sopenharmony_ci } 217cb93a386Sopenharmony_ci ); 218cb93a386Sopenharmony_ci} 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ciTextRange ParagraphImpl::resetRangeWithDeletedRange(const TextRange& sourceRange, 221cb93a386Sopenharmony_ci const TextRange& deletedRange, const size_t& ellSize) 222cb93a386Sopenharmony_ci{ 223cb93a386Sopenharmony_ci if (sourceRange.end <= deletedRange.start) { 224cb93a386Sopenharmony_ci return sourceRange; 225cb93a386Sopenharmony_ci } 226cb93a386Sopenharmony_ci auto changeSize = ellSize - deletedRange.width(); 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ci if (sourceRange.start >= deletedRange.end) { 229cb93a386Sopenharmony_ci return TextRange(sourceRange.start + changeSize, sourceRange.end + changeSize); 230cb93a386Sopenharmony_ci } 231cb93a386Sopenharmony_ci 232cb93a386Sopenharmony_ci TextRange target; 233cb93a386Sopenharmony_ci target.start = sourceRange.start <= deletedRange.start ? sourceRange.start : deletedRange.start + ellSize; 234cb93a386Sopenharmony_ci target.end = sourceRange.end <= deletedRange.end ? deletedRange.start + ellSize : sourceRange.end + changeSize; 235cb93a386Sopenharmony_ci return target.start <= target.end ? target : EMPTY_RANGE; 236cb93a386Sopenharmony_ci} 237cb93a386Sopenharmony_ci 238cb93a386Sopenharmony_civoid ParagraphImpl::resetTextStyleRange(const TextRange& deletedRange) 239cb93a386Sopenharmony_ci{ 240cb93a386Sopenharmony_ci auto tmpTextStyle = fTextStyles; 241cb93a386Sopenharmony_ci fTextStyles.reset(); 242cb93a386Sopenharmony_ci for (auto fs : tmpTextStyle) { 243cb93a386Sopenharmony_ci auto newTextRange = resetRangeWithDeletedRange(fs.fRange, deletedRange, this->getEllipsis().size()); 244cb93a386Sopenharmony_ci LOGD("ParagraphImpl::resetTextStyleRange old = [%{public}lu,%{public}lu), new = [%{public}lu,%{public}lu)", 245cb93a386Sopenharmony_ci static_cast<unsigned long>(fs.fRange.start), static_cast<unsigned long>(fs.fRange.end), 246cb93a386Sopenharmony_ci static_cast<unsigned long>(newTextRange.start), static_cast<unsigned long>(newTextRange.end)); 247cb93a386Sopenharmony_ci if (newTextRange.width() == 0) { 248cb93a386Sopenharmony_ci continue; 249cb93a386Sopenharmony_ci } 250cb93a386Sopenharmony_ci fs.fRange = newTextRange; 251cb93a386Sopenharmony_ci fTextStyles.emplace_back(fs); 252cb93a386Sopenharmony_ci } 253cb93a386Sopenharmony_ci} 254cb93a386Sopenharmony_ci 255cb93a386Sopenharmony_civoid ParagraphImpl::resetPlaceholderRange(const TextRange& deletedRange) 256cb93a386Sopenharmony_ci{ 257cb93a386Sopenharmony_ci // reset fRange && fTextBefore && fBlockBefore 258cb93a386Sopenharmony_ci auto ellSize = this->getEllipsis().size(); 259cb93a386Sopenharmony_ci auto tmpPlaceholders = fPlaceholders; 260cb93a386Sopenharmony_ci fPlaceholders.reset(); 261cb93a386Sopenharmony_ci for (auto ph : tmpPlaceholders) { 262cb93a386Sopenharmony_ci auto newTextRange = resetRangeWithDeletedRange(ph.fRange, deletedRange, ellSize); 263cb93a386Sopenharmony_ci LOGD("ParagraphImpl::resetPlaceholderRange old = [%{public}lu,%{public}lu), new = [%{public}lu,%{public}lu)", 264cb93a386Sopenharmony_ci static_cast<unsigned long>(ph.fRange.start), static_cast<unsigned long>(ph.fRange.end), 265cb93a386Sopenharmony_ci static_cast<unsigned long>(newTextRange.start), static_cast<unsigned long>(newTextRange.end)); 266cb93a386Sopenharmony_ci if (newTextRange.empty()) { 267cb93a386Sopenharmony_ci continue; 268cb93a386Sopenharmony_ci } 269cb93a386Sopenharmony_ci ph.fRange = newTextRange; 270cb93a386Sopenharmony_ci newTextRange = ph.fTextBefore; 271cb93a386Sopenharmony_ci newTextRange.start = fPlaceholders.empty() ? 0 : fPlaceholders.back().fRange.end; 272cb93a386Sopenharmony_ci if (newTextRange.end > deletedRange.start) { 273cb93a386Sopenharmony_ci newTextRange.end = newTextRange.end <= deletedRange.end ? 274cb93a386Sopenharmony_ci deletedRange.start + ellSize : newTextRange.end + ellSize - deletedRange.width(); 275cb93a386Sopenharmony_ci } 276cb93a386Sopenharmony_ci ph.fTextBefore = newTextRange; 277cb93a386Sopenharmony_ci fPlaceholders.emplace_back(ph); 278cb93a386Sopenharmony_ci } 279cb93a386Sopenharmony_ci} 280cb93a386Sopenharmony_ci 281cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 282cb93a386Sopenharmony_cibool ParagraphImpl::middleEllipsisDeal() 283cb93a386Sopenharmony_ci{ 284cb93a386Sopenharmony_ci if (fRuns.empty()) { 285cb93a386Sopenharmony_ci return false; 286cb93a386Sopenharmony_ci } 287cb93a386Sopenharmony_ci isMiddleEllipsis = false; 288cb93a386Sopenharmony_ci 289cb93a386Sopenharmony_ci size_t end = 0; 290cb93a386Sopenharmony_ci size_t charbegin = 0; 291cb93a386Sopenharmony_ci size_t charend = 0; 292cb93a386Sopenharmony_ci if (fRuns.begin()->leftToRight()) { 293cb93a386Sopenharmony_ci middleEllipsisLtrDeal(end, charbegin, charend); 294cb93a386Sopenharmony_ci } else { 295cb93a386Sopenharmony_ci middleEllipsisRtlDeal(end, charbegin, charend); 296cb93a386Sopenharmony_ci } 297cb93a386Sopenharmony_ci if (end != 0) { 298cb93a386Sopenharmony_ci TextRange deletedRange(charbegin, charend); 299cb93a386Sopenharmony_ci resetTextStyleRange(deletedRange); 300cb93a386Sopenharmony_ci resetPlaceholderRange(deletedRange); 301cb93a386Sopenharmony_ci fEllipsisRange = deletedRange; 302cb93a386Sopenharmony_ci } 303cb93a386Sopenharmony_ci // end = 0 means the text does not exceed the width limit 304cb93a386Sopenharmony_ci return end != 0; 305cb93a386Sopenharmony_ci} 306cb93a386Sopenharmony_ci 307cb93a386Sopenharmony_civoid ParagraphImpl::middleEllipsisLtrDeal(size_t& end, 308cb93a386Sopenharmony_ci size_t& charbegin, 309cb93a386Sopenharmony_ci size_t& charend) 310cb93a386Sopenharmony_ci{ 311cb93a386Sopenharmony_ci const SkString& ell = this->getEllipsis(); 312cb93a386Sopenharmony_ci const char *ellStr = ell.c_str(); 313cb93a386Sopenharmony_ci size_t start = 0; 314cb93a386Sopenharmony_ci if (ltrTextSize[0].phraseWidth >= fOldMaxWidth) { 315cb93a386Sopenharmony_ci fText.reset(); 316cb93a386Sopenharmony_ci fText.set(ellStr); 317cb93a386Sopenharmony_ci end = 1; 318cb93a386Sopenharmony_ci charend = ell.size(); 319cb93a386Sopenharmony_ci } else { 320cb93a386Sopenharmony_ci scanTextCutPoint(ltrTextSize, start, end); 321cb93a386Sopenharmony_ci if (end) { 322cb93a386Sopenharmony_ci charbegin = ltrTextSize[start].charbegin; 323cb93a386Sopenharmony_ci charend = ltrTextSize[end].charOver; 324cb93a386Sopenharmony_ci fText.remove(ltrTextSize[start].charbegin, ltrTextSize[end].charOver - ltrTextSize[start].charbegin); 325cb93a386Sopenharmony_ci fText.insert(ltrTextSize[start].charbegin, ellStr); 326cb93a386Sopenharmony_ci } 327cb93a386Sopenharmony_ci } 328cb93a386Sopenharmony_ci ltrTextSize.clear(); 329cb93a386Sopenharmony_ci} 330cb93a386Sopenharmony_ci 331cb93a386Sopenharmony_civoid ParagraphImpl::middleEllipsisRtlDeal(size_t& end, 332cb93a386Sopenharmony_ci size_t& charbegin, 333cb93a386Sopenharmony_ci size_t& charend) 334cb93a386Sopenharmony_ci{ 335cb93a386Sopenharmony_ci const SkString& ell = this->getEllipsis(); 336cb93a386Sopenharmony_ci const char *ellStr = ell.c_str(); 337cb93a386Sopenharmony_ci size_t start = 0; 338cb93a386Sopenharmony_ci scanTextCutPoint(rtlTextSize, start, end); 339cb93a386Sopenharmony_ci if (start < 1 || end + PARAM_DOUBLE >= rtlTextSize.size()) { 340cb93a386Sopenharmony_ci start = 0; 341cb93a386Sopenharmony_ci end = 0; 342cb93a386Sopenharmony_ci } 343cb93a386Sopenharmony_ci if (end) { 344cb93a386Sopenharmony_ci charbegin = rtlTextSize[start - 1].charbegin; 345cb93a386Sopenharmony_ci charend = rtlTextSize[end + PARAM_DOUBLE].charbegin; 346cb93a386Sopenharmony_ci fText.remove(rtlTextSize[start - 1].charbegin, 347cb93a386Sopenharmony_ci rtlTextSize[end + PARAM_DOUBLE].charbegin - rtlTextSize[start - 1].charbegin); 348cb93a386Sopenharmony_ci fText.insert(rtlTextSize[start - 1].charbegin, ellStr); 349cb93a386Sopenharmony_ci } 350cb93a386Sopenharmony_ci rtlTextSize.clear(); 351cb93a386Sopenharmony_ci} 352cb93a386Sopenharmony_ci#endif 353cb93a386Sopenharmony_ci 354cb93a386Sopenharmony_ciSkScalar ParagraphImpl::resetEllipsisWidth(SkScalar ellipsisWidth, size_t& lastRunIndex, const size_t textIndex) 355cb93a386Sopenharmony_ci{ 356cb93a386Sopenharmony_ci auto targetCluster = cluster(clusterIndex(textIndex)); 357cb93a386Sopenharmony_ci if (lastRunIndex != targetCluster.runIndex()) { 358cb93a386Sopenharmony_ci TextLine textLine; 359cb93a386Sopenharmony_ci textLine.setParagraphImpl(this); 360cb93a386Sopenharmony_ci auto blockRange = findAllBlocks(TextRange(textIndex, textIndex + 1)); 361cb93a386Sopenharmony_ci textLine.setBlockRange(blockRange); 362cb93a386Sopenharmony_ci const SkString& ellipsis = this->getEllipsis(); 363cb93a386Sopenharmony_ci std::unique_ptr<Run> ellipsisRun; 364cb93a386Sopenharmony_ci ellipsisRun = textLine.shapeEllipsis(ellipsis, &targetCluster); 365cb93a386Sopenharmony_ci lastRunIndex = targetCluster.runIndex(); 366cb93a386Sopenharmony_ci ellipsisWidth = ellipsisRun->fAdvanceX(); 367cb93a386Sopenharmony_ci ellipsisRun.reset(); 368cb93a386Sopenharmony_ci } 369cb93a386Sopenharmony_ci return ellipsisWidth; 370cb93a386Sopenharmony_ci} 371cb93a386Sopenharmony_ci 372cb93a386Sopenharmony_civoid ParagraphImpl::scanRTLTextCutPoint(const std::vector<TextCutRecord>& rawTextSize, size_t& start, size_t& end) 373cb93a386Sopenharmony_ci{ 374cb93a386Sopenharmony_ci size_t lastRunIndex = EMPTY_RUN; 375cb93a386Sopenharmony_ci auto runTimeEllipsisWidth = resetEllipsisWidth(0, lastRunIndex, 0); 376cb93a386Sopenharmony_ci float measureWidth = runTimeEllipsisWidth; 377cb93a386Sopenharmony_ci size_t left = 0; 378cb93a386Sopenharmony_ci size_t right = rawTextSize.size() - 1; 379cb93a386Sopenharmony_ci while (left < rawTextSize.size() && measureWidth < fOldMaxWidth && left <= right) { 380cb93a386Sopenharmony_ci measureWidth += rawTextSize[left++].phraseWidth; 381cb93a386Sopenharmony_ci if (right > left && measureWidth < fOldMaxWidth) { 382cb93a386Sopenharmony_ci measureWidth += rawTextSize[right--].phraseWidth; 383cb93a386Sopenharmony_ci } 384cb93a386Sopenharmony_ci measureWidth -= runTimeEllipsisWidth; 385cb93a386Sopenharmony_ci runTimeEllipsisWidth = resetEllipsisWidth(runTimeEllipsisWidth, lastRunIndex, left); 386cb93a386Sopenharmony_ci measureWidth += runTimeEllipsisWidth; 387cb93a386Sopenharmony_ci } 388cb93a386Sopenharmony_ci 389cb93a386Sopenharmony_ci if (right < left) { 390cb93a386Sopenharmony_ci right = left; 391cb93a386Sopenharmony_ci } 392cb93a386Sopenharmony_ci 393cb93a386Sopenharmony_ci if (measureWidth >= fOldMaxWidth || fParagraphStyle.getTextOverflower()) { 394cb93a386Sopenharmony_ci start = left; 395cb93a386Sopenharmony_ci end = right; 396cb93a386Sopenharmony_ci } else { 397cb93a386Sopenharmony_ci start = 0; 398cb93a386Sopenharmony_ci end = 0; 399cb93a386Sopenharmony_ci } 400cb93a386Sopenharmony_ci} 401cb93a386Sopenharmony_ci 402cb93a386Sopenharmony_civoid ParagraphImpl::scanLTRTextCutPoint(const std::vector<TextCutRecord>& rawTextSize, size_t& start, size_t& end) 403cb93a386Sopenharmony_ci{ 404cb93a386Sopenharmony_ci size_t lastRunIndex = EMPTY_RUN; 405cb93a386Sopenharmony_ci auto runTimeEllipsisWidth = resetEllipsisWidth(0, lastRunIndex, 0); 406cb93a386Sopenharmony_ci float measureWidth = runTimeEllipsisWidth; 407cb93a386Sopenharmony_ci size_t begin = 0; 408cb93a386Sopenharmony_ci size_t last = rawTextSize.size() - 1; 409cb93a386Sopenharmony_ci bool rightExit = false; 410cb93a386Sopenharmony_ci while (begin < last && !rightExit && measureWidth < fOldMaxWidth) { 411cb93a386Sopenharmony_ci measureWidth += rawTextSize[begin++].phraseWidth; 412cb93a386Sopenharmony_ci if (measureWidth > fOldMaxWidth) { 413cb93a386Sopenharmony_ci --begin; 414cb93a386Sopenharmony_ci break; 415cb93a386Sopenharmony_ci } 416cb93a386Sopenharmony_ci if (last > begin && measureWidth < fOldMaxWidth) { 417cb93a386Sopenharmony_ci measureWidth += rawTextSize[last--].phraseWidth; 418cb93a386Sopenharmony_ci if (measureWidth > fOldMaxWidth) { 419cb93a386Sopenharmony_ci rightExit = true; 420cb93a386Sopenharmony_ci ++last; 421cb93a386Sopenharmony_ci } 422cb93a386Sopenharmony_ci } 423cb93a386Sopenharmony_ci measureWidth -= runTimeEllipsisWidth; 424cb93a386Sopenharmony_ci runTimeEllipsisWidth = resetEllipsisWidth(runTimeEllipsisWidth, lastRunIndex, begin); 425cb93a386Sopenharmony_ci measureWidth += runTimeEllipsisWidth; 426cb93a386Sopenharmony_ci } 427cb93a386Sopenharmony_ci 428cb93a386Sopenharmony_ci if (measureWidth >= fOldMaxWidth || fParagraphStyle.getTextOverflower()) { 429cb93a386Sopenharmony_ci start = begin; 430cb93a386Sopenharmony_ci end = last; 431cb93a386Sopenharmony_ci } else { 432cb93a386Sopenharmony_ci start = 0; 433cb93a386Sopenharmony_ci end = 0; 434cb93a386Sopenharmony_ci } 435cb93a386Sopenharmony_ci} 436cb93a386Sopenharmony_ci 437cb93a386Sopenharmony_civoid ParagraphImpl::scanTextCutPoint(const std::vector<TextCutRecord>& rawTextSize, size_t& start, size_t& end) 438cb93a386Sopenharmony_ci{ 439cb93a386Sopenharmony_ci if (allTextWidth <= fOldMaxWidth || !rawTextSize.size()) { 440cb93a386Sopenharmony_ci allTextWidth = 0; 441cb93a386Sopenharmony_ci return; 442cb93a386Sopenharmony_ci } 443cb93a386Sopenharmony_ci 444cb93a386Sopenharmony_ci if (fRuns.begin()->leftToRight()) { 445cb93a386Sopenharmony_ci scanLTRTextCutPoint(rawTextSize, start, end); 446cb93a386Sopenharmony_ci } else { 447cb93a386Sopenharmony_ci scanRTLTextCutPoint(rawTextSize, start, end); 448cb93a386Sopenharmony_ci } 449cb93a386Sopenharmony_ci} 450cb93a386Sopenharmony_ci 451cb93a386Sopenharmony_cibool ParagraphImpl::shapeForMiddleEllipsis(SkScalar rawWidth) 452cb93a386Sopenharmony_ci{ 453cb93a386Sopenharmony_ci if (fParagraphStyle.getMaxLines() != 1 || fParagraphStyle.getEllipsisMod() != EllipsisModal::MIDDLE || 454cb93a386Sopenharmony_ci !fParagraphStyle.ellipsized()) { 455cb93a386Sopenharmony_ci return true; 456cb93a386Sopenharmony_ci } 457cb93a386Sopenharmony_ci fOldMaxWidth = rawWidth; 458cb93a386Sopenharmony_ci isMiddleEllipsis = true; 459cb93a386Sopenharmony_ci allTextWidth = 0; 460cb93a386Sopenharmony_ci this->computeCodeUnitProperties(); 461cb93a386Sopenharmony_ci this->fRuns.reset(); 462cb93a386Sopenharmony_ci this->fClusters.reset(); 463cb93a386Sopenharmony_ci this->fClustersIndexFromCodeUnit.reset(); 464cb93a386Sopenharmony_ci this->fClustersIndexFromCodeUnit.push_back_n(fText.size() + 1, EMPTY_INDEX); 465cb93a386Sopenharmony_ci if (!this->shapeTextIntoEndlessLine()) { 466cb93a386Sopenharmony_ci return false; 467cb93a386Sopenharmony_ci } 468cb93a386Sopenharmony_ci return middleEllipsisDeal(); 469cb93a386Sopenharmony_ci} 470cb93a386Sopenharmony_ci 471cb93a386Sopenharmony_civoid ParagraphImpl::prepareForMiddleEllipsis(SkScalar rawWidth) 472cb93a386Sopenharmony_ci{ 473cb93a386Sopenharmony_ci if (fParagraphStyle.getMaxLines() != 1 || fParagraphStyle.getEllipsisMod() != EllipsisModal::MIDDLE || 474cb93a386Sopenharmony_ci !fParagraphStyle.ellipsized()) { 475cb93a386Sopenharmony_ci return; 476cb93a386Sopenharmony_ci } 477cb93a386Sopenharmony_ci std::shared_ptr<ParagraphImpl> tmpParagraph = std::make_shared<ParagraphImpl>(fText, fParagraphStyle, fTextStyles, 478cb93a386Sopenharmony_ci fPlaceholders, fFontCollection, fUnicode); 479cb93a386Sopenharmony_ci if (tmpParagraph->shapeForMiddleEllipsis(rawWidth)) { 480cb93a386Sopenharmony_ci fText = tmpParagraph->fText; 481cb93a386Sopenharmony_ci fTextStyles = tmpParagraph->fTextStyles; 482cb93a386Sopenharmony_ci fPlaceholders = tmpParagraph->fPlaceholders; 483cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 484cb93a386Sopenharmony_ci fEllipsisRange = tmpParagraph->fEllipsisRange; 485cb93a386Sopenharmony_ci#endif 486cb93a386Sopenharmony_ci } 487cb93a386Sopenharmony_ci} 488cb93a386Sopenharmony_ci 489cb93a386Sopenharmony_civoid ParagraphImpl::layout(SkScalar rawWidth) { 490cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 491cb93a386Sopenharmony_ci TEXT_TRACE_FUNC(); 492cb93a386Sopenharmony_ci#endif 493cb93a386Sopenharmony_ci fLineNumber = 1; 494cb93a386Sopenharmony_ci allTextWidth = 0; 495cb93a386Sopenharmony_ci fLayoutRawWidth = rawWidth; 496cb93a386Sopenharmony_ci // TODO: This rounding is done to match Flutter tests. Must be removed... 497cb93a386Sopenharmony_ci auto floorWidth = rawWidth; 498cb93a386Sopenharmony_ci 499cb93a386Sopenharmony_ci if (fParagraphStyle.getMaxLines() == 1 && 500cb93a386Sopenharmony_ci fParagraphStyle.getEllipsisMod() == EllipsisModal::MIDDLE) { 501cb93a386Sopenharmony_ci fOldMaxWidth = rawWidth; 502cb93a386Sopenharmony_ci isMiddleEllipsis = true; 503cb93a386Sopenharmony_ci } 504cb93a386Sopenharmony_ci if (getApplyRoundingHack()) { 505cb93a386Sopenharmony_ci floorWidth = SkScalarFloorToScalar(floorWidth); 506cb93a386Sopenharmony_ci } 507cb93a386Sopenharmony_ci 508cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 509cb93a386Sopenharmony_ci bool isMaxLinesZero = false; 510cb93a386Sopenharmony_ci#endif 511cb93a386Sopenharmony_ci if (fParagraphStyle.getMaxLines() == 0) { 512cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 513cb93a386Sopenharmony_ci if (fText.size() != 0) { 514cb93a386Sopenharmony_ci isMaxLinesZero = true; 515cb93a386Sopenharmony_ci } 516cb93a386Sopenharmony_ci#endif 517cb93a386Sopenharmony_ci fText.reset(); 518cb93a386Sopenharmony_ci } 519cb93a386Sopenharmony_ci 520cb93a386Sopenharmony_ci if ((!SkScalarIsFinite(rawWidth) || fLongestLine <= floorWidth) && 521cb93a386Sopenharmony_ci fState >= kLineBroken && 522cb93a386Sopenharmony_ci fLines.size() == 1 && fLines.front().ellipsis() == nullptr) { 523cb93a386Sopenharmony_ci // Most common case: one line of text (and one line is never justified, so no cluster shifts) 524cb93a386Sopenharmony_ci // We cannot mark it as kLineBroken because the new width can be bigger than the old width 525cb93a386Sopenharmony_ci fWidth = floorWidth; 526cb93a386Sopenharmony_ci fState = kShaped; 527cb93a386Sopenharmony_ci } else if (fState >= kLineBroken && fOldWidth != floorWidth) { 528cb93a386Sopenharmony_ci // We can use the results from SkShaper but have to do EVERYTHING ELSE again 529cb93a386Sopenharmony_ci fState = kShaped; 530cb93a386Sopenharmony_ci } else { 531cb93a386Sopenharmony_ci // Nothing changed case: we can reuse the data from the last layout 532cb93a386Sopenharmony_ci } 533cb93a386Sopenharmony_ci 534cb93a386Sopenharmony_ci this->prepareForMiddleEllipsis(rawWidth); 535cb93a386Sopenharmony_ci this->fUnicodeText = convertUtf8ToUnicode(fText); 536cb93a386Sopenharmony_ci auto paragraphCache = fFontCollection->getParagraphCache(); 537cb93a386Sopenharmony_ci 538cb93a386Sopenharmony_ci if (fState < kShaped) { 539cb93a386Sopenharmony_ci // Check if we have the text in the cache and don't need to shape it again 540cb93a386Sopenharmony_ci if (!paragraphCache->findParagraph(this)) { 541cb93a386Sopenharmony_ci if (fState < kIndexed) { 542cb93a386Sopenharmony_ci // This only happens once at the first layout; the text is immutable 543cb93a386Sopenharmony_ci // and there is no reason to repeat it 544cb93a386Sopenharmony_ci if (this->computeCodeUnitProperties()) { 545cb93a386Sopenharmony_ci fState = kIndexed; 546cb93a386Sopenharmony_ci } 547cb93a386Sopenharmony_ci } 548cb93a386Sopenharmony_ci this->fRuns.reset(); 549cb93a386Sopenharmony_ci this->fClusters.reset(); 550cb93a386Sopenharmony_ci this->fClustersIndexFromCodeUnit.reset(); 551cb93a386Sopenharmony_ci this->fClustersIndexFromCodeUnit.push_back_n(fText.size() + 1, EMPTY_INDEX); 552cb93a386Sopenharmony_ci if (!this->shapeTextIntoEndlessLine()) { 553cb93a386Sopenharmony_ci this->resetContext(); 554cb93a386Sopenharmony_ci 555cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 556cb93a386Sopenharmony_ci if (isMaxLinesZero) { 557cb93a386Sopenharmony_ci fExceededMaxLines = true; 558cb93a386Sopenharmony_ci } 559cb93a386Sopenharmony_ci#endif 560cb93a386Sopenharmony_ci // TODO: merge the two next calls - they always come together 561cb93a386Sopenharmony_ci this->resolveStrut(); 562cb93a386Sopenharmony_ci this->computeEmptyMetrics(); 563cb93a386Sopenharmony_ci this->fLines.reset(); 564cb93a386Sopenharmony_ci 565cb93a386Sopenharmony_ci // Set the important values that are not zero 566cb93a386Sopenharmony_ci fWidth = floorWidth; 567cb93a386Sopenharmony_ci fHeight = fEmptyMetrics.height(); 568cb93a386Sopenharmony_ci if (fParagraphStyle.getStrutStyle().getStrutEnabled() && 569cb93a386Sopenharmony_ci fParagraphStyle.getStrutStyle().getForceStrutHeight()) { 570cb93a386Sopenharmony_ci fHeight = fStrutMetrics.height(); 571cb93a386Sopenharmony_ci } 572cb93a386Sopenharmony_ci if (fParagraphStyle.getMaxLines() == 0) { 573cb93a386Sopenharmony_ci fHeight = 0; 574cb93a386Sopenharmony_ci } 575cb93a386Sopenharmony_ci fAlphabeticBaseline = fEmptyMetrics.alphabeticBaseline(); 576cb93a386Sopenharmony_ci fIdeographicBaseline = fEmptyMetrics.ideographicBaseline(); 577cb93a386Sopenharmony_ci fLongestLine = FLT_MIN - FLT_MAX; // That is what flutter has 578cb93a386Sopenharmony_ci fMinIntrinsicWidth = 0; 579cb93a386Sopenharmony_ci fMaxIntrinsicWidth = 0; 580cb93a386Sopenharmony_ci this->fOldWidth = floorWidth; 581cb93a386Sopenharmony_ci this->fOldHeight = this->fHeight; 582cb93a386Sopenharmony_ci 583cb93a386Sopenharmony_ci return; 584cb93a386Sopenharmony_ci } else if (!(fParagraphStyle.getMaxLines() == 1 && 585cb93a386Sopenharmony_ci fParagraphStyle.getEllipsisMod() == EllipsisModal::MIDDLE)) { 586cb93a386Sopenharmony_ci // Add the paragraph to the cache 587cb93a386Sopenharmony_ci paragraphCache->updateParagraph(this); 588cb93a386Sopenharmony_ci } 589cb93a386Sopenharmony_ci } 590cb93a386Sopenharmony_ci fState = kShaped; 591cb93a386Sopenharmony_ci } 592cb93a386Sopenharmony_ci 593cb93a386Sopenharmony_ci if (fState == kShaped) { 594cb93a386Sopenharmony_ci this->resetContext(); 595cb93a386Sopenharmony_ci this->resolveStrut(); 596cb93a386Sopenharmony_ci this->computeEmptyMetrics(); 597cb93a386Sopenharmony_ci this->fLines.reset(); 598cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 599cb93a386Sopenharmony_ci // fast path 600cb93a386Sopenharmony_ci if (!fHasLineBreaks && 601cb93a386Sopenharmony_ci !fHasWhitespacesInside && 602cb93a386Sopenharmony_ci fPlaceholders.size() == 1 && 603cb93a386Sopenharmony_ci (fRuns.size() == 1 && fRuns[0].fAdvance.fX <= floorWidth - this->detectIndents(0))) { 604cb93a386Sopenharmony_ci positionShapedTextIntoLine(floorWidth); 605cb93a386Sopenharmony_ci } else if (!paragraphCache->GetStoredLayout(*this)) { 606cb93a386Sopenharmony_ci breakShapedTextIntoLines(floorWidth); 607cb93a386Sopenharmony_ci // text breaking did not go to fast path and we did not have cached layout 608cb93a386Sopenharmony_ci paragraphCache->SetStoredLayout(*this); 609cb93a386Sopenharmony_ci } 610cb93a386Sopenharmony_ci#else 611cb93a386Sopenharmony_ci this->breakShapedTextIntoLines(floorWidth); 612cb93a386Sopenharmony_ci#endif 613cb93a386Sopenharmony_ci fState = kLineBroken; 614cb93a386Sopenharmony_ci } 615cb93a386Sopenharmony_ci 616cb93a386Sopenharmony_ci if (fState == kLineBroken) { 617cb93a386Sopenharmony_ci // Build the picture lazily not until we actually have to paint (or never) 618cb93a386Sopenharmony_ci this->resetShifts(); 619cb93a386Sopenharmony_ci this->formatLines(fWidth); 620cb93a386Sopenharmony_ci fState = kFormatted; 621cb93a386Sopenharmony_ci } 622cb93a386Sopenharmony_ci 623cb93a386Sopenharmony_ci if (fParagraphStyle.getMaxLines() == 0) { 624cb93a386Sopenharmony_ci fHeight = 0; 625cb93a386Sopenharmony_ci } 626cb93a386Sopenharmony_ci 627cb93a386Sopenharmony_ci this->fOldWidth = floorWidth; 628cb93a386Sopenharmony_ci this->fOldHeight = this->fHeight; 629cb93a386Sopenharmony_ci 630cb93a386Sopenharmony_ci if (getApplyRoundingHack()) { 631cb93a386Sopenharmony_ci // TODO: This rounding is done to match Flutter tests. Must be removed... 632cb93a386Sopenharmony_ci fMinIntrinsicWidth = littleRound(fMinIntrinsicWidth); 633cb93a386Sopenharmony_ci fMaxIntrinsicWidth = littleRound(fMaxIntrinsicWidth); 634cb93a386Sopenharmony_ci } 635cb93a386Sopenharmony_ci 636cb93a386Sopenharmony_ci // TODO: This is strictly Flutter thing. Must be factored out into some flutter code 637cb93a386Sopenharmony_ci if (fParagraphStyle.getMaxLines() == 1 || 638cb93a386Sopenharmony_ci (fParagraphStyle.unlimited_lines() && fParagraphStyle.ellipsized())) { 639cb93a386Sopenharmony_ci fMinIntrinsicWidth = fMaxIntrinsicWidth; 640cb93a386Sopenharmony_ci } 641cb93a386Sopenharmony_ci 642cb93a386Sopenharmony_ci // TODO: Since min and max are calculated differently it's possible to get a rounding error 643cb93a386Sopenharmony_ci // that would make min > max. Sort it out later, make it the same for now 644cb93a386Sopenharmony_ci if (fMaxIntrinsicWidth < fMinIntrinsicWidth) { 645cb93a386Sopenharmony_ci fMaxIntrinsicWidth = fMinIntrinsicWidth; 646cb93a386Sopenharmony_ci } 647cb93a386Sopenharmony_ci if (fParagraphStyle.getMaxLines() == 0) { 648cb93a386Sopenharmony_ci fLineNumber = 0; 649cb93a386Sopenharmony_ci } else { 650cb93a386Sopenharmony_ci fLineNumber = std::max(size_t(1), fLines.size()); 651cb93a386Sopenharmony_ci } 652cb93a386Sopenharmony_ci //SkDebugf("layout('%s', %f): %f %f\n", fText.c_str(), rawWidth, fMinIntrinsicWidth, fMaxIntrinsicWidth); 653cb93a386Sopenharmony_ci} 654cb93a386Sopenharmony_ci 655cb93a386Sopenharmony_civoid ParagraphImpl::paint(SkCanvas* canvas, SkScalar x, SkScalar y) { 656cb93a386Sopenharmony_ci CanvasParagraphPainter painter(canvas); 657cb93a386Sopenharmony_ci paint(&painter, x, y); 658cb93a386Sopenharmony_ci} 659cb93a386Sopenharmony_ci 660cb93a386Sopenharmony_civoid ParagraphImpl::paint(ParagraphPainter* painter, SkScalar x, SkScalar y) { 661cb93a386Sopenharmony_ci for (auto& line : fLines) { 662cb93a386Sopenharmony_ci line.paint(painter, x, y); 663cb93a386Sopenharmony_ci } 664cb93a386Sopenharmony_ci} 665cb93a386Sopenharmony_ci 666cb93a386Sopenharmony_civoid ParagraphImpl::paint(ParagraphPainter* painter, RSPath* path, SkScalar hOffset, SkScalar vOffset) { 667cb93a386Sopenharmony_ci auto& style = fTextStyles[0].fStyle; 668cb93a386Sopenharmony_ci float align = 0.0f; 669cb93a386Sopenharmony_ci switch (paragraphStyle().getTextAlign()) { 670cb93a386Sopenharmony_ci case TextAlign::kCenter: 671cb93a386Sopenharmony_ci align = -0.5f; 672cb93a386Sopenharmony_ci break; 673cb93a386Sopenharmony_ci case TextAlign::kRight: 674cb93a386Sopenharmony_ci align = -1.0f; 675cb93a386Sopenharmony_ci break; 676cb93a386Sopenharmony_ci default: 677cb93a386Sopenharmony_ci break; 678cb93a386Sopenharmony_ci } 679cb93a386Sopenharmony_ci hOffset += align * (fMaxIntrinsicWidth - style.getLetterSpacing() - path->GetLength(false)); 680cb93a386Sopenharmony_ci for (auto& line : fLines) { 681cb93a386Sopenharmony_ci line.paint(painter, path, hOffset, vOffset); 682cb93a386Sopenharmony_ci } 683cb93a386Sopenharmony_ci} 684cb93a386Sopenharmony_ci 685cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 686cb93a386Sopenharmony_ciTextRange ParagraphImpl::getEllipsisTextRange() { 687cb93a386Sopenharmony_ci if (fState < kLineBroken) { 688cb93a386Sopenharmony_ci return EMPTY_RANGE; 689cb93a386Sopenharmony_ci } 690cb93a386Sopenharmony_ci if (!fEllipsisRange.empty()) { 691cb93a386Sopenharmony_ci return fEllipsisRange; 692cb93a386Sopenharmony_ci } 693cb93a386Sopenharmony_ci this->ensureUTF16Mapping(); 694cb93a386Sopenharmony_ci for (const auto& line: fLines) { 695cb93a386Sopenharmony_ci if (line.getTextRangeReplacedByEllipsis().empty()) { 696cb93a386Sopenharmony_ci continue; 697cb93a386Sopenharmony_ci } 698cb93a386Sopenharmony_ci auto ellipsisClusterRange = line.getTextRangeReplacedByEllipsis(); 699cb93a386Sopenharmony_ci return TextRange(getUTF16Index(ellipsisClusterRange.start), 700cb93a386Sopenharmony_ci getUTF16Index(ellipsisClusterRange.end)); 701cb93a386Sopenharmony_ci } 702cb93a386Sopenharmony_ci return EMPTY_RANGE; 703cb93a386Sopenharmony_ci} 704cb93a386Sopenharmony_ci#endif 705cb93a386Sopenharmony_ci 706cb93a386Sopenharmony_civoid ParagraphImpl::resetContext() { 707cb93a386Sopenharmony_ci fAlphabeticBaseline = 0; 708cb93a386Sopenharmony_ci fHeight = 0; 709cb93a386Sopenharmony_ci fWidth = 0; 710cb93a386Sopenharmony_ci fIdeographicBaseline = 0; 711cb93a386Sopenharmony_ci fMaxIntrinsicWidth = 0; 712cb93a386Sopenharmony_ci fMinIntrinsicWidth = 0; 713cb93a386Sopenharmony_ci fLongestLine = 0; 714cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 715cb93a386Sopenharmony_ci fLongestLineWithIndent = 0; 716cb93a386Sopenharmony_ci#endif 717cb93a386Sopenharmony_ci fMaxWidthWithTrailingSpaces = 0; 718cb93a386Sopenharmony_ci fExceededMaxLines = false; 719cb93a386Sopenharmony_ci} 720cb93a386Sopenharmony_ci 721cb93a386Sopenharmony_ci// shapeTextIntoEndlessLine is the thing that calls this method 722cb93a386Sopenharmony_cibool ParagraphImpl::computeCodeUnitProperties() { 723cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 724cb93a386Sopenharmony_ci TEXT_TRACE_FUNC(); 725cb93a386Sopenharmony_ci#endif 726cb93a386Sopenharmony_ci if (nullptr == fUnicode) { 727cb93a386Sopenharmony_ci return false; 728cb93a386Sopenharmony_ci } 729cb93a386Sopenharmony_ci 730cb93a386Sopenharmony_ci // Get bidi regions 731cb93a386Sopenharmony_ci auto textDirection = fParagraphStyle.getTextDirection() == TextDirection::kLtr 732cb93a386Sopenharmony_ci ? SkUnicode::TextDirection::kLTR 733cb93a386Sopenharmony_ci : SkUnicode::TextDirection::kRTL; 734cb93a386Sopenharmony_ci if (!fUnicode->getBidiRegions(fText.c_str(), fText.size(), textDirection, &fBidiRegions)) { 735cb93a386Sopenharmony_ci return false; 736cb93a386Sopenharmony_ci } 737cb93a386Sopenharmony_ci 738cb93a386Sopenharmony_ci // Collect all spaces and some extra information 739cb93a386Sopenharmony_ci // (and also substitute \t with a space while we are at it) 740cb93a386Sopenharmony_ci if (!fUnicode->computeCodeUnitFlags(&fText[0], 741cb93a386Sopenharmony_ci fText.size(), 742cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 743cb93a386Sopenharmony_ci this->paragraphStyle().getReplaceTabCharacters() || 744cb93a386Sopenharmony_ci (!(this->paragraphStyle().getTextTab().location < 1.0)), 745cb93a386Sopenharmony_ci#else 746cb93a386Sopenharmony_ci this->paragraphStyle().getReplaceTabCharacters(), 747cb93a386Sopenharmony_ci#endif 748cb93a386Sopenharmony_ci &fCodeUnitProperties)) { 749cb93a386Sopenharmony_ci return false; 750cb93a386Sopenharmony_ci } 751cb93a386Sopenharmony_ci 752cb93a386Sopenharmony_ci // Get some information about trailing spaces / hard line breaks 753cb93a386Sopenharmony_ci fTrailingSpaces = fText.size(); 754cb93a386Sopenharmony_ci TextIndex firstWhitespace = EMPTY_INDEX; 755cb93a386Sopenharmony_ci for (int i = 0; i < fCodeUnitProperties.size(); ++i) { 756cb93a386Sopenharmony_ci auto flags = fCodeUnitProperties[i]; 757cb93a386Sopenharmony_ci if (SkUnicode::isPartOfWhiteSpaceBreak(flags)) { 758cb93a386Sopenharmony_ci if (fTrailingSpaces == fText.size()) { 759cb93a386Sopenharmony_ci fTrailingSpaces = i; 760cb93a386Sopenharmony_ci } 761cb93a386Sopenharmony_ci if (firstWhitespace == EMPTY_INDEX) { 762cb93a386Sopenharmony_ci firstWhitespace = i; 763cb93a386Sopenharmony_ci } 764cb93a386Sopenharmony_ci } else { 765cb93a386Sopenharmony_ci fTrailingSpaces = fText.size(); 766cb93a386Sopenharmony_ci } 767cb93a386Sopenharmony_ci if (SkUnicode::isHardLineBreak(flags)) { 768cb93a386Sopenharmony_ci fHasLineBreaks = true; 769cb93a386Sopenharmony_ci } 770cb93a386Sopenharmony_ci } 771cb93a386Sopenharmony_ci 772cb93a386Sopenharmony_ci if (firstWhitespace < fTrailingSpaces) { 773cb93a386Sopenharmony_ci fHasWhitespacesInside = true; 774cb93a386Sopenharmony_ci } 775cb93a386Sopenharmony_ci 776cb93a386Sopenharmony_ci return true; 777cb93a386Sopenharmony_ci} 778cb93a386Sopenharmony_ci 779cb93a386Sopenharmony_cistatic bool is_ascii_7bit_space(int c) { 780cb93a386Sopenharmony_ci SkASSERT(c >= 0 && c <= 127); 781cb93a386Sopenharmony_ci 782cb93a386Sopenharmony_ci // Extracted from https://en.wikipedia.org/wiki/Whitespace_character 783cb93a386Sopenharmony_ci // 784cb93a386Sopenharmony_ci enum WS { 785cb93a386Sopenharmony_ci kHT = 9, 786cb93a386Sopenharmony_ci kLF = 10, 787cb93a386Sopenharmony_ci kVT = 11, 788cb93a386Sopenharmony_ci kFF = 12, 789cb93a386Sopenharmony_ci kCR = 13, 790cb93a386Sopenharmony_ci kSP = 32, // too big to use as shift 791cb93a386Sopenharmony_ci }; 792cb93a386Sopenharmony_ci#define M(shift) (1 << (shift)) 793cb93a386Sopenharmony_ci constexpr uint32_t kSpaceMask = M(kHT) | M(kLF) | M(kVT) | M(kFF) | M(kCR); 794cb93a386Sopenharmony_ci // we check for Space (32) explicitly, since it is too large to shift 795cb93a386Sopenharmony_ci return (c == kSP) || (c <= 31 && (kSpaceMask & M(c))); 796cb93a386Sopenharmony_ci#undef M 797cb93a386Sopenharmony_ci} 798cb93a386Sopenharmony_ci 799cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 800cb93a386Sopenharmony_cistatic std::vector<SkRange<SkUnichar>> CJK_UNICODE_SET = { 801cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x4E00, 0x9FFF), 802cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x3400, 0x4DBF), 803cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x20000, 0x2A6DF), 804cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x2A700, 0x2B73F), 805cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x2B740, 0x2B81F), 806cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x2B820, 0x2CEAF), 807cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x2CEB0, 0x2EBEF), 808cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x30000, 0x3134F), 809cb93a386Sopenharmony_ci SkRange<SkUnichar>(0xF900, 0xFAFF), 810cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x3040, 0x309F), 811cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x30A0, 0x30FF), 812cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x31F0, 0x31FF), 813cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x1100, 0x11FF), 814cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x3130, 0x318F), 815cb93a386Sopenharmony_ci SkRange<SkUnichar>(0xAC00, 0xD7AF), 816cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x31C0, 0x31EF), 817cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x2E80, 0x2EFF), 818cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x2F800, 0x2FA1F), 819cb93a386Sopenharmony_ci}; 820cb93a386Sopenharmony_ci 821cb93a386Sopenharmony_cistatic std::vector<SkRange<SkUnichar>> WESTERN_UNICODE_SET = { 822cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x0041, 0x005A), 823cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x0061, 0x007A), 824cb93a386Sopenharmony_ci SkRange<SkUnichar>(0x0030, 0x0039), 825cb93a386Sopenharmony_ci}; 826cb93a386Sopenharmony_ci 827cb93a386Sopenharmony_ciconstexpr SkUnichar COPYRIGHT_UNICODE = 0x00A9; 828cb93a386Sopenharmony_ci 829cb93a386Sopenharmony_cistruct UnicodeSet { 830cb93a386Sopenharmony_ci std::unordered_set<SkUnichar> set_; 831cb93a386Sopenharmony_ci explicit UnicodeSet(const std::vector<SkRange<SkUnichar>>& unicodeSet) { 832cb93a386Sopenharmony_ci if (!TextParameter::GetAutoSpacingEnable()) { 833cb93a386Sopenharmony_ci return; 834cb93a386Sopenharmony_ci } 835cb93a386Sopenharmony_ci for (auto unicodeSetRange : unicodeSet) { 836cb93a386Sopenharmony_ci for (auto i = unicodeSetRange.start; i <= unicodeSetRange.end; ++i) { 837cb93a386Sopenharmony_ci set_.insert(i); 838cb93a386Sopenharmony_ci } 839cb93a386Sopenharmony_ci } 840cb93a386Sopenharmony_ci } 841cb93a386Sopenharmony_ci bool exist(SkUnichar c) const { 842cb93a386Sopenharmony_ci return set_.find(c) != set_.end(); 843cb93a386Sopenharmony_ci } 844cb93a386Sopenharmony_ci}; 845cb93a386Sopenharmony_ci 846cb93a386Sopenharmony_cistatic const UnicodeSet CJK_SET(CJK_UNICODE_SET); 847cb93a386Sopenharmony_cistatic const UnicodeSet WESTERN_SET(WESTERN_UNICODE_SET); 848cb93a386Sopenharmony_ci#endif 849cb93a386Sopenharmony_ci 850cb93a386Sopenharmony_ciCluster::Cluster(ParagraphImpl* owner, 851cb93a386Sopenharmony_ci RunIndex runIndex, 852cb93a386Sopenharmony_ci size_t start, 853cb93a386Sopenharmony_ci size_t end, 854cb93a386Sopenharmony_ci SkSpan<const char> text, 855cb93a386Sopenharmony_ci SkScalar width, 856cb93a386Sopenharmony_ci SkScalar height) 857cb93a386Sopenharmony_ci : fOwner(owner) 858cb93a386Sopenharmony_ci , fRunIndex(runIndex) 859cb93a386Sopenharmony_ci , fTextRange(text.begin() - fOwner->text().begin(), text.end() - fOwner->text().begin()) 860cb93a386Sopenharmony_ci , fGraphemeRange(EMPTY_RANGE) 861cb93a386Sopenharmony_ci , fStart(start) 862cb93a386Sopenharmony_ci , fEnd(end) 863cb93a386Sopenharmony_ci , fWidth(width) 864cb93a386Sopenharmony_ci , fHeight(height) 865cb93a386Sopenharmony_ci , fHalfLetterSpacing(0.0) 866cb93a386Sopenharmony_ci , fIsIdeographic(false) { 867cb93a386Sopenharmony_ci size_t whiteSpacesBreakLen = 0; 868cb93a386Sopenharmony_ci size_t intraWordBreakLen = 0; 869cb93a386Sopenharmony_ci 870cb93a386Sopenharmony_ci const char* ch = text.begin(); 871cb93a386Sopenharmony_ci if (text.end() - ch == 1 && *(unsigned char*)ch <= 0x7F) { 872cb93a386Sopenharmony_ci // I am not even sure it's worth it if we do not save a unicode call 873cb93a386Sopenharmony_ci if (is_ascii_7bit_space(*ch)) { 874cb93a386Sopenharmony_ci ++whiteSpacesBreakLen; 875cb93a386Sopenharmony_ci } 876cb93a386Sopenharmony_ci } else { 877cb93a386Sopenharmony_ci for (auto i = fTextRange.start; i < fTextRange.end; ++i) { 878cb93a386Sopenharmony_ci if (fOwner->codeUnitHasProperty(i, SkUnicode::CodeUnitFlags::kPartOfWhiteSpaceBreak)) { 879cb93a386Sopenharmony_ci ++whiteSpacesBreakLen; 880cb93a386Sopenharmony_ci } 881cb93a386Sopenharmony_ci if (fOwner->codeUnitHasProperty(i, SkUnicode::CodeUnitFlags::kPartOfIntraWordBreak)) { 882cb93a386Sopenharmony_ci ++intraWordBreakLen; 883cb93a386Sopenharmony_ci } 884cb93a386Sopenharmony_ci if (fOwner->codeUnitHasProperty(i, SkUnicode::CodeUnitFlags::kIdeographic)) { 885cb93a386Sopenharmony_ci fIsIdeographic = true; 886cb93a386Sopenharmony_ci } 887cb93a386Sopenharmony_ci } 888cb93a386Sopenharmony_ci } 889cb93a386Sopenharmony_ci 890cb93a386Sopenharmony_ci fIsWhiteSpaceBreak = whiteSpacesBreakLen == fTextRange.width(); 891cb93a386Sopenharmony_ci fIsIntraWordBreak = intraWordBreakLen == fTextRange.width(); 892cb93a386Sopenharmony_ci fIsHardBreak = fOwner->codeUnitHasProperty(fTextRange.end, 893cb93a386Sopenharmony_ci SkUnicode::CodeUnitFlags::kHardLineBreakBefore); 894cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 895cb93a386Sopenharmony_ci fIsTabulation = fOwner->codeUnitHasProperty(fTextRange.start, 896cb93a386Sopenharmony_ci SkUnicode::CodeUnitFlags::kTabulation); 897cb93a386Sopenharmony_ci#endif 898cb93a386Sopenharmony_ci auto unicodeStart = fOwner->getUnicodeIndex(fTextRange.start); 899cb93a386Sopenharmony_ci auto unicodeEnd = fOwner->getUnicodeIndex(fTextRange.end); 900cb93a386Sopenharmony_ci SkUnichar unicode = 0; 901cb93a386Sopenharmony_ci if (unicodeEnd - unicodeStart == 1 && unicodeStart < fOwner->unicodeText().size()) { 902cb93a386Sopenharmony_ci unicode = fOwner->unicodeText()[unicodeStart]; 903cb93a386Sopenharmony_ci } 904cb93a386Sopenharmony_ci fIsCopyright = unicode == COPYRIGHT_UNICODE; 905cb93a386Sopenharmony_ci fIsCJK = CJK_SET.exist(unicode); 906cb93a386Sopenharmony_ci fIsWestern = WESTERN_SET.exist(unicode); 907cb93a386Sopenharmony_ci} 908cb93a386Sopenharmony_ci 909cb93a386Sopenharmony_ciSkScalar Run::calculateWidth(size_t start, size_t end, bool clip) const { 910cb93a386Sopenharmony_ci SkASSERT(start <= end); 911cb93a386Sopenharmony_ci // clip |= end == size(); // Clip at the end of the run? 912cb93a386Sopenharmony_ci auto correction = 0.0f; 913cb93a386Sopenharmony_ci if (end > start && !fJustificationShifts.empty()) { 914cb93a386Sopenharmony_ci // This is not a typo: we are using Point as a pair of SkScalars 915cb93a386Sopenharmony_ci correction = fJustificationShifts[end - 1].fX - 916cb93a386Sopenharmony_ci fJustificationShifts[start].fY; 917cb93a386Sopenharmony_ci } 918cb93a386Sopenharmony_ci if (end > start && !fAutoSpacings.empty()) { 919cb93a386Sopenharmony_ci // This is not a tyopo: we are using Point as a pair of SkScalars 920cb93a386Sopenharmony_ci correction += fAutoSpacings[end - 1].fX - fAutoSpacings[start].fY; 921cb93a386Sopenharmony_ci } 922cb93a386Sopenharmony_ci return posX(end) - posX(start) + correction; 923cb93a386Sopenharmony_ci} 924cb93a386Sopenharmony_ci 925cb93a386Sopenharmony_ci// In some cases we apply spacing to glyphs first and then build the cluster table, in some we do 926cb93a386Sopenharmony_ci// the opposite - just to optimize the most common case. 927cb93a386Sopenharmony_civoid ParagraphImpl::applySpacingAndBuildClusterTable() { 928cb93a386Sopenharmony_ci 929cb93a386Sopenharmony_ci // Check all text styles to see what we have to do (if anything) 930cb93a386Sopenharmony_ci size_t letterSpacingStyles = 0; 931cb93a386Sopenharmony_ci bool hasWordSpacing = false; 932cb93a386Sopenharmony_ci for (auto& block : fTextStyles) { 933cb93a386Sopenharmony_ci if (block.fRange.width() > 0) { 934cb93a386Sopenharmony_ci if (!SkScalarNearlyZero(block.fStyle.getLetterSpacing())) { 935cb93a386Sopenharmony_ci ++letterSpacingStyles; 936cb93a386Sopenharmony_ci } 937cb93a386Sopenharmony_ci if (!SkScalarNearlyZero(block.fStyle.getWordSpacing())) { 938cb93a386Sopenharmony_ci hasWordSpacing = true; 939cb93a386Sopenharmony_ci } 940cb93a386Sopenharmony_ci } 941cb93a386Sopenharmony_ci } 942cb93a386Sopenharmony_ci 943cb93a386Sopenharmony_ci if (letterSpacingStyles == 0 && !hasWordSpacing) { 944cb93a386Sopenharmony_ci // We don't have to do anything about spacing (most common case) 945cb93a386Sopenharmony_ci this->buildClusterTable(); 946cb93a386Sopenharmony_ci return; 947cb93a386Sopenharmony_ci } 948cb93a386Sopenharmony_ci 949cb93a386Sopenharmony_ci if (letterSpacingStyles == 1 && !hasWordSpacing && fTextStyles.size() == 1 && 950cb93a386Sopenharmony_ci fTextStyles[0].fRange.width() == fText.size() && fRuns.size() == 1) { 951cb93a386Sopenharmony_ci // We have to letter space the entire paragraph (second most common case) 952cb93a386Sopenharmony_ci auto& run = fRuns[0]; 953cb93a386Sopenharmony_ci auto& style = fTextStyles[0].fStyle; 954cb93a386Sopenharmony_ci this->buildClusterTable(); 955cb93a386Sopenharmony_ci SkScalar shift = 0; 956cb93a386Sopenharmony_ci run.iterateThroughClusters([this, &run, &shift, &style](Cluster* cluster) { 957cb93a386Sopenharmony_ci run.shift(cluster, shift); 958cb93a386Sopenharmony_ci shift += run.addSpacesEvenly(style.getLetterSpacing(), cluster); 959cb93a386Sopenharmony_ci }); 960cb93a386Sopenharmony_ci return; 961cb93a386Sopenharmony_ci } 962cb93a386Sopenharmony_ci 963cb93a386Sopenharmony_ci // The complex case: many text styles with spacing (possibly not adjusted to glyphs) 964cb93a386Sopenharmony_ci this->buildClusterTable(); 965cb93a386Sopenharmony_ci 966cb93a386Sopenharmony_ci // Walk through all the clusters in the direction of shaped text 967cb93a386Sopenharmony_ci // (we have to walk through the styles in the same order, too) 968cb93a386Sopenharmony_ci SkScalar shift = 0; 969cb93a386Sopenharmony_ci for (auto& run : fRuns) { 970cb93a386Sopenharmony_ci 971cb93a386Sopenharmony_ci // Skip placeholder runs 972cb93a386Sopenharmony_ci if (run.isPlaceholder()) { 973cb93a386Sopenharmony_ci continue; 974cb93a386Sopenharmony_ci } 975cb93a386Sopenharmony_ci bool soFarWhitespacesOnly = true; 976cb93a386Sopenharmony_ci bool wordSpacingPending = false; 977cb93a386Sopenharmony_ci Cluster* lastSpaceCluster = nullptr; 978cb93a386Sopenharmony_ci run.iterateThroughClusters([this, &run, &shift, &soFarWhitespacesOnly, &wordSpacingPending, &lastSpaceCluster](Cluster* cluster) { 979cb93a386Sopenharmony_ci // Shift the cluster (shift collected from the previous clusters) 980cb93a386Sopenharmony_ci run.shift(cluster, shift); 981cb93a386Sopenharmony_ci 982cb93a386Sopenharmony_ci // Synchronize styles (one cluster can be covered by few styles) 983cb93a386Sopenharmony_ci Block* currentStyle = fTextStyles.begin(); 984cb93a386Sopenharmony_ci while (!cluster->startsIn(currentStyle->fRange)) { 985cb93a386Sopenharmony_ci currentStyle++; 986cb93a386Sopenharmony_ci SkASSERT(currentStyle != fTextStyles.end()); 987cb93a386Sopenharmony_ci } 988cb93a386Sopenharmony_ci 989cb93a386Sopenharmony_ci SkASSERT(!currentStyle->fStyle.isPlaceholder()); 990cb93a386Sopenharmony_ci 991cb93a386Sopenharmony_ci // Process word spacing 992cb93a386Sopenharmony_ci if (currentStyle->fStyle.getWordSpacing() != 0) { 993cb93a386Sopenharmony_ci if (cluster->isWhitespaceBreak() && cluster->isSoftBreak()) { 994cb93a386Sopenharmony_ci if (!soFarWhitespacesOnly) { 995cb93a386Sopenharmony_ci lastSpaceCluster = cluster; 996cb93a386Sopenharmony_ci wordSpacingPending = true; 997cb93a386Sopenharmony_ci } 998cb93a386Sopenharmony_ci } else if (wordSpacingPending) { 999cb93a386Sopenharmony_ci SkScalar spacing = currentStyle->fStyle.getWordSpacing(); 1000cb93a386Sopenharmony_ci run.addSpacesAtTheEnd(spacing, lastSpaceCluster); 1001cb93a386Sopenharmony_ci run.shift(cluster, spacing); 1002cb93a386Sopenharmony_ci shift += spacing; 1003cb93a386Sopenharmony_ci wordSpacingPending = false; 1004cb93a386Sopenharmony_ci } 1005cb93a386Sopenharmony_ci } 1006cb93a386Sopenharmony_ci // Process letter spacing 1007cb93a386Sopenharmony_ci if (currentStyle->fStyle.getLetterSpacing() != 0) { 1008cb93a386Sopenharmony_ci shift += run.addSpacesEvenly(currentStyle->fStyle.getLetterSpacing(), cluster); 1009cb93a386Sopenharmony_ci } 1010cb93a386Sopenharmony_ci 1011cb93a386Sopenharmony_ci if (soFarWhitespacesOnly && !cluster->isWhitespaceBreak()) { 1012cb93a386Sopenharmony_ci soFarWhitespacesOnly = false; 1013cb93a386Sopenharmony_ci } 1014cb93a386Sopenharmony_ci }); 1015cb93a386Sopenharmony_ci } 1016cb93a386Sopenharmony_ci} 1017cb93a386Sopenharmony_ci 1018cb93a386Sopenharmony_civoid ParagraphImpl::middleEllipsisAddText(size_t charStart, 1019cb93a386Sopenharmony_ci size_t charEnd, 1020cb93a386Sopenharmony_ci SkScalar& allTextWidth, 1021cb93a386Sopenharmony_ci SkScalar width, 1022cb93a386Sopenharmony_ci bool isLeftToRight) { 1023cb93a386Sopenharmony_ci if (isMiddleEllipsis) { 1024cb93a386Sopenharmony_ci TextCutRecord textCount; 1025cb93a386Sopenharmony_ci textCount.charbegin = charStart; 1026cb93a386Sopenharmony_ci textCount.charOver = charEnd; 1027cb93a386Sopenharmony_ci textCount.phraseWidth = width; 1028cb93a386Sopenharmony_ci allTextWidth += width; 1029cb93a386Sopenharmony_ci if (isLeftToRight) { 1030cb93a386Sopenharmony_ci this->ltrTextSize.emplace_back(textCount); 1031cb93a386Sopenharmony_ci } else { 1032cb93a386Sopenharmony_ci this->rtlTextSize.emplace_back(textCount); 1033cb93a386Sopenharmony_ci } 1034cb93a386Sopenharmony_ci } 1035cb93a386Sopenharmony_ci} 1036cb93a386Sopenharmony_ci 1037cb93a386Sopenharmony_ci// Clusters in the order of the input text 1038cb93a386Sopenharmony_civoid ParagraphImpl::buildClusterTable() { 1039cb93a386Sopenharmony_ci // It's possible that one grapheme includes few runs; we cannot handle it 1040cb93a386Sopenharmony_ci // so we break graphemes by the runs instead 1041cb93a386Sopenharmony_ci // It's not the ideal solution and has to be revisited later 1042cb93a386Sopenharmony_ci int cluster_count = 1; 1043cb93a386Sopenharmony_ci for (auto& run : fRuns) { 1044cb93a386Sopenharmony_ci cluster_count += run.isPlaceholder() ? 1 : run.size(); 1045cb93a386Sopenharmony_ci fCodeUnitProperties[run.fTextRange.start] |= SkUnicode::CodeUnitFlags::kGraphemeStart; 1046cb93a386Sopenharmony_ci fCodeUnitProperties[run.fTextRange.start] |= SkUnicode::CodeUnitFlags::kGlyphClusterStart; 1047cb93a386Sopenharmony_ci } 1048cb93a386Sopenharmony_ci if (!fRuns.empty()) { 1049cb93a386Sopenharmony_ci fCodeUnitProperties[fRuns.back().textRange().end] |= SkUnicode::CodeUnitFlags::kGraphemeStart; 1050cb93a386Sopenharmony_ci fCodeUnitProperties[fRuns.back().textRange().end] |= SkUnicode::CodeUnitFlags::kGlyphClusterStart; 1051cb93a386Sopenharmony_ci } 1052cb93a386Sopenharmony_ci fClusters.reserve_back(fClusters.size() + cluster_count); 1053cb93a386Sopenharmony_ci 1054cb93a386Sopenharmony_ci // Walk through all the run in the direction of input text 1055cb93a386Sopenharmony_ci for (auto& run : fRuns) { 1056cb93a386Sopenharmony_ci auto runIndex = run.index(); 1057cb93a386Sopenharmony_ci auto runStart = fClusters.size(); 1058cb93a386Sopenharmony_ci if (run.isPlaceholder()) { 1059cb93a386Sopenharmony_ci // Add info to cluster indexes table (text -> cluster) 1060cb93a386Sopenharmony_ci for (auto i = run.textRange().start; i < run.textRange().end; ++i) { 1061cb93a386Sopenharmony_ci fClustersIndexFromCodeUnit[i] = fClusters.size(); 1062cb93a386Sopenharmony_ci } 1063cb93a386Sopenharmony_ci // There are no glyphs but we want to have one cluster 1064cb93a386Sopenharmony_ci fClusters.emplace_back(this, runIndex, 0ul, 1ul, this->text(run.textRange()), run.advance().fX, run.advance().fY); 1065cb93a386Sopenharmony_ci fCodeUnitProperties[run.textRange().start] |= SkUnicode::CodeUnitFlags::kSoftLineBreakBefore; 1066cb93a386Sopenharmony_ci fCodeUnitProperties[run.textRange().end] |= SkUnicode::CodeUnitFlags::kSoftLineBreakBefore; 1067cb93a386Sopenharmony_ci } else { 1068cb93a386Sopenharmony_ci // Walk through the glyph in the direction of input text 1069cb93a386Sopenharmony_ci run.iterateThroughClustersInTextOrder([&run, runIndex, this](size_t glyphStart, 1070cb93a386Sopenharmony_ci size_t glyphEnd, 1071cb93a386Sopenharmony_ci size_t charStart, 1072cb93a386Sopenharmony_ci size_t charEnd, 1073cb93a386Sopenharmony_ci SkScalar width, 1074cb93a386Sopenharmony_ci SkScalar height) { 1075cb93a386Sopenharmony_ci SkASSERT(charEnd >= charStart); 1076cb93a386Sopenharmony_ci // Add info to cluster indexes table (text -> cluster) 1077cb93a386Sopenharmony_ci for (auto i = charStart; i < charEnd; ++i) { 1078cb93a386Sopenharmony_ci fClustersIndexFromCodeUnit[i] = fClusters.size(); 1079cb93a386Sopenharmony_ci } 1080cb93a386Sopenharmony_ci 1081cb93a386Sopenharmony_ci middleEllipsisAddText(charStart, charEnd, allTextWidth, width, run.leftToRight()); 1082cb93a386Sopenharmony_ci SkSpan<const char> text(fText.c_str() + charStart, charEnd - charStart); 1083cb93a386Sopenharmony_ci fClusters.emplace_back(this, runIndex, glyphStart, glyphEnd, text, width, height); 1084cb93a386Sopenharmony_ci fCodeUnitProperties[charStart] |= SkUnicode::CodeUnitFlags::kGlyphClusterStart; 1085cb93a386Sopenharmony_ci }); 1086cb93a386Sopenharmony_ci } 1087cb93a386Sopenharmony_ci fCodeUnitProperties[run.textRange().start] |= SkUnicode::CodeUnitFlags::kGlyphClusterStart; 1088cb93a386Sopenharmony_ci 1089cb93a386Sopenharmony_ci run.setClusterRange(runStart, fClusters.size()); 1090cb93a386Sopenharmony_ci fMaxIntrinsicWidth += run.advance().fX; 1091cb93a386Sopenharmony_ci } 1092cb93a386Sopenharmony_ci fClustersIndexFromCodeUnit[fText.size()] = fClusters.size(); 1093cb93a386Sopenharmony_ci fClusters.emplace_back(this, EMPTY_RUN, 0, 0, this->text({fText.size(), fText.size()}), 0, 0); 1094cb93a386Sopenharmony_ci} 1095cb93a386Sopenharmony_ci 1096cb93a386Sopenharmony_cibool ParagraphImpl::shapeTextIntoEndlessLine() { 1097cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1098cb93a386Sopenharmony_ci TEXT_TRACE_FUNC(); 1099cb93a386Sopenharmony_ci#endif 1100cb93a386Sopenharmony_ci if (fText.size() == 0) { 1101cb93a386Sopenharmony_ci return false; 1102cb93a386Sopenharmony_ci } 1103cb93a386Sopenharmony_ci 1104cb93a386Sopenharmony_ci fUnresolvedCodepoints.clear(); 1105cb93a386Sopenharmony_ci fFontSwitches.reset(); 1106cb93a386Sopenharmony_ci 1107cb93a386Sopenharmony_ci OneLineShaper oneLineShaper(this); 1108cb93a386Sopenharmony_ci auto result = oneLineShaper.shape(); 1109cb93a386Sopenharmony_ci fUnresolvedGlyphs = oneLineShaper.unresolvedGlyphs(); 1110cb93a386Sopenharmony_ci 1111cb93a386Sopenharmony_ci this->applySpacingAndBuildClusterTable(); 1112cb93a386Sopenharmony_ci 1113cb93a386Sopenharmony_ci return result; 1114cb93a386Sopenharmony_ci} 1115cb93a386Sopenharmony_ci 1116cb93a386Sopenharmony_civoid ParagraphImpl::setIndents(const std::vector<SkScalar>& indents) 1117cb93a386Sopenharmony_ci{ 1118cb93a386Sopenharmony_ci fIndents = indents; 1119cb93a386Sopenharmony_ci} 1120cb93a386Sopenharmony_ci 1121cb93a386Sopenharmony_ciSkScalar ParagraphImpl::detectIndents(size_t index) 1122cb93a386Sopenharmony_ci{ 1123cb93a386Sopenharmony_ci SkScalar indent = 0.0; 1124cb93a386Sopenharmony_ci if (fIndents.size() > 0 && index < fIndents.size()) { 1125cb93a386Sopenharmony_ci indent = fIndents[index]; 1126cb93a386Sopenharmony_ci } else { 1127cb93a386Sopenharmony_ci indent = fIndents.size() > 0 ? fIndents.back() : 0.0; 1128cb93a386Sopenharmony_ci } 1129cb93a386Sopenharmony_ci 1130cb93a386Sopenharmony_ci return indent; 1131cb93a386Sopenharmony_ci} 1132cb93a386Sopenharmony_ci 1133cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1134cb93a386Sopenharmony_civoid ParagraphImpl::positionShapedTextIntoLine(SkScalar maxWidth) { 1135cb93a386Sopenharmony_ci resetAutoSpacing(); 1136cb93a386Sopenharmony_ci // This is a short version of a line breaking when we know that: 1137cb93a386Sopenharmony_ci // 1. We have only one line of text 1138cb93a386Sopenharmony_ci // 2. It's shaped into a single run 1139cb93a386Sopenharmony_ci // 3. There are no placeholders 1140cb93a386Sopenharmony_ci // 4. There are no linebreaks (which will format text into multiple lines) 1141cb93a386Sopenharmony_ci // 5. There are no whitespaces so the minIntrinsicWidth=maxIntrinsicWidth 1142cb93a386Sopenharmony_ci // (To think about that, the last condition is not quite right; 1143cb93a386Sopenharmony_ci // we should calculate minIntrinsicWidth by soft line breaks. 1144cb93a386Sopenharmony_ci // However, it's how it's done in Flutter now) 1145cb93a386Sopenharmony_ci auto& run = this->fRuns[0]; 1146cb93a386Sopenharmony_ci auto advance = run.advance(); 1147cb93a386Sopenharmony_ci auto textRange = TextRange(0, this->text().size()); 1148cb93a386Sopenharmony_ci auto textExcludingSpaces = TextRange(0, fTrailingSpaces); 1149cb93a386Sopenharmony_ci InternalLineMetrics metrics(this->strutForceHeight()); 1150cb93a386Sopenharmony_ci metrics.add(&run); 1151cb93a386Sopenharmony_ci auto disableFirstAscent = this->paragraphStyle().getTextHeightBehavior() & 1152cb93a386Sopenharmony_ci TextHeightBehavior::kDisableFirstAscent; 1153cb93a386Sopenharmony_ci auto disableLastDescent = this->paragraphStyle().getTextHeightBehavior() & 1154cb93a386Sopenharmony_ci TextHeightBehavior::kDisableLastDescent; 1155cb93a386Sopenharmony_ci if (disableFirstAscent) { 1156cb93a386Sopenharmony_ci metrics.fAscent = metrics.fRawAscent; 1157cb93a386Sopenharmony_ci } 1158cb93a386Sopenharmony_ci if (disableLastDescent) { 1159cb93a386Sopenharmony_ci metrics.fDescent = metrics.fRawDescent; 1160cb93a386Sopenharmony_ci } 1161cb93a386Sopenharmony_ci if (this->strutEnabled()) { 1162cb93a386Sopenharmony_ci this->strutMetrics().updateLineMetrics(metrics); 1163cb93a386Sopenharmony_ci } 1164cb93a386Sopenharmony_ci ClusterIndex trailingSpaces = fClusters.size(); 1165cb93a386Sopenharmony_ci do { 1166cb93a386Sopenharmony_ci --trailingSpaces; 1167cb93a386Sopenharmony_ci auto& cluster = fClusters[trailingSpaces]; 1168cb93a386Sopenharmony_ci if (!cluster.isWhitespaceBreak()) { 1169cb93a386Sopenharmony_ci ++trailingSpaces; 1170cb93a386Sopenharmony_ci break; 1171cb93a386Sopenharmony_ci } 1172cb93a386Sopenharmony_ci advance.fX -= cluster.width(); 1173cb93a386Sopenharmony_ci } while (trailingSpaces != 0); 1174cb93a386Sopenharmony_ci 1175cb93a386Sopenharmony_ci advance.fY = metrics.height(); 1176cb93a386Sopenharmony_ci auto clusterRange = ClusterRange(0, trailingSpaces); 1177cb93a386Sopenharmony_ci auto clusterRangeWithGhosts = ClusterRange(0, this->clusters().size() - 1); 1178cb93a386Sopenharmony_ci SkScalar offsetX = this->detectIndents(0); 1179cb93a386Sopenharmony_ci auto &line = this->addLine(SkPoint::Make(offsetX, 0), advance, 1180cb93a386Sopenharmony_ci textExcludingSpaces, textRange, textRange, 1181cb93a386Sopenharmony_ci clusterRange, clusterRangeWithGhosts, run.advance().x(), 1182cb93a386Sopenharmony_ci metrics); 1183cb93a386Sopenharmony_ci auto spacing = line.autoSpacing(); 1184cb93a386Sopenharmony_ci auto longestLine = std::max(run.advance().fX, advance.fX) + spacing; 1185cb93a386Sopenharmony_ci setSize(advance.fY, maxWidth, longestLine); 1186cb93a386Sopenharmony_ci setLongestLineWithIndent(longestLine + offsetX); 1187cb93a386Sopenharmony_ci setIntrinsicSize(run.advance().fX, advance.fX, 1188cb93a386Sopenharmony_ci fLines.empty() ? fEmptyMetrics.alphabeticBaseline() : fLines.front().alphabeticBaseline(), 1189cb93a386Sopenharmony_ci fLines.empty() ? fEmptyMetrics.ideographicBaseline() : fLines.front().ideographicBaseline(), 1190cb93a386Sopenharmony_ci false); 1191cb93a386Sopenharmony_ci} 1192cb93a386Sopenharmony_ci 1193cb93a386Sopenharmony_civoid ParagraphImpl::breakShapedTextIntoLines(SkScalar maxWidth) { 1194cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1195cb93a386Sopenharmony_ci TEXT_TRACE_FUNC(); 1196cb93a386Sopenharmony_ci#endif 1197cb93a386Sopenharmony_ci resetAutoSpacing(); 1198cb93a386Sopenharmony_ci TextWrapper textWrapper; 1199cb93a386Sopenharmony_ci textWrapper.breakTextIntoLines( 1200cb93a386Sopenharmony_ci this, 1201cb93a386Sopenharmony_ci maxWidth, 1202cb93a386Sopenharmony_ci [&](TextRange textExcludingSpaces, 1203cb93a386Sopenharmony_ci TextRange text, 1204cb93a386Sopenharmony_ci TextRange textWithNewlines, 1205cb93a386Sopenharmony_ci ClusterRange clusters, 1206cb93a386Sopenharmony_ci ClusterRange clustersWithGhosts, 1207cb93a386Sopenharmony_ci SkScalar widthWithSpaces, 1208cb93a386Sopenharmony_ci size_t startPos, 1209cb93a386Sopenharmony_ci size_t endPos, 1210cb93a386Sopenharmony_ci SkVector offset, 1211cb93a386Sopenharmony_ci SkVector advance, 1212cb93a386Sopenharmony_ci InternalLineMetrics metrics, 1213cb93a386Sopenharmony_ci bool addEllipsis, 1214cb93a386Sopenharmony_ci SkScalar indent, 1215cb93a386Sopenharmony_ci SkScalar noIndentWidth) { 1216cb93a386Sopenharmony_ci // TODO: Take in account clipped edges 1217cb93a386Sopenharmony_ci auto& line = this->addLine(offset, advance, textExcludingSpaces, text, textWithNewlines, clusters, clustersWithGhosts, widthWithSpaces, metrics); 1218cb93a386Sopenharmony_ci if (addEllipsis && this->paragraphStyle().getEllipsisMod() == EllipsisModal::TAIL) { 1219cb93a386Sopenharmony_ci line.createTailEllipsis(noIndentWidth, this->getEllipsis(), true, this->getWordBreakType()); 1220cb93a386Sopenharmony_ci } else if (addEllipsis && this->paragraphStyle().getEllipsisMod() == EllipsisModal::HEAD) { 1221cb93a386Sopenharmony_ci line.createHeadEllipsis(noIndentWidth, this->getEllipsis(), true); 1222cb93a386Sopenharmony_ci } 1223cb93a386Sopenharmony_ci auto spacing = line.autoSpacing(); 1224cb93a386Sopenharmony_ci auto longestLine = std::max(line.width(), line.widthWithEllipsisSpaces()) + spacing; 1225cb93a386Sopenharmony_ci fLongestLine = std::max(fLongestLine, longestLine); 1226cb93a386Sopenharmony_ci fLongestLineWithIndent = std::max(fLongestLineWithIndent, longestLine + indent); 1227cb93a386Sopenharmony_ci }); 1228cb93a386Sopenharmony_ci setSize(textWrapper.height(), maxWidth, fLongestLine); 1229cb93a386Sopenharmony_ci setIntrinsicSize(textWrapper.maxIntrinsicWidth(), textWrapper.minIntrinsicWidth(), 1230cb93a386Sopenharmony_ci fLines.empty() ? fEmptyMetrics.alphabeticBaseline() : fLines.front().alphabeticBaseline(), 1231cb93a386Sopenharmony_ci fLines.empty() ? fEmptyMetrics.ideographicBaseline() : fLines.front().ideographicBaseline(), 1232cb93a386Sopenharmony_ci textWrapper.exceededMaxLines()); 1233cb93a386Sopenharmony_ci} 1234cb93a386Sopenharmony_ci#else 1235cb93a386Sopenharmony_civoid ParagraphImpl::breakShapedTextIntoLines(SkScalar maxWidth) { 1236cb93a386Sopenharmony_ci 1237cb93a386Sopenharmony_ci if (!fHasLineBreaks && 1238cb93a386Sopenharmony_ci !fHasWhitespacesInside && 1239cb93a386Sopenharmony_ci fPlaceholders.size() == 1 && 1240cb93a386Sopenharmony_ci fRuns.size() == 1 && fRuns[0].fAdvance.fX <= maxWidth) { 1241cb93a386Sopenharmony_ci // This is a short version of a line breaking when we know that: 1242cb93a386Sopenharmony_ci // 1. We have only one line of text 1243cb93a386Sopenharmony_ci // 2. It's shaped into a single run 1244cb93a386Sopenharmony_ci // 3. There are no placeholders 1245cb93a386Sopenharmony_ci // 4. There are no linebreaks (which will format text into multiple lines) 1246cb93a386Sopenharmony_ci // 5. There are no whitespaces so the minIntrinsicWidth=maxIntrinsicWidth 1247cb93a386Sopenharmony_ci // (To think about that, the last condition is not quite right; 1248cb93a386Sopenharmony_ci // we should calculate minIntrinsicWidth by soft line breaks. 1249cb93a386Sopenharmony_ci // However, it's how it's done in Flutter now) 1250cb93a386Sopenharmony_ci auto& run = this->fRuns[0]; 1251cb93a386Sopenharmony_ci auto advance = run.advance(); 1252cb93a386Sopenharmony_ci auto textRange = TextRange(0, this->text().size()); 1253cb93a386Sopenharmony_ci auto textExcludingSpaces = TextRange(0, fTrailingSpaces); 1254cb93a386Sopenharmony_ci InternalLineMetrics metrics(this->strutForceHeight()); 1255cb93a386Sopenharmony_ci metrics.add(&run); 1256cb93a386Sopenharmony_ci auto disableFirstAscent = this->paragraphStyle().getTextHeightBehavior() & 1257cb93a386Sopenharmony_ci TextHeightBehavior::kDisableFirstAscent; 1258cb93a386Sopenharmony_ci auto disableLastDescent = this->paragraphStyle().getTextHeightBehavior() & 1259cb93a386Sopenharmony_ci TextHeightBehavior::kDisableLastDescent; 1260cb93a386Sopenharmony_ci if (disableFirstAscent) { 1261cb93a386Sopenharmony_ci metrics.fAscent = metrics.fRawAscent; 1262cb93a386Sopenharmony_ci } 1263cb93a386Sopenharmony_ci if (disableLastDescent) { 1264cb93a386Sopenharmony_ci metrics.fDescent = metrics.fRawDescent; 1265cb93a386Sopenharmony_ci } 1266cb93a386Sopenharmony_ci if (this->strutEnabled()) { 1267cb93a386Sopenharmony_ci this->strutMetrics().updateLineMetrics(metrics); 1268cb93a386Sopenharmony_ci } 1269cb93a386Sopenharmony_ci ClusterIndex trailingSpaces = fClusters.size(); 1270cb93a386Sopenharmony_ci do { 1271cb93a386Sopenharmony_ci --trailingSpaces; 1272cb93a386Sopenharmony_ci auto& cluster = fClusters[trailingSpaces]; 1273cb93a386Sopenharmony_ci if (!cluster.isWhitespaceBreak()) { 1274cb93a386Sopenharmony_ci ++trailingSpaces; 1275cb93a386Sopenharmony_ci break; 1276cb93a386Sopenharmony_ci } 1277cb93a386Sopenharmony_ci advance.fX -= cluster.width(); 1278cb93a386Sopenharmony_ci } while (trailingSpaces != 0); 1279cb93a386Sopenharmony_ci 1280cb93a386Sopenharmony_ci advance.fY = metrics.height(); 1281cb93a386Sopenharmony_ci auto clusterRange = ClusterRange(0, trailingSpaces); 1282cb93a386Sopenharmony_ci auto clusterRangeWithGhosts = ClusterRange(0, this->clusters().size() - 1); 1283cb93a386Sopenharmony_ci this->addLine(SkPoint::Make(0, 0), advance, 1284cb93a386Sopenharmony_ci textExcludingSpaces, textRange, textRange, 1285cb93a386Sopenharmony_ci clusterRange, clusterRangeWithGhosts, run.advance().x(), 1286cb93a386Sopenharmony_ci metrics); 1287cb93a386Sopenharmony_ci 1288cb93a386Sopenharmony_ci fLongestLine = nearlyZero(advance.fX) ? run.advance().fX : advance.fX; 1289cb93a386Sopenharmony_ci fHeight = advance.fY; 1290cb93a386Sopenharmony_ci fWidth = maxWidth; 1291cb93a386Sopenharmony_ci fMaxIntrinsicWidth = run.advance().fX; 1292cb93a386Sopenharmony_ci fMinIntrinsicWidth = advance.fX; 1293cb93a386Sopenharmony_ci fAlphabeticBaseline = fLines.empty() ? fEmptyMetrics.alphabeticBaseline() : fLines.front().alphabeticBaseline(); 1294cb93a386Sopenharmony_ci fIdeographicBaseline = fLines.empty() ? fEmptyMetrics.ideographicBaseline() : fLines.front().ideographicBaseline(); 1295cb93a386Sopenharmony_ci fExceededMaxLines = false; 1296cb93a386Sopenharmony_ci return; 1297cb93a386Sopenharmony_ci } 1298cb93a386Sopenharmony_ci 1299cb93a386Sopenharmony_ci TextWrapper textWrapper; 1300cb93a386Sopenharmony_ci textWrapper.breakTextIntoLines( 1301cb93a386Sopenharmony_ci this, 1302cb93a386Sopenharmony_ci maxWidth, 1303cb93a386Sopenharmony_ci [&](TextRange textExcludingSpaces, 1304cb93a386Sopenharmony_ci TextRange text, 1305cb93a386Sopenharmony_ci TextRange textWithNewlines, 1306cb93a386Sopenharmony_ci ClusterRange clusters, 1307cb93a386Sopenharmony_ci ClusterRange clustersWithGhosts, 1308cb93a386Sopenharmony_ci SkScalar widthWithSpaces, 1309cb93a386Sopenharmony_ci size_t startPos, 1310cb93a386Sopenharmony_ci size_t endPos, 1311cb93a386Sopenharmony_ci SkVector offset, 1312cb93a386Sopenharmony_ci SkVector advance, 1313cb93a386Sopenharmony_ci InternalLineMetrics metrics, 1314cb93a386Sopenharmony_ci bool addEllipsis) { 1315cb93a386Sopenharmony_ci // TODO: Take in account clipped edges 1316cb93a386Sopenharmony_ci auto& line = this->addLine(offset, advance, textExcludingSpaces, text, textWithNewlines, clusters, clustersWithGhosts, widthWithSpaces, metrics); 1317cb93a386Sopenharmony_ci if (addEllipsis) { 1318cb93a386Sopenharmony_ci line.createEllipsis(maxWidth, this->getEllipsis(), true); 1319cb93a386Sopenharmony_ci } 1320cb93a386Sopenharmony_ci fLongestLine = std::max(fLongestLine, nearlyZero(advance.fX) ? widthWithSpaces : advance.fX); 1321cb93a386Sopenharmony_ci }); 1322cb93a386Sopenharmony_ci 1323cb93a386Sopenharmony_ci fHeight = textWrapper.height(); 1324cb93a386Sopenharmony_ci fWidth = maxWidth; 1325cb93a386Sopenharmony_ci fMaxIntrinsicWidth = textWrapper.maxIntrinsicWidth(); 1326cb93a386Sopenharmony_ci fMinIntrinsicWidth = textWrapper.minIntrinsicWidth(); 1327cb93a386Sopenharmony_ci fAlphabeticBaseline = fLines.empty() ? fEmptyMetrics.alphabeticBaseline() : fLines.front().alphabeticBaseline(); 1328cb93a386Sopenharmony_ci fIdeographicBaseline = fLines.empty() ? fEmptyMetrics.ideographicBaseline() : fLines.front().ideographicBaseline(); 1329cb93a386Sopenharmony_ci fExceededMaxLines = textWrapper.exceededMaxLines(); 1330cb93a386Sopenharmony_ci} 1331cb93a386Sopenharmony_ci#endif 1332cb93a386Sopenharmony_ci 1333cb93a386Sopenharmony_civoid ParagraphImpl::formatLines(SkScalar maxWidth) { 1334cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1335cb93a386Sopenharmony_ci TEXT_TRACE_FUNC(); 1336cb93a386Sopenharmony_ci#endif 1337cb93a386Sopenharmony_ci auto effectiveAlign = fParagraphStyle.effective_align(); 1338cb93a386Sopenharmony_ci const bool isLeftAligned = effectiveAlign == TextAlign::kLeft 1339cb93a386Sopenharmony_ci || (effectiveAlign == TextAlign::kJustify && fParagraphStyle.getTextDirection() == TextDirection::kLtr); 1340cb93a386Sopenharmony_ci 1341cb93a386Sopenharmony_ci if (!SkScalarIsFinite(maxWidth) && !isLeftAligned) { 1342cb93a386Sopenharmony_ci // Special case: clean all text in case of maxWidth == INF & align != left 1343cb93a386Sopenharmony_ci // We had to go through shaping though because we need all the measurement numbers 1344cb93a386Sopenharmony_ci fLines.reset(); 1345cb93a386Sopenharmony_ci return; 1346cb93a386Sopenharmony_ci } 1347cb93a386Sopenharmony_ci 1348cb93a386Sopenharmony_ci size_t iLineNumber = 0; 1349cb93a386Sopenharmony_ci for (auto& line : fLines) { 1350cb93a386Sopenharmony_ci SkScalar noIndentWidth = maxWidth - detectIndents(iLineNumber++); 1351cb93a386Sopenharmony_ci if (fParagraphStyle.getTextDirection() == TextDirection::kRtl) { 1352cb93a386Sopenharmony_ci line.setLineOffsetX(0); 1353cb93a386Sopenharmony_ci } 1354cb93a386Sopenharmony_ci line.format(effectiveAlign, noIndentWidth, this->paragraphStyle().getEllipsisMod()); 1355cb93a386Sopenharmony_ci } 1356cb93a386Sopenharmony_ci} 1357cb93a386Sopenharmony_ci 1358cb93a386Sopenharmony_civoid ParagraphImpl::resolveStrut() { 1359cb93a386Sopenharmony_ci auto strutStyle = this->paragraphStyle().getStrutStyle(); 1360cb93a386Sopenharmony_ci if (!strutStyle.getStrutEnabled() || strutStyle.getFontSize() < 0) { 1361cb93a386Sopenharmony_ci return; 1362cb93a386Sopenharmony_ci } 1363cb93a386Sopenharmony_ci 1364cb93a386Sopenharmony_ci auto typefaces = fFontCollection->findTypefaces(strutStyle.getFontFamilies(), strutStyle.getFontStyle(), std::nullopt); 1365cb93a386Sopenharmony_ci if (typefaces.empty()) { 1366cb93a386Sopenharmony_ci SkDEBUGF("Could not resolve strut font\n"); 1367cb93a386Sopenharmony_ci return; 1368cb93a386Sopenharmony_ci } 1369cb93a386Sopenharmony_ci 1370cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 1371cb93a386Sopenharmony_ci SkFont font(typefaces.front(), strutStyle.getFontSize()); 1372cb93a386Sopenharmony_ci SkFontMetrics metrics; 1373cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1374cb93a386Sopenharmony_ci SkFont compressFont = font; 1375cb93a386Sopenharmony_ci scaleFontWithCompressionConfig(compressFont, ScaleOP::COMPRESS); 1376cb93a386Sopenharmony_ci compressFont.getMetrics(&metrics); 1377cb93a386Sopenharmony_ci metricsIncludeFontPadding(&metrics, font); 1378cb93a386Sopenharmony_ci#else 1379cb93a386Sopenharmony_ci font.getMetrics(&metrics); 1380cb93a386Sopenharmony_ci#endif 1381cb93a386Sopenharmony_ci#else 1382cb93a386Sopenharmony_ci RSFont font(typefaces.front(), strutStyle.getFontSize(), 1, 0); 1383cb93a386Sopenharmony_ci RSFontMetrics metrics; 1384cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1385cb93a386Sopenharmony_ci RSFont compressFont = font; 1386cb93a386Sopenharmony_ci scaleFontWithCompressionConfig(compressFont, ScaleOP::COMPRESS); 1387cb93a386Sopenharmony_ci compressFont.GetMetrics(&metrics); 1388cb93a386Sopenharmony_ci metricsIncludeFontPadding(&metrics, font); 1389cb93a386Sopenharmony_ci#else 1390cb93a386Sopenharmony_ci font.GetMetrics(&metrics); 1391cb93a386Sopenharmony_ci#endif 1392cb93a386Sopenharmony_ci#endif 1393cb93a386Sopenharmony_ci 1394cb93a386Sopenharmony_ci if (strutStyle.getHeightOverride()) { 1395cb93a386Sopenharmony_ci auto strutHeight = metrics.fDescent - metrics.fAscent; 1396cb93a386Sopenharmony_ci auto strutMultiplier = strutStyle.getHeight() * strutStyle.getFontSize(); 1397cb93a386Sopenharmony_ci fStrutMetrics = InternalLineMetrics( 1398cb93a386Sopenharmony_ci (metrics.fAscent / strutHeight) * strutMultiplier, 1399cb93a386Sopenharmony_ci (metrics.fDescent / strutHeight) * strutMultiplier, 1400cb93a386Sopenharmony_ci strutStyle.getLeading() < 0 ? 0 : strutStyle.getLeading() * strutStyle.getFontSize(), 1401cb93a386Sopenharmony_ci metrics.fAscent, metrics.fDescent, metrics.fLeading); 1402cb93a386Sopenharmony_ci } else { 1403cb93a386Sopenharmony_ci fStrutMetrics = InternalLineMetrics( 1404cb93a386Sopenharmony_ci metrics.fAscent, 1405cb93a386Sopenharmony_ci metrics.fDescent, 1406cb93a386Sopenharmony_ci strutStyle.getLeading() < 0 ? 0 : strutStyle.getLeading() * strutStyle.getFontSize()); 1407cb93a386Sopenharmony_ci } 1408cb93a386Sopenharmony_ci fStrutMetrics.setForceStrut(this->paragraphStyle().getStrutStyle().getForceStrutHeight()); 1409cb93a386Sopenharmony_ci} 1410cb93a386Sopenharmony_ci 1411cb93a386Sopenharmony_ciBlockRange ParagraphImpl::findAllBlocks(TextRange textRange) { 1412cb93a386Sopenharmony_ci BlockIndex begin = EMPTY_BLOCK; 1413cb93a386Sopenharmony_ci BlockIndex end = EMPTY_BLOCK; 1414cb93a386Sopenharmony_ci for (int index = 0; index < fTextStyles.size(); ++index) { 1415cb93a386Sopenharmony_ci auto& block = fTextStyles[index]; 1416cb93a386Sopenharmony_ci if (block.fRange.end <= textRange.start) { 1417cb93a386Sopenharmony_ci continue; 1418cb93a386Sopenharmony_ci } 1419cb93a386Sopenharmony_ci if (block.fRange.start >= textRange.end) { 1420cb93a386Sopenharmony_ci break; 1421cb93a386Sopenharmony_ci } 1422cb93a386Sopenharmony_ci if (begin == EMPTY_BLOCK) { 1423cb93a386Sopenharmony_ci begin = index; 1424cb93a386Sopenharmony_ci } 1425cb93a386Sopenharmony_ci end = index; 1426cb93a386Sopenharmony_ci } 1427cb93a386Sopenharmony_ci 1428cb93a386Sopenharmony_ci if (begin == EMPTY_INDEX || end == EMPTY_INDEX) { 1429cb93a386Sopenharmony_ci // It's possible if some text is not covered with any text style 1430cb93a386Sopenharmony_ci // Not in Flutter but in direct use of SkParagraph 1431cb93a386Sopenharmony_ci return EMPTY_RANGE; 1432cb93a386Sopenharmony_ci } 1433cb93a386Sopenharmony_ci 1434cb93a386Sopenharmony_ci return { begin, end + 1 }; 1435cb93a386Sopenharmony_ci} 1436cb93a386Sopenharmony_ci 1437cb93a386Sopenharmony_ciTextLine& ParagraphImpl::addLine(SkVector offset, 1438cb93a386Sopenharmony_ci SkVector advance, 1439cb93a386Sopenharmony_ci TextRange textExcludingSpaces, 1440cb93a386Sopenharmony_ci TextRange text, 1441cb93a386Sopenharmony_ci TextRange textIncludingNewLines, 1442cb93a386Sopenharmony_ci ClusterRange clusters, 1443cb93a386Sopenharmony_ci ClusterRange clustersWithGhosts, 1444cb93a386Sopenharmony_ci SkScalar widthWithSpaces, 1445cb93a386Sopenharmony_ci InternalLineMetrics sizes) { 1446cb93a386Sopenharmony_ci // Define a list of styles that covers the line 1447cb93a386Sopenharmony_ci auto blocks = findAllBlocks(textIncludingNewLines); 1448cb93a386Sopenharmony_ci return fLines.emplace_back(this, offset, advance, blocks, 1449cb93a386Sopenharmony_ci textExcludingSpaces, text, textIncludingNewLines, 1450cb93a386Sopenharmony_ci clusters, clustersWithGhosts, widthWithSpaces, sizes); 1451cb93a386Sopenharmony_ci} 1452cb93a386Sopenharmony_ci 1453cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1454cb93a386Sopenharmony_ciTextBox ParagraphImpl::getEmptyTextRect(RectHeightStyle rectHeightStyle) const 1455cb93a386Sopenharmony_ci{ 1456cb93a386Sopenharmony_ci // get textStyle to calculate text box when text is empty(reference to ParagraphImpl::computeEmptyMetrics()) 1457cb93a386Sopenharmony_ci bool emptyParagraph = fRuns.empty(); 1458cb93a386Sopenharmony_ci TextStyle textStyle = paragraphStyle().getTextStyle(); 1459cb93a386Sopenharmony_ci if (emptyParagraph && !fTextStyles.empty()) { 1460cb93a386Sopenharmony_ci textStyle = fTextStyles.back().fStyle; 1461cb93a386Sopenharmony_ci } 1462cb93a386Sopenharmony_ci 1463cb93a386Sopenharmony_ci // calculate text box(reference to TextLine::getRectsForRange(), switch(rectHeightStyle)) 1464cb93a386Sopenharmony_ci TextBox box(SkRect::MakeXYWH(0, 0, 0, fHeight), fParagraphStyle.getTextDirection()); 1465cb93a386Sopenharmony_ci auto verticalShift = fEmptyMetrics.rawAscent() - fEmptyMetrics.ascent(); 1466cb93a386Sopenharmony_ci switch (rectHeightStyle) { 1467cb93a386Sopenharmony_ci case RectHeightStyle::kTight: 1468cb93a386Sopenharmony_ci if (textStyle.getHeightOverride() && textStyle.getHeight() > 0) { 1469cb93a386Sopenharmony_ci const auto effectiveBaseline = fEmptyMetrics.baseline() + fEmptyMetrics.delta(); 1470cb93a386Sopenharmony_ci box.rect.fTop = effectiveBaseline + fEmptyMetrics.rawAscent(); 1471cb93a386Sopenharmony_ci box.rect.fBottom = effectiveBaseline + fEmptyMetrics.rawDescent(); 1472cb93a386Sopenharmony_ci } 1473cb93a386Sopenharmony_ci return box; 1474cb93a386Sopenharmony_ci case RectHeightStyle::kMax: 1475cb93a386Sopenharmony_ci box.rect.fBottom = fHeight; 1476cb93a386Sopenharmony_ci box.rect.fTop = fEmptyMetrics.delta(); 1477cb93a386Sopenharmony_ci return box; 1478cb93a386Sopenharmony_ci case RectHeightStyle::kIncludeLineSpacingMiddle: 1479cb93a386Sopenharmony_ci case RectHeightStyle::kIncludeLineSpacingTop: 1480cb93a386Sopenharmony_ci case RectHeightStyle::kIncludeLineSpacingBottom: 1481cb93a386Sopenharmony_ci box.rect.fBottom = fHeight; 1482cb93a386Sopenharmony_ci box.rect.fTop = fEmptyMetrics.delta() + verticalShift; 1483cb93a386Sopenharmony_ci return box; 1484cb93a386Sopenharmony_ci case RectHeightStyle::kStrut: 1485cb93a386Sopenharmony_ci if (fParagraphStyle.getStrutStyle().getStrutEnabled() && 1486cb93a386Sopenharmony_ci fParagraphStyle.getStrutStyle().getFontSize() > 0) { 1487cb93a386Sopenharmony_ci auto baseline = fEmptyMetrics.baseline(); 1488cb93a386Sopenharmony_ci box.rect.fTop = baseline + fStrutMetrics.ascent(); 1489cb93a386Sopenharmony_ci box.rect.fBottom = baseline + fStrutMetrics.descent(); 1490cb93a386Sopenharmony_ci } 1491cb93a386Sopenharmony_ci return box; 1492cb93a386Sopenharmony_ci default: 1493cb93a386Sopenharmony_ci return box; 1494cb93a386Sopenharmony_ci } 1495cb93a386Sopenharmony_ci} 1496cb93a386Sopenharmony_ci#endif 1497cb93a386Sopenharmony_ci 1498cb93a386Sopenharmony_ci// Returns a vector of bounding boxes that enclose all text between 1499cb93a386Sopenharmony_ci// start and end glyph indexes, including start and excluding end 1500cb93a386Sopenharmony_cistd::vector<TextBox> ParagraphImpl::getRectsForRange(unsigned start, 1501cb93a386Sopenharmony_ci unsigned end, 1502cb93a386Sopenharmony_ci RectHeightStyle rectHeightStyle, 1503cb93a386Sopenharmony_ci RectWidthStyle rectWidthStyle) { 1504cb93a386Sopenharmony_ci std::vector<TextBox> results; 1505cb93a386Sopenharmony_ci // this method should not be called before kshaped 1506cb93a386Sopenharmony_ci if (fText.isEmpty() || fState < kShaped) { 1507cb93a386Sopenharmony_ci if (start == 0 && end > 0) { 1508cb93a386Sopenharmony_ci // On account of implied "\n" that is always at the end of the text 1509cb93a386Sopenharmony_ci //SkDebugf("getRectsForRange(%d, %d): %f\n", start, end, fHeight); 1510cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1511cb93a386Sopenharmony_ci results.emplace_back(getEmptyTextRect(rectHeightStyle)); 1512cb93a386Sopenharmony_ci#else 1513cb93a386Sopenharmony_ci results.emplace_back(SkRect::MakeXYWH(0, 0, 0, fHeight), fParagraphStyle.getTextDirection()); 1514cb93a386Sopenharmony_ci#endif 1515cb93a386Sopenharmony_ci } 1516cb93a386Sopenharmony_ci return results; 1517cb93a386Sopenharmony_ci } 1518cb93a386Sopenharmony_ci 1519cb93a386Sopenharmony_ci this->ensureUTF16Mapping(); 1520cb93a386Sopenharmony_ci 1521cb93a386Sopenharmony_ci if (start >= end || start > SkToSizeT(fUTF8IndexForUTF16Index.size()) || end == 0) { 1522cb93a386Sopenharmony_ci return results; 1523cb93a386Sopenharmony_ci } 1524cb93a386Sopenharmony_ci 1525cb93a386Sopenharmony_ci // Adjust the text to grapheme edges 1526cb93a386Sopenharmony_ci // Apparently, text editor CAN move inside graphemes but CANNOT select a part of it. 1527cb93a386Sopenharmony_ci // I don't know why - the solution I have here returns an empty box for every query that 1528cb93a386Sopenharmony_ci // does not contain an end of a grapheme. 1529cb93a386Sopenharmony_ci // Once a cursor is inside a complex grapheme I can press backspace and cause trouble. 1530cb93a386Sopenharmony_ci // To avoid any problems, I will not allow any selection of a part of a grapheme. 1531cb93a386Sopenharmony_ci // One flutter test fails because of it but the editing experience is correct 1532cb93a386Sopenharmony_ci // (although you have to press the cursor many times before it moves to the next grapheme). 1533cb93a386Sopenharmony_ci TextRange text(fText.size(), fText.size()); 1534cb93a386Sopenharmony_ci // TODO: This is probably a temp change that makes SkParagraph work as TxtLib 1535cb93a386Sopenharmony_ci // (so we can compare the results). We now include in the selection box only the graphemes 1536cb93a386Sopenharmony_ci // that belongs to the given [start:end) range entirely (not the ones that intersect with it) 1537cb93a386Sopenharmony_ci if (start < SkToSizeT(fUTF8IndexForUTF16Index.size())) { 1538cb93a386Sopenharmony_ci auto utf8 = fUTF8IndexForUTF16Index[start]; 1539cb93a386Sopenharmony_ci // If start points to a trailing surrogate, skip it 1540cb93a386Sopenharmony_ci if (start > 0 && fUTF8IndexForUTF16Index[start - 1] == utf8) { 1541cb93a386Sopenharmony_ci utf8 = fUTF8IndexForUTF16Index[start + 1]; 1542cb93a386Sopenharmony_ci } 1543cb93a386Sopenharmony_ci text.start = this->findNextGraphemeBoundary(utf8); 1544cb93a386Sopenharmony_ci } 1545cb93a386Sopenharmony_ci if (end < SkToSizeT(fUTF8IndexForUTF16Index.size())) { 1546cb93a386Sopenharmony_ci auto utf8 = this->findPreviousGraphemeBoundary(fUTF8IndexForUTF16Index[end]); 1547cb93a386Sopenharmony_ci text.end = utf8; 1548cb93a386Sopenharmony_ci } 1549cb93a386Sopenharmony_ci //SkDebugf("getRectsForRange(%d,%d) -> (%d:%d)\n", start, end, text.start, text.end); 1550cb93a386Sopenharmony_ci for (auto& line : fLines) { 1551cb93a386Sopenharmony_ci auto lineText = line.textWithNewlines(); 1552cb93a386Sopenharmony_ci lineText = textRangeMergeBtoA(lineText, line.getTextRangeReplacedByEllipsis()); 1553cb93a386Sopenharmony_ci auto intersect = lineText * text; 1554cb93a386Sopenharmony_ci if (intersect.empty() && lineText.start != text.start) { 1555cb93a386Sopenharmony_ci continue; 1556cb93a386Sopenharmony_ci } 1557cb93a386Sopenharmony_ci 1558cb93a386Sopenharmony_ci line.getRectsForRange(intersect, rectHeightStyle, rectWidthStyle, results); 1559cb93a386Sopenharmony_ci } 1560cb93a386Sopenharmony_ci/* 1561cb93a386Sopenharmony_ci SkDebugf("getRectsForRange(%d, %d)\n", start, end); 1562cb93a386Sopenharmony_ci for (auto& r : results) { 1563cb93a386Sopenharmony_ci r.rect.fLeft = littleRound(r.rect.fLeft); 1564cb93a386Sopenharmony_ci r.rect.fRight = littleRound(r.rect.fRight); 1565cb93a386Sopenharmony_ci r.rect.fTop = littleRound(r.rect.fTop); 1566cb93a386Sopenharmony_ci r.rect.fBottom = littleRound(r.rect.fBottom); 1567cb93a386Sopenharmony_ci SkDebugf("[%f:%f * %f:%f]\n", r.rect.fLeft, r.rect.fRight, r.rect.fTop, r.rect.fBottom); 1568cb93a386Sopenharmony_ci } 1569cb93a386Sopenharmony_ci*/ 1570cb93a386Sopenharmony_ci return results; 1571cb93a386Sopenharmony_ci} 1572cb93a386Sopenharmony_ci 1573cb93a386Sopenharmony_cistd::vector<TextBox> ParagraphImpl::getRectsForPlaceholders() { 1574cb93a386Sopenharmony_ci std::vector<TextBox> boxes; 1575cb93a386Sopenharmony_ci // this method should not be called before kshaped 1576cb93a386Sopenharmony_ci if (fText.isEmpty() || fState < kShaped) { 1577cb93a386Sopenharmony_ci return boxes; 1578cb93a386Sopenharmony_ci } 1579cb93a386Sopenharmony_ci if (fPlaceholders.size() == 1) { 1580cb93a386Sopenharmony_ci // We always have one fake placeholder 1581cb93a386Sopenharmony_ci return boxes; 1582cb93a386Sopenharmony_ci } 1583cb93a386Sopenharmony_ci for (auto& line : fLines) { 1584cb93a386Sopenharmony_ci line.getRectsForPlaceholders(boxes); 1585cb93a386Sopenharmony_ci } 1586cb93a386Sopenharmony_ci /* 1587cb93a386Sopenharmony_ci SkDebugf("getRectsForPlaceholders('%s'): %d\n", fText.c_str(), boxes.size()); 1588cb93a386Sopenharmony_ci for (auto& r : boxes) { 1589cb93a386Sopenharmony_ci r.rect.fLeft = littleRound(r.rect.fLeft); 1590cb93a386Sopenharmony_ci r.rect.fRight = littleRound(r.rect.fRight); 1591cb93a386Sopenharmony_ci r.rect.fTop = littleRound(r.rect.fTop); 1592cb93a386Sopenharmony_ci r.rect.fBottom = littleRound(r.rect.fBottom); 1593cb93a386Sopenharmony_ci SkDebugf("[%f:%f * %f:%f] %s\n", r.rect.fLeft, r.rect.fRight, r.rect.fTop, r.rect.fBottom, 1594cb93a386Sopenharmony_ci (r.direction == TextDirection::kLtr ? "left" : "right")); 1595cb93a386Sopenharmony_ci } 1596cb93a386Sopenharmony_ci */ 1597cb93a386Sopenharmony_ci return boxes; 1598cb93a386Sopenharmony_ci} 1599cb93a386Sopenharmony_ci 1600cb93a386Sopenharmony_ci// TODO: Optimize (save cluster <-> codepoint connection) 1601cb93a386Sopenharmony_ciPositionWithAffinity ParagraphImpl::getGlyphPositionAtCoordinate(SkScalar dx, SkScalar dy) { 1602cb93a386Sopenharmony_ci 1603cb93a386Sopenharmony_ci if (fText.isEmpty()) { 1604cb93a386Sopenharmony_ci return {0, Affinity::kDownstream}; 1605cb93a386Sopenharmony_ci } 1606cb93a386Sopenharmony_ci 1607cb93a386Sopenharmony_ci this->ensureUTF16Mapping(); 1608cb93a386Sopenharmony_ci 1609cb93a386Sopenharmony_ci for (auto& line : fLines) { 1610cb93a386Sopenharmony_ci // Let's figure out if we can stop looking 1611cb93a386Sopenharmony_ci auto offsetY = line.offset().fY; 1612cb93a386Sopenharmony_ci if (dy >= offsetY + line.height() && &line != &fLines.back()) { 1613cb93a386Sopenharmony_ci // This line is not good enough 1614cb93a386Sopenharmony_ci continue; 1615cb93a386Sopenharmony_ci } 1616cb93a386Sopenharmony_ci 1617cb93a386Sopenharmony_ci // This is so far the the line vertically closest to our coordinates 1618cb93a386Sopenharmony_ci // (or the first one, or the only one - all the same) 1619cb93a386Sopenharmony_ci 1620cb93a386Sopenharmony_ci auto result = line.getGlyphPositionAtCoordinate(dx); 1621cb93a386Sopenharmony_ci //SkDebugf("getGlyphPositionAtCoordinate(%f, %f): %d %s\n", dx, dy, result.position, 1622cb93a386Sopenharmony_ci // result.affinity == Affinity::kUpstream ? "up" : "down"); 1623cb93a386Sopenharmony_ci return result; 1624cb93a386Sopenharmony_ci } 1625cb93a386Sopenharmony_ci 1626cb93a386Sopenharmony_ci return {0, Affinity::kDownstream}; 1627cb93a386Sopenharmony_ci} 1628cb93a386Sopenharmony_ci 1629cb93a386Sopenharmony_ci// Finds the first and last glyphs that define a word containing 1630cb93a386Sopenharmony_ci// the glyph at index offset. 1631cb93a386Sopenharmony_ci// By "glyph" they mean a character index - indicated by Minikin's code 1632cb93a386Sopenharmony_ciSkRange<size_t> ParagraphImpl::getWordBoundary(unsigned offset) { 1633cb93a386Sopenharmony_ci 1634cb93a386Sopenharmony_ci if (fWords.empty()) { 1635cb93a386Sopenharmony_ci if (!fUnicode->getWords(fText.c_str(), fText.size(), nullptr, &fWords)) { 1636cb93a386Sopenharmony_ci return {0, 0 }; 1637cb93a386Sopenharmony_ci } 1638cb93a386Sopenharmony_ci } 1639cb93a386Sopenharmony_ci 1640cb93a386Sopenharmony_ci int32_t start = 0; 1641cb93a386Sopenharmony_ci int32_t end = 0; 1642cb93a386Sopenharmony_ci for (size_t i = 0; i < fWords.size(); ++i) { 1643cb93a386Sopenharmony_ci auto word = fWords[i]; 1644cb93a386Sopenharmony_ci if (word <= offset) { 1645cb93a386Sopenharmony_ci start = word; 1646cb93a386Sopenharmony_ci end = word; 1647cb93a386Sopenharmony_ci } else if (word > offset) { 1648cb93a386Sopenharmony_ci end = word; 1649cb93a386Sopenharmony_ci break; 1650cb93a386Sopenharmony_ci } 1651cb93a386Sopenharmony_ci } 1652cb93a386Sopenharmony_ci 1653cb93a386Sopenharmony_ci //SkDebugf("getWordBoundary(%d): %d - %d\n", offset, start, end); 1654cb93a386Sopenharmony_ci return { SkToU32(start), SkToU32(end) }; 1655cb93a386Sopenharmony_ci} 1656cb93a386Sopenharmony_ci 1657cb93a386Sopenharmony_civoid ParagraphImpl::getLineMetrics(std::vector<LineMetrics>& metrics) { 1658cb93a386Sopenharmony_ci metrics.clear(); 1659cb93a386Sopenharmony_ci for (auto& line : fLines) { 1660cb93a386Sopenharmony_ci metrics.emplace_back(line.getMetrics()); 1661cb93a386Sopenharmony_ci } 1662cb93a386Sopenharmony_ci} 1663cb93a386Sopenharmony_ci 1664cb93a386Sopenharmony_ciSkSpan<const char> ParagraphImpl::text(TextRange textRange) { 1665cb93a386Sopenharmony_ci SkASSERT(textRange.start <= fText.size() && textRange.end <= fText.size()); 1666cb93a386Sopenharmony_ci auto start = fText.c_str() + textRange.start; 1667cb93a386Sopenharmony_ci return SkSpan<const char>(start, textRange.width()); 1668cb93a386Sopenharmony_ci} 1669cb93a386Sopenharmony_ci 1670cb93a386Sopenharmony_ciSkSpan<Cluster> ParagraphImpl::clusters(ClusterRange clusterRange) { 1671cb93a386Sopenharmony_ci SkASSERT(clusterRange.start < SkToSizeT(fClusters.size()) && 1672cb93a386Sopenharmony_ci clusterRange.end <= SkToSizeT(fClusters.size())); 1673cb93a386Sopenharmony_ci return SkSpan<Cluster>(&fClusters[clusterRange.start], clusterRange.width()); 1674cb93a386Sopenharmony_ci} 1675cb93a386Sopenharmony_ci 1676cb93a386Sopenharmony_ciCluster& ParagraphImpl::cluster(ClusterIndex clusterIndex) { 1677cb93a386Sopenharmony_ci SkASSERT(clusterIndex < SkToSizeT(fClusters.size())); 1678cb93a386Sopenharmony_ci return fClusters[clusterIndex]; 1679cb93a386Sopenharmony_ci} 1680cb93a386Sopenharmony_ci 1681cb93a386Sopenharmony_ciRun& ParagraphImpl::runByCluster(ClusterIndex clusterIndex) { 1682cb93a386Sopenharmony_ci auto start = cluster(clusterIndex); 1683cb93a386Sopenharmony_ci return this->run(start.fRunIndex); 1684cb93a386Sopenharmony_ci} 1685cb93a386Sopenharmony_ci 1686cb93a386Sopenharmony_ciSkSpan<Block> ParagraphImpl::blocks(BlockRange blockRange) { 1687cb93a386Sopenharmony_ci SkASSERT(blockRange.start < SkToSizeT(fTextStyles.size()) && 1688cb93a386Sopenharmony_ci blockRange.end <= SkToSizeT(fTextStyles.size())); 1689cb93a386Sopenharmony_ci return SkSpan<Block>(&fTextStyles[blockRange.start], blockRange.width()); 1690cb93a386Sopenharmony_ci} 1691cb93a386Sopenharmony_ci 1692cb93a386Sopenharmony_ciBlock& ParagraphImpl::block(BlockIndex blockIndex) { 1693cb93a386Sopenharmony_ci SkASSERT(blockIndex < SkToSizeT(fTextStyles.size())); 1694cb93a386Sopenharmony_ci return fTextStyles[blockIndex]; 1695cb93a386Sopenharmony_ci} 1696cb93a386Sopenharmony_ci 1697cb93a386Sopenharmony_civoid ParagraphImpl::setState(InternalState state) { 1698cb93a386Sopenharmony_ci if (fState <= state) { 1699cb93a386Sopenharmony_ci fState = state; 1700cb93a386Sopenharmony_ci return; 1701cb93a386Sopenharmony_ci } 1702cb93a386Sopenharmony_ci 1703cb93a386Sopenharmony_ci fState = state; 1704cb93a386Sopenharmony_ci switch (fState) { 1705cb93a386Sopenharmony_ci case kUnknown: 1706cb93a386Sopenharmony_ci SkASSERT(false); 1707cb93a386Sopenharmony_ci /* 1708cb93a386Sopenharmony_ci // The text is immutable and so are all the text indexing properties 1709cb93a386Sopenharmony_ci // taken from SkUnicode 1710cb93a386Sopenharmony_ci fCodeUnitProperties.reset(); 1711cb93a386Sopenharmony_ci fWords.clear(); 1712cb93a386Sopenharmony_ci fBidiRegions.clear(); 1713cb93a386Sopenharmony_ci fUTF8IndexForUTF16Index.reset(); 1714cb93a386Sopenharmony_ci fUTF16IndexForUTF8Index.reset(); 1715cb93a386Sopenharmony_ci */ 1716cb93a386Sopenharmony_ci [[fallthrough]]; 1717cb93a386Sopenharmony_ci 1718cb93a386Sopenharmony_ci case kIndexed: 1719cb93a386Sopenharmony_ci fRuns.reset(); 1720cb93a386Sopenharmony_ci fClusters.reset(); 1721cb93a386Sopenharmony_ci [[fallthrough]]; 1722cb93a386Sopenharmony_ci 1723cb93a386Sopenharmony_ci case kShaped: 1724cb93a386Sopenharmony_ci fLines.reset(); 1725cb93a386Sopenharmony_ci [[fallthrough]]; 1726cb93a386Sopenharmony_ci 1727cb93a386Sopenharmony_ci case kLineBroken: 1728cb93a386Sopenharmony_ci fPicture = nullptr; 1729cb93a386Sopenharmony_ci [[fallthrough]]; 1730cb93a386Sopenharmony_ci 1731cb93a386Sopenharmony_ci default: 1732cb93a386Sopenharmony_ci break; 1733cb93a386Sopenharmony_ci } 1734cb93a386Sopenharmony_ci} 1735cb93a386Sopenharmony_ci 1736cb93a386Sopenharmony_civoid ParagraphImpl::computeEmptyMetrics() { 1737cb93a386Sopenharmony_ci 1738cb93a386Sopenharmony_ci // The empty metrics is used to define the height of the empty lines 1739cb93a386Sopenharmony_ci // Unfortunately, Flutter has 2 different cases for that: 1740cb93a386Sopenharmony_ci // 1. An empty line inside the text 1741cb93a386Sopenharmony_ci // 2. An empty paragraph 1742cb93a386Sopenharmony_ci // In the first case SkParagraph takes the metrics from the default paragraph style 1743cb93a386Sopenharmony_ci // In the second case it should take it from the current text style 1744cb93a386Sopenharmony_ci bool emptyParagraph = fRuns.empty(); 1745cb93a386Sopenharmony_ci TextStyle textStyle = paragraphStyle().getTextStyle(); 1746cb93a386Sopenharmony_ci if (emptyParagraph && !fTextStyles.empty()) { 1747cb93a386Sopenharmony_ci textStyle = fTextStyles.back().fStyle; 1748cb93a386Sopenharmony_ci } 1749cb93a386Sopenharmony_ci 1750cb93a386Sopenharmony_ci auto typefaces = fontCollection()->findTypefaces( 1751cb93a386Sopenharmony_ci textStyle.getFontFamilies(), textStyle.getFontStyle(), textStyle.getFontArguments()); 1752cb93a386Sopenharmony_ci auto typeface = typefaces.empty() ? nullptr : typefaces.front(); 1753cb93a386Sopenharmony_ci 1754cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 1755cb93a386Sopenharmony_ci SkFont font(typeface, textStyle.getFontSize()); 1756cb93a386Sopenharmony_ci#else 1757cb93a386Sopenharmony_ci RSFont font(typeface, textStyle.getFontSize(), 1, 0); 1758cb93a386Sopenharmony_ci#endif 1759cb93a386Sopenharmony_ci fEmptyMetrics = InternalLineMetrics(font, paragraphStyle().getStrutStyle().getForceStrutHeight()); 1760cb93a386Sopenharmony_ci 1761cb93a386Sopenharmony_ci if (!paragraphStyle().getStrutStyle().getForceStrutHeight() && 1762cb93a386Sopenharmony_ci textStyle.getHeightOverride()) { 1763cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1764cb93a386Sopenharmony_ci const auto intrinsicHeight = fEmptyMetrics.fDescent - fEmptyMetrics.fAscent + fEmptyMetrics.fLeading; 1765cb93a386Sopenharmony_ci#else 1766cb93a386Sopenharmony_ci const auto intrinsicHeight = fEmptyMetrics.height(); 1767cb93a386Sopenharmony_ci#endif 1768cb93a386Sopenharmony_ci const auto strutHeight = textStyle.getHeight() * textStyle.getFontSize(); 1769cb93a386Sopenharmony_ci if (paragraphStyle().getStrutStyle().getHalfLeading()) { 1770cb93a386Sopenharmony_ci fEmptyMetrics.update( 1771cb93a386Sopenharmony_ci fEmptyMetrics.ascent(), 1772cb93a386Sopenharmony_ci fEmptyMetrics.descent(), 1773cb93a386Sopenharmony_ci fEmptyMetrics.leading() + strutHeight - intrinsicHeight); 1774cb93a386Sopenharmony_ci } else { 1775cb93a386Sopenharmony_ci const auto multiplier = strutHeight / intrinsicHeight; 1776cb93a386Sopenharmony_ci fEmptyMetrics.update( 1777cb93a386Sopenharmony_ci fEmptyMetrics.ascent() * multiplier, 1778cb93a386Sopenharmony_ci fEmptyMetrics.descent() * multiplier, 1779cb93a386Sopenharmony_ci fEmptyMetrics.leading() * multiplier); 1780cb93a386Sopenharmony_ci } 1781cb93a386Sopenharmony_ci } 1782cb93a386Sopenharmony_ci 1783cb93a386Sopenharmony_ci if (emptyParagraph) { 1784cb93a386Sopenharmony_ci // For an empty text we apply both TextHeightBehaviour flags 1785cb93a386Sopenharmony_ci // In case of non-empty paragraph TextHeightBehaviour flags will be applied at the appropriate place 1786cb93a386Sopenharmony_ci // We have to do it here because we skip wrapping for an empty text 1787cb93a386Sopenharmony_ci auto disableFirstAscent = (paragraphStyle().getTextHeightBehavior() & TextHeightBehavior::kDisableFirstAscent) == TextHeightBehavior::kDisableFirstAscent; 1788cb93a386Sopenharmony_ci auto disableLastDescent = (paragraphStyle().getTextHeightBehavior() & TextHeightBehavior::kDisableLastDescent) == TextHeightBehavior::kDisableLastDescent; 1789cb93a386Sopenharmony_ci fEmptyMetrics.update( 1790cb93a386Sopenharmony_ci disableFirstAscent ? fEmptyMetrics.rawAscent() : fEmptyMetrics.ascent(), 1791cb93a386Sopenharmony_ci disableLastDescent ? fEmptyMetrics.rawDescent() : fEmptyMetrics.descent(), 1792cb93a386Sopenharmony_ci fEmptyMetrics.leading()); 1793cb93a386Sopenharmony_ci } 1794cb93a386Sopenharmony_ci 1795cb93a386Sopenharmony_ci if (fParagraphStyle.getStrutStyle().getStrutEnabled()) { 1796cb93a386Sopenharmony_ci fStrutMetrics.updateLineMetrics(fEmptyMetrics); 1797cb93a386Sopenharmony_ci } 1798cb93a386Sopenharmony_ci} 1799cb93a386Sopenharmony_ci 1800cb93a386Sopenharmony_ciSkString ParagraphImpl::getEllipsis() const { 1801cb93a386Sopenharmony_ci 1802cb93a386Sopenharmony_ci auto ellipsis8 = fParagraphStyle.getEllipsis(); 1803cb93a386Sopenharmony_ci auto ellipsis16 = fParagraphStyle.getEllipsisUtf16(); 1804cb93a386Sopenharmony_ci if (!ellipsis8.isEmpty()) { 1805cb93a386Sopenharmony_ci return ellipsis8; 1806cb93a386Sopenharmony_ci } else { 1807cb93a386Sopenharmony_ci return SkUnicode::convertUtf16ToUtf8(fParagraphStyle.getEllipsisUtf16()); 1808cb93a386Sopenharmony_ci } 1809cb93a386Sopenharmony_ci} 1810cb93a386Sopenharmony_ci 1811cb93a386Sopenharmony_ciWordBreakType ParagraphImpl::getWordBreakType() const { 1812cb93a386Sopenharmony_ci return fParagraphStyle.getStrutStyle().getWordBreakType(); 1813cb93a386Sopenharmony_ci} 1814cb93a386Sopenharmony_ci 1815cb93a386Sopenharmony_ciLineBreakStrategy ParagraphImpl::getLineBreakStrategy() const { 1816cb93a386Sopenharmony_ci return fParagraphStyle.getStrutStyle().getLineBreakStrategy(); 1817cb93a386Sopenharmony_ci} 1818cb93a386Sopenharmony_ci 1819cb93a386Sopenharmony_civoid ParagraphImpl::updateFontSize(size_t from, size_t to, SkScalar fontSize) { 1820cb93a386Sopenharmony_ci 1821cb93a386Sopenharmony_ci SkASSERT(from == 0 && to == fText.size()); 1822cb93a386Sopenharmony_ci auto defaultStyle = fParagraphStyle.getTextStyle(); 1823cb93a386Sopenharmony_ci defaultStyle.setFontSize(fontSize); 1824cb93a386Sopenharmony_ci fParagraphStyle.setTextStyle(defaultStyle); 1825cb93a386Sopenharmony_ci 1826cb93a386Sopenharmony_ci for (auto& textStyle : fTextStyles) { 1827cb93a386Sopenharmony_ci textStyle.fStyle.setFontSize(fontSize); 1828cb93a386Sopenharmony_ci } 1829cb93a386Sopenharmony_ci 1830cb93a386Sopenharmony_ci fState = std::min(fState, kIndexed); 1831cb93a386Sopenharmony_ci fOldWidth = 0; 1832cb93a386Sopenharmony_ci fOldHeight = 0; 1833cb93a386Sopenharmony_ci} 1834cb93a386Sopenharmony_ci 1835cb93a386Sopenharmony_civoid ParagraphImpl::updateTextAlign(TextAlign textAlign) { 1836cb93a386Sopenharmony_ci fParagraphStyle.setTextAlign(textAlign); 1837cb93a386Sopenharmony_ci 1838cb93a386Sopenharmony_ci if (fState >= kLineBroken) { 1839cb93a386Sopenharmony_ci fState = kLineBroken; 1840cb93a386Sopenharmony_ci } 1841cb93a386Sopenharmony_ci} 1842cb93a386Sopenharmony_ci 1843cb93a386Sopenharmony_civoid ParagraphImpl::updateForegroundPaint(size_t from, size_t to, SkPaint paint) { 1844cb93a386Sopenharmony_ci SkASSERT(from == 0 && to == fText.size()); 1845cb93a386Sopenharmony_ci auto defaultStyle = fParagraphStyle.getTextStyle(); 1846cb93a386Sopenharmony_ci defaultStyle.setForegroundColor(paint); 1847cb93a386Sopenharmony_ci fParagraphStyle.setTextStyle(defaultStyle); 1848cb93a386Sopenharmony_ci 1849cb93a386Sopenharmony_ci for (auto& textStyle : fTextStyles) { 1850cb93a386Sopenharmony_ci textStyle.fStyle.setForegroundColor(paint); 1851cb93a386Sopenharmony_ci } 1852cb93a386Sopenharmony_ci} 1853cb93a386Sopenharmony_ci 1854cb93a386Sopenharmony_civoid ParagraphImpl::updateBackgroundPaint(size_t from, size_t to, SkPaint paint) { 1855cb93a386Sopenharmony_ci SkASSERT(from == 0 && to == fText.size()); 1856cb93a386Sopenharmony_ci auto defaultStyle = fParagraphStyle.getTextStyle(); 1857cb93a386Sopenharmony_ci defaultStyle.setBackgroundColor(paint); 1858cb93a386Sopenharmony_ci fParagraphStyle.setTextStyle(defaultStyle); 1859cb93a386Sopenharmony_ci 1860cb93a386Sopenharmony_ci for (auto& textStyle : fTextStyles) { 1861cb93a386Sopenharmony_ci textStyle.fStyle.setBackgroundColor(paint); 1862cb93a386Sopenharmony_ci } 1863cb93a386Sopenharmony_ci} 1864cb93a386Sopenharmony_ci 1865cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1866cb93a386Sopenharmony_ciParagraphPainter::PaintID ParagraphImpl::updateTextStyleColorAndForeground(TextStyle& textStyle, SkColor color) 1867cb93a386Sopenharmony_ci{ 1868cb93a386Sopenharmony_ci textStyle.setColor(color); 1869cb93a386Sopenharmony_ci if (textStyle.hasForeground()) { 1870cb93a386Sopenharmony_ci auto paintOrID = textStyle.getForegroundPaintOrID(); 1871cb93a386Sopenharmony_ci SkPaint* paint = std::get_if<SkPaint>(&paintOrID); 1872cb93a386Sopenharmony_ci if (paint) { 1873cb93a386Sopenharmony_ci paint->setColor(color); 1874cb93a386Sopenharmony_ci textStyle.setForegroundPaint(*paint); 1875cb93a386Sopenharmony_ci } else { 1876cb93a386Sopenharmony_ci auto paintID = std::get_if<ParagraphPainter::PaintID>(&paintOrID); 1877cb93a386Sopenharmony_ci if (paintID) { 1878cb93a386Sopenharmony_ci return *paintID; 1879cb93a386Sopenharmony_ci } 1880cb93a386Sopenharmony_ci } 1881cb93a386Sopenharmony_ci } 1882cb93a386Sopenharmony_ci return INVALID_PAINT_ID; 1883cb93a386Sopenharmony_ci} 1884cb93a386Sopenharmony_ci 1885cb93a386Sopenharmony_cistd::vector<ParagraphPainter::PaintID> ParagraphImpl::updateColor(size_t from, size_t to, SkColor color) { 1886cb93a386Sopenharmony_ci std::vector<ParagraphPainter::PaintID> unresolvedPaintID; 1887cb93a386Sopenharmony_ci if (from >= to) { 1888cb93a386Sopenharmony_ci return unresolvedPaintID; 1889cb93a386Sopenharmony_ci } 1890cb93a386Sopenharmony_ci this->ensureUTF16Mapping(); 1891cb93a386Sopenharmony_ci from = (from < SkToSizeT(fUTF8IndexForUTF16Index.size())) ? fUTF8IndexForUTF16Index[from] : fText.size(); 1892cb93a386Sopenharmony_ci to = (to < SkToSizeT(fUTF8IndexForUTF16Index.size())) ? fUTF8IndexForUTF16Index[to] : fText.size(); 1893cb93a386Sopenharmony_ci if (from == 0 && to == fText.size()) { 1894cb93a386Sopenharmony_ci auto defaultStyle = fParagraphStyle.getTextStyle(); 1895cb93a386Sopenharmony_ci auto paintID = updateTextStyleColorAndForeground(defaultStyle, color); 1896cb93a386Sopenharmony_ci if (paintID != INVALID_PAINT_ID) { 1897cb93a386Sopenharmony_ci unresolvedPaintID.emplace_back(paintID); 1898cb93a386Sopenharmony_ci } 1899cb93a386Sopenharmony_ci fParagraphStyle.setTextStyle(defaultStyle); 1900cb93a386Sopenharmony_ci } 1901cb93a386Sopenharmony_ci 1902cb93a386Sopenharmony_ci for (auto& textStyle : fTextStyles) { 1903cb93a386Sopenharmony_ci auto& fRange = textStyle.fRange; 1904cb93a386Sopenharmony_ci if (to < fRange.end) { 1905cb93a386Sopenharmony_ci break; 1906cb93a386Sopenharmony_ci } 1907cb93a386Sopenharmony_ci if (from > fRange.start) { 1908cb93a386Sopenharmony_ci continue; 1909cb93a386Sopenharmony_ci } 1910cb93a386Sopenharmony_ci auto paintID = updateTextStyleColorAndForeground(textStyle.fStyle, color); 1911cb93a386Sopenharmony_ci if (paintID != INVALID_PAINT_ID) { 1912cb93a386Sopenharmony_ci unresolvedPaintID.emplace_back(paintID); 1913cb93a386Sopenharmony_ci } 1914cb93a386Sopenharmony_ci } 1915cb93a386Sopenharmony_ci for (auto& line : fLines) { 1916cb93a386Sopenharmony_ci line.setTextBlobCachePopulated(false); 1917cb93a386Sopenharmony_ci } 1918cb93a386Sopenharmony_ci return unresolvedPaintID; 1919cb93a386Sopenharmony_ci} 1920cb93a386Sopenharmony_ci#endif 1921cb93a386Sopenharmony_ci 1922cb93a386Sopenharmony_ciSkTArray<TextIndex> ParagraphImpl::countSurroundingGraphemes(TextRange textRange) const { 1923cb93a386Sopenharmony_ci textRange = textRange.intersection({0, fText.size()}); 1924cb93a386Sopenharmony_ci SkTArray<TextIndex> graphemes; 1925cb93a386Sopenharmony_ci if ((fCodeUnitProperties[textRange.start] & SkUnicode::CodeUnitFlags::kGraphemeStart) == 0) { 1926cb93a386Sopenharmony_ci // Count the previous partial grapheme 1927cb93a386Sopenharmony_ci graphemes.emplace_back(textRange.start); 1928cb93a386Sopenharmony_ci } 1929cb93a386Sopenharmony_ci for (auto index = textRange.start; index < textRange.end; ++index) { 1930cb93a386Sopenharmony_ci if ((fCodeUnitProperties[index] & SkUnicode::CodeUnitFlags::kGraphemeStart) != 0) { 1931cb93a386Sopenharmony_ci graphemes.emplace_back(index); 1932cb93a386Sopenharmony_ci } 1933cb93a386Sopenharmony_ci } 1934cb93a386Sopenharmony_ci return graphemes; 1935cb93a386Sopenharmony_ci} 1936cb93a386Sopenharmony_ci 1937cb93a386Sopenharmony_ciTextIndex ParagraphImpl::findPreviousGraphemeBoundary(TextIndex utf8) const { 1938cb93a386Sopenharmony_ci while (utf8 > 0 && 1939cb93a386Sopenharmony_ci (fCodeUnitProperties[utf8] & SkUnicode::CodeUnitFlags::kGraphemeStart) == 0) { 1940cb93a386Sopenharmony_ci --utf8; 1941cb93a386Sopenharmony_ci } 1942cb93a386Sopenharmony_ci return utf8; 1943cb93a386Sopenharmony_ci} 1944cb93a386Sopenharmony_ci 1945cb93a386Sopenharmony_ciTextIndex ParagraphImpl::findNextGraphemeBoundary(TextIndex utf8) const { 1946cb93a386Sopenharmony_ci while (utf8 < fText.size() && 1947cb93a386Sopenharmony_ci (fCodeUnitProperties[utf8] & SkUnicode::CodeUnitFlags::kGraphemeStart) == 0) { 1948cb93a386Sopenharmony_ci ++utf8; 1949cb93a386Sopenharmony_ci } 1950cb93a386Sopenharmony_ci return utf8; 1951cb93a386Sopenharmony_ci} 1952cb93a386Sopenharmony_ci 1953cb93a386Sopenharmony_ciTextIndex ParagraphImpl::findNextGlyphClusterBoundary(TextIndex utf8) const { 1954cb93a386Sopenharmony_ci while (utf8 < fText.size() && 1955cb93a386Sopenharmony_ci (fCodeUnitProperties[utf8] & SkUnicode::CodeUnitFlags::kGlyphClusterStart) == 0) { 1956cb93a386Sopenharmony_ci ++utf8; 1957cb93a386Sopenharmony_ci } 1958cb93a386Sopenharmony_ci return utf8; 1959cb93a386Sopenharmony_ci} 1960cb93a386Sopenharmony_ci 1961cb93a386Sopenharmony_ciTextIndex ParagraphImpl::findPreviousGlyphClusterBoundary(TextIndex utf8) const { 1962cb93a386Sopenharmony_ci while (utf8 > 0 && 1963cb93a386Sopenharmony_ci (fCodeUnitProperties[utf8] & SkUnicode::CodeUnitFlags::kGlyphClusterStart) == 0) { 1964cb93a386Sopenharmony_ci --utf8; 1965cb93a386Sopenharmony_ci } 1966cb93a386Sopenharmony_ci return utf8; 1967cb93a386Sopenharmony_ci} 1968cb93a386Sopenharmony_ci 1969cb93a386Sopenharmony_civoid ParagraphImpl::ensureUTF16Mapping() { 1970cb93a386Sopenharmony_ci fillUTF16MappingOnce([&] { 1971cb93a386Sopenharmony_ci fUnicode->extractUtfConversionMapping( 1972cb93a386Sopenharmony_ci this->text(), 1973cb93a386Sopenharmony_ci [&](size_t index) { fUTF8IndexForUTF16Index.emplace_back(index); }, 1974cb93a386Sopenharmony_ci [&](size_t index) { fUTF16IndexForUTF8Index.emplace_back(index); }); 1975cb93a386Sopenharmony_ci }); 1976cb93a386Sopenharmony_ci} 1977cb93a386Sopenharmony_ci 1978cb93a386Sopenharmony_civoid ParagraphImpl::visit(const Visitor& visitor) { 1979cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 1980cb93a386Sopenharmony_ci int lineNumber = 0; 1981cb93a386Sopenharmony_ci for (auto& line : fLines) { 1982cb93a386Sopenharmony_ci line.ensureTextBlobCachePopulated(); 1983cb93a386Sopenharmony_ci for (auto& rec : line.fTextBlobCache) { 1984cb93a386Sopenharmony_ci SkTextBlob::Iter iter(*rec.fBlob); 1985cb93a386Sopenharmony_ci SkTextBlob::Iter::ExperimentalRun run; 1986cb93a386Sopenharmony_ci 1987cb93a386Sopenharmony_ci SkSTArray<128, uint32_t> clusterStorage; 1988cb93a386Sopenharmony_ci const Run* R = rec.fVisitor_Run; 1989cb93a386Sopenharmony_ci const uint32_t* clusterPtr = &R->fClusterIndexes[0]; 1990cb93a386Sopenharmony_ci 1991cb93a386Sopenharmony_ci if (R->fClusterStart > 0) { 1992cb93a386Sopenharmony_ci int count = R->fClusterIndexes.size(); 1993cb93a386Sopenharmony_ci clusterStorage.reset(count); 1994cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 1995cb93a386Sopenharmony_ci clusterStorage[i] = R->fClusterStart + R->fClusterIndexes[i]; 1996cb93a386Sopenharmony_ci } 1997cb93a386Sopenharmony_ci clusterPtr = &clusterStorage[0]; 1998cb93a386Sopenharmony_ci } 1999cb93a386Sopenharmony_ci clusterPtr += rec.fVisitor_Pos; 2000cb93a386Sopenharmony_ci 2001cb93a386Sopenharmony_ci while (iter.experimentalNext(&run)) { 2002cb93a386Sopenharmony_ci const Paragraph::VisitorInfo info = { 2003cb93a386Sopenharmony_ci run.font, 2004cb93a386Sopenharmony_ci rec.fOffset, 2005cb93a386Sopenharmony_ci rec.fClipRect.fRight, 2006cb93a386Sopenharmony_ci run.count, 2007cb93a386Sopenharmony_ci run.glyphs, 2008cb93a386Sopenharmony_ci run.positions, 2009cb93a386Sopenharmony_ci clusterPtr, 2010cb93a386Sopenharmony_ci 0, // flags 2011cb93a386Sopenharmony_ci }; 2012cb93a386Sopenharmony_ci visitor(lineNumber, &info); 2013cb93a386Sopenharmony_ci clusterPtr += run.count; 2014cb93a386Sopenharmony_ci } 2015cb93a386Sopenharmony_ci } 2016cb93a386Sopenharmony_ci visitor(lineNumber, nullptr); // signal end of line 2017cb93a386Sopenharmony_ci lineNumber += 1; 2018cb93a386Sopenharmony_ci } 2019cb93a386Sopenharmony_ci#endif 2020cb93a386Sopenharmony_ci} 2021cb93a386Sopenharmony_ci 2022cb93a386Sopenharmony_ciint ParagraphImpl::getLineNumberAt(TextIndex codeUnitIndex) const { 2023cb93a386Sopenharmony_ci for (auto i = 0; i < fLines.size(); ++i) { 2024cb93a386Sopenharmony_ci auto& line = fLines[i]; 2025cb93a386Sopenharmony_ci if (line.text().contains({codeUnitIndex, codeUnitIndex + 1})) { 2026cb93a386Sopenharmony_ci return i; 2027cb93a386Sopenharmony_ci } 2028cb93a386Sopenharmony_ci } 2029cb93a386Sopenharmony_ci return -1; 2030cb93a386Sopenharmony_ci} 2031cb93a386Sopenharmony_ci 2032cb93a386Sopenharmony_cibool ParagraphImpl::getLineMetricsAt(int lineNumber, LineMetrics* lineMetrics) const { 2033cb93a386Sopenharmony_ci if (lineNumber < 0 || lineNumber >= fLines.size()) { 2034cb93a386Sopenharmony_ci return false; 2035cb93a386Sopenharmony_ci } 2036cb93a386Sopenharmony_ci auto& line = fLines[lineNumber]; 2037cb93a386Sopenharmony_ci if (lineMetrics) { 2038cb93a386Sopenharmony_ci *lineMetrics = line.getMetrics(); 2039cb93a386Sopenharmony_ci } 2040cb93a386Sopenharmony_ci return true; 2041cb93a386Sopenharmony_ci} 2042cb93a386Sopenharmony_ci 2043cb93a386Sopenharmony_ciTextRange ParagraphImpl::getActualTextRange(int lineNumber, bool includeSpaces) const { 2044cb93a386Sopenharmony_ci if (lineNumber < 0 || lineNumber >= fLines.size()) { 2045cb93a386Sopenharmony_ci return EMPTY_TEXT; 2046cb93a386Sopenharmony_ci } 2047cb93a386Sopenharmony_ci auto& line = fLines[lineNumber]; 2048cb93a386Sopenharmony_ci return includeSpaces ? line.text() : line.trimmedText(); 2049cb93a386Sopenharmony_ci} 2050cb93a386Sopenharmony_ci 2051cb93a386Sopenharmony_cibool ParagraphImpl::getGlyphClusterAt(TextIndex codeUnitIndex, GlyphClusterInfo* glyphInfo) { 2052cb93a386Sopenharmony_ci for (auto i = 0; i < fLines.size(); ++i) { 2053cb93a386Sopenharmony_ci auto& line = fLines[i]; 2054cb93a386Sopenharmony_ci if (!line.text().contains({codeUnitIndex, codeUnitIndex})) { 2055cb93a386Sopenharmony_ci continue; 2056cb93a386Sopenharmony_ci } 2057cb93a386Sopenharmony_ci for (auto c = line.clustersWithSpaces().start; c < line.clustersWithSpaces().end; ++c) { 2058cb93a386Sopenharmony_ci auto& cluster = fClusters[c]; 2059cb93a386Sopenharmony_ci if (cluster.contains(codeUnitIndex)) { 2060cb93a386Sopenharmony_ci std::vector<TextBox> boxes; 2061cb93a386Sopenharmony_ci line.getRectsForRange(cluster.textRange(), 2062cb93a386Sopenharmony_ci RectHeightStyle::kTight, 2063cb93a386Sopenharmony_ci RectWidthStyle::kTight, 2064cb93a386Sopenharmony_ci boxes); 2065cb93a386Sopenharmony_ci if (boxes.size() > 0) { 2066cb93a386Sopenharmony_ci if (glyphInfo) { 2067cb93a386Sopenharmony_ci *glyphInfo = {boxes[0].rect, cluster.textRange(), boxes[0].direction}; 2068cb93a386Sopenharmony_ci } 2069cb93a386Sopenharmony_ci return true; 2070cb93a386Sopenharmony_ci } 2071cb93a386Sopenharmony_ci } 2072cb93a386Sopenharmony_ci } 2073cb93a386Sopenharmony_ci return false; 2074cb93a386Sopenharmony_ci } 2075cb93a386Sopenharmony_ci return false; 2076cb93a386Sopenharmony_ci} 2077cb93a386Sopenharmony_ci 2078cb93a386Sopenharmony_cibool ParagraphImpl::getClosestGlyphClusterAt(SkScalar dx, 2079cb93a386Sopenharmony_ci SkScalar dy, 2080cb93a386Sopenharmony_ci GlyphClusterInfo* glyphInfo) { 2081cb93a386Sopenharmony_ci auto res = this->getGlyphPositionAtCoordinate(dx, dy); 2082cb93a386Sopenharmony_ci auto textIndex = res.position + (res.affinity == Affinity::kDownstream ? 0 : 1); 2083cb93a386Sopenharmony_ci GlyphClusterInfo gci; 2084cb93a386Sopenharmony_ci if (this->getGlyphClusterAt(textIndex, glyphInfo ? glyphInfo : &gci)) { 2085cb93a386Sopenharmony_ci return true; 2086cb93a386Sopenharmony_ci } else { 2087cb93a386Sopenharmony_ci return false; 2088cb93a386Sopenharmony_ci } 2089cb93a386Sopenharmony_ci} 2090cb93a386Sopenharmony_ci 2091cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 2092cb93a386Sopenharmony_ciSkFont ParagraphImpl::getFontAt(TextIndex codeUnitIndex) const { 2093cb93a386Sopenharmony_ci for (auto& run : fRuns) { 2094cb93a386Sopenharmony_ci if (run.textRange().contains({codeUnitIndex, codeUnitIndex})) { 2095cb93a386Sopenharmony_ci return run.font(); 2096cb93a386Sopenharmony_ci } 2097cb93a386Sopenharmony_ci } 2098cb93a386Sopenharmony_ci return SkFont(); 2099cb93a386Sopenharmony_ci} 2100cb93a386Sopenharmony_ci#else 2101cb93a386Sopenharmony_ciRSFont ParagraphImpl::getFontAt(TextIndex codeUnitIndex) const 2102cb93a386Sopenharmony_ci{ 2103cb93a386Sopenharmony_ci for (auto& run : fRuns) { 2104cb93a386Sopenharmony_ci if (run.textRange().contains({codeUnitIndex, codeUnitIndex})) { 2105cb93a386Sopenharmony_ci return run.font(); 2106cb93a386Sopenharmony_ci } 2107cb93a386Sopenharmony_ci } 2108cb93a386Sopenharmony_ci return RSFont(); 2109cb93a386Sopenharmony_ci} 2110cb93a386Sopenharmony_ci#endif 2111cb93a386Sopenharmony_ci 2112cb93a386Sopenharmony_cistd::vector<Paragraph::FontInfo> ParagraphImpl::getFonts() const { 2113cb93a386Sopenharmony_ci std::vector<FontInfo> results; 2114cb93a386Sopenharmony_ci for (auto& run : fRuns) { 2115cb93a386Sopenharmony_ci results.emplace_back(run.font(), run.textRange()); 2116cb93a386Sopenharmony_ci } 2117cb93a386Sopenharmony_ci return results; 2118cb93a386Sopenharmony_ci} 2119cb93a386Sopenharmony_ci 2120cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 2121cb93a386Sopenharmony_ciSkFontMetrics ParagraphImpl::measureText() { 2122cb93a386Sopenharmony_ci SkFontMetrics metrics; 2123cb93a386Sopenharmony_ci if (fRuns.empty()) { 2124cb93a386Sopenharmony_ci return metrics; 2125cb93a386Sopenharmony_ci } 2126cb93a386Sopenharmony_ci 2127cb93a386Sopenharmony_ci const auto& firstFont = fRuns.front().font(); 2128cb93a386Sopenharmony_ci SkRect firstBounds; 2129cb93a386Sopenharmony_ci auto firstStr = text(fRuns.front().textRange()); 2130cb93a386Sopenharmony_ci firstFont.getMetrics(&metrics); 2131cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 2132cb93a386Sopenharmony_ci auto decompressFont = firstFont; 2133cb93a386Sopenharmony_ci scaleFontWithCompressionConfig(decompressFont, ScaleOP::DECOMPRESS); 2134cb93a386Sopenharmony_ci metricsIncludeFontPadding(&metrics, decompressFont); 2135cb93a386Sopenharmony_ci#endif 2136cb93a386Sopenharmony_ci firstFont.measureText(firstStr.data(), firstStr.size(), SkTextEncoding::kUTF8, &firstBounds, nullptr); 2137cb93a386Sopenharmony_ci fGlyphsBoundsTop = firstBounds.top(); 2138cb93a386Sopenharmony_ci fGlyphsBoundsBottom = firstBounds.bottom(); 2139cb93a386Sopenharmony_ci fGlyphsBoundsLeft = firstBounds.left(); 2140cb93a386Sopenharmony_ci SkScalar realWidth = 0; 2141cb93a386Sopenharmony_ci for (size_t i = 0; i < fRuns.size(); ++i) { 2142cb93a386Sopenharmony_ci auto run = fRuns[i]; 2143cb93a386Sopenharmony_ci const auto& font = run.font(); 2144cb93a386Sopenharmony_ci SkRect bounds; 2145cb93a386Sopenharmony_ci auto str = text(run.textRange()); 2146cb93a386Sopenharmony_ci auto advance = font.measureText(str.data(), str.size(), SkTextEncoding::kUTF8, &bounds, nullptr); 2147cb93a386Sopenharmony_ci realWidth += advance; 2148cb93a386Sopenharmony_ci if (i == 0) { 2149cb93a386Sopenharmony_ci realWidth -= ((advance - (bounds.right() - bounds.left())) / 2); 2150cb93a386Sopenharmony_ci } 2151cb93a386Sopenharmony_ci if (i == (fRuns.size() - 1)) { 2152cb93a386Sopenharmony_ci realWidth -= ((advance - (bounds.right() - bounds.left())) / 2); 2153cb93a386Sopenharmony_ci } 2154cb93a386Sopenharmony_ci fGlyphsBoundsTop = std::min(fGlyphsBoundsTop, bounds.top()); 2155cb93a386Sopenharmony_ci fGlyphsBoundsBottom = std::max(fGlyphsBoundsBottom, bounds.bottom()); 2156cb93a386Sopenharmony_ci } 2157cb93a386Sopenharmony_ci fGlyphsBoundsRight = realWidth + fGlyphsBoundsLeft; 2158cb93a386Sopenharmony_ci return metrics; 2159cb93a386Sopenharmony_ci} 2160cb93a386Sopenharmony_ci#else 2161cb93a386Sopenharmony_ciRSFontMetrics ParagraphImpl::measureText() 2162cb93a386Sopenharmony_ci{ 2163cb93a386Sopenharmony_ci RSFontMetrics metrics; 2164cb93a386Sopenharmony_ci if (fRuns.empty()) { 2165cb93a386Sopenharmony_ci return metrics; 2166cb93a386Sopenharmony_ci } 2167cb93a386Sopenharmony_ci 2168cb93a386Sopenharmony_ci auto& firstFont = const_cast<RSFont&>(fRuns.front().font()); 2169cb93a386Sopenharmony_ci RSRect firstBounds; 2170cb93a386Sopenharmony_ci auto firstStr = text(fRuns.front().textRange()); 2171cb93a386Sopenharmony_ci firstFont.GetMetrics(&metrics); 2172cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 2173cb93a386Sopenharmony_ci auto decompressFont = firstFont; 2174cb93a386Sopenharmony_ci scaleFontWithCompressionConfig(decompressFont, ScaleOP::DECOMPRESS); 2175cb93a386Sopenharmony_ci metricsIncludeFontPadding(&metrics, decompressFont); 2176cb93a386Sopenharmony_ci#endif 2177cb93a386Sopenharmony_ci firstFont.MeasureText(firstStr.data(), firstStr.size(), RSDrawing::TextEncoding::UTF8, &firstBounds); 2178cb93a386Sopenharmony_ci fGlyphsBoundsTop = firstBounds.GetTop(); 2179cb93a386Sopenharmony_ci fGlyphsBoundsBottom = firstBounds.GetBottom(); 2180cb93a386Sopenharmony_ci fGlyphsBoundsLeft = firstBounds.GetLeft(); 2181cb93a386Sopenharmony_ci float realWidth = 0; 2182cb93a386Sopenharmony_ci for (size_t i = 0; i < fRuns.size(); ++i) { 2183cb93a386Sopenharmony_ci auto run = fRuns[i]; 2184cb93a386Sopenharmony_ci auto& font = const_cast<RSFont&>(run.font()); 2185cb93a386Sopenharmony_ci RSRect bounds; 2186cb93a386Sopenharmony_ci auto str = text(run.textRange()); 2187cb93a386Sopenharmony_ci auto advance = font.MeasureText(str.data(), str.size(), RSDrawing::TextEncoding::UTF8, &bounds); 2188cb93a386Sopenharmony_ci realWidth += advance; 2189cb93a386Sopenharmony_ci if (i == 0) { 2190cb93a386Sopenharmony_ci realWidth -= ((advance - (bounds.GetRight() - bounds.GetLeft())) / 2); 2191cb93a386Sopenharmony_ci } 2192cb93a386Sopenharmony_ci if (i == (fRuns.size() - 1)) { 2193cb93a386Sopenharmony_ci realWidth -= ((advance - (bounds.GetRight() - bounds.GetLeft())) / 2); 2194cb93a386Sopenharmony_ci } 2195cb93a386Sopenharmony_ci fGlyphsBoundsTop = std::min(fGlyphsBoundsTop, bounds.GetTop()); 2196cb93a386Sopenharmony_ci fGlyphsBoundsBottom = std::max(fGlyphsBoundsBottom, bounds.GetBottom()); 2197cb93a386Sopenharmony_ci } 2198cb93a386Sopenharmony_ci fGlyphsBoundsRight = realWidth + fGlyphsBoundsLeft; 2199cb93a386Sopenharmony_ci return metrics; 2200cb93a386Sopenharmony_ci} 2201cb93a386Sopenharmony_ci#endif 2202cb93a386Sopenharmony_ci 2203cb93a386Sopenharmony_cistd::vector<std::unique_ptr<TextLineBase>> ParagraphImpl::GetTextLines() { 2204cb93a386Sopenharmony_ci std::vector<std::unique_ptr<TextLineBase>> textLineBases; 2205cb93a386Sopenharmony_ci for (auto& line: fLines) { 2206cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 2207cb93a386Sopenharmony_ci std::unique_ptr<TextLineBaseImpl> textLineBaseImplPtr = 2208cb93a386Sopenharmony_ci std::make_unique<TextLineBaseImpl>(std::make_unique<TextLine>(std::move(line))); 2209cb93a386Sopenharmony_ci#else 2210cb93a386Sopenharmony_ci std::unique_ptr<TextLineBaseImpl> textLineBaseImplPtr = std::make_unique<TextLineBaseImpl>(&line); 2211cb93a386Sopenharmony_ci#endif 2212cb93a386Sopenharmony_ci textLineBases.emplace_back(std::move(textLineBaseImplPtr)); 2213cb93a386Sopenharmony_ci } 2214cb93a386Sopenharmony_ci 2215cb93a386Sopenharmony_ci return textLineBases; 2216cb93a386Sopenharmony_ci} 2217cb93a386Sopenharmony_ci 2218cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 2219cb93a386Sopenharmony_cisize_t ParagraphImpl::prefixByteCountUntilChar(size_t index) { 2220cb93a386Sopenharmony_ci convertUtf8ToUnicode(fText); 2221cb93a386Sopenharmony_ci if (fUnicodeIndexForUTF8Index.empty()) { 2222cb93a386Sopenharmony_ci return std::numeric_limits<size_t>::max(); 2223cb93a386Sopenharmony_ci } 2224cb93a386Sopenharmony_ci auto it = std::lower_bound(fUnicodeIndexForUTF8Index.begin(), fUnicodeIndexForUTF8Index.end(), index); 2225cb93a386Sopenharmony_ci if (it != fUnicodeIndexForUTF8Index.end() && *it == index) { 2226cb93a386Sopenharmony_ci return std::distance(fUnicodeIndexForUTF8Index.begin(), it); 2227cb93a386Sopenharmony_ci } else { 2228cb93a386Sopenharmony_ci return std::numeric_limits<size_t>::max(); 2229cb93a386Sopenharmony_ci } 2230cb93a386Sopenharmony_ci} 2231cb93a386Sopenharmony_ci 2232cb93a386Sopenharmony_civoid ParagraphImpl::copyProperties(const ParagraphImpl& source) { 2233cb93a386Sopenharmony_ci fText = source.fText; 2234cb93a386Sopenharmony_ci fTextStyles = source.fTextStyles; 2235cb93a386Sopenharmony_ci fPlaceholders = source.fPlaceholders; 2236cb93a386Sopenharmony_ci fParagraphStyle = source.fParagraphStyle; 2237cb93a386Sopenharmony_ci fFontCollection = source.fFontCollection; 2238cb93a386Sopenharmony_ci fUnicode = source.fUnicode; 2239cb93a386Sopenharmony_ci 2240cb93a386Sopenharmony_ci fState = kUnknown; 2241cb93a386Sopenharmony_ci fUnresolvedGlyphs = 0; 2242cb93a386Sopenharmony_ci fPicture = nullptr; 2243cb93a386Sopenharmony_ci fStrutMetrics = false; 2244cb93a386Sopenharmony_ci fOldWidth = 0; 2245cb93a386Sopenharmony_ci fOldHeight = 0; 2246cb93a386Sopenharmony_ci fHasLineBreaks = false; 2247cb93a386Sopenharmony_ci fHasWhitespacesInside = false; 2248cb93a386Sopenharmony_ci fTrailingSpaces = 0; 2249cb93a386Sopenharmony_ci} 2250cb93a386Sopenharmony_ci 2251cb93a386Sopenharmony_cistd::unique_ptr<Paragraph> ParagraphImpl::createCroppedCopy(size_t startIndex, size_t count) { 2252cb93a386Sopenharmony_ci std::unique_ptr<ParagraphImpl> paragraph = std::make_unique<ParagraphImpl>(); 2253cb93a386Sopenharmony_ci paragraph->copyProperties(*this); 2254cb93a386Sopenharmony_ci 2255cb93a386Sopenharmony_ci // change range 2256cb93a386Sopenharmony_ci auto validStart = prefixByteCountUntilChar(startIndex); 2257cb93a386Sopenharmony_ci if (validStart == std::numeric_limits<size_t>::max()) { 2258cb93a386Sopenharmony_ci return nullptr; 2259cb93a386Sopenharmony_ci } 2260cb93a386Sopenharmony_ci // For example, when the clipped string str1 is "123456789" 2261cb93a386Sopenharmony_ci // startIndex=2, count=std:: numeric_imits<size_t>:: max(), the resulting string str2 is "3456789". 2262cb93a386Sopenharmony_ci // When startIndex=3 and count=3, crop the generated string str3 to "456" 2263cb93a386Sopenharmony_ci TextRange firstDeleteRange(0, validStart); 2264cb93a386Sopenharmony_ci paragraph->fText.remove(0, validStart); 2265cb93a386Sopenharmony_ci paragraph->resetTextStyleRange(firstDeleteRange); 2266cb93a386Sopenharmony_ci paragraph->resetPlaceholderRange(firstDeleteRange); 2267cb93a386Sopenharmony_ci 2268cb93a386Sopenharmony_ci if (count != std::numeric_limits<size_t>::max()) { 2269cb93a386Sopenharmony_ci auto invalidStart = paragraph->prefixByteCountUntilChar(count); 2270cb93a386Sopenharmony_ci if (invalidStart == std::numeric_limits<size_t>::max()) { 2271cb93a386Sopenharmony_ci return nullptr; 2272cb93a386Sopenharmony_ci } 2273cb93a386Sopenharmony_ci auto invalidEnd = paragraph->fText.size(); 2274cb93a386Sopenharmony_ci TextRange secodeDeleteRange(invalidStart, invalidEnd); 2275cb93a386Sopenharmony_ci paragraph->fText.remove(invalidStart, invalidEnd - invalidStart); 2276cb93a386Sopenharmony_ci paragraph->resetTextStyleRange(secodeDeleteRange); 2277cb93a386Sopenharmony_ci paragraph->resetPlaceholderRange(secodeDeleteRange); 2278cb93a386Sopenharmony_ci } 2279cb93a386Sopenharmony_ci return paragraph; 2280cb93a386Sopenharmony_ci} 2281cb93a386Sopenharmony_ci 2282cb93a386Sopenharmony_civoid ParagraphImpl::initUnicodeText() { 2283cb93a386Sopenharmony_ci this->fUnicodeText = convertUtf8ToUnicode(fText); 2284cb93a386Sopenharmony_ci} 2285cb93a386Sopenharmony_ci#endif 2286cb93a386Sopenharmony_ci 2287cb93a386Sopenharmony_cistd::unique_ptr<Paragraph> ParagraphImpl::CloneSelf() 2288cb93a386Sopenharmony_ci{ 2289cb93a386Sopenharmony_ci std::unique_ptr<ParagraphImpl> paragraph = std::make_unique<ParagraphImpl>(); 2290cb93a386Sopenharmony_ci 2291cb93a386Sopenharmony_ci paragraph->fFontCollection = this->fFontCollection; 2292cb93a386Sopenharmony_ci paragraph->fParagraphStyle = this->fParagraphStyle; 2293cb93a386Sopenharmony_ci paragraph->fAlphabeticBaseline = this->fAlphabeticBaseline; 2294cb93a386Sopenharmony_ci paragraph->fIdeographicBaseline = this->fIdeographicBaseline; 2295cb93a386Sopenharmony_ci paragraph->fGlyphsBoundsTop = this->fGlyphsBoundsTop; 2296cb93a386Sopenharmony_ci paragraph->fGlyphsBoundsBottom = this->fGlyphsBoundsBottom; 2297cb93a386Sopenharmony_ci paragraph->fGlyphsBoundsLeft = this->fGlyphsBoundsLeft; 2298cb93a386Sopenharmony_ci paragraph->fGlyphsBoundsRight = this->fGlyphsBoundsRight; 2299cb93a386Sopenharmony_ci paragraph->fHeight = this->fHeight; 2300cb93a386Sopenharmony_ci paragraph->fWidth = this->fWidth; 2301cb93a386Sopenharmony_ci paragraph->fMaxIntrinsicWidth = this->fMaxIntrinsicWidth; 2302cb93a386Sopenharmony_ci paragraph->fMinIntrinsicWidth = this->fMinIntrinsicWidth; 2303cb93a386Sopenharmony_ci paragraph->fLongestLine = this->fLongestLine; 2304cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 2305cb93a386Sopenharmony_ci paragraph->fLongestLineWithIndent = this->fLongestLineWithIndent; 2306cb93a386Sopenharmony_ci#endif 2307cb93a386Sopenharmony_ci paragraph->fExceededMaxLines = this->fExceededMaxLines; 2308cb93a386Sopenharmony_ci 2309cb93a386Sopenharmony_ci paragraph->fLetterSpaceStyles = this->fLetterSpaceStyles; 2310cb93a386Sopenharmony_ci paragraph->fWordSpaceStyles = this->fWordSpaceStyles; 2311cb93a386Sopenharmony_ci paragraph->fBackgroundStyles = this->fBackgroundStyles; 2312cb93a386Sopenharmony_ci paragraph->fForegroundStyles = this->fForegroundStyles; 2313cb93a386Sopenharmony_ci paragraph->fShadowStyles = this->fShadowStyles; 2314cb93a386Sopenharmony_ci paragraph->fDecorationStyles = this->fDecorationStyles; 2315cb93a386Sopenharmony_ci paragraph->fTextStyles = this->fTextStyles; 2316cb93a386Sopenharmony_ci paragraph->fPlaceholders = this->fPlaceholders; 2317cb93a386Sopenharmony_ci paragraph->fText = this->fText; 2318cb93a386Sopenharmony_ci 2319cb93a386Sopenharmony_ci paragraph->fState = this->fState; 2320cb93a386Sopenharmony_ci paragraph->fRuns = this->fRuns; 2321cb93a386Sopenharmony_ci paragraph->fClusters = this->fClusters; 2322cb93a386Sopenharmony_ci paragraph->fCodeUnitProperties = this->fCodeUnitProperties; 2323cb93a386Sopenharmony_ci paragraph->fClustersIndexFromCodeUnit = this->fClustersIndexFromCodeUnit; 2324cb93a386Sopenharmony_ci 2325cb93a386Sopenharmony_ci paragraph->fWords = this->fWords; 2326cb93a386Sopenharmony_ci paragraph->fIndents = this->fIndents; 2327cb93a386Sopenharmony_ci paragraph->rtlTextSize = this->rtlTextSize; 2328cb93a386Sopenharmony_ci paragraph->ltrTextSize = this->ltrTextSize; 2329cb93a386Sopenharmony_ci paragraph->fBidiRegions = this->fBidiRegions; 2330cb93a386Sopenharmony_ci 2331cb93a386Sopenharmony_ci paragraph->fUTF8IndexForUTF16Index = this->fUTF8IndexForUTF16Index; 2332cb93a386Sopenharmony_ci paragraph->fUTF16IndexForUTF8Index = this->fUTF16IndexForUTF8Index; 2333cb93a386Sopenharmony_ci paragraph->fUnresolvedGlyphs = this->fUnresolvedGlyphs; 2334cb93a386Sopenharmony_ci paragraph->isMiddleEllipsis = this->isMiddleEllipsis; 2335cb93a386Sopenharmony_ci paragraph->fUnresolvedCodepoints = this->fUnresolvedCodepoints; 2336cb93a386Sopenharmony_ci 2337cb93a386Sopenharmony_ci for (auto& line : this->fLines) { 2338cb93a386Sopenharmony_ci paragraph->fLines.emplace_back(line.CloneSelf()); 2339cb93a386Sopenharmony_ci } 2340cb93a386Sopenharmony_ci 2341cb93a386Sopenharmony_ci paragraph->fPicture = this->fPicture; 2342cb93a386Sopenharmony_ci paragraph->fFontSwitches = this->fFontSwitches; 2343cb93a386Sopenharmony_ci paragraph->fEmptyMetrics = this->fEmptyMetrics; 2344cb93a386Sopenharmony_ci paragraph->fStrutMetrics = this->fStrutMetrics; 2345cb93a386Sopenharmony_ci 2346cb93a386Sopenharmony_ci paragraph->fOldWidth = this->fOldWidth; 2347cb93a386Sopenharmony_ci paragraph->fOldHeight = this->fOldHeight; 2348cb93a386Sopenharmony_ci paragraph->fMaxWidthWithTrailingSpaces = this->fMaxWidthWithTrailingSpaces; 2349cb93a386Sopenharmony_ci paragraph->fOldMaxWidth = this->fOldMaxWidth; 2350cb93a386Sopenharmony_ci paragraph->allTextWidth = this->allTextWidth; 2351cb93a386Sopenharmony_ci 2352cb93a386Sopenharmony_ci paragraph->fUnicode = this->fUnicode; 2353cb93a386Sopenharmony_ci paragraph->fHasLineBreaks = this->fHasLineBreaks; 2354cb93a386Sopenharmony_ci paragraph->fHasWhitespacesInside = this->fHasWhitespacesInside; 2355cb93a386Sopenharmony_ci paragraph->fTrailingSpaces = this->fTrailingSpaces; 2356cb93a386Sopenharmony_ci paragraph->fLineNumber = this->fLineNumber; 2357cb93a386Sopenharmony_ci paragraph->fEllipsisRange = this->fEllipsisRange; 2358cb93a386Sopenharmony_ci 2359cb93a386Sopenharmony_ci for (auto& run : paragraph->fRuns) { 2360cb93a386Sopenharmony_ci run.setOwner(paragraph.get()); 2361cb93a386Sopenharmony_ci } 2362cb93a386Sopenharmony_ci for (auto& cluster : paragraph->fClusters) { 2363cb93a386Sopenharmony_ci cluster.setOwner(paragraph.get()); 2364cb93a386Sopenharmony_ci } 2365cb93a386Sopenharmony_ci for (auto& line : paragraph->fLines) { 2366cb93a386Sopenharmony_ci line.setParagraphImpl(paragraph.get()); 2367cb93a386Sopenharmony_ci } 2368cb93a386Sopenharmony_ci return paragraph; 2369cb93a386Sopenharmony_ci} 2370cb93a386Sopenharmony_ci 2371cb93a386Sopenharmony_ci} // namespace textlayout 2372cb93a386Sopenharmony_ci} // namespace skia 2373