Cache should work with INF values
Change-Id: I1ae8d95bb85d28fdce9e0cf270583f0224e4dfed Bug: skia:9874 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/268938 Commit-Queue: Julia Lavrova <jlavrova@google.com> Reviewed-by: Ben Wagner <bungeman@google.com>
This commit is contained in:
parent
2bc603196a
commit
c0360582d2
@ -37,6 +37,17 @@ struct StrutStyle {
|
||||
bool getHeightOverride() const { return fHeightOverride; }
|
||||
void setHeightOverride(bool v) { fHeightOverride = v; }
|
||||
|
||||
bool operator==(const StrutStyle& rhs) const {
|
||||
return this->fEnabled == rhs.fEnabled &&
|
||||
this->fHeightOverride == rhs.fHeightOverride &&
|
||||
this->fForceHeight == rhs.fForceHeight &&
|
||||
nearlyEqual(this->fLeading, rhs.fLeading) &&
|
||||
nearlyEqual(this->fHeight, rhs.fHeight) &&
|
||||
nearlyEqual(this->fFontSize, rhs.fFontSize) &&
|
||||
this->fFontStyle == rhs.fFontStyle &&
|
||||
this->fFontFamilies == rhs.fFontFamilies;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector<SkString> fFontFamilies;
|
||||
|
@ -18,6 +18,21 @@
|
||||
namespace skia {
|
||||
namespace textlayout {
|
||||
|
||||
static inline bool nearlyZero(SkScalar x, SkScalar tolerance = SK_ScalarNearlyZero) {
|
||||
if (SkScalarIsFinite(x)) {
|
||||
return SkScalarNearlyZero(x, tolerance);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool nearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance = SK_ScalarNearlyZero) {
|
||||
if (SkScalarIsFinite(x) && SkScalarIsFinite(x)) {
|
||||
return SkScalarNearlyEqual(x, y, tolerance);
|
||||
}
|
||||
// Inf == Inf, anything else is false
|
||||
return x == y;
|
||||
}
|
||||
|
||||
// Multiple decorations can be applied at once. Ex: Underline and overline is
|
||||
// (0x1 | 0x2)
|
||||
enum TextDecoration {
|
||||
@ -100,7 +115,13 @@ struct FontFeature {
|
||||
};
|
||||
|
||||
struct PlaceholderStyle {
|
||||
PlaceholderStyle() { }
|
||||
PlaceholderStyle()
|
||||
: fWidth(0)
|
||||
, fHeight(0)
|
||||
, fAlignment(PlaceholderAlignment::kBaseline)
|
||||
, fBaseline(TextBaseline::kAlphabetic)
|
||||
, fBaselineOffset(0) {}
|
||||
|
||||
PlaceholderStyle(SkScalar width, SkScalar height, PlaceholderAlignment alignment,
|
||||
TextBaseline baseline, SkScalar offset)
|
||||
: fWidth(width)
|
||||
@ -111,13 +132,10 @@ struct PlaceholderStyle {
|
||||
|
||||
bool equals(const PlaceholderStyle& other) const;
|
||||
|
||||
SkScalar fWidth = 0;
|
||||
SkScalar fHeight = 0;
|
||||
|
||||
SkScalar fWidth;
|
||||
SkScalar fHeight;
|
||||
PlaceholderAlignment fAlignment;
|
||||
|
||||
TextBaseline fBaseline;
|
||||
|
||||
// Distance from the top edge of the rect to the baseline position. This
|
||||
// baseline will be aligned against the alphabetic baseline of the surrounding
|
||||
// text.
|
||||
@ -126,7 +144,7 @@ struct PlaceholderStyle {
|
||||
// small or negative values will cause the rect to be positioned underneath
|
||||
// the line. When baseline == height, the bottom edge of the rect will rest on
|
||||
// the alphabetic baseline.
|
||||
SkScalar fBaselineOffset = 0;
|
||||
SkScalar fBaselineOffset;
|
||||
};
|
||||
|
||||
class TextStyle {
|
||||
|
@ -483,7 +483,7 @@ bool OneLineShaper::iterateThroughShapingRegions(const ShapeVisitor& shape) {
|
||||
run.fPositions[0] = { advanceX, 0 };
|
||||
run.fOffsets[0] = {0, 0};
|
||||
run.fClusterIndexes[0] = 0;
|
||||
run.fPlaceholder = &placeholder.fStyle;
|
||||
run.fPlaceholderIndex = &placeholder - fParagraph->fPlaceholders.begin();
|
||||
advanceX += placeholder.fStyle.fWidth;
|
||||
}
|
||||
return true;
|
||||
|
@ -8,8 +8,12 @@ namespace textlayout {
|
||||
namespace {
|
||||
SkScalar relax(SkScalar a) {
|
||||
// This rounding is done to match Flutter tests. Must be removed..
|
||||
auto threshold = SkIntToScalar(1 << 12);
|
||||
return SkScalarRoundToScalar(a * threshold)/threshold;
|
||||
if (SkScalarIsFinite(a)) {
|
||||
auto threshold = SkIntToScalar(1 << 12);
|
||||
return SkScalarRoundToScalar(a * threshold)/threshold;
|
||||
} else {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,19 +35,15 @@ class ParagraphCacheValue {
|
||||
public:
|
||||
ParagraphCacheValue(const ParagraphImpl* paragraph)
|
||||
: fKey(ParagraphCacheKey(paragraph))
|
||||
, fInternalState(paragraph->fState)
|
||||
, fRuns(paragraph->fRuns)
|
||||
, fClusters(paragraph->fClusters)
|
||||
, fUnresolvedGlyphs(paragraph->fUnresolvedGlyphs){ }
|
||||
, fClusters(paragraph->fClusters) { }
|
||||
|
||||
// Input == key
|
||||
ParagraphCacheKey fKey;
|
||||
|
||||
// Shaped results:
|
||||
InternalState fInternalState;
|
||||
// Shaped results
|
||||
SkTArray<Run, false> fRuns;
|
||||
SkTArray<Cluster, true> fClusters;
|
||||
size_t fUnresolvedGlyphs;
|
||||
};
|
||||
|
||||
uint32_t ParagraphCache::KeyHash::mix(uint32_t hash, uint32_t data) const {
|
||||
@ -56,21 +56,20 @@ uint32_t ParagraphCache::KeyHash::mix(uint32_t hash, uint32_t data) const {
|
||||
uint32_t ParagraphCache::KeyHash::operator()(const ParagraphCacheKey& key) const {
|
||||
uint32_t hash = 0;
|
||||
for (auto& ph : key.fPlaceholders) {
|
||||
if (&ph == &key.fPlaceholders.back()) {
|
||||
// Skip the last "dummy" placeholder
|
||||
break;
|
||||
if (ph.fRange.width() == 0) {
|
||||
continue;
|
||||
}
|
||||
hash = mix(hash, SkGoodHash()(ph.fRange.start));
|
||||
hash = mix(hash, SkGoodHash()(ph.fRange.end));
|
||||
hash = mix(hash, SkGoodHash()(relax(ph.fStyle.fBaselineOffset)));
|
||||
hash = mix(hash, SkGoodHash()(ph.fStyle.fBaseline));
|
||||
hash = mix(hash, SkGoodHash()(relax(ph.fStyle.fHeight)));
|
||||
hash = mix(hash, SkGoodHash()(relax(ph.fStyle.fWidth)));
|
||||
hash = mix(hash, SkGoodHash()(ph.fStyle.fAlignment));
|
||||
hash = mix(hash, SkGoodHash()(ph.fStyle.fBaseline));
|
||||
if (ph.fStyle.fAlignment == PlaceholderAlignment::kBaseline) {
|
||||
hash = mix(hash, SkGoodHash()(relax(ph.fStyle.fBaselineOffset)));
|
||||
}
|
||||
hash = mix(hash, SkGoodHash()(relax(ph.fStyle.fHeight)));
|
||||
hash = mix(hash, SkGoodHash()(relax(ph.fStyle.fWidth)));
|
||||
}
|
||||
|
||||
for (auto& ts : key.fTextStyles) {
|
||||
if (ts.fStyle.isPlaceholder()) {
|
||||
continue;
|
||||
@ -79,22 +78,34 @@ 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()(ts.fRange));
|
||||
for (auto& ff : ts.fStyle.getFontFamilies()) {
|
||||
hash = mix(hash, SkGoodHash()(ff));
|
||||
}
|
||||
for (auto& ff : ts.fStyle.getFontFeatures()) {
|
||||
hash = mix(hash, SkGoodHash()(ff));
|
||||
hash = mix(hash, SkGoodHash()(ff.fValue));
|
||||
hash = mix(hash, SkGoodHash()(ff.fName));
|
||||
}
|
||||
hash = mix(hash, SkGoodHash()(ts.fStyle.getFontStyle()));
|
||||
hash = mix(hash, SkGoodHash()(relax(ts.fStyle.getFontSize())));
|
||||
hash = mix(hash, SkGoodHash()(ts.fRange.start));
|
||||
hash = mix(hash, SkGoodHash()(ts.fRange.end));
|
||||
hash = mix(hash, SkGoodHash()(ts.fRange));
|
||||
}
|
||||
|
||||
hash = mix(hash, SkGoodHash()(relax(key.fParagraphStyle.getHeight())));
|
||||
hash = mix(hash, SkGoodHash()(key.fParagraphStyle.getTextDirection()));
|
||||
|
||||
auto& strutStyle = key.fParagraphStyle.getStrutStyle();
|
||||
if (strutStyle.getStrutEnabled()) {
|
||||
hash = mix(hash, SkGoodHash()(relax(strutStyle.getHeight())));
|
||||
hash = mix(hash, SkGoodHash()(relax(strutStyle.getLeading())));
|
||||
hash = mix(hash, SkGoodHash()(relax(strutStyle.getFontSize())));
|
||||
hash = mix(hash, SkGoodHash()(strutStyle.getHeightOverride()));
|
||||
hash = mix(hash, SkGoodHash()(strutStyle.getFontStyle()));
|
||||
hash = mix(hash, SkGoodHash()(strutStyle.getForceStrutHeight()));
|
||||
for (auto& ff : strutStyle.getFontFamilies()) {
|
||||
hash = mix(hash, SkGoodHash()(ff));
|
||||
}
|
||||
}
|
||||
|
||||
hash = mix(hash, SkGoodHash()(key.fText));
|
||||
return hash;
|
||||
}
|
||||
@ -114,13 +125,17 @@ bool operator==(const ParagraphCacheKey& a, const ParagraphCacheKey& b) {
|
||||
}
|
||||
|
||||
// There is no need to compare default paragraph styles - they are included into fTextStyles
|
||||
if (!SkScalarNearlyEqual(a.fParagraphStyle.getHeight(), b.fParagraphStyle.getHeight())) {
|
||||
if (!nearlyEqual(a.fParagraphStyle.getHeight(), b.fParagraphStyle.getHeight())) {
|
||||
return false;
|
||||
}
|
||||
if (a.fParagraphStyle.getTextDirection() != b.fParagraphStyle.getTextDirection()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(a.fParagraphStyle.getStrutStyle() == b.fParagraphStyle.getStrutStyle())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < a.fTextStyles.size(); ++i) {
|
||||
auto& tsa = a.fTextStyles[i];
|
||||
auto& tsb = b.fTextStyles[i];
|
||||
@ -137,9 +152,12 @@ bool operator==(const ParagraphCacheKey& a, const ParagraphCacheKey& b) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < a.fPlaceholders.size() - 1; ++i) {
|
||||
for (size_t i = 0; i < a.fPlaceholders.size(); ++i) {
|
||||
auto& tsa = a.fPlaceholders[i];
|
||||
auto& tsb = b.fPlaceholders[i];
|
||||
if (tsa.fRange.width() == 0 && tsb.fRange.width() == 0) {
|
||||
continue;
|
||||
}
|
||||
if (!(tsa.fStyle.equals(tsb.fStyle))) {
|
||||
return false;
|
||||
}
|
||||
@ -175,7 +193,6 @@ ParagraphCache::~ParagraphCache() { }
|
||||
|
||||
void ParagraphCache::updateFrom(const ParagraphImpl* paragraph, Entry* entry) {
|
||||
|
||||
entry->fValue->fInternalState = paragraph->state();
|
||||
for (size_t i = 0; i < paragraph->fRuns.size(); ++i) {
|
||||
auto& run = paragraph->fRuns[i];
|
||||
if (run.fSpaced) {
|
||||
@ -185,6 +202,7 @@ void ParagraphCache::updateFrom(const ParagraphImpl* paragraph, Entry* entry) {
|
||||
}
|
||||
|
||||
void ParagraphCache::updateTo(ParagraphImpl* paragraph, const Entry* entry) {
|
||||
|
||||
paragraph->fRuns.reset();
|
||||
paragraph->fRuns = entry->fValue->fRuns;
|
||||
for (auto& run : paragraph->fRuns) {
|
||||
@ -197,8 +215,7 @@ void ParagraphCache::updateTo(ParagraphImpl* paragraph, const Entry* entry) {
|
||||
cluster.setMaster(paragraph);
|
||||
}
|
||||
|
||||
paragraph->fState = entry->fValue->fInternalState;
|
||||
paragraph->fUnresolvedGlyphs = entry->fValue->fUnresolvedGlyphs;
|
||||
paragraph->fState = kMarked;
|
||||
}
|
||||
|
||||
void ParagraphCache::printStatistics() {
|
||||
|
@ -414,7 +414,7 @@ void ParagraphImpl::breakShapedTextIntoLines(SkScalar maxWidth) {
|
||||
}
|
||||
}
|
||||
|
||||
fLongestLine = SkTMax(fLongestLine, SkScalarNearlyZero(advance.fX) ? widthWithSpaces : advance.fX);
|
||||
fLongestLine = SkTMax(fLongestLine, nearlyZero(advance.fX) ? widthWithSpaces : advance.fX);
|
||||
});
|
||||
fHeight = textWrapper.height();
|
||||
fWidth = maxWidth;
|
||||
@ -427,9 +427,17 @@ void ParagraphImpl::breakShapedTextIntoLines(SkScalar maxWidth) {
|
||||
|
||||
void ParagraphImpl::formatLines(SkScalar maxWidth) {
|
||||
auto effectiveAlign = fParagraphStyle.effective_align();
|
||||
|
||||
if (!SkScalarIsFinite(maxWidth) && effectiveAlign != TextAlign::kLeft) {
|
||||
// Special case: clean all text in case of maxWidth == INF & align != left
|
||||
// We had to go through shaping though because we need all the measurement numbers
|
||||
fLines.reset();
|
||||
return;
|
||||
}
|
||||
if (effectiveAlign == TextAlign::kJustify) {
|
||||
this->resetRunShifts();
|
||||
}
|
||||
|
||||
for (auto& line : fLines) {
|
||||
if (&line == &fLines.back() && effectiveAlign == TextAlign::kJustify) {
|
||||
effectiveAlign = line.assumedTextAlign();
|
||||
@ -768,16 +776,16 @@ std::vector<TextBox> ParagraphImpl::getRectsForRange(unsigned start,
|
||||
bool mergedBoxes = false;
|
||||
if (!results.empty() &&
|
||||
lastRun != nullptr &&
|
||||
lastRun->placeholder() == nullptr &&
|
||||
context.run->placeholder() == nullptr &&
|
||||
SkScalarNearlyEqual(lastRun->lineHeight(), context.run->lineHeight()) &&
|
||||
lastRun->placeholderStyle() == nullptr &&
|
||||
context.run->placeholderStyle() == nullptr &&
|
||||
nearlyEqual(lastRun->lineHeight(), context.run->lineHeight()) &&
|
||||
lastRun->font() == context.run->font())
|
||||
{
|
||||
auto& lastBox = results.back();
|
||||
if (SkScalarNearlyEqual(lastBox.rect.fTop, clip.fTop) &&
|
||||
SkScalarNearlyEqual(lastBox.rect.fBottom, clip.fBottom) &&
|
||||
(SkScalarNearlyEqual(lastBox.rect.fLeft, clip.fRight) ||
|
||||
SkScalarNearlyEqual(lastBox.rect.fRight, clip.fLeft)))
|
||||
if (nearlyEqual(lastBox.rect.fTop, clip.fTop) &&
|
||||
nearlyEqual(lastBox.rect.fBottom, clip.fBottom) &&
|
||||
(nearlyEqual(lastBox.rect.fLeft, clip.fRight) ||
|
||||
nearlyEqual(lastBox.rect.fRight, clip.fLeft)))
|
||||
{
|
||||
lastBox.rect.fLeft = SkTMin(lastBox.rect.fLeft, clip.fLeft);
|
||||
lastBox.rect.fRight = SkTMax(lastBox.rect.fRight, clip.fRight);
|
||||
@ -792,7 +800,7 @@ std::vector<TextBox> ParagraphImpl::getRectsForRange(unsigned start,
|
||||
results.emplace_back(
|
||||
clip, context.run->leftToRight() ? TextDirection::kLtr : TextDirection::kRtl);
|
||||
}
|
||||
if (!SkScalarNearlyZero(trailingSpaces.width()) && !merge(trailingSpaces)) {
|
||||
if (!nearlyZero(trailingSpaces.width()) && !merge(trailingSpaces)) {
|
||||
results.emplace_back(trailingSpaces, paragraphTextDirection);
|
||||
}
|
||||
|
||||
@ -843,7 +851,7 @@ std::vector<TextBox> ParagraphImpl::getRectsForPlaceholders() {
|
||||
auto context =
|
||||
line.measureTextInsideOneRun(textRange, run, runOffset, 0, true, false);
|
||||
*width = context.clip.width();
|
||||
if (run->placeholder() == nullptr) {
|
||||
if (run->placeholderStyle() == nullptr) {
|
||||
return true;
|
||||
}
|
||||
if (run->textRange().width() == 0) {
|
||||
@ -1120,7 +1128,9 @@ void ParagraphImpl::computeEmptyMetrics() {
|
||||
fEmptyMetrics.leading() * multiplier);
|
||||
}
|
||||
|
||||
fStrutMetrics.updateLineMetrics(fEmptyMetrics);
|
||||
if (fParagraphStyle.getStrutStyle().getStrutEnabled()) {
|
||||
fStrutMetrics.updateLineMetrics(fEmptyMetrics);
|
||||
}
|
||||
}
|
||||
|
||||
void ParagraphImpl::updateText(size_t from, SkString text) {
|
||||
|
@ -135,6 +135,9 @@ public:
|
||||
SkSpan<Block> styles() {
|
||||
return SkSpan<Block>(fTextStyles.data(), fTextStyles.size());
|
||||
}
|
||||
SkSpan<Placeholder> placeholders() {
|
||||
return SkSpan<Placeholder>(fPlaceholders.data(), fPlaceholders.size());
|
||||
}
|
||||
SkSpan<TextLine> lines() { return SkSpan<TextLine>(fLines.data(), fLines.size()); }
|
||||
const ParagraphStyle& paragraphStyle() const { return fParagraphStyle; }
|
||||
SkSpan<Cluster> clusters() { return SkSpan<Cluster>(fClusters.begin(), fClusters.size()); }
|
||||
|
@ -47,7 +47,7 @@ Run::Run(ParagraphImpl* master,
|
||||
fOffsets[info.glyphCount] = { 0, 0};
|
||||
fClusterIndexes[info.glyphCount] = this->leftToRight() ? info.utf8Range.end() : info.utf8Range.begin();
|
||||
fEllipsis = false;
|
||||
fPlaceholder = nullptr;
|
||||
fPlaceholderIndex = std::numeric_limits<size_t>::max();
|
||||
}
|
||||
|
||||
SkShaper::RunHandler::Buffer Run::newRunBuffer() {
|
||||
@ -238,9 +238,11 @@ void Run::shift(const Cluster* cluster, SkScalar offset) {
|
||||
|
||||
void Run::updateMetrics(InternalLineMetrics* endlineMetrics) {
|
||||
|
||||
SkASSERT(isPlaceholder());
|
||||
auto placeholderStyle = this->placeholderStyle();
|
||||
// Difference between the placeholder baseline and the line bottom
|
||||
SkScalar baselineAdjustment = 0;
|
||||
switch (fPlaceholder->fBaseline) {
|
||||
switch (placeholderStyle->fBaseline) {
|
||||
case TextBaseline::kAlphabetic:
|
||||
break;
|
||||
|
||||
@ -249,11 +251,11 @@ void Run::updateMetrics(InternalLineMetrics* endlineMetrics) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto height = fPlaceholder->fHeight;
|
||||
auto offset = fPlaceholder->fBaselineOffset;
|
||||
auto height = placeholderStyle->fHeight;
|
||||
auto offset = placeholderStyle->fBaselineOffset;
|
||||
|
||||
fFontMetrics.fLeading = 0;
|
||||
switch (fPlaceholder->fAlignment) {
|
||||
switch (placeholderStyle->fAlignment) {
|
||||
case PlaceholderAlignment::kBaseline:
|
||||
fFontMetrics.fAscent = baselineAdjustment - offset;
|
||||
fFontMetrics.fDescent = baselineAdjustment + height - offset;
|
||||
@ -339,6 +341,14 @@ SkScalar Run::positionX(size_t pos) const {
|
||||
return posX(pos) + fShifts[pos] + fMaster->posShift(fIndex, pos);
|
||||
}
|
||||
|
||||
PlaceholderStyle* Run::placeholderStyle() const {
|
||||
if (isPlaceholder()) {
|
||||
return &fMaster->placeholders()[fPlaceholderIndex].fStyle;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Run* Cluster::run() const {
|
||||
if (fRunIndex >= fMaster->runs().size()) {
|
||||
return nullptr;
|
||||
|
@ -104,8 +104,8 @@ public:
|
||||
bool leftToRight() const { return fBidiLevel % 2 == 0; }
|
||||
size_t index() const { return fIndex; }
|
||||
SkScalar lineHeight() const { return fHeightMultiplier; }
|
||||
PlaceholderStyle* placeholder() const { return fPlaceholder; }
|
||||
bool isPlaceholder() const { return fPlaceholder != nullptr; }
|
||||
PlaceholderStyle* placeholderStyle() const;
|
||||
bool isPlaceholder() const { return fPlaceholderIndex != std::numeric_limits<size_t>::max(); }
|
||||
size_t clusterIndex(size_t pos) const { return fClusterIndexes[pos]; }
|
||||
SkScalar positionX(size_t pos) const;
|
||||
|
||||
@ -177,7 +177,7 @@ private:
|
||||
SkFont fFont;
|
||||
SkFontMetrics fFontMetrics;
|
||||
SkScalar fHeightMultiplier;
|
||||
PlaceholderStyle* fPlaceholder;
|
||||
size_t fPlaceholderIndex;
|
||||
bool fEllipsis;
|
||||
size_t fIndex;
|
||||
uint8_t fBidiLevel;
|
||||
|
@ -34,7 +34,7 @@ int compareRound(SkScalar a, SkScalar b) {
|
||||
// It has to be relative to be useful
|
||||
auto base = SkTMax(SkScalarAbs(a), SkScalarAbs(b));
|
||||
auto diff = SkScalarAbs(a - b);
|
||||
if (SkScalarNearlyZero(base) || diff / base < 0.001f) {
|
||||
if (nearlyZero(base) || diff / base < 0.001f) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -223,7 +223,7 @@ void TextLine::paint(SkCanvas* textCanvas) {
|
||||
this->iterateThroughVisualRuns(false,
|
||||
[textCanvas, this]
|
||||
(const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) {
|
||||
if (run->placeholder() != nullptr) {
|
||||
if (run->placeholderStyle() != nullptr) {
|
||||
*runWidthInLine = run->advance().fX;
|
||||
return true;
|
||||
}
|
||||
@ -300,7 +300,7 @@ SkRect TextLine::extendHeight(const ClipContext& context) const {
|
||||
|
||||
void TextLine::paintText(SkCanvas* canvas, TextRange textRange, const TextStyle& style, const ClipContext& context) const {
|
||||
|
||||
if (context.run->placeholder() != nullptr) {
|
||||
if (context.run->placeholderStyle() != nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -578,7 +578,7 @@ void TextLine::justify(SkScalar maxWidth) {
|
||||
return true;
|
||||
});
|
||||
|
||||
SkAssertResult(SkScalarNearlyEqual(shift, maxWidth - textLen));
|
||||
SkAssertResult(nearlyEqual(shift, maxWidth - textLen));
|
||||
SkASSERT(whitespacePatches == 0);
|
||||
|
||||
this->fWidthWithSpaces += ghostShift;
|
||||
@ -644,7 +644,7 @@ Run* TextLine::shapeEllipsis(const SkString& ellipsis, Run* run) {
|
||||
void commitRunBuffer(const RunInfo& info) override {
|
||||
fRun->fAdvance.fX = info.fAdvance.fX;
|
||||
fRun->fAdvance.fY = fRun->advance().fY;
|
||||
fRun->fPlaceholder = nullptr;
|
||||
fRun->fPlaceholderIndex = std::numeric_limits<size_t>::max();
|
||||
fRun->fEllipsis = true;
|
||||
}
|
||||
|
||||
@ -673,7 +673,7 @@ TextLine::ClipContext TextLine::measureTextInsideOneRun(TextRange textRange,
|
||||
bool limitToClusters) const {
|
||||
ClipContext result = { run, 0, run->size(), 0, SkRect::MakeEmpty(), false };
|
||||
|
||||
if (run->placeholder() != nullptr || run->fEllipsis) {
|
||||
if (run->placeholderStyle() != nullptr || run->fEllipsis) {
|
||||
// Both ellipsis and placeholders can only be measured as one glyph
|
||||
SkASSERT(textRange == run->textRange());
|
||||
result.fTextShift = runOffsetInLine;
|
||||
@ -931,7 +931,7 @@ LineMetrics TextLine::getMetrics() const {
|
||||
this->iterateThroughVisualRuns(false,
|
||||
[this, &result]
|
||||
(const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) {
|
||||
if (run->placeholder() != nullptr) {
|
||||
if (run->placeholderStyle() != nullptr) {
|
||||
*runWidthInLine = run->advance().fX;
|
||||
return true;
|
||||
}
|
||||
|
@ -108,10 +108,10 @@ bool TextStyle::equalsByFonts(const TextStyle& that) const {
|
||||
fFontStyle == that.fFontStyle &&
|
||||
fFontFamilies == that.fFontFamilies &&
|
||||
fFontFeatures == that.fFontFeatures &&
|
||||
SkScalarNearlyEqual(fLetterSpacing, that.fLetterSpacing) &&
|
||||
SkScalarNearlyEqual(fWordSpacing, that.fWordSpacing) &&
|
||||
SkScalarNearlyEqual(fHeight, that.fHeight) &&
|
||||
SkScalarNearlyEqual(fFontSize, that.fFontSize) &&
|
||||
nearlyEqual(fLetterSpacing, that.fLetterSpacing) &&
|
||||
nearlyEqual(fWordSpacing, that.fWordSpacing) &&
|
||||
nearlyEqual(fHeight, that.fHeight) &&
|
||||
nearlyEqual(fFontSize, that.fFontSize) &&
|
||||
fLocale == that.fLocale;
|
||||
}
|
||||
|
||||
@ -180,12 +180,12 @@ void TextStyle::getFontMetrics(SkFontMetrics* metrics) const {
|
||||
}
|
||||
|
||||
bool PlaceholderStyle::equals(const PlaceholderStyle& other) const {
|
||||
return SkScalarNearlyEqual(fWidth, other.fWidth) &&
|
||||
SkScalarNearlyEqual(fHeight, other.fHeight) &&
|
||||
return nearlyEqual(fWidth, other.fWidth) &&
|
||||
nearlyEqual(fHeight, other.fHeight) &&
|
||||
fAlignment == other.fAlignment &&
|
||||
fBaseline == other.fBaseline &&
|
||||
(fAlignment != PlaceholderAlignment::kBaseline ||
|
||||
SkScalarNearlyEqual(fBaselineOffset, other.fBaselineOffset));
|
||||
nearlyEqual(fBaselineOffset, other.fBaselineOffset));
|
||||
}
|
||||
|
||||
} // namespace textlayout
|
||||
|
@ -220,7 +220,7 @@ void TextWrapper::breakTextIntoLines(ParagraphImpl* parent,
|
||||
continue;
|
||||
}
|
||||
lastRun = cluster->run();
|
||||
if (lastRun->placeholder() != nullptr) {
|
||||
if (lastRun->placeholderStyle() != nullptr) {
|
||||
SkASSERT(lastRun->size() == 1);
|
||||
// Update the placeholder metrics so we can get the placeholder positions later
|
||||
// and the line metrics (to make sure the placeholder fits)
|
||||
|
@ -112,7 +112,7 @@ class TextWrapper {
|
||||
if (fEnd.cluster() != nullptr &&
|
||||
fEnd.cluster()->master() != nullptr &&
|
||||
fEnd.cluster()->run() != nullptr &&
|
||||
fEnd.cluster()->run()->placeholder() == nullptr &&
|
||||
fEnd.cluster()->run()->placeholderStyle() == nullptr &&
|
||||
fWidth > 0) {
|
||||
fWidth -= (fEnd.cluster()->width() - fEnd.cluster()->trimmedWidth(fEnd.position()));
|
||||
}
|
||||
|
@ -1869,27 +1869,61 @@ protected:
|
||||
|
||||
void onDrawContent(SkCanvas* canvas) override {
|
||||
canvas->drawColor(SK_ColorWHITE);
|
||||
|
||||
const char* text = "Overflowing endorsement that has a large lengthy text and is a lot longer than expected";
|
||||
/*
|
||||
* Shell: ParagraphStyle: 1.000000 1
|
||||
Shell: Strut enabled: 0 1.000000 14.000000 400 5 0
|
||||
Shell: Font Families: 0
|
||||
Shell: DefaultTextStyle: 16.000000 500 5 0
|
||||
Shell: Font Families: 1 Roboto
|
||||
Shell: Font Features: 0
|
||||
Shell: TextStyle#0: [0:22) 16.000000 500 5 0
|
||||
Shell: Font Families: 1 Roboto
|
||||
Shell: Font Features: 0
|
||||
Shell: TextStyle#1: [25:49) 16.000000 500 5 0
|
||||
Shell: Font Families: 1 Roboto
|
||||
Shell: Font Features: 0
|
||||
Shell: Placeholder#0: [22:25) 32.000000 32.000000 32.000000 0 5
|
||||
Shell: Placeholder#1: [49:52) 19.000000 41.000000 19.000000 0 4
|
||||
Shell: Placeholder#2: [52:52) 0.000000 0.000000 0.000000 0 5
|
||||
Shell: layout('Go to device settings  and set up a passcode. ', 280.000000): 280.000000 * 38.000000
|
||||
*/
|
||||
auto fontCollection = getFontCollection();
|
||||
//fontCollection->getParagraphCache()->turnOn(false);
|
||||
const char* text1 = "Go to device settings ";
|
||||
const char* text2 = "and set up a passcode.";
|
||||
ParagraphStyle paragraph_style;
|
||||
paragraph_style.setEllipsis(u"\u2026");
|
||||
paragraph_style.setMaxLines(std::numeric_limits<size_t>::max());
|
||||
ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
|
||||
StrutStyle strut_style;
|
||||
strut_style.setStrutEnabled(false);
|
||||
strut_style.setFontSize(14);
|
||||
strut_style.setForceStrutHeight(false);
|
||||
strut_style.setHeight(14);
|
||||
paragraph_style.setStrutStyle(strut_style);
|
||||
TextStyle text_style;
|
||||
text_style.setColor(SK_ColorBLACK);
|
||||
text_style.setFontFamilies({SkString("Google Sans")});
|
||||
text_style.setFontSize(20);
|
||||
builder.pushStyle(text_style);
|
||||
builder.addText(text);
|
||||
auto paragraph = builder.Build();
|
||||
paragraph->layout(594.0f);
|
||||
paragraph->paint(canvas, 0, 0);
|
||||
canvas->translate(0, 200);
|
||||
paragraph->layout(std::numeric_limits<SkScalar>::max());
|
||||
paragraph->paint(canvas, 0, 0);
|
||||
canvas->translate(0, 200);
|
||||
paragraph->layout(787.0f);
|
||||
paragraph->paint(canvas, 0, 0);
|
||||
text_style.setFontFamilies({SkString("Roboto")});
|
||||
text_style.setFontSize(16);
|
||||
PlaceholderStyle placeholder_style;
|
||||
{
|
||||
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
|
||||
builder.pushStyle(text_style);
|
||||
builder.addText(text1);
|
||||
placeholder_style.fHeight = 32;
|
||||
placeholder_style.fWidth = 32;
|
||||
placeholder_style.fBaselineOffset = 32;
|
||||
placeholder_style.fBaseline = TextBaseline::kAlphabetic;
|
||||
placeholder_style.fAlignment = PlaceholderAlignment::kMiddle;
|
||||
builder.addPlaceholder(placeholder_style);
|
||||
builder.addText(text2);
|
||||
placeholder_style.fHeight = 19;
|
||||
placeholder_style.fWidth = 41;
|
||||
placeholder_style.fBaselineOffset = 19;
|
||||
placeholder_style.fBaseline = TextBaseline::kAlphabetic;
|
||||
placeholder_style.fAlignment = PlaceholderAlignment::kTop;
|
||||
builder.addPlaceholder(placeholder_style);
|
||||
auto paragraph = builder.Build();
|
||||
paragraph->layout(280);
|
||||
paragraph->paint(canvas, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
@ -2089,5 +2123,5 @@ 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();)
|
||||
|
@ -5223,3 +5223,55 @@ DEF_TEST(SkParagraph_MemoryLeak, reporter) {
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
}
|
||||
};
|
||||
|
||||
DEF_TEST(SkParagraph_FormattingInfinity, reporter) {
|
||||
sk_sp<ResourceFontCollection> fontCollection = sk_make_sp<ResourceFontCollection>();
|
||||
if (!fontCollection->fontsFound()) return;
|
||||
fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
|
||||
TestCanvas canvas("SkParagraph_FormattingInfinity.png");
|
||||
|
||||
const char* text = "Some text\nAnother line";
|
||||
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(SK_ColorBLACK);
|
||||
|
||||
TextStyle textStyle;
|
||||
textStyle.setForegroundColor(paint);
|
||||
textStyle.setFontFamilies({ SkString("Roboto") });
|
||||
ParagraphStyle paragraphStyle;
|
||||
paragraphStyle.setTextStyle(textStyle);
|
||||
|
||||
auto draw = [&](const char* prefix, TextAlign textAlign) {
|
||||
paragraphStyle.setTextAlign(textAlign);
|
||||
ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
|
||||
builder.addText(text);
|
||||
auto paragraph = builder.Build();
|
||||
paragraph->layout(SK_ScalarInfinity);
|
||||
paragraph->paint(canvas.get(), 0, 0);
|
||||
canvas.get()->translate(0, 100);
|
||||
};
|
||||
|
||||
draw("left", TextAlign::kLeft);
|
||||
draw("right", TextAlign::kRight);
|
||||
draw("center", TextAlign::kCenter);
|
||||
draw("justify", TextAlign::kJustify);
|
||||
};
|
||||
|
||||
DEF_TEST(SkParagraph_Infinity, reporter) {
|
||||
SkASSERT(nearlyEqual(1, SK_ScalarInfinity) == false);
|
||||
SkASSERT(nearlyEqual(1, SK_ScalarNegativeInfinity) == false);
|
||||
SkASSERT(nearlyEqual(1, SK_ScalarNaN) == false);
|
||||
|
||||
SkASSERT(nearlyEqual(SK_ScalarInfinity, SK_ScalarInfinity) == true);
|
||||
SkASSERT(nearlyEqual(SK_ScalarInfinity, SK_ScalarNegativeInfinity) == false);
|
||||
SkASSERT(nearlyEqual(SK_ScalarInfinity, SK_ScalarNaN) == false);
|
||||
|
||||
SkASSERT(nearlyEqual(SK_ScalarNegativeInfinity, SK_ScalarInfinity) == false);
|
||||
SkASSERT(nearlyEqual(SK_ScalarNegativeInfinity, SK_ScalarNegativeInfinity) == true);
|
||||
SkASSERT(nearlyEqual(SK_ScalarNegativeInfinity, SK_ScalarNaN) == false);
|
||||
|
||||
SkASSERT(nearlyEqual(SK_ScalarNaN, SK_ScalarInfinity) == false);
|
||||
SkASSERT(nearlyEqual(SK_ScalarNaN, SK_ScalarNegativeInfinity) == false);
|
||||
SkASSERT(nearlyEqual(SK_ScalarNaN, SK_ScalarNaN) == false);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user