Reland "[skottie] AllCaps support"

This reverts commit 6142500513.

Reason for revert: relanding with fixes

Original change's description:
> Revert "[skottie] AllCaps support"
>
> This reverts commit efc7ca4a71.
>
> Reason for revert: broke Chromium, NoDEPS builds
>
> Original change's description:
> > [skottie] AllCaps support
> >
> > AfterEffects and Bodymovin support an "AllCaps" text flag which forces
> > text capitalization.
> >
> >   * add toUpper() bindings to SkUnicode/SkICU
> >   * add capitalization options to SkottieShaper
> >   * plumb existing Lottie 'ca' (AllCaps) prop
> >   * also fix a couple of unrelated whoopsies
> >
> > Change-Id: I8e80921b66530e9830938004946082c6e450b04b
> > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/445104
> > Reviewed-by: Ben Wagner <bungeman@google.com>
> > Commit-Queue: Florin Malita <fmalita@google.com>
>
> TBR=bungeman@google.com,fmalita@chromium.org,fmalita@google.com,jlavrova@google.com,skcq-be@skia-corp.google.com.iam.gserviceaccount.com
>
> Change-Id: I3bb43f37f07cfc021e397df578499a4c4da15ca3
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/444980
> Reviewed-by: Florin Malita <fmalita@google.com>
> Commit-Queue: Florin Malita <fmalita@google.com>

Change-Id: Id729e09d4cade0cead193ffc5e6bd4fea1cdcff6
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/445598
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Florin Malita <fmalita@google.com>
This commit is contained in:
Florin Malita 2021-09-03 09:45:53 -04:00 committed by SkCQ
parent 6142500513
commit 5572b2a3ed
15 changed files with 112 additions and 24 deletions

View File

@ -281,6 +281,7 @@ def compile_fn(api, checkout_root, out_dir):
'skia_use_expat': 'false',
'skia_use_freetype': 'false',
'skia_use_harfbuzz': 'false',
'skia_use_icu': 'false',
'skia_use_libjpeg_turbo_decode': 'false',
'skia_use_libjpeg_turbo_encode': 'false',
'skia_use_libpng_decode': 'false',

View File

@ -52,7 +52,7 @@
"[START_DIR]/cache/work/skia/bin/gn",
"gen",
"[START_DIR]/cache/work/skia/out/Build-Debian10-Clang-x86_64-Release-NoDEPS/Release",
"--args=cc=\"[START_DIR]/clang_linux/bin/clang\" cc_wrapper=\"[START_DIR]/ccache_linux/bin/ccache\" cxx=\"[START_DIR]/clang_linux/bin/clang++\" extra_cflags=[\"-B[START_DIR]/clang_linux/bin\", \"-DPLACEHOLDER_clang_linux_version=42\"] extra_ldflags=[\"-B[START_DIR]/clang_linux/bin\", \"-fuse-ld=lld\", \"-L[START_DIR]/clang_linux/lib\"] is_debug=false is_official_build=true skia_enable_fontmgr_empty=true skia_enable_gpu=true skia_enable_pdf=false skia_use_expat=false skia_use_freetype=false skia_use_harfbuzz=false skia_use_libjpeg_turbo_decode=false skia_use_libjpeg_turbo_encode=false skia_use_libpng_decode=false skia_use_libpng_encode=false skia_use_libwebp_decode=false skia_use_libwebp_encode=false skia_use_vulkan=false skia_use_zlib=false target_cpu=\"x86_64\" werror=true"
"--args=cc=\"[START_DIR]/clang_linux/bin/clang\" cc_wrapper=\"[START_DIR]/ccache_linux/bin/ccache\" cxx=\"[START_DIR]/clang_linux/bin/clang++\" extra_cflags=[\"-B[START_DIR]/clang_linux/bin\", \"-DPLACEHOLDER_clang_linux_version=42\"] extra_ldflags=[\"-B[START_DIR]/clang_linux/bin\", \"-fuse-ld=lld\", \"-L[START_DIR]/clang_linux/lib\"] is_debug=false is_official_build=true skia_enable_fontmgr_empty=true skia_enable_gpu=true skia_enable_pdf=false skia_use_expat=false skia_use_freetype=false skia_use_harfbuzz=false skia_use_icu=false skia_use_libjpeg_turbo_decode=false skia_use_libjpeg_turbo_encode=false skia_use_libpng_decode=false skia_use_libpng_encode=false skia_use_libwebp_decode=false skia_use_libwebp_encode=false skia_use_vulkan=false skia_use_zlib=false target_cpu=\"x86_64\" werror=true"
],
"cwd": "[START_DIR]/cache/work/skia",
"env": {

View File

@ -139,7 +139,7 @@
"[START_DIR]\\skia\\bin\\gn",
"gen",
"[START_DIR]\\skia\\out\\Build-Win10-Clang-x86_64-Release-NoDEPS\\Release_x64",
"--args=cc=\"clang\" clang_win=\"[START_DIR]\\clang_win\" cxx=\"clang++\" extra_cflags=[\"-DPLACEHOLDER_clang_win_version=42\"] is_debug=false is_official_build=true skia_enable_fontmgr_empty=true skia_enable_gpu=true skia_enable_pdf=false skia_use_expat=false skia_use_freetype=false skia_use_harfbuzz=false skia_use_libjpeg_turbo_decode=false skia_use_libjpeg_turbo_encode=false skia_use_libpng_decode=false skia_use_libpng_encode=false skia_use_libwebp_decode=false skia_use_libwebp_encode=false skia_use_vulkan=false skia_use_zlib=false target_cpu=\"x86_64\" werror=true win_sdk=\"[START_DIR]\\win_toolchain/win_sdk\" win_vc=\"[START_DIR]\\win_toolchain/VC\""
"--args=cc=\"clang\" clang_win=\"[START_DIR]\\clang_win\" cxx=\"clang++\" extra_cflags=[\"-DPLACEHOLDER_clang_win_version=42\"] is_debug=false is_official_build=true skia_enable_fontmgr_empty=true skia_enable_gpu=true skia_enable_pdf=false skia_use_expat=false skia_use_freetype=false skia_use_harfbuzz=false skia_use_icu=false skia_use_libjpeg_turbo_decode=false skia_use_libjpeg_turbo_encode=false skia_use_libpng_decode=false skia_use_libpng_encode=false skia_use_libwebp_decode=false skia_use_libwebp_encode=false skia_use_vulkan=false skia_use_zlib=false target_cpu=\"x86_64\" werror=true win_sdk=\"[START_DIR]\\win_toolchain/win_sdk\" win_vc=\"[START_DIR]\\win_toolchain/VC\""
],
"cwd": "[START_DIR]\\skia",
"env": {

View File

@ -23,6 +23,7 @@ if (skia_enable_skottie) {
"../skresources",
"../sksg",
"../skshaper",
"../skunicode",
]
}

View File

@ -39,24 +39,25 @@ enum class TextPaintOrder : uint8_t {
struct TextPropertyValue {
sk_sp<SkTypeface> fTypeface;
SkString fText;
float fTextSize = 0,
fMinTextSize = 0, // when auto-sizing
fMaxTextSize = std::numeric_limits<float>::max(), // when auto-sizing
fStrokeWidth = 0,
fLineHeight = 0,
fLineShift = 0,
fAscent = 0;
SkTextUtils::Align fHAlign = SkTextUtils::kLeft_Align;
Shaper::VAlign fVAlign = Shaper::VAlign::kTop;
Shaper::ResizePolicy fResize = Shaper::ResizePolicy::kNone;
Shaper::LinebreakPolicy fLineBreak = Shaper::LinebreakPolicy::kExplicit;
Shaper::Direction fDirection = Shaper::Direction::kLTR;
SkRect fBox = SkRect::MakeEmpty();
SkColor fFillColor = SK_ColorTRANSPARENT,
fStrokeColor = SK_ColorTRANSPARENT;
TextPaintOrder fPaintOrder = TextPaintOrder::kFillStroke;
bool fHasFill = false,
fHasStroke = false;
float fTextSize = 0,
fMinTextSize = 0, // when auto-sizing
fMaxTextSize = std::numeric_limits<float>::max(), // when auto-sizing
fStrokeWidth = 0,
fLineHeight = 0,
fLineShift = 0,
fAscent = 0;
SkTextUtils::Align fHAlign = SkTextUtils::kLeft_Align;
Shaper::VAlign fVAlign = Shaper::VAlign::kTop;
Shaper::ResizePolicy fResize = Shaper::ResizePolicy::kNone;
Shaper::LinebreakPolicy fLineBreak = Shaper::LinebreakPolicy::kExplicit;
Shaper::Direction fDirection = Shaper::Direction::kLTR;
Shaper::Capitalization fCapitalization = Shaper::Capitalization::kNone;
SkRect fBox = SkRect::MakeEmpty();
SkColor fFillColor = SK_ColorTRANSPARENT,
fStrokeColor = SK_ColorTRANSPARENT;
TextPaintOrder fPaintOrder = TextPaintOrder::kFillStroke;
bool fHasFill = false,
fHasStroke = false;
bool operator==(const TextPropertyValue& other) const;
bool operator!=(const TextPropertyValue& other) const;

View File

@ -27,6 +27,7 @@ bool TextPropertyValue::operator==(const TextPropertyValue& other) const {
&& fResize == other.fResize
&& fLineBreak == other.fLineBreak
&& fDirection == other.fDirection
&& fCapitalization == other.fCapitalization
&& fBox == other.fBox
&& fFillColor == other.fFillColor
&& fStrokeColor == other.fStrokeColor

View File

@ -326,6 +326,7 @@ DEF_TEST(Skottie_Properties, reporter) {
Shaper::ResizePolicy::kNone,
Shaper::LinebreakPolicy::kExplicit,
Shaper::Direction::kLTR,
Shaper::Capitalization::kNone,
SkRect::MakeEmpty(),
SK_ColorTRANSPARENT,
SK_ColorTRANSPARENT,
@ -478,6 +479,7 @@ DEF_TEST(Skottie_Shaper_HAlign, reporter) {
Shaper::ResizePolicy::kNone,
Shaper::LinebreakPolicy::kExplicit,
Shaper::Direction::kLTR,
Shaper::Capitalization::kNone,
Shaper::Flags::kNone
};
@ -548,6 +550,7 @@ DEF_TEST(Skottie_Shaper_VAlign, reporter) {
Shaper::ResizePolicy::kNone,
Shaper::LinebreakPolicy::kParagraph,
Shaper::Direction::kLTR,
Shaper::Capitalization::kNone,
Shaper::Flags::kNone
};
@ -588,6 +591,7 @@ DEF_TEST(Skottie_Shaper_FragmentGlyphs, reporter) {
Shaper::ResizePolicy::kNone,
Shaper::LinebreakPolicy::kParagraph,
Shaper::Direction::kLTR,
Shaper::Capitalization::kNone,
Shaper::Flags::kNone
};
@ -680,6 +684,7 @@ DEF_TEST(Skottie_Shaper_ExplicitFontMgr, reporter) {
Shaper::ResizePolicy::kNone,
Shaper::LinebreakPolicy::kParagraph,
Shaper::Direction::kLTR,
Shaper::Capitalization::kNone,
Shaper::Flags::kNone
};

View File

@ -13,6 +13,7 @@
#include "include/private/SkTPin.h"
#include "include/private/SkTemplates.h"
#include "modules/skshaper/include/SkShaper.h"
#include "modules/skunicode/include/SkUnicode.h"
#include "src/core/SkTLazy.h"
#include "src/core/SkTextBlobPriv.h"
#include "src/utils/SkUTF.h"
@ -446,18 +447,47 @@ Shaper::Result ShapeToFit(const SkString& txt, const Shaper::TextDesc& orig_desc
return best_result;
}
// Applies capitalization rules.
class AdjustedText {
public:
AdjustedText(const SkString& txt, const Shaper::TextDesc& desc)
: fText(txt) {
switch (desc.fCapitalization) {
case Shaper::Capitalization::kNone:
break;
case Shaper::Capitalization::kUpperCase:
#ifdef SK_UNICODE_AVAILABLE
if (auto skuni = SkUnicode::Make()) {
*fText.writable() = skuni->toUpper(*fText);
}
#endif
break;
}
}
operator const SkString&() const { return *fText; }
private:
SkTCopyOnFirstWrite<SkString> fText;
};
} // namespace
Shaper::Result Shaper::Shape(const SkString& txt, const TextDesc& desc, const SkPoint& point,
Shaper::Result Shaper::Shape(const SkString& orig_txt, const TextDesc& desc, const SkPoint& point,
const sk_sp<SkFontMgr>& fontmgr) {
const AdjustedText txt(orig_txt, desc);
return (desc.fResize == ResizePolicy::kScaleToFit ||
desc.fResize == ResizePolicy::kDownscaleToFit) // makes no sense in point mode
? Result()
: ShapeImpl(txt, desc, SkRect::MakeEmpty().makeOffset(point.x(), point.y()), fontmgr);
}
Shaper::Result Shaper::Shape(const SkString& txt, const TextDesc& desc, const SkRect& box,
Shaper::Result Shaper::Shape(const SkString& orig_txt, const TextDesc& desc, const SkRect& box,
const sk_sp<SkFontMgr>& fontmgr) {
const AdjustedText txt(orig_txt, desc);
switch(desc.fResize) {
case ResizePolicy::kNone:
return ShapeImpl(txt, desc, box, fontmgr);

View File

@ -86,6 +86,11 @@ public:
// Initial text direction.
enum class Direction : uint8_t { kLTR, kRTL };
enum class Capitalization {
kNone,
kUpperCase,
};
enum Flags : uint32_t {
kNone = 0x00,
@ -110,6 +115,7 @@ public:
ResizePolicy fResize;
LinebreakPolicy fLinebreak;
Direction fDirection;
Capitalization fCapitalization;
uint32_t fFlags;
};

View File

@ -279,6 +279,7 @@ void TextAdapter::reshape() {
fText->fResize,
fText->fLineBreak,
fText->fDirection,
fText->fCapitalization,
this->shaperFlags(),
};
const auto shape_result = Shaper::Shape(fText->fText, text_desc, fText->fBox, fFontMgr);

View File

@ -46,7 +46,7 @@ bool Parse(const skjson::Value& jv, const internal::AnimationBuilder& abuilder,
SkTextUtils::kCenter_Align // 'j': 2
};
v->fHAlign = gAlignMap[std::min<size_t>(ParseDefault<size_t>((*jtxt)["j"], 0),
SK_ARRAY_COUNT(gAlignMap))];
SK_ARRAY_COUNT(gAlignMap) - 1)];
// Optional text box size.
if (const skjson::ArrayValue* jsz = (*jtxt)["sz"]) {
@ -72,7 +72,7 @@ bool Parse(const skjson::Value& jv, const internal::AnimationBuilder& abuilder,
// TODO: remove "sk_rs" support after migrating clients.
v->fResize = gResizeMap[std::min(std::max(ParseDefault<size_t>((*jtxt)[ "rs"], 0),
ParseDefault<size_t>((*jtxt)["sk_rs"], 0)),
SK_ARRAY_COUNT(gResizeMap))];
SK_ARRAY_COUNT(gResizeMap) - 1)];
// Optional min/max font size (used when aute-resizing)
v->fMinTextSize = ParseDefault<SkScalar>((*jtxt)["mf"], 0.0f);
@ -93,6 +93,14 @@ bool Parse(const skjson::Value& jv, const internal::AnimationBuilder& abuilder,
: Shaper::LinebreakPolicy::kParagraph; // 'm': 1 -> paragraph text
}
// Optional capitalization.
static constexpr Shaper::Capitalization gCapMap[] = {
Shaper::Capitalization::kNone, // 'ca': 0
Shaper::Capitalization::kUpperCase, // 'ca': 1
};
v->fCapitalization = gCapMap[std::min<size_t>(ParseDefault<size_t>((*jtxt)["ca"], 0),
SK_ARRAY_COUNT(gCapMap) - 1)];
// In point mode, the text is baseline-aligned.
v->fVAlign = v->fBox.isEmpty() ? Shaper::VAlign::kTopBaseline
: Shaper::VAlign::kTop;

View File

@ -116,6 +116,7 @@ class SKUNICODE_API SkUnicode {
virtual bool isWhitespace(SkUnichar utf8) = 0;
virtual bool isSpace(SkUnichar utf8) = 0;
virtual SkString convertUtf16ToUtf8(const std::u16string& utf16) = 0;
virtual SkString toUpper(const SkString&) = 0;
// Methods used in SkShaper and SkText
virtual std::unique_ptr<SkBidiIterator> makeBidiIterator

View File

@ -498,6 +498,37 @@ public:
}
}
SkString toUpper(const SkString& str) override {
// Convert to UTF16 since that's what ICU wants.
std::unique_ptr<uint16_t[]> str16;
const auto str16len = utf8ToUtf16(str.c_str(), str.size(), &str16);
if (str16len <= 0) {
return SkString();
}
UErrorCode icu_err = U_ZERO_ERROR;
const auto upper16len = sk_u_strToUpper(nullptr, 0, (UChar*)(str16.get()), str16len,
nullptr, &icu_err);
if (icu_err != U_BUFFER_OVERFLOW_ERROR || upper16len <= 0) {
return SkString();
}
SkAutoSTArray<128, uint16_t> upper16(upper16len);
icu_err = U_ZERO_ERROR;
sk_u_strToUpper((UChar*)(upper16.get()), SkToS32(upper16.size()),
(UChar*)(str16.get()), str16len,
nullptr, &icu_err);
SkASSERT(!U_FAILURE(icu_err));
// ... and back to utf8 'cause that's what we want.
std::unique_ptr<char[]> upper8;
auto upper8len = utf16ToUtf8(upper16.data(), upper16.size(), &upper8);
return upper8len >= 0
? SkString(upper8.get(), upper8len)
: SkString();
}
bool getBidiRegions(const char utf8[],
int utf8Units,
TextDirection dir,

View File

@ -22,6 +22,7 @@
SKICU_FUNC(u_iscntrl) \
SKICU_FUNC(u_isspace) \
SKICU_FUNC(u_isWhitespace) \
SKICU_FUNC(u_strToUpper) \
SKICU_FUNC(ubidi_close) \
SKICU_FUNC(ubidi_getLength) \
SKICU_FUNC(ubidi_getLevelAt) \

View File

@ -0,0 +1 @@
{"assets":[],"ddd":0,"fonts":{"list":[{"ascent":71.5988159179688,"fClass":"","fFamily":"Arial","fName":"ArialMT","fPath":"","fStyle":"Regular","fWeight":"","origin":0}]},"fr":60,"h":500,"ip":0,"layers":[{"ao":0,"bm":0,"ddd":0,"ind":1,"ip":0,"ks":{"a":{"a":0,"ix":1,"k":[0,0,0],"l":2},"o":{"a":0,"ix":11,"k":100},"p":{"a":0,"ix":2,"k":[245,226.5,0],"l":2},"r":{"a":0,"ix":10,"k":0},"s":{"a":0,"ix":6,"k":[100,100,100],"l":2}},"nm":"Foo Bar - allcaps","op":600,"sr":1,"st":0,"t":{"a":[],"d":{"k":[{"s":{"ca":0,"f":"ArialMT","fc":[0.706,0,1],"j":2,"lh":75.6,"ls":0,"mc":100,"mf":10,"ps":[-164,-141.5],"rs":1,"s":63,"sz":[354,335],"t":"Hello there, κεφαλαίο κείμενο!","tr":0,"vj":1,"xf":100},"t":0},{"s":{"ca":1,"f":"ArialMT","fc":[0.706,0,1],"j":2,"lh":75.6,"ls":0,"mc":100,"mf":10,"ps":[-164,-141.5],"rs":1,"s":63,"sz":[354,335],"t":"Hello there, κεφαλαίο κείμενο!","tr":0,"vj":1,"xf":100},"t":150},{"s":{"ca":0,"f":"ArialMT","fc":[0.706,0,1],"j":2,"lh":75.6,"ls":0,"mc":100,"mf":10,"ps":[-164,-141.5],"rs":1,"s":63,"sz":[354,335],"t":"Hello there, κεφαλαίο κείμενο!","tr":0,"vj":1,"xf":100},"t":300},{"s":{"ca":1,"f":"ArialMT","fc":[0.706,0,1],"j":2,"lh":75.6,"ls":0,"mc":100,"mf":10,"ps":[-164,-141.5],"rs":1,"s":63,"sz":[354,335],"t":"Hello there, κεφαλαίο κείμενο!","tr":0,"vj":1,"xf":100},"t":450}]},"m":{"a":{"a":0,"ix":2,"k":[0,0]},"g":1},"p":{}},"ty":5}],"markers":[],"nm":"allcaps","op":600,"v":"5.7.11","w":500}