diff --git a/modules/skparagraph/src/OneLineShaper.cpp b/modules/skparagraph/src/OneLineShaper.cpp index 67ea5204f025a4cb229f740ae234716513fe3490..2c0fb0f889624cb062758fd9d0953bded6888a9b 100644 --- a/modules/skparagraph/src/OneLineShaper.cpp +++ b/modules/skparagraph/src/OneLineShaper.cpp @@ -151,6 +151,117 @@ void OneLineShaper::fillGaps(size_t startingCount) { } } +#ifdef OHOS_SUPPORT +// 1. glyphs in run between [glyphStart, glyphEnd) are all equal to zero. +// 2. run is nullptr. +// 3. charStart flag has kCombine. +// one of the above conditions is met, will return true. +// anything else, return false. +bool OneLineShaper::isUnresolvedCombineGlyphRange(std::shared_ptr run, size_t glyphStart, size_t glyphEnd, + size_t charStart) const +{ + if (run == nullptr || + (fParagraph != nullptr && !fParagraph->codeUnitHasProperty(charStart, SkUnicode::kCombine))) { + return true; + } + size_t iterGlyphEnd = std::min(run->fGlyphs.size(), glyphEnd); + for (size_t glyph = glyphStart; glyph < iterGlyphEnd; ++glyph) { + if (run->fGlyphs[glyph] != 0) { + return false; + } + } + + return true; +} + +// split unresolvedBlock. +// extract resolvedBlock(which isUnresolvedGlyphRange is false), emplace back to stagedUnresolvedBlocks. +// the rest block emplace back to fUnresolvedBlocks without run. +void OneLineShaper::splitUnresolvedBlockAndStageResolvedSubBlock( + std::deque& stagedUnresolvedBlocks, const RunBlock& unresolvedBlock) +{ + if (unresolvedBlock.fRun == nullptr) { + return; + } + std::shared_ptr run = unresolvedBlock.fRun; + bool hasUnresolvedText = false; + size_t curTextStart = EMPTY_INDEX; + size_t curGlyphEdge = EMPTY_INDEX; + run->iterateGlyphRangeInTextOrder(unresolvedBlock.fGlyphs, + [&stagedUnresolvedBlocks, &hasUnresolvedText, &curTextStart, &curGlyphEdge, run, this] + (size_t glyphStart, size_t glyphEnd, size_t charStart, size_t charEnd) { + if (!isUnresolvedCombineGlyphRange(run, glyphStart, glyphEnd, charStart)) { + if (curTextStart == EMPTY_INDEX) { + curTextStart = charStart; + } + if (curGlyphEdge == EMPTY_INDEX) { + curGlyphEdge = run->leftToRight() ? glyphStart : glyphEnd; + } + return; + } + hasUnresolvedText = true; + this->fUnresolvedBlocks.emplace_back(RunBlock(TextRange(charStart, charEnd))); + if (curTextStart == EMPTY_INDEX) { + return; + } + if (run->leftToRight()) { + stagedUnresolvedBlocks.emplace_back( + run, TextRange(curTextStart, charStart), GlyphRange(curGlyphEdge, glyphStart), 0); + } else { + stagedUnresolvedBlocks.emplace_back( + run, TextRange(curTextStart, charStart), GlyphRange(glyphEnd, curGlyphEdge), 0); + } + curTextStart = EMPTY_INDEX; + curGlyphEdge = EMPTY_INDEX; + }); + if (!hasUnresolvedText) { + stagedUnresolvedBlocks.emplace_back(unresolvedBlock); + return; + } + if (curTextStart == EMPTY_INDEX) { + return; + } + if (run->leftToRight()) { + stagedUnresolvedBlocks.emplace_back(run, TextRange(curTextStart, unresolvedBlock.fText.end), + GlyphRange(curGlyphEdge, unresolvedBlock.fGlyphs.end), 0); + } else { + stagedUnresolvedBlocks.emplace_back(run, TextRange(curTextStart, unresolvedBlock.fText.end), + GlyphRange(unresolvedBlock.fGlyphs.start, curGlyphEdge), 0); + } +} + +// shape unresolved text separately. +void OneLineShaper::shapeUnresolvedTextSeparatelyFromUnresolvedBlock( + const TextStyle& textStyle, const TypefaceVisitor& visitor) +{ + if (fUnresolvedBlocks.empty()) { + return; + } + TEXT_TRACE_FUNC(); + std::deque stagedUnresolvedBlocks; + size_t unresolvedBlockCount = fUnresolvedBlocks.size(); + while (unresolvedBlockCount-- > 0) { + RunBlock unresolvedBlock = fUnresolvedBlocks.front(); + fUnresolvedBlocks.pop_front(); + + if (unresolvedBlock.fText.width() <= 1 || unresolvedBlock.fRun == nullptr) { + stagedUnresolvedBlocks.emplace_back(unresolvedBlock); + continue; + } + + splitUnresolvedBlockAndStageResolvedSubBlock(stagedUnresolvedBlocks, unresolvedBlock); + } + + this->matchResolvedFonts(textStyle, visitor); + + while (!stagedUnresolvedBlocks.empty()) { + auto block = stagedUnresolvedBlocks.front(); + stagedUnresolvedBlocks.pop_front(); + fUnresolvedBlocks.emplace_back(block); + } +} +#endif + void OneLineShaper::finish(const Block& block, SkScalar height, SkScalar& advanceX) { auto blockText = block.fRange; @@ -671,12 +782,15 @@ bool OneLineShaper::shape() { fCurrentText = block.fRange; fUnresolvedBlocks.emplace_back(RunBlock(block.fRange)); -#ifndef USE_SKIA_TXT - this->matchResolvedFonts(block.fStyle, [&](sk_sp typeface) { +#ifdef OHOS_SUPPORT +#ifdef USE_SKIA_TXT + auto typefaceVisitor = [&](std::shared_ptr typeface) { #else - this->matchResolvedFonts(block.fStyle, [&](std::shared_ptr typeface) { + auto typefaceVisitor = [&](sk_sp typeface) { +#endif +#else + this->matchResolvedFonts(block.fStyle, [&](sk_sp typeface) { #endif - // Create one more font to try #ifndef USE_SKIA_TXT SkFont font(std::move(typeface), block.fStyle.getFontSize()); @@ -770,8 +884,13 @@ bool OneLineShaper::shape() { } else { return Resolved::Nothing; } +#ifdef OHOS_SUPPORT + }; + this->matchResolvedFonts(block.fStyle, typefaceVisitor); + this->shapeUnresolvedTextSeparatelyFromUnresolvedBlock(block.fStyle, typefaceVisitor); +#else }); - +#endif this->finish(block, fHeight, advanceX); }); diff --git a/modules/skparagraph/src/OneLineShaper.h b/modules/skparagraph/src/OneLineShaper.h index aaaed2965ebc58b6a5c43088d22859d555618c24..d2d800c67a0da083181f6111f7b61fa37e30687f 100644 --- a/modules/skparagraph/src/OneLineShaper.h +++ b/modules/skparagraph/src/OneLineShaper.h @@ -74,6 +74,15 @@ private: using TypefaceVisitor = std::function typeface)>; #endif void matchResolvedFonts(const TextStyle& textStyle, const TypefaceVisitor& visitor); + +#ifdef OHOS_SUPPORT + bool isUnresolvedCombineGlyphRange(std::shared_ptr run, size_t glyphStart, size_t glyphEnd, + size_t charStart) const; + void splitUnresolvedBlockAndStageResolvedSubBlock( + std::deque& stagedUnresolvedBlocks, const RunBlock& unresolvedBlock); + void shapeUnresolvedTextSeparatelyFromUnresolvedBlock(const TextStyle& textStyle, const TypefaceVisitor& visitor); +#endif + #ifdef SK_DEBUG void printState(); #endif diff --git a/modules/skparagraph/src/ParagraphImpl.cpp b/modules/skparagraph/src/ParagraphImpl.cpp index fe8a25d562f6b7ab28dd30935472e2cd9f86e0ca..024ab850c20f2ac33525d067e0750cd751defd96 100644 --- a/modules/skparagraph/src/ParagraphImpl.cpp +++ b/modules/skparagraph/src/ParagraphImpl.cpp @@ -2276,6 +2276,8 @@ void ParagraphImpl::initUnicodeText() { this->fUnicodeText = convertUtf8ToUnicode(fText); } +// Currently, only support to generate text and text shadow paint regions. +// Can't accurately calculate the paint region of italic fonts(including fake italic). SkIRect ParagraphImpl::generatePaintRegion(SkScalar x, SkScalar y) { if (fState < kFormatted) { TEXT_LOGW("Call generatePaintRegion when paragraph is not formatted"); diff --git a/modules/skparagraph/src/Run.h b/modules/skparagraph/src/Run.h index 66f092fedae059042f3ec7e387ac51b359590929..2268c0e0b4fcb0ccb36e76e8aefcbdba425d314a 100644 --- a/modules/skparagraph/src/Run.h +++ b/modules/skparagraph/src/Run.h @@ -184,6 +184,11 @@ public: template void iterateThroughClustersInTextOrder(Visitor visitor); +#ifdef OHOS_SUPPORT + template + void iterateGlyphRangeInTextOrder(const GlyphRange& glyphRange, Visitor visitor); +#endif + using ClusterVisitor = std::function; void iterateThroughClusters(const ClusterVisitor& visitor); @@ -344,6 +349,43 @@ void Run::iterateThroughClustersInTextOrder(Visitor visitor) { } } +#ifdef OHOS_SUPPORT +template +void Run::iterateGlyphRangeInTextOrder(const GlyphRange& glyphRange, Visitor visitor) { + if (glyphRange.start >= glyphRange.end || glyphRange.end > size()) { + return; + } + if (leftToRight()) { + size_t start = glyphRange.start; + size_t cluster = this->clusterIndex(start); + for (size_t glyph = glyphRange.start + 1; glyph <= glyphRange.end; ++glyph) { + auto nextCluster = this->clusterIndex(glyph); + if (nextCluster <= cluster) { + continue; + } + + visitor(start, glyph, fClusterStart + cluster, fClusterStart + nextCluster); + start = glyph; + cluster = nextCluster; + } + } else { + size_t glyph = glyphRange.end; + size_t cluster = this->clusterIndex(glyphRange.end - 1); + int32_t glyphStart = std::max((int32_t)glyphRange.start, 0); + for (int32_t start = glyphRange.end - 1; start >= glyphStart; --start) { + size_t nextCluster = start == 0 ? this->fUtf8Range.end() : this->clusterIndex(start - 1); + if (nextCluster <= cluster) { + continue; + } + + visitor(start, glyph, fClusterStart + cluster, fClusterStart + nextCluster); + glyph = start; + cluster = nextCluster; + } + } +} +#endif + class Cluster { public: enum BreakType { diff --git a/modules/skparagraph/src/TextLine.cpp b/modules/skparagraph/src/TextLine.cpp index bf9aa0db1ffbbb450bae3e5b37729e7c5e762878..7b90c66f814c30dc8dbd79ed577811e99306d12a 100644 --- a/modules/skparagraph/src/TextLine.cpp +++ b/modules/skparagraph/src/TextLine.cpp @@ -2590,7 +2590,7 @@ SkRect TextLine::computeShadowRect(SkScalar x, SkScalar y, const TextStyle& styl { SkScalar offsetX = x + this->fOffset.fX; SkScalar offsetY = y + this->fOffset.fY - - (context.run ? context.run->fCompressionBaselineShift : 0);; + (context.run ? context.run->fCompressionBaselineShift : 0); SkRect shadowRect = SkRect::MakeEmpty(); for (const TextShadow& shadow : style.getShadows()) { diff --git a/modules/skunicode/include/SkUnicode.h b/modules/skunicode/include/SkUnicode.h index bc09d7b9c6c994e6bde63bd695b0fa28502d52e4..76e81535708f0f8ac30012090a388398b32ce03f 100644 --- a/modules/skunicode/include/SkUnicode.h +++ b/modules/skunicode/include/SkUnicode.h @@ -87,6 +87,9 @@ class SKUNICODE_API SkUnicode { kTabulation = 0x40, kGlyphClusterStart = 0x80, kIdeographic = 0x100, +#ifdef OHOS_SUPPORT + kCombine = 0x200, +#endif }; enum class TextDirection { kLTR, diff --git a/modules/skunicode/src/SkUnicode_icu.cpp b/modules/skunicode/src/SkUnicode_icu.cpp index 213c6d0c2c9e7af9359f3bf6b5a04006d623a0f1..9df3c475f7b24792b2b8f9bedd97b514b15d03e3 100644 --- a/modules/skunicode/src/SkUnicode_icu.cpp +++ b/modules/skunicode/src/SkUnicode_icu.cpp @@ -434,8 +434,8 @@ public: #ifdef OHOS_SUPPORT if (SkUnicode_icu::isGraphemeExtend(unichar)) { - // Current unichar is a combining one. we regard it as a grapheme boundary for being shaped separately. - results->at(before) |= SkUnicode::kGraphemeStart; + // Current unichar is a combining one. + results->at(before) |= SkUnicode::kCombine; } #endif }