layout/relayout with different widths and justification

Change-Id: I2f6d9121a97d3dc12981e0aaf420c56a8f7e05eb
Bug: skia:9851, skia:9875
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/271536
Commit-Queue: Julia Lavrova <jlavrova@google.com>
Reviewed-by: Ben Wagner <bungeman@google.com>
This commit is contained in:
Julia Lavrova 2020-02-18 12:05:55 -05:00 committed by Skia Commit-Bot
parent 5a5fe79ebf
commit 212bf079de
6 changed files with 156 additions and 12 deletions

View File

@ -131,8 +131,17 @@ void ParagraphImpl::layout(SkScalar rawWidth) {
this->fRunShifts.reset();
this->fClusters.reset();
} else if (fState >= kLineBroken && (fOldWidth != floorWidth || fOldHeight != fHeight)) {
// We can use the results from SkShaper but have to break lines again
// We can use the results from SkShaper but have to do EVERYTHING ELSE again
this->fClusters.reset();
this->fRunShifts.reset();
this->resetRunShifts();
fState = kShaped;
this->buildClusterTable();
fState = kClusterized;
this->markLineBreaks(); // Just because it's on cluster table
fState = kMarked;
}
if (fState < kShaped) {
@ -165,6 +174,7 @@ void ParagraphImpl::layout(SkScalar rawWidth) {
return;
}
if (fState < kShaped) {
this->resetRunShifts();
fState = kShaped;
} else {
layout(floorWidth);
@ -434,9 +444,6 @@ void ParagraphImpl::formatLines(SkScalar maxWidth) {
fLines.reset();
return;
}
if (effectiveAlign == TextAlign::kJustify) {
this->resetRunShifts();
}
for (auto& line : fLines) {
if (&line == &fLines.back() && effectiveAlign == TextAlign::kJustify) {
@ -1073,9 +1080,17 @@ Block& ParagraphImpl::block(BlockIndex blockIndex) {
// TODO: Cache this information
void ParagraphImpl::resetRunShifts() {
fRunShifts.resize(fRuns.size());
if (fRunShifts.empty()) {
fRunShifts.resize(fRuns.size());
}
for (size_t i = 0; i < fRuns.size(); ++i) {
fRunShifts[i].fShifts.push_back_n(fRuns[i].size() + 1, 0.0);
auto& run = fRuns[i];
auto& shifts = fRunShifts[i];
run.resetShifts();
shifts.fShifts.reset();
shifts.fShifts.push_back_n(run.size() + 1, 0.0);
}
}

View File

@ -334,7 +334,7 @@ SkScalar Cluster::trimmedWidth(size_t pos) const {
// Find the width until the pos and return the min between trimmedWidth and the width(pos)
// We don't have to take in account cluster shift since it's the same for 0 and for pos
auto& run = fMaster->run(fRunIndex);
return std::min(run.positionX(pos) - run.positionX(fStart), fWidth - fSpacing);
return std::min(run.positionX(pos) - run.positionX(fStart), fWidth);
}
SkScalar Run::positionX(size_t pos) const {

View File

@ -163,6 +163,11 @@ public:
void commit();
SkRect getBounds(size_t pos) const { return fBounds[pos]; }
void resetShifts() {
for (auto& r: fShifts) { r = 0; }
fSpaced = false;
}
private:
friend class ParagraphImpl;
friend class TextLine;

View File

@ -136,7 +136,7 @@ SkRect TextLine::calculateBoundaries() {
}
clusterShift += cluster->width();
for (auto i = cluster->startPos(); i < cluster->endPos(); ++i) {
auto posX = run->posX(i);
auto posX = run->positionX(i);
auto posY = run->posY(i);
auto bounds = run->getBounds(i);
bounds.offset(posX + runShift, posY);
@ -724,6 +724,9 @@ TextLine::ClipContext TextLine::measureTextInsideOneRun(TextRange textRange,
result.clip.offset(textStartInLine, 0);
if (compareRound(result.clip.fRight, fAdvance.fX) > 0 && !includeGhostSpaces) {
// There are few cases when we need it.
// The most important one: we measure the text with spaces at the end
// and we should ignore these spaces
result.clippingNeeded = true;
result.clip.fRight = fAdvance.fX;
}

View File

@ -47,7 +47,13 @@ void TextWrapper::lookAhead(SkScalar maxWidth, Cluster* endOfClusters) {
if (nextWordLength > maxWidth) {
// If the word is too long we can break it right now and hope it's enough
fMinIntrinsicWidth = std::max(fMinIntrinsicWidth, nextWordLength);
fTooLongWord = true;
if (fClusters.endPos() - fClusters.startPos() > 1 ||
fWords.empty()) {
fTooLongWord = true;
} else {
// Even if the word is too long there is a very little space on this line.
// let's deal with it on the next line.
}
}
if (cluster->width() > maxWidth) {
@ -255,6 +261,7 @@ void TextWrapper::breakTextIntoLines(ParagraphImpl* parent,
needEllipsis && !fHardLineBreak);
softLineMaxIntrinsicWidth += widthWithSpaces;
fMaxIntrinsicWidth = std::max(fMaxIntrinsicWidth, softLineMaxIntrinsicWidth);
if (fHardLineBreak) {
softLineMaxIntrinsicWidth = 0;
@ -283,6 +290,7 @@ void TextWrapper::breakTextIntoLines(ParagraphImpl* parent,
}
// We finished formatting the text but we need to scan the rest for some numbers
// TODO: make it a case of a normal flow
if (fEndLine.endCluster() != nullptr) {
auto lastWordLength = 0.0f;
auto cluster = fEndLine.endCluster();
@ -291,7 +299,6 @@ void TextWrapper::breakTextIntoLines(ParagraphImpl* parent,
if (cluster->isHardBreak()) {
fMaxIntrinsicWidth = std::max(fMaxIntrinsicWidth, softLineMaxIntrinsicWidth);
softLineMaxIntrinsicWidth = 0;
fMinIntrinsicWidth = std::max(fMinIntrinsicWidth, lastWordLength);
lastWordLength = 0;
} else if (cluster->isWhitespaces()) {

View File

@ -2097,6 +2097,117 @@ private:
typedef Sample INHERITED;
};
class ParagraphView28 : public ParagraphView_Base {
protected:
SkString name() override { return SkString("Paragraph28"); }
void onDrawContent(SkCanvas* canvas) override {
const char* text = "AAAAA BBBBB CCCCC DDDDD EEEEE FFFFF GGGGG HHHHH IIIII JJJJJ KKKKK LLLLL MMMMM NNNNN OOOOO PPPPP QQQQQ";
canvas->drawColor(SK_ColorWHITE);
ParagraphStyle paragraph_style;
paragraph_style.setTextAlign(TextAlign::kJustify);
auto collection = getFontCollection();
ParagraphBuilderImpl builder(paragraph_style, collection);
TextStyle text_style;
text_style.setColor(SK_ColorBLACK);
text_style.setFontFamilies({SkString("Roboto")});
text_style.setFontSize(40);
builder.pushStyle(text_style);
builder.addText(text);
auto paragraph = builder.Build();
auto s = 186;
paragraph->layout(360 - s);
paragraph->paint(canvas, 0, 0);
/*
paragraph->layout(360);
paragraph->paint(canvas, 0, 0);
canvas->translate(0, 400);
paragraph->layout(354.333);
paragraph->paint(canvas, 0, 0);
*/
}
private:
typedef Sample INHERITED;
};
class ParagraphView29 : public ParagraphView_Base {
protected:
SkString name() override { return SkString("Paragraph29"); }
void onDrawContent(SkCanvas* canvas) override {
const char* text = "PESTO";
canvas->drawColor(SK_ColorWHITE);
SkPaint paint;
paint.setColor(SK_ColorRED);
paint.setStyle(SkPaint::kStroke_Style);
paint.setAntiAlias(true);
paint.setStrokeWidth(1);
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);
builder.pushStyle(text_style);
builder.addText(text);
auto paragraph = builder.Build();
auto w = width() / 2;
paragraph->layout(w);
paragraph->paint(canvas, 0, 0);
canvas->drawRect(SkRect::MakeXYWH(0, 0, width() / 2, paragraph->getHeight()), paint);
}
private:
typedef Sample INHERITED;
};
class ParagraphView30 : public ParagraphView_Base {
protected:
SkString name() override { return SkString("Paragraph30"); }
void onDrawContent(SkCanvas* canvas) override {
const char* text = "test text with space at end ";
canvas->drawColor(SK_ColorWHITE);
ParagraphStyle paragraph_style;
paragraph_style.setTextAlign(TextAlign::kCenter);
auto collection = getFontCollection();
TextStyle text_style;
text_style.setColor(SK_ColorBLACK);
text_style.setFontFamilies({SkString("Roboto")});
text_style.setFontSize(48);
ParagraphBuilderImpl builder(paragraph_style, collection);
builder.pushStyle(text_style);
builder.addText(text);
auto paragraph = builder.Build();
auto width = this->width();
paragraph->layout(width);
SkDebugf("%f: %f %f\n", width, paragraph->getMinIntrinsicWidth(), paragraph->getMaxIntrinsicWidth());
paragraph->paint(canvas, 0, 0);
auto boxes = paragraph->getRectsForRange(0, 1, RectHeightStyle::kTight, RectWidthStyle::kTight);
for (auto& b : boxes) {
SkDebugf("box[%f:%f * %f:%f] %s\n",
b.rect.fLeft, b.rect.fRight, b.rect.fTop, b.rect.fBottom,
b.direction == TextDirection::kRtl ? "rtl" : "ltr");
}
}
private:
typedef Sample INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
DEF_SAMPLE(return new ParagraphView1();)
@ -2123,5 +2234,8 @@ DEF_SAMPLE(return new ParagraphView22();)
DEF_SAMPLE(return new ParagraphView23();)
DEF_SAMPLE(return new ParagraphView24();)
DEF_SAMPLE(return new ParagraphView25();)
//DEF_SAMPLE(return new ParagraphView26();)
//DEF_SAMPLE(return new ParagraphView27();)
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();)