1cb93a386Sopenharmony_ci// Copyright 2019 Google LLC. 2cb93a386Sopenharmony_ci 3cb93a386Sopenharmony_ci#include "include/core/SkBlurTypes.h" 4cb93a386Sopenharmony_ci#include "include/core/SkFont.h" 5cb93a386Sopenharmony_ci#include "include/core/SkFontMetrics.h" 6cb93a386Sopenharmony_ci#include "include/core/SkMaskFilter.h" 7cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 8cb93a386Sopenharmony_ci#include "include/core/SkSpan.h" 9cb93a386Sopenharmony_ci#include "include/core/SkString.h" 10cb93a386Sopenharmony_ci#include "include/core/SkTextBlob.h" 11cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 12cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 13cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 14cb93a386Sopenharmony_ci#include "modules/skparagraph/include/DartTypes.h" 15cb93a386Sopenharmony_ci#include "modules/skparagraph/include/Metrics.h" 16cb93a386Sopenharmony_ci#include "modules/skparagraph/include/ParagraphPainter.h" 17cb93a386Sopenharmony_ci#include "modules/skparagraph/include/ParagraphStyle.h" 18cb93a386Sopenharmony_ci#include "modules/skparagraph/include/TextShadow.h" 19cb93a386Sopenharmony_ci#include "modules/skparagraph/include/TextStyle.h" 20cb93a386Sopenharmony_ci#include "modules/skparagraph/src/Decorations.h" 21cb93a386Sopenharmony_ci#include "modules/skparagraph/src/ParagraphImpl.h" 22cb93a386Sopenharmony_ci#include "modules/skparagraph/src/ParagraphPainterImpl.h" 23cb93a386Sopenharmony_ci#include "modules/skparagraph/src/TextLine.h" 24cb93a386Sopenharmony_ci#include "modules/skshaper/include/SkShaper.h" 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci#include <algorithm> 27cb93a386Sopenharmony_ci#include <iterator> 28cb93a386Sopenharmony_ci#include <limits> 29cb93a386Sopenharmony_ci#include <map> 30cb93a386Sopenharmony_ci#include <memory> 31cb93a386Sopenharmony_ci#include <tuple> 32cb93a386Sopenharmony_ci#include <type_traits> 33cb93a386Sopenharmony_ci#include <utility> 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 36cb93a386Sopenharmony_ci#include "log.h" 37cb93a386Sopenharmony_ci#include "modules/skparagraph/src/RunBaseImpl.h" 38cb93a386Sopenharmony_ci#include "modules/skparagraph/src/TextLineBaseImpl.h" 39cb93a386Sopenharmony_ci#include "TextParameter.h" 40cb93a386Sopenharmony_ci#endif 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_cinamespace skia { 43cb93a386Sopenharmony_cinamespace textlayout { 44cb93a386Sopenharmony_ci#define MAX_INT_VALUE 0x7FFFFFFF 45cb93a386Sopenharmony_ci#define EMOJI_UNICODE_START 0x1F300 46cb93a386Sopenharmony_ci#define EMOJI_UNICODE_END 0x1F9EF 47cb93a386Sopenharmony_ci#define EMOJI_WIDTH 4 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_cinamespace { 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci// TODO: deal with all the intersection functionality 52cb93a386Sopenharmony_ciTextRange intersected(const TextRange& a, const TextRange& b) { 53cb93a386Sopenharmony_ci if (a.start == b.start && a.end == b.end) return a; 54cb93a386Sopenharmony_ci auto begin = std::max(a.start, b.start); 55cb93a386Sopenharmony_ci auto end = std::min(a.end, b.end); 56cb93a386Sopenharmony_ci return end >= begin ? TextRange(begin, end) : EMPTY_TEXT; 57cb93a386Sopenharmony_ci} 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ciSkScalar littleRound(SkScalar a) { 60cb93a386Sopenharmony_ci // This rounding is done to match Flutter tests. Must be removed.. 61cb93a386Sopenharmony_ci return SkScalarRoundToScalar(a * 100.0)/100.0; 62cb93a386Sopenharmony_ci} 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_ciTextRange operator*(const TextRange& a, const TextRange& b) { 65cb93a386Sopenharmony_ci if (a.start == b.start && a.end == b.end) return a; 66cb93a386Sopenharmony_ci auto begin = std::max(a.start, b.start); 67cb93a386Sopenharmony_ci auto end = std::min(a.end, b.end); 68cb93a386Sopenharmony_ci return end > begin ? TextRange(begin, end) : EMPTY_TEXT; 69cb93a386Sopenharmony_ci} 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ciint compareRound(SkScalar a, SkScalar b, bool applyRoundingHack) { 72cb93a386Sopenharmony_ci // There is a rounding error that gets bigger when maxWidth gets bigger 73cb93a386Sopenharmony_ci // VERY long zalgo text (> 100000) on a VERY long line (> 10000) 74cb93a386Sopenharmony_ci // Canvas scaling affects it 75cb93a386Sopenharmony_ci // Letter spacing affects it 76cb93a386Sopenharmony_ci // It has to be relative to be useful 77cb93a386Sopenharmony_ci auto base = std::max(SkScalarAbs(a), SkScalarAbs(b)); 78cb93a386Sopenharmony_ci auto diff = SkScalarAbs(a - b); 79cb93a386Sopenharmony_ci if (nearlyZero(base) || diff / base < 0.001f) { 80cb93a386Sopenharmony_ci return 0; 81cb93a386Sopenharmony_ci } 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ci auto ra = a; 84cb93a386Sopenharmony_ci auto rb = b; 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_ci if (applyRoundingHack) { 87cb93a386Sopenharmony_ci ra = littleRound(a); 88cb93a386Sopenharmony_ci rb = littleRound(b); 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci if (ra < rb) { 91cb93a386Sopenharmony_ci return -1; 92cb93a386Sopenharmony_ci } else { 93cb93a386Sopenharmony_ci return 1; 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci} 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_ci#ifdef USE_SKIA_TXT 98cb93a386Sopenharmony_cibool IsRSFontEquals(const RSFont& font0, const RSFont& font1) { 99cb93a386Sopenharmony_ci auto f0 = const_cast<RSFont&>(font0); 100cb93a386Sopenharmony_ci auto f1 = const_cast<RSFont&>(font1); 101cb93a386Sopenharmony_ci return f0.GetTypeface().get() == f1.GetTypeface().get() && 102cb93a386Sopenharmony_ci f0.GetSize() == f1.GetSize() && 103cb93a386Sopenharmony_ci f0.GetScaleX() == f1.GetScaleX() && 104cb93a386Sopenharmony_ci f0.GetSkewX() == f1.GetSkewX() && 105cb93a386Sopenharmony_ci f0.GetEdging() == f1.GetEdging() && 106cb93a386Sopenharmony_ci f0.GetHinting() == f1.GetHinting(); 107cb93a386Sopenharmony_ci} 108cb93a386Sopenharmony_ci#endif 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci} // namespace 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ciTextLine::TextLine(ParagraphImpl* owner, 113cb93a386Sopenharmony_ci SkVector offset, 114cb93a386Sopenharmony_ci SkVector advance, 115cb93a386Sopenharmony_ci BlockRange blocks, 116cb93a386Sopenharmony_ci TextRange textExcludingSpaces, 117cb93a386Sopenharmony_ci TextRange text, 118cb93a386Sopenharmony_ci TextRange textIncludingNewlines, 119cb93a386Sopenharmony_ci ClusterRange clusters, 120cb93a386Sopenharmony_ci ClusterRange clustersWithGhosts, 121cb93a386Sopenharmony_ci SkScalar widthWithSpaces, 122cb93a386Sopenharmony_ci InternalLineMetrics sizes) 123cb93a386Sopenharmony_ci : fOwner(owner) 124cb93a386Sopenharmony_ci , fBlockRange(blocks) 125cb93a386Sopenharmony_ci , fTextExcludingSpaces(textExcludingSpaces) 126cb93a386Sopenharmony_ci , fText(text) 127cb93a386Sopenharmony_ci , fTextIncludingNewlines(textIncludingNewlines) 128cb93a386Sopenharmony_ci , fClusterRange(clusters) 129cb93a386Sopenharmony_ci , fGhostClusterRange(clustersWithGhosts) 130cb93a386Sopenharmony_ci , fRunsInVisualOrder() 131cb93a386Sopenharmony_ci , fAdvance(advance) 132cb93a386Sopenharmony_ci , fOffset(offset) 133cb93a386Sopenharmony_ci , fShift(0.0) 134cb93a386Sopenharmony_ci , fWidthWithSpaces(widthWithSpaces) 135cb93a386Sopenharmony_ci , fEllipsis(nullptr) 136cb93a386Sopenharmony_ci , fSizes(sizes) 137cb93a386Sopenharmony_ci , fHasBackground(false) 138cb93a386Sopenharmony_ci , fHasShadows(false) 139cb93a386Sopenharmony_ci , fHasDecorations(false) 140cb93a386Sopenharmony_ci , fIsArcText(false) 141cb93a386Sopenharmony_ci , fArcTextState(false) 142cb93a386Sopenharmony_ci , fAscentStyle(LineMetricStyle::CSS) 143cb93a386Sopenharmony_ci , fDescentStyle(LineMetricStyle::CSS) 144cb93a386Sopenharmony_ci , fTextBlobCachePopulated(false) { 145cb93a386Sopenharmony_ci // Reorder visual runs 146cb93a386Sopenharmony_ci auto& start = owner->cluster(fGhostClusterRange.start); 147cb93a386Sopenharmony_ci auto& end = owner->cluster(fGhostClusterRange.end - 1); 148cb93a386Sopenharmony_ci size_t numRuns = end.runIndex() - start.runIndex() + 1; 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_ci for (BlockIndex index = fBlockRange.start; index < fBlockRange.end; ++index) { 151cb93a386Sopenharmony_ci auto b = fOwner->styles().begin() + index; 152cb93a386Sopenharmony_ci if (b->fStyle.hasBackground()) { 153cb93a386Sopenharmony_ci fHasBackground = true; 154cb93a386Sopenharmony_ci } 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 157cb93a386Sopenharmony_ci if (b->fStyle.getDecorationType() != TextDecoration::kNoDecoration && 158cb93a386Sopenharmony_ci b->fStyle.getDecorationThicknessMultiplier() > 0) { 159cb93a386Sopenharmony_ci#else 160cb93a386Sopenharmony_ci if (b->fStyle.getDecorationType() != TextDecoration::kNoDecoration) { 161cb93a386Sopenharmony_ci#endif 162cb93a386Sopenharmony_ci fHasDecorations = true; 163cb93a386Sopenharmony_ci } 164cb93a386Sopenharmony_ci if (b->fStyle.getShadowNumber() > 0) { 165cb93a386Sopenharmony_ci fHasShadows = true; 166cb93a386Sopenharmony_ci } 167cb93a386Sopenharmony_ci } 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci // Get the logical order 170cb93a386Sopenharmony_ci 171cb93a386Sopenharmony_ci // This is just chosen to catch the common/fast cases. Feel free to tweak. 172cb93a386Sopenharmony_ci constexpr int kPreallocCount = 4; 173cb93a386Sopenharmony_ci SkAutoSTArray<kPreallocCount, SkUnicode::BidiLevel> runLevels(numRuns); 174cb93a386Sopenharmony_ci std::vector<RunIndex> placeholdersInOriginalOrder; 175cb93a386Sopenharmony_ci size_t runLevelsIndex = 0; 176cb93a386Sopenharmony_ci // Placeholders must be laid out using the original order in which they were added 177cb93a386Sopenharmony_ci // in the input. The API does not provide a way to indicate that a placeholder 178cb93a386Sopenharmony_ci // position was moved due to bidi reordering. 179cb93a386Sopenharmony_ci for (auto runIndex = start.runIndex(); runIndex <= end.runIndex(); ++runIndex) { 180cb93a386Sopenharmony_ci auto& run = fOwner->run(runIndex); 181cb93a386Sopenharmony_ci runLevels[runLevelsIndex++] = run.fBidiLevel; 182cb93a386Sopenharmony_ci fMaxRunMetrics.add( 183cb93a386Sopenharmony_ci InternalLineMetrics(run.correctAscent(), run.correctDescent(), run.fFontMetrics.fLeading)); 184cb93a386Sopenharmony_ci if (run.isPlaceholder()) { 185cb93a386Sopenharmony_ci placeholdersInOriginalOrder.push_back(runIndex); 186cb93a386Sopenharmony_ci } 187cb93a386Sopenharmony_ci } 188cb93a386Sopenharmony_ci SkASSERT(runLevelsIndex == numRuns); 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci SkAutoSTArray<kPreallocCount, int32_t> logicalOrder(numRuns); 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ci // TODO: hide all these logic in SkUnicode? 193cb93a386Sopenharmony_ci fOwner->getUnicode()->reorderVisual(runLevels.data(), numRuns, logicalOrder.data()); 194cb93a386Sopenharmony_ci auto firstRunIndex = start.runIndex(); 195cb93a386Sopenharmony_ci auto placeholderIter = placeholdersInOriginalOrder.begin(); 196cb93a386Sopenharmony_ci for (auto index : logicalOrder) { 197cb93a386Sopenharmony_ci auto runIndex = firstRunIndex + index; 198cb93a386Sopenharmony_ci if (fOwner->run(runIndex).isPlaceholder()) { 199cb93a386Sopenharmony_ci fRunsInVisualOrder.push_back(*placeholderIter++); 200cb93a386Sopenharmony_ci } else { 201cb93a386Sopenharmony_ci fRunsInVisualOrder.push_back(runIndex); 202cb93a386Sopenharmony_ci } 203cb93a386Sopenharmony_ci } 204cb93a386Sopenharmony_ci 205cb93a386Sopenharmony_ci fTextRangeReplacedByEllipsis = EMPTY_RANGE; 206cb93a386Sopenharmony_ci fEllipsisIndex = EMPTY_INDEX; 207cb93a386Sopenharmony_ci fLastClipRunLtr = false; 208cb93a386Sopenharmony_ci} 209cb93a386Sopenharmony_ci 210cb93a386Sopenharmony_civoid TextLine::paint(ParagraphPainter* painter, const RSPath* path, SkScalar hOffset, SkScalar vOffset) { 211cb93a386Sopenharmony_ci prepareRoundRect(); 212cb93a386Sopenharmony_ci fIsArcText = true; 213cb93a386Sopenharmony_ci if (pathParameters.hOffset != hOffset || pathParameters.vOffset != vOffset) { 214cb93a386Sopenharmony_ci fTextBlobCachePopulated = false; 215cb93a386Sopenharmony_ci } 216cb93a386Sopenharmony_ci pathParameters.recordPath = path; 217cb93a386Sopenharmony_ci pathParameters.hOffset = hOffset; 218cb93a386Sopenharmony_ci pathParameters.vOffset = vOffset; 219cb93a386Sopenharmony_ci this->ensureTextBlobCachePopulated(); 220cb93a386Sopenharmony_ci for (auto& record : fTextBlobCache) { 221cb93a386Sopenharmony_ci record.paint(painter); 222cb93a386Sopenharmony_ci } 223cb93a386Sopenharmony_ci} 224cb93a386Sopenharmony_ci 225cb93a386Sopenharmony_civoid TextLine::paint(ParagraphPainter* painter, SkScalar x, SkScalar y) { 226cb93a386Sopenharmony_ci prepareRoundRect(); 227cb93a386Sopenharmony_ci fIsArcText = false; 228cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 229cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_REPLACED_WORD, true, 230cb93a386Sopenharmony_ci#else 231cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(false, 232cb93a386Sopenharmony_ci#endif 233cb93a386Sopenharmony_ci [painter, x, y, this] 234cb93a386Sopenharmony_ci (const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) { 235cb93a386Sopenharmony_ci *runWidthInLine = this->iterateThroughSingleRunByStyles( 236cb93a386Sopenharmony_ci TextAdjustment::GlyphCluster, run, runOffsetInLine, textRange, StyleType::kBackground, 237cb93a386Sopenharmony_ci [painter, x, y, run, this](TextRange textRange, const TextStyle& style, const ClipContext& context) { 238cb93a386Sopenharmony_ci if (fHasBackground) { 239cb93a386Sopenharmony_ci this->paintBackground(painter, x, y, textRange, style, context); 240cb93a386Sopenharmony_ci } 241cb93a386Sopenharmony_ci paintRoundRect(painter, x, y, run); 242cb93a386Sopenharmony_ci }); 243cb93a386Sopenharmony_ci return true; 244cb93a386Sopenharmony_ci }); 245cb93a386Sopenharmony_ci 246cb93a386Sopenharmony_ci if (fHasShadows) { 247cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 248cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_REPLACED_WORD, false, 249cb93a386Sopenharmony_ci#else 250cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(false, 251cb93a386Sopenharmony_ci#endif 252cb93a386Sopenharmony_ci [painter, x, y, this] 253cb93a386Sopenharmony_ci (const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) { 254cb93a386Sopenharmony_ci *runWidthInLine = this->iterateThroughSingleRunByStyles( 255cb93a386Sopenharmony_ci TextAdjustment::GlyphCluster, run, runOffsetInLine, textRange, StyleType::kShadow, 256cb93a386Sopenharmony_ci [painter, x, y, this] 257cb93a386Sopenharmony_ci (TextRange textRange, const TextStyle& style, const ClipContext& context) { 258cb93a386Sopenharmony_ci this->paintShadow(painter, x, y, textRange, style, context); 259cb93a386Sopenharmony_ci }); 260cb93a386Sopenharmony_ci return true; 261cb93a386Sopenharmony_ci }); 262cb93a386Sopenharmony_ci } 263cb93a386Sopenharmony_ci 264cb93a386Sopenharmony_ci this->ensureTextBlobCachePopulated(); 265cb93a386Sopenharmony_ci 266cb93a386Sopenharmony_ci for (auto& record : fTextBlobCache) { 267cb93a386Sopenharmony_ci record.paint(painter, x, y); 268cb93a386Sopenharmony_ci } 269cb93a386Sopenharmony_ci 270cb93a386Sopenharmony_ci if (fHasDecorations) { 271cb93a386Sopenharmony_ci this->fDecorationContext = {0.0f, 0.0f, 0.0f}; 272cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 273cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(EllipsisReadStrategy::DEFAULT, true, 274cb93a386Sopenharmony_ci#else 275cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(false, 276cb93a386Sopenharmony_ci#endif 277cb93a386Sopenharmony_ci [painter, x, y, this] 278cb93a386Sopenharmony_ci (const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) { 279cb93a386Sopenharmony_ci *runWidthInLine = this->iterateThroughSingleRunByStyles( 280cb93a386Sopenharmony_ci TextAdjustment::GlyphCluster, run, runOffsetInLine, textRange, 281cb93a386Sopenharmony_ci StyleType::kDecorations, [painter, x, y, this] 282cb93a386Sopenharmony_ci (TextRange textRange, const TextStyle& style, const ClipContext& context) { 283cb93a386Sopenharmony_ci if (style.getDecoration().fType == TextDecoration::kUnderline) { 284cb93a386Sopenharmony_ci SkScalar tmpThick = this->calculateThickness(style, context); 285cb93a386Sopenharmony_ci fDecorationContext.thickness = fDecorationContext.thickness > tmpThick ? 286cb93a386Sopenharmony_ci fDecorationContext.thickness : tmpThick; 287cb93a386Sopenharmony_ci } 288cb93a386Sopenharmony_ci }); 289cb93a386Sopenharmony_ci return true; 290cb93a386Sopenharmony_ci }); 291cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 292cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(EllipsisReadStrategy::DEFAULT, true, 293cb93a386Sopenharmony_ci#else 294cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(false, 295cb93a386Sopenharmony_ci#endif 296cb93a386Sopenharmony_ci [painter, x, y, this] 297cb93a386Sopenharmony_ci (const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) { 298cb93a386Sopenharmony_ci *runWidthInLine = this->iterateThroughSingleRunByStyles( 299cb93a386Sopenharmony_ci TextAdjustment::GlyphCluster, run, runOffsetInLine, textRange, StyleType::kDecorations, 300cb93a386Sopenharmony_ci [painter, x, y, this] 301cb93a386Sopenharmony_ci (TextRange textRange, const TextStyle& style, const ClipContext& context) { 302cb93a386Sopenharmony_ci // 12% of row height. 303cb93a386Sopenharmony_ci fDecorationContext.underlinePosition = (fSizes.height() * 0.12 + this->baseline()); 304cb93a386Sopenharmony_ci fDecorationContext.textBlobTop = fSizes.height() * 0.12; 305cb93a386Sopenharmony_ci this->paintDecorations(painter, x, y, textRange, style, context); 306cb93a386Sopenharmony_ci }); 307cb93a386Sopenharmony_ci return true; 308cb93a386Sopenharmony_ci }); 309cb93a386Sopenharmony_ci } 310cb93a386Sopenharmony_ci} 311cb93a386Sopenharmony_ci 312cb93a386Sopenharmony_cibool TextLine::hasBackgroundRect(const RoundRectAttr& attr) { 313cb93a386Sopenharmony_ci return attr.roundRectStyle.color != 0 && attr.rect.width() > 0; 314cb93a386Sopenharmony_ci} 315cb93a386Sopenharmony_ci 316cb93a386Sopenharmony_civoid TextLine::computeRoundRect(int& index, int& preIndex, std::vector<Run*>& groupRuns, Run* run) { 317cb93a386Sopenharmony_ci int runCount = roundRectAttrs.size(); 318cb93a386Sopenharmony_ci if (index >= runCount) { 319cb93a386Sopenharmony_ci return; 320cb93a386Sopenharmony_ci } 321cb93a386Sopenharmony_ci 322cb93a386Sopenharmony_ci bool leftRound = false; 323cb93a386Sopenharmony_ci bool rightRound = false; 324cb93a386Sopenharmony_ci if (hasBackgroundRect(roundRectAttrs[index])) { 325cb93a386Sopenharmony_ci int styleId = roundRectAttrs[index].styleId; 326cb93a386Sopenharmony_ci // index - 1 is previous index, -1 is the invalid styleId 327cb93a386Sopenharmony_ci int preStyleId = index == 0 ? -1 : roundRectAttrs[index - 1].styleId; 328cb93a386Sopenharmony_ci // runCount - 1 is the last run index, index + 1 is next run index, -1 is the invalid styleId 329cb93a386Sopenharmony_ci int nextStyleId = index == runCount - 1 ? -1 : roundRectAttrs[index + 1].styleId; 330cb93a386Sopenharmony_ci // index - preIndex > 1 means the left run has no background rect 331cb93a386Sopenharmony_ci leftRound = (preIndex < 0 || index - preIndex > 1 || preStyleId != styleId); 332cb93a386Sopenharmony_ci // runCount - 1 is the last run index 333cb93a386Sopenharmony_ci rightRound = (index == runCount - 1 || !hasBackgroundRect(roundRectAttrs[index + 1]) || 334cb93a386Sopenharmony_ci nextStyleId != styleId); 335cb93a386Sopenharmony_ci preIndex = index; 336cb93a386Sopenharmony_ci groupRuns.push_back(run); 337cb93a386Sopenharmony_ci } else if (!groupRuns.empty()) { 338cb93a386Sopenharmony_ci groupRuns.erase(groupRuns.begin(), groupRuns.end()); 339cb93a386Sopenharmony_ci } 340cb93a386Sopenharmony_ci if (leftRound && rightRound) { 341cb93a386Sopenharmony_ci run->setRoundRectType(RoundRectType::ALL); 342cb93a386Sopenharmony_ci } else if (leftRound) { 343cb93a386Sopenharmony_ci run->setRoundRectType(RoundRectType::LEFT_ONLY); 344cb93a386Sopenharmony_ci } else if (rightRound) { 345cb93a386Sopenharmony_ci run->setRoundRectType(RoundRectType::RIGHT_ONLY); 346cb93a386Sopenharmony_ci } else { 347cb93a386Sopenharmony_ci run->setRoundRectType(RoundRectType::NONE); 348cb93a386Sopenharmony_ci } 349cb93a386Sopenharmony_ci 350cb93a386Sopenharmony_ci if (rightRound && !groupRuns.empty()) { 351cb93a386Sopenharmony_ci double maxRoundRectRadius = MAX_INT_VALUE; 352cb93a386Sopenharmony_ci double minTop = MAX_INT_VALUE; 353cb93a386Sopenharmony_ci double maxBottom = 0; 354cb93a386Sopenharmony_ci for (auto &gRun : groupRuns) { 355cb93a386Sopenharmony_ci RoundRectAttr& attr = roundRectAttrs[gRun->getIndexInLine()]; 356cb93a386Sopenharmony_ci maxRoundRectRadius = std::fmin(std::fmin(attr.rect.width(), attr.rect.height()), maxRoundRectRadius); 357cb93a386Sopenharmony_ci minTop = std::fmin(minTop, attr.rect.top()); 358cb93a386Sopenharmony_ci maxBottom = std::fmax(maxBottom, attr.rect.bottom()); 359cb93a386Sopenharmony_ci } 360cb93a386Sopenharmony_ci for (auto &gRun : groupRuns) { 361cb93a386Sopenharmony_ci gRun->setMaxRoundRectRadius(maxRoundRectRadius); 362cb93a386Sopenharmony_ci gRun->setTopInGroup(minTop - gRun->offset().y()); 363cb93a386Sopenharmony_ci gRun->setBottomInGroup(maxBottom - gRun->offset().y()); 364cb93a386Sopenharmony_ci } 365cb93a386Sopenharmony_ci groupRuns.erase(groupRuns.begin(), groupRuns.end()); 366cb93a386Sopenharmony_ci } 367cb93a386Sopenharmony_ci index++; 368cb93a386Sopenharmony_ci} 369cb93a386Sopenharmony_ci 370cb93a386Sopenharmony_civoid TextLine::prepareRoundRect() { 371cb93a386Sopenharmony_ci roundRectAttrs.clear(); 372cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 373cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_REPLACED_WORD, true, 374cb93a386Sopenharmony_ci#else 375cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(true, 376cb93a386Sopenharmony_ci#endif 377cb93a386Sopenharmony_ci [this](const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) { 378cb93a386Sopenharmony_ci *runWidthInLine = this->iterateThroughSingleRunByStyles( 379cb93a386Sopenharmony_ci TextAdjustment::GlyphCluster, run, runOffsetInLine, textRange, StyleType::kBackground, 380cb93a386Sopenharmony_ci [run, this](TextRange textRange, const TextStyle& style, const ClipContext& context) { 381cb93a386Sopenharmony_ci roundRectAttrs.push_back({style.getStyleId(), style.getBackgroundRect(), context.clip}); 382cb93a386Sopenharmony_ci }); 383cb93a386Sopenharmony_ci return true; 384cb93a386Sopenharmony_ci }); 385cb93a386Sopenharmony_ci 386cb93a386Sopenharmony_ci std::vector<Run*> groupRuns; 387cb93a386Sopenharmony_ci int index = 0; 388cb93a386Sopenharmony_ci int preIndex = -1; 389cb93a386Sopenharmony_ci for (auto& runIndex : fRunsInVisualOrder) { 390cb93a386Sopenharmony_ci auto run = &this->fOwner->run(runIndex); 391cb93a386Sopenharmony_ci run->setIndexInLine(static_cast<size_t>(index)); 392cb93a386Sopenharmony_ci computeRoundRect(index, preIndex, groupRuns, run); 393cb93a386Sopenharmony_ci } 394cb93a386Sopenharmony_ci} 395cb93a386Sopenharmony_ci 396cb93a386Sopenharmony_civoid TextLine::ensureTextBlobCachePopulated() { 397cb93a386Sopenharmony_ci if (fTextBlobCachePopulated && fArcTextState == fIsArcText) { 398cb93a386Sopenharmony_ci return; 399cb93a386Sopenharmony_ci } 400cb93a386Sopenharmony_ci fTextBlobCache.clear(); 401cb93a386Sopenharmony_ci if (fBlockRange.width() == 1 && 402cb93a386Sopenharmony_ci fRunsInVisualOrder.size() == 1 && 403cb93a386Sopenharmony_ci fEllipsis == nullptr && 404cb93a386Sopenharmony_ci fOwner->run(fRunsInVisualOrder[0]).placeholderStyle() == nullptr) { 405cb93a386Sopenharmony_ci if (fClusterRange.width() == 0) { 406cb93a386Sopenharmony_ci return; 407cb93a386Sopenharmony_ci } 408cb93a386Sopenharmony_ci // Most common and most simple case 409cb93a386Sopenharmony_ci const auto& style = fOwner->block(fBlockRange.start).fStyle; 410cb93a386Sopenharmony_ci const auto& run = fOwner->run(fRunsInVisualOrder[0]); 411cb93a386Sopenharmony_ci auto clip = SkRect::MakeXYWH(0.0f, this->sizes().runTop(&run, this->fAscentStyle), 412cb93a386Sopenharmony_ci fAdvance.fX, 413cb93a386Sopenharmony_ci run.calculateHeight(this->fAscentStyle, this->fDescentStyle)); 414cb93a386Sopenharmony_ci 415cb93a386Sopenharmony_ci auto& start = fOwner->cluster(fClusterRange.start); 416cb93a386Sopenharmony_ci auto& end = fOwner->cluster(fClusterRange.end - 1); 417cb93a386Sopenharmony_ci SkASSERT(start.runIndex() == end.runIndex()); 418cb93a386Sopenharmony_ci GlyphRange glyphs; 419cb93a386Sopenharmony_ci if (run.leftToRight()) { 420cb93a386Sopenharmony_ci glyphs = GlyphRange(start.startPos(), 421cb93a386Sopenharmony_ci end.isHardBreak() ? end.startPos() : end.endPos()); 422cb93a386Sopenharmony_ci } else { 423cb93a386Sopenharmony_ci glyphs = GlyphRange(end.startPos(), 424cb93a386Sopenharmony_ci start.isHardBreak() ? start.startPos() : start.endPos()); 425cb93a386Sopenharmony_ci } 426cb93a386Sopenharmony_ci ClipContext context = {/*run=*/&run, 427cb93a386Sopenharmony_ci /*pos=*/glyphs.start, 428cb93a386Sopenharmony_ci /*size=*/glyphs.width(), 429cb93a386Sopenharmony_ci /*fTextShift=*/-run.positionX(glyphs.start), // starting position 430cb93a386Sopenharmony_ci /*clip=*/clip, // entire line 431cb93a386Sopenharmony_ci /*fExcludedTrailingSpaces=*/0.0f, // no need for that 432cb93a386Sopenharmony_ci /*clippingNeeded=*/false}; // no need for that 433cb93a386Sopenharmony_ci this->buildTextBlob(fTextExcludingSpaces, style, context); 434cb93a386Sopenharmony_ci } else { 435cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 436cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_ELLIPSIS_WORD, false, 437cb93a386Sopenharmony_ci#else 438cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(false, 439cb93a386Sopenharmony_ci#endif 440cb93a386Sopenharmony_ci [this](const Run* run, 441cb93a386Sopenharmony_ci SkScalar runOffsetInLine, 442cb93a386Sopenharmony_ci TextRange textRange, 443cb93a386Sopenharmony_ci SkScalar* runWidthInLine) { 444cb93a386Sopenharmony_ci if (run->placeholderStyle() != nullptr) { 445cb93a386Sopenharmony_ci *runWidthInLine = run->advance().fX; 446cb93a386Sopenharmony_ci return true; 447cb93a386Sopenharmony_ci } 448cb93a386Sopenharmony_ci *runWidthInLine = this->iterateThroughSingleRunByStyles( 449cb93a386Sopenharmony_ci TextAdjustment::GlyphCluster, 450cb93a386Sopenharmony_ci run, 451cb93a386Sopenharmony_ci runOffsetInLine, 452cb93a386Sopenharmony_ci textRange, 453cb93a386Sopenharmony_ci StyleType::kForeground, 454cb93a386Sopenharmony_ci [this](TextRange textRange, const TextStyle& style, const ClipContext& context) { 455cb93a386Sopenharmony_ci this->buildTextBlob(textRange, style, context); 456cb93a386Sopenharmony_ci }); 457cb93a386Sopenharmony_ci return true; 458cb93a386Sopenharmony_ci }); 459cb93a386Sopenharmony_ci } 460cb93a386Sopenharmony_ci fTextBlobCachePopulated = true; 461cb93a386Sopenharmony_ci fArcTextState = fIsArcText; 462cb93a386Sopenharmony_ci pathParameters.recordPath = nullptr; 463cb93a386Sopenharmony_ci} 464cb93a386Sopenharmony_ci 465cb93a386Sopenharmony_civoid TextLine::format(TextAlign align, SkScalar maxWidth, EllipsisModal ellipsisModal) { 466cb93a386Sopenharmony_ci SkScalar delta = maxWidth - this->widthWithEllipsisSpaces(); 467cb93a386Sopenharmony_ci if (delta <= 0) { 468cb93a386Sopenharmony_ci return; 469cb93a386Sopenharmony_ci } 470cb93a386Sopenharmony_ci 471cb93a386Sopenharmony_ci // We do nothing for left align 472cb93a386Sopenharmony_ci if (align == TextAlign::kJustify) { 473cb93a386Sopenharmony_ci if (!this->endsWithHardLineBreak()) { 474cb93a386Sopenharmony_ci this->justify(maxWidth); 475cb93a386Sopenharmony_ci } else if (fOwner->paragraphStyle().getTextDirection() == TextDirection::kRtl) { 476cb93a386Sopenharmony_ci // Justify -> Right align 477cb93a386Sopenharmony_ci fShift = delta; 478cb93a386Sopenharmony_ci } 479cb93a386Sopenharmony_ci } else if (align == TextAlign::kRight) { 480cb93a386Sopenharmony_ci fShift = delta; 481cb93a386Sopenharmony_ci } else if (align == TextAlign::kCenter) { 482cb93a386Sopenharmony_ci fShift = delta / 2; 483cb93a386Sopenharmony_ci } 484cb93a386Sopenharmony_ci} 485cb93a386Sopenharmony_ci 486cb93a386Sopenharmony_ciSkScalar TextLine::calculateSpacing(const Cluster prevCluster, const Cluster curCluster) 487cb93a386Sopenharmony_ci{ 488cb93a386Sopenharmony_ci if (prevCluster.isWhitespaceBreak() || curCluster.isWhitespaceBreak()) { 489cb93a386Sopenharmony_ci return 0; 490cb93a386Sopenharmony_ci } 491cb93a386Sopenharmony_ci if (prevCluster.isHardBreak() || curCluster.isHardBreak()) { 492cb93a386Sopenharmony_ci return 0; 493cb93a386Sopenharmony_ci } 494cb93a386Sopenharmony_ci if (prevCluster.isCopyright() || curCluster.isCopyright()) { 495cb93a386Sopenharmony_ci return prevCluster.getFontSize() / AUTO_SPACING_WIDTH_RATIO; 496cb93a386Sopenharmony_ci } 497cb93a386Sopenharmony_ci if ((curCluster.isCJK() && prevCluster.isWestern()) || (curCluster.isWestern() && prevCluster.isCJK())) { 498cb93a386Sopenharmony_ci return prevCluster.getFontSize() / AUTO_SPACING_WIDTH_RATIO; 499cb93a386Sopenharmony_ci } 500cb93a386Sopenharmony_ci return 0; 501cb93a386Sopenharmony_ci} 502cb93a386Sopenharmony_ci 503cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 504cb93a386Sopenharmony_ciSkScalar TextLine::autoSpacing() { 505cb93a386Sopenharmony_ci if (!TextParameter::GetAutoSpacingEnable()) { 506cb93a386Sopenharmony_ci return 0; 507cb93a386Sopenharmony_ci } 508cb93a386Sopenharmony_ci SkScalar spacing = 0.0; 509cb93a386Sopenharmony_ci auto prevCluster = fOwner->cluster(fClusterRange.start); 510cb93a386Sopenharmony_ci for (auto clusterIndex = fClusterRange.start + 1; clusterIndex < fClusterRange.end; ++clusterIndex) { 511cb93a386Sopenharmony_ci auto prevSpacing = spacing; 512cb93a386Sopenharmony_ci auto& cluster = fOwner->cluster(clusterIndex); 513cb93a386Sopenharmony_ci spacing += calculateSpacing(prevCluster, cluster); 514cb93a386Sopenharmony_ci spacingCluster(&cluster, spacing, prevSpacing); 515cb93a386Sopenharmony_ci prevCluster = cluster; 516cb93a386Sopenharmony_ci } 517cb93a386Sopenharmony_ci this->fWidthWithSpaces += spacing; 518cb93a386Sopenharmony_ci this->fAdvance.fX += spacing; 519cb93a386Sopenharmony_ci return spacing; 520cb93a386Sopenharmony_ci} 521cb93a386Sopenharmony_ci#endif 522cb93a386Sopenharmony_ci 523cb93a386Sopenharmony_civoid TextLine::scanStyles(StyleType styleType, const RunStyleVisitor& visitor) { 524cb93a386Sopenharmony_ci if (this->empty()) { 525cb93a386Sopenharmony_ci return; 526cb93a386Sopenharmony_ci } 527cb93a386Sopenharmony_ci 528cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 529cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_REPLACED_WORD, false, 530cb93a386Sopenharmony_ci#else 531cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(false, 532cb93a386Sopenharmony_ci#endif 533cb93a386Sopenharmony_ci [this, visitor, styleType]( 534cb93a386Sopenharmony_ci const Run* run, SkScalar runOffset, TextRange textRange, SkScalar* width) { 535cb93a386Sopenharmony_ci *width = this->iterateThroughSingleRunByStyles( 536cb93a386Sopenharmony_ci TextAdjustment::GlyphCluster, 537cb93a386Sopenharmony_ci run, 538cb93a386Sopenharmony_ci runOffset, 539cb93a386Sopenharmony_ci textRange, 540cb93a386Sopenharmony_ci styleType, 541cb93a386Sopenharmony_ci [visitor](TextRange textRange, 542cb93a386Sopenharmony_ci const TextStyle& style, 543cb93a386Sopenharmony_ci const ClipContext& context) { 544cb93a386Sopenharmony_ci visitor(textRange, style, context); 545cb93a386Sopenharmony_ci }); 546cb93a386Sopenharmony_ci return true; 547cb93a386Sopenharmony_ci }); 548cb93a386Sopenharmony_ci} 549cb93a386Sopenharmony_ci 550cb93a386Sopenharmony_ciSkRect TextLine::extendHeight(const ClipContext& context) const { 551cb93a386Sopenharmony_ci SkRect result = context.clip; 552cb93a386Sopenharmony_ci result.fBottom += std::max(this->fMaxRunMetrics.height() - this->height(), 0.0f); 553cb93a386Sopenharmony_ci return result; 554cb93a386Sopenharmony_ci} 555cb93a386Sopenharmony_ci 556cb93a386Sopenharmony_civoid TextLine::buildTextBlob(TextRange textRange, const TextStyle& style, const ClipContext& context) { 557cb93a386Sopenharmony_ci if (context.run->placeholderStyle() != nullptr) { 558cb93a386Sopenharmony_ci return; 559cb93a386Sopenharmony_ci } 560cb93a386Sopenharmony_ci 561cb93a386Sopenharmony_ci fTextBlobCache.emplace_back(); 562cb93a386Sopenharmony_ci TextBlobRecord& record = fTextBlobCache.back(); 563cb93a386Sopenharmony_ci 564cb93a386Sopenharmony_ci if (style.hasForeground()) { 565cb93a386Sopenharmony_ci record.fPaint = style.getForegroundPaintOrID(); 566cb93a386Sopenharmony_ci } else { 567cb93a386Sopenharmony_ci std::get<SkPaint>(record.fPaint).setColor(style.getColor()); 568cb93a386Sopenharmony_ci } 569cb93a386Sopenharmony_ci record.fVisitor_Run = context.run; 570cb93a386Sopenharmony_ci record.fVisitor_Pos = context.pos; 571cb93a386Sopenharmony_ci record.fVisitor_Size = context.size; 572cb93a386Sopenharmony_ci 573cb93a386Sopenharmony_ci // TODO: This is the change for flutter, must be removed later 574cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 575cb93a386Sopenharmony_ci SkTextBlobBuilder builder; 576cb93a386Sopenharmony_ci#else 577cb93a386Sopenharmony_ci RSTextBlobBuilder builder; 578cb93a386Sopenharmony_ci#endif 579cb93a386Sopenharmony_ci if (pathParameters.recordPath) { 580cb93a386Sopenharmony_ci context.run->copyTo(builder, 581cb93a386Sopenharmony_ci pathParameters.recordPath, 582cb93a386Sopenharmony_ci pathParameters.hOffset, 583cb93a386Sopenharmony_ci pathParameters.vOffset, 584cb93a386Sopenharmony_ci context.fTextShift, 585cb93a386Sopenharmony_ci SkToU32(context.pos), 586cb93a386Sopenharmony_ci context.size); 587cb93a386Sopenharmony_ci } else { 588cb93a386Sopenharmony_ci context.run->copyTo(builder, SkToU32(context.pos), context.size); 589cb93a386Sopenharmony_ci } 590cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 591cb93a386Sopenharmony_ci // when letterspacing < 0, it causes the font is cliped. so the record fClippingNeeded is set false 592cb93a386Sopenharmony_ci#else 593cb93a386Sopenharmony_ci record.fClippingNeeded = context.clippingNeeded; 594cb93a386Sopenharmony_ci#endif 595cb93a386Sopenharmony_ci if (context.clippingNeeded) { 596cb93a386Sopenharmony_ci record.fClipRect = extendHeight(context).makeOffset(this->offset()); 597cb93a386Sopenharmony_ci } else { 598cb93a386Sopenharmony_ci record.fClipRect = context.clip.makeOffset(this->offset()); 599cb93a386Sopenharmony_ci } 600cb93a386Sopenharmony_ci 601cb93a386Sopenharmony_ci SkASSERT(nearlyEqual(context.run->baselineShift(), style.getBaselineShift())); 602cb93a386Sopenharmony_ci SkScalar correctedBaseline = SkScalarFloorToScalar(this->baseline() + style.getBaselineShift() + 0.5); 603cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 604cb93a386Sopenharmony_ci record.fBlob = builder.make(); 605cb93a386Sopenharmony_ci if (record.fBlob != nullptr) { 606cb93a386Sopenharmony_ci record.fBounds.joinPossiblyEmptyRect(record.fBlob->bounds()); 607cb93a386Sopenharmony_ci } 608cb93a386Sopenharmony_ci#else 609cb93a386Sopenharmony_ci record.fBlob = builder.Make(); 610cb93a386Sopenharmony_ci if (record.fBlob != nullptr) { 611cb93a386Sopenharmony_ci auto bounds = record.fBlob->Bounds(); 612cb93a386Sopenharmony_ci if (bounds) { 613cb93a386Sopenharmony_ci record.fBounds.joinPossiblyEmptyRect(SkRect::MakeLTRB( 614cb93a386Sopenharmony_ci bounds->left_, bounds->top_, bounds->right_, bounds->bottom_ 615cb93a386Sopenharmony_ci )); 616cb93a386Sopenharmony_ci } 617cb93a386Sopenharmony_ci } 618cb93a386Sopenharmony_ci#endif 619cb93a386Sopenharmony_ci 620cb93a386Sopenharmony_ci record.fOffset = SkPoint::Make(this->offset().fX + context.fTextShift, 621cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 622cb93a386Sopenharmony_ci this->offset().fY + correctedBaseline - (context.run ? context.run->fCompressionBaselineShift : 0)); 623cb93a386Sopenharmony_ci#else 624cb93a386Sopenharmony_ci this->offset().fY + correctedBaseline); 625cb93a386Sopenharmony_ci#endif 626cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 627cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 628cb93a386Sopenharmony_ci SkFont font; 629cb93a386Sopenharmony_ci#else 630cb93a386Sopenharmony_ci RSFont font; 631cb93a386Sopenharmony_ci#endif 632cb93a386Sopenharmony_ci if (record.fBlob != nullptr && record.fVisitor_Run != nullptr) { 633cb93a386Sopenharmony_ci font = record.fVisitor_Run->font(); 634cb93a386Sopenharmony_ci if (font.GetTypeface() != nullptr && 635cb93a386Sopenharmony_ci (font.GetTypeface()->GetFamilyName().find("Emoji") != std::string::npos || 636cb93a386Sopenharmony_ci font.GetTypeface()->GetFamilyName().find("emoji") != std::string::npos)) { 637cb93a386Sopenharmony_ci record.fBlob->SetEmoji(true); 638cb93a386Sopenharmony_ci } 639cb93a386Sopenharmony_ci } 640cb93a386Sopenharmony_ci#endif 641cb93a386Sopenharmony_ci} 642cb93a386Sopenharmony_ci 643cb93a386Sopenharmony_civoid TextLine::TextBlobRecord::paint(ParagraphPainter* painter, SkScalar x, SkScalar y) { 644cb93a386Sopenharmony_ci if (fClippingNeeded) { 645cb93a386Sopenharmony_ci painter->save(); 646cb93a386Sopenharmony_ci painter->clipRect(fClipRect.makeOffset(x, y)); 647cb93a386Sopenharmony_ci } 648cb93a386Sopenharmony_ci painter->drawTextBlob(fBlob, x + fOffset.x(), y + fOffset.y(), fPaint); 649cb93a386Sopenharmony_ci if (fClippingNeeded) { 650cb93a386Sopenharmony_ci painter->restore(); 651cb93a386Sopenharmony_ci } 652cb93a386Sopenharmony_ci} 653cb93a386Sopenharmony_ci 654cb93a386Sopenharmony_civoid TextLine::TextBlobRecord::paint(ParagraphPainter* painter) { 655cb93a386Sopenharmony_ci if (fClippingNeeded) { 656cb93a386Sopenharmony_ci painter->save(); 657cb93a386Sopenharmony_ci } 658cb93a386Sopenharmony_ci painter->drawTextBlob(fBlob, 0, 0, fPaint); 659cb93a386Sopenharmony_ci if (fClippingNeeded) { 660cb93a386Sopenharmony_ci painter->restore(); 661cb93a386Sopenharmony_ci } 662cb93a386Sopenharmony_ci} 663cb93a386Sopenharmony_ci 664cb93a386Sopenharmony_civoid TextLine::paintBackground(ParagraphPainter* painter, 665cb93a386Sopenharmony_ci SkScalar x, 666cb93a386Sopenharmony_ci SkScalar y, 667cb93a386Sopenharmony_ci TextRange textRange, 668cb93a386Sopenharmony_ci const TextStyle& style, 669cb93a386Sopenharmony_ci const ClipContext& context) const { 670cb93a386Sopenharmony_ci if (style.hasBackground()) { 671cb93a386Sopenharmony_ci painter->drawRect(context.clip.makeOffset(this->offset() + SkPoint::Make(x, y)), 672cb93a386Sopenharmony_ci style.getBackgroundPaintOrID()); 673cb93a386Sopenharmony_ci } 674cb93a386Sopenharmony_ci} 675cb93a386Sopenharmony_ci 676cb93a386Sopenharmony_civoid TextLine::paintRoundRect(ParagraphPainter* painter, SkScalar x, SkScalar y, const Run* run) const { 677cb93a386Sopenharmony_ci size_t index = run->getIndexInLine(); 678cb93a386Sopenharmony_ci if (index >= roundRectAttrs.size()) { 679cb93a386Sopenharmony_ci return; 680cb93a386Sopenharmony_ci } 681cb93a386Sopenharmony_ci 682cb93a386Sopenharmony_ci const RoundRectAttr& attr = roundRectAttrs[index]; 683cb93a386Sopenharmony_ci if (attr.roundRectStyle.color == 0) { 684cb93a386Sopenharmony_ci return; 685cb93a386Sopenharmony_ci } 686cb93a386Sopenharmony_ci 687cb93a386Sopenharmony_ci SkScalar ltRadius = 0.0f; 688cb93a386Sopenharmony_ci SkScalar rtRadius = 0.0f; 689cb93a386Sopenharmony_ci SkScalar rbRadius = 0.0f; 690cb93a386Sopenharmony_ci SkScalar lbRadius = 0.0f; 691cb93a386Sopenharmony_ci RoundRectType rType = run->getRoundRectType(); 692cb93a386Sopenharmony_ci if (rType == RoundRectType::ALL || rType == RoundRectType::LEFT_ONLY) { 693cb93a386Sopenharmony_ci ltRadius = std::fmin(attr.roundRectStyle.leftTopRadius, run->getMaxRoundRectRadius()); 694cb93a386Sopenharmony_ci lbRadius = std::fmin(attr.roundRectStyle.leftBottomRadius, run->getMaxRoundRectRadius()); 695cb93a386Sopenharmony_ci } 696cb93a386Sopenharmony_ci if (rType == RoundRectType::ALL || rType == RoundRectType::RIGHT_ONLY) { 697cb93a386Sopenharmony_ci rtRadius = std::fmin(attr.roundRectStyle.rightTopRadius, run->getMaxRoundRectRadius()); 698cb93a386Sopenharmony_ci rbRadius = std::fmin(attr.roundRectStyle.rightBottomRadius, run->getMaxRoundRectRadius()); 699cb93a386Sopenharmony_ci } 700cb93a386Sopenharmony_ci const SkVector radii[4] = {{ltRadius, ltRadius}, {rtRadius, rtRadius}, {rbRadius, rbRadius}, {lbRadius, lbRadius}}; 701cb93a386Sopenharmony_ci SkRect skRect(SkRect::MakeLTRB(attr.rect.left(), run->getTopInGroup(), attr.rect.right(), 702cb93a386Sopenharmony_ci run->getBottomInGroup())); 703cb93a386Sopenharmony_ci SkRRect skRRect; 704cb93a386Sopenharmony_ci skRRect.setRectRadii(skRect, radii); 705cb93a386Sopenharmony_ci skRRect.offset(x + this->offset().x(), y + this->offset().y()); 706cb93a386Sopenharmony_ci painter->drawRRect(skRRect, attr.roundRectStyle.color); 707cb93a386Sopenharmony_ci} 708cb93a386Sopenharmony_ci 709cb93a386Sopenharmony_civoid TextLine::paintShadow(ParagraphPainter* painter, 710cb93a386Sopenharmony_ci SkScalar x, 711cb93a386Sopenharmony_ci SkScalar y, 712cb93a386Sopenharmony_ci TextRange textRange, 713cb93a386Sopenharmony_ci const TextStyle& style, 714cb93a386Sopenharmony_ci const ClipContext& context) const { 715cb93a386Sopenharmony_ci SkScalar correctedBaseline = SkScalarFloorToScalar(this->baseline() + style.getBaselineShift() + 0.5); 716cb93a386Sopenharmony_ci 717cb93a386Sopenharmony_ci for (TextShadow shadow : style.getShadows()) { 718cb93a386Sopenharmony_ci if (!shadow.hasShadow()) continue; 719cb93a386Sopenharmony_ci 720cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 721cb93a386Sopenharmony_ci SkTextBlobBuilder builder; 722cb93a386Sopenharmony_ci#else 723cb93a386Sopenharmony_ci RSTextBlobBuilder builder; 724cb93a386Sopenharmony_ci#endif 725cb93a386Sopenharmony_ci context.run->copyTo(builder, context.pos, context.size); 726cb93a386Sopenharmony_ci 727cb93a386Sopenharmony_ci if (context.clippingNeeded) { 728cb93a386Sopenharmony_ci painter->save(); 729cb93a386Sopenharmony_ci SkRect clip = extendHeight(context); 730cb93a386Sopenharmony_ci clip.offset(x, y); 731cb93a386Sopenharmony_ci clip.offset(this->offset()); 732cb93a386Sopenharmony_ci painter->clipRect(clip); 733cb93a386Sopenharmony_ci } 734cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 735cb93a386Sopenharmony_ci auto blob = builder.make(); 736cb93a386Sopenharmony_ci#else 737cb93a386Sopenharmony_ci auto blob = builder.Make(); 738cb93a386Sopenharmony_ci#endif 739cb93a386Sopenharmony_ci painter->drawTextShadow(blob, 740cb93a386Sopenharmony_ci x + this->offset().fX + shadow.fOffset.x() + context.fTextShift, 741cb93a386Sopenharmony_ci y + this->offset().fY + shadow.fOffset.y() + correctedBaseline, 742cb93a386Sopenharmony_ci shadow.fColor, 743cb93a386Sopenharmony_ci SkDoubleToScalar(shadow.fBlurSigma)); 744cb93a386Sopenharmony_ci if (context.clippingNeeded) { 745cb93a386Sopenharmony_ci painter->restore(); 746cb93a386Sopenharmony_ci } 747cb93a386Sopenharmony_ci } 748cb93a386Sopenharmony_ci} 749cb93a386Sopenharmony_ci 750cb93a386Sopenharmony_ciSkScalar TextLine::calculateThickness(const TextStyle& style, const ClipContext& content) 751cb93a386Sopenharmony_ci{ 752cb93a386Sopenharmony_ci Decorations decoration; 753cb93a386Sopenharmony_ci return decoration.calculateThickness(style, content); 754cb93a386Sopenharmony_ci} 755cb93a386Sopenharmony_ci 756cb93a386Sopenharmony_civoid TextLine::paintDecorations(ParagraphPainter* painter, SkScalar x, SkScalar y, TextRange textRange, const TextStyle& style, const ClipContext& context) const { 757cb93a386Sopenharmony_ci ParagraphPainterAutoRestore ppar(painter); 758cb93a386Sopenharmony_ci painter->translate(x + this->offset().fX, y + this->offset().fY + style.getBaselineShift()); 759cb93a386Sopenharmony_ci Decorations decorations; 760cb93a386Sopenharmony_ci decorations.setDecorationContext(fDecorationContext); 761cb93a386Sopenharmony_ci SkScalar correctedBaseline = SkScalarFloorToScalar(-this->sizes().rawAscent() + style.getBaselineShift() + 0.5); 762cb93a386Sopenharmony_ci decorations.paint(painter, style, context, correctedBaseline); 763cb93a386Sopenharmony_ci} 764cb93a386Sopenharmony_ci 765cb93a386Sopenharmony_civoid TextLine::justify(SkScalar maxWidth) { 766cb93a386Sopenharmony_ci int whitespacePatches = 0; 767cb93a386Sopenharmony_ci SkScalar textLen = 0; 768cb93a386Sopenharmony_ci bool whitespacePatch = false; 769cb93a386Sopenharmony_ci // Take leading whitespaces width but do not increment a whitespace patch number 770cb93a386Sopenharmony_ci bool leadingWhitespaces = false; 771cb93a386Sopenharmony_ci this->iterateThroughClustersInGlyphsOrder(false, false, 772cb93a386Sopenharmony_ci [&](const Cluster* cluster, ClusterIndex index, bool ghost) { 773cb93a386Sopenharmony_ci if (cluster->isWhitespaceBreak()) { 774cb93a386Sopenharmony_ci if (index == 0) { 775cb93a386Sopenharmony_ci leadingWhitespaces = true; 776cb93a386Sopenharmony_ci } else if (!whitespacePatch && !leadingWhitespaces) { 777cb93a386Sopenharmony_ci // We only count patches BETWEEN words, not before 778cb93a386Sopenharmony_ci ++whitespacePatches; 779cb93a386Sopenharmony_ci } 780cb93a386Sopenharmony_ci whitespacePatch = !leadingWhitespaces; 781cb93a386Sopenharmony_ci } else if (cluster->isIdeographic()) { 782cb93a386Sopenharmony_ci // Whitespace break before and after 783cb93a386Sopenharmony_ci if (!whitespacePatch && index != 0) { 784cb93a386Sopenharmony_ci // We only count patches BETWEEN words, not before 785cb93a386Sopenharmony_ci ++whitespacePatches; // before 786cb93a386Sopenharmony_ci } 787cb93a386Sopenharmony_ci whitespacePatch = true; 788cb93a386Sopenharmony_ci leadingWhitespaces = false; 789cb93a386Sopenharmony_ci ++whitespacePatches; // after 790cb93a386Sopenharmony_ci } else { 791cb93a386Sopenharmony_ci whitespacePatch = false; 792cb93a386Sopenharmony_ci leadingWhitespaces = false; 793cb93a386Sopenharmony_ci } 794cb93a386Sopenharmony_ci textLen += cluster->width(); 795cb93a386Sopenharmony_ci return true; 796cb93a386Sopenharmony_ci }); 797cb93a386Sopenharmony_ci 798cb93a386Sopenharmony_ci if (whitespacePatch) { 799cb93a386Sopenharmony_ci // We only count patches BETWEEN words, not after 800cb93a386Sopenharmony_ci --whitespacePatches; 801cb93a386Sopenharmony_ci } 802cb93a386Sopenharmony_ci if (whitespacePatches == 0) { 803cb93a386Sopenharmony_ci if (fOwner->paragraphStyle().getTextDirection() == TextDirection::kRtl) { 804cb93a386Sopenharmony_ci // Justify -> Right align 805cb93a386Sopenharmony_ci fShift = maxWidth - textLen; 806cb93a386Sopenharmony_ci } 807cb93a386Sopenharmony_ci return; 808cb93a386Sopenharmony_ci } 809cb93a386Sopenharmony_ci 810cb93a386Sopenharmony_ci SkScalar step = (maxWidth - textLen) / whitespacePatches; 811cb93a386Sopenharmony_ci SkScalar shift = 0.0f; 812cb93a386Sopenharmony_ci SkScalar prevShift = 0.0f; 813cb93a386Sopenharmony_ci 814cb93a386Sopenharmony_ci // Deal with the ghost spaces 815cb93a386Sopenharmony_ci auto ghostShift = maxWidth - this->fAdvance.fX; 816cb93a386Sopenharmony_ci // Spread the extra whitespaces 817cb93a386Sopenharmony_ci whitespacePatch = false; 818cb93a386Sopenharmony_ci // Do not break on leading whitespaces 819cb93a386Sopenharmony_ci leadingWhitespaces = false; 820cb93a386Sopenharmony_ci this->iterateThroughClustersInGlyphsOrder(false, true, [&](const Cluster* cluster, ClusterIndex index, bool ghost) { 821cb93a386Sopenharmony_ci 822cb93a386Sopenharmony_ci if (ghost) { 823cb93a386Sopenharmony_ci if (cluster->run().leftToRight()) { 824cb93a386Sopenharmony_ci this->shiftCluster(cluster, ghostShift, ghostShift); 825cb93a386Sopenharmony_ci } 826cb93a386Sopenharmony_ci return true; 827cb93a386Sopenharmony_ci } 828cb93a386Sopenharmony_ci 829cb93a386Sopenharmony_ci if (cluster->isWhitespaceBreak()) { 830cb93a386Sopenharmony_ci if (index == 0) { 831cb93a386Sopenharmony_ci leadingWhitespaces = true; 832cb93a386Sopenharmony_ci } else if (!whitespacePatch && !leadingWhitespaces) { 833cb93a386Sopenharmony_ci shift += step; 834cb93a386Sopenharmony_ci whitespacePatch = true; 835cb93a386Sopenharmony_ci --whitespacePatches; 836cb93a386Sopenharmony_ci } 837cb93a386Sopenharmony_ci } else if (cluster->isIdeographic()) { 838cb93a386Sopenharmony_ci if (!whitespacePatch && index != 0) { 839cb93a386Sopenharmony_ci shift += step; 840cb93a386Sopenharmony_ci --whitespacePatches; 841cb93a386Sopenharmony_ci } 842cb93a386Sopenharmony_ci whitespacePatch = false; 843cb93a386Sopenharmony_ci leadingWhitespaces = false; 844cb93a386Sopenharmony_ci } else { 845cb93a386Sopenharmony_ci whitespacePatch = false; 846cb93a386Sopenharmony_ci leadingWhitespaces = false; 847cb93a386Sopenharmony_ci } 848cb93a386Sopenharmony_ci this->shiftCluster(cluster, shift, prevShift); 849cb93a386Sopenharmony_ci prevShift = shift; 850cb93a386Sopenharmony_ci // We skip ideographic whitespaces 851cb93a386Sopenharmony_ci if (!cluster->isWhitespaceBreak() && cluster->isIdeographic()) { 852cb93a386Sopenharmony_ci shift += step; 853cb93a386Sopenharmony_ci whitespacePatch = true; 854cb93a386Sopenharmony_ci --whitespacePatches; 855cb93a386Sopenharmony_ci } 856cb93a386Sopenharmony_ci return true; 857cb93a386Sopenharmony_ci }); 858cb93a386Sopenharmony_ci 859cb93a386Sopenharmony_ci if (whitespacePatch && whitespacePatches < 0) { 860cb93a386Sopenharmony_ci whitespacePatches++; 861cb93a386Sopenharmony_ci shift -= step; 862cb93a386Sopenharmony_ci } 863cb93a386Sopenharmony_ci 864cb93a386Sopenharmony_ci SkAssertResult(nearlyEqual(shift, maxWidth - textLen)); 865cb93a386Sopenharmony_ci SkASSERT(whitespacePatches == 0); 866cb93a386Sopenharmony_ci 867cb93a386Sopenharmony_ci this->fWidthWithSpaces += ghostShift; 868cb93a386Sopenharmony_ci this->fAdvance.fX = maxWidth; 869cb93a386Sopenharmony_ci} 870cb93a386Sopenharmony_ci 871cb93a386Sopenharmony_civoid TextLine::shiftCluster(const Cluster* cluster, SkScalar shift, SkScalar prevShift) { 872cb93a386Sopenharmony_ci 873cb93a386Sopenharmony_ci auto& run = cluster->run(); 874cb93a386Sopenharmony_ci auto start = cluster->startPos(); 875cb93a386Sopenharmony_ci auto end = cluster->endPos(); 876cb93a386Sopenharmony_ci 877cb93a386Sopenharmony_ci if (end == run.size()) { 878cb93a386Sopenharmony_ci // Set the same shift for the fake last glyph (to avoid all extra checks) 879cb93a386Sopenharmony_ci ++end; 880cb93a386Sopenharmony_ci } 881cb93a386Sopenharmony_ci 882cb93a386Sopenharmony_ci if (run.fJustificationShifts.empty()) { 883cb93a386Sopenharmony_ci // Do not fill this array until needed 884cb93a386Sopenharmony_ci run.fJustificationShifts.push_back_n(run.size() + 1, { 0, 0 }); 885cb93a386Sopenharmony_ci } 886cb93a386Sopenharmony_ci 887cb93a386Sopenharmony_ci for (size_t pos = start; pos < end; ++pos) { 888cb93a386Sopenharmony_ci run.fJustificationShifts[pos] = { shift, prevShift }; 889cb93a386Sopenharmony_ci } 890cb93a386Sopenharmony_ci} 891cb93a386Sopenharmony_ci 892cb93a386Sopenharmony_civoid TextLine::spacingCluster(const Cluster* cluster, SkScalar spacing, SkScalar prevSpacing) { 893cb93a386Sopenharmony_ci auto& run = cluster->run(); 894cb93a386Sopenharmony_ci auto start = cluster->startPos(); 895cb93a386Sopenharmony_ci auto end = cluster->endPos(); 896cb93a386Sopenharmony_ci if (end == run.size()) { 897cb93a386Sopenharmony_ci // Set the same shift for the fake last glyph (to avoid all extra checks) 898cb93a386Sopenharmony_ci ++end; 899cb93a386Sopenharmony_ci } 900cb93a386Sopenharmony_ci 901cb93a386Sopenharmony_ci if (run.fAutoSpacings.empty()) { 902cb93a386Sopenharmony_ci // Do not fill this array until needed 903cb93a386Sopenharmony_ci run.fAutoSpacings.push_back_n(run.size() + 1, { 0, 0 }); 904cb93a386Sopenharmony_ci } 905cb93a386Sopenharmony_ci 906cb93a386Sopenharmony_ci for (size_t pos = start; pos < end; ++pos) { 907cb93a386Sopenharmony_ci run.fAutoSpacings[pos] = { spacing, prevSpacing}; 908cb93a386Sopenharmony_ci } 909cb93a386Sopenharmony_ci} 910cb93a386Sopenharmony_ci 911cb93a386Sopenharmony_civoid TextLine::countWord(int& wordCount, bool& inWord) { 912cb93a386Sopenharmony_ci for (auto clusterIndex = fGhostClusterRange.start; clusterIndex < fGhostClusterRange.end; ++clusterIndex) { 913cb93a386Sopenharmony_ci auto& cluster = fOwner->cluster(clusterIndex); 914cb93a386Sopenharmony_ci if (cluster.isWordBreak()) { 915cb93a386Sopenharmony_ci inWord = false; 916cb93a386Sopenharmony_ci } else if (!inWord) { 917cb93a386Sopenharmony_ci ++wordCount; 918cb93a386Sopenharmony_ci inWord = true; 919cb93a386Sopenharmony_ci } 920cb93a386Sopenharmony_ci } 921cb93a386Sopenharmony_ci} 922cb93a386Sopenharmony_ci 923cb93a386Sopenharmony_civoid TextLine::ellipsisNotFitProcess(EllipsisModal ellipsisModal) { 924cb93a386Sopenharmony_ci if (fEllipsis) { 925cb93a386Sopenharmony_ci return; 926cb93a386Sopenharmony_ci } 927cb93a386Sopenharmony_ci 928cb93a386Sopenharmony_ci // Weird situation: ellipsis does not fit; no ellipsis then 929cb93a386Sopenharmony_ci switch (ellipsisModal) { 930cb93a386Sopenharmony_ci case EllipsisModal::TAIL: 931cb93a386Sopenharmony_ci fClusterRange.end = fClusterRange.start; 932cb93a386Sopenharmony_ci fGhostClusterRange.end = fClusterRange.start; 933cb93a386Sopenharmony_ci fText.end = fText.start; 934cb93a386Sopenharmony_ci fTextIncludingNewlines.end = fTextIncludingNewlines.start; 935cb93a386Sopenharmony_ci fTextExcludingSpaces.end = fTextExcludingSpaces.start; 936cb93a386Sopenharmony_ci fAdvance.fX = 0; 937cb93a386Sopenharmony_ci break; 938cb93a386Sopenharmony_ci case EllipsisModal::HEAD: 939cb93a386Sopenharmony_ci fClusterRange.start = fClusterRange.end; 940cb93a386Sopenharmony_ci fGhostClusterRange.start = fClusterRange.end; 941cb93a386Sopenharmony_ci fText.start = fText.end; 942cb93a386Sopenharmony_ci fTextIncludingNewlines.start = fTextIncludingNewlines.end; 943cb93a386Sopenharmony_ci fTextExcludingSpaces.start = fTextExcludingSpaces.end; 944cb93a386Sopenharmony_ci fAdvance.fX = 0; 945cb93a386Sopenharmony_ci break; 946cb93a386Sopenharmony_ci default: 947cb93a386Sopenharmony_ci return; 948cb93a386Sopenharmony_ci } 949cb93a386Sopenharmony_ci} 950cb93a386Sopenharmony_ci 951cb93a386Sopenharmony_civoid TextLine::createTailEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr, WordBreakType wordBreakType) { 952cb93a386Sopenharmony_ci // Replace some clusters with the ellipsis 953cb93a386Sopenharmony_ci // Go through the clusters in the reverse logical order 954cb93a386Sopenharmony_ci // taking off cluster by cluster until the ellipsis fits 955cb93a386Sopenharmony_ci SkScalar width = fAdvance.fX; 956cb93a386Sopenharmony_ci RunIndex lastRun = EMPTY_RUN; 957cb93a386Sopenharmony_ci std::unique_ptr<Run> ellipsisRun; 958cb93a386Sopenharmony_ci int wordCount = 0; 959cb93a386Sopenharmony_ci bool inWord = false; 960cb93a386Sopenharmony_ci 961cb93a386Sopenharmony_ci countWord(wordCount, inWord); 962cb93a386Sopenharmony_ci 963cb93a386Sopenharmony_ci bool iterForWord = false; 964cb93a386Sopenharmony_ci 965cb93a386Sopenharmony_ci for (auto clusterIndex = fGhostClusterRange.end; clusterIndex > fGhostClusterRange.start; --clusterIndex) { 966cb93a386Sopenharmony_ci auto& cluster = fOwner->cluster(clusterIndex - 1); 967cb93a386Sopenharmony_ci // Shape the ellipsis if the run has changed 968cb93a386Sopenharmony_ci if (lastRun != cluster.runIndex()) { 969cb93a386Sopenharmony_ci ellipsisRun = this->shapeEllipsis(ellipsis, &cluster); 970cb93a386Sopenharmony_ci // We may need to continue 971cb93a386Sopenharmony_ci lastRun = cluster.runIndex(); 972cb93a386Sopenharmony_ci } 973cb93a386Sopenharmony_ci 974cb93a386Sopenharmony_ci if (!cluster.isWordBreak()) { 975cb93a386Sopenharmony_ci inWord = true; 976cb93a386Sopenharmony_ci } else if (inWord) { 977cb93a386Sopenharmony_ci --wordCount; 978cb93a386Sopenharmony_ci inWord = false; 979cb93a386Sopenharmony_ci } 980cb93a386Sopenharmony_ci // See if it fits 981cb93a386Sopenharmony_ci if (width + ellipsisRun->advance().fX > maxWidth) { 982cb93a386Sopenharmony_ci if (!cluster.isHardBreak()) { 983cb93a386Sopenharmony_ci width -= cluster.width(); 984cb93a386Sopenharmony_ci } 985cb93a386Sopenharmony_ci // Continue if the ellipsis does not fit 986cb93a386Sopenharmony_ci iterForWord = (wordCount != 1 && wordBreakType != WordBreakType::BREAK_ALL && !cluster.isWordBreak()); 987cb93a386Sopenharmony_ci if (std::floor(width) > 0) { 988cb93a386Sopenharmony_ci continue; 989cb93a386Sopenharmony_ci } 990cb93a386Sopenharmony_ci } 991cb93a386Sopenharmony_ci 992cb93a386Sopenharmony_ci if (iterForWord && !cluster.isWordBreak()) { 993cb93a386Sopenharmony_ci width -= cluster.width(); 994cb93a386Sopenharmony_ci if (std::floor(width) > 0) { 995cb93a386Sopenharmony_ci continue; 996cb93a386Sopenharmony_ci } 997cb93a386Sopenharmony_ci } 998cb93a386Sopenharmony_ci 999cb93a386Sopenharmony_ci // Get the last run directions after clipping 1000cb93a386Sopenharmony_ci fEllipsisIndex = cluster.runIndex(); 1001cb93a386Sopenharmony_ci fLastClipRunLtr = fOwner->run(fEllipsisIndex).leftToRight(); 1002cb93a386Sopenharmony_ci 1003cb93a386Sopenharmony_ci // We found enough room for the ellipsis 1004cb93a386Sopenharmony_ci fAdvance.fX = width; 1005cb93a386Sopenharmony_ci fEllipsis = std::move(ellipsisRun); 1006cb93a386Sopenharmony_ci fEllipsis->setOwner(fOwner); 1007cb93a386Sopenharmony_ci fTextRangeReplacedByEllipsis = TextRange(cluster.textRange().end, fOwner->text().size()); 1008cb93a386Sopenharmony_ci 1009cb93a386Sopenharmony_ci // Let's update the line 1010cb93a386Sopenharmony_ci fClusterRange.end = clusterIndex; 1011cb93a386Sopenharmony_ci fGhostClusterRange.end = fClusterRange.end; 1012cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1013cb93a386Sopenharmony_ci fEllipsis->fTextRange = 1014cb93a386Sopenharmony_ci TextRange(cluster.textRange().end, cluster.textRange().end + ellipsis.size()); 1015cb93a386Sopenharmony_ci fEllipsis->fClusterStart = cluster.textRange().end; 1016cb93a386Sopenharmony_ci#else 1017cb93a386Sopenharmony_ci fEllipsis->fClusterStart = cluster.textRange().start; 1018cb93a386Sopenharmony_ci#endif 1019cb93a386Sopenharmony_ci fText.end = cluster.textRange().end; 1020cb93a386Sopenharmony_ci fTextIncludingNewlines.end = cluster.textRange().end; 1021cb93a386Sopenharmony_ci fTextExcludingSpaces.end = cluster.textRange().end; 1022cb93a386Sopenharmony_ci 1023cb93a386Sopenharmony_ci if (SkScalarNearlyZero(width)) { 1024cb93a386Sopenharmony_ci fRunsInVisualOrder.reset(); 1025cb93a386Sopenharmony_ci } 1026cb93a386Sopenharmony_ci 1027cb93a386Sopenharmony_ci break; 1028cb93a386Sopenharmony_ci } 1029cb93a386Sopenharmony_ci 1030cb93a386Sopenharmony_ci fWidthWithSpaces = width; 1031cb93a386Sopenharmony_ci 1032cb93a386Sopenharmony_ci ellipsisNotFitProcess(EllipsisModal::TAIL); 1033cb93a386Sopenharmony_ci} 1034cb93a386Sopenharmony_ci 1035cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1036cb93a386Sopenharmony_civoid TextLine::createHeadEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool) { 1037cb93a386Sopenharmony_ci if (fAdvance.fX <= maxWidth) { 1038cb93a386Sopenharmony_ci return; 1039cb93a386Sopenharmony_ci } 1040cb93a386Sopenharmony_ci SkScalar width = fAdvance.fX; 1041cb93a386Sopenharmony_ci std::unique_ptr<Run> ellipsisRun; 1042cb93a386Sopenharmony_ci RunIndex lastRun = EMPTY_RUN; 1043cb93a386Sopenharmony_ci for (auto clusterIndex = fGhostClusterRange.start; clusterIndex < fGhostClusterRange.end; ++clusterIndex) { 1044cb93a386Sopenharmony_ci auto& cluster = fOwner->cluster(clusterIndex); 1045cb93a386Sopenharmony_ci // Shape the ellipsis if the run has changed 1046cb93a386Sopenharmony_ci if (lastRun != cluster.runIndex()) { 1047cb93a386Sopenharmony_ci ellipsisRun = this->shapeEllipsis(ellipsis, &cluster); 1048cb93a386Sopenharmony_ci // We may need to continue 1049cb93a386Sopenharmony_ci lastRun = cluster.runIndex(); 1050cb93a386Sopenharmony_ci } 1051cb93a386Sopenharmony_ci // See if it fits 1052cb93a386Sopenharmony_ci if (width + ellipsisRun->advance().fX > maxWidth) { 1053cb93a386Sopenharmony_ci width -= cluster.width(); 1054cb93a386Sopenharmony_ci // Continue if the ellipsis does not fit 1055cb93a386Sopenharmony_ci if (std::floor(width) > 0) { 1056cb93a386Sopenharmony_ci continue; 1057cb93a386Sopenharmony_ci } 1058cb93a386Sopenharmony_ci } 1059cb93a386Sopenharmony_ci 1060cb93a386Sopenharmony_ci // Get the last run directions after clipping 1061cb93a386Sopenharmony_ci fEllipsisIndex = cluster.runIndex(); 1062cb93a386Sopenharmony_ci fLastClipRunLtr = fOwner->run(fEllipsisIndex).leftToRight(); 1063cb93a386Sopenharmony_ci 1064cb93a386Sopenharmony_ci // We found enough room for the ellipsis 1065cb93a386Sopenharmony_ci fAdvance.fX = width + ellipsisRun->advance().fX; 1066cb93a386Sopenharmony_ci fEllipsis = std::move(ellipsisRun); 1067cb93a386Sopenharmony_ci fEllipsis->setOwner(fOwner); 1068cb93a386Sopenharmony_ci fTextRangeReplacedByEllipsis = TextRange(0, cluster.textRange().start); 1069cb93a386Sopenharmony_ci fClusterRange.start = clusterIndex; 1070cb93a386Sopenharmony_ci fGhostClusterRange.start = fClusterRange.start; 1071cb93a386Sopenharmony_ci fEllipsis->fClusterStart = 0; 1072cb93a386Sopenharmony_ci fText.start = cluster.textRange().start; 1073cb93a386Sopenharmony_ci fTextIncludingNewlines.start = cluster.textRange().start; 1074cb93a386Sopenharmony_ci fTextExcludingSpaces.start = cluster.textRange().start; 1075cb93a386Sopenharmony_ci break; 1076cb93a386Sopenharmony_ci } 1077cb93a386Sopenharmony_ci 1078cb93a386Sopenharmony_ci fWidthWithSpaces = width; 1079cb93a386Sopenharmony_ci 1080cb93a386Sopenharmony_ci ellipsisNotFitProcess(EllipsisModal::HEAD); 1081cb93a386Sopenharmony_ci} 1082cb93a386Sopenharmony_ci#endif 1083cb93a386Sopenharmony_ci 1084cb93a386Sopenharmony_cistatic inline SkUnichar nextUtf8Unit(const char** ptr, const char* end) { 1085cb93a386Sopenharmony_ci SkUnichar val = SkUTF::NextUTF8(ptr, end); 1086cb93a386Sopenharmony_ci return val < 0 ? 0xFFFD : val; 1087cb93a386Sopenharmony_ci} 1088cb93a386Sopenharmony_ci 1089cb93a386Sopenharmony_cistd::unique_ptr<Run> TextLine::shapeEllipsis(const SkString& ellipsis, const Cluster* cluster) { 1090cb93a386Sopenharmony_ci 1091cb93a386Sopenharmony_ci class ShapeHandler final : public SkShaper::RunHandler { 1092cb93a386Sopenharmony_ci public: 1093cb93a386Sopenharmony_ci ShapeHandler(SkScalar lineHeight, bool useHalfLeading, SkScalar baselineShift, const SkString& ellipsis) 1094cb93a386Sopenharmony_ci : fRun(nullptr), fLineHeight(lineHeight), fUseHalfLeading(useHalfLeading), fBaselineShift(baselineShift), fEllipsis(ellipsis) {} 1095cb93a386Sopenharmony_ci std::unique_ptr<Run> run() & { return std::move(fRun); } 1096cb93a386Sopenharmony_ci 1097cb93a386Sopenharmony_ci private: 1098cb93a386Sopenharmony_ci void beginLine() override {} 1099cb93a386Sopenharmony_ci 1100cb93a386Sopenharmony_ci void runInfo(const RunInfo&) override {} 1101cb93a386Sopenharmony_ci 1102cb93a386Sopenharmony_ci void commitRunInfo() override {} 1103cb93a386Sopenharmony_ci 1104cb93a386Sopenharmony_ci Buffer runBuffer(const RunInfo& info) override { 1105cb93a386Sopenharmony_ci SkASSERT(!fRun); 1106cb93a386Sopenharmony_ci fRun = std::make_unique<Run>(nullptr, info, 0, fLineHeight, fUseHalfLeading, fBaselineShift, 0, 0); 1107cb93a386Sopenharmony_ci return fRun->newRunBuffer(); 1108cb93a386Sopenharmony_ci } 1109cb93a386Sopenharmony_ci 1110cb93a386Sopenharmony_ci void commitRunBuffer(const RunInfo& info) override { 1111cb93a386Sopenharmony_ci fRun->fAdvance.fX = info.fAdvance.fX; 1112cb93a386Sopenharmony_ci fRun->fAdvance.fY = fRun->advance().fY; 1113cb93a386Sopenharmony_ci fRun->fPlaceholderIndex = std::numeric_limits<size_t>::max(); 1114cb93a386Sopenharmony_ci fRun->fEllipsis = true; 1115cb93a386Sopenharmony_ci } 1116cb93a386Sopenharmony_ci 1117cb93a386Sopenharmony_ci void commitLine() override {} 1118cb93a386Sopenharmony_ci 1119cb93a386Sopenharmony_ci std::unique_ptr<Run> fRun; 1120cb93a386Sopenharmony_ci SkScalar fLineHeight; 1121cb93a386Sopenharmony_ci bool fUseHalfLeading; 1122cb93a386Sopenharmony_ci SkScalar fBaselineShift; 1123cb93a386Sopenharmony_ci SkString fEllipsis; 1124cb93a386Sopenharmony_ci }; 1125cb93a386Sopenharmony_ci 1126cb93a386Sopenharmony_ci const Run& run = cluster->run(); 1127cb93a386Sopenharmony_ci TextStyle textStyle = fOwner->paragraphStyle().getTextStyle(); 1128cb93a386Sopenharmony_ci for (auto i = fBlockRange.start; i < fBlockRange.end; ++i) { 1129cb93a386Sopenharmony_ci auto& block = fOwner->block(i); 1130cb93a386Sopenharmony_ci if (run.leftToRight() && cluster->textRange().end <= block.fRange.end) { 1131cb93a386Sopenharmony_ci textStyle = block.fStyle; 1132cb93a386Sopenharmony_ci break; 1133cb93a386Sopenharmony_ci } else if (!run.leftToRight() && cluster->textRange().start <= block.fRange.end) { 1134cb93a386Sopenharmony_ci textStyle = block.fStyle; 1135cb93a386Sopenharmony_ci break; 1136cb93a386Sopenharmony_ci } 1137cb93a386Sopenharmony_ci } 1138cb93a386Sopenharmony_ci 1139cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 1140cb93a386Sopenharmony_ci auto shaped = [&](sk_sp<SkTypeface> typeface, bool fallback) -> std::unique_ptr<Run> { 1141cb93a386Sopenharmony_ci#else 1142cb93a386Sopenharmony_ci auto shaped = [&](std::shared_ptr<RSTypeface> typeface, bool fallback) -> std::unique_ptr<Run> { 1143cb93a386Sopenharmony_ci#endif 1144cb93a386Sopenharmony_ci ShapeHandler handler(run.heightMultiplier(), run.useHalfLeading(), run.baselineShift(), ellipsis); 1145cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 1146cb93a386Sopenharmony_ci SkFont font(typeface, textStyle.getFontSize()); 1147cb93a386Sopenharmony_ci font.setEdging(SkFont::Edging::kAntiAlias); 1148cb93a386Sopenharmony_ci font.setHinting(SkFontHinting::kSlight); 1149cb93a386Sopenharmony_ci font.setSubpixel(true); 1150cb93a386Sopenharmony_ci#else 1151cb93a386Sopenharmony_ci RSFont font(typeface, textStyle.getFontSize(), 1, 0); 1152cb93a386Sopenharmony_ci font.SetEdging(RSDrawing::FontEdging::ANTI_ALIAS); 1153cb93a386Sopenharmony_ci font.SetHinting(RSDrawing::FontHinting::SLIGHT); 1154cb93a386Sopenharmony_ci font.SetSubpixel(true); 1155cb93a386Sopenharmony_ci#endif 1156cb93a386Sopenharmony_ci 1157cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 1158cb93a386Sopenharmony_ci std::unique_ptr<SkShaper> shaper = SkShaper::MakeShapeDontWrapOrReorder( 1159cb93a386Sopenharmony_ci fOwner->getUnicode()->copy(), 1160cb93a386Sopenharmony_ci fallback ? SkFontMgr::RefDefault() : SkFontMgr::RefEmpty()); 1161cb93a386Sopenharmony_ci#else 1162cb93a386Sopenharmony_ci std::unique_ptr<SkShaper> shaper = SkShaper::MakeShapeDontWrapOrReorder( 1163cb93a386Sopenharmony_ci fOwner->getUnicode()->copy(), 1164cb93a386Sopenharmony_ci fallback ? RSFontMgr::CreateDefaultFontMgr() : RSFontMgr::CreateDefaultFontMgr()); 1165cb93a386Sopenharmony_ci#endif 1166cb93a386Sopenharmony_ci shaper->shape(ellipsis.c_str(), 1167cb93a386Sopenharmony_ci ellipsis.size(), 1168cb93a386Sopenharmony_ci font, 1169cb93a386Sopenharmony_ci true, 1170cb93a386Sopenharmony_ci std::numeric_limits<SkScalar>::max(), 1171cb93a386Sopenharmony_ci &handler); 1172cb93a386Sopenharmony_ci auto ellipsisRun = handler.run(); 1173cb93a386Sopenharmony_ci ellipsisRun->fTextRange = TextRange(0, ellipsis.size()); 1174cb93a386Sopenharmony_ci ellipsisRun->fOwner = fOwner; 1175cb93a386Sopenharmony_ci return ellipsisRun; 1176cb93a386Sopenharmony_ci }; 1177cb93a386Sopenharmony_ci 1178cb93a386Sopenharmony_ci // Check all allowed fonts 1179cb93a386Sopenharmony_ci auto typefaces = fOwner->fontCollection()->findTypefaces( 1180cb93a386Sopenharmony_ci textStyle.getFontFamilies(), textStyle.getFontStyle(), textStyle.getFontArguments()); 1181cb93a386Sopenharmony_ci for (const auto& typeface : typefaces) { 1182cb93a386Sopenharmony_ci auto ellipsisRun = shaped(typeface, false); 1183cb93a386Sopenharmony_ci if (ellipsisRun->isResolved()) { 1184cb93a386Sopenharmony_ci return ellipsisRun; 1185cb93a386Sopenharmony_ci } 1186cb93a386Sopenharmony_ci } 1187cb93a386Sopenharmony_ci 1188cb93a386Sopenharmony_ci // Try the fallback 1189cb93a386Sopenharmony_ci if (fOwner->fontCollection()->fontFallbackEnabled()) { 1190cb93a386Sopenharmony_ci const char* ch = ellipsis.c_str(); 1191cb93a386Sopenharmony_ci SkUnichar unicode = nextUtf8Unit(&ch, ellipsis.c_str() + ellipsis.size()); 1192cb93a386Sopenharmony_ci 1193cb93a386Sopenharmony_ci auto typeface = fOwner->fontCollection()->defaultFallback( 1194cb93a386Sopenharmony_ci unicode, textStyle.getFontStyle(), textStyle.getLocale()); 1195cb93a386Sopenharmony_ci if (typeface) { 1196cb93a386Sopenharmony_ci if (textStyle.getFontArguments()) { 1197cb93a386Sopenharmony_ci typeface = fOwner->fontCollection()->CloneTypeface(typeface, textStyle.getFontArguments()); 1198cb93a386Sopenharmony_ci } 1199cb93a386Sopenharmony_ci auto ellipsisRun = shaped(typeface, true); 1200cb93a386Sopenharmony_ci if (ellipsisRun->isResolved()) { 1201cb93a386Sopenharmony_ci return ellipsisRun; 1202cb93a386Sopenharmony_ci } 1203cb93a386Sopenharmony_ci } 1204cb93a386Sopenharmony_ci } 1205cb93a386Sopenharmony_ci 1206cb93a386Sopenharmony_ci // Check the current font 1207cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 1208cb93a386Sopenharmony_ci auto ellipsisRun = shaped(run.fFont.refTypeface(), false); 1209cb93a386Sopenharmony_ci#else 1210cb93a386Sopenharmony_ci auto ellipsisRun = shaped(const_cast<RSFont&>(run.fFont).GetTypeface(), false); 1211cb93a386Sopenharmony_ci#endif 1212cb93a386Sopenharmony_ci if (ellipsisRun->isResolved()) { 1213cb93a386Sopenharmony_ci return ellipsisRun; 1214cb93a386Sopenharmony_ci } 1215cb93a386Sopenharmony_ci return ellipsisRun; 1216cb93a386Sopenharmony_ci} 1217cb93a386Sopenharmony_ci 1218cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1219cb93a386Sopenharmony_civoid TextLine::measureTextWithSpacesAtTheEnd(ClipContext& context, bool includeGhostSpaces) const 1220cb93a386Sopenharmony_ci{ 1221cb93a386Sopenharmony_ci if (compareRound(context.clip.fRight, fAdvance.fX, fOwner->getApplyRoundingHack()) > 0 && !includeGhostSpaces && 1222cb93a386Sopenharmony_ci fAdvance.fX > 0) { 1223cb93a386Sopenharmony_ci // There are few cases when we need it. 1224cb93a386Sopenharmony_ci // The most important one: we measure the text with spaces at the end (or at the beginning in RTL) 1225cb93a386Sopenharmony_ci // and we should ignore these spaces 1226cb93a386Sopenharmony_ci if (fOwner->paragraphStyle().getTextDirection() == TextDirection::kLtr) { 1227cb93a386Sopenharmony_ci // We only use this member for LTR 1228cb93a386Sopenharmony_ci context.fExcludedTrailingSpaces = std::max(context.clip.fRight - fAdvance.fX, 0.0f); 1229cb93a386Sopenharmony_ci context.clippingNeeded = true; 1230cb93a386Sopenharmony_ci context.clip.fRight = fAdvance.fX; 1231cb93a386Sopenharmony_ci } 1232cb93a386Sopenharmony_ci } 1233cb93a386Sopenharmony_ci} 1234cb93a386Sopenharmony_ci#endif 1235cb93a386Sopenharmony_ci 1236cb93a386Sopenharmony_ciTextLine::ClipContext TextLine::measureTextInsideOneRun(TextRange textRange, 1237cb93a386Sopenharmony_ci const Run* run, 1238cb93a386Sopenharmony_ci SkScalar runOffsetInLine, 1239cb93a386Sopenharmony_ci SkScalar textOffsetInRunInLine, 1240cb93a386Sopenharmony_ci bool includeGhostSpaces, 1241cb93a386Sopenharmony_ci TextAdjustment textAdjustment) const { 1242cb93a386Sopenharmony_ci ClipContext result = { run, 0, run->size(), 0, SkRect::MakeEmpty(), 0, false }; 1243cb93a386Sopenharmony_ci 1244cb93a386Sopenharmony_ci if (run->fEllipsis) { 1245cb93a386Sopenharmony_ci // Both ellipsis and placeholders can only be measured as one glyph 1246cb93a386Sopenharmony_ci result.fTextShift = runOffsetInLine; 1247cb93a386Sopenharmony_ci result.clip = SkRect::MakeXYWH(runOffsetInLine, 1248cb93a386Sopenharmony_ci sizes().runTop(run, this->fAscentStyle), 1249cb93a386Sopenharmony_ci run->advance().fX, 1250cb93a386Sopenharmony_ci run->calculateHeight(this->fAscentStyle,this->fDescentStyle)); 1251cb93a386Sopenharmony_ci return result; 1252cb93a386Sopenharmony_ci } else if (run->isPlaceholder()) { 1253cb93a386Sopenharmony_ci result.fTextShift = runOffsetInLine; 1254cb93a386Sopenharmony_ci if (SkScalarIsFinite(run->fFontMetrics.fAscent)) { 1255cb93a386Sopenharmony_ci result.clip = SkRect::MakeXYWH(runOffsetInLine, 1256cb93a386Sopenharmony_ci sizes().runTop(run, this->fAscentStyle), 1257cb93a386Sopenharmony_ci run->advance().fX, 1258cb93a386Sopenharmony_ci run->calculateHeight(this->fAscentStyle,this->fDescentStyle)); 1259cb93a386Sopenharmony_ci } else { 1260cb93a386Sopenharmony_ci result.clip = SkRect::MakeXYWH(runOffsetInLine, run->fFontMetrics.fAscent, run->advance().fX, 0); 1261cb93a386Sopenharmony_ci } 1262cb93a386Sopenharmony_ci return result; 1263cb93a386Sopenharmony_ci } else if (textRange.empty()) { 1264cb93a386Sopenharmony_ci return result; 1265cb93a386Sopenharmony_ci } 1266cb93a386Sopenharmony_ci 1267cb93a386Sopenharmony_ci TextRange originalTextRange(textRange); // We need it for proportional measurement 1268cb93a386Sopenharmony_ci // Find [start:end] clusters for the text 1269cb93a386Sopenharmony_ci while (true) { 1270cb93a386Sopenharmony_ci // Update textRange by cluster edges (shift start up to the edge of the cluster) 1271cb93a386Sopenharmony_ci // TODO: remove this limitation? 1272cb93a386Sopenharmony_ci TextRange updatedTextRange; 1273cb93a386Sopenharmony_ci bool found; 1274cb93a386Sopenharmony_ci std::tie(found, updatedTextRange.start, updatedTextRange.end) = 1275cb93a386Sopenharmony_ci run->findLimitingGlyphClusters(textRange); 1276cb93a386Sopenharmony_ci if (!found) { 1277cb93a386Sopenharmony_ci return result; 1278cb93a386Sopenharmony_ci } 1279cb93a386Sopenharmony_ci 1280cb93a386Sopenharmony_ci if ((textAdjustment & TextAdjustment::Grapheme) == 0) { 1281cb93a386Sopenharmony_ci textRange = updatedTextRange; 1282cb93a386Sopenharmony_ci break; 1283cb93a386Sopenharmony_ci } 1284cb93a386Sopenharmony_ci 1285cb93a386Sopenharmony_ci // Update text range by grapheme edges (shift start up to the edge of the grapheme) 1286cb93a386Sopenharmony_ci std::tie(found, updatedTextRange.start, updatedTextRange.end) = 1287cb93a386Sopenharmony_ci run->findLimitingGraphemes(updatedTextRange); 1288cb93a386Sopenharmony_ci if (updatedTextRange == textRange) { 1289cb93a386Sopenharmony_ci break; 1290cb93a386Sopenharmony_ci } 1291cb93a386Sopenharmony_ci 1292cb93a386Sopenharmony_ci // Some clusters are inside graphemes and we need to adjust them 1293cb93a386Sopenharmony_ci //SkDebugf("Correct range: [%d:%d) -> [%d:%d)\n", textRange.start, textRange.end, startIndex, endIndex); 1294cb93a386Sopenharmony_ci textRange = updatedTextRange; 1295cb93a386Sopenharmony_ci 1296cb93a386Sopenharmony_ci // Move the start until it's on the grapheme edge (and glypheme, too) 1297cb93a386Sopenharmony_ci } 1298cb93a386Sopenharmony_ci Cluster* start = &fOwner->cluster(fOwner->clusterIndex(textRange.start)); 1299cb93a386Sopenharmony_ci Cluster* end = &fOwner->cluster(fOwner->clusterIndex(textRange.end - (textRange.width() == 0 ? 0 : 1))); 1300cb93a386Sopenharmony_ci 1301cb93a386Sopenharmony_ci if (!run->leftToRight()) { 1302cb93a386Sopenharmony_ci std::swap(start, end); 1303cb93a386Sopenharmony_ci } 1304cb93a386Sopenharmony_ci result.pos = start->startPos(); 1305cb93a386Sopenharmony_ci result.size = (end->isHardBreak() ? end->startPos() : end->endPos()) - start->startPos(); 1306cb93a386Sopenharmony_ci auto textStartInRun = run->positionX(start->startPos()); 1307cb93a386Sopenharmony_ci auto textStartInLine = runOffsetInLine + textOffsetInRunInLine; 1308cb93a386Sopenharmony_ci if (!run->leftToRight()) { 1309cb93a386Sopenharmony_ci std::swap(start, end); 1310cb93a386Sopenharmony_ci } 1311cb93a386Sopenharmony_ci/* 1312cb93a386Sopenharmony_ci if (!run->fJustificationShifts.empty()) { 1313cb93a386Sopenharmony_ci SkDebugf("Justification for [%d:%d)\n", textRange.start, textRange.end); 1314cb93a386Sopenharmony_ci for (auto i = result.pos; i < result.pos + result.size; ++i) { 1315cb93a386Sopenharmony_ci auto j = run->fJustificationShifts[i]; 1316cb93a386Sopenharmony_ci SkDebugf("[%d] = %f %f\n", i, j.fX, j.fY); 1317cb93a386Sopenharmony_ci } 1318cb93a386Sopenharmony_ci } 1319cb93a386Sopenharmony_ci*/ 1320cb93a386Sopenharmony_ci // Calculate the clipping rectangle for the text with cluster edges 1321cb93a386Sopenharmony_ci // There are 2 cases: 1322cb93a386Sopenharmony_ci // EOL (when we expect the last cluster clipped without any spaces) 1323cb93a386Sopenharmony_ci // Anything else (when we want the cluster width contain all the spaces - 1324cb93a386Sopenharmony_ci // coming from letter spacing or word spacing or justification) 1325cb93a386Sopenharmony_ci result.clip = 1326cb93a386Sopenharmony_ci SkRect::MakeXYWH(0, 1327cb93a386Sopenharmony_ci sizes().runTop(run, this->fAscentStyle), 1328cb93a386Sopenharmony_ci run->calculateWidth(result.pos, result.pos + result.size, false), 1329cb93a386Sopenharmony_ci run->calculateHeight(this->fAscentStyle,this->fDescentStyle)); 1330cb93a386Sopenharmony_ci 1331cb93a386Sopenharmony_ci // Correct the width in case the text edges don't match clusters 1332cb93a386Sopenharmony_ci // TODO: This is where we get smart about selecting a part of a cluster 1333cb93a386Sopenharmony_ci // by shaping each grapheme separately and then use the result sizes 1334cb93a386Sopenharmony_ci // to calculate the proportions 1335cb93a386Sopenharmony_ci auto leftCorrection = start->sizeToChar(originalTextRange.start); 1336cb93a386Sopenharmony_ci auto rightCorrection = end->sizeFromChar(originalTextRange.end - 1); 1337cb93a386Sopenharmony_ci /* 1338cb93a386Sopenharmony_ci SkDebugf("[%d: %d) => [%d: %d), @%d, %d: [%f:%f) + [%f:%f) = ", // جَآَهُ 1339cb93a386Sopenharmony_ci originalTextRange.start, originalTextRange.end, textRange.start, textRange.end, 1340cb93a386Sopenharmony_ci result.pos, result.size, 1341cb93a386Sopenharmony_ci result.clip.fLeft, result.clip.fRight, leftCorrection, rightCorrection); 1342cb93a386Sopenharmony_ci */ 1343cb93a386Sopenharmony_ci result.clippingNeeded = leftCorrection != 0 || rightCorrection != 0; 1344cb93a386Sopenharmony_ci if (run->leftToRight()) { 1345cb93a386Sopenharmony_ci result.clip.fLeft += leftCorrection; 1346cb93a386Sopenharmony_ci result.clip.fRight -= rightCorrection; 1347cb93a386Sopenharmony_ci textStartInLine -= leftCorrection; 1348cb93a386Sopenharmony_ci } else { 1349cb93a386Sopenharmony_ci result.clip.fRight -= leftCorrection; 1350cb93a386Sopenharmony_ci result.clip.fLeft += rightCorrection; 1351cb93a386Sopenharmony_ci textStartInLine -= rightCorrection; 1352cb93a386Sopenharmony_ci } 1353cb93a386Sopenharmony_ci 1354cb93a386Sopenharmony_ci result.clip.offset(textStartInLine, 0); 1355cb93a386Sopenharmony_ci //SkDebugf("@%f[%f:%f)\n", textStartInLine, result.clip.fLeft, result.clip.fRight); 1356cb93a386Sopenharmony_ci 1357cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1358cb93a386Sopenharmony_ci measureTextWithSpacesAtTheEnd(result, includeGhostSpaces); 1359cb93a386Sopenharmony_ci#else 1360cb93a386Sopenharmony_ci if (compareRound(result.clip.fRight, fAdvance.fX, fOwner->getApplyRoundingHack()) > 0 && !includeGhostSpaces) { 1361cb93a386Sopenharmony_ci // There are few cases when we need it. 1362cb93a386Sopenharmony_ci // The most important one: we measure the text with spaces at the end (or at the beginning in RTL) 1363cb93a386Sopenharmony_ci // and we should ignore these spaces 1364cb93a386Sopenharmony_ci if (fOwner->paragraphStyle().getTextDirection() == TextDirection::kLtr) { 1365cb93a386Sopenharmony_ci // We only use this member for LTR 1366cb93a386Sopenharmony_ci result.fExcludedTrailingSpaces = std::max(result.clip.fRight - fAdvance.fX, 0.0f); 1367cb93a386Sopenharmony_ci result.clippingNeeded = true; 1368cb93a386Sopenharmony_ci result.clip.fRight = fAdvance.fX; 1369cb93a386Sopenharmony_ci } 1370cb93a386Sopenharmony_ci } 1371cb93a386Sopenharmony_ci 1372cb93a386Sopenharmony_ci if (result.clip.width() < 0) { 1373cb93a386Sopenharmony_ci // Weird situation when glyph offsets move the glyph to the left 1374cb93a386Sopenharmony_ci // (happens with zalgo texts, for instance) 1375cb93a386Sopenharmony_ci result.clip.fRight = result.clip.fLeft; 1376cb93a386Sopenharmony_ci } 1377cb93a386Sopenharmony_ci#endif 1378cb93a386Sopenharmony_ci 1379cb93a386Sopenharmony_ci // The text must be aligned with the lineOffset 1380cb93a386Sopenharmony_ci result.fTextShift = textStartInLine - textStartInRun; 1381cb93a386Sopenharmony_ci 1382cb93a386Sopenharmony_ci return result; 1383cb93a386Sopenharmony_ci} 1384cb93a386Sopenharmony_ci 1385cb93a386Sopenharmony_civoid TextLine::iterateThroughClustersInGlyphsOrder(bool reversed, 1386cb93a386Sopenharmony_ci bool includeGhosts, 1387cb93a386Sopenharmony_ci const ClustersVisitor& visitor) const { 1388cb93a386Sopenharmony_ci // Walk through the clusters in the logical order (or reverse) 1389cb93a386Sopenharmony_ci SkSpan<const size_t> runs(fRunsInVisualOrder.data(), fRunsInVisualOrder.size()); 1390cb93a386Sopenharmony_ci bool ignore = false; 1391cb93a386Sopenharmony_ci ClusterIndex index = 0; 1392cb93a386Sopenharmony_ci directional_for_each(runs, !reversed, [&](decltype(runs[0]) r) { 1393cb93a386Sopenharmony_ci if (ignore) return; 1394cb93a386Sopenharmony_ci auto run = this->fOwner->run(r); 1395cb93a386Sopenharmony_ci auto trimmedRange = fClusterRange.intersection(run.clusterRange()); 1396cb93a386Sopenharmony_ci auto trailedRange = fGhostClusterRange.intersection(run.clusterRange()); 1397cb93a386Sopenharmony_ci SkASSERT(trimmedRange.start == trailedRange.start); 1398cb93a386Sopenharmony_ci 1399cb93a386Sopenharmony_ci auto trailed = fOwner->clusters(trailedRange); 1400cb93a386Sopenharmony_ci auto trimmed = fOwner->clusters(trimmedRange); 1401cb93a386Sopenharmony_ci directional_for_each(trailed, reversed != run.leftToRight(), [&](Cluster& cluster) { 1402cb93a386Sopenharmony_ci if (ignore) return; 1403cb93a386Sopenharmony_ci bool ghost = &cluster >= trimmed.end(); 1404cb93a386Sopenharmony_ci if (!includeGhosts && ghost) { 1405cb93a386Sopenharmony_ci return; 1406cb93a386Sopenharmony_ci } 1407cb93a386Sopenharmony_ci if (!visitor(&cluster, index++, ghost)) { 1408cb93a386Sopenharmony_ci 1409cb93a386Sopenharmony_ci ignore = true; 1410cb93a386Sopenharmony_ci return; 1411cb93a386Sopenharmony_ci } 1412cb93a386Sopenharmony_ci }); 1413cb93a386Sopenharmony_ci }); 1414cb93a386Sopenharmony_ci} 1415cb93a386Sopenharmony_ci 1416cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1417cb93a386Sopenharmony_civoid TextLine::computeNextPaintGlyphRange(ClipContext& context, 1418cb93a386Sopenharmony_ci const TextRange& lastGlyphRange, StyleType styleType) const 1419cb93a386Sopenharmony_ci{ 1420cb93a386Sopenharmony_ci if (styleType != StyleType::kForeground) { 1421cb93a386Sopenharmony_ci return; 1422cb93a386Sopenharmony_ci } 1423cb93a386Sopenharmony_ci TextRange curGlyphRange = TextRange(context.pos, context.pos + context.size); 1424cb93a386Sopenharmony_ci auto intersect = intersected(lastGlyphRange, curGlyphRange); 1425cb93a386Sopenharmony_ci if (intersect == EMPTY_TEXT || (intersect.start != curGlyphRange.start && intersect.end != curGlyphRange.end)) { 1426cb93a386Sopenharmony_ci return; 1427cb93a386Sopenharmony_ci } 1428cb93a386Sopenharmony_ci if (intersect.start == curGlyphRange.start) { 1429cb93a386Sopenharmony_ci curGlyphRange = TextRange(intersect.end, curGlyphRange.end); 1430cb93a386Sopenharmony_ci } else if (intersect.end == curGlyphRange.end) { 1431cb93a386Sopenharmony_ci curGlyphRange = TextRange(curGlyphRange.start, intersect.start); 1432cb93a386Sopenharmony_ci } 1433cb93a386Sopenharmony_ci 1434cb93a386Sopenharmony_ci context.pos = curGlyphRange.start; 1435cb93a386Sopenharmony_ci context.size = curGlyphRange.width(); 1436cb93a386Sopenharmony_ci} 1437cb93a386Sopenharmony_ci#endif 1438cb93a386Sopenharmony_ci 1439cb93a386Sopenharmony_ciSkScalar TextLine::iterateThroughSingleRunByStyles(TextAdjustment textAdjustment, 1440cb93a386Sopenharmony_ci const Run* run, 1441cb93a386Sopenharmony_ci SkScalar runOffset, 1442cb93a386Sopenharmony_ci TextRange textRange, 1443cb93a386Sopenharmony_ci StyleType styleType, 1444cb93a386Sopenharmony_ci const RunStyleVisitor& visitor) const { 1445cb93a386Sopenharmony_ci auto includeGhostSpaces = (styleType == StyleType::kDecorations || styleType == StyleType::kBackground || 1446cb93a386Sopenharmony_ci styleType == StyleType::kNone); 1447cb93a386Sopenharmony_ci auto correctContext = [&](TextRange textRange, SkScalar textOffsetInRun) -> ClipContext { 1448cb93a386Sopenharmony_ci auto result = this->measureTextInsideOneRun( 1449cb93a386Sopenharmony_ci textRange, run, runOffset, textOffsetInRun, includeGhostSpaces, textAdjustment); 1450cb93a386Sopenharmony_ci if (styleType == StyleType::kDecorations) { 1451cb93a386Sopenharmony_ci // Decorations are drawn based on the real font metrics (regardless of styles and strut) 1452cb93a386Sopenharmony_ci result.clip.fTop = this->sizes().runTop(run, LineMetricStyle::CSS) - run->baselineShift(); 1453cb93a386Sopenharmony_ci result.clip.fBottom = result.clip.fTop + 1454cb93a386Sopenharmony_ci run->calculateHeight(LineMetricStyle::CSS, LineMetricStyle::CSS); 1455cb93a386Sopenharmony_ci } 1456cb93a386Sopenharmony_ci return result; 1457cb93a386Sopenharmony_ci }; 1458cb93a386Sopenharmony_ci 1459cb93a386Sopenharmony_ci if (run->fEllipsis) { 1460cb93a386Sopenharmony_ci // Extra efforts to get the ellipsis text style 1461cb93a386Sopenharmony_ci ClipContext clipContext = correctContext(run->textRange(), 0.0f); 1462cb93a386Sopenharmony_ci for (BlockIndex index = fBlockRange.start; index < fBlockRange.end; ++index) { 1463cb93a386Sopenharmony_ci auto block = fOwner->styles().begin() + index; 1464cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1465cb93a386Sopenharmony_ci TextRange intersect = intersected(block->fRange, 1466cb93a386Sopenharmony_ci TextRange(fEllipsis->textRange().start - 1, fEllipsis->textRange().end)); 1467cb93a386Sopenharmony_ci if (intersect.width() > 0) { 1468cb93a386Sopenharmony_ci visitor(fTextRangeReplacedByEllipsis, block->fStyle, clipContext); 1469cb93a386Sopenharmony_ci return run->advance().fX; 1470cb93a386Sopenharmony_ci } 1471cb93a386Sopenharmony_ci#else 1472cb93a386Sopenharmony_ci if (block->fRange.start >= run->fClusterStart && block->fRange.end < run->fClusterStart) { 1473cb93a386Sopenharmony_ci visitor(fTextRangeReplacedByEllipsis, block->fStyle, clipContext); 1474cb93a386Sopenharmony_ci return run->advance().fX; 1475cb93a386Sopenharmony_ci } 1476cb93a386Sopenharmony_ci#endif 1477cb93a386Sopenharmony_ci } 1478cb93a386Sopenharmony_ci SkASSERT(false); 1479cb93a386Sopenharmony_ci } 1480cb93a386Sopenharmony_ci 1481cb93a386Sopenharmony_ci if (styleType == StyleType::kNone) { 1482cb93a386Sopenharmony_ci ClipContext clipContext = correctContext(textRange, 0.0f); 1483cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1484cb93a386Sopenharmony_ci if (clipContext.clip.height() > 0 || 1485cb93a386Sopenharmony_ci (run->isPlaceholder() && SkScalarNearlyZero(clipContext.clip.height()))) { 1486cb93a386Sopenharmony_ci#else 1487cb93a386Sopenharmony_ci if (clipContext.clip.height() > 0) { 1488cb93a386Sopenharmony_ci#endif 1489cb93a386Sopenharmony_ci visitor(textRange, TextStyle(), clipContext); 1490cb93a386Sopenharmony_ci return clipContext.clip.width(); 1491cb93a386Sopenharmony_ci } else { 1492cb93a386Sopenharmony_ci return 0; 1493cb93a386Sopenharmony_ci } 1494cb93a386Sopenharmony_ci } 1495cb93a386Sopenharmony_ci 1496cb93a386Sopenharmony_ci TextIndex start = EMPTY_INDEX; 1497cb93a386Sopenharmony_ci size_t size = 0; 1498cb93a386Sopenharmony_ci const TextStyle* prevStyle = nullptr; 1499cb93a386Sopenharmony_ci SkScalar textOffsetInRun = 0; 1500cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1501cb93a386Sopenharmony_ci TextRange lastGlyphRange = EMPTY_TEXT; 1502cb93a386Sopenharmony_ci#endif 1503cb93a386Sopenharmony_ci const BlockIndex blockRangeSize = fBlockRange.end - fBlockRange.start; 1504cb93a386Sopenharmony_ci for (BlockIndex index = 0; index <= blockRangeSize; ++index) { 1505cb93a386Sopenharmony_ci 1506cb93a386Sopenharmony_ci TextRange intersect; 1507cb93a386Sopenharmony_ci TextStyle* style = nullptr; 1508cb93a386Sopenharmony_ci if (index < blockRangeSize) { 1509cb93a386Sopenharmony_ci auto block = fOwner->styles().begin() + 1510cb93a386Sopenharmony_ci (run->leftToRight() ? fBlockRange.start + index : fBlockRange.end - index - 1); 1511cb93a386Sopenharmony_ci 1512cb93a386Sopenharmony_ci // Get the text 1513cb93a386Sopenharmony_ci intersect = intersected(block->fRange, textRange); 1514cb93a386Sopenharmony_ci if (intersect.width() == 0) { 1515cb93a386Sopenharmony_ci if (start == EMPTY_INDEX) { 1516cb93a386Sopenharmony_ci // This style is not applicable to the text yet 1517cb93a386Sopenharmony_ci continue; 1518cb93a386Sopenharmony_ci } else { 1519cb93a386Sopenharmony_ci // We have found all the good styles already 1520cb93a386Sopenharmony_ci // but we need to process the last one of them 1521cb93a386Sopenharmony_ci intersect = TextRange(start, start + size); 1522cb93a386Sopenharmony_ci index = fBlockRange.end; 1523cb93a386Sopenharmony_ci } 1524cb93a386Sopenharmony_ci } else { 1525cb93a386Sopenharmony_ci // Get the style 1526cb93a386Sopenharmony_ci style = &block->fStyle; 1527cb93a386Sopenharmony_ci if (start != EMPTY_INDEX && style->matchOneAttribute(styleType, *prevStyle)) { 1528cb93a386Sopenharmony_ci size += intersect.width(); 1529cb93a386Sopenharmony_ci // RTL text intervals move backward 1530cb93a386Sopenharmony_ci start = std::min(intersect.start, start); 1531cb93a386Sopenharmony_ci continue; 1532cb93a386Sopenharmony_ci } else if (start == EMPTY_INDEX ) { 1533cb93a386Sopenharmony_ci // First time only 1534cb93a386Sopenharmony_ci prevStyle = style; 1535cb93a386Sopenharmony_ci size = intersect.width(); 1536cb93a386Sopenharmony_ci start = intersect.start; 1537cb93a386Sopenharmony_ci continue; 1538cb93a386Sopenharmony_ci } 1539cb93a386Sopenharmony_ci } 1540cb93a386Sopenharmony_ci } else if (prevStyle != nullptr) { 1541cb93a386Sopenharmony_ci // This is the last style 1542cb93a386Sopenharmony_ci } else { 1543cb93a386Sopenharmony_ci break; 1544cb93a386Sopenharmony_ci } 1545cb93a386Sopenharmony_ci 1546cb93a386Sopenharmony_ci // We have the style and the text 1547cb93a386Sopenharmony_ci auto runStyleTextRange = TextRange(start, start + size); 1548cb93a386Sopenharmony_ci ClipContext clipContext = correctContext(runStyleTextRange, textOffsetInRun); 1549cb93a386Sopenharmony_ci textOffsetInRun += clipContext.clip.width(); 1550cb93a386Sopenharmony_ci if (clipContext.clip.height() == 0) { 1551cb93a386Sopenharmony_ci continue; 1552cb93a386Sopenharmony_ci } 1553cb93a386Sopenharmony_ci 1554cb93a386Sopenharmony_ci RectStyle temp; 1555cb93a386Sopenharmony_ci if (styleType == StyleType::kBackground && 1556cb93a386Sopenharmony_ci prevStyle->getBackgroundRect() != temp && 1557cb93a386Sopenharmony_ci prevStyle->getHeight() != 0) { 1558cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1559cb93a386Sopenharmony_ci clipContext.clip.fTop = run->fFontMetrics.fAscent + this->baseline(); 1560cb93a386Sopenharmony_ci#else 1561cb93a386Sopenharmony_ci clipContext.clip.fTop = run->fFontMetrics.fAscent - run->fCorrectAscent; 1562cb93a386Sopenharmony_ci#endif 1563cb93a386Sopenharmony_ci clipContext.clip.fBottom = clipContext.clip.fTop + run->fFontMetrics.fDescent - 1564cb93a386Sopenharmony_ci run->fFontMetrics.fAscent; 1565cb93a386Sopenharmony_ci } 1566cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1567cb93a386Sopenharmony_ci computeNextPaintGlyphRange(clipContext, lastGlyphRange, styleType); 1568cb93a386Sopenharmony_ci if (clipContext.size != 0) { 1569cb93a386Sopenharmony_ci lastGlyphRange = TextRange(clipContext.pos, clipContext.pos + clipContext.size); 1570cb93a386Sopenharmony_ci } 1571cb93a386Sopenharmony_ci#endif 1572cb93a386Sopenharmony_ci visitor(runStyleTextRange, *prevStyle, clipContext); 1573cb93a386Sopenharmony_ci 1574cb93a386Sopenharmony_ci // Start all over again 1575cb93a386Sopenharmony_ci prevStyle = style; 1576cb93a386Sopenharmony_ci start = intersect.start; 1577cb93a386Sopenharmony_ci size = intersect.width(); 1578cb93a386Sopenharmony_ci } 1579cb93a386Sopenharmony_ci return textOffsetInRun; 1580cb93a386Sopenharmony_ci} 1581cb93a386Sopenharmony_ci 1582cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1583cb93a386Sopenharmony_cibool TextLine::processEllipsisRun(bool& isAlreadyUseEllipsis, 1584cb93a386Sopenharmony_ci SkScalar& runOffset, 1585cb93a386Sopenharmony_ci EllipsisReadStrategy ellipsisReadStrategy, 1586cb93a386Sopenharmony_ci const RunVisitor& visitor, 1587cb93a386Sopenharmony_ci SkScalar& runWidthInLine) const { 1588cb93a386Sopenharmony_ci isAlreadyUseEllipsis = true; 1589cb93a386Sopenharmony_ci runOffset += this->ellipsis()->offset().fX; 1590cb93a386Sopenharmony_ci if (ellipsisReadStrategy == EllipsisReadStrategy::READ_REPLACED_WORD) { 1591cb93a386Sopenharmony_ci if (!visitor(ellipsis(), runOffset, fTextRangeReplacedByEllipsis, &runWidthInLine)) { 1592cb93a386Sopenharmony_ci LOGE("Visitor process ellipsis replace word error!"); 1593cb93a386Sopenharmony_ci return false; 1594cb93a386Sopenharmony_ci } 1595cb93a386Sopenharmony_ci } else if (ellipsisReadStrategy == EllipsisReadStrategy::READ_ELLIPSIS_WORD) { 1596cb93a386Sopenharmony_ci if (!visitor(ellipsis(), runOffset, ellipsis()->textRange(), &runWidthInLine)) { 1597cb93a386Sopenharmony_ci LOGE("Visitor process ellipsis word error!"); 1598cb93a386Sopenharmony_ci return false; 1599cb93a386Sopenharmony_ci } 1600cb93a386Sopenharmony_ci } else { 1601cb93a386Sopenharmony_ci runWidthInLine = this->ellipsis()->advance().fX; 1602cb93a386Sopenharmony_ci } 1603cb93a386Sopenharmony_ci return true; 1604cb93a386Sopenharmony_ci} 1605cb93a386Sopenharmony_ci#endif 1606cb93a386Sopenharmony_ci 1607cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1608cb93a386Sopenharmony_civoid TextLine::iterateThroughVisualRuns(EllipsisReadStrategy ellipsisReadStrategy, 1609cb93a386Sopenharmony_ci bool includingGhostSpaces, 1610cb93a386Sopenharmony_ci const RunVisitor& visitor) const { 1611cb93a386Sopenharmony_ci // Walk through all the runs that intersect with the line in visual order 1612cb93a386Sopenharmony_ci SkScalar width = 0; 1613cb93a386Sopenharmony_ci SkScalar runOffset = 0; 1614cb93a386Sopenharmony_ci SkScalar totalWidth = 0; 1615cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1616cb93a386Sopenharmony_ci bool ellipsisModeIsHead = fIsTextLineEllipsisHeadModal ? true : 1617cb93a386Sopenharmony_ci fOwner->paragraphStyle().getEllipsisMod() == EllipsisModal::HEAD; 1618cb93a386Sopenharmony_ci#else 1619cb93a386Sopenharmony_ci bool ellipsisModeIsHead = fOwner->paragraphStyle().getEllipsisMod() == EllipsisModal::HEAD; 1620cb93a386Sopenharmony_ci#endif 1621cb93a386Sopenharmony_ci bool isAlreadyUseEllipsis = false; 1622cb93a386Sopenharmony_ci auto textRange = includingGhostSpaces ? this->textWithNewlines() : this->trimmedText(); 1623cb93a386Sopenharmony_ci 1624cb93a386Sopenharmony_ci if (fRunsInVisualOrder.size() == 0 && fEllipsis != nullptr) { 1625cb93a386Sopenharmony_ci if (!processEllipsisRun(isAlreadyUseEllipsis, runOffset, ellipsisReadStrategy, visitor, width)) { 1626cb93a386Sopenharmony_ci return; 1627cb93a386Sopenharmony_ci } 1628cb93a386Sopenharmony_ci totalWidth += width; 1629cb93a386Sopenharmony_ci } 1630cb93a386Sopenharmony_ci 1631cb93a386Sopenharmony_ci for (auto& runIndex : fRunsInVisualOrder) { 1632cb93a386Sopenharmony_ci // add the lastClipRun's left ellipsis if necessary 1633cb93a386Sopenharmony_ci if (!isAlreadyUseEllipsis && fEllipsisIndex == runIndex && 1634cb93a386Sopenharmony_ci ((!fLastClipRunLtr && !ellipsisModeIsHead) || (ellipsisModeIsHead && fLastClipRunLtr))) { 1635cb93a386Sopenharmony_ci if (!processEllipsisRun(isAlreadyUseEllipsis, runOffset, ellipsisReadStrategy, visitor, width)) { 1636cb93a386Sopenharmony_ci return; 1637cb93a386Sopenharmony_ci } 1638cb93a386Sopenharmony_ci runOffset += width; 1639cb93a386Sopenharmony_ci totalWidth += width; 1640cb93a386Sopenharmony_ci } 1641cb93a386Sopenharmony_ci 1642cb93a386Sopenharmony_ci const auto run = &this->fOwner->run(runIndex); 1643cb93a386Sopenharmony_ci auto lineIntersection = intersected(run->textRange(), textRange); 1644cb93a386Sopenharmony_ci if (lineIntersection.width() == 0 && this->width() != 0) { 1645cb93a386Sopenharmony_ci // TODO: deal with empty runs in a better way 1646cb93a386Sopenharmony_ci continue; 1647cb93a386Sopenharmony_ci } 1648cb93a386Sopenharmony_ci if (!run->leftToRight() && runOffset == 0 && includingGhostSpaces) { 1649cb93a386Sopenharmony_ci // runOffset does not take in account a possibility 1650cb93a386Sopenharmony_ci // that RTL run could start before the line (trailing spaces) 1651cb93a386Sopenharmony_ci // so we need to do runOffset -= "trailing whitespaces length" 1652cb93a386Sopenharmony_ci TextRange whitespaces = intersected( 1653cb93a386Sopenharmony_ci TextRange(fTextExcludingSpaces.end, fTextIncludingNewlines.end), run->fTextRange); 1654cb93a386Sopenharmony_ci if (whitespaces.width() > 0) { 1655cb93a386Sopenharmony_ci auto whitespacesLen = measureTextInsideOneRun(whitespaces, run, runOffset, 0, true, 1656cb93a386Sopenharmony_ci TextAdjustment::GlyphCluster).clip.width(); 1657cb93a386Sopenharmony_ci runOffset -= whitespacesLen; 1658cb93a386Sopenharmony_ci } 1659cb93a386Sopenharmony_ci } 1660cb93a386Sopenharmony_ci 1661cb93a386Sopenharmony_ci if (!visitor(run, runOffset, lineIntersection, &width)) { 1662cb93a386Sopenharmony_ci return; 1663cb93a386Sopenharmony_ci } 1664cb93a386Sopenharmony_ci 1665cb93a386Sopenharmony_ci runOffset += width; 1666cb93a386Sopenharmony_ci totalWidth += width; 1667cb93a386Sopenharmony_ci 1668cb93a386Sopenharmony_ci // add the lastClipRun's right ellipsis if necessary 1669cb93a386Sopenharmony_ci if (!isAlreadyUseEllipsis && fEllipsisIndex == runIndex) { 1670cb93a386Sopenharmony_ci if (!processEllipsisRun(isAlreadyUseEllipsis, runOffset, ellipsisReadStrategy, visitor, width)) { 1671cb93a386Sopenharmony_ci return; 1672cb93a386Sopenharmony_ci } 1673cb93a386Sopenharmony_ci runOffset += width; 1674cb93a386Sopenharmony_ci totalWidth += width; 1675cb93a386Sopenharmony_ci } 1676cb93a386Sopenharmony_ci } 1677cb93a386Sopenharmony_ci 1678cb93a386Sopenharmony_ci if (!includingGhostSpaces && compareRound(totalWidth, this->width(), fOwner->getApplyRoundingHack()) != 0) { 1679cb93a386Sopenharmony_ci // This is a very important assert! 1680cb93a386Sopenharmony_ci // It asserts that 2 different ways of calculation come with the same results 1681cb93a386Sopenharmony_ci SkDebugf("ASSERT: %f != %f\n", totalWidth, this->width()); 1682cb93a386Sopenharmony_ci SkASSERT(false); 1683cb93a386Sopenharmony_ci } 1684cb93a386Sopenharmony_ci} 1685cb93a386Sopenharmony_ci#else 1686cb93a386Sopenharmony_civoid TextLine::iterateThroughVisualRuns(bool includingGhostSpaces, const RunVisitor& visitor) const { 1687cb93a386Sopenharmony_ci 1688cb93a386Sopenharmony_ci // Walk through all the runs that intersect with the line in visual order 1689cb93a386Sopenharmony_ci SkScalar width = 0; 1690cb93a386Sopenharmony_ci SkScalar runOffset = 0; 1691cb93a386Sopenharmony_ci SkScalar totalWidth = 0; 1692cb93a386Sopenharmony_ci auto textRange = includingGhostSpaces ? this->textWithNewlines() : this->trimmedText(); 1693cb93a386Sopenharmony_ci for (auto& runIndex : fRunsInVisualOrder) { 1694cb93a386Sopenharmony_ci 1695cb93a386Sopenharmony_ci const auto run = &this->fOwner->run(runIndex); 1696cb93a386Sopenharmony_ci auto lineIntersection = intersected(run->textRange(), textRange); 1697cb93a386Sopenharmony_ci if (lineIntersection.width() == 0 && this->width() != 0) { 1698cb93a386Sopenharmony_ci // TODO: deal with empty runs in a better way 1699cb93a386Sopenharmony_ci continue; 1700cb93a386Sopenharmony_ci } 1701cb93a386Sopenharmony_ci if (!run->leftToRight() && runOffset == 0 && includingGhostSpaces) { 1702cb93a386Sopenharmony_ci // runOffset does not take in account a possibility 1703cb93a386Sopenharmony_ci // that RTL run could start before the line (trailing spaces) 1704cb93a386Sopenharmony_ci // so we need to do runOffset -= "trailing whitespaces length" 1705cb93a386Sopenharmony_ci TextRange whitespaces = intersected( 1706cb93a386Sopenharmony_ci TextRange(fTextExcludingSpaces.end, fTextIncludingNewlines.end), run->fTextRange); 1707cb93a386Sopenharmony_ci if (whitespaces.width() > 0) { 1708cb93a386Sopenharmony_ci auto whitespacesLen = measureTextInsideOneRun(whitespaces, run, runOffset, 0, true, false).clip.width(); 1709cb93a386Sopenharmony_ci runOffset -= whitespacesLen; 1710cb93a386Sopenharmony_ci } 1711cb93a386Sopenharmony_ci } 1712cb93a386Sopenharmony_ci runOffset += width; 1713cb93a386Sopenharmony_ci totalWidth += width; 1714cb93a386Sopenharmony_ci if (!visitor(run, runOffset, lineIntersection, &width)) { 1715cb93a386Sopenharmony_ci return; 1716cb93a386Sopenharmony_ci } 1717cb93a386Sopenharmony_ci } 1718cb93a386Sopenharmony_ci 1719cb93a386Sopenharmony_ci runOffset += width; 1720cb93a386Sopenharmony_ci totalWidth += width; 1721cb93a386Sopenharmony_ci 1722cb93a386Sopenharmony_ci if (this->ellipsis() != nullptr) { 1723cb93a386Sopenharmony_ci if (visitor(ellipsis(), runOffset, ellipsis()->textRange(), &width)) { 1724cb93a386Sopenharmony_ci totalWidth += width; 1725cb93a386Sopenharmony_ci } 1726cb93a386Sopenharmony_ci } 1727cb93a386Sopenharmony_ci 1728cb93a386Sopenharmony_ci // This is a very important assert! 1729cb93a386Sopenharmony_ci // It asserts that 2 different ways of calculation come with the same results 1730cb93a386Sopenharmony_ci if (!includingGhostSpaces && compareRound(totalWidth, this->width()) != 0) { 1731cb93a386Sopenharmony_ci SkDebugf("ASSERT: %f != %f\n", totalWidth, this->width()); 1732cb93a386Sopenharmony_ci SkASSERT(false); 1733cb93a386Sopenharmony_ci } 1734cb93a386Sopenharmony_ci} 1735cb93a386Sopenharmony_ci#endif 1736cb93a386Sopenharmony_ci 1737cb93a386Sopenharmony_ciSkVector TextLine::offset() const { 1738cb93a386Sopenharmony_ci return fOffset + SkVector::Make(fShift, 0); 1739cb93a386Sopenharmony_ci} 1740cb93a386Sopenharmony_ci 1741cb93a386Sopenharmony_ciLineMetrics TextLine::getMetrics() const { 1742cb93a386Sopenharmony_ci LineMetrics result; 1743cb93a386Sopenharmony_ci 1744cb93a386Sopenharmony_ci // Fill out the metrics 1745cb93a386Sopenharmony_ci fOwner->ensureUTF16Mapping(); 1746cb93a386Sopenharmony_ci result.fStartIndex = fOwner->getUTF16Index(fTextExcludingSpaces.start); 1747cb93a386Sopenharmony_ci result.fEndExcludingWhitespaces = fOwner->getUTF16Index(fTextExcludingSpaces.end); 1748cb93a386Sopenharmony_ci result.fEndIndex = fOwner->getUTF16Index(fText.end); 1749cb93a386Sopenharmony_ci result.fEndIncludingNewline = fOwner->getUTF16Index(fTextIncludingNewlines.end); 1750cb93a386Sopenharmony_ci result.fHardBreak = endsWithHardLineBreak(); 1751cb93a386Sopenharmony_ci result.fAscent = - fMaxRunMetrics.ascent(); 1752cb93a386Sopenharmony_ci result.fDescent = fMaxRunMetrics.descent(); 1753cb93a386Sopenharmony_ci result.fUnscaledAscent = - fMaxRunMetrics.ascent(); // TODO: implement 1754cb93a386Sopenharmony_ci result.fHeight = fAdvance.fY; 1755cb93a386Sopenharmony_ci result.fWidth = fAdvance.fX; 1756cb93a386Sopenharmony_ci if (fOwner->getApplyRoundingHack()) { 1757cb93a386Sopenharmony_ci result.fHeight = littleRound(result.fHeight); 1758cb93a386Sopenharmony_ci result.fWidth = littleRound(result.fWidth); 1759cb93a386Sopenharmony_ci } 1760cb93a386Sopenharmony_ci result.fLeft = this->offset().fX; 1761cb93a386Sopenharmony_ci // This is Flutter definition of a baseline 1762cb93a386Sopenharmony_ci result.fBaseline = this->offset().fY + this->height() - this->sizes().descent(); 1763cb93a386Sopenharmony_ci result.fLineNumber = this - fOwner->lines().begin(); 1764cb93a386Sopenharmony_ci result.fWidthWithSpaces = fWidthWithSpaces; 1765cb93a386Sopenharmony_ci result.fTopHeight = this->offset().fY; 1766cb93a386Sopenharmony_ci 1767cb93a386Sopenharmony_ci // Fill out the style parts 1768cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1769cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_REPLACED_WORD, false, 1770cb93a386Sopenharmony_ci#else 1771cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(false, 1772cb93a386Sopenharmony_ci#endif 1773cb93a386Sopenharmony_ci [this, &result] 1774cb93a386Sopenharmony_ci (const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) { 1775cb93a386Sopenharmony_ci if (run->placeholderStyle() != nullptr) { 1776cb93a386Sopenharmony_ci *runWidthInLine = run->advance().fX; 1777cb93a386Sopenharmony_ci return true; 1778cb93a386Sopenharmony_ci } 1779cb93a386Sopenharmony_ci *runWidthInLine = this->iterateThroughSingleRunByStyles( 1780cb93a386Sopenharmony_ci TextAdjustment::GlyphCluster, run, runOffsetInLine, textRange, StyleType::kForeground, 1781cb93a386Sopenharmony_ci [&result, &run](TextRange textRange, const TextStyle& style, const ClipContext& context) { 1782cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 1783cb93a386Sopenharmony_ci SkFontMetrics fontMetrics; 1784cb93a386Sopenharmony_ci run->fFont.getMetrics(&fontMetrics); 1785cb93a386Sopenharmony_ci#else 1786cb93a386Sopenharmony_ci RSFontMetrics fontMetrics; 1787cb93a386Sopenharmony_ci run->fFont.GetMetrics(&fontMetrics); 1788cb93a386Sopenharmony_ci#endif 1789cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1790cb93a386Sopenharmony_ci auto decompressFont = run->fFont; 1791cb93a386Sopenharmony_ci scaleFontWithCompressionConfig(decompressFont, ScaleOP::DECOMPRESS); 1792cb93a386Sopenharmony_ci metricsIncludeFontPadding(&fontMetrics, decompressFont); 1793cb93a386Sopenharmony_ci#endif 1794cb93a386Sopenharmony_ci StyleMetrics styleMetrics(&style, fontMetrics); 1795cb93a386Sopenharmony_ci result.fLineMetrics.emplace(textRange.start, styleMetrics); 1796cb93a386Sopenharmony_ci }); 1797cb93a386Sopenharmony_ci return true; 1798cb93a386Sopenharmony_ci }); 1799cb93a386Sopenharmony_ci 1800cb93a386Sopenharmony_ci return result; 1801cb93a386Sopenharmony_ci} 1802cb93a386Sopenharmony_ci 1803cb93a386Sopenharmony_cibool TextLine::isFirstLine() const { 1804cb93a386Sopenharmony_ci return this == &fOwner->lines().front(); 1805cb93a386Sopenharmony_ci} 1806cb93a386Sopenharmony_ci 1807cb93a386Sopenharmony_cibool TextLine::isLastLine() const { 1808cb93a386Sopenharmony_ci return this == &fOwner->lines().back(); 1809cb93a386Sopenharmony_ci} 1810cb93a386Sopenharmony_ci 1811cb93a386Sopenharmony_cibool TextLine::endsWithHardLineBreak() const { 1812cb93a386Sopenharmony_ci // TODO: For some reason Flutter imagines a hard line break at the end of the last line. 1813cb93a386Sopenharmony_ci // To be removed... 1814cb93a386Sopenharmony_ci return (fGhostClusterRange.width() > 0 && fOwner->cluster(fGhostClusterRange.end - 1).isHardBreak()) || 1815cb93a386Sopenharmony_ci fEllipsis != nullptr || 1816cb93a386Sopenharmony_ci fGhostClusterRange.end == fOwner->clusters().size() - 1; 1817cb93a386Sopenharmony_ci} 1818cb93a386Sopenharmony_ci 1819cb93a386Sopenharmony_civoid TextLine::getRectsForRange(TextRange textRange0, 1820cb93a386Sopenharmony_ci RectHeightStyle rectHeightStyle, 1821cb93a386Sopenharmony_ci RectWidthStyle rectWidthStyle, 1822cb93a386Sopenharmony_ci std::vector<TextBox>& boxes) const 1823cb93a386Sopenharmony_ci{ 1824cb93a386Sopenharmony_ci const Run* lastRun = nullptr; 1825cb93a386Sopenharmony_ci auto startBox = boxes.size(); 1826cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 1827cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_REPLACED_WORD, true, 1828cb93a386Sopenharmony_ci#else 1829cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(true, 1830cb93a386Sopenharmony_ci#endif 1831cb93a386Sopenharmony_ci [textRange0, rectHeightStyle, rectWidthStyle, &boxes, &lastRun, startBox, this] 1832cb93a386Sopenharmony_ci (const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) { 1833cb93a386Sopenharmony_ci *runWidthInLine = this->iterateThroughSingleRunByStyles( 1834cb93a386Sopenharmony_ci TextAdjustment::GraphemeGluster, run, runOffsetInLine, textRange, StyleType::kNone, 1835cb93a386Sopenharmony_ci [run, runOffsetInLine, textRange0, rectHeightStyle, rectWidthStyle, &boxes, &lastRun, startBox, this] 1836cb93a386Sopenharmony_ci (TextRange textRange, const TextStyle& style, const TextLine::ClipContext& lineContext) { 1837cb93a386Sopenharmony_ci 1838cb93a386Sopenharmony_ci auto intersect = textRange * textRange0; 1839cb93a386Sopenharmony_ci if (intersect.empty()) { 1840cb93a386Sopenharmony_ci return true; 1841cb93a386Sopenharmony_ci } 1842cb93a386Sopenharmony_ci 1843cb93a386Sopenharmony_ci auto paragraphStyle = fOwner->paragraphStyle(); 1844cb93a386Sopenharmony_ci 1845cb93a386Sopenharmony_ci // Found a run that intersects with the text 1846cb93a386Sopenharmony_ci auto context = this->measureTextInsideOneRun( 1847cb93a386Sopenharmony_ci intersect, run, runOffsetInLine, 0, true, TextAdjustment::GraphemeGluster); 1848cb93a386Sopenharmony_ci SkRect clip = context.clip; 1849cb93a386Sopenharmony_ci clip.offset(lineContext.fTextShift - context.fTextShift, 0); 1850cb93a386Sopenharmony_ci 1851cb93a386Sopenharmony_ci switch (rectHeightStyle) { 1852cb93a386Sopenharmony_ci case RectHeightStyle::kMax: 1853cb93a386Sopenharmony_ci // TODO: Change it once flutter rolls into google3 1854cb93a386Sopenharmony_ci // (probably will break things if changed before) 1855cb93a386Sopenharmony_ci clip.fBottom = this->height(); 1856cb93a386Sopenharmony_ci clip.fTop = this->sizes().delta(); 1857cb93a386Sopenharmony_ci break; 1858cb93a386Sopenharmony_ci case RectHeightStyle::kIncludeLineSpacingTop: { 1859cb93a386Sopenharmony_ci clip.fBottom = this->height(); 1860cb93a386Sopenharmony_ci clip.fTop = this->sizes().delta(); 1861cb93a386Sopenharmony_ci auto verticalShift = this->sizes().rawAscent() - this->sizes().ascent(); 1862cb93a386Sopenharmony_ci if (isFirstLine()) { 1863cb93a386Sopenharmony_ci clip.fTop += verticalShift; 1864cb93a386Sopenharmony_ci } 1865cb93a386Sopenharmony_ci break; 1866cb93a386Sopenharmony_ci } 1867cb93a386Sopenharmony_ci case RectHeightStyle::kIncludeLineSpacingMiddle: { 1868cb93a386Sopenharmony_ci clip.fBottom = this->height(); 1869cb93a386Sopenharmony_ci clip.fTop = this->sizes().delta(); 1870cb93a386Sopenharmony_ci auto verticalShift = this->sizes().rawAscent() - this->sizes().ascent(); 1871cb93a386Sopenharmony_ci clip.offset(0, verticalShift / 2.0); 1872cb93a386Sopenharmony_ci if (isFirstLine()) { 1873cb93a386Sopenharmony_ci clip.fTop += verticalShift / 2.0; 1874cb93a386Sopenharmony_ci } 1875cb93a386Sopenharmony_ci if (isLastLine()) { 1876cb93a386Sopenharmony_ci clip.fBottom -= verticalShift / 2.0; 1877cb93a386Sopenharmony_ci } 1878cb93a386Sopenharmony_ci break; 1879cb93a386Sopenharmony_ci } 1880cb93a386Sopenharmony_ci case RectHeightStyle::kIncludeLineSpacingBottom: { 1881cb93a386Sopenharmony_ci clip.fBottom = this->height(); 1882cb93a386Sopenharmony_ci clip.fTop = this->sizes().delta(); 1883cb93a386Sopenharmony_ci auto verticalShift = this->sizes().rawAscent() - this->sizes().ascent(); 1884cb93a386Sopenharmony_ci clip.offset(0, verticalShift); 1885cb93a386Sopenharmony_ci if (isLastLine()) { 1886cb93a386Sopenharmony_ci clip.fBottom -= verticalShift; 1887cb93a386Sopenharmony_ci } 1888cb93a386Sopenharmony_ci break; 1889cb93a386Sopenharmony_ci } 1890cb93a386Sopenharmony_ci case RectHeightStyle::kStrut: { 1891cb93a386Sopenharmony_ci const auto& strutStyle = paragraphStyle.getStrutStyle(); 1892cb93a386Sopenharmony_ci if (strutStyle.getStrutEnabled() 1893cb93a386Sopenharmony_ci && strutStyle.getFontSize() > 0) { 1894cb93a386Sopenharmony_ci auto strutMetrics = fOwner->strutMetrics(); 1895cb93a386Sopenharmony_ci auto top = this->baseline(); 1896cb93a386Sopenharmony_ci clip.fTop = top + strutMetrics.ascent(); 1897cb93a386Sopenharmony_ci clip.fBottom = top + strutMetrics.descent(); 1898cb93a386Sopenharmony_ci } 1899cb93a386Sopenharmony_ci } 1900cb93a386Sopenharmony_ci break; 1901cb93a386Sopenharmony_ci case RectHeightStyle::kTight: { 1902cb93a386Sopenharmony_ci if (run->fHeightMultiplier <= 0) { 1903cb93a386Sopenharmony_ci break; 1904cb93a386Sopenharmony_ci } 1905cb93a386Sopenharmony_ci const auto effectiveBaseline = this->baseline() + this->sizes().delta(); 1906cb93a386Sopenharmony_ci clip.fTop = effectiveBaseline + run->ascent(); 1907cb93a386Sopenharmony_ci clip.fBottom = effectiveBaseline + run->descent(); 1908cb93a386Sopenharmony_ci } 1909cb93a386Sopenharmony_ci break; 1910cb93a386Sopenharmony_ci default: 1911cb93a386Sopenharmony_ci SkASSERT(false); 1912cb93a386Sopenharmony_ci break; 1913cb93a386Sopenharmony_ci } 1914cb93a386Sopenharmony_ci 1915cb93a386Sopenharmony_ci // Separate trailing spaces and move them in the default order of the paragraph 1916cb93a386Sopenharmony_ci // in case the run order and the paragraph order don't match 1917cb93a386Sopenharmony_ci SkRect trailingSpaces = SkRect::MakeEmpty(); 1918cb93a386Sopenharmony_ci if (this->trimmedText().end <this->textWithNewlines().end && // Line has trailing space 1919cb93a386Sopenharmony_ci this->textWithNewlines().end == intersect.end && // Range is at the end of the line 1920cb93a386Sopenharmony_ci this->trimmedText().end > intersect.start) // Range has more than just spaces 1921cb93a386Sopenharmony_ci { 1922cb93a386Sopenharmony_ci auto delta = this->spacesWidth(); 1923cb93a386Sopenharmony_ci trailingSpaces = SkRect::MakeXYWH(0, 0, 0, 0); 1924cb93a386Sopenharmony_ci // There are trailing spaces in this run 1925cb93a386Sopenharmony_ci if (paragraphStyle.getTextAlign() == TextAlign::kJustify && isLastLine()) 1926cb93a386Sopenharmony_ci { 1927cb93a386Sopenharmony_ci // TODO: this is just a patch. Make it right later (when it's clear what and how) 1928cb93a386Sopenharmony_ci trailingSpaces = clip; 1929cb93a386Sopenharmony_ci if(run->leftToRight()) { 1930cb93a386Sopenharmony_ci trailingSpaces.fLeft = this->width(); 1931cb93a386Sopenharmony_ci clip.fRight = this->width(); 1932cb93a386Sopenharmony_ci } else { 1933cb93a386Sopenharmony_ci trailingSpaces.fRight = 0; 1934cb93a386Sopenharmony_ci clip.fLeft = 0; 1935cb93a386Sopenharmony_ci } 1936cb93a386Sopenharmony_ci } else if (paragraphStyle.getTextDirection() == TextDirection::kRtl && 1937cb93a386Sopenharmony_ci !run->leftToRight()) 1938cb93a386Sopenharmony_ci { 1939cb93a386Sopenharmony_ci // Split 1940cb93a386Sopenharmony_ci trailingSpaces = clip; 1941cb93a386Sopenharmony_ci trailingSpaces.fLeft = - delta; 1942cb93a386Sopenharmony_ci trailingSpaces.fRight = 0; 1943cb93a386Sopenharmony_ci clip.fLeft += delta; 1944cb93a386Sopenharmony_ci } else if (paragraphStyle.getTextDirection() == TextDirection::kLtr && 1945cb93a386Sopenharmony_ci run->leftToRight()) 1946cb93a386Sopenharmony_ci { 1947cb93a386Sopenharmony_ci // Split 1948cb93a386Sopenharmony_ci trailingSpaces = clip; 1949cb93a386Sopenharmony_ci trailingSpaces.fLeft = this->width(); 1950cb93a386Sopenharmony_ci trailingSpaces.fRight = trailingSpaces.fLeft + delta; 1951cb93a386Sopenharmony_ci clip.fRight -= delta; 1952cb93a386Sopenharmony_ci } 1953cb93a386Sopenharmony_ci } 1954cb93a386Sopenharmony_ci 1955cb93a386Sopenharmony_ci clip.offset(this->offset()); 1956cb93a386Sopenharmony_ci if (trailingSpaces.width() > 0) { 1957cb93a386Sopenharmony_ci trailingSpaces.offset(this->offset()); 1958cb93a386Sopenharmony_ci } 1959cb93a386Sopenharmony_ci 1960cb93a386Sopenharmony_ci // Check if we can merge two boxes instead of adding a new one 1961cb93a386Sopenharmony_ci auto merge = [&lastRun, &context, &boxes](SkRect clip) { 1962cb93a386Sopenharmony_ci bool mergedBoxes = false; 1963cb93a386Sopenharmony_ci if (!boxes.empty() && 1964cb93a386Sopenharmony_ci lastRun != nullptr && 1965cb93a386Sopenharmony_ci context.run->leftToRight() == lastRun->leftToRight() && 1966cb93a386Sopenharmony_ci lastRun->placeholderStyle() == nullptr && 1967cb93a386Sopenharmony_ci context.run->placeholderStyle() == nullptr && 1968cb93a386Sopenharmony_ci nearlyEqual(lastRun->heightMultiplier(), 1969cb93a386Sopenharmony_ci context.run->heightMultiplier()) && 1970cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 1971cb93a386Sopenharmony_ci lastRun->font() == context.run->font()) 1972cb93a386Sopenharmony_ci#else 1973cb93a386Sopenharmony_ci IsRSFontEquals(lastRun->font(), context.run->font())) 1974cb93a386Sopenharmony_ci#endif 1975cb93a386Sopenharmony_ci { 1976cb93a386Sopenharmony_ci auto& lastBox = boxes.back(); 1977cb93a386Sopenharmony_ci if (nearlyEqual(lastBox.rect.fTop, clip.fTop) && 1978cb93a386Sopenharmony_ci nearlyEqual(lastBox.rect.fBottom, clip.fBottom) && 1979cb93a386Sopenharmony_ci (nearlyEqual(lastBox.rect.fLeft, clip.fRight) || 1980cb93a386Sopenharmony_ci nearlyEqual(lastBox.rect.fRight, clip.fLeft))) 1981cb93a386Sopenharmony_ci { 1982cb93a386Sopenharmony_ci lastBox.rect.fLeft = std::min(lastBox.rect.fLeft, clip.fLeft); 1983cb93a386Sopenharmony_ci lastBox.rect.fRight = std::max(lastBox.rect.fRight, clip.fRight); 1984cb93a386Sopenharmony_ci mergedBoxes = true; 1985cb93a386Sopenharmony_ci } 1986cb93a386Sopenharmony_ci } 1987cb93a386Sopenharmony_ci lastRun = context.run; 1988cb93a386Sopenharmony_ci return mergedBoxes; 1989cb93a386Sopenharmony_ci }; 1990cb93a386Sopenharmony_ci 1991cb93a386Sopenharmony_ci if (!merge(clip)) { 1992cb93a386Sopenharmony_ci boxes.emplace_back(clip, context.run->getTextDirection()); 1993cb93a386Sopenharmony_ci } 1994cb93a386Sopenharmony_ci if (!nearlyZero(trailingSpaces.width()) && !merge(trailingSpaces)) { 1995cb93a386Sopenharmony_ci boxes.emplace_back(trailingSpaces, paragraphStyle.getTextDirection()); 1996cb93a386Sopenharmony_ci } 1997cb93a386Sopenharmony_ci 1998cb93a386Sopenharmony_ci if (rectWidthStyle == RectWidthStyle::kMax && !isLastLine()) { 1999cb93a386Sopenharmony_ci // Align the very left/right box horizontally 2000cb93a386Sopenharmony_ci auto lineStart = this->offset().fX; 2001cb93a386Sopenharmony_ci auto lineEnd = this->offset().fX + this->width(); 2002cb93a386Sopenharmony_ci auto left = boxes[startBox]; 2003cb93a386Sopenharmony_ci auto right = boxes.back(); 2004cb93a386Sopenharmony_ci if (left.rect.fLeft > lineStart && left.direction == TextDirection::kRtl) { 2005cb93a386Sopenharmony_ci left.rect.fRight = left.rect.fLeft; 2006cb93a386Sopenharmony_ci left.rect.fLeft = 0; 2007cb93a386Sopenharmony_ci boxes.insert(boxes.begin() + startBox + 1, left); 2008cb93a386Sopenharmony_ci } 2009cb93a386Sopenharmony_ci if (right.direction == TextDirection::kLtr && 2010cb93a386Sopenharmony_ci right.rect.fRight >= lineEnd && 2011cb93a386Sopenharmony_ci right.rect.fRight < fOwner->widthWithTrailingSpaces()) { 2012cb93a386Sopenharmony_ci right.rect.fLeft = right.rect.fRight; 2013cb93a386Sopenharmony_ci right.rect.fRight = fOwner->widthWithTrailingSpaces(); 2014cb93a386Sopenharmony_ci boxes.emplace_back(right); 2015cb93a386Sopenharmony_ci } 2016cb93a386Sopenharmony_ci } 2017cb93a386Sopenharmony_ci 2018cb93a386Sopenharmony_ci return true; 2019cb93a386Sopenharmony_ci }); 2020cb93a386Sopenharmony_ci return true; 2021cb93a386Sopenharmony_ci }); 2022cb93a386Sopenharmony_ci if (fOwner->getApplyRoundingHack()) { 2023cb93a386Sopenharmony_ci for (auto& r : boxes) { 2024cb93a386Sopenharmony_ci r.rect.fLeft = littleRound(r.rect.fLeft); 2025cb93a386Sopenharmony_ci r.rect.fRight = littleRound(r.rect.fRight); 2026cb93a386Sopenharmony_ci r.rect.fTop = littleRound(r.rect.fTop); 2027cb93a386Sopenharmony_ci r.rect.fBottom = littleRound(r.rect.fBottom); 2028cb93a386Sopenharmony_ci } 2029cb93a386Sopenharmony_ci } 2030cb93a386Sopenharmony_ci} 2031cb93a386Sopenharmony_ci 2032cb93a386Sopenharmony_ciPositionWithAffinity TextLine::getGlyphPositionAtCoordinate(SkScalar dx) { 2033cb93a386Sopenharmony_ci 2034cb93a386Sopenharmony_ci if (SkScalarNearlyZero(this->width()) && SkScalarNearlyZero(this->spacesWidth())) { 2035cb93a386Sopenharmony_ci // TODO: this is one of the flutter changes that have to go away eventually 2036cb93a386Sopenharmony_ci // Empty line is a special case in txtlib (but only when there are no spaces, too) 2037cb93a386Sopenharmony_ci auto utf16Index = fOwner->getUTF16Index(this->fTextExcludingSpaces.end); 2038cb93a386Sopenharmony_ci return { SkToS32(utf16Index) , kDownstream }; 2039cb93a386Sopenharmony_ci } 2040cb93a386Sopenharmony_ci 2041cb93a386Sopenharmony_ci PositionWithAffinity result(0, Affinity::kDownstream); 2042cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 2043cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_REPLACED_WORD, true, 2044cb93a386Sopenharmony_ci#else 2045cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(true, 2046cb93a386Sopenharmony_ci#endif 2047cb93a386Sopenharmony_ci [this, dx, &result] 2048cb93a386Sopenharmony_ci (const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) { 2049cb93a386Sopenharmony_ci bool keepLooking = true; 2050cb93a386Sopenharmony_ci *runWidthInLine = this->iterateThroughSingleRunByStyles( 2051cb93a386Sopenharmony_ci TextAdjustment::GraphemeGluster, run, runOffsetInLine, textRange, StyleType::kNone, 2052cb93a386Sopenharmony_ci [this, run, dx, &result, &keepLooking] 2053cb93a386Sopenharmony_ci (TextRange textRange, const TextStyle& style, const TextLine::ClipContext& context0) { 2054cb93a386Sopenharmony_ci 2055cb93a386Sopenharmony_ci SkScalar offsetX = this->offset().fX; 2056cb93a386Sopenharmony_ci ClipContext context = context0; 2057cb93a386Sopenharmony_ci 2058cb93a386Sopenharmony_ci // Correct the clip size because libtxt counts trailing spaces 2059cb93a386Sopenharmony_ci if (run->leftToRight()) { 2060cb93a386Sopenharmony_ci context.clip.fRight += context.fExcludedTrailingSpaces; // extending clip to the right 2061cb93a386Sopenharmony_ci } else { 2062cb93a386Sopenharmony_ci // Clip starts from 0; we cannot extend it to the left from that 2063cb93a386Sopenharmony_ci } 2064cb93a386Sopenharmony_ci // However, we need to offset the clip 2065cb93a386Sopenharmony_ci context.clip.offset(offsetX, 0.0f); 2066cb93a386Sopenharmony_ci 2067cb93a386Sopenharmony_ci // This patch will help us to avoid a floating point error 2068cb93a386Sopenharmony_ci if (SkScalarNearlyEqual(context.clip.fRight, dx, 0.01f)) { 2069cb93a386Sopenharmony_ci context.clip.fRight = dx; 2070cb93a386Sopenharmony_ci } 2071cb93a386Sopenharmony_ci 2072cb93a386Sopenharmony_ci if (dx <= context.clip.fLeft) { 2073cb93a386Sopenharmony_ci // All the other runs are placed right of this one 2074cb93a386Sopenharmony_ci auto utf16Index = fOwner->getUTF16Index(context.run->globalClusterIndex(context.pos)); 2075cb93a386Sopenharmony_ci if (run->leftToRight()) { 2076cb93a386Sopenharmony_ci result = { SkToS32(utf16Index), kDownstream}; 2077cb93a386Sopenharmony_ci keepLooking = false; 2078cb93a386Sopenharmony_ci } else { 2079cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 2080cb93a386Sopenharmony_ci result = { SkToS32(utf16Index + 1), kUpstream}; 2081cb93a386Sopenharmony_ci size_t glyphCnt = context.run->glyphs().size(); 2082cb93a386Sopenharmony_ci if ((glyphCnt != 0) && (context.run->fUtf8Range.end() - context.run->fUtf8Range.begin()) / 2083cb93a386Sopenharmony_ci glyphCnt == EMOJI_WIDTH) { 2084cb93a386Sopenharmony_ci result = { SkToS32(utf16Index + 2), kUpstream}; 2085cb93a386Sopenharmony_ci } 2086cb93a386Sopenharmony_ci#else 2087cb93a386Sopenharmony_ci result = { SkToS32(utf16Index + 1), kUpstream}; 2088cb93a386Sopenharmony_ci#endif 2089cb93a386Sopenharmony_ci // If we haven't reached the end of the run we need to keep looking 2090cb93a386Sopenharmony_ci keepLooking = context.pos != 0; 2091cb93a386Sopenharmony_ci } 2092cb93a386Sopenharmony_ci // For RTL we go another way 2093cb93a386Sopenharmony_ci return !run->leftToRight(); 2094cb93a386Sopenharmony_ci } 2095cb93a386Sopenharmony_ci 2096cb93a386Sopenharmony_ci if (dx >= context.clip.fRight) { 2097cb93a386Sopenharmony_ci // We have to keep looking ; just in case keep the last one as the closest 2098cb93a386Sopenharmony_ci auto utf16Index = fOwner->getUTF16Index(context.run->globalClusterIndex(context.pos + context.size)); 2099cb93a386Sopenharmony_ci if (run->leftToRight()) { 2100cb93a386Sopenharmony_ci result = {SkToS32(utf16Index), kUpstream}; 2101cb93a386Sopenharmony_ci } else { 2102cb93a386Sopenharmony_ci result = {SkToS32(utf16Index), kDownstream}; 2103cb93a386Sopenharmony_ci } 2104cb93a386Sopenharmony_ci // For RTL we go another way 2105cb93a386Sopenharmony_ci return run->leftToRight(); 2106cb93a386Sopenharmony_ci } 2107cb93a386Sopenharmony_ci 2108cb93a386Sopenharmony_ci // So we found the run that contains our coordinates 2109cb93a386Sopenharmony_ci // Find the glyph position in the run that is the closest left of our point 2110cb93a386Sopenharmony_ci // TODO: binary search 2111cb93a386Sopenharmony_ci size_t found = context.pos; 2112cb93a386Sopenharmony_ci for (size_t index = context.pos; index < context.pos + context.size; ++index) { 2113cb93a386Sopenharmony_ci // TODO: this rounding is done to match Flutter tests. Must be removed.. 2114cb93a386Sopenharmony_ci auto end = context.run->positionX(index) + context.fTextShift + offsetX; 2115cb93a386Sopenharmony_ci if (fOwner->getApplyRoundingHack()) { 2116cb93a386Sopenharmony_ci end = littleRound(end); 2117cb93a386Sopenharmony_ci } 2118cb93a386Sopenharmony_ci if (end > dx) { 2119cb93a386Sopenharmony_ci break; 2120cb93a386Sopenharmony_ci } else if (end == dx && !context.run->leftToRight()) { 2121cb93a386Sopenharmony_ci // When we move RTL variable end points to the beginning of the code point which is included 2122cb93a386Sopenharmony_ci found = index; 2123cb93a386Sopenharmony_ci break; 2124cb93a386Sopenharmony_ci } 2125cb93a386Sopenharmony_ci found = index; 2126cb93a386Sopenharmony_ci } 2127cb93a386Sopenharmony_ci 2128cb93a386Sopenharmony_ci SkScalar glyphemePosLeft = context.run->positionX(found) + context.fTextShift + offsetX; 2129cb93a386Sopenharmony_ci SkScalar glyphemesWidth = context.run->positionX(found + 1) - context.run->positionX(found); 2130cb93a386Sopenharmony_ci 2131cb93a386Sopenharmony_ci // Find the grapheme range that contains the point 2132cb93a386Sopenharmony_ci auto clusterIndex8 = context.run->globalClusterIndex(found); 2133cb93a386Sopenharmony_ci auto clusterEnd8 = context.run->globalClusterIndex(found + 1); 2134cb93a386Sopenharmony_ci auto graphemes = fOwner->countSurroundingGraphemes({clusterIndex8, clusterEnd8}); 2135cb93a386Sopenharmony_ci 2136cb93a386Sopenharmony_ci SkScalar center = (context.clip.right() + context.clip.left()) / 2; 2137cb93a386Sopenharmony_ci if (graphemes.size() > 1) { 2138cb93a386Sopenharmony_ci // Calculate the position proportionally based on grapheme count 2139cb93a386Sopenharmony_ci SkScalar averageGraphemeWidth = glyphemesWidth / graphemes.size(); 2140cb93a386Sopenharmony_ci SkScalar delta = dx - glyphemePosLeft; 2141cb93a386Sopenharmony_ci int graphemeIndex = SkScalarNearlyZero(averageGraphemeWidth) 2142cb93a386Sopenharmony_ci ? 0 2143cb93a386Sopenharmony_ci : SkScalarFloorToInt(delta / averageGraphemeWidth); 2144cb93a386Sopenharmony_ci auto graphemeCenter = glyphemePosLeft + graphemeIndex * averageGraphemeWidth + 2145cb93a386Sopenharmony_ci averageGraphemeWidth * fOwner->getTextSplitRatio(); 2146cb93a386Sopenharmony_ci auto graphemeUtf8Index = graphemes[graphemeIndex]; 2147cb93a386Sopenharmony_ci if ((dx < graphemeCenter) == context.run->leftToRight()) { 2148cb93a386Sopenharmony_ci size_t utf16Index = fOwner->getUTF16Index(graphemeUtf8Index); 2149cb93a386Sopenharmony_ci result = { SkToS32(utf16Index), kDownstream }; 2150cb93a386Sopenharmony_ci } else { 2151cb93a386Sopenharmony_ci size_t utf16Index = fOwner->getUTF16Index(graphemeUtf8Index + 1); 2152cb93a386Sopenharmony_ci result = { SkToS32(utf16Index), kUpstream }; 2153cb93a386Sopenharmony_ci } 2154cb93a386Sopenharmony_ci // Keep UTF16 index as is 2155cb93a386Sopenharmony_ci } else if ((dx < center) == context.run->leftToRight()) { 2156cb93a386Sopenharmony_ci size_t utf16Index = fOwner->getUTF16Index(clusterIndex8); 2157cb93a386Sopenharmony_ci result = { SkToS32(utf16Index), kDownstream }; 2158cb93a386Sopenharmony_ci } else { 2159cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 2160cb93a386Sopenharmony_ci size_t utf16Index = 0; 2161cb93a386Sopenharmony_ci size_t glyphCnt = context.run->glyphs().size(); 2162cb93a386Sopenharmony_ci if ((glyphCnt != 0) && !context.run->leftToRight() && (context.run->fUtf8Range.end() - 2163cb93a386Sopenharmony_ci context.run->fUtf8Range.begin()) / glyphCnt == EMOJI_WIDTH) { 2164cb93a386Sopenharmony_ci utf16Index = fOwner->getUTF16Index(clusterIndex8) + 2; 2165cb93a386Sopenharmony_ci } else if (!context.run->leftToRight()) { 2166cb93a386Sopenharmony_ci utf16Index = fOwner->getUTF16Index(clusterIndex8) + 1; 2167cb93a386Sopenharmony_ci } else { 2168cb93a386Sopenharmony_ci utf16Index = fOwner->getUTF16Index(clusterEnd8); 2169cb93a386Sopenharmony_ci } 2170cb93a386Sopenharmony_ci#else 2171cb93a386Sopenharmony_ci size_t utf16Index = context.run->leftToRight() 2172cb93a386Sopenharmony_ci ? fOwner->getUTF16Index(clusterEnd8) 2173cb93a386Sopenharmony_ci : fOwner->getUTF16Index(clusterIndex8) + 1; 2174cb93a386Sopenharmony_ci#endif 2175cb93a386Sopenharmony_ci result = { SkToS32(utf16Index), kUpstream }; 2176cb93a386Sopenharmony_ci } 2177cb93a386Sopenharmony_ci 2178cb93a386Sopenharmony_ci return keepLooking = false; 2179cb93a386Sopenharmony_ci 2180cb93a386Sopenharmony_ci }); 2181cb93a386Sopenharmony_ci return keepLooking; 2182cb93a386Sopenharmony_ci } 2183cb93a386Sopenharmony_ci ); 2184cb93a386Sopenharmony_ci return result; 2185cb93a386Sopenharmony_ci} 2186cb93a386Sopenharmony_ci 2187cb93a386Sopenharmony_civoid TextLine::getRectsForPlaceholders(std::vector<TextBox>& boxes) { 2188cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 2189cb93a386Sopenharmony_ci this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_REPLACED_WORD, true, 2190cb93a386Sopenharmony_ci#else 2191cb93a386Sopenharmony_ci this->iterateThroughVisualRuns( true, 2192cb93a386Sopenharmony_ci#endif 2193cb93a386Sopenharmony_ci [&boxes, this](const Run* run, SkScalar runOffset, TextRange textRange, 2194cb93a386Sopenharmony_ci SkScalar* width) { 2195cb93a386Sopenharmony_ci auto context = this->measureTextInsideOneRun( 2196cb93a386Sopenharmony_ci textRange, run, runOffset, 0, true, TextAdjustment::GraphemeGluster); 2197cb93a386Sopenharmony_ci *width = context.clip.width(); 2198cb93a386Sopenharmony_ci 2199cb93a386Sopenharmony_ci if (textRange.width() == 0) { 2200cb93a386Sopenharmony_ci return true; 2201cb93a386Sopenharmony_ci } 2202cb93a386Sopenharmony_ci if (!run->isPlaceholder()) { 2203cb93a386Sopenharmony_ci return true; 2204cb93a386Sopenharmony_ci } 2205cb93a386Sopenharmony_ci 2206cb93a386Sopenharmony_ci SkRect clip = context.clip; 2207cb93a386Sopenharmony_ci clip.offset(this->offset()); 2208cb93a386Sopenharmony_ci 2209cb93a386Sopenharmony_ci if (fOwner->getApplyRoundingHack()) { 2210cb93a386Sopenharmony_ci clip.fLeft = littleRound(clip.fLeft); 2211cb93a386Sopenharmony_ci clip.fRight = littleRound(clip.fRight); 2212cb93a386Sopenharmony_ci clip.fTop = littleRound(clip.fTop); 2213cb93a386Sopenharmony_ci clip.fBottom = littleRound(clip.fBottom); 2214cb93a386Sopenharmony_ci } 2215cb93a386Sopenharmony_ci boxes.emplace_back(clip, run->getTextDirection()); 2216cb93a386Sopenharmony_ci return true; 2217cb93a386Sopenharmony_ci }); 2218cb93a386Sopenharmony_ci} 2219cb93a386Sopenharmony_ci 2220cb93a386Sopenharmony_cisize_t TextLine::getGlyphCount() const 2221cb93a386Sopenharmony_ci{ 2222cb93a386Sopenharmony_ci size_t glyphCount = 0; 2223cb93a386Sopenharmony_ci for (auto& blob: fTextBlobCache) { 2224cb93a386Sopenharmony_ci glyphCount += blob.fVisitor_Size; 2225cb93a386Sopenharmony_ci } 2226cb93a386Sopenharmony_ci return glyphCount; 2227cb93a386Sopenharmony_ci} 2228cb93a386Sopenharmony_ci 2229cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 2230cb93a386Sopenharmony_cistd::vector<std::unique_ptr<RunBase>> TextLine::getGlyphRuns() const 2231cb93a386Sopenharmony_ci{ 2232cb93a386Sopenharmony_ci std::vector<std::unique_ptr<RunBase>> runBases; 2233cb93a386Sopenharmony_ci size_t num = 0; 2234cb93a386Sopenharmony_ci // Gets the offset position of the current line across the paragraph 2235cb93a386Sopenharmony_ci size_t pos = fClusterRange.start; 2236cb93a386Sopenharmony_ci size_t trailSpaces = 0; 2237cb93a386Sopenharmony_ci for (auto& blob: fTextBlobCache) { 2238cb93a386Sopenharmony_ci ++num; 2239cb93a386Sopenharmony_ci if (blob.fVisitor_Size == 0) { 2240cb93a386Sopenharmony_ci continue; 2241cb93a386Sopenharmony_ci } 2242cb93a386Sopenharmony_ci if (num == fTextBlobCache.size()) { 2243cb93a386Sopenharmony_ci // Counts how many tabs have been removed from the end of the current line 2244cb93a386Sopenharmony_ci trailSpaces = fGhostClusterRange.width() - fClusterRange.width(); 2245cb93a386Sopenharmony_ci } 2246cb93a386Sopenharmony_ci std::unique_ptr<RunBaseImpl> runBaseImplPtr = std::make_unique<RunBaseImpl>( 2247cb93a386Sopenharmony_ci blob.fBlob, blob.fOffset, blob.fPaint, blob.fClippingNeeded, blob.fClipRect, 2248cb93a386Sopenharmony_ci blob.fVisitor_Run, blob.fVisitor_Pos, pos, trailSpaces, blob.fVisitor_Size); 2249cb93a386Sopenharmony_ci 2250cb93a386Sopenharmony_ci // Calculate the position of each blob, relative to the entire paragraph 2251cb93a386Sopenharmony_ci pos += blob.fVisitor_Size; 2252cb93a386Sopenharmony_ci runBases.emplace_back(std::move(runBaseImplPtr)); 2253cb93a386Sopenharmony_ci } 2254cb93a386Sopenharmony_ci return runBases; 2255cb93a386Sopenharmony_ci} 2256cb93a386Sopenharmony_ci#else 2257cb93a386Sopenharmony_cistd::vector<std::unique_ptr<RunBase>> TextLine::getGlyphRuns() const 2258cb93a386Sopenharmony_ci{ 2259cb93a386Sopenharmony_ci std::vector<std::unique_ptr<RunBase>> runBases; 2260cb93a386Sopenharmony_ci for (auto& blob: fTextBlobCache) { 2261cb93a386Sopenharmony_ci std::unique_ptr<RunBaseImpl> runBaseImplPtr = std::make_unique<RunBaseImpl>( 2262cb93a386Sopenharmony_ci blob.fBlob, blob.fOffset, blob.fPaint, blob.fClippingNeeded, blob.fClipRect, 2263cb93a386Sopenharmony_ci blob.fVisitor_Run, blob.fVisitor_Pos, blob.fVisitor_Size); 2264cb93a386Sopenharmony_ci runBases.emplace_back(std::move(runBaseImplPtr)); 2265cb93a386Sopenharmony_ci } 2266cb93a386Sopenharmony_ci return runBases; 2267cb93a386Sopenharmony_ci} 2268cb93a386Sopenharmony_ci#endif 2269cb93a386Sopenharmony_ci 2270cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 2271cb93a386Sopenharmony_ciint getEndWhitespaceCount(const ClusterRange& range, ParagraphImpl* owner) 2272cb93a386Sopenharmony_ci{ 2273cb93a386Sopenharmony_ci if (owner == nullptr) { 2274cb93a386Sopenharmony_ci return 0; 2275cb93a386Sopenharmony_ci } 2276cb93a386Sopenharmony_ci 2277cb93a386Sopenharmony_ci int endWhitespaceCount = 0; 2278cb93a386Sopenharmony_ci for (auto clusterIndex = range.end - 1; clusterIndex >= range.start; clusterIndex--) { 2279cb93a386Sopenharmony_ci if (!owner->cluster(clusterIndex).isWhitespaceBreak()) { 2280cb93a386Sopenharmony_ci break; 2281cb93a386Sopenharmony_ci } 2282cb93a386Sopenharmony_ci 2283cb93a386Sopenharmony_ci endWhitespaceCount++; 2284cb93a386Sopenharmony_ci if (clusterIndex == range.start) { 2285cb93a386Sopenharmony_ci break; 2286cb93a386Sopenharmony_ci } 2287cb93a386Sopenharmony_ci } 2288cb93a386Sopenharmony_ci 2289cb93a386Sopenharmony_ci return endWhitespaceCount; 2290cb93a386Sopenharmony_ci} 2291cb93a386Sopenharmony_ci 2292cb93a386Sopenharmony_cistd::unique_ptr<TextLineBase> TextLine::createTruncatedLine(double width, EllipsisModal ellipsisMode, 2293cb93a386Sopenharmony_ci const std::string& ellipsisStr) 2294cb93a386Sopenharmony_ci{ 2295cb93a386Sopenharmony_ci if (width > 0 && (ellipsisMode == EllipsisModal::HEAD || ellipsisMode == EllipsisModal::TAIL)) { 2296cb93a386Sopenharmony_ci TextLine textLine = CloneSelf(); 2297cb93a386Sopenharmony_ci if (width < widthWithEllipsisSpaces() && !ellipsisStr.empty()) { 2298cb93a386Sopenharmony_ci if (ellipsisMode == EllipsisModal::HEAD) { 2299cb93a386Sopenharmony_ci textLine.fIsTextLineEllipsisHeadModal = true; 2300cb93a386Sopenharmony_ci textLine.setTextBlobCachePopulated(false); 2301cb93a386Sopenharmony_ci textLine.createHeadEllipsis(width, SkString(ellipsisStr), true); 2302cb93a386Sopenharmony_ci } else if (ellipsisMode == EllipsisModal::TAIL) { 2303cb93a386Sopenharmony_ci textLine.fIsTextLineEllipsisHeadModal = false; 2304cb93a386Sopenharmony_ci textLine.setTextBlobCachePopulated(false); 2305cb93a386Sopenharmony_ci int endWhitespaceCount = getEndWhitespaceCount(fGhostClusterRange, fOwner); 2306cb93a386Sopenharmony_ci textLine.fGhostClusterRange.end -= endWhitespaceCount; 2307cb93a386Sopenharmony_ci textLine.createTailEllipsis(width, SkString(ellipsisStr), true, fOwner->getWordBreakType()); 2308cb93a386Sopenharmony_ci } 2309cb93a386Sopenharmony_ci } 2310cb93a386Sopenharmony_ci return std::make_unique<TextLineBaseImpl>(std::make_unique<TextLine>(std::move(textLine))); 2311cb93a386Sopenharmony_ci } 2312cb93a386Sopenharmony_ci 2313cb93a386Sopenharmony_ci return nullptr; 2314cb93a386Sopenharmony_ci} 2315cb93a386Sopenharmony_ci 2316cb93a386Sopenharmony_cidouble TextLine::getTypographicBounds(double* ascent, double* descent, double* leading) const 2317cb93a386Sopenharmony_ci{ 2318cb93a386Sopenharmony_ci if (ascent == nullptr || descent == nullptr || leading == nullptr) { 2319cb93a386Sopenharmony_ci return 0.0; 2320cb93a386Sopenharmony_ci } 2321cb93a386Sopenharmony_ci 2322cb93a386Sopenharmony_ci *ascent = std::abs(fMaxRunMetrics.ascent()); 2323cb93a386Sopenharmony_ci *descent = std::abs(fMaxRunMetrics.descent()); 2324cb93a386Sopenharmony_ci *leading = fMaxRunMetrics.leading(); 2325cb93a386Sopenharmony_ci return widthWithEllipsisSpaces(); 2326cb93a386Sopenharmony_ci} 2327cb93a386Sopenharmony_ci 2328cb93a386Sopenharmony_cisize_t getPrevGlyphsIndex(const ClusterRange& range, ParagraphImpl* owner, RunIndex& prevRunIndex) 2329cb93a386Sopenharmony_ci{ 2330cb93a386Sopenharmony_ci if (owner == nullptr) { 2331cb93a386Sopenharmony_ci return 0; 2332cb93a386Sopenharmony_ci } 2333cb93a386Sopenharmony_ci 2334cb93a386Sopenharmony_ci size_t glyphsIndex = 0; 2335cb93a386Sopenharmony_ci auto clusterIndex = range.start - 1; 2336cb93a386Sopenharmony_ci prevRunIndex = owner->cluster(clusterIndex).runIndex(); 2337cb93a386Sopenharmony_ci if (prevRunIndex != owner->cluster(range.start).runIndex()) { 2338cb93a386Sopenharmony_ci // Belongs to a different run. 2339cb93a386Sopenharmony_ci return 0; 2340cb93a386Sopenharmony_ci } 2341cb93a386Sopenharmony_ci 2342cb93a386Sopenharmony_ci for (; clusterIndex >= 0; clusterIndex--) { 2343cb93a386Sopenharmony_ci RunIndex runIndex = owner->cluster(clusterIndex).runIndex(); 2344cb93a386Sopenharmony_ci if (prevRunIndex != runIndex) { 2345cb93a386Sopenharmony_ci // Found a different run. 2346cb93a386Sopenharmony_ci break; 2347cb93a386Sopenharmony_ci } 2348cb93a386Sopenharmony_ci 2349cb93a386Sopenharmony_ci glyphsIndex++; 2350cb93a386Sopenharmony_ci 2351cb93a386Sopenharmony_ci if (clusterIndex == 0) { 2352cb93a386Sopenharmony_ci // All belong to the first run. 2353cb93a386Sopenharmony_ci break; 2354cb93a386Sopenharmony_ci } 2355cb93a386Sopenharmony_ci } 2356cb93a386Sopenharmony_ci 2357cb93a386Sopenharmony_ci return glyphsIndex; 2358cb93a386Sopenharmony_ci} 2359cb93a386Sopenharmony_ci 2360cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 2361cb93a386Sopenharmony_cistd::vector<SkRect> getAllRectInfo(const ClusterRange& range, ParagraphImpl* owner) 2362cb93a386Sopenharmony_ci{ 2363cb93a386Sopenharmony_ci std::vector<SkRect> rectVec; 2364cb93a386Sopenharmony_ci#else 2365cb93a386Sopenharmony_cistd::vector<RSRect> getAllRectInfo(const ClusterRange& range, ParagraphImpl* owner) 2366cb93a386Sopenharmony_ci{ 2367cb93a386Sopenharmony_ci std::vector<RSRect> rectVec; 2368cb93a386Sopenharmony_ci#endif 2369cb93a386Sopenharmony_ci if (owner == nullptr) { 2370cb93a386Sopenharmony_ci return rectVec; 2371cb93a386Sopenharmony_ci } 2372cb93a386Sopenharmony_ci 2373cb93a386Sopenharmony_ci // If it is not the first line, you need to get the GlyphsIndex of the first character. 2374cb93a386Sopenharmony_ci size_t glyphsIndex = 0; 2375cb93a386Sopenharmony_ci RunIndex prevRunIndex = 0; 2376cb93a386Sopenharmony_ci if (range.start > 0) { 2377cb93a386Sopenharmony_ci glyphsIndex = getPrevGlyphsIndex(range, owner, prevRunIndex); 2378cb93a386Sopenharmony_ci } 2379cb93a386Sopenharmony_ci 2380cb93a386Sopenharmony_ci for (auto clusterIndex = range.start; clusterIndex < range.end; clusterIndex++) { 2381cb93a386Sopenharmony_ci RunIndex runIndex = owner->cluster(clusterIndex).runIndex(); 2382cb93a386Sopenharmony_ci if (prevRunIndex != runIndex) { 2383cb93a386Sopenharmony_ci glyphsIndex = 0; 2384cb93a386Sopenharmony_ci } 2385cb93a386Sopenharmony_ci 2386cb93a386Sopenharmony_ci auto run = owner->cluster(clusterIndex).runOrNull(); 2387cb93a386Sopenharmony_ci if (run == nullptr) { 2388cb93a386Sopenharmony_ci break; 2389cb93a386Sopenharmony_ci } 2390cb93a386Sopenharmony_ci 2391cb93a386Sopenharmony_ci SkGlyphID glyphId = run->glyphs()[glyphsIndex]; 2392cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 2393cb93a386Sopenharmony_ci SkRect glyphBounds; 2394cb93a386Sopenharmony_ci run->font().getBounds(&glyphId, 1, &glyphBounds, nullptr); 2395cb93a386Sopenharmony_ci#else 2396cb93a386Sopenharmony_ci RSRect glyphBounds; 2397cb93a386Sopenharmony_ci run->font().GetWidths(&glyphId, 1, nullptr, &glyphBounds); 2398cb93a386Sopenharmony_ci#endif 2399cb93a386Sopenharmony_ci rectVec.push_back(glyphBounds); 2400cb93a386Sopenharmony_ci glyphsIndex++; 2401cb93a386Sopenharmony_ci prevRunIndex = runIndex; 2402cb93a386Sopenharmony_ci } 2403cb93a386Sopenharmony_ci 2404cb93a386Sopenharmony_ci return rectVec; 2405cb93a386Sopenharmony_ci} 2406cb93a386Sopenharmony_ci 2407cb93a386Sopenharmony_ciRSRect TextLine::getImageBounds() const 2408cb93a386Sopenharmony_ci{ 2409cb93a386Sopenharmony_ci // Look for the first non-space character from the end and get its advance and index 2410cb93a386Sopenharmony_ci // to calculate the final image bounds. 2411cb93a386Sopenharmony_ci SkRect rect = {0.0, 0.0, 0.0, 0.0}; 2412cb93a386Sopenharmony_ci int endWhitespaceCount = getEndWhitespaceCount(fGhostClusterRange, fOwner); 2413cb93a386Sopenharmony_ci if (endWhitespaceCount == (fGhostClusterRange.end - fGhostClusterRange.start)) { 2414cb93a386Sopenharmony_ci // Full of Spaces. 2415cb93a386Sopenharmony_ci return {}; 2416cb93a386Sopenharmony_ci } 2417cb93a386Sopenharmony_ci SkScalar endAdvance = fOwner->cluster(fGhostClusterRange.end - endWhitespaceCount - 1).width(); 2418cb93a386Sopenharmony_ci 2419cb93a386Sopenharmony_ci // The first space width of the line needs to be added to the x value. 2420cb93a386Sopenharmony_ci SkScalar startWhitespaceAdvance = 0.0; 2421cb93a386Sopenharmony_ci int startWhitespaceCount = 0; 2422cb93a386Sopenharmony_ci for (auto clusterIndex = fGhostClusterRange.start; clusterIndex < fGhostClusterRange.end; clusterIndex++) { 2423cb93a386Sopenharmony_ci if (fOwner->cluster(clusterIndex).isWhitespaceBreak()) { 2424cb93a386Sopenharmony_ci startWhitespaceAdvance += fOwner->cluster(clusterIndex).width(); 2425cb93a386Sopenharmony_ci startWhitespaceCount++; 2426cb93a386Sopenharmony_ci } else { 2427cb93a386Sopenharmony_ci break; 2428cb93a386Sopenharmony_ci } 2429cb93a386Sopenharmony_ci } 2430cb93a386Sopenharmony_ci 2431cb93a386Sopenharmony_ci // Gets rect information for all characters in line. 2432cb93a386Sopenharmony_ci auto rectVec = getAllRectInfo(fGhostClusterRange, fOwner); 2433cb93a386Sopenharmony_ci // Calculate the final y and height. 2434cb93a386Sopenharmony_ci auto joinRect = rectVec[startWhitespaceCount]; 2435cb93a386Sopenharmony_ci for (int i = startWhitespaceCount + 1; i < rectVec.size() - endWhitespaceCount; ++i) { 2436cb93a386Sopenharmony_ci joinRect.Join(rectVec[i]); 2437cb93a386Sopenharmony_ci } 2438cb93a386Sopenharmony_ci 2439cb93a386Sopenharmony_ci SkScalar lineWidth = width(); 2440cb93a386Sopenharmony_ci auto endRect = rectVec[rectVec.size() - endWhitespaceCount - 1]; 2441cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT 2442cb93a386Sopenharmony_ci SkScalar x = rectVec[startWhitespaceCount].x() + startWhitespaceAdvance; 2443cb93a386Sopenharmony_ci SkScalar y = joinRect.bottom(); 2444cb93a386Sopenharmony_ci SkScalar width = lineWidth - (endAdvance - endRect.x() - endRect.width()) - x; 2445cb93a386Sopenharmony_ci SkScalar height = joinRect.height(); 2446cb93a386Sopenharmony_ci#else 2447cb93a386Sopenharmony_ci SkScalar x = rectVec[startWhitespaceCount].GetLeft() + startWhitespaceAdvance; 2448cb93a386Sopenharmony_ci SkScalar y = joinRect.GetBottom(); 2449cb93a386Sopenharmony_ci SkScalar width = lineWidth - (endAdvance - endRect.GetLeft() - endRect.GetWidth()) - x; 2450cb93a386Sopenharmony_ci SkScalar height = joinRect.GetHeight(); 2451cb93a386Sopenharmony_ci#endif 2452cb93a386Sopenharmony_ci 2453cb93a386Sopenharmony_ci rect.setXYWH(x, y, width, height); 2454cb93a386Sopenharmony_ci return {rect.fLeft, rect.fTop, rect.fRight, rect.fBottom}; 2455cb93a386Sopenharmony_ci} 2456cb93a386Sopenharmony_ci 2457cb93a386Sopenharmony_cidouble TextLine::getTrailingSpaceWidth() const 2458cb93a386Sopenharmony_ci{ 2459cb93a386Sopenharmony_ci return spacesWidth(); 2460cb93a386Sopenharmony_ci} 2461cb93a386Sopenharmony_ci 2462cb93a386Sopenharmony_ciint32_t TextLine::getStringIndexForPosition(SkPoint point) const 2463cb93a386Sopenharmony_ci{ 2464cb93a386Sopenharmony_ci int32_t index = fGhostClusterRange.start; 2465cb93a386Sopenharmony_ci double offset = point.x(); 2466cb93a386Sopenharmony_ci if (offset >= widthWithEllipsisSpaces()) { 2467cb93a386Sopenharmony_ci index = fGhostClusterRange.end; 2468cb93a386Sopenharmony_ci } else if (offset > 0) { 2469cb93a386Sopenharmony_ci double curOffset = 0.0; 2470cb93a386Sopenharmony_ci for (auto clusterIndex = fGhostClusterRange.start; clusterIndex < fGhostClusterRange.end; ++clusterIndex) { 2471cb93a386Sopenharmony_ci double characterWidth = fOwner->cluster(clusterIndex).width(); 2472cb93a386Sopenharmony_ci if (offset <= curOffset + characterWidth / 2) { 2473cb93a386Sopenharmony_ci return index; 2474cb93a386Sopenharmony_ci } 2475cb93a386Sopenharmony_ci index++; 2476cb93a386Sopenharmony_ci curOffset += characterWidth; 2477cb93a386Sopenharmony_ci } 2478cb93a386Sopenharmony_ci } 2479cb93a386Sopenharmony_ci 2480cb93a386Sopenharmony_ci return index; 2481cb93a386Sopenharmony_ci} 2482cb93a386Sopenharmony_ci 2483cb93a386Sopenharmony_cidouble TextLine::getOffsetForStringIndex(int32_t index) const 2484cb93a386Sopenharmony_ci{ 2485cb93a386Sopenharmony_ci double offset = 0.0; 2486cb93a386Sopenharmony_ci if (index <= 0) { 2487cb93a386Sopenharmony_ci return offset; 2488cb93a386Sopenharmony_ci } 2489cb93a386Sopenharmony_ci 2490cb93a386Sopenharmony_ci if (index >= fGhostClusterRange.end) { 2491cb93a386Sopenharmony_ci offset = widthWithEllipsisSpaces(); 2492cb93a386Sopenharmony_ci } else if (index > fGhostClusterRange.start) { 2493cb93a386Sopenharmony_ci size_t clusterIndex = fGhostClusterRange.start; 2494cb93a386Sopenharmony_ci while (clusterIndex < fGhostClusterRange.end) { 2495cb93a386Sopenharmony_ci offset += fOwner->cluster(clusterIndex).width(); 2496cb93a386Sopenharmony_ci if (++clusterIndex == index) { 2497cb93a386Sopenharmony_ci break; 2498cb93a386Sopenharmony_ci } 2499cb93a386Sopenharmony_ci } 2500cb93a386Sopenharmony_ci } 2501cb93a386Sopenharmony_ci 2502cb93a386Sopenharmony_ci return offset; 2503cb93a386Sopenharmony_ci} 2504cb93a386Sopenharmony_ci 2505cb93a386Sopenharmony_cistd::map<int32_t, double> TextLine::getIndexAndOffsets(bool& isHardBreak) const 2506cb93a386Sopenharmony_ci{ 2507cb93a386Sopenharmony_ci std::map<int32_t, double> offsetMap; 2508cb93a386Sopenharmony_ci double offset = 0.0; 2509cb93a386Sopenharmony_ci for (auto clusterIndex = fGhostClusterRange.start; clusterIndex < fGhostClusterRange.end; ++clusterIndex) { 2510cb93a386Sopenharmony_ci auto& cluster = fOwner->cluster(clusterIndex); 2511cb93a386Sopenharmony_ci offset += cluster.width(); 2512cb93a386Sopenharmony_ci isHardBreak = cluster.isHardBreak(); 2513cb93a386Sopenharmony_ci if (!isHardBreak) { 2514cb93a386Sopenharmony_ci offsetMap[clusterIndex] = offset; 2515cb93a386Sopenharmony_ci } 2516cb93a386Sopenharmony_ci } 2517cb93a386Sopenharmony_ci return offsetMap; 2518cb93a386Sopenharmony_ci} 2519cb93a386Sopenharmony_ci 2520cb93a386Sopenharmony_cidouble TextLine::getAlignmentOffset(double alignmentFactor, double alignmentWidth) const 2521cb93a386Sopenharmony_ci{ 2522cb93a386Sopenharmony_ci double lineWidth = width(); 2523cb93a386Sopenharmony_ci if (alignmentWidth <= lineWidth) { 2524cb93a386Sopenharmony_ci return 0.0; 2525cb93a386Sopenharmony_ci } 2526cb93a386Sopenharmony_ci 2527cb93a386Sopenharmony_ci double offset = 0.0; 2528cb93a386Sopenharmony_ci TextDirection textDirection = fOwner->paragraphStyle().getTextDirection(); 2529cb93a386Sopenharmony_ci if (alignmentFactor <= 0) { 2530cb93a386Sopenharmony_ci // Flush left. 2531cb93a386Sopenharmony_ci if (textDirection == TextDirection::kRtl) { 2532cb93a386Sopenharmony_ci offset = lineWidth - alignmentWidth; 2533cb93a386Sopenharmony_ci } 2534cb93a386Sopenharmony_ci } else if (alignmentFactor < 1) { 2535cb93a386Sopenharmony_ci // Align according to the alignmentFactor. 2536cb93a386Sopenharmony_ci if (textDirection == TextDirection::kLtr) { 2537cb93a386Sopenharmony_ci offset = (alignmentWidth - lineWidth) * alignmentFactor; 2538cb93a386Sopenharmony_ci } else { 2539cb93a386Sopenharmony_ci offset = (lineWidth - alignmentWidth) * (1 - alignmentFactor); 2540cb93a386Sopenharmony_ci } 2541cb93a386Sopenharmony_ci } else { 2542cb93a386Sopenharmony_ci // Flush right. 2543cb93a386Sopenharmony_ci if (textDirection == TextDirection::kLtr) { 2544cb93a386Sopenharmony_ci offset = alignmentWidth - lineWidth; 2545cb93a386Sopenharmony_ci } 2546cb93a386Sopenharmony_ci } 2547cb93a386Sopenharmony_ci 2548cb93a386Sopenharmony_ci return offset; 2549cb93a386Sopenharmony_ci} 2550cb93a386Sopenharmony_ci#endif 2551cb93a386Sopenharmony_ci 2552cb93a386Sopenharmony_ciTextLine TextLine::CloneSelf() 2553cb93a386Sopenharmony_ci{ 2554cb93a386Sopenharmony_ci TextLine textLine; 2555cb93a386Sopenharmony_ci textLine.fBlockRange = this->fBlockRange; 2556cb93a386Sopenharmony_ci textLine.fTextExcludingSpaces = this->fTextExcludingSpaces; 2557cb93a386Sopenharmony_ci textLine.fText = this->fText; 2558cb93a386Sopenharmony_ci textLine.fTextIncludingNewlines = this->fTextIncludingNewlines; 2559cb93a386Sopenharmony_ci textLine.fClusterRange = this->fClusterRange; 2560cb93a386Sopenharmony_ci 2561cb93a386Sopenharmony_ci textLine.fGhostClusterRange = this->fGhostClusterRange; 2562cb93a386Sopenharmony_ci textLine.fRunsInVisualOrder = this->fRunsInVisualOrder; 2563cb93a386Sopenharmony_ci textLine.fAdvance = this->fAdvance; 2564cb93a386Sopenharmony_ci textLine.fOffset = this->fOffset; 2565cb93a386Sopenharmony_ci textLine.fShift = this->fShift; 2566cb93a386Sopenharmony_ci 2567cb93a386Sopenharmony_ci textLine.fWidthWithSpaces = this->fWidthWithSpaces; 2568cb93a386Sopenharmony_ci if (this->fEllipsis) { 2569cb93a386Sopenharmony_ci textLine.fEllipsis = std::make_unique<Run>(*this->fEllipsis); 2570cb93a386Sopenharmony_ci } 2571cb93a386Sopenharmony_ci 2572cb93a386Sopenharmony_ci textLine.fSizes = this->fSizes; 2573cb93a386Sopenharmony_ci textLine.fMaxRunMetrics = this->fMaxRunMetrics; 2574cb93a386Sopenharmony_ci textLine.fHasBackground = this->fHasBackground; 2575cb93a386Sopenharmony_ci textLine.fHasShadows = this->fHasShadows; 2576cb93a386Sopenharmony_ci textLine.fHasDecorations = this->fHasDecorations; 2577cb93a386Sopenharmony_ci textLine.fAscentStyle = this->fAscentStyle; 2578cb93a386Sopenharmony_ci textLine.fDescentStyle = this->fDescentStyle; 2579cb93a386Sopenharmony_ci textLine.fTextBlobCachePopulated = this->fTextBlobCachePopulated; 2580cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT 2581cb93a386Sopenharmony_ci textLine.fOwner = this->fOwner; 2582cb93a386Sopenharmony_ci textLine.fIsTextLineEllipsisHeadModal = this->fIsTextLineEllipsisHeadModal; 2583cb93a386Sopenharmony_ci#endif 2584cb93a386Sopenharmony_ci 2585cb93a386Sopenharmony_ci textLine.roundRectAttrs = this->roundRectAttrs; 2586cb93a386Sopenharmony_ci textLine.fTextBlobCache = this->fTextBlobCache; 2587cb93a386Sopenharmony_ci textLine.fTextRangeReplacedByEllipsis = this->fTextRangeReplacedByEllipsis; 2588cb93a386Sopenharmony_ci textLine.fEllipsisIndex = this->fEllipsisIndex; 2589cb93a386Sopenharmony_ci textLine.fLastClipRunLtr = this->fLastClipRunLtr; 2590cb93a386Sopenharmony_ci return textLine; 2591cb93a386Sopenharmony_ci} 2592cb93a386Sopenharmony_ci} // namespace textlayout 2593cb93a386Sopenharmony_ci} // namespace skia 2594