RTL Paragraph + all it causes

Change-Id: Ia8711bf8a002af7ca9ae603cdd9a109c8af86360
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/264640
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Julia Lavrova <jlavrova@google.com>
This commit is contained in:
Julia Lavrova 2020-01-15 14:46:35 -05:00 committed by Skia Commit-Bot
parent 23f29761a6
commit 9bd8351ef3
7 changed files with 82 additions and 61 deletions

View File

@ -333,7 +333,6 @@ void OneLineShaper::sortOutGlyphs(std::function<void(GlyphRange)>&& sortOutUnres
block.end = fCurrentRun->size();
sortOutUnresolvedBLock(block);
}
}
void OneLineShaper::iterateThroughFontStyles(SkSpan<Block> 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<SkScalar>::max();
auto result = iterateThroughShapingRegions(

View File

@ -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];

View File

@ -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);
}

View File

@ -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();

View File

@ -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();

View File

@ -93,6 +93,8 @@ public:
LineMetrics getMetrics() const;
SkRect calculateBoundaries();
private:
Run* shapeEllipsis(const SkString& ellipsis, Run* run);

View File

@ -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<SkScalar>::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();)