From 9bd8351ef39b15e1f706d4772e4e6c5edaa00b54 Mon Sep 17 00:00:00 2001 From: Julia Lavrova Date: Wed, 15 Jan 2020 14:46:35 -0500 Subject: [PATCH] RTL Paragraph + all it causes Change-Id: Ia8711bf8a002af7ca9ae603cdd9a109c8af86360 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/264640 Reviewed-by: Ben Wagner Commit-Queue: Julia Lavrova --- modules/skparagraph/src/OneLineShaper.cpp | 3 +- modules/skparagraph/src/ParagraphCache.cpp | 3 +- modules/skparagraph/src/ParagraphImpl.cpp | 37 ++----------- modules/skparagraph/src/ParagraphImpl.h | 2 +- modules/skparagraph/src/TextLine.cpp | 32 ++++++++++- modules/skparagraph/src/TextLine.h | 2 + samplecode/SampleParagraph.cpp | 64 ++++++++++++++-------- 7 files changed, 82 insertions(+), 61 deletions(-) diff --git a/modules/skparagraph/src/OneLineShaper.cpp b/modules/skparagraph/src/OneLineShaper.cpp index 05eac3bdcb..e9d7b92792 100644 --- a/modules/skparagraph/src/OneLineShaper.cpp +++ b/modules/skparagraph/src/OneLineShaper.cpp @@ -333,7 +333,6 @@ void OneLineShaper::sortOutGlyphs(std::function&& sortOutUnres block.end = fCurrentRun->size(); sortOutUnresolvedBLock(block); } - } void OneLineShaper::iterateThroughFontStyles(SkSpan styleSpan, @@ -466,7 +465,7 @@ bool OneLineShaper::shape() { // The text can be broken into many shaping sequences // (by place holders, possibly, by hard line breaks or tabs, too) - uint8_t textDirection = fParagraph->fParagraphStyle.getTextDirection() == TextDirection::kLtr ? 2 : 1; + uint8_t textDirection = fParagraph->fParagraphStyle.getTextDirection() == TextDirection::kLtr ? 2 : 0xff; auto limitlessWidth = std::numeric_limits::max(); auto result = iterateThroughShapingRegions( diff --git a/modules/skparagraph/src/ParagraphCache.cpp b/modules/skparagraph/src/ParagraphCache.cpp index af35d5df18..e8978821ff 100644 --- a/modules/skparagraph/src/ParagraphCache.cpp +++ b/modules/skparagraph/src/ParagraphCache.cpp @@ -89,10 +89,11 @@ bool operator==(const ParagraphCacheKey& a, const ParagraphCacheKey& b) { return false; } - if (a.fParagraphStyle.getMaxLines() != b.fParagraphStyle.getMaxLines()) { + if (!(a.fParagraphStyle == b.fParagraphStyle)) { // This is too strong, but at least we will not lose lines return false; } + for (size_t i = 0; i < a.fTextStyles.size(); ++i) { auto& tsa = a.fTextStyles[i]; auto& tsb = b.fTextStyles[i]; diff --git a/modules/skparagraph/src/ParagraphImpl.cpp b/modules/skparagraph/src/ParagraphImpl.cpp index ff0bcfd07c..67dd39d811 100644 --- a/modules/skparagraph/src/ParagraphImpl.cpp +++ b/modules/skparagraph/src/ParagraphImpl.cpp @@ -192,6 +192,8 @@ void ParagraphImpl::layout(SkScalar rawWidth) { if (fState < kFormatted) { // Build the picture lazily not until we actually have to paint (or never) this->formatLines(fWidth); + // We have to calculate the paragraph boundaries only after we format the lines + this->calculateBoundaries(); fState = kFormatted; } @@ -492,34 +494,10 @@ BlockRange ParagraphImpl::findAllBlocks(TextRange textRange) { return { begin, end + 1 }; } -void ParagraphImpl::calculateBoundaries(ClusterRange clusters, SkVector offset, SkVector advance) { - - auto boundaries = SkRect::MakeXYWH(0, 0, advance.fX, advance.fY); - - if (!fRuns.empty()) { - // TODO: Move it down to the TextWrapper to avoid extra calculations - auto run = &fRuns[0]; - auto runShift = 0.0f; - auto clusterShift = 0.0f; - for (auto index = clusters.start; index < clusters.end; ++index) { - auto& cluster = fClusters[index]; - if (cluster.runIndex() != run->index()) { - run = &fRuns[cluster.runIndex()]; - runShift += clusterShift; - clusterShift = 0; - } - clusterShift += cluster.width(); - for (auto i = cluster.startPos(); i < cluster.endPos(); ++i) { - auto posX = run->posX(i); - auto posY = run->posY(i); - auto bounds = run->getBounds(i); - bounds.offset(posX + runShift, posY); - boundaries.joinPossiblyEmptyRect(bounds); - } - } +void ParagraphImpl::calculateBoundaries() { + for (auto& line : fLines) { + fOrigin.joinPossiblyEmptyRect(line.calculateBoundaries()); } - boundaries.offset(offset); - fOrigin.joinPossiblyEmptyRect(boundaries); } TextLine& ParagraphImpl::addLine(SkVector offset, @@ -532,11 +510,6 @@ TextLine& ParagraphImpl::addLine(SkVector offset, InternalLineMetrics sizes) { // Define a list of styles that covers the line auto blocks = findAllBlocks(text); - - auto correctedOffset = offset; - correctedOffset.offset(0, sizes.baseline()); - calculateBoundaries(clusters, correctedOffset, advance); - return fLines.emplace_back(this, offset, advance, blocks, text, textWithSpaces, clusters, clustersWithGhosts, widthWithSpaces, sizes); } diff --git a/modules/skparagraph/src/ParagraphImpl.h b/modules/skparagraph/src/ParagraphImpl.h index 30508c90c8..bac15992fc 100644 --- a/modules/skparagraph/src/ParagraphImpl.h +++ b/modules/skparagraph/src/ParagraphImpl.h @@ -210,7 +210,7 @@ private: friend class TextWrapper; friend class OneLineShaper; - void calculateBoundaries(ClusterRange clusters, SkVector offset, SkVector advance); + void calculateBoundaries(); void extractStyles(); void markGraphemes16(); diff --git a/modules/skparagraph/src/TextLine.cpp b/modules/skparagraph/src/TextLine.cpp index 08dd178bbf..bb1e4a798e 100644 --- a/modules/skparagraph/src/TextLine.cpp +++ b/modules/skparagraph/src/TextLine.cpp @@ -115,6 +115,36 @@ TextLine::TextLine(ParagraphImpl* master, } } +SkRect TextLine::calculateBoundaries() { + + auto boundaries = SkRect::MakeEmpty(); + auto clusters = fMaster->clusters(fClusterRange); + Run* run = nullptr; + auto runShift = 0.0f; + auto clusterShift = 0.0f; + for (auto cluster = clusters.begin(); cluster != clusters.end(); ++cluster) { + if (run == nullptr || cluster->runIndex() != run->index()) { + run = &fMaster->run(cluster->runIndex()); + runShift += clusterShift; + clusterShift = 0; + } + clusterShift += cluster->width(); + for (auto i = cluster->startPos(); i < cluster->endPos(); ++i) { + auto posX = run->posX(i); + auto posY = run->posY(i); + auto bounds = run->getBounds(i); + bounds.offset(posX + runShift, posY); + boundaries.joinPossiblyEmptyRect(bounds); + } + } + + boundaries.offset(this->fOffset); // Line offset from the beginning of the para + boundaries.offset(this->fShift, 0); // Shift produced by formatting + boundaries.offset(0, this->baseline()); // Down by baseline + + return boundaries; +} + void TextLine::paint(SkCanvas* textCanvas) { if (this->empty()) { return; @@ -239,13 +269,13 @@ void TextLine::paintText(SkCanvas* canvas, TextRange textRange, const TextStyle& // TODO: This is the change for flutter, must be removed later SkScalar correctedBaseline = SkScalarFloorToScalar(this->baseline() + 0.5); - SkTextBlobBuilder builder; context.run->copyTo(builder, SkToU32(context.pos), context.size, SkVector::Make(0, correctedBaseline)); canvas->save(); if (context.clippingNeeded) { canvas->clipRect(context.clip); } + canvas->translate(context.fTextShift, 0); canvas->drawTextBlob(builder.make(), 0, 0, paint); canvas->restore(); diff --git a/modules/skparagraph/src/TextLine.h b/modules/skparagraph/src/TextLine.h index 9abd28d22f..465ae9ef2e 100644 --- a/modules/skparagraph/src/TextLine.h +++ b/modules/skparagraph/src/TextLine.h @@ -93,6 +93,8 @@ public: LineMetrics getMetrics() const; + SkRect calculateBoundaries(); + private: Run* shapeEllipsis(const SkString& ellipsis, Run* run); diff --git a/samplecode/SampleParagraph.cpp b/samplecode/SampleParagraph.cpp index a14926b70a..8847addf86 100644 --- a/samplecode/SampleParagraph.cpp +++ b/samplecode/SampleParagraph.cpp @@ -1723,36 +1723,52 @@ class ParagraphView22 : public ParagraphView_Base { protected: SkString name() override { return SkString("Paragraph22"); } - void onDrawContent(SkCanvas* canvas) override { - canvas->drawColor(SK_ColorWHITE); - - const char* text = "By continuing, you agree to the Google Payments . The  describes how your data is handled."; - for (size_t i = 0; i < 10000; ++i) { - ParagraphStyle paragraph_style; - ParagraphBuilderImpl builder(paragraph_style, getFontCollection()); - TextStyle text_style; - text_style.setColor(SK_ColorBLACK); - text_style.setFontFamilies({SkString("Roboto")}); - text_style.setFontSize(12); - builder.pushStyle(text_style); - builder.addText(text); - auto paragraph = builder.Build(); - paragraph->layout(std::numeric_limits::max()); - SkDebugf("layout: %f %f\n", paragraph->getMaxWidth(), paragraph->getHeight()); - if (i % 3 != 1) { - paragraph->layout(566); - SkDebugf("layout: %f %f\n", paragraph->getMaxWidth(), paragraph->getHeight()); - } else if (i % 3 == 2) { - paragraph->layout(633); - SkDebugf("layout: %f %f\n", paragraph->getMaxWidth(), paragraph->getHeight()); + bool onChar(SkUnichar uni) override { + switch (uni) { + case 'l': + direction = true; + return true; + case 'r': + direction = false; + return true; + default: + break; } - } - //paragraph->paint(canvas, 0, 0); + return false; + } + + void onDrawContent(SkCanvas* canvas) override { + + canvas->drawColor(SK_ColorWHITE); + ParagraphStyle paragraph_style; + paragraph_style.setTextDirection(direction ? TextDirection::kLtr : TextDirection::kRtl); + auto collection = getFontCollection(); + ParagraphBuilderImpl builder(paragraph_style, collection); + collection->getParagraphCache()->reset(); + collection->getParagraphCache()->turnOn(false); + TextStyle text_style; + text_style.setColor(SK_ColorBLACK); + text_style.setFontFamilies({SkString("Roboto")}); + text_style.setFontSize(12); + builder.pushStyle(text_style); + builder.addText("I have got a "); + text_style.setFontStyle(SkFontStyle::Bold()); + builder.pushStyle(text_style); + builder.addText("lovely bunch"); + text_style.setFontStyle(SkFontStyle::Normal()); + builder.pushStyle(text_style); + builder.addText(" of coconuts."); + auto paragraph = builder.Build(); + paragraph->layout(this->width()); + paragraph->paint(canvas, 0, 0); + collection->getParagraphCache()->turnOn(true); } private: typedef Sample INHERITED; + bool direction; }; + ////////////////////////////////////////////////////////////////////////////// DEF_SAMPLE(return new ParagraphView1();)