Make SkShaper more modular
Skottie depends on SkShaper::Make() and SkUnicode::Make(), which
rely on compile-time defines that do not play well with the modular
build. While we could get around this by making "skottie_harfbuzz_icu"
and "skottie_coretext" targets, this is a bit awkward in more complex
builds, and for clients that don't directly need to do text shaping
(or are fine with the smaller, primitive shaper).
While this CL does not remove the compile-time configuration of
Skottie, it does lay the groundwork for that by adding some
new headers and APIs for SkShaper to make a specific backend.
I put these in a namespace SkShapers and then added some nested
namespaces (HB, CT) since that made the names read nicer IMO.
While we could probably have a "core" SkShaper and break primitive
stuff out into its own header, I think for simplicity it is fine
to have primitive be a part of "core".
The following SkShaper functions have been moved or deprecated:
- SkShaper::MakePrimitive() -> SkShapers::Primitive()
- SkShaper::MakeShaperDrivenWrapper() -> SkShapers::HB::ShaperDrivenWrapper()
- SkShaper::MakeShapeThenWrap() -> SkShapers::HB::ShapeThenWrap()
- SkShaper::MakeShapeDontWrapOrReorder() -> SkShapers::HB::ShapeDontWrapOrReorder()
- SkShaper::MakeCoreText() -> SkShapers::CT::CoreText()
- SkShaper::Make() -> deleted, use one of the above directly,
- SkShaper::MakeSkUnicodeBidiRunIterator() -> SkShapers::unicode::BidiRunIterator()
- SkShaper::MakeBiDiRunIterator() -> deleted, use SkShapers::unicode::BidiRunIterator() or SkShapers::TrivialBiDiRunIterator()
- SkShaper::MakeIcuBiDiRunIterator() -> deleted, use SkShapers::unicode::BidiRunIterator()
- SkShaper::MakeSkUnicodeHbScriptRunIterator() -> SkShapers::HB::ScriptRunIterator()
- SkShaper::MakeHbIcuScriptRunIterator() -> SkShapers::HB::ScriptRunIterator()
- SkShaper::MakeScriptRunIterator() -> deleted, use SkShapers::HB::ScriptRunIterator() or SkShapers::TrivialScriptRunIterator
This also updates our internal callsites to use the new APIs
(the old ones can be disabled by a flag), some of which also need
#ifdefs (not quite sure if modules/svg should always be using
HarfBuzz or if it also needs to have a registration something).
A follow-up CL will try to remove the #ifdefs from skottie/TextShaper
by adding a codec-like registration or something similar. Another
follow-up CL will decouple SkUnicode in a similar way.
Change-Id: I791b8382817e3b7c2c7fb54c6e4a9b432c9d4f9d
Bug: b/40045064
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/817199
Reviewed-by: Florin Malita <fmalita@google.com>
Commit-Queue: Kevin Lubick <kjlubick@google.com>
diff --git a/BUILD.bazel b/BUILD.bazel
index 37124bf..bbc0967 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -206,6 +206,33 @@
###
alias(
+ name = "skshaper_core",
+ actual = "//modules/skshaper:skshaper_core",
+ visibility = ["//visibility:public"],
+)
+
+# TODO(kjlubick)
+# alias(
+# name = "skshaper_coretext",
+# actual = "//modules/skshaper:skshaper_coretext",
+# visibility = ["//visibility:public"],
+# )
+
+alias(
+ name = "skshaper_harfbuzz",
+ actual = "//modules/skshaper:skshaper_harfbuzz",
+ visibility = ["//visibility:public"],
+)
+
+alias(
+ name = "skshaper_unicode",
+ actual = "//modules/skshaper:skshaper_unicode",
+ visibility = ["//visibility:public"],
+)
+
+###
+
+alias(
name = "skresources",
actual = "//modules/skresources:skresources",
visibility = ["//visibility:public"],
diff --git a/modules/skottie/BUILD.bazel b/modules/skottie/BUILD.bazel
index 3bd9eed..3920fbb 100644
--- a/modules/skottie/BUILD.bazel
+++ b/modules/skottie/BUILD.bazel
@@ -118,6 +118,28 @@
)
skia_cc_library(
+ name = "skottie",
+ srcs = [
+ "//modules/skottie/src:srcs",
+ "//src/utils:json_hdrs",
+ "//src/utils:json_srcs",
+ ],
+ hdrs = ["//modules/skottie/include:hdrs"],
+ features = ["layering_check"],
+ visibility = ["//:__subpackages__"],
+ deps = [
+ ":textshaper",
+ "//:core",
+ "//modules/skresources",
+ "//modules/sksg",
+ "//modules/sksg:sksg_priv",
+ "//src/base",
+ "//src/codec:codec_support_priv",
+ "//src/core:core_priv",
+ ],
+)
+
+skia_cc_library(
name = "utils",
srcs = ["//modules/skottie/utils:srcs"],
hdrs = ["//modules/skottie/utils:hdrs"],
@@ -139,9 +161,25 @@
visibility = ["//:__subpackages__"],
deps = [
"//:core",
- "//modules/skshaper:skshaper_harfbuzz",
+ "//:skshaper_harfbuzz",
+ "//:skshaper_unicode",
"//modules/skunicode:skunicode_icu",
"//src/base",
"//src/core:core_priv",
],
)
+
+skia_cc_library(
+ name = "textshaper",
+ srcs = ["//modules/skottie/src/text:text_shaper_srcs"],
+ hdrs = ["//modules/skottie/include:text_shaper_hdrs"],
+ features = ["layering_check"],
+ visibility = ["//:__subpackages__"],
+ deps = [
+ "//:core",
+ "//src/base",
+ "//src/core:core_priv",
+ "//:skshaper_core",
+ # TODO(kjlubick) make this depend on skunicode_core
+ ],
+)
diff --git a/modules/skottie/src/layers/TextLayer.cpp b/modules/skottie/src/layers/TextLayer.cpp
index bcfbd9a..f325501 100644
--- a/modules/skottie/src/layers/TextLayer.cpp
+++ b/modules/skottie/src/layers/TextLayer.cpp
@@ -309,7 +309,7 @@
}
// Final pass to commit custom typefaces.
- auto has_unresolved = false;
+ bool has_unresolved = false;
std::vector<std::unique_ptr<CustomFont>> custom_fonts;
fFonts.foreach([&has_unresolved, &custom_fonts](const SkString&, FontInfo* finfo) {
if (finfo->fTypeface) {
diff --git a/modules/skottie/src/text/TextShaper.cpp b/modules/skottie/src/text/TextShaper.cpp
index db3f19c..800df3c 100644
--- a/modules/skottie/src/text/TextShaper.cpp
+++ b/modules/skottie/src/text/TextShaper.cpp
@@ -25,8 +25,19 @@
#include "src/base/SkUTF.h"
#include "src/core/SkFontPriv.h"
-#ifdef SK_UNICODE_AVAILABLE
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
+#include "modules/skshaper/include/SkShaper_harfbuzz.h"
+#include "modules/skshaper/include/SkShaper_skunicode.h"
+#endif
+
+#if defined(SK_UNICODE_AVAILABLE)
#include "modules/skunicode/include/SkUnicode.h"
+#else
+class SkUnicode;
+#endif
+
+#if defined(SK_SHAPER_CORETEXT_AVAILABLE)
+#include "modules/skshaper/include/SkShaper_coretext.h"
#endif
#include <algorithm>
@@ -47,17 +58,53 @@
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
}
+// TODO(kjlubick,fmalita) Remove these defines by having clients register something or somehow
+// plumbing this all into the animation builder factories.
+static SkUnicode* get_unicode() {
+#if defined(SK_UNICODE_AVAILABLE) && defined(SK_UNICODE_ICU_IMPLEMENTATION)
+ static SkUnicode* icu_unicode = SkUnicode::MakeIcuBasedUnicode().release();
+ if (icu_unicode != nullptr) {
+ return icu_unicode;
+ }
+#endif
+#if defined(SK_UNICODE_AVAILABLE) && defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION)
+ static SkUnicode* grapheme_unicode = SkUnicode::MakeLibgraphemeBasedUnicode().release();
+ if (grapheme_unicode != nullptr) {
+ return grapheme_unicode;
+ }
+#endif
+ return nullptr;
+}
+
+static std::unique_ptr<SkShaper> get_shaper(sk_sp<SkFontMgr> fallback) {
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
+ auto unicode = get_unicode();
+ if (!unicode) {
+ return SkShapers::Primitive();
+ }
+ if (auto shaper = SkShapers::HB::ShaperDrivenWrapper(unicode->copy(), std::move(fallback))) {
+ return shaper;
+ }
+#endif
+#if defined(SK_SHAPER_CORETEXT_AVAILABLE)
+ if (auto shaper = SkShapers::CT::CoreText()) {
+ return shaper;
+ }
+#endif
+ return SkShapers::Primitive();
+}
+
// Helper for interfacing with SkShaper: buffers shaper-fed runs and performs
// per-line position adjustments (for external line breaking, horizontal alignment, etc).
class ResultBuilder final : public SkShaper::RunHandler {
public:
ResultBuilder(const Shaper::TextDesc& desc, const SkRect& box, const sk_sp<SkFontMgr>& fontmgr)
- : fDesc(desc)
- , fBox(box)
- , fHAlignFactor(HAlignFactor(fDesc.fHAlign))
- , fFont(fDesc.fTypeface, fDesc.fTextSize)
- , fFontMgr(fontmgr)
- , fShaper(SkShaper::Make(fontmgr)) {
+ : fDesc(desc)
+ , fBox(box)
+ , fHAlignFactor(HAlignFactor(fDesc.fHAlign))
+ , fFont(fDesc.fTypeface, fDesc.fTextSize)
+ , fFontMgr(fontmgr)
+ , fShaper(get_shaper(fontmgr)) {
fFont.setHinting(SkFontHinting::kNone);
fFont.setSubpixel(true);
fFont.setLinearMetrics(true);
@@ -339,10 +386,27 @@
fFont.getTypeface()->fontStyle(),
lang_iter.get());
#endif
- const auto bidi_iter = SkShaper::MakeBiDiRunIterator(start, utf8_bytes,
- shape_ltr ? kBidiLevelLTR : kBidiLevelRTL);
- const auto scpt_iter = SkShaper::MakeScriptRunIterator(start, utf8_bytes,
- SkSetFourByteTag('Z', 'z', 'z', 'z'));
+
+ [[maybe_unused]] SkUnicode* unicode = get_unicode();
+ std::unique_ptr<SkShaper::BiDiRunIterator> bidi_iter = nullptr;
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
+ bidi_iter = SkShapers::unicode::BidiRunIterator(
+ unicode, start, utf8_bytes, shape_ltr ? kBidiLevelLTR : kBidiLevelRTL);
+#endif
+ if (!bidi_iter) {
+ bidi_iter = std::make_unique<SkShaper::TrivialBiDiRunIterator>(
+ shape_ltr ? kBidiLevelLTR : kBidiLevelRTL, utf8_bytes);
+ }
+
+ std::unique_ptr<SkShaper::ScriptRunIterator> scpt_iter = nullptr;
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
+ scpt_iter = SkShapers::HB::ScriptRunIterator(
+ start, utf8_bytes, SkSetFourByteTag('Z', 'z', 'z', 'z'));
+#endif
+ if (!scpt_iter) {
+ scpt_iter = std::make_unique<SkShaper::TrivialScriptRunIterator>(
+ utf8_bytes, SkSetFourByteTag('Z', 'z', 'z', 'z'));
+ }
if (!font_iter || !bidi_iter || !scpt_iter || !lang_iter) {
return;
@@ -350,12 +414,16 @@
fUTF8 = start;
fUTF8Offset = utf8_offset;
- fShaper->shape(start, utf8_bytes,
+ fShaper->shape(start,
+ utf8_bytes,
*font_iter,
*bidi_iter,
*scpt_iter,
*lang_iter,
- shape_width, this);
+ nullptr,
+ 0,
+ shape_width,
+ this);
fUTF8 = nullptr;
}
@@ -597,8 +665,8 @@
case Shaper::Capitalization::kNone:
break;
case Shaper::Capitalization::kUpperCase:
-#ifdef SK_UNICODE_AVAILABLE
- if (auto skuni = SkUnicode::Make()) {
+#if defined(SK_UNICODE_AVAILABLE)
+ if (auto skuni = get_unicode()) {
*fText.writable() = skuni->toUpper(*fText);
}
#endif
diff --git a/modules/skottie/tests/Shaper.cpp b/modules/skottie/tests/Shaper.cpp
index 56eced9..4328d09 100644
--- a/modules/skottie/tests/Shaper.cpp
+++ b/modules/skottie/tests/Shaper.cpp
@@ -236,6 +236,7 @@
const auto shape_result = Shaper::Shape(text, desc, text_box, ToolUtils::TestFontMgr());
// Default/consolidated mode => single blob result.
REPORTER_ASSERT(reporter, shape_result.fFragments.size() == 1ul);
+ SkASSERT(!shape_result.fFragments.empty());
REPORTER_ASSERT(reporter, !shape_result.fFragments[0].fGlyphs.fRuns.empty());
}
@@ -246,6 +247,7 @@
// Fragmented mode => one blob per glyph.
const size_t expectedSize = text.size();
REPORTER_ASSERT(reporter, shape_result.fFragments.size() == expectedSize);
+ SkASSERT(!shape_result.fFragments.empty());
for (size_t i = 0; i < expectedSize; ++i) {
REPORTER_ASSERT(reporter, !shape_result.fFragments[i].fGlyphs.fRuns.empty());
}
diff --git a/modules/skparagraph/src/FontCollection.cpp b/modules/skparagraph/src/FontCollection.cpp
index df69143..2458ab5 100644
--- a/modules/skparagraph/src/FontCollection.cpp
+++ b/modules/skparagraph/src/FontCollection.cpp
@@ -1,9 +1,10 @@
// Copyright 2019 Google LLC.
-#include "include/core/SkTypeface.h"
#include "modules/skparagraph/include/FontCollection.h"
+
+#include "include/core/SkTypeface.h"
#include "modules/skparagraph/include/Paragraph.h"
#include "modules/skparagraph/src/ParagraphImpl.h"
-#include "modules/skshaper/include/SkShaper.h"
+#include "modules/skshaper/include/SkShaper_harfbuzz.h"
namespace {
#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
@@ -220,7 +221,7 @@
void FontCollection::clearCaches() {
fParagraphCache.reset();
fTypefaces.reset();
- SkShaper::PurgeCaches();
+ SkShapers::HB::PurgeCaches();
}
} // namespace textlayout
diff --git a/modules/skparagraph/src/OneLineShaper.cpp b/modules/skparagraph/src/OneLineShaper.cpp
index 9098ee9..50e4479 100644
--- a/modules/skparagraph/src/OneLineShaper.cpp
+++ b/modules/skparagraph/src/OneLineShaper.cpp
@@ -1,7 +1,8 @@
// Copyright 2019 Google LLC.
+#include "modules/skparagraph/src/OneLineShaper.h"
#include "modules/skparagraph/src/Iterators.h"
-#include "modules/skparagraph/src/OneLineShaper.h"
+#include "modules/skshaper/include/SkShaper_harfbuzz.h"
#include "src/base/SkUTF.h"
#include <algorithm>
@@ -624,8 +625,8 @@
(TextRange textRange, SkSpan<Block> styleSpan, SkScalar& advanceX, TextIndex textStart, uint8_t defaultBidiLevel) {
// Set up the shaper and shape the next
- auto shaper = SkShaper::MakeShapeDontWrapOrReorder(fParagraph->fUnicode->copy(),
- SkFontMgr::RefEmpty()); // no fallback
+ auto shaper = SkShapers::HB::ShapeDontWrapOrReorder(fParagraph->fUnicode->copy(),
+ SkFontMgr::RefEmpty()); // no fallback
if (shaper == nullptr) {
// For instance, loadICU does not work. We have to stop the process
return false;
@@ -681,8 +682,8 @@
LangIterator langIter(unresolvedText, blockSpan,
fParagraph->paragraphStyle().getTextStyle());
SkShaper::TrivialBiDiRunIterator bidiIter(defaultBidiLevel, unresolvedText.size());
- auto scriptIter = SkShaper::MakeSkUnicodeHbScriptRunIterator(
- unresolvedText.begin(), unresolvedText.size());
+ auto scriptIter = SkShapers::HB::ScriptRunIterator(unresolvedText.begin(),
+ unresolvedText.size());
fCurrentText = unresolvedRange;
// Map the block's features to subranges within the unresolved range.
diff --git a/modules/skparagraph/src/TextLine.cpp b/modules/skparagraph/src/TextLine.cpp
index 0668454..511899b 100644
--- a/modules/skparagraph/src/TextLine.cpp
+++ b/modules/skparagraph/src/TextLine.cpp
@@ -1,5 +1,7 @@
// Copyright 2019 Google LLC.
+#include "modules/skparagraph/src/TextLine.h"
+
#include "include/core/SkBlurTypes.h"
#include "include/core/SkFont.h"
#include "include/core/SkFontMetrics.h"
@@ -20,8 +22,9 @@
#include "modules/skparagraph/src/Decorations.h"
#include "modules/skparagraph/src/ParagraphImpl.h"
#include "modules/skparagraph/src/ParagraphPainterImpl.h"
-#include "modules/skparagraph/src/TextLine.h"
#include "modules/skshaper/include/SkShaper.h"
+#include "modules/skshaper/include/SkShaper_harfbuzz.h"
+#include "modules/skshaper/include/SkShaper_skunicode.h"
#include <algorithm>
#include <iterator>
@@ -685,13 +688,37 @@
font.setHinting(SkFontHinting::kSlight);
font.setSubpixel(true);
- std::unique_ptr<SkShaper> shaper = SkShaper::MakeShapeDontWrapOrReorder(
- fOwner->getUnicode()->copy(),
- fallback ? fallback : SkFontMgr::RefEmpty());
- shaper->shape(ellipsis.c_str(),
- ellipsis.size(),
- font,
- true,
+ std::unique_ptr<SkShaper> shaper = SkShapers::HB::ShapeDontWrapOrReorder(
+ fOwner->getUnicode()->copy(), fallback ? fallback : SkFontMgr::RefEmpty());
+
+ const SkBidiIterator::Level defaultLevel = SkBidiIterator::kLTR;
+ const char* utf8 = ellipsis.c_str();
+ size_t utf8Bytes = ellipsis.size();
+
+ std::unique_ptr<SkShaper::BiDiRunIterator> bidi = SkShapers::unicode::BidiRunIterator(
+ fOwner->getUnicode(), utf8, utf8Bytes, defaultLevel);
+ SkASSERT(bidi);
+
+ std::unique_ptr<SkShaper::LanguageRunIterator> language =
+ SkShaper::MakeStdLanguageRunIterator(utf8, utf8Bytes);
+ SkASSERT(language);
+
+ std::unique_ptr<SkShaper::ScriptRunIterator> script =
+ SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes);
+ SkASSERT(script);
+
+ std::unique_ptr<SkShaper::FontRunIterator> fontRuns =
+ SkShaper::MakeFontMgrRunIterator(utf8, utf8Bytes, font, fallback);
+ SkASSERT(fontRuns);
+
+ shaper->shape(utf8,
+ utf8Bytes,
+ *fontRuns,
+ *bidi,
+ *script,
+ *language,
+ nullptr,
+ 0,
std::numeric_limits<SkScalar>::max(),
&handler);
auto ellipsisRun = handler.run();
diff --git a/modules/skplaintexteditor/src/shape.cpp b/modules/skplaintexteditor/src/shape.cpp
index 9802ac8..f22a9f0 100644
--- a/modules/skplaintexteditor/src/shape.cpp
+++ b/modules/skplaintexteditor/src/shape.cpp
@@ -18,6 +18,12 @@
#include "src/base/SkUTF.h"
#include "src/core/SkTextBlobPriv.h"
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
+#include "modules/skshaper/include/SkShaper_harfbuzz.h"
+#include "modules/skshaper/include/SkShaper_skunicode.h"
+#include "modules/skunicode/include/SkUnicode.h"
+#endif
+
#include <cfloat>
#include <climits>
#include <cstring>
@@ -270,7 +276,15 @@
utf8Text = nullptr;
textByteLen = 0;
}
- std::unique_ptr<SkShaper> shaper = SkShaper::Make(fontMgr);
+ std::unique_ptr<SkShaper> shaper = nullptr;
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
+ auto unicode = SkUnicode::Make();
+ shaper = SkShapers::HB::ShaperDrivenWrapper(std::move(unicode), fontMgr);
+#else
+ shaper = SkShapers::Primitive();
+#endif
+ SkASSERT(shaper);
+
float height = font.getSpacing();
RunHandler runHandler(utf8Text, textByteLen);
if (textByteLen) {
@@ -279,8 +293,41 @@
c = SkRect{-FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX};
}
runHandler.setRunCallback(set_character_bounds, result.glyphBounds.data());
- // TODO: make use of locale in shaping.
- shaper->shape(utf8Text, textByteLen, font, true, width, &runHandler);
+
+ static constexpr uint8_t kBidiLevelLTR = 0;
+ std::unique_ptr<SkShaper::BiDiRunIterator> bidi = nullptr;
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
+ auto unicode2 = SkUnicode::Make();
+ bidi = SkShapers::unicode::BidiRunIterator(
+ unicode2.get(), utf8Text, textByteLen, kBidiLevelLTR);
+#endif
+ if (!bidi) {
+ bidi = std::make_unique<SkShaper::TrivialBiDiRunIterator>(kBidiLevelLTR, textByteLen);
+ }
+ SkASSERT(bidi);
+
+ std::unique_ptr<SkShaper::LanguageRunIterator> language =
+ SkShaper::MakeStdLanguageRunIterator(utf8Text, textByteLen);
+ SkASSERT(language);
+
+ std::unique_ptr<SkShaper::ScriptRunIterator> script =
+ SkShapers::HB::ScriptRunIterator(utf8Text, textByteLen);
+ SkASSERT(script);
+
+ std::unique_ptr<SkShaper::FontRunIterator> fontRuns =
+ SkShaper::MakeFontMgrRunIterator(utf8Text, textByteLen, font, fontMgr);
+ SkASSERT(fontRuns);
+
+ shaper->shape(utf8Text,
+ textByteLen,
+ *fontRuns,
+ *bidi,
+ *script,
+ *language,
+ nullptr,
+ 0,
+ width,
+ &runHandler);
if (runHandler.lineEndOffsets().size() > 1) {
result.lineBreakOffsets = runHandler.lineEndOffsets();
SkASSERT(result.lineBreakOffsets.size() > 0);
diff --git a/modules/skshaper/BUILD.bazel b/modules/skshaper/BUILD.bazel
index 93087f0..e2abfb6 100644
--- a/modules/skshaper/BUILD.bazel
+++ b/modules/skshaper/BUILD.bazel
@@ -46,19 +46,13 @@
}),
)
-# TODO(kjlubick,bungeman) break this up such that a client could have one or more
-# non-conflicting skshaper targets (e.g. move core_srcs to a central cc_library)
skia_cc_library(
- name = "skshaper_harfbuzz",
+ name = "skshaper_core",
srcs = [
"//modules/skshaper/src:core_srcs",
- "//modules/skshaper/src:harfbuzz_srcs",
],
- hdrs = ["//modules/skshaper/include:hdrs"],
- defines = [
- "SK_SHAPER_UNICODE_AVAILABLE",
- "SK_SHAPER_HARFBUZZ_AVAILABLE",
- ],
+ hdrs = ["//modules/skshaper/include:core_hdrs"],
+ defines = ["SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS"],
features = ["layering_check"],
local_defines = ["SKSHAPER_IMPLEMENTATION=1"],
visibility = [
@@ -66,9 +60,62 @@
],
deps = [
"//:core",
- "//modules/skunicode:skunicode_icu",
+ "//src/base",
+ "//src/core:core_priv",
+ ],
+)
+
+skia_cc_library(
+ name = "skshaper_harfbuzz",
+ srcs = [
+ "//modules/skshaper/src:harfbuzz_srcs",
+ ],
+ hdrs = [
+ "//modules/skshaper/include:core_hdrs",
+ "//modules/skshaper/include:harfbuzz_hdrs",
+ ],
+ defines = [
+ "SK_SHAPER_HARFBUZZ_AVAILABLE",
+ "SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS",
+ ],
+ features = ["layering_check"],
+ local_defines = ["SKSHAPER_IMPLEMENTATION=1"],
+ visibility = [
+ "//:__subpackages__",
+ ],
+ deps = [
+ ":skshaper_core",
+ "//:core",
+ "//modules/skunicode:skunicode_icu", # TODO(kjlubick) make this depend on skunicode_core
"//src/base",
"//src/core:core_priv",
"@harfbuzz",
],
)
+
+skia_cc_library(
+ name = "skshaper_unicode",
+ srcs = [
+ "//modules/skshaper/src:skunicode_srcs",
+ ],
+ hdrs = [
+ "//modules/skshaper/include:core_hdrs",
+ "//modules/skshaper/include:skunicode_hdrs",
+ ],
+ defines = [
+ "SK_SHAPER_UNICODE_AVAILABLE",
+ "SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS",
+ ],
+ features = ["layering_check"],
+ local_defines = ["SKSHAPER_IMPLEMENTATION=1"],
+ visibility = [
+ "//:__subpackages__",
+ ],
+ deps = [
+ ":skshaper_core",
+ "//:core",
+ "//modules/skunicode:skunicode_icu", # TODO(kjlubick) make this depend on skunicode_core
+ "//src/base",
+ "//src/core:core_priv",
+ ],
+)
diff --git a/modules/skshaper/include/BUILD.bazel b/modules/skshaper/include/BUILD.bazel
index 9bce7f5..d64d1b2 100644
--- a/modules/skshaper/include/BUILD.bazel
+++ b/modules/skshaper/include/BUILD.bazel
@@ -8,6 +8,41 @@
name = "hdrs",
srcs = [
"SkShaper.h",
+ "SkShaper_harfbuzz.h",
+ "SkShaper_skunicode.h",
+ ],
+ visibility = ["//modules/skshaper:__pkg__"],
+)
+
+skia_filegroup(
+ name = "core_hdrs",
+ srcs = [
+ "SkShaper.h",
+ "SkShaper_harfbuzz.h",
+ ],
+ visibility = ["//modules/skshaper:__pkg__"],
+)
+
+skia_filegroup(
+ name = "coretext_hdrs",
+ srcs = [
+ "SkShaper_coretext.h",
+ ],
+ visibility = ["//modules/skshaper:__pkg__"],
+)
+
+skia_filegroup(
+ name = "harfbuzz_hdrs",
+ srcs = [
+ "SkShaper_harfbuzz.h",
+ ],
+ visibility = ["//modules/skshaper:__pkg__"],
+)
+
+skia_filegroup(
+ name = "skunicode_hdrs",
+ srcs = [
+ "SkShaper_skunicode.h",
],
visibility = ["//modules/skshaper:__pkg__"],
)
diff --git a/modules/skshaper/include/SkShaper.h b/modules/skshaper/include/SkShaper.h
index f80c675..f128b19 100644
--- a/modules/skshaper/include/SkShaper.h
+++ b/modules/skshaper/include/SkShaper.h
@@ -47,20 +47,24 @@
class SKSHAPER_API SkShaper {
public:
+#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
static std::unique_ptr<SkShaper> MakePrimitive();
- #ifdef SK_SHAPER_HARFBUZZ_AVAILABLE
+
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE)
static std::unique_ptr<SkShaper> MakeShaperDrivenWrapper(sk_sp<SkFontMgr> fallback);
static std::unique_ptr<SkShaper> MakeShapeThenWrap(sk_sp<SkFontMgr> fallback);
static std::unique_ptr<SkShaper> MakeShapeDontWrapOrReorder(std::unique_ptr<SkUnicode> unicode,
sk_sp<SkFontMgr> fallback);
static void PurgeHarfBuzzCache();
- #endif
- #ifdef SK_SHAPER_CORETEXT_AVAILABLE
+#endif
+
+#if defined(SK_SHAPER_CORETEXT_AVAILABLE)
static std::unique_ptr<SkShaper> MakeCoreText();
- #endif
+#endif
static std::unique_ptr<SkShaper> Make(sk_sp<SkFontMgr> fallback = nullptr);
static void PurgeCaches();
+#endif // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
SkShaper();
virtual ~SkShaper();
@@ -133,6 +137,7 @@
SkFont fFont;
};
+#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
static std::unique_ptr<BiDiRunIterator>
MakeBiDiRunIterator(const char* utf8, size_t utf8Bytes, uint8_t bidiLevel);
#if defined(SK_SHAPER_UNICODE_AVAILABLE)
@@ -140,7 +145,9 @@
MakeSkUnicodeBidiRunIterator(SkUnicode* unicode, const char* utf8, size_t utf8Bytes, uint8_t bidiLevel);
static std::unique_ptr<BiDiRunIterator>
MakeIcuBiDiRunIterator(const char* utf8, size_t utf8Bytes, uint8_t bidiLevel);
-#endif
+#endif // defined(SK_SHAPER_UNICODE_AVAILABLE)
+#endif // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
+
class TrivialBiDiRunIterator : public TrivialRunIterator<BiDiRunIterator> {
public:
TrivialBiDiRunIterator(uint8_t bidiLevel, size_t utf8Bytes)
@@ -150,6 +157,7 @@
uint8_t fBidiLevel;
};
+#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
static std::unique_ptr<ScriptRunIterator>
MakeScriptRunIterator(const char* utf8, size_t utf8Bytes, SkFourByteTag script);
#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE)
@@ -160,7 +168,9 @@
// Still used in some cases
static std::unique_ptr<ScriptRunIterator>
MakeHbIcuScriptRunIterator(const char* utf8, size_t utf8Bytes);
-#endif
+#endif // defined(SK_SHAPER_HARFBUZZ_AVAILABLE)
+#endif // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
+
class TrivialScriptRunIterator : public TrivialRunIterator<ScriptRunIterator> {
public:
TrivialScriptRunIterator(SkFourByteTag script, size_t utf8Bytes)
@@ -231,6 +241,7 @@
virtual void commitLine() = 0;
};
+#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
virtual void shape(const char* utf8, size_t utf8Bytes,
const SkFont& srcFont,
bool leftToRight,
@@ -244,13 +255,15 @@
LanguageRunIterator&,
SkScalar width,
RunHandler*) const = 0;
-
- virtual void shape(const char* utf8, size_t utf8Bytes,
+#endif
+ virtual void shape(const char* utf8,
+ size_t utf8Bytes,
FontRunIterator&,
BiDiRunIterator&,
ScriptRunIterator&,
LanguageRunIterator&,
- const Feature* features, size_t featuresSize,
+ const Feature* features,
+ size_t featuresSize,
SkScalar width,
RunHandler*) const = 0;
@@ -290,4 +303,14 @@
SkPoint fOffset;
};
+namespace SkShapers {
+SKSHAPER_API std::unique_ptr<SkShaper> Primitive();
+
+SKSHAPER_API std::unique_ptr<SkShaper::BiDiRunIterator> TrivialBiDiRunIterator(size_t utf8Bytes,
+ uint8_t bidiLevel);
+
+SKSHAPER_API std::unique_ptr<SkShaper::ScriptRunIterator> TrivialScriptRunIterator(
+ size_t utf8Bytes, SkFourByteTag scriptTag);
+} // namespace SkShapers
+
#endif // SkShaper_DEFINED
diff --git a/modules/skshaper/include/SkShaper_coretext.h b/modules/skshaper/include/SkShaper_coretext.h
new file mode 100644
index 0000000..d2e2fad
--- /dev/null
+++ b/modules/skshaper/include/SkShaper_coretext.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkShaper_coretext_DEFINED
+#define SkShaper_coretext_DEFINED
+
+#include "modules/skshaper/include/SkShaper.h"
+
+#include <memory>
+
+namespace SkShapers::CT {
+SKSHAPER_API std::unique_ptr<SkShaper> CoreText();
+}
+
+#endif
diff --git a/modules/skshaper/include/SkShaper_harfbuzz.h b/modules/skshaper/include/SkShaper_harfbuzz.h
new file mode 100644
index 0000000..67bfbef
--- /dev/null
+++ b/modules/skshaper/include/SkShaper_harfbuzz.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkShaper_harfbuzz_DEFINED
+#define SkShaper_harfbuzz_DEFINED
+
+#include "include/core/SkRefCnt.h"
+#include "include/core/SkTypes.h"
+#include "modules/skshaper/include/SkShaper.h"
+
+#include <cstddef>
+#include <memory>
+
+class SkFontMgr;
+class SkUnicode;
+
+namespace SkShapers::HB {
+SKSHAPER_API std::unique_ptr<SkShaper> ShaperDrivenWrapper(std::unique_ptr<SkUnicode> unicode,
+ sk_sp<SkFontMgr> fallback);
+SKSHAPER_API std::unique_ptr<SkShaper> ShapeThenWrap(std::unique_ptr<SkUnicode> unicode,
+ sk_sp<SkFontMgr> fallback);
+SKSHAPER_API std::unique_ptr<SkShaper> ShapeDontWrapOrReorder(std::unique_ptr<SkUnicode> unicode,
+ sk_sp<SkFontMgr> fallback);
+
+SKSHAPER_API std::unique_ptr<SkShaper::ScriptRunIterator> ScriptRunIterator(const char* utf8,
+ size_t utf8Bytes);
+SKSHAPER_API std::unique_ptr<SkShaper::ScriptRunIterator> ScriptRunIterator(const char* utf8,
+ size_t utf8Bytes,
+ SkFourByteTag script);
+
+SKSHAPER_API void PurgeCaches();
+} // namespace SkShapers::HB
+
+#endif
diff --git a/modules/skshaper/include/SkShaper_skunicode.h b/modules/skshaper/include/SkShaper_skunicode.h
new file mode 100644
index 0000000..35872e8
--- /dev/null
+++ b/modules/skshaper/include/SkShaper_skunicode.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkShaper_skunicode_DEFINED
+#define SkShaper_skunicode_DEFINED
+
+#include "modules/skshaper/include/SkShaper.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+
+class SkUnicode;
+
+namespace SkShapers::unicode {
+SKSHAPER_API std::unique_ptr<SkShaper::BiDiRunIterator> BidiRunIterator(SkUnicode* unicode,
+ const char* utf8,
+ size_t utf8Bytes,
+ uint8_t bidiLevel);
+
+} // namespace SkShapers::unicode
+
+#endif
diff --git a/modules/skshaper/skshaper.gni b/modules/skshaper/skshaper.gni
index 2aca6e9..6939c72 100644
--- a/modules/skshaper/skshaper.gni
+++ b/modules/skshaper/skshaper.gni
@@ -11,7 +11,11 @@
_modules = get_path_info("../../modules", "abspath")
# Generated by Bazel rule //modules/skshaper/include:hdrs
-skia_shaper_public = [ "$_modules/skshaper/include/SkShaper.h" ]
+skia_shaper_public = [
+ "$_modules/skshaper/include/SkShaper.h",
+ "$_modules/skshaper/include/SkShaper_harfbuzz.h",
+ "$_modules/skshaper/include/SkShaper_skunicode.h",
+]
# Generated by Bazel rule //modules/skshaper/src:base_srcs
skia_shaper_primitive_sources = [
diff --git a/modules/skshaper/src/BUILD.bazel b/modules/skshaper/src/BUILD.bazel
index 32bb633..8eba00e 100644
--- a/modules/skshaper/src/BUILD.bazel
+++ b/modules/skshaper/src/BUILD.bazel
@@ -15,6 +15,7 @@
skia_filegroup(
name = "skunicode_srcs",
srcs = ["SkShaper_skunicode.cpp"],
+ visibility = ["//modules/skshaper:__pkg__"],
)
# In own group for export to //modules/skshaper/skshaper.gni:skia_shaper_coretext_sources.
@@ -52,7 +53,7 @@
name = "core_srcs",
srcs = [
"SkShaper.cpp",
- "SkShaper_skunicode.cpp",
+ "SkShaper_primitive.cpp",
],
visibility = ["//modules/skshaper:__pkg__"],
)
diff --git a/modules/skshaper/src/SkShaper.cpp b/modules/skshaper/src/SkShaper.cpp
index 6e948c5..548c8a4 100644
--- a/modules/skshaper/src/SkShaper.cpp
+++ b/modules/skshaper/src/SkShaper.cpp
@@ -21,43 +21,51 @@
#include <string>
#include <utility>
-#ifdef SK_SHAPER_UNICODE_AVAILABLE
+#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
+#if defined(SK_SHAPER_UNICODE_AVAILABLE)
+#include "modules/skshaper/include/SkShaper_skunicode.h"
#include "modules/skunicode/include/SkUnicode.h"
#endif
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE)
+#include "modules/skshaper/include/SkShaper_harfbuzz.h"
+#endif
+
+#if defined(SK_SHAPER_CORETEXT_AVAILABLE)
+#include "modules/skshaper/include/SkShaper_coretext.h"
+#endif
+
+#endif // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
+
+#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
std::unique_ptr<SkShaper> SkShaper::Make(sk_sp<SkFontMgr> fallback) {
-#ifdef SK_SHAPER_HARFBUZZ_AVAILABLE
- std::unique_ptr<SkShaper> shaper = SkShaper::MakeShaperDrivenWrapper(std::move(fallback));
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
+ auto unicode = SkUnicode::Make();
+ std::unique_ptr<SkShaper> shaper =
+ SkShapers::HB::ShaperDrivenWrapper(std::move(unicode), std::move(fallback));
if (shaper) {
return shaper;
}
#elif defined(SK_SHAPER_CORETEXT_AVAILABLE)
- if (auto shaper = SkShaper::MakeCoreText()) {
+ if (auto shaper = SkShapers::CT::CoreText()) {
return shaper;
}
#endif
-#if defined(SK_SHAPER_PRIMITIVE_AVAILABLE)
- return SkShaper::MakePrimitive();
-#else
- return nullptr;
-#endif
+ return SkShapers::Primitive();
}
void SkShaper::PurgeCaches() {
-#ifdef SK_SHAPER_HARFBUZZ_AVAILABLE
- PurgeHarfBuzzCache();
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE)
+ SkShapers::HB::PurgeCaches();
#endif
}
std::unique_ptr<SkShaper::BiDiRunIterator>
SkShaper::MakeBiDiRunIterator(const char* utf8, size_t utf8Bytes, uint8_t bidiLevel) {
-#ifdef SK_SHAPER_UNICODE_AVAILABLE
+#if defined(SK_SHAPER_UNICODE_AVAILABLE)
if (const auto unicode = SkUnicode::Make()) {
std::unique_ptr<SkShaper::BiDiRunIterator> bidi =
- SkShaper::MakeSkUnicodeBidiRunIterator(unicode.get(),
- utf8,
- utf8Bytes,
- bidiLevel);
+ SkShapers::unicode::BidiRunIterator(unicode.get(), utf8, utf8Bytes, bidiLevel);
if (bidi) {
return bidi;
}
@@ -70,13 +78,14 @@
SkShaper::MakeScriptRunIterator(const char* utf8, size_t utf8Bytes, SkFourByteTag scriptTag) {
#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE)
std::unique_ptr<SkShaper::ScriptRunIterator> script =
- SkShaper::MakeSkUnicodeHbScriptRunIterator(utf8, utf8Bytes, scriptTag);
+ SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes, scriptTag);
if (script) {
return script;
}
#endif
return std::make_unique<SkShaper::TrivialScriptRunIterator>(scriptTag, utf8Bytes);
}
+#endif // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
SkShaper::SkShaper() {}
SkShaper::~SkShaper() {}
diff --git a/modules/skshaper/src/SkShaper_coretext.cpp b/modules/skshaper/src/SkShaper_coretext.cpp
index bf90014..8d7f8e5 100644
--- a/modules/skshaper/src/SkShaper_coretext.cpp
+++ b/modules/skshaper/src/SkShaper_coretext.cpp
@@ -34,6 +34,7 @@
public:
SkShaper_CoreText() {}
private:
+#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
void shape(const char* utf8, size_t utf8Bytes,
const SkFont& srcFont,
bool leftToRight,
@@ -47,6 +48,7 @@
LanguageRunIterator&,
SkScalar width,
RunHandler*) const override;
+#endif
void shape(const char* utf8, size_t utf8Bytes,
FontRunIterator&,
@@ -58,47 +60,6 @@
RunHandler*) const override;
};
-std::unique_ptr<SkShaper> SkShaper::MakeCoreText() {
- return std::make_unique<SkShaper_CoreText>();
-}
-
-void SkShaper_CoreText::shape(const char* utf8, size_t utf8Bytes,
- FontRunIterator& font,
- BiDiRunIterator& bidi,
- ScriptRunIterator&,
- LanguageRunIterator&,
- SkScalar width,
- RunHandler* handler) const
-{
- SkFont skfont;
- if (!font.atEnd()) {
- font.consume();
- skfont = font.currentFont();
- }
- SkASSERT(skfont.getTypeface());
- bool skbidi = 0;
- if (!bidi.atEnd()) {
- bidi.consume();
- skbidi = (bidi.currentLevel() % 2) == 0;
- }
- return this->shape(utf8, utf8Bytes, skfont, skbidi, width, handler);
-}
-
-void SkShaper_CoreText::shape(const char* utf8, size_t utf8Bytes,
- FontRunIterator& font,
- BiDiRunIterator& bidi,
- ScriptRunIterator&,
- LanguageRunIterator&,
- const Feature*, size_t,
- SkScalar width,
- RunHandler* handler) const {
- font.consume();
- SkASSERT(font.currentFont().getTypeface());
- bidi.consume();
- return this->shape(utf8, utf8Bytes, font.currentFont(), (bidi.currentLevel() % 2) == 0,
- width, handler);
-}
-
// CTFramesetter/CTFrame can do this, but require version 10.14
class LineBreakIter {
CTTypesetterRef fTypesetter;
@@ -197,11 +158,54 @@
// kCTTrackingAttributeName not available until 10.12
const CFStringRef kCTTracking_AttributeName = CFSTR("CTTracking");
-void SkShaper_CoreText::shape(const char* utf8, size_t utf8Bytes,
- const SkFont& font,
- bool /* leftToRight */,
+#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
+void SkShaper_CoreText::shape(const char* utf8,
+ size_t utf8Bytes,
+ FontRunIterator& font,
+ BiDiRunIterator& bidi,
+ ScriptRunIterator& script,
+ LanguageRunIterator& lang,
SkScalar width,
RunHandler* handler) const {
+ return this->shape(utf8, utf8Bytes, font, bidi, script, lang, nullptr, 0, width, handler);
+}
+
+void SkShaper_CoreText::shape(const char* utf8,
+ size_t utf8Bytes,
+ const SkFont& font,
+ bool,
+ SkScalar width,
+ RunHandler* handler) const {
+ std::unique_ptr<FontRunIterator> fontRuns(
+ MakeFontMgrRunIterator(utf8, utf8Bytes, font, nullptr));
+ if (!fontRuns) {
+ return;
+ }
+ // bidi, script, and lang are all unused so we can construct them with empty data.
+ TrivialBiDiRunIterator bidi{0, 0};
+ TrivialScriptRunIterator script{0, 0};
+ TrivialLanguageRunIterator lang{nullptr, 0};
+ return this->shape(utf8, utf8Bytes, *fontRuns, bidi, script, lang, nullptr, 0, width, handler);
+}
+#endif
+
+void SkShaper_CoreText::shape(const char* utf8,
+ size_t utf8Bytes,
+ FontRunIterator& fontRuns,
+ BiDiRunIterator&,
+ ScriptRunIterator&,
+ LanguageRunIterator&,
+ const Feature*,
+ size_t,
+ SkScalar width,
+ RunHandler* handler) const {
+ SkFont font;
+ if (!fontRuns.atEnd()) {
+ fontRuns.consume();
+ font = fontRuns.currentFont();
+ }
+ SkASSERT(font.getTypeface());
+
SkUniqueCFRef<CFStringRef> textString(
CFStringCreateWithBytes(kCFAllocatorDefault, (const uint8_t*)utf8, utf8Bytes,
kCFStringEncodingUTF8, false));
@@ -312,3 +316,7 @@
handler->commitLine();
}
}
+
+namespace SkShapers::CT {
+std::unique_ptr<SkShaper> CoreText() { return std::make_unique<SkShaper_CoreText>(); }
+} // namespace SkShapers::CT
diff --git a/modules/skshaper/src/SkShaper_harfbuzz.cpp b/modules/skshaper/src/SkShaper_harfbuzz.cpp
index 4de90a5..6c7a18b 100644
--- a/modules/skshaper/src/SkShaper_harfbuzz.cpp
+++ b/modules/skshaper/src/SkShaper_harfbuzz.cpp
@@ -5,6 +5,8 @@
* found in the LICENSE file.
*/
+#include "modules/skshaper/include/SkShaper_harfbuzz.h"
+
#include "include/core/SkData.h"
#include "include/core/SkFont.h"
#include "include/core/SkFontArguments.h"
@@ -34,6 +36,10 @@
#include "src/base/SkUTF.h"
#include "src/core/SkLRUCache.h"
+#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
+#include "modules/skshaper/include/SkShaper_skunicode.h"
+#endif
+
#include <hb-ot.h>
#include <hb.h>
@@ -638,6 +644,7 @@
HBBuffer fBuffer;
hb_language_t fUndefinedLanguage;
+#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
void shape(const char* utf8, size_t utf8Bytes,
const SkFont&,
bool leftToRight,
@@ -651,6 +658,7 @@
LanguageRunIterator&,
SkScalar width,
RunHandler*) const override;
+#endif
void shape(const char* utf8Text, size_t textBytes,
FontRunIterator&,
@@ -717,28 +725,6 @@
RunHandler*) const override;
};
-static std::unique_ptr<SkShaper> MakeHarfBuzz(sk_sp<SkFontMgr> fallback, bool correct) {
- HBBuffer buffer(hb_buffer_create());
- if (!buffer) {
- SkDEBUGF("Could not create hb_buffer");
- return nullptr;
- }
-
- auto unicode = SkUnicode::Make();
- if (!unicode) {
- return nullptr;
- }
-
- if (correct) {
- return std::make_unique<ShaperDrivenWrapper>(std::move(unicode),
- std::move(buffer),
- std::move(fallback));
- }
- return std::make_unique<ShapeThenWrap>(std::move(unicode),
- std::move(buffer),
- std::move(fallback));
-}
-
ShaperHarfBuzz::ShaperHarfBuzz(std::unique_ptr<SkUnicode> unicode,
HBBuffer buffer,
sk_sp<SkFontMgr> fallback)
@@ -746,19 +732,21 @@
, fFontMgr(fallback ? std::move(fallback) : SkFontMgr::RefEmpty())
, fBuffer(std::move(buffer))
, fUndefinedLanguage(hb_language_from_string("und", -1)) {
+#if defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
+ SkASSERT(unicode);
+#endif
}
-void ShaperHarfBuzz::shape(const char* utf8, size_t utf8Bytes,
+#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
+void ShaperHarfBuzz::shape(const char* utf8,
+ size_t utf8Bytes,
const SkFont& srcFont,
bool leftToRight,
SkScalar width,
- RunHandler* handler) const
-{
+ RunHandler* handler) const {
SkBidiIterator::Level defaultLevel = leftToRight ? SkBidiIterator::kLTR : SkBidiIterator::kRTL;
- std::unique_ptr<BiDiRunIterator> bidi(MakeSkUnicodeBidiRunIterator(fUnicode.get(),
- utf8,
- utf8Bytes,
- defaultLevel));
+ std::unique_ptr<BiDiRunIterator> bidi(
+ SkShapers::unicode::BidiRunIterator(fUnicode.get(), utf8, utf8Bytes, defaultLevel));
if (!bidi) {
return;
@@ -769,7 +757,7 @@
return;
}
- std::unique_ptr<ScriptRunIterator> script(MakeSkUnicodeHbScriptRunIterator(utf8, utf8Bytes));
+ std::unique_ptr<ScriptRunIterator> script(SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes));
if (!script) {
return;
}
@@ -783,26 +771,28 @@
this->shape(utf8, utf8Bytes, *font, *bidi, *script, *language, width, handler);
}
-void ShaperHarfBuzz::shape(const char* utf8, size_t utf8Bytes,
+void ShaperHarfBuzz::shape(const char* utf8,
+ size_t utf8Bytes,
FontRunIterator& font,
BiDiRunIterator& bidi,
ScriptRunIterator& script,
LanguageRunIterator& language,
SkScalar width,
- RunHandler* handler) const
-{
+ RunHandler* handler) const {
this->shape(utf8, utf8Bytes, font, bidi, script, language, nullptr, 0, width, handler);
}
+#endif // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
-void ShaperHarfBuzz::shape(const char* utf8, size_t utf8Bytes,
+void ShaperHarfBuzz::shape(const char* utf8,
+ size_t utf8Bytes,
FontRunIterator& font,
BiDiRunIterator& bidi,
ScriptRunIterator& script,
LanguageRunIterator& language,
- const Feature* features, size_t featuresSize,
+ const Feature* features,
+ size_t featuresSize,
SkScalar width,
- RunHandler* handler) const
-{
+ RunHandler* handler) const {
SkASSERT(handler);
RunIteratorQueue runSegmenter;
runSegmenter.insert(&font, 3); // The font iterator is always run last in case of tie.
@@ -1430,45 +1420,95 @@
} // namespace
+#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
std::unique_ptr<SkShaper::ScriptRunIterator>
SkShaper::MakeHbIcuScriptRunIterator(const char* utf8, size_t utf8Bytes) {
- return SkShaper::MakeSkUnicodeHbScriptRunIterator(utf8, utf8Bytes);
+ return SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes);
}
std::unique_ptr<SkShaper::ScriptRunIterator>
SkShaper::MakeSkUnicodeHbScriptRunIterator(const char* utf8, size_t utf8Bytes) {
- return std::make_unique<SkUnicodeHbScriptRunIterator>(utf8, utf8Bytes, HB_SCRIPT_UNKNOWN);
+ return SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes);
}
std::unique_ptr<SkShaper::ScriptRunIterator> SkShaper::MakeSkUnicodeHbScriptRunIterator(
const char* utf8, size_t utf8Bytes, SkFourByteTag script) {
- return std::make_unique<SkUnicodeHbScriptRunIterator>(
- utf8, utf8Bytes, hb_script_from_iso15924_tag((hb_tag_t)script));
+ return SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes, script);
}
std::unique_ptr<SkShaper> SkShaper::MakeShaperDrivenWrapper(sk_sp<SkFontMgr> fontmgr) {
- return MakeHarfBuzz(std::move(fontmgr), true);
+ auto unicode = SkUnicode::Make();
+ return SkShapers::HB::ShaperDrivenWrapper(std::move(unicode), fontmgr);
}
+
std::unique_ptr<SkShaper> SkShaper::MakeShapeThenWrap(sk_sp<SkFontMgr> fontmgr) {
- return MakeHarfBuzz(std::move(fontmgr), false);
+ auto unicode = SkUnicode::Make();
+ return SkShapers::HB::ShapeThenWrap(std::move(unicode), fontmgr);
}
+
std::unique_ptr<SkShaper> SkShaper::MakeShapeDontWrapOrReorder(std::unique_ptr<SkUnicode> unicode,
sk_sp<SkFontMgr> fontmgr) {
+ return SkShapers::HB::ShapeDontWrapOrReorder(std::move(unicode), std::move(fontmgr));
+}
+
+void SkShaper::PurgeHarfBuzzCache() { SkShapers::HB::PurgeCaches(); }
+#endif // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
+
+namespace SkShapers::HB {
+std::unique_ptr<SkShaper> ShaperDrivenWrapper(std::unique_ptr<SkUnicode> unicode,
+ sk_sp<SkFontMgr> fallback) {
+ if (!unicode) {
+ return nullptr;
+ }
HBBuffer buffer(hb_buffer_create());
if (!buffer) {
SkDEBUGF("Could not create hb_buffer");
return nullptr;
}
+ return std::make_unique<::ShaperDrivenWrapper>(
+ std::move(unicode), std::move(buffer), std::move(fallback));
+}
+std::unique_ptr<SkShaper> ShapeThenWrap(std::unique_ptr<SkUnicode> unicode,
+ sk_sp<SkFontMgr> fallback) {
if (!unicode) {
return nullptr;
}
-
- return std::make_unique<ShapeDontWrapOrReorder>
- (std::move(unicode), std::move(buffer), std::move(fontmgr));
+ HBBuffer buffer(hb_buffer_create());
+ if (!buffer) {
+ SkDEBUGF("Could not create hb_buffer");
+ return nullptr;
+ }
+ return std::make_unique<::ShapeThenWrap>(
+ std::move(unicode), std::move(buffer), std::move(fallback));
}
-void SkShaper::PurgeHarfBuzzCache() {
+std::unique_ptr<SkShaper> ShapeDontWrapOrReorder(std::unique_ptr<SkUnicode> unicode,
+ sk_sp<SkFontMgr> fallback) {
+ if (!unicode) {
+ return nullptr;
+ }
+ HBBuffer buffer(hb_buffer_create());
+ if (!buffer) {
+ SkDEBUGF("Could not create hb_buffer");
+ return nullptr;
+ }
+ return std::make_unique<::ShapeDontWrapOrReorder>(
+ std::move(unicode), std::move(buffer), std::move(fallback));
+}
+
+std::unique_ptr<SkShaper::ScriptRunIterator> ScriptRunIterator(const char* utf8, size_t utf8Bytes) {
+ return std::make_unique<SkUnicodeHbScriptRunIterator>(utf8, utf8Bytes, HB_SCRIPT_UNKNOWN);
+}
+std::unique_ptr<SkShaper::ScriptRunIterator> ScriptRunIterator(const char* utf8,
+ size_t utf8Bytes,
+ SkFourByteTag script) {
+ return std::make_unique<SkUnicodeHbScriptRunIterator>(
+ utf8, utf8Bytes, hb_script_from_iso15924_tag((hb_tag_t)script));
+}
+
+void PurgeCaches() {
HBLockedFaceCache cache = get_hbFace_cache();
cache.reset();
}
+} // namespace SkShapers::HB
diff --git a/modules/skshaper/src/SkShaper_primitive.cpp b/modules/skshaper/src/SkShaper_primitive.cpp
index 5622918..fa0a66c 100644
--- a/modules/skshaper/src/SkShaper_primitive.cpp
+++ b/modules/skshaper/src/SkShaper_primitive.cpp
@@ -6,11 +6,11 @@
*/
#include "include/core/SkFont.h"
+#include "include/core/SkFontMgr.h"
#include "include/core/SkFontTypes.h"
#include "include/core/SkPoint.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
-#include "include/private/base/SkTemplates.h"
#include "include/private/base/SkTo.h"
#include "modules/skshaper/include/SkShaper.h"
#include "src/base/SkUTF.h"
@@ -19,11 +19,11 @@
#include <cstring>
#include <memory>
-
class SkShaperPrimitive : public SkShaper {
public:
SkShaperPrimitive() {}
private:
+#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
void shape(const char* utf8, size_t utf8Bytes,
const SkFont& srcFont,
bool leftToRight,
@@ -37,6 +37,7 @@
LanguageRunIterator&,
SkScalar width,
RunHandler*) const override;
+#endif
void shape(const char* utf8, size_t utf8Bytes,
FontRunIterator&,
@@ -48,10 +49,6 @@
RunHandler*) const override;
};
-std::unique_ptr<SkShaper> SkShaper::MakePrimitive() {
- return std::make_unique<SkShaperPrimitive>();
-}
-
static inline bool is_breaking_whitespace(SkUnichar c) {
switch (c) {
case 0x0020: // SPACE
@@ -139,49 +136,53 @@
return text - start;
}
-void SkShaperPrimitive::shape(const char* utf8, size_t utf8Bytes,
+#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
+void SkShaperPrimitive::shape(const char* utf8,
+ size_t utf8Bytes,
FontRunIterator& font,
BiDiRunIterator& bidi,
- ScriptRunIterator&,
- LanguageRunIterator&,
- SkScalar width,
- RunHandler* handler) const
-{
- SkFont skfont;
- if (!font.atEnd()) {
- font.consume();
- skfont = font.currentFont();
- }
- SkASSERT(skfont.getTypeface());
- bool skbidi = 0;
- if (!bidi.atEnd()) {
- bidi.consume();
- skbidi = (bidi.currentLevel() % 2) == 0;
- }
- return this->shape(utf8, utf8Bytes, skfont, skbidi, width, handler);
-}
-
-void SkShaperPrimitive::shape(const char* utf8, size_t utf8Bytes,
- FontRunIterator& font,
- BiDiRunIterator& bidi,
- ScriptRunIterator&,
- LanguageRunIterator&,
- const Feature*, size_t,
+ ScriptRunIterator& script,
+ LanguageRunIterator& lang,
SkScalar width,
RunHandler* handler) const {
- font.consume();
- SkASSERT(font.currentFont().getTypeface());
- bidi.consume();
- return this->shape(utf8, utf8Bytes, font.currentFont(), (bidi.currentLevel() % 2) == 0,
- width, handler);
+ return this->shape(utf8, utf8Bytes, font, bidi, script, lang, nullptr, 0, width, handler);
}
-void SkShaperPrimitive::shape(const char* utf8, size_t utf8Bytes,
+void SkShaperPrimitive::shape(const char* utf8,
+ size_t utf8Bytes,
const SkFont& font,
bool leftToRight,
SkScalar width,
RunHandler* handler) const {
- sk_ignore_unused_variable(leftToRight);
+ std::unique_ptr<FontRunIterator> fontRuns(
+ MakeFontMgrRunIterator(utf8, utf8Bytes, font, nullptr));
+ if (!fontRuns) {
+ return;
+ }
+ // bidi, script, and lang are all unused so we can construct them with empty data.
+ TrivialBiDiRunIterator bidi{0, 0};
+ TrivialScriptRunIterator script{0, 0};
+ TrivialLanguageRunIterator lang{nullptr, 0};
+ return this->shape(utf8, utf8Bytes, *fontRuns, bidi, script, lang, nullptr, 0, width, handler);
+}
+#endif
+
+void SkShaperPrimitive::shape(const char* utf8,
+ size_t utf8Bytes,
+ FontRunIterator& fontRuns,
+ BiDiRunIterator&,
+ ScriptRunIterator&,
+ LanguageRunIterator&,
+ const Feature*,
+ size_t,
+ SkScalar width,
+ RunHandler* handler) const {
+ SkFont font;
+ if (!fontRuns.atEnd()) {
+ fontRuns.consume();
+ font = fontRuns.currentFont();
+ }
+ SkASSERT(font.getTypeface());
int glyphCount = font.countText(utf8, utf8Bytes, SkTextEncoding::kUTF8);
if (glyphCount < 0) {
@@ -242,3 +243,11 @@
utf8Bytes -= bytesConsumed;
} while (0 < utf8Bytes);
}
+
+#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
+std::unique_ptr<SkShaper> SkShaper::MakePrimitive() { return SkShapers::Primitive(); }
+#endif
+
+namespace SkShapers {
+std::unique_ptr<SkShaper> Primitive() { return std::make_unique<SkShaperPrimitive>(); }
+} // namespace SkShapers
diff --git a/modules/skshaper/src/SkShaper_skunicode.cpp b/modules/skshaper/src/SkShaper_skunicode.cpp
index 140c910..9df0457 100644
--- a/modules/skshaper/src/SkShaper_skunicode.cpp
+++ b/modules/skshaper/src/SkShaper_skunicode.cpp
@@ -4,6 +4,7 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
+#include "modules/skshaper/include/SkShaper_skunicode.h"
#include "include/private/base/SkAssert.h"
#include "include/private/base/SkDebug.h"
@@ -71,9 +72,26 @@
SkBidiIterator::Level fLevel;
};
-std::unique_ptr<SkShaper::BiDiRunIterator>
-SkShaper::MakeSkUnicodeBidiRunIterator(SkUnicode* unicode, const char* utf8, size_t utf8Bytes,
- uint8_t bidiLevel) {
+#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
+std::unique_ptr<SkShaper::BiDiRunIterator> SkShaper::MakeIcuBiDiRunIterator(const char* utf8,
+ size_t utf8Bytes,
+ uint8_t bidiLevel) {
+ auto unicode = SkUnicode::Make();
+ if (!unicode) {
+ return nullptr;
+ }
+ return SkShapers::unicode::BidiRunIterator(unicode.get(), utf8, utf8Bytes, bidiLevel);
+}
+#endif
+
+namespace SkShapers::unicode {
+std::unique_ptr<SkShaper::BiDiRunIterator> BidiRunIterator(SkUnicode* unicode,
+ const char* utf8,
+ size_t utf8Bytes,
+ uint8_t bidiLevel) {
+ if (!unicode) {
+ return nullptr;
+ }
// ubidi only accepts utf16 (though internally it basically works on utf32 chars).
// We want an ubidi_setPara(UBiDi*, UText*, UBiDiLevel, UBiDiLevel*, UErrorCode*);
if (!SkTFitsIn<int32_t>(utf8Bytes)) {
@@ -99,15 +117,4 @@
return std::make_unique<SkUnicodeBidiRunIterator>(utf8, utf8 + utf8Bytes, std::move(bidi));
}
-
-std::unique_ptr<SkShaper::BiDiRunIterator>
-SkShaper::MakeIcuBiDiRunIterator(const char* utf8, size_t utf8Bytes, uint8_t bidiLevel) {
- auto unicode = SkUnicode::Make();
- if (!unicode) {
- return nullptr;
- }
- return SkShaper::MakeSkUnicodeBidiRunIterator(unicode.get(),
- utf8,
- utf8Bytes,
- bidiLevel);
-}
+} // namespace SkShapers::unicode
diff --git a/modules/skshaper/tests/ShaperTest.cpp b/modules/skshaper/tests/ShaperTest.cpp
index 10a0355..95e1d48 100644
--- a/modules/skshaper/tests/ShaperTest.cpp
+++ b/modules/skshaper/tests/ShaperTest.cpp
@@ -3,8 +3,6 @@
#include "tests/Test.h"
-#if !defined(SK_BUILD_FOR_GOOGLE3)
-
#include "include/core/SkData.h"
#include "include/core/SkFont.h"
#include "include/core/SkPoint.h"
@@ -15,6 +13,9 @@
#include "include/core/SkTypes.h"
#include "include/private/base/SkTo.h"
#include "modules/skshaper/include/SkShaper.h"
+#include "modules/skshaper/include/SkShaper_harfbuzz.h"
+#include "modules/skshaper/include/SkShaper_skunicode.h"
+#include "modules/skunicode/include/SkUnicode.h"
#include "src/base/SkZip.h"
#include "tools/Resources.h"
#include "tools/fonts/FontToolUtils.h"
@@ -117,19 +118,45 @@
};
void shaper_test(skiatest::Reporter* reporter, const char* name, SkData* data) {
- auto shaper = SkShaper::Make(SkFontMgr::RefEmpty()); // no fallback
+ skiatest::ReporterContext context(reporter, name);
+ auto shaper = SkShapers::HB::ShaperDrivenWrapper(SkUnicode::Make(),
+ SkFontMgr::RefEmpty()); // no fallback
if (!shaper) {
ERRORF(reporter, "Could not create shaper.");
return;
}
-
+ auto unicode = SkUnicode::Make();
+ if (!unicode) {
+ ERRORF(reporter, "Could not create unicode.");
+ return;
+ }
constexpr float kWidth = 400;
SkFont font = ToolUtils::DefaultFont();
- RunHandler rh(name, reporter, (const char*)data->data(), data->size());
- shaper->shape((const char*)data->data(), data->size(), font, true, kWidth, &rh);
+ const char* utf8 = (const char*)data->data();
+ size_t utf8Bytes = data->size();
- // Even on empty input, expect that the line is started, that the zero run infos are comitted,
- // and the empty line is comitted. This allows the user to properly handle empy runs.
+ RunHandler rh(name, reporter, utf8, utf8Bytes);
+
+ const SkBidiIterator::Level defaultLevel = SkBidiIterator::kLTR;
+ std::unique_ptr<SkShaper::BiDiRunIterator> bidi =
+ SkShapers::unicode::BidiRunIterator(unicode.get(), utf8, utf8Bytes, defaultLevel);
+ SkASSERT(bidi);
+
+ std::unique_ptr<SkShaper::LanguageRunIterator> language =
+ SkShaper::MakeStdLanguageRunIterator(utf8, utf8Bytes);
+ SkASSERT(language);
+
+ std::unique_ptr<SkShaper::ScriptRunIterator> script =
+ SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes);
+ SkASSERT(script);
+
+ std::unique_ptr<SkShaper::FontRunIterator> fontRuns =
+ SkShaper::MakeFontMgrRunIterator(utf8, utf8Bytes, font, SkFontMgr::RefEmpty());
+ SkASSERT(fontRuns);
+ shaper->shape(utf8, utf8Bytes, *fontRuns, *bidi, *script, *language, nullptr, 0, kWidth, &rh);
+
+ // Even on empty input, expect that the line is started, that the zero run infos are committed,
+ // and the empty line is committed. This allows the user to properly handle empty runs.
REPORTER_ASSERT(reporter, rh.fBeginLine);
REPORTER_ASSERT(reporter, rh.fCommitRunInfo);
REPORTER_ASSERT(reporter, rh.fCommitLine);
@@ -139,8 +166,16 @@
auto bidiIterator = SkShaper::TrivialBiDiRunIterator(0, data->size());
auto scriptIterator = SkShaper::TrivialScriptRunIterator(latn, data->size());
auto languageIterator = SkShaper::TrivialLanguageRunIterator("en-US", data->size());
- shaper->shape((const char*)data->data(), data->size(),
- fontIterator, bidiIterator, scriptIterator, languageIterator, kWidth, &rh);
+ shaper->shape((const char*)data->data(),
+ data->size(),
+ fontIterator,
+ bidiIterator,
+ scriptIterator,
+ languageIterator,
+ nullptr,
+ 0,
+ kWidth,
+ &rh);
}
void cluster_test(skiatest::Reporter* reporter, const char* resource) {
@@ -193,5 +228,3 @@
SHAPER_TEST(taitham)
SHAPER_TEST(tamil)
#undef SHAPER_TEST
-
-#endif // defined(SKSHAPER_IMPLEMENTATION) && !defined(SK_BUILD_FOR_GOOGLE3)
diff --git a/modules/svg/src/SkSVGText.cpp b/modules/svg/src/SkSVGText.cpp
index 03bb76c..9fd45d4 100644
--- a/modules/svg/src/SkSVGText.cpp
+++ b/modules/svg/src/SkSVGText.cpp
@@ -24,6 +24,16 @@
#include "src/base/SkUTF.h"
#include "src/core/SkTextBlobPriv.h"
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
+#include "modules/skshaper/include/SkShaper_harfbuzz.h"
+#include "modules/skshaper/include/SkShaper_skunicode.h"
+#include "modules/skunicode/include/SkUnicode.h"
+#endif
+
+#if defined(SK_SHAPER_CORETEXT_AVAILABLE)
+#include "modules/skshaper/include/SkShaper_coretext.h"
+#endif
+
using namespace skia_private;
namespace {
@@ -220,23 +230,75 @@
fUtf8PosAdjust.push_back_n(utf8_len, pos);
}
-void SkSVGTextContext::shapePendingBuffer(const SkFont& font) {
- // TODO: directionality hints?
- const auto LTR = true;
+void SkSVGTextContext::shapePendingBuffer(const SkFont& font, sk_sp<SkFontMgr> fallback) {
+ const char* utf8 = fShapeBuffer.fUtf8.data();
+ size_t utf8Bytes = fShapeBuffer.fUtf8.size();
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
+ auto unicode = SkUnicode::Make();
+ const SkBidiIterator::Level defaultLevel = SkBidiIterator::kLTR;
+ std::unique_ptr<SkShaper::BiDiRunIterator> bidi =
+ SkShapers::unicode::BidiRunIterator(unicode.get(), utf8, utf8Bytes, defaultLevel);
+ if (!bidi) {
+ return;
+ }
- // Initiate shaping: this will generate a series of runs via callbacks.
- fShaper->shape(fShapeBuffer.fUtf8.data(), fShapeBuffer.fUtf8.size(),
- font, LTR, SK_ScalarMax, this);
+ std::unique_ptr<SkShaper::LanguageRunIterator> language =
+ SkShaper::MakeStdLanguageRunIterator(utf8, utf8Bytes);
+ if (!language) {
+ return;
+ }
+
+ std::unique_ptr<SkShaper::ScriptRunIterator> script =
+ SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes);
+ if (!script) {
+ return;
+ }
+
+ std::unique_ptr<SkShaper::FontRunIterator> fontRuns =
+ SkShaper::MakeFontMgrRunIterator(utf8, utf8Bytes, font, fallback);
+ if (!fontRuns) {
+ return;
+ }
+ fShaper->shape(
+ utf8, utf8Bytes, *fontRuns, *bidi, *script, *language, nullptr, 0, SK_ScalarMax, this);
+#else
+ std::unique_ptr<SkShaper::FontRunIterator> fontRuns =
+ SkShaper::MakeFontMgrRunIterator(utf8, utf8Bytes, font, fallback);
+ if (!fontRuns) {
+ return;
+ }
+ // bidi, script, and lang are all unused so we can construct them with empty data.
+ SkShaper::TrivialBiDiRunIterator bidi{0, 0};
+ SkShaper::TrivialScriptRunIterator script{0, 0};
+ SkShaper::TrivialLanguageRunIterator lang{nullptr, 0};
+ fShaper->shape(utf8, utf8Bytes, *fontRuns, bidi, script, lang, nullptr, 0, SK_ScalarMax, this);
+#endif
fShapeBuffer.reset();
}
-SkSVGTextContext::SkSVGTextContext(const SkSVGRenderContext& ctx, const ShapedTextCallback& cb,
+static std::unique_ptr<SkShaper> make_shaper(sk_sp<SkFontMgr> fallback) {
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
+ auto unicode = SkUnicode::Make();
+ std::unique_ptr<SkShaper> shaper =
+ SkShapers::HB::ShaperDrivenWrapper(std::move(unicode), fallback);
+ if (shaper) {
+ return shaper;
+ }
+#elif defined(SK_SHAPER_CORETEXT_AVAILABLE)
+ if (auto shaper = SkShapers::CT::CoreText()) {
+ return shaper;
+ }
+#endif
+ return SkShapers::Primitive();
+}
+
+SkSVGTextContext::SkSVGTextContext(const SkSVGRenderContext& ctx,
+ const ShapedTextCallback& cb,
const SkSVGTextPath* tpath)
- : fRenderContext(ctx)
- , fCallback(cb)
- , fShaper(SkShaper::Make(ctx.fontMgr()))
- , fChunkAlignmentFactor(ComputeAlignmentFactor(ctx.presentationContext()))
-{
+ : fRenderContext(ctx)
+ , fCallback(cb)
+ , fShaper(make_shaper(ctx.fontMgr()))
+ , fChunkAlignmentFactor(ComputeAlignmentFactor(ctx.presentationContext())) {
if (tpath) {
fPathData = std::make_unique<PathData>(ctx, *tpath);
@@ -325,7 +387,7 @@
// Absolute position adjustments define a new chunk.
// (https://www.w3.org/TR/SVG11/text.html#TextLayoutIntroduction)
if (pos.has(PosAttrs::kX) || pos.has(PosAttrs::kY)) {
- this->shapePendingBuffer(font);
+ this->shapePendingBuffer(font, ctx.fontMgr());
this->flushChunk(ctx);
// New chunk position.
@@ -348,7 +410,7 @@
fPrevCharSpace = (ch == ' ');
}
- this->shapePendingBuffer(font);
+ this->shapePendingBuffer(font, ctx.fontMgr());
// Note: at this point we have shaped and buffered RunRecs for the current fragment.
// The active text chunk continues until an explicit or implicit flush.
diff --git a/modules/svg/src/SkSVGTextPriv.h b/modules/svg/src/SkSVGTextPriv.h
index b46337e..3739243 100644
--- a/modules/svg/src/SkSVGTextPriv.h
+++ b/modules/svg/src/SkSVGTextPriv.h
@@ -168,7 +168,7 @@
float fLength = 0; // total path length
};
- void shapePendingBuffer(const SkFont&);
+ void shapePendingBuffer(const SkFont&, sk_sp<SkFontMgr> fallback);
SkRSXform computeGlyphXform(SkGlyphID, const SkFont&, const SkPoint& glyph_pos,
const PositionAdjustment&) const;
diff --git a/public.bzl b/public.bzl
index 9eccdee..b376a27 100644
--- a/public.bzl
+++ b/public.bzl
@@ -2583,6 +2583,9 @@
SKSHAPER_HDRS = [
"modules/skshaper/include/SkShaper.h",
+ "modules/skshaper/include/SkShaper_harfbuzz.h",
+ "modules/skshaper/include/SkShaper_coretext.h",
+ "modules/skshaper/include/SkShaper_skunicode.h",
]
SKSHAPER_HARFBUZZ_SRCS = [
diff --git a/relnotes/skshaper.md b/relnotes/skshaper.md
new file mode 100644
index 0000000..66b534a
--- /dev/null
+++ b/relnotes/skshaper.md
@@ -0,0 +1,16 @@
+The following SkShaper functions have been moved or deleted:
+ - SkShaper::MakePrimitive() -> SkShapers::Primitive()
+ - SkShaper::MakeShaperDrivenWrapper() -> SkShapers::HB::ShaperDrivenWrapper()
+ - SkShaper::MakeShapeThenWrap() -> SkShapers::HB::ShapeThenWrap()
+ - SkShaper::MakeShapeDontWrapOrReorder() -> SkShapers::HB::ShapeDontWrapOrReorder()
+ - SkShaper::MakeCoreText() -> SkShapers::CT::CoreText()
+ - SkShaper::Make() -> deleted, use one of the above directly,
+ - SkShaper::MakeSkUnicodeBidiRunIterator() -> SkShapers::unicode::BidiRunIterator()
+ - SkShaper::MakeBiDiRunIterator() -> deleted, use SkShapers::unicode::BidiRunIterator() or SkShapers::TrivialBiDiRunIterator()
+ - SkShaper::MakeIcuBiDiRunIterator() -> deleted, use SkShapers::unicode::BidiRunIterator()
+ - SkShaper::MakeSkUnicodeHbScriptRunIterator() -> SkShapers::HB::ScriptRunIterator()
+ - SkShaper::MakeHbIcuScriptRunIterator() -> SkShapers::HB::ScriptRunIterator()
+ - SkShaper::MakeScriptRunIterator() -> deleted, use SkShapers::HB::ScriptRunIterator() or SkShapers::TrivialScriptRunIterator
+
+Additionally, two `SkShaper::shape` method overloads have been removed - clients now need to
+specify all 10 arguments (although it is common to pass in nullptr for features).
diff --git a/tools/using_skia_and_harfbuzz.cpp b/tools/using_skia_and_harfbuzz.cpp
index 94c85fe..60df44d 100644
--- a/tools/using_skia_and_harfbuzz.cpp
+++ b/tools/using_skia_and_harfbuzz.cpp
@@ -22,8 +22,9 @@
#include "include/core/SkTypeface.h"
#include "include/docs/SkPDFDocument.h"
#include "include/ports/SkFontMgr_empty.h"
-#include "modules/skshaper/include/SkShaper.h"
-
+#include "modules/skshaper/include/SkShaper_harfbuzz.h"
+#include "modules/skshaper/include/SkShaper_skunicode.h"
+#include "modules/skunicode/include/SkUnicode.h"
// Options /////////////////////////////////////////////////////////////////////
@@ -142,10 +143,38 @@
font.setSize(SkDoubleToScalar(config->font_size.value));
}
- void WriteLine(const SkShaper& shaper, const char *text, size_t textBytes) {
+ void WriteLine(const SkShaper& shaper, const char* text, size_t textBytes) {
SkTextBlobBuilderRunHandler textBlobBuilder(text, {0, 0});
- shaper.shape(text, textBytes, font, true,
- config->page_width.value - 2*config->left_margin.value, &textBlobBuilder);
+
+ const SkBidiIterator::Level defaultLevel = SkBidiIterator::kLTR;
+ auto unicode = SkUnicode::Make();
+ std::unique_ptr<SkShaper::BiDiRunIterator> bidi =
+ SkShapers::unicode::BidiRunIterator(unicode.get(), text, textBytes, defaultLevel);
+ SkASSERT(bidi);
+
+ std::unique_ptr<SkShaper::LanguageRunIterator> language =
+ SkShaper::MakeStdLanguageRunIterator(text, textBytes);
+ SkASSERT(language);
+
+ std::unique_ptr<SkShaper::ScriptRunIterator> script =
+ SkShapers::HB::ScriptRunIterator(text, textBytes);
+ SkASSERT(script);
+
+ std::unique_ptr<SkShaper::FontRunIterator> fontRuns =
+ SkShaper::MakeFontMgrRunIterator(text, textBytes, font, SkFontMgr::RefEmpty());
+ SkASSERT(fontRuns);
+
+ const SkScalar width = config->page_width.value - 2 * config->left_margin.value;
+ shaper.shape(text,
+ textBytes,
+ *fontRuns,
+ *bidi,
+ *script,
+ *language,
+ nullptr,
+ 0,
+ width,
+ &textBlobBuilder);
SkPoint endPoint = textBlobBuilder.endPoint();
sk_sp<const SkTextBlob> blob = textBlobBuilder.makeBlob();
// If we don't have a page, or if we're not at the start of the page and the blob won't fit
@@ -215,7 +244,9 @@
assert(mgr);
typeface = mgr->makeFromFile(font_file.c_str(), 0 /* index */);
}
- std::unique_ptr<SkShaper> shaper = SkShaper::Make();
+ auto unicode = SkUnicode::Make();
+ std::unique_ptr<SkShaper> shaper =
+ SkShapers::HB::ShaperDrivenWrapper(std::move(unicode), nullptr);
assert(shaper);
//SkString line("This is هذا هو الخط a line.");
//SkString line("This is a line هذا هو الخط.");
diff --git a/tools/viewer/TextBoxSlide.cpp b/tools/viewer/TextBoxSlide.cpp
index 8a5475a..fa3c0e2 100644
--- a/tools/viewer/TextBoxSlide.cpp
+++ b/tools/viewer/TextBoxSlide.cpp
@@ -17,6 +17,8 @@
#include "include/core/SkTypeface.h"
#include "include/effects/SkGradientShader.h"
#include "modules/skshaper/include/SkShaper.h"
+#include "modules/skshaper/include/SkShaper_skunicode.h"
+#include "modules/skunicode/include/SkUnicode.h"
#include "src/base/SkRandom.h"
#include "src/base/SkTime.h"
#include "src/base/SkUTF.h"
@@ -24,6 +26,14 @@
#include "tools/fonts/FontToolUtils.h"
#include "tools/viewer/Slide.h"
+#if defined(SK_SHAPER_CORETEXT_AVAILABLE)
+#include "modules/skshaper/include/SkShaper_coretext.h"
+#endif
+
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE)
+#include "modules/skshaper/include/SkShaper_harfbuzz.h"
+#endif
+
typedef std::unique_ptr<SkShaper> (*ShaperFactory)();
static const char gText[] =
@@ -34,9 +44,73 @@
"a decent respect to the opinions of mankind requires that they should "
"declare the causes which impel them to the separation.";
+static std::unique_ptr<SkUnicode> make_sk_unicode() {
+#if defined(SK_UNICODE_ICU_IMPLEMENTATION)
+ unicode = SkUnicode::MakeIcuBasedUnicode();
+ if (unicode) {
+ return unicode;
+ }
+#endif
+#if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION)
+ unicode = SkUnicode::MakeLibgraphemeBasedUnicode();
+ if (unicode) {
+ return unicode;
+ }
+#endif
+#if defined(SK_UNICODE_ICU4X_IMPLEMENTATION)
+ return SkUnicode::MakeIcu4xBasedUnicode();
+#endif
+ return nullptr;
+}
+
+using MakeBidiIteratorCallback = std::unique_ptr<SkShaper::BiDiRunIterator> (*)(SkUnicode* unicode,
+ const char* utf8,
+ size_t utf8Bytes,
+ uint8_t bidiLevel);
+using MakeScriptRunCallback = std::unique_ptr<SkShaper::ScriptRunIterator> (*)(
+ const char* utf8, size_t utf8Bytes, SkFourByteTag script);
+
+static std::unique_ptr<SkShaper::BiDiRunIterator> make_trivial_bidi(SkUnicode*,
+ const char*,
+ size_t utf8Bytes,
+ uint8_t bidiLevel) {
+ return std::make_unique<SkShaper::TrivialBiDiRunIterator>(bidiLevel, utf8Bytes);
+}
+
+static std::unique_ptr<SkShaper::BiDiRunIterator> make_unicode_bidi(SkUnicode* unicode,
+ const char* utf8,
+ size_t utf8Bytes,
+ uint8_t bidiLevel) {
+ if (auto bidi = SkShapers::unicode::BidiRunIterator(unicode, utf8, utf8Bytes, bidiLevel)) {
+ return bidi;
+ }
+ return make_trivial_bidi(unicode, utf8, utf8Bytes, bidiLevel);
+}
+
+static std::unique_ptr<SkShaper::ScriptRunIterator> make_trivial_script_runner(
+ const char*, size_t utf8Bytes, SkFourByteTag scriptTag) {
+ return std::make_unique<SkShaper::TrivialScriptRunIterator>(scriptTag, utf8Bytes);
+}
+
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE)
+static std::unique_ptr<SkShaper::ScriptRunIterator> make_harfbuzz_script_runner(
+ const char* utf8, size_t utf8Bytes, SkFourByteTag scriptTag) {
+ std::unique_ptr<SkShaper::ScriptRunIterator> script =
+ SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes, scriptTag);
+ if (script) {
+ return script;
+ }
+ return std::make_unique<SkShaper::TrivialScriptRunIterator>(scriptTag, utf8Bytes);
+}
+#endif
+
class TextBoxSlide : public Slide {
public:
- TextBoxSlide(ShaperFactory fact, const char suffix[]) : fShaper(fact()) {
+ TextBoxSlide(ShaperFactory fact,
+ MakeBidiIteratorCallback bidi,
+ MakeScriptRunCallback script,
+ const char suffix[])
+ : fShaper(fact()), fBidiCallback(bidi), fScriptRunCallback(script) {
fName = SkStringPrintf("TextBox_%s", suffix);
}
@@ -68,7 +142,9 @@
paint.setColor(fg);
for (int i = 9; i < 24; i += 2) {
- SkShaper::PurgeCaches();
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE)
+ SkShapers::HB::PurgeCaches();
+#endif
SkTextBlobBuilderRunHandler builder(gText, { margin, margin });
SkFont srcFont(nullptr, SkIntToScalar(i));
srcFont.setEdging(SkFont::Edging::kSubpixelAntiAlias);
@@ -77,8 +153,9 @@
const char* utf8 = gText;
size_t utf8Bytes = sizeof(gText) - 1;
- std::unique_ptr<SkShaper::BiDiRunIterator> bidi(
- SkShaper::MakeBiDiRunIterator(utf8, utf8Bytes, 0xfe));
+ std::unique_ptr<SkUnicode> unicode = make_sk_unicode();
+ std::unique_ptr<SkShaper::BiDiRunIterator> bidi =
+ fBidiCallback(unicode.get(), utf8, utf8Bytes, 0xfe);
if (!bidi) {
return;
}
@@ -90,8 +167,8 @@
}
SkFourByteTag undeterminedScript = SkSetFourByteTag('Z','y','y','y');
- std::unique_ptr<SkShaper::ScriptRunIterator> script(
- SkShaper::MakeScriptRunIterator(utf8, utf8Bytes, undeterminedScript));
+ std::unique_ptr<SkShaper::ScriptRunIterator> script =
+ fScriptRunCallback(utf8, utf8Bytes, undeterminedScript);
if (!script) {
return;
}
@@ -108,7 +185,16 @@
return;
}
- fShaper->shape(utf8, utf8Bytes, *font, *bidi, *script, *language, w - margin, &builder);
+ fShaper->shape(utf8,
+ utf8Bytes,
+ *font,
+ *bidi,
+ *script,
+ *language,
+ nullptr,
+ 0,
+ w - margin,
+ &builder);
canvas->drawTextBlob(builder.makeBlob(), 0, 0, paint);
canvas->translate(0, builder.endPoint().y());
@@ -117,11 +203,32 @@
SkSize fSize;
std::unique_ptr<SkShaper> fShaper;
+ MakeBidiIteratorCallback fBidiCallback;
+ MakeScriptRunCallback fScriptRunCallback;
};
-DEF_SLIDE( return new TextBoxSlide([](){ return SkShaper::Make(SkFontMgr::RefEmpty()); }, "default"); );
-#ifdef SK_SHAPER_CORETEXT_AVAILABLE
-DEF_SLIDE( return new TextBoxSlide(SkShaper::MakeCoreText, "coretext"); );
+DEF_SLIDE(return new TextBoxSlide(SkShapers::Primitive,
+ make_trivial_bidi,
+ make_trivial_script_runner,
+ "primitive"););
+
+#if defined(SK_SHAPER_CORETEXT_AVAILABLE)
+DEF_SLIDE(return new TextBoxSlide(SkShapers::CT::CoreText,
+ make_trivial_bidi,
+ make_trivial_script_runner,
+ "coretext"););
+#endif
+
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE)
+DEF_SLIDE(return new TextBoxSlide(
+ []() {
+ auto unicode = make_sk_unicode();
+ return SkShapers::HB::ShaperDrivenWrapper(std::move(unicode),
+ SkFontMgr::RefEmpty());
+ },
+ make_unicode_bidi,
+ make_harfbuzz_script_runner,
+ "harfbuzz"););
#endif
class ShaperSlide : public Slide {
@@ -134,18 +241,43 @@
const char text[] = "world";
for (SkScalar size = 30; size <= 30; size += 10) {
- this->drawTest(canvas, text, size, SkShaper::Make(SkFontMgr::RefEmpty()));
+ this->drawTest(canvas,
+ text,
+ size,
+ SkShapers::Primitive(),
+ make_trivial_bidi,
+ make_trivial_script_runner);
canvas->translate(0, size + 5);
- #ifdef SK_SHAPER_CORETEXT_AVAILABLE
- this->drawTest(canvas, text, size, SkShaper::MakeCoreText());
- #endif
+#if defined(SK_SHAPER_CORETEXT_AVAILABLE)
+ this->drawTest(canvas,
+ text,
+ size,
+ SkShapers::CT::CoreText(),
+ make_trivial_bidi,
+ make_trivial_script_runner);
+#endif
+ canvas->translate(0, size + 5);
+#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
+ auto unicode = make_sk_unicode();
+ this->drawTest(
+ canvas,
+ text,
+ size,
+ SkShapers::HB::ShaperDrivenWrapper(std::move(unicode), SkFontMgr::RefEmpty()),
+ make_unicode_bidi,
+ make_harfbuzz_script_runner);
+#endif
canvas->translate(0, size*2);
}
}
private:
- void drawTest(SkCanvas* canvas, const char str[], SkScalar size,
- std::unique_ptr<SkShaper> shaper) {
+ void drawTest(SkCanvas* canvas,
+ const char str[],
+ SkScalar size,
+ std::unique_ptr<SkShaper> shaper,
+ MakeBidiIteratorCallback bidiCallback,
+ MakeScriptRunCallback scriptRunCallback) {
if (!shaper) return;
SkTextBlobBuilderRunHandler builder(str, {0, 0});
@@ -156,8 +288,9 @@
size_t len = strlen(str);
- std::unique_ptr<SkShaper::BiDiRunIterator> bidi(
- SkShaper::MakeBiDiRunIterator(str, len, 0xfe));
+ std::unique_ptr<SkUnicode> unicode = make_sk_unicode();
+ std::unique_ptr<SkShaper::BiDiRunIterator> bidi =
+ bidiCallback(unicode.get(), str, len, 0xfe);
if (!bidi) {
return;
}
@@ -170,7 +303,7 @@
SkFourByteTag undeterminedScript = SkSetFourByteTag('Z','y','y','y');
std::unique_ptr<SkShaper::ScriptRunIterator> script(
- SkShaper::MakeScriptRunIterator(str, len, undeterminedScript));
+ scriptRunCallback(str, len, undeterminedScript));
if (!script) {
return;
}
@@ -187,11 +320,10 @@
return;
}
- shaper->shape(str, len, *font, *bidi, *script, *language, 2000, &builder);
+ shaper->shape(str, len, *font, *bidi, *script, *language, nullptr, 0, 2000, &builder);
canvas->drawTextBlob(builder.makeBlob(), 0, 0, SkPaint());
}
-
};
DEF_SLIDE( return new ShaperSlide; );