成熟丰满熟妇高潮XXXXX,人妻无码AV中文系列久久兔费 ,国产精品一国产精品,国精品午夜福利视频不卡麻豆

您好,歡迎來到九壹網(wǎng)。
搜索
您的當前位置:首頁harfbuzz-ng如何選擇一個shaper

harfbuzz-ng如何選擇一個shaper

來源:九壹網(wǎng)

harfbuzz-ng如何選擇一個shaper

harfbuzz-ng在shape文字時,依然是會根據(jù)文字的特點,選中一個種shaper,然后再將實際shape的過程都交給shaper來處理這樣。只是在harfbuzz-ng中,不像在老版harfbuzz中那樣,是簡單的依據(jù)所傳入字串的script,通過一個表就直接地選定一個shaper,而是在參考字串的特性(script)之外,還會參考字庫文件本身的特征,來最終選定一個shaper。同時,harfbuzz-ng中的shaper與老版harfbuzz中的shaper在概念上也有一定的區(qū)別。老版harfbuzz中的shaper基本上都是針對某種特定的語言而實現(xiàn),并借助于內(nèi)部的OpenType處理功能,來提供OpenType的高級渲染操作,可以稱為是語言shaper吧。而在harfbuzz-ng中,其shaper則主要包括Graphite2 shaper,OpenType shaper這樣的一些,可以稱為是字庫shaper吧。借助于harfbuzz-ng這樣的一種結(jié)構(gòu),用戶可以只為harfbuzz-ng編寫一個客戶端,然后簡單的將Graphite2之類的其他shape engine接到harfbuzz-ng下面,以實現(xiàn)對字串的最優(yōu)化shaping。harfbuzz-ng本身主要是實現(xiàn)了OpenType shaper,因而下面我們也會更多的關(guān)注與OpenType shaper有關(guān)的一些內(nèi)容。下面我們就來看一下,在harfbuzz-ng中,選擇shaper的邏輯是怎樣的吧。當然,下面的code分析,一定是基于harfbuzz某個特定的版本的,這個版本實際上是0.9.10,harfbuzz目前都還依然處于開放狀態(tài)中,本文的分析對于未來的某些版本也可能會有不適用的狀況。

harfbuzz-ng shape文本的主流程

首先,來看一下harfbuzz-ng的主入口函數(shù)hb_shape():

void
hb_shape (hb_font_t           *font,
	  hb_buffer_t         *buffer,
	  const hb_feature_t  *features,
	  unsigned int         num_features)
{
  hb_shape_full (font, buffer, features, num_features, NULL);
}

這個函數(shù)接收font和buffer參數(shù),其中font里面包含有與字體相關(guān)的信息,比如所使用的字庫文件的內(nèi)容,字體的大小等;而buffer中則包含有關(guān)于字串的信息,比如字串的內(nèi)容,字串的方向和script等。而這個函數(shù)的?features??和?num_features?參數(shù)常常是NULL和0,因為客戶端通常都不需要自己來確定shape一個字串所需要的features嘛,選擇到底要使用那些features的工作,完全交給harfbuzz-ng來就行了。完成對字串的shaping之后,結(jié)果會通過傳入的buffer參數(shù)返回給調(diào)用者。

可以看到hb_shape()的定義倒是簡單的很,就只是調(diào)用了hb_shape_full()來完成所有的工作而已。接下來來看一下hb_shape_full()的實現(xiàn):

hb_bool_t
hb_shape_full (hb_font_t          *font,
	       hb_buffer_t        *buffer,
	       const hb_feature_t *features,
	       unsigned int        num_features,
	       const char * const *shaper_list)
{
  if (unlikely (!buffer->len))
    return true;

  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);

  buffer->guess_segment_properties ();

  hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list);
  hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
  hb_shape_plan_destroy (shape_plan);

  if (res)
    buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
  return res;
}

可以看到這個函數(shù)對字串做shape的過程:

不過所謂的shape plan究竟是個什么東西呢?先來看一下hb_shape_plan_t的定義:

struct hb_shape_plan_t
{
  hb_object_header_t header;
  ASSERT_POD ();

  hb_bool_t default_shaper_list;
  hb_face_t *face;
  hb_segment_properties_t props;

  hb_shape_func_t *shaper_func;
  const char *shaper_name;

  struct hb_shaper_data_t shaper_data;
};

在harfbuzz-ng中,hb_face_t是一個字庫文件的抽象,harfbuzz-ng可以借助于這個對象來獲取字庫文件的一些內(nèi)容,比如獲取OpenType的表等;而hb_segment_properties_t則主要保存字串屬性相關(guān)的一些信息,包括script,direction和language等。可以看到,這個結(jié)構(gòu)前面的幾個字段,主要是與字庫文件(face)和字串屬性(props)有關(guān)的一些內(nèi)容,而后面的幾個字段,則是與選中的shaper有關(guān)的一些內(nèi)容。不難理解,創(chuàng)建shape plan的過程,大體上應(yīng)該是,用client傳入的參數(shù),設(shè)置前面的幾個字段(default_shaper_list,face和props),然后依據(jù)于client傳入的參數(shù),創(chuàng)建或者確定后面幾個字段(shaper_func,shaper_name和shaper_data)的內(nèi)容。接著,我們就來看一下,harfbuzz-ng到底是如何完成這一切的吧。

hb_shape_plan_create_cached() --- shape plan創(chuàng)建的主要流程

前面提到,hb_shape_plan_create_cached()函數(shù)創(chuàng)建shape plan,那么我們就先來看一下這個函數(shù)的定義

hb_shape_plan_t *
hb_shape_plan_create_cached (hb_face_t                     *face,
			     const hb_segment_properties_t *props,
			     const hb_feature_t            *user_features,
			     unsigned int                   num_user_features,
			     const char * const            *shaper_list)
{
  if (num_user_features)
    return hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);

  hb_shape_plan_proposal_t proposal = {
    *props,
    shaper_list,
    NULL
  };

  if (shaper_list) {
    /* Choose shaper.  Adapted from hb_shape_plan_plan(). */
#define HB_SHAPER_PLAN(shaper) \
	  HB_STMT_START { \
	    if (hb_##shaper##_shaper_face_data_ensure (face)) \
	      proposal.shaper_func = _hb_##shaper##_shape; \
	  } HB_STMT_END

    for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++)
      if (0)
	;
#define HB_SHAPER_IMPLEMENT(shaper) \
      else if (0 == strcmp (*shaper_item, #shaper)) \
	HB_SHAPER_PLAN (shaper);
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT

#undef HB_SHAPER_PLAN

    if (unlikely (!proposal.shaper_list))
      return hb_shape_plan_get_empty ();
  }


retry:
  hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans);
  for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
    if (hb_shape_plan_matches (node->shape_plan, &proposal))
      return hb_shape_plan_reference (node->shape_plan);

  /* Not found. */

  hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);

  hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
  if (unlikely (!node))
    return shape_plan;

  node->shape_plan = shape_plan;
  node->next = cached_plan_nodes;

  if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) {
    hb_shape_plan_destroy (shape_plan);
    free (node);
    goto retry;
  }

  /* Release our reference on face. */
  hb_face_destroy (face);

  return hb_shape_plan_reference (shape_plan);
}

可以看到,這個函數(shù)正是主要依據(jù)于faceprops來創(chuàng)建shape plan的。這個函數(shù)中為兩種情況做了一些特殊的處理:第一種是num_user_features大于0的情況,即客戶端指定了一些features;第二種是shaper_list非空的情況,即客戶端已經(jīng)提供了一個shaper列表給harfbuzz-ng來選則適當?shù)膕haper。

第一種情況簡單明了,會直接調(diào)用hb_shape_plan_create()函數(shù)來創(chuàng)建shape plan,此處不再多說,后面會再來說明這個函數(shù)的定義。那就來看一下第二種情況的一些特殊處理:

if (shaper_list) {
    /* Choose shaper.  Adapted from hb_shape_plan_plan(). */
#define HB_SHAPER_PLAN(shaper) \
	  HB_STMT_START { \
	    if (hb_##shaper##_shaper_face_data_ensure (face)) \
	      proposal.shaper_func = _hb_##shaper##_shape; \
	  } HB_STMT_END

    for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++)
      if (0)
	;
#define HB_SHAPER_IMPLEMENT(shaper) \
      else if (0 == strcmp (*shaper_item, #shaper)) \
	HB_SHAPER_PLAN (shaper);
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT

#undef HB_SHAPER_PLAN

    if (unlikely (!proposal.shaper_list))
      return hb_shape_plan_get_empty ();
  }

這段code看起來還真夠奇怪的。這都是些什么東西嘛。只是定義了兩個宏,HB_SHAPER_PLANHB_SHAPER_IMPLEMENT,然后外加一個什么也沒做的空循環(huán),在然后就是include了一個文件而已。難道include的那個文件暗藏玄機?沒錯,所有的秘密還確實都在那個文件里了。我們來看一下那個hb-shaper-list.hh的內(nèi)容

#ifndef HB_SHAPER_LIST_HH
#define HB_SHAPER_LIST_HH
#endif /* HB_SHAPER_LIST_HH */ /* Dummy header guards */

/* v--- Add new shapers in the right place here. */

#ifdef HAVE_GRAPHITE2
/* Only picks up fonts that have a "Silf" table. */
HB_SHAPER_IMPLEMENT (graphite2)
#endif

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

#ifdef HAVE_HB_OLD
HB_SHAPER_IMPLEMENT (old)
#endif
#ifdef HAVE_ICU_LE
HB_SHAPER_IMPLEMENT (icu_le)
#endif
#ifdef HAVE_UNISCRIBE
HB_SHAPER_IMPLEMENT (uniscribe)
#endif
#ifdef HAVE_CORETEXT
HB_SHAPER_IMPLEMENT (coretext)
#endif

HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */

至此,那兩個宏的作用看起來就清晰多了嘛。根據(jù)這個文件中的內(nèi)容,將前面看到的那兩個宏都解開來看那段code到底是什么:

if (shaper_list) {
    for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++)
      if (0)
        ;
      else if (0 == strcmp (*shaper_item, "graphite2"))
        do {
          if (hb_graphite_shaper_face_data_ensure (face)) 
	     proposal.shaper_func = _hb_graphite_shape; 
        } wihle (0);
      else if (0 == strcmp (*shaper_item, "ot"))
        do {
          if (hb_ot_shaper_face_data_ensure (face)) 
            proposal.shaper_func = _hb_ot_shape; 
        } wihle (0);
      else if (0 == strcmp (*shaper_item, "fallback"))
        do {
          if (hb_fallback_shaper_face_data_ensure (face)) 
            proposal.shaper_func = _hb_fallback_shape; 
        } wihle (0); 
      if (unlikely (!proposal.shaper_list))
          return hb_shape_plan_get_empty ();
  }

當然,這個也不一定就是前面那段code將宏解開的真實結(jié)果。由hb-shaper-list.hh的內(nèi)容,我們知道,for循環(huán)下的else-if block的數(shù)量和內(nèi)容,都會依賴于到底有多少種shaper是通過宏而被enabled起來的。不過,有兩種shaper是必定會被enabled的,一種是harfbuzz-ng實現(xiàn)的ot,另外一種就是fallback。

由這段code來看,前面所提到的針對第二種情況的特殊處理,其實也就是補足proposalshape_func相關(guān)的信息,以便于后面在匹配shape plan時,能有更多的依據(jù)。

這段code會逐個的檢查傳進來的那個shaper_list中的shaper,以確定合適的shaper。它會調(diào)用shaper的hb_##shaper##_shaper_face_data_ensure()函數(shù),比如hb_ot_shaper_face_data_ensure()等,來檢查相應(yīng)的shaper是否能夠處理傳入的那個face(字庫文件),如果可以,則將相應(yīng)的shaper_func函數(shù)賦給proposal.shaper_func

那么,在選擇shaper的時候為什么會需要對字庫做檢查呢?因為確實有一些shaper對字庫有特殊的要求,比如ot的shaper就要求傳入的字庫必須是一個OpenType字庫,而不能是簡單的TrueType字庫,graphite2的shaper則對字庫有更高的要求。

根據(jù)需要(shaper_list非空的那段code,通常都不會執(zhí)行到,shaper_list為空的時候多),對第二種情況作了proposalshape_func相關(guān)信息的補充之后,hb_shape_plan_create_cached()函數(shù)就會從face對象中取出一個緩存的hb_face_t::plan_node_t鏈表(face->shape_plans),并檢查是否能夠找到proposal所描述的shape plan,若可以找到則將shape plan返回給調(diào)用者,創(chuàng)建shape plan的過程就算結(jié)束了。

hb_shape_plan_create_cached()函數(shù)沒能在face的緩存中找到所需要的shape plan的話,則它就會調(diào)用hb_shape_plan_create()來創(chuàng)建一個,將這個shape plan緩存進face的shape_plans鏈表里去,并返回剛剛創(chuàng)建的這個shape plan。

hb_##shaper##_shaper_face_data_ensure (face) ?--- 對字庫文件做檢查

那個所謂的對字庫的檢查到底是如何進行的呢?以ot的shaper為例,來看一下字庫檢查都做了些什么事情。來看hb_ot_shaper_face_data_ensure()函數(shù)的定義,它是通過一個宏在相同的文件(hb-shape-plan.cc)中完成的

#define HB_SHAPER_IMPLEMENT(shaper) \
	HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face) \
	HB_SHAPER_DATA_ENSURE_DECLARE(shaper, font)
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT

然后,我們繼續(xù)追蹤,來看宏HB_SHAPER_DATA_ENSURE_DECLARE的定義(在hb-shaper-private.hh中):

#define HB_SHAPER_DATA_ENSURE_DECLARE(shaper, object) \
static inline bool \
hb_##shaper##_shaper_##object##_data_ensure (hb_##object##_t *object) \
{\
  retry: \
  HB_SHAPER_DATA_TYPE (shaper, object) *data = (HB_SHAPER_DATA_TYPE (shaper, object) *) hb_atomic_ptr_get (&HB_SHAPER_DATA (shaper, object)); \
  if (unlikely (!data)) { \
    data = HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (object); \
    if (unlikely (!data)) \
      data = (HB_SHAPER_DATA_TYPE (shaper, object) *) HB_SHAPER_DATA_INVALID; \
    if (!hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), NULL, data)) { \
      HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data); \
      goto retry; \
    } \
  } \
  return data != NULL && !HB_SHAPER_DATA_IS_INVALID (data); \
}
這么大一坨,都是些什么東西嘛。又是引用了一堆的宏,真是看得人暈死了。不用急,可以先逐個的看一下那些宏到底是怎么定義的,然后根據(jù)那些宏的定義,再逐行的解開這個函數(shù)就都大白了? 。首先是 HB_SHAPER_DATA, HB_SHAPER_DATA_INSTANCE和 HB_SHAPER_DATA_TYPE的定義:

#define HB_SHAPER_DATA_TYPE(shaper, object)		struct hb_##shaper##_shaper_##object##_data_t
#define HB_SHAPER_DATA_INSTANCE(shaper, object, instance)	(* (HB_SHAPER_DATA_TYPE(shaper, object) **) &(instance)->shaper_data.shaper)
#define HB_SHAPER_DATA(shaper, object)			HB_SHAPER_DATA_INSTANCE (shaper, object, object)

我們知道,用于實現(xiàn)hb_ot_shaper_face_data_ensure()這個函數(shù)時,HB_SHAPER_DATA_ENSURE_DECLARE(shaper, object)宏的shaper是“ot”,而object是“face”。先來解開如下的這一行:

HB_SHAPER_DATA_TYPE (shaper, object) *data = (HB_SHAPER_DATA_TYPE (shaper, object) *) hb_atomic_ptr_get (&HB_SHAPER_DATA (shaper, object));

可以看到這一行實際上是:

struct hb_ot_shaper_face_data_t *data = (struct hb_ot_shaper_face_data_t *) hb_atomic_ptr_get (&(*(struct hb_ot_shaper_face_data_t**)&face->shaper_data.ot));

到底是什么意思呢?說白了就是從face對象里面拿了一個數(shù)據(jù)成員出來,即face->shaper_data.ot。那它拿的那個成員到底又是怎么一回事呢?可以再來跟一下hb_face_t定義中與這個部分有關(guān)的一些內(nèi)容。來看一下那個shaper_data成員是個什么東西:

struct hb_face_t {
  hb_object_header_t header;
  ASSERT_POD ();

  hb_bool_t immutable;

  hb_reference_table_func_t  reference_table_func;
  void                      *user_data;
  hb_destroy_func_t          destroy;

  unsigned int index;
  mutable unsigned int upem;
  mutable unsigned int num_glyphs;

  struct hb_shaper_data_t shaper_data;

shaper_data的類型是hb_shaper_data_t,然后來看hb_shaper_data_t的定義:

struct hb_shaper_data_t {
#define HB_SHAPER_IMPLEMENT(shaper) void *shaper;
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
};

聯(lián)系我們前面看到的hb-shaper-list.hh文件的內(nèi)容,可以發(fā)現(xiàn)hb_shaper_data_t就只是包含了一些void *類型的指針而已。 因而前面取出數(shù)據(jù)的那個過程,其實就是取出一個void *指針,然后做強制類型轉(zhuǎn)換。

讓我們回到HB_SHAPER_DATA_ENSURE_DECLARE的定義,接著來看HB_SHAPER_DATA_CREATE_FUNC宏的定義:

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

展開這個宏就是:

_hb_ot_shaper_face_data_create

它其實是定義在hb-ot-shape.cc中的一個函數(shù):

hb_ot_shaper_face_data_t *
_hb_ot_shaper_face_data_create (hb_face_t *face)
{
  return _hb_ot_layout_create (face);
}

至此,我們可以來總結(jié)一下hb_ot_shaper_face_data_ensure()函數(shù)所做的事情:它會從face對象里面拿到對應(yīng)于ot shaper的shaper_data,也就是一個struct hb_ot_shaper_face_data_t?對象,檢查一下是否為空;若為空,他就會去創(chuàng)建一個struct hb_ot_shaper_face_data_t?對象,并賦給face->shaper_data的ot成員face->shaper_data.ot。可以再多來看一點,那個struct hb_ot_shaper_face_data_t的實際類型是struct hb_ot_layout_t

#define hb_ot_shaper_face_data_t hb_ot_layout_t

hb_ot_shaper_face_data_ensure()函數(shù)以什么為依據(jù)來判斷face所代表的字庫是ot shaper所能處理的字庫呢?就是看那個data對象是否能創(chuàng)建成功并且有效。

可見hb_ot_shaper_face_data_ensure()函數(shù)可能不僅僅是做check,它還可能新創(chuàng)建一個特定于shaper的結(jié)構(gòu),由face傳出,以供后面shaper的func在執(zhí)行時使用。

hb_shape_plan_create() --- 實際創(chuàng)建shape plan

來看hb_shape_plan_create_cached()中另外的一個重要函數(shù),也就是實際完成創(chuàng)建shape plan動作的hb_shape_plan_create()函數(shù),來看它的定義:

hb_shape_plan_t *
hb_shape_plan_create (hb_face_t                     *face,
		      const hb_segment_properties_t *props,
		      const hb_feature_t            *user_features,
		      unsigned int                   num_user_features,
		      const char * const            *shaper_list)
{
  assert (props->direction != HB_DIRECTION_INVALID);

  hb_shape_plan_t *shape_plan;

  if (unlikely (!face))
    face = hb_face_get_empty ();
  if (unlikely (!props || hb_object_is_inert (face)))
    return hb_shape_plan_get_empty ();
  if (!(shape_plan = hb_object_create<hb_shape_plan_t> ()))
    return hb_shape_plan_get_empty ();

  hb_face_make_immutable (face);
  shape_plan->default_shaper_list = shaper_list == NULL;
  shape_plan->face = hb_face_reference (face);
  shape_plan->props = *props;

  hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list);

  return shape_plan;
}

可以看到,這個函數(shù)主要是為hb_shape_plan_t對象分配了內(nèi)存空間,簡單地初始化了一些變量,完了之后便調(diào)用另外的一個函數(shù)hb_shape_plan_plan()來對hb_shape_plan_t對象做更細致的設(shè)置。來看hb_shape_plan_plan()的定義:

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)
{
  const hb_shaper_pair_t *shapers = _hb_shapers_get ();

#define HB_SHAPER_PLAN(shaper) \
	HB_STMT_START { \
	  if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face)) { \
	    HB_SHAPER_DATA (shaper, shape_plan) = \
	      HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \
	    shape_plan->shaper_func = _hb_##shaper##_shape; \
	    shape_plan->shaper_name = #shaper; \
	    return; \
	  } \
	} HB_STMT_END

  if (likely (!shaper_list)) {
    for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
      if (0)
	;
#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 {
    for (; *shaper_list; shaper_list++)
      if (0)
	;
#define HB_SHAPER_IMPLEMENT(shaper) \
      else if (0 == strcmp (*shaper_list, #shaper)) \
	HB_SHAPER_PLAN (shaper);
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
  }

#undef HB_SHAPER_PLAN
}

又是一大堆宏在這兒繞來繞去。不過沒關(guān)系,畢竟這個函數(shù)的結(jié)構(gòu)總體看起來還算清晰。定義宏,然后通過include?"hb-shaper-list.hh"文件而產(chǎn)生代碼的這種手法,在前面是已經(jīng)有見識過了,因而這個部分的邏輯應(yīng)該也還不難理解。這個函數(shù)首先是調(diào)用了_hb_shapers_get ()函數(shù)獲取到一個hb_shaper_pair_t的列表,然后分為shaper_list為空和非空兩種情況來處理。先來看一下hb_shaper_pair_t的定義:

struct hb_shaper_pair_t {
  char name[16];
  hb_shape_func_t *func;
};

這個結(jié)構(gòu)只有兩個成員,一個是shaper的name,另外一個就是shape func,一個函數(shù)指針,其他不需要做過多的解釋。

shaper_list為空時,也是執(zhí)行這個函數(shù)最經(jīng)常出現(xiàn)的情況,在那個if block里面實現(xiàn),由里面的for循環(huán),不難看出這個函數(shù)是會從_hb_shapers_get()返回的shaper list中挑選一個。由if block里面的else-if語句,可以知道,for循環(huán)每遍歷到一個shaper,就總有一個else-if能與之匹配,所以else-if語句僅有的作用,就只是幫助它的HB_SHAPER_PLAN()來識別一個shaper而已。而選擇shaper的主要依據(jù),還得看HB_SHAPER_PLAN()宏,展開這個宏的定義,可以發(fā)現(xiàn),此處也一樣是調(diào)用hb_##shaper##_shaper_face_data_ensure()函數(shù)來對字庫文件做檢查,而這個函數(shù)算是我們的老朋友了,如前所述,它主要是創(chuàng)建一個face data,若創(chuàng)建成功,harfbuzz-ng就認為相應(yīng)的shaper是可用的。

選擇一個shaper的具體含義又是什么呢?可以看宏HB_SHAPER_PLAN()接下來的幾行,首先是,通過一個函數(shù)_hb_##shaper##_shaper_##object##_data_create(),創(chuàng)建一個shape_plan的data,并賦值給shape_plan->shaper_data.shaper。比如,對于ot shaper,就是調(diào)用_hb_ot_shaper_shape_plan_data_create()函數(shù),創(chuàng)建一個struct hb_ot_shaper_shape_plan_data_t對象,并賦值給shape_plan->shaper_data.ot,以返回給調(diào)用者。接下來便是設(shè)置shape_plan的shaper_func為對應(yīng)shaper的shaper_func。最后就是將shape_plan的shaper_name設(shè)置為對應(yīng)shaper的shaper_name。

shaper_list非空時,又是怎樣的一個執(zhí)行過程呢?有相應(yīng)的block里面的code來看,它與shaper_list為空時,有兩點區(qū)別,一是,它在調(diào)用者傳進來的shaper_list中來選擇;二是,它是通過shaper的shaper_name類識別一個shaper的,而不像前面的case,是通過shaper_func來識別一個shaper。其他則都完全一樣。

總結(jié)

此處我們來總結(jié)一下,harfbuzz-ng選擇一個shaper的過程。首先,harfbuzz-ng是通過調(diào)用shaper的hb_##shaper##_shaper_face_data_ensure()函數(shù)來確定那個shaper是否可用的,這個函數(shù)實際上算是在對字庫文件做檢查,它會創(chuàng)建一個face data,若創(chuàng)建成功,則認為相應(yīng)的shaper可用,否則,認為shaper不可用。這個函數(shù)還會將創(chuàng)建的face data賦值給face->shaper_data.shaper,以返回給調(diào)用者。確定了一個shaper可用之后,harfbuzz-ng還會通過調(diào)用shaper的_hb_##shaper##_shaper_shape_plan_data_create()函數(shù)創(chuàng)建一個shape plan的data,并通過shape_plan->shaper_data.shaper返回給調(diào)用者。然后就是為shape_plan設(shè)置適當?shù)膕haper_func和shaper_name,其中的shaper_func是名為_hb_##shaper##_shape的函數(shù)。另外,就是harfbuzz-ng在選擇shaper時是有按一定的優(yōu)先級的,在hb-shaper-list.hh文件中,被列出的越靠前的shaper,其優(yōu)先級就相應(yīng)的越高。

轉(zhuǎn)載于:https://my.oschina.net/wolfcs/blog/143250

因篇幅問題不能全部顯示,請點此查看更多更全內(nèi)容

Copyright ? 2019- 91gzw.com 版權(quán)所有 湘ICP備2023023988號-2

違法及侵權(quán)請聯(lián)系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市萬商天勤律師事務(wù)所王興未律師提供法律服務(wù)