らんだむな記憶

blogというものを体験してみようか!的なー

ちょっとだけharfbuzz(5)

hb-shaper-list.hhに

#ifdef HAVE_OT
HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */
#endif

とかあるけど、この HAVE_OT の定義はどこでされるんだろう?とgrepしてみた。
●底辺プログラマの3種の神器

ということで、他力本願に検索で。
config.hのようだ。

/* Have native OpenType Layout backend */
#define HAVE_OT 1

どうも configure の時に生成されている感じがする。

/* config.h.  Generated from config.h.in by configure.  */

って書いてあるからアタリマエやろ?というのをまず確認しないのが底辺なのである。
なお、git statusで表示されないが、それは .gitignore に

...
/config.cache
/config.guess
/config.h
/config.h.in
/config.log
/config.lt
/config.status
/config.status.lineno
/config.sub
/configure
/configure.lineno
/configure.scan
...

などと書いてあるからだ。

Ubuntuでやっているので、Windows系のDirectWriteは使えないので HAVE_DIRECTWRITE は定義されていないし、OSXでもないので CoreText も使えないということで HAVE_CORETEXT も定義されていない。

さて、init, medi, finaがデフォルトで適用されるのは、 hb-ot-shape-complex-arabic.cc の collect_features_arabic が呼ばれているからなのだと思うが、どうやって呼ばれているのだろう?

[hb-ot-shape-complex-private.hh]

static inline const hb_ot_complex_shaper_t *
hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
{
    ...
    case HB_SCRIPT_ARABIC:
    ...
    case HB_SCRIPT_PSALTER_PAHLAVI:

      /* For Arabic script, use the Arabic shaper even if no OT script tag was found.
       * This is because we do fallback shaping for Arabic script (and not others).
       * But note that Arabic shaping is applicable only to horizontal layout; for
       * vertical text, just use the generic shaper instead. */
      if ((planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT ||
           planner->props.script == HB_SCRIPT_ARABIC) &&
          HB_DIRECTION_IS_HORIZONTAL(planner->props.direction))
        return &_hb_ot_complex_shaper_arabic;
      else
        return &_hb_ot_complex_shaper_default;

というように “private” のくせにおもらし(return &_hb_ot_complex_shaper_arabic;)をしているからのように感じる。どうもharfbuzzは結構おもらしをしていてて、OOPのふりをしてどうにもそうではない。まぁ、classではなくstructが多用されているのでお察しなのだが。ということで、あまり厳格にOOPの目で見るとはまる。
なお、tabstop=8のようである。

そして、上記は hb_ot_shape_complex_categorize は、hb-ot-shape.cc の _hb_ot_shaper_shape_plan_data_create から呼ばれている。
_hb_ot_shaper_shape_plan_data_create が grep ではここしかひっかからない。これは、マクロを使っている予感...。C#の自動実装プロパティみたいなものというかテンプレート関数というかなんというか、マクロ関数を使ってメソッドを生成する系は実装した瞬間は「俺様、Coooool!!!」とか思える部分もないではないが、後から grep で探せなくて、IDEとかの力を使わないとならなくなるのでちょっと嫌だ。
[hb-ot-shape.cc]

hb_ot_shaper_shape_plan_data_t *
_hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
				      const hb_feature_t *user_features,
				      unsigned int        num_user_features)
{
    printf("[%s] called\n", __FUNCTION__);

のようなくっそ底辺なことをするとやはり呼ばれている。一応gdbを使おうかと思ったけど、hb-viewはシェルスクリプトなので、またもや実行ファイル本体ではない...。
hb-shaper-private.hh の

#define HB_SHAPER_DATA_CREATE_FUNC(shaper, object)	_hb_##shaper##_shaper_##object##_data_create

のようだ。

[hb-shape-plan.cc]

static void
hb_shape_plan_plan (hb_shape_plan_t    *shape_plan,
		    const hb_feature_t *user_features,
		    unsigned int        num_user_features,
		    const char * const *shaper_list)
{
    ...
#define HB_SHAPER_IMPLEMENT(shaper) \
      else if (shapers[i].func == _hb_##shaper##_shape) \
        HB_SHAPER_PLAN (shaper);
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT

よく見ると、ここで大量の else if ... else if ... else if がマクロ関数の力で生成されて展開されるんだな。ふぉぉぉぉ...

hb_shape_full@hb-shape.cc -> hb_shape_plan_create_cached@hb-shape-plan.cc -> hb_shape_plan_create@hb-shape-plan.cc -> hb_shape_plan_plan@hb-shape-plan.cc -> _hb_ot_shaper_shape_plan_data_create@hb-ot-shape.cc -> hb_ot_shape_complex_categorize@hb-ot-shape-complex-private.hh という連鎖か。