2626#include " include/private/SkTo.h"
2727#include " modules/skshaper/include/SkShaper.h"
2828#include " src/core/SkMakeUnique.h"
29+ #include " src/core/SkSpan.h"
2930#include " src/core/SkTDPQueue.h"
3031#include " src/utils/SkUTF.h"
3132
5051#include " SkLoadICU.h"
5152#endif
5253
54+ // HB_FEATURE_GLOBAL_START and HB_FEATURE_GLOBAL_END were not added until HarfBuzz 2.0
55+ // They would have always worked, they just hadn't been named yet.
56+ #if !defined(HB_FEATURE_GLOBAL_START)
57+ # define HB_FEATURE_GLOBAL_START 0
58+ #endif
59+ #if !defined(HB_FEATURE_GLOBAL_END)
60+ # define HB_FEATURE_GLOBAL_END ((unsigned int ) -1 )
61+ #endif
62+
5363namespace skstd {
5464template <> struct is_bitmask_enum <hb_buffer_flags_t > : std::true_type {};
5565}
5666
5767namespace {
58- template <typename T, void (*P)(T*)> using resource =
59- std::unique_ptr<T, SkFunctionWrapper<skstd::remove_pointer_t <decltype (P)>, P>>;
60- using HBBlob = resource<hb_blob_t , &hb_blob_destroy >;
61- using HBFace = resource<hb_face_t , &hb_face_destroy >;
62- using HBFont = resource<hb_font_t , &hb_font_destroy >;
63- using HBBuffer = resource<hb_buffer_t , &hb_buffer_destroy>;
64- using ICUBiDi = resource<UBiDi , &ubidi_close >;
65- using ICUBrk = resource<UBreakIterator, &ubrk_close >;
66- using ICUUText = std::unique_ptr<UText, SkFunctionWrapper<decltype (utext_close), utext_close>>;
68+ template <typename T,typename P,P* p> using resource = std::unique_ptr<T, SkFunctionWrapper<P, p>>;
69+ using HBBlob = resource<hb_blob_t , decltype (hb_blob_destroy) , hb_blob_destroy >;
70+ using HBFace = resource<hb_face_t , decltype (hb_face_destroy) , hb_face_destroy >;
71+ using HBFont = resource<hb_font_t , decltype (hb_font_destroy) , hb_font_destroy >;
72+ using HBBuffer = resource<hb_buffer_t , decltype (hb_buffer_destroy), hb_buffer_destroy>;
73+ using ICUBiDi = resource<UBiDi , decltype (ubidi_close) , ubidi_close >;
74+ using ICUBrk = resource<UBreakIterator, decltype (ubrk_close) , ubrk_close >;
75+ using ICUUText = resource<UText , decltype (utext_close) , utext_close >;
6776
6877HBBlob stream_to_blob (std::unique_ptr<SkStreamAsset> asset) {
6978 size_t size = asset->getLength ();
@@ -641,7 +650,8 @@ class ShaperHarfBuzz : public SkShaper {
641650 const BiDiRunIterator&,
642651 const LanguageRunIterator&,
643652 const ScriptRunIterator&,
644- const FontRunIterator&) const ;
653+ const FontRunIterator&,
654+ const Feature*, size_t featuresSize) const ;
645655private:
646656 const sk_sp<SkFontMgr> fFontMgr ;
647657 HBBuffer fBuffer ;
@@ -660,12 +670,22 @@ class ShaperHarfBuzz : public SkShaper {
660670 SkScalar width,
661671 RunHandler*) const override ;
662672
673+ void shape (const char * utf8Text, size_t textBytes,
674+ FontRunIterator&,
675+ BiDiRunIterator&,
676+ ScriptRunIterator&,
677+ LanguageRunIterator&,
678+ const Feature*, size_t featuresSize,
679+ SkScalar width,
680+ RunHandler*) const override ;
681+
663682 virtual void wrap (char const * const utf8, size_t utf8Bytes,
664683 const BiDiRunIterator&,
665684 const LanguageRunIterator&,
666685 const ScriptRunIterator&,
667686 const FontRunIterator&,
668687 RunIteratorQueue& runSegmenter,
688+ const Feature*, size_t featuresSize,
669689 SkScalar width,
670690 RunHandler*) const = 0;
671691};
@@ -680,6 +700,7 @@ class ShaperDrivenWrapper : public ShaperHarfBuzz {
680700 const ScriptRunIterator&,
681701 const FontRunIterator&,
682702 RunIteratorQueue& runSegmenter,
703+ const Feature*, size_t featuresSize,
683704 SkScalar width,
684705 RunHandler*) const override ;
685706};
@@ -694,6 +715,7 @@ class ShapeThenWrap : public ShaperHarfBuzz {
694715 const ScriptRunIterator&,
695716 const FontRunIterator&,
696717 RunIteratorQueue& runSegmenter,
718+ const Feature*, size_t featuresSize,
697719 SkScalar width,
698720 RunHandler*) const override ;
699721};
@@ -708,6 +730,7 @@ class ShapeDontWrapOrReorder : public ShaperHarfBuzz {
708730 const ScriptRunIterator&,
709731 const FontRunIterator&,
710732 RunIteratorQueue& runSegmenter,
733+ const Feature*, size_t featuresSize,
711734 SkScalar width,
712735 RunHandler*) const override ;
713736};
@@ -799,6 +822,18 @@ void ShaperHarfBuzz::shape(const char* utf8, size_t utf8Bytes,
799822 LanguageRunIterator& language,
800823 SkScalar width,
801824 RunHandler* handler) const
825+ {
826+ this ->shape (utf8, utf8Bytes, font, bidi, script, language, nullptr , 0 , width, handler);
827+ }
828+
829+ void ShaperHarfBuzz::shape (const char * utf8, size_t utf8Bytes,
830+ FontRunIterator& font,
831+ BiDiRunIterator& bidi,
832+ ScriptRunIterator& script,
833+ LanguageRunIterator& language,
834+ const Feature* features, size_t featuresSize,
835+ SkScalar width,
836+ RunHandler* handler) const
802837{
803838 SkASSERT (handler);
804839 RunIteratorQueue runSegmenter;
@@ -807,7 +842,8 @@ void ShaperHarfBuzz::shape(const char* utf8, size_t utf8Bytes,
807842 runSegmenter.insert (&script, 1 );
808843 runSegmenter.insert (&language, 0 );
809844
810- this ->wrap (utf8, utf8Bytes, bidi, language, script, font, runSegmenter, width, handler);
845+ this ->wrap (utf8, utf8Bytes, bidi, language, script, font, runSegmenter,
846+ features, featuresSize, width, handler);
811847}
812848
813849void ShaperDrivenWrapper::wrap (char const * const utf8, size_t utf8Bytes,
@@ -816,6 +852,7 @@ void ShaperDrivenWrapper::wrap(char const * const utf8, size_t utf8Bytes,
816852 const ScriptRunIterator& script,
817853 const FontRunIterator& font,
818854 RunIteratorQueue& runSegmenter,
855+ const Feature* features, size_t featuresSize,
819856 SkScalar width,
820857 RunHandler* handler) const
821858{
@@ -845,7 +882,8 @@ void ShaperDrivenWrapper::wrap(char const * const utf8, size_t utf8Bytes,
845882 if (modelNeedsRegenerated) {
846883 model = shape (utf8, utf8Bytes,
847884 utf8Start, utf8End,
848- bidi, language, script, font);
885+ bidi, language, script, font,
886+ features, featuresSize);
849887 modelGlyphOffset = 0 ;
850888
851889 SkVector advance = {0 , 0 };
@@ -911,7 +949,8 @@ void ShaperDrivenWrapper::wrap(char const * const utf8, size_t utf8Bytes,
911949 } else {
912950 return shape (utf8, utf8Bytes,
913951 utf8Start, utf8Start + breakIteratorCurrent,
914- bidi, language, script, font);
952+ bidi, language, script, font,
953+ features, featuresSize);
915954 }
916955 }(modelText[breakIteratorCurrent + modelTextOffset]);
917956 auto score = [widthLeft](const ShapedRun& run) -> SkScalar {
@@ -966,6 +1005,7 @@ void ShapeThenWrap::wrap(char const * const utf8, size_t utf8Bytes,
9661005 const ScriptRunIterator& script,
9671006 const FontRunIterator& font,
9681007 RunIteratorQueue& runSegmenter,
1008+ const Feature* features, size_t featuresSize,
9691009 SkScalar width,
9701010 RunHandler* handler) const
9711011{
@@ -1002,7 +1042,8 @@ void ShapeThenWrap::wrap(char const * const utf8, size_t utf8Bytes,
10021042
10031043 runs.emplace_back (shape (utf8, utf8Bytes,
10041044 utf8Start, utf8End,
1005- bidi, language, script, font));
1045+ bidi, language, script, font,
1046+ features, featuresSize));
10061047 ShapedRun& run = runs.back ();
10071048
10081049 uint32_t previousCluster = 0xFFFFFFFF ;
@@ -1192,6 +1233,7 @@ void ShapeDontWrapOrReorder::wrap(char const * const utf8, size_t utf8Bytes,
11921233 const ScriptRunIterator& script,
11931234 const FontRunIterator& font,
11941235 RunIteratorQueue& runSegmenter,
1236+ const Feature* features, size_t featuresSize,
11951237 SkScalar width,
11961238 RunHandler* handler) const
11971239{
@@ -1206,7 +1248,8 @@ void ShapeDontWrapOrReorder::wrap(char const * const utf8, size_t utf8Bytes,
12061248
12071249 runs.emplace_back (shape (utf8, utf8Bytes,
12081250 utf8Start, utf8End,
1209- bidi, language, script, font));
1251+ bidi, language, script, font,
1252+ features, featuresSize));
12101253 }
12111254
12121255 handler->beginLine ();
@@ -1237,11 +1280,12 @@ void ShapeDontWrapOrReorder::wrap(char const * const utf8, size_t utf8Bytes,
12371280ShapedRun ShaperHarfBuzz::shape (char const * const utf8,
12381281 size_t const utf8Bytes,
12391282 char const * const utf8Start,
1240- char const * const utf8End,
1283+ char const * const utf8End,
12411284 const BiDiRunIterator& bidi,
12421285 const LanguageRunIterator& language,
12431286 const ScriptRunIterator& script,
1244- const FontRunIterator& font) const
1287+ const FontRunIterator& font,
1288+ Feature const * const features, size_t const featuresSize) const
12451289{
12461290 size_t utf8runLength = utf8End - utf8Start;
12471291 ShapedRun run (RunHandler::Range (utf8Start - utf8, utf8runLength),
@@ -1274,14 +1318,32 @@ ShapedRun ShaperHarfBuzz::shape(char const * const utf8,
12741318 hb_buffer_set_script (buffer, hb_script_from_iso15924_tag ((hb_tag_t )script.currentScript ()));
12751319 hb_buffer_set_language (buffer, hb_language_from_string (language.currentLanguage (), -1 ));
12761320 hb_buffer_guess_segment_properties (buffer);
1277- // TODO: features
12781321
12791322 // TODO: how to cache hbface (typeface) / hbfont (font)
12801323 HBFont hbFont (create_hb_font (font.currentFont ()));
12811324 if (!hbFont) {
12821325 return run;
12831326 }
1284- hb_shape (hbFont.get (), buffer, nullptr , 0 );
1327+
1328+ SkSTArray<32 , hb_feature_t > hbFeatures;
1329+ for (const auto & feature : SkMakeSpan (features, featuresSize)) {
1330+ if (feature.end < SkTo<size_t >(utf8Start - utf8) ||
1331+ SkTo<size_t >(utf8End - utf8) <= feature.start )
1332+ {
1333+ continue ;
1334+ }
1335+ if (feature.start <= SkTo<size_t >(utf8Start - utf8) &&
1336+ SkTo<size_t >(utf8End - utf8) <= feature.end )
1337+ {
1338+ hbFeatures.push_back ({ (hb_tag_t )feature.tag , feature.value ,
1339+ HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END});
1340+ } else {
1341+ hbFeatures.push_back ({ (hb_tag_t )feature.tag , feature.value ,
1342+ SkTo<unsigned >(feature.start ), SkTo<unsigned >(feature.end )});
1343+ }
1344+ }
1345+
1346+ hb_shape (hbFont.get (), buffer, hbFeatures.data (), hbFeatures.size ());
12851347 unsigned len = hb_buffer_get_length (buffer);
12861348 if (len == 0 ) {
12871349 return run;
0 commit comments