hb-shaper-list.hhに
#ifdef HAVE_OT HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */ #endif
とかあるけど、この HAVE_OT の定義はどこでされるんだろう?とgrepしてみた。
●底辺プログラマの3種の神器
- gg
- grep
- find
ということで、他力本願に検索で。
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 という連鎖か。