diff --git a/modules/skparagraph/src/OneLineShaper.cpp b/modules/skparagraph/src/OneLineShaper.cpp index e52e6d194c..5ba6e8ae11 100644 --- a/modules/skparagraph/src/OneLineShaper.cpp +++ b/modules/skparagraph/src/OneLineShaper.cpp @@ -44,7 +44,7 @@ void OneLineShaper::commitRunBuffer(const RunInfo&) { auto& front = fUnresolvedBlocks.front(); // The one we need to resolve auto& back = fUnresolvedBlocks.back(); // The one we have from shaper if (fUnresolvedBlocks.size() == oldUnresolvedCount + 1 && - front.fText.width() == back.fText.width()) { + front.fText == back.fText) { // The entire block remains unresolved! if (front.fRun != nullptr) { back.fRun = front.fRun; @@ -394,25 +394,38 @@ void OneLineShaper::matchResolvedFonts(const TextStyle& textStyle, std::vector> typefaces = fParagraph->fFontCollection->findTypefaces(textStyle.getFontFamilies(), textStyle.getFontStyle()); for (const auto& typeface : typefaces) { - if (!visitor(typeface)) + if (!visitor(typeface)) { + // Resolved everything return; + } } if (fParagraph->fFontCollection->fontFallbackEnabled()) { // Give fallback a clue - SkASSERT(!fUnresolvedBlocks.empty()); - auto unresolvedRange = fUnresolvedBlocks.front().fText; - auto unresolvedText = fParagraph->text(unresolvedRange); - const char* ch = unresolvedText.begin(); - SkUnichar unicode = utf8_next(&ch, unresolvedText.end()); + // Some unresolved subblocks might be resolved with different fallback fonts + while (!fUnresolvedBlocks.empty()) { + auto unresolvedRange = fUnresolvedBlocks.front().fText; + auto unresolvedText = fParagraph->text(unresolvedRange); + const char* ch = unresolvedText.begin(); + SkUnichar unicode = utf8_next(&ch, unresolvedText.end()); - auto typeface = fParagraph->fFontCollection->defaultFallback( - unicode, textStyle.getFontStyle(), textStyle.getLocale()); + auto typeface = fParagraph->fFontCollection->defaultFallback( + unicode, textStyle.getFontStyle(), textStyle.getLocale()); - if (typeface != nullptr) { - if (!visitor(typeface)) { + if (typeface == nullptr) { return; } + + if (!visitor(typeface)) { + // Resolved everything + return; + } else { + // Check if anything was resolved and stop it it was not + auto last = fUnresolvedBlocks.back(); + if (unresolvedRange == last.fText) { + return; + } + } } } } diff --git a/modules/skparagraph/src/ParagraphImpl.cpp b/modules/skparagraph/src/ParagraphImpl.cpp index 45c7bd4960..13e5e9be0c 100644 --- a/modules/skparagraph/src/ParagraphImpl.cpp +++ b/modules/skparagraph/src/ParagraphImpl.cpp @@ -933,6 +933,8 @@ PositionWithAffinity ParagraphImpl::getGlyphPositionAtCoordinate(SkScalar dx, Sk auto glyphStart = context.run->positionX(found) + context.fTextShift + offsetX; auto glyphWidth = context.run->positionX(found + 1) - context.run->positionX(found); auto clusterIndex8 = context.run->fClusterIndexes[found]; + auto clusterEnd8 = context.run->fClusterIndexes[found + 1]; + TextRange clusterText (clusterIndex8, clusterEnd8); // Find the grapheme positions in codepoints that contains the point auto codepoint = std::lower_bound( @@ -941,21 +943,29 @@ PositionWithAffinity ParagraphImpl::getGlyphPositionAtCoordinate(SkScalar dx, Sk [](const Codepoint& lhs,size_t rhs) -> bool { return lhs.fTextIndex < rhs; }); auto codepointIndex = codepoint - fCodePoints.begin(); - auto codepoints = fGraphemes16[codepoint->fGrapheme].fCodepointRange; + CodepointRange codepoints(codepointIndex, codepointIndex); + for (codepoints.end = codepointIndex + 1; codepoints.end < fCodePoints.size(); ++codepoints.end) { + auto& cp = fCodePoints[codepoints.end]; + if (cp.fTextIndex >= clusterText.end) { + break; + } + } auto graphemeSize = codepoints.width(); // We only need to inspect one glyph (maybe not even the entire glyph) SkScalar center; + bool insideGlyph = false; if (graphemeSize > 1) { - auto averageCodepoint = glyphWidth / graphemeSize; - auto codepointStart = glyphStart + averageCodepoint * (codepointIndex - codepoints.start); - auto codepointEnd = codepointStart + averageCodepoint; - center = (codepointStart + codepointEnd) / 2; + auto averageCodepointWidth = glyphWidth / graphemeSize; + auto delta = dx - glyphStart; + auto insideIndex = SkScalarFloorToInt(delta / averageCodepointWidth); + insideGlyph = delta > averageCodepointWidth; + center = glyphStart + averageCodepointWidth * insideIndex + averageCodepointWidth / 2; + codepointIndex += insideIndex; } else { - SkASSERT(graphemeSize == 1); center = glyphStart + glyphWidth / 2; } - if ((dx < center) == context.run->leftToRight()) { + if ((dx < center) == context.run->leftToRight() || insideGlyph) { result = { SkToS32(codepointIndex), kDownstream }; } else { result = { SkToS32(codepointIndex + 1), kUpstream }; diff --git a/modules/skparagraph/src/Run.cpp b/modules/skparagraph/src/Run.cpp index 9bcdf90c68..a9404eeeec 100644 --- a/modules/skparagraph/src/Run.cpp +++ b/modules/skparagraph/src/Run.cpp @@ -12,6 +12,7 @@ SkUnichar utf8_next(const char** ptr, const char* end) { SkUnichar val = SkUTF::NextUTF8(ptr, end); return val < 0 ? 0xFFFD : val; } + } namespace skia { @@ -88,7 +89,7 @@ void Run::copyTo(SkTextBlobBuilder& builder, size_t pos, size_t size, SkVector r } } -std::tuple Run::findLimitingClusters(TextRange text, bool onlyInnerClusters) const { +std::tuple Run::findLimitingClusters(TextRange text, bool extendToClusters) const { if (text.width() == 0) { for (auto i = fClusterRange.start; i != fClusterRange.end; ++i) { @@ -101,19 +102,27 @@ std::tuple Run::findLimitingClusters(TextRange } Cluster* start = nullptr; Cluster* end = nullptr; - if (onlyInnerClusters) { + if (extendToClusters) { for (auto i = fClusterRange.start; i != fClusterRange.end; ++i) { auto& cluster = fMaster->cluster(i); - if (cluster.textRange().start >= text.start && start == nullptr) { - start = &cluster; - } - if (cluster.textRange().end <= text.end) { - end = &cluster; - } else { + auto clusterRange = cluster.textRange(); + if (clusterRange.end <= text.start) { + continue; + } else if (clusterRange.start >= text.end) { break; } + + TextRange s = TextRange(std::max(clusterRange.start, text.start), + std::min(clusterRange.end, text.end)); + if (s.width() > 0) { + if (start == nullptr) { + start = &cluster; + } + end = &cluster; + } } } else { + // TODO: Do we need to use this branch?.. for (auto i = fClusterRange.start; i != fClusterRange.end; ++i) { auto& cluster = fMaster->cluster(i); if (cluster.textRange().end > text.start && start == nullptr) { diff --git a/samplecode/SampleParagraph.cpp b/samplecode/SampleParagraph.cpp index 6391670171..d7d30abd2e 100644 --- a/samplecode/SampleParagraph.cpp +++ b/samplecode/SampleParagraph.cpp @@ -2139,91 +2139,50 @@ protected: void onDrawContent(SkCanvas* canvas) override { - const char* text = "PESTO"; + const char* text = "ffi"; canvas->drawColor(SK_ColorWHITE); - SkPaint paint; - paint.setColor(SK_ColorRED); - paint.setStyle(SkPaint::kStroke_Style); - paint.setAntiAlias(true); - paint.setStrokeWidth(1); + auto collection = getFontCollection(); ParagraphStyle paragraph_style; - paragraph_style.setTextAlign(TextAlign::kCenter); - auto collection = getFontCollection(); ParagraphBuilderImpl builder(paragraph_style, collection); TextStyle text_style; text_style.setColor(SK_ColorBLACK); text_style.setFontFamilies({SkString("Roboto")}); - text_style.setFontSize(48); - text_style.setFontStyle(SkFontStyle::Bold()); - text_style.setLetterSpacing(3); + text_style.setFontSize(60); builder.pushStyle(text_style); builder.addText(text); auto paragraph = builder.Build(); - auto w = width() / 2; - paragraph->layout(w); + paragraph->layout(width()); paragraph->paint(canvas, 0, 0); - canvas->drawRect(SkRect::MakeXYWH(0, 0, width() / 2, paragraph->getHeight()), paint); + auto width = paragraph->getLongestLine(); + auto height = paragraph->getHeight(); + + auto f1 = paragraph->getGlyphPositionAtCoordinate(width/6, height/2); + auto f2 = paragraph->getGlyphPositionAtCoordinate(width/2, height/2); + auto i = paragraph->getGlyphPositionAtCoordinate(width*5/6, height/2); + + SkDebugf("%d(%s) %d(%s) %d(%s)\n", + f1.position, f1.affinity == Affinity::kUpstream ? "up" : "down", + f2.position, f2.affinity == Affinity::kUpstream ? "up" : "down", + i.position, i.affinity == Affinity::kUpstream ? "up" : "down"); + + auto rf1 = paragraph->getRectsForRange(0, 1, RectHeightStyle::kTight, RectWidthStyle::kTight)[0]; + auto rf2 = paragraph->getRectsForRange(1, 2, RectHeightStyle::kTight, RectWidthStyle::kTight)[0]; + auto rfi = paragraph->getRectsForRange(2, 3, RectHeightStyle::kTight, RectWidthStyle::kTight)[0]; + + SkDebugf("f1: [%f:%f] %s\n", + rf1.rect.fLeft, rf1.rect.fRight, rf1.direction == TextDirection::kRtl ? "rtl" : "ltr"); + SkDebugf("f2: [%f:%f] %s\n", + rf2.rect.fLeft, rf2.rect.fRight, rf2.direction == TextDirection::kRtl ? "rtl" : "ltr"); + SkDebugf("i: [%f:%f] %s\n", + rfi.rect.fLeft, rfi.rect.fRight, rfi.direction == TextDirection::kRtl ? "rtl" : "ltr"); } private: typedef Sample INHERITED; }; -class ParagraphView30 : public ParagraphView_Base { -protected: - SkString name() override { return SkString("Paragraph30"); } - - void onDrawContent(SkCanvas* canvas) override { - - /* - * text: TextSpan( - text: 'aaaa bbbb ', - style: TextStyle(fontSize: 48.0), - children: [ - TextSpan(text: 'cc dd', style:TextStyle(fontFamily: 'serif', fontSize: 64.0)), - ], - ), - textDirection: TextDirection.ltr, - textAlign: TextAlign.justify, - - */ - - const char* text1 = "aaaa bbbb "; - const char* text2 = "cc dd"; - - canvas->drawColor(SK_ColorWHITE); - - ParagraphStyle paragraph_style; - paragraph_style.setTextAlign(TextAlign::kJustify); - auto collection = getFontCollection(); - SkPaint red; - red.setColor(SK_ColorRED); - TextStyle text_style; - text_style.setColor(SK_ColorBLACK); - - ParagraphBuilderImpl builder(paragraph_style, collection); - - text_style.setFontFamilies({SkString("Roboto")}); - text_style.setFontSize(48); - builder.pushStyle(text_style); - builder.addText(text1); - - text_style.setFontFamilies({SkString("Google Sans")}); - text_style.setFontSize(64); - builder.pushStyle(text_style); - builder.addText(text2); - - auto paragraph = builder.Build(); - - paragraph->layout(310); - paragraph->paint(canvas, 0, 0); - } - -private: - typedef Sample INHERITED; -}; ////////////////////////////////////////////////////////////////////////////// DEF_SAMPLE(return new ParagraphView1();) @@ -2254,4 +2213,3 @@ DEF_SAMPLE(return new ParagraphView26();) DEF_SAMPLE(return new ParagraphView27();) DEF_SAMPLE(return new ParagraphView28();) DEF_SAMPLE(return new ParagraphView29();) -DEF_SAMPLE(return new ParagraphView30();)