Implementing baseline shift for JetBrains

Bug: skia:12390
Change-Id: I90d99e1ca18c1274ac53ab35a3f63b716d26cb5d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/457097
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Julia Lavrova <jlavrova@google.com>
This commit is contained in:
Julia Lavrova 2021-10-07 14:23:39 -04:00 committed by SkCQ
parent c9f160b8dd
commit 0c1f6e5dab
9 changed files with 190 additions and 13 deletions

View File

@ -215,6 +215,9 @@ public:
fFontFamilies = std::move(families);
}
SkScalar getBaselineShift() const { return fBaselineShift; }
void setBaselineShift(SkScalar baselineShift) { fBaselineShift = baselineShift; }
void setHeight(SkScalar height) { fHeight = height; }
SkScalar getHeight() const { return fHeightOverride ? fHeight : 0; }
@ -265,6 +268,7 @@ private:
SkScalar fFontSize = 14.0;
SkScalar fHeight = 1.0;
bool fHeightOverride = false;
SkScalar fBaselineShift = 0.0f;
// true: half leading.
// false: scale ascent/descent with fHeight.
bool fHalfLeading = false;

View File

@ -3611,6 +3611,151 @@ protected:
private:
using INHERITED = Sample;
};
// Baseline shift
class ParagraphView63 : public ParagraphView_Base {
protected:
SkString name() override { return SkString("ParagraphView63"); }
void onDrawContent(SkCanvas* canvas) override {
canvas->drawColor(SK_ColorWHITE);
auto fontCollection = getFontCollection();
fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
fontCollection->enableFontFallback();
TextStyle roboto;
roboto.setColor(SK_ColorBLACK);
roboto.setFontFamilies({SkString("Roboto")});
roboto.setFontSize(20.0f);
TextStyle assyrian;
assyrian.setColor(SK_ColorRED);
assyrian.setFontFamilies({SkString("Assyrian")});
assyrian.setFontSize(40.0f);
ParagraphStyle paragraph_style;
paragraph_style.setTextStyle(roboto);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
roboto.setBaselineShift(0.0f);
builder.pushStyle(roboto);
builder.addText("Notice that the line height increased on the lines with ");
assyrian.setBaselineShift(.0f);
builder.pushStyle(assyrian);
builder.addText("baseline shifts:\n");
roboto.setBaselineShift(0.0f);
builder.pushStyle(roboto);
builder.addText("Zero baseline shift text ");
assyrian.setBaselineShift(-20.0f);
builder.pushStyle(assyrian);
builder.addText("Up20");
roboto.setBaselineShift(-40.0f);
builder.pushStyle(roboto);
builder.addText("Up40");
assyrian.setBaselineShift(-60.0f);
builder.pushStyle(assyrian);
builder.addText("Up60");
roboto.setBaselineShift(-40.0f);
builder.pushStyle(roboto);
builder.addText("Up40");
assyrian.setBaselineShift(-20.0f);
builder.pushStyle(assyrian);
builder.addText("Up20");
roboto.setBaselineShift(-0.0f);
builder.pushStyle(roboto);
builder.addText(" Zero baseline shift text\n");
assyrian.addShadow(TextShadow(SK_ColorGREEN, SkPoint::Make(5, 5), 2));
assyrian.setDecorationStyle(TextDecorationStyle::kSolid);
assyrian.setDecoration(TextDecoration::kUnderline);
assyrian.setDecorationColor(SK_ColorBLUE);
roboto.setBaselineShift(0.0f);
builder.pushStyle(roboto);
builder.addText("Notice that shadows and decorations are shifted if there is a text with ");
assyrian.setBaselineShift(.0f);
builder.pushStyle(assyrian);
builder.addText("baseline shifts:\n");
assyrian.setDecoration(TextDecoration::kNoDecoration);
roboto.setBaselineShift(0.0f);
builder.pushStyle(roboto);
builder.addText("Zero baseline shift text ");
assyrian.setBaselineShift(20.0f);
builder.pushStyle(assyrian);
builder.addText("Down20");
roboto.setBaselineShift(40.0f);
builder.pushStyle(roboto);
builder.addText("Down40");
assyrian.setBaselineShift(60.0f);
builder.pushStyle(assyrian);
builder.addText("Down60");
roboto.setBaselineShift(40.0f);
builder.pushStyle(roboto);
builder.addText("Down40");
assyrian.setBaselineShift(20.0f);
builder.pushStyle(assyrian);
builder.addText("Down20");
roboto.setBaselineShift(0.0f);
builder.pushStyle(roboto);
builder.addText(" Zero baseline shift text\n");
assyrian.resetShadows();
assyrian.setDecorationStyle(TextDecorationStyle::kSolid);
assyrian.setDecoration(TextDecoration::kUnderline);
assyrian.setDecorationColor(SK_ColorBLUE);
roboto.setBaselineShift(0.0f);
builder.pushStyle(roboto);
builder.addText("Zero baseline shift text ");
assyrian.setBaselineShift(-20.0f);
builder.pushStyle(assyrian);
builder.addText("Up20");
roboto.setBaselineShift(-40.0f);
builder.pushStyle(roboto);
builder.addText("Up40");
assyrian.setBaselineShift(-60.0f);
builder.pushStyle(assyrian);
builder.addText("Up60");
roboto.setBaselineShift(-40.0f);
builder.pushStyle(roboto);
builder.addText("Up40");
assyrian.setBaselineShift(-20.0f);
builder.pushStyle(assyrian);
builder.addText("Up20");
roboto.setBaselineShift(-0.0f);
builder.pushStyle(roboto);
builder.addText(" Zero baseline shift text");
auto paragraph = builder.Build();
paragraph->layout(SK_ScalarInfinity);
paragraph->paint(canvas, 0, 0);
}
private:
using INHERITED = Sample;
};
} // namespace
//////////////////////////////////////////////////////////////////////////////
@ -3674,3 +3819,4 @@ DEF_SAMPLE(return new ParagraphView59();)
DEF_SAMPLE(return new ParagraphView60();)
DEF_SAMPLE(return new ParagraphView61();)
DEF_SAMPLE(return new ParagraphView62();)
DEF_SAMPLE(return new ParagraphView63();)

View File

@ -210,6 +210,7 @@ void OneLineShaper::finish(const Block& block, SkScalar height, SkScalar& advanc
run->fClusterStart,
height,
block.fStyle.getHalfLeading(),
block.fStyle.getBaselineShift(),
this->fParagraph->fRuns.count(),
advanceX
);
@ -606,6 +607,7 @@ bool OneLineShaper::iterateThroughShapingRegions(const ShapeVisitor& shape) {
runInfo,
placeholder.fRange.start,
0.0f,
0.0f,
false,
fParagraph->fRuns.count(),
advanceX);
@ -643,6 +645,7 @@ bool OneLineShaper::shape() {
// Start from the beginning (hoping that it's a simple case one block - one run)
fHeight = block.fStyle.getHeightOverride() ? block.fStyle.getHeight() : 0;
fUseHalfLeading = block.fStyle.getHalfLeading();
fBaselineShift = block.fStyle.getBaselineShift();
fAdvance = SkVector::Make(advanceX, 0);
fCurrentText = block.fRange;
fUnresolvedBlocks.emplace_back(RunBlock(block.fRange));

View File

@ -19,6 +19,7 @@ public:
: fParagraph(paragraph)
, fHeight(0.0f)
, fUseHalfLeading(false)
, fBaselineShift(0.0f)
, fAdvance(SkPoint::Make(0.0f, 0.0f))
, fUnresolvedGlyphs(0)
, fUniqueRunId(paragraph->fRuns.size()){ }
@ -83,6 +84,7 @@ private:
fCurrentText.start,
fHeight,
fUseHalfLeading,
fBaselineShift,
++fUniqueRunId,
fAdvance.fX);
return fCurrentRun->newRunBuffer();
@ -104,6 +106,7 @@ private:
TextRange fCurrentText;
SkScalar fHeight;
bool fUseHalfLeading;
SkScalar fBaselineShift;
SkVector fAdvance;
size_t fUnresolvedGlyphs;
size_t fUniqueRunId;

View File

@ -93,6 +93,7 @@ uint32_t ParagraphCache::KeyHash::operator()(const ParagraphCacheKey& key) const
hash = mix(hash, SkGoodHash()(relax(ts.fStyle.getWordSpacing())));
hash = mix(hash, SkGoodHash()(ts.fStyle.getLocale()));
hash = mix(hash, SkGoodHash()(relax(ts.fStyle.getHeight())));
hash = mix(hash, SkGoodHash()(relax(ts.fStyle.getBaselineShift())));
for (auto& ff : ts.fStyle.getFontFamilies()) {
hash = mix(hash, SkGoodHash()(ff));
}

View File

@ -19,6 +19,7 @@ Run::Run(ParagraphImpl* owner,
size_t firstChar,
SkScalar heightMultiplier,
bool useHalfLeading,
SkScalar baselineShift,
size_t index,
SkScalar offsetX)
: fOwner(owner)
@ -28,6 +29,7 @@ Run::Run(ParagraphImpl* owner,
, fClusterStart(firstChar)
, fHeightMultiplier(heightMultiplier)
, fUseHalfLeading(useHalfLeading)
, fBaselineShift(baselineShift)
{
fBidiLevel = info.fBidiLevel;
fAdvance = info.fAdvance;
@ -69,6 +71,9 @@ void Run::calculateMetrics() {
fCorrectAscent *= multiplier;
fCorrectDescent *= multiplier;
}
// If we shift the baseline we need to make sure the shifted text fits the line
fCorrectAscent += fBaselineShift;
fCorrectDescent += fBaselineShift;
}
SkShaper::RunHandler::Buffer Run::newRunBuffer() {

View File

@ -59,6 +59,7 @@ public:
size_t firstChar,
SkScalar heightMultiplier,
bool useHalfLeading,
SkScalar baselineShift,
size_t index,
SkScalar shiftX);
Run(const Run&) = default;
@ -85,11 +86,11 @@ public:
return SkVector::Make(fAdvance.fX, fFontMetrics.fDescent - fFontMetrics.fAscent + fFontMetrics.fLeading);
}
SkVector offset() const { return fOffset; }
SkScalar ascent() const { return fFontMetrics.fAscent; }
SkScalar descent() const { return fFontMetrics.fDescent; }
SkScalar ascent() const { return fFontMetrics.fAscent + fBaselineShift; }
SkScalar descent() const { return fFontMetrics.fDescent + fBaselineShift; }
SkScalar leading() const { return fFontMetrics.fLeading; }
SkScalar correctAscent() const { return fCorrectAscent; }
SkScalar correctDescent() const { return fCorrectDescent; }
SkScalar correctAscent() const { return fCorrectAscent + fBaselineShift; }
SkScalar correctDescent() const { return fCorrectDescent + fBaselineShift; }
SkScalar correctLeading() const { return fCorrectLeading; }
const SkFont& font() const { return fFont; }
bool leftToRight() const { return fBidiLevel % 2 == 0; }
@ -97,6 +98,7 @@ public:
size_t index() const { return fIndex; }
SkScalar heightMultiplier() const { return fHeightMultiplier; }
bool useHalfLeading() const { return fUseHalfLeading; }
SkScalar baselineShift() const { return fBaselineShift; }
PlaceholderStyle* placeholderStyle() const;
bool isPlaceholder() const { return fPlaceholderIndex != std::numeric_limits<size_t>::max(); }
size_t clusterIndex(size_t pos) const { return fClusterIndexes[pos]; }
@ -193,6 +195,7 @@ private:
SkFontMetrics fFontMetrics;
const SkScalar fHeightMultiplier;
const bool fUseHalfLeading;
const SkScalar fBaselineShift;
SkScalar fCorrectAscent;
SkScalar fCorrectDescent;
SkScalar fCorrectLeading;

View File

@ -337,7 +337,8 @@ void TextLine::buildTextBlob(TextRange textRange, const TextStyle& style, const
record.fClipRect = context.clip.makeOffset(this->offset());
}
SkScalar correctedBaseline = SkScalarFloorToScalar(this->baseline() + 0.5);
SkASSERT(nearlyEqual(context.run->baselineShift(), style.getBaselineShift()));
SkScalar correctedBaseline = SkScalarFloorToScalar(this->baseline() + style.getBaselineShift() + 0.5);
record.fBlob = builder.make();
if (record.fBlob != nullptr) {
record.fBounds.joinPossiblyEmptyRect(record.fBlob->bounds());
@ -366,7 +367,7 @@ void TextLine::paintBackground(SkCanvas* canvas, SkScalar x, SkScalar y, TextRan
SkRect TextLine::paintShadow(SkCanvas* canvas, SkScalar x, SkScalar y, TextRange textRange, const TextStyle& style, const ClipContext& context) const {
SkScalar correctedBaseline = SkScalarFloorToScalar(this->baseline() + 0.5);
SkScalar correctedBaseline = SkScalarFloorToScalar(this->baseline() + style.getBaselineShift() + 0.5);
SkRect shadowBounds = SkRect::MakeEmpty();
for (TextShadow shadow : style.getShadows()) {
@ -413,9 +414,9 @@ SkRect TextLine::paintShadow(SkCanvas* canvas, SkScalar x, SkScalar y, TextRange
void TextLine::paintDecorations(SkCanvas* canvas, SkScalar x, SkScalar y, TextRange textRange, const TextStyle& style, const ClipContext& context) const {
SkAutoCanvasRestore acr(canvas, true);
canvas->translate(x + this->offset().fX, y + this->offset().fY);
canvas->translate(x + this->offset().fX, y + this->offset().fY + style.getBaselineShift());
Decorations decorations;
SkScalar correctedBaseline = SkScalarFloorToScalar(this->baseline() + 0.5);
SkScalar correctedBaseline = SkScalarFloorToScalar(this->baseline() + style.getBaselineShift() + 0.5);
decorations.paint(canvas, style, context, correctedBaseline);
}
@ -541,8 +542,8 @@ std::unique_ptr<Run> TextLine::shapeEllipsis(const SkString& ellipsis, const Run
class ShapeHandler final : public SkShaper::RunHandler {
public:
ShapeHandler(SkScalar lineHeight, bool useHalfLeading, const SkString& ellipsis)
: fRun(nullptr), fLineHeight(lineHeight), fUseHalfLeading(useHalfLeading), fEllipsis(ellipsis) {}
ShapeHandler(SkScalar lineHeight, bool useHalfLeading, SkScalar baselineShift, const SkString& ellipsis)
: fRun(nullptr), fLineHeight(lineHeight), fUseHalfLeading(useHalfLeading), fBaselineShift(baselineShift), fEllipsis(ellipsis) {}
Run* run() & { return fRun.get(); }
std::unique_ptr<Run> run() && { return std::move(fRun); }
@ -555,7 +556,7 @@ std::unique_ptr<Run> TextLine::shapeEllipsis(const SkString& ellipsis, const Run
Buffer runBuffer(const RunInfo& info) override {
SkASSERT(!fRun);
fRun = std::make_unique<Run>(nullptr, info, 0, fLineHeight, fUseHalfLeading, 0, 0);
fRun = std::make_unique<Run>(nullptr, info, 0, fLineHeight, fUseHalfLeading, fBaselineShift, 0, 0);
return fRun->newRunBuffer();
}
@ -571,10 +572,11 @@ std::unique_ptr<Run> TextLine::shapeEllipsis(const SkString& ellipsis, const Run
std::unique_ptr<Run> fRun;
SkScalar fLineHeight;
bool fUseHalfLeading;
SkScalar fBaselineShift;
SkString fEllipsis;
};
ShapeHandler handler(run.heightMultiplier(), run.useHalfLeading(), ellipsis);
ShapeHandler handler(run.heightMultiplier(), run.useHalfLeading(), run.baselineShift(), ellipsis);
std::unique_ptr<SkShaper> shaper = SkShaper::MakeShapeDontWrapOrReorder();
SkASSERT_RELEASE(shaper != nullptr);
shaper->shape(ellipsis.c_str(), ellipsis.size(), run.font(), true,

View File

@ -21,6 +21,7 @@ TextStyle::TextStyle(const TextStyle& other, bool placeholder) {
fIsPlaceholder = placeholder;
fFontFeatures = other.fFontFeatures;
fHalfLeading = other.fHalfLeading;
fBaselineShift = other.fBaselineShift;
}
bool TextStyle::equals(const TextStyle& other) const {
@ -53,6 +54,9 @@ bool TextStyle::equals(const TextStyle& other) const {
if (fHalfLeading != other.fHalfLeading) {
return false;
}
if (fBaselineShift != other.fBaselineShift) {
return false;
}
if (fFontSize != other.fFontSize) {
return false;
}
@ -94,6 +98,7 @@ bool TextStyle::equalsByFonts(const TextStyle& that) const {
nearlyEqual(fLetterSpacing, that.fLetterSpacing) &&
nearlyEqual(fWordSpacing, that.fWordSpacing) &&
nearlyEqual(fHeight, that.fHeight) &&
nearlyEqual(fBaselineShift, that.fBaselineShift) &&
nearlyEqual(fFontSize, that.fFontSize) &&
fLocale == that.fLocale;
}
@ -139,7 +144,9 @@ bool TextStyle::matchOneAttribute(StyleType styleType, const TextStyle& other) c
fFontFamilies == other.fFontFamilies &&
fFontSize == other.fFontSize &&
fHeight == other.fHeight &&
fHalfLeading == other.fHalfLeading;
fHeight == other.fHeight &&
fHalfLeading == other.fHalfLeading &&
fBaselineShift == other.fBaselineShift;
default:
SkASSERT(false);
return false;
@ -162,6 +169,9 @@ void TextStyle::getFontMetrics(SkFontMetrics* metrics) const {
metrics->fAscent = (metrics->fAscent - metrics->fLeading / 2);
metrics->fDescent = (metrics->fDescent + metrics->fLeading / 2);
}
// If we shift the baseline we need to make sure the shifted text fits the line
metrics->fAscent += fBaselineShift;
metrics->fDescent += fBaselineShift;
}
bool PlaceholderStyle::equals(const PlaceholderStyle& other) const {