Bugs
Change-Id: I3d45c6c8cef0109377812de0a3aab5d457a29b86
Bugs: skia:9849, skia:9850
9849 is related to font resolution (we may have to try different fallback
fonts to resolve all codepoints)
9850 is related to finding a position inside a glyph ("ffi" is an example)
Change-Id: I3d45c6c8cef0109377812de0a3aab5d457a29b86
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/271745
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Julia Lavrova <jlavrova@google.com>
diff --git a/modules/skparagraph/src/OneLineShaper.cpp b/modules/skparagraph/src/OneLineShaper.cpp
index e52e6d1..5ba6e8a 100644
--- a/modules/skparagraph/src/OneLineShaper.cpp
+++ b/modules/skparagraph/src/OneLineShaper.cpp
@@ -44,7 +44,7 @@
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 @@
std::vector<sk_sp<SkTypeface>> 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 45c7bd4..13e5e9b 100644
--- a/modules/skparagraph/src/ParagraphImpl.cpp
+++ b/modules/skparagraph/src/ParagraphImpl.cpp
@@ -933,6 +933,8 @@
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 @@
[](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 9bcdf90..a9404ee 100644
--- a/modules/skparagraph/src/Run.cpp
+++ b/modules/skparagraph/src/Run.cpp
@@ -12,6 +12,7 @@
SkUnichar val = SkUTF::NextUTF8(ptr, end);
return val < 0 ? 0xFFFD : val;
}
+
}
namespace skia {
@@ -88,7 +89,7 @@
}
}
-std::tuple<bool, ClusterIndex, ClusterIndex> Run::findLimitingClusters(TextRange text, bool onlyInnerClusters) const {
+std::tuple<bool, ClusterIndex, ClusterIndex> Run::findLimitingClusters(TextRange text, bool extendToClusters) const {
if (text.width() == 0) {
for (auto i = fClusterRange.start; i != fClusterRange.end; ++i) {
@@ -101,19 +102,27 @@
}
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 6391670..d7d30ab 100644
--- a/samplecode/SampleParagraph.cpp
+++ b/samplecode/SampleParagraph.cpp
@@ -2139,91 +2139,50 @@
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>[
- 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 ParagraphView27();)
DEF_SAMPLE(return new ParagraphView28();)
DEF_SAMPLE(return new ParagraphView29();)
-DEF_SAMPLE(return new ParagraphView30();)