Reland "[skottie] Max lines text auto-sizing constraint"
This relands commit 4d6d9e3f89
.
Original change's description:
> [skottie] Max lines text auto-sizing constraint
>
> Introduce a new text property ("xl"), to limit the number of lines when
> auto-sizing.
>
> This is a Skottie extension, pending UI/controls in Bodymovin.
>
> Change-Id: Id0f1e633e1b324a97b227d6b187cd540990796a7
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/518498
> Reviewed-by: Ben Wagner <bungeman@google.com>
> Reviewed-by: Jorge Betancourt <jmbetancourt@google.com>
> Commit-Queue: Florin Malita <fmalita@google.com>
Change-Id: Ib9d28366332866d8b787f89fa1dc13132c02b435
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/518699
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Florin Malita <fmalita@google.com>
This commit is contained in:
parent
bad94bc85a
commit
762f8fbcad
@ -46,6 +46,7 @@ struct TextPropertyValue {
|
||||
fLineHeight = 0,
|
||||
fLineShift = 0,
|
||||
fAscent = 0;
|
||||
size_t fMaxLines = 0; // when auto-sizing
|
||||
SkTextUtils::Align fHAlign = SkTextUtils::kLeft_Align;
|
||||
Shaper::VAlign fVAlign = Shaper::VAlign::kTop;
|
||||
Shaper::ResizePolicy fResize = Shaper::ResizePolicy::kNone;
|
||||
|
@ -22,6 +22,7 @@ bool TextPropertyValue::operator==(const TextPropertyValue& other) const {
|
||||
&& fLineHeight == other.fLineHeight
|
||||
&& fLineShift == other.fLineShift
|
||||
&& fAscent == other.fAscent
|
||||
&& fMaxLines == other.fMaxLines
|
||||
&& fHAlign == other.fHAlign
|
||||
&& fVAlign == other.fVAlign
|
||||
&& fResize == other.fResize
|
||||
|
@ -321,6 +321,7 @@ DEF_TEST(Skottie_Properties, reporter) {
|
||||
120,
|
||||
12,
|
||||
0,
|
||||
0,
|
||||
SkTextUtils::kLeft_Align,
|
||||
Shaper::VAlign::kTopBaseline,
|
||||
Shaper::ResizePolicy::kNone,
|
||||
@ -480,7 +481,6 @@ DEF_TEST(Skottie_Shaper_HAlign, reporter) {
|
||||
Shaper::LinebreakPolicy::kExplicit,
|
||||
Shaper::Direction::kLTR,
|
||||
Shaper::Capitalization::kNone,
|
||||
Shaper::Flags::kNone
|
||||
};
|
||||
|
||||
const auto shape_result = Shaper::Shape(text, desc, text_point,
|
||||
@ -551,7 +551,6 @@ DEF_TEST(Skottie_Shaper_VAlign, reporter) {
|
||||
Shaper::LinebreakPolicy::kParagraph,
|
||||
Shaper::Direction::kLTR,
|
||||
Shaper::Capitalization::kNone,
|
||||
Shaper::Flags::kNone
|
||||
};
|
||||
|
||||
const auto shape_result = Shaper::Shape(text, desc, text_box, SkFontMgr::RefDefault());
|
||||
@ -592,7 +591,6 @@ DEF_TEST(Skottie_Shaper_FragmentGlyphs, reporter) {
|
||||
Shaper::LinebreakPolicy::kParagraph,
|
||||
Shaper::Direction::kLTR,
|
||||
Shaper::Capitalization::kNone,
|
||||
Shaper::Flags::kNone
|
||||
};
|
||||
|
||||
const SkString text("Foo bar baz");
|
||||
@ -685,7 +683,6 @@ DEF_TEST(Skottie_Shaper_ExplicitFontMgr, reporter) {
|
||||
Shaper::LinebreakPolicy::kParagraph,
|
||||
Shaper::Direction::kLTR,
|
||||
Shaper::Capitalization::kNone,
|
||||
Shaper::Flags::kNone
|
||||
};
|
||||
|
||||
const auto text_box = SkRect::MakeWH(100, 100);
|
||||
|
@ -385,6 +385,22 @@ Shaper::Result ShapeImpl(const SkString& txt, const Shaper::TextDesc& desc,
|
||||
return blobMaker.finalize(shaped_size);
|
||||
}
|
||||
|
||||
bool result_fits(const Shaper::Result& res, const SkSize& res_size,
|
||||
const SkRect& box, const Shaper::TextDesc& desc) {
|
||||
// optional max line count constraint
|
||||
if (desc.fMaxLines) {
|
||||
const auto line_count = res.fFragments.empty()
|
||||
? 0
|
||||
: res.fFragments.back().fLineIndex + 1;
|
||||
if (line_count > desc.fMaxLines) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// geometric constraint
|
||||
return res_size.width() <= box.width() && res_size.height() <= box.height();
|
||||
}
|
||||
|
||||
Shaper::Result ShapeToFit(const SkString& txt, const Shaper::TextDesc& orig_desc,
|
||||
const SkRect& box, const sk_sp<SkFontMgr>& fontmgr) {
|
||||
Shaper::Result best_result;
|
||||
@ -419,7 +435,7 @@ Shaper::Result ShapeToFit(const SkString& txt, const Shaper::TextDesc& orig_desc
|
||||
auto res = ShapeImpl(txt, desc, box, fontmgr, &res_size);
|
||||
|
||||
const auto prev_scale = try_scale;
|
||||
if (res_size.width() > box.width() || res_size.height() > box.height()) {
|
||||
if (!result_fits(res, res_size, box, desc)) {
|
||||
out_scale = try_scale;
|
||||
try_scale = (in_scale == min_scale)
|
||||
// initial in_scale not found yet - search exponentially
|
||||
@ -498,7 +514,7 @@ Shaper::Result Shaper::Shape(const SkString& orig_txt, const TextDesc& desc, con
|
||||
SkSize size;
|
||||
auto result = ShapeImpl(txt, desc, box, fontmgr, &size);
|
||||
|
||||
return (size.width() <= box.width() && size.height() <= box.height())
|
||||
return result_fits(result, size, box, desc)
|
||||
? result
|
||||
: ShapeToFit(txt, desc, box, fontmgr);
|
||||
}
|
||||
|
@ -108,19 +108,20 @@ public:
|
||||
|
||||
struct TextDesc {
|
||||
const sk_sp<SkTypeface>& fTypeface;
|
||||
SkScalar fTextSize,
|
||||
fMinTextSize,
|
||||
fMaxTextSize,
|
||||
fLineHeight,
|
||||
fLineShift,
|
||||
fAscent;
|
||||
SkTextUtils::Align fHAlign;
|
||||
VAlign fVAlign;
|
||||
ResizePolicy fResize;
|
||||
LinebreakPolicy fLinebreak;
|
||||
Direction fDirection;
|
||||
Capitalization fCapitalization;
|
||||
uint32_t fFlags;
|
||||
SkScalar fTextSize = 0,
|
||||
fMinTextSize = 0, // when auto-sizing
|
||||
fMaxTextSize = 0, // when auto-sizing
|
||||
fLineHeight = 0,
|
||||
fLineShift = 0,
|
||||
fAscent = 0;
|
||||
SkTextUtils::Align fHAlign = SkTextUtils::kLeft_Align;
|
||||
VAlign fVAlign = Shaper::VAlign::kTop;
|
||||
ResizePolicy fResize = Shaper::ResizePolicy::kNone;
|
||||
LinebreakPolicy fLinebreak = Shaper::LinebreakPolicy::kExplicit;
|
||||
Direction fDirection = Shaper::Direction::kLTR ;
|
||||
Capitalization fCapitalization = Shaper::Capitalization::kNone;
|
||||
size_t fMaxLines = 0; // when auto-sizing, 0 -> no max
|
||||
uint32_t fFlags = 0;
|
||||
};
|
||||
|
||||
// Performs text layout along an infinite horizontal line, starting at |textPoint|.
|
||||
|
@ -440,10 +440,17 @@ void TextAdapter::setText(const TextValue& txt) {
|
||||
uint32_t TextAdapter::shaperFlags() const {
|
||||
uint32_t flags = Shaper::Flags::kNone;
|
||||
|
||||
// We need granular fragments (as opposed to consolidated blobs) when animating, or when
|
||||
// positioning on a path.
|
||||
if (!fAnimators.empty() || fPathInfo) flags |= Shaper::Flags::kFragmentGlyphs;
|
||||
if (fRequiresAnchorPoint) flags |= Shaper::Flags::kTrackFragmentAdvanceAscent;
|
||||
// We need granular fragments (as opposed to consolidated blobs):
|
||||
// - when animating
|
||||
// - when positioning on a path
|
||||
// - when clamping the number or lines (for accurate line count)
|
||||
if (!fAnimators.empty() || fPathInfo || fText->fMaxLines) {
|
||||
flags |= Shaper::Flags::kFragmentGlyphs;
|
||||
}
|
||||
|
||||
if (fRequiresAnchorPoint) {
|
||||
flags |= Shaper::Flags::kTrackFragmentAdvanceAscent;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
@ -463,6 +470,7 @@ void TextAdapter::reshape() {
|
||||
fText->fLineBreak,
|
||||
fText->fDirection,
|
||||
fText->fCapitalization,
|
||||
fText->fMaxLines,
|
||||
this->shaperFlags(),
|
||||
};
|
||||
const auto shape_result = Shaper::Shape(fText->fText, text_desc, fText->fBox, fFontMgr);
|
||||
|
@ -74,9 +74,10 @@ bool Parse(const skjson::Value& jv, const internal::AnimationBuilder& abuilder,
|
||||
ParseDefault<size_t>((*jtxt)["sk_rs"], 0)),
|
||||
SK_ARRAY_COUNT(gResizeMap) - 1)];
|
||||
|
||||
// Optional min/max font size (used when aute-resizing)
|
||||
// Optional min/max font size and line count (used when aute-resizing)
|
||||
v->fMinTextSize = ParseDefault<SkScalar>((*jtxt)["mf"], 0.0f);
|
||||
v->fMaxTextSize = ParseDefault<SkScalar>((*jtxt)["xf"], std::numeric_limits<float>::max());
|
||||
v->fMaxLines = ParseDefault<size_t> ((*jtxt)["xl"], 0);
|
||||
|
||||
// At the moment, BM uses the paragraph box to discriminate point mode vs. paragraph mode.
|
||||
v->fLineBreak = v->fBox.isEmpty()
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user