LCOV - code coverage report
Current view: top level - gfx/harfbuzz/src - hb-shape-plan.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 79 131 60.3 %
Date: 2017-07-14 16:53:18 Functions: 11 17 64.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright © 2012  Google, Inc.
       3             :  *
       4             :  *  This is part of HarfBuzz, a text shaping library.
       5             :  *
       6             :  * Permission is hereby granted, without written agreement and without
       7             :  * license or royalty fees, to use, copy, modify, and distribute this
       8             :  * software and its documentation for any purpose, provided that the
       9             :  * above copyright notice and the following two paragraphs appear in
      10             :  * all copies of this software.
      11             :  *
      12             :  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
      13             :  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
      14             :  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
      15             :  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
      16             :  * DAMAGE.
      17             :  *
      18             :  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
      19             :  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
      20             :  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
      21             :  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
      22             :  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
      23             :  *
      24             :  * Google Author(s): Behdad Esfahbod
      25             :  */
      26             : 
      27             : #include "hb-shape-plan-private.hh"
      28             : #include "hb-shaper-private.hh"
      29             : #include "hb-font-private.hh"
      30             : #include "hb-buffer-private.hh"
      31             : 
      32             : 
      33             : #ifndef HB_DEBUG_SHAPE_PLAN
      34             : #define HB_DEBUG_SHAPE_PLAN (HB_DEBUG+0)
      35             : #endif
      36             : 
      37             : 
      38             : static void
      39           2 : hb_shape_plan_plan (hb_shape_plan_t    *shape_plan,
      40             :                     const hb_feature_t *user_features,
      41             :                     unsigned int        num_user_features,
      42             :                     const int          *coords,
      43             :                     unsigned int        num_coords,
      44             :                     const char * const *shaper_list)
      45             : {
      46             :   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
      47             :                   "num_features=%d num_coords=%d shaper_list=%p",
      48             :                   num_user_features,
      49             :                   num_coords,
      50           2 :                   shaper_list);
      51             : 
      52           2 :   const hb_shaper_pair_t *shapers = _hb_shapers_get ();
      53             : 
      54             : #define HB_SHAPER_PLAN(shaper) \
      55             :         HB_STMT_START { \
      56             :           if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) { \
      57             :             HB_SHAPER_DATA (shaper, shape_plan) = \
      58             :               HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, \
      59             :                                                                user_features, num_user_features, \
      60             :                                                                coords, num_coords); \
      61             :             shape_plan->shaper_func = _hb_##shaper##_shape; \
      62             :             shape_plan->shaper_name = #shaper; \
      63             :             return; \
      64             :           } \
      65             :         } HB_STMT_END
      66             : 
      67           2 :   if (likely (!shaper_list)) {
      68           2 :     for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
      69             :       if (0)
      70             :         ;
      71             : #define HB_SHAPER_IMPLEMENT(shaper) \
      72             :       else if (shapers[i].func == _hb_##shaper##_shape) \
      73             :         HB_SHAPER_PLAN (shaper);
      74             : #include "hb-shaper-list.hh"
      75             : #undef HB_SHAPER_IMPLEMENT
      76             :   } else {
      77           0 :     for (; *shaper_list; shaper_list++)
      78             :       if (0)
      79             :         ;
      80             : #define HB_SHAPER_IMPLEMENT(shaper) \
      81             :       else if (0 == strcmp (*shaper_list, #shaper)) \
      82             :         HB_SHAPER_PLAN (shaper);
      83             : #include "hb-shaper-list.hh"
      84             : #undef HB_SHAPER_IMPLEMENT
      85             :   }
      86             : 
      87             : #undef HB_SHAPER_PLAN
      88             : }
      89             : 
      90             : 
      91             : /*
      92             :  * hb_shape_plan_t
      93             :  */
      94             : 
      95             : /**
      96             :  * hb_shape_plan_create: (Xconstructor)
      97             :  * @face: 
      98             :  * @props: 
      99             :  * @user_features: (array length=num_user_features):
     100             :  * @num_user_features: 
     101             :  * @shaper_list: (array zero-terminated=1):
     102             :  *
     103             :  * 
     104             :  *
     105             :  * Return value: (transfer full):
     106             :  *
     107             :  * Since: 0.9.7
     108             :  **/
     109             : hb_shape_plan_t *
     110           0 : hb_shape_plan_create (hb_face_t                     *face,
     111             :                       const hb_segment_properties_t *props,
     112             :                       const hb_feature_t            *user_features,
     113             :                       unsigned int                   num_user_features,
     114             :                       const char * const            *shaper_list)
     115             : {
     116             :   return hb_shape_plan_create2 (face, props,
     117             :                                 user_features, num_user_features,
     118             :                                 NULL, 0,
     119           0 :                                 shaper_list);
     120             : }
     121             : 
     122             : hb_shape_plan_t *
     123           2 : hb_shape_plan_create2 (hb_face_t                     *face,
     124             :                        const hb_segment_properties_t *props,
     125             :                        const hb_feature_t            *user_features,
     126             :                        unsigned int                   num_user_features,
     127             :                        const int                     *orig_coords,
     128             :                        unsigned int                   num_coords,
     129             :                        const char * const            *shaper_list)
     130             : {
     131             :   DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
     132             :                   "face=%p num_features=%d num_coords=%d shaper_list=%p",
     133             :                   face,
     134             :                   num_user_features,
     135             :                   num_coords,
     136           2 :                   shaper_list);
     137             : 
     138             :   hb_shape_plan_t *shape_plan;
     139           2 :   hb_feature_t *features = NULL;
     140           2 :   int *coords = NULL;
     141             : 
     142           2 :   if (unlikely (!face))
     143           0 :     face = hb_face_get_empty ();
     144           2 :   if (unlikely (!props))
     145           0 :     return hb_shape_plan_get_empty ();
     146           2 :   if (num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
     147           0 :     return hb_shape_plan_get_empty ();
     148           2 :   if (num_coords && !(coords = (int *) calloc (num_coords, sizeof (int))))
     149             :   {
     150           0 :     free (features);
     151           0 :     return hb_shape_plan_get_empty ();
     152             :   }
     153           2 :   if (!(shape_plan = hb_object_create<hb_shape_plan_t> ()))
     154             :   {
     155           0 :     free (coords);
     156           0 :     free (features);
     157           0 :     return hb_shape_plan_get_empty ();
     158             :   }
     159             : 
     160           2 :   assert (props->direction != HB_DIRECTION_INVALID);
     161             : 
     162           2 :   hb_face_make_immutable (face);
     163           2 :   shape_plan->default_shaper_list = shaper_list == NULL;
     164           2 :   shape_plan->face_unsafe = face;
     165           2 :   shape_plan->props = *props;
     166           2 :   shape_plan->num_user_features = num_user_features;
     167           2 :   shape_plan->user_features = features;
     168           2 :   if (num_user_features)
     169           0 :     memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
     170           2 :   shape_plan->num_coords = num_coords;
     171           2 :   shape_plan->coords = coords;
     172           2 :   if (num_coords)
     173           0 :     memcpy (coords, orig_coords, num_coords * sizeof (int));
     174             : 
     175             :   hb_shape_plan_plan (shape_plan,
     176             :                       user_features, num_user_features,
     177             :                       coords, num_coords,
     178           2 :                       shaper_list);
     179             : 
     180           2 :   return shape_plan;
     181             : }
     182             : 
     183             : /**
     184             :  * hb_shape_plan_get_empty:
     185             :  *
     186             :  * 
     187             :  *
     188             :  * Return value: (transfer full):
     189             :  *
     190             :  * Since: 0.9.7
     191             :  **/
     192             : hb_shape_plan_t *
     193           0 : hb_shape_plan_get_empty (void)
     194             : {
     195             :   static const hb_shape_plan_t _hb_shape_plan_nil = {
     196             :     HB_OBJECT_HEADER_STATIC,
     197             : 
     198             :     true, /* default_shaper_list */
     199             :     NULL, /* face */
     200             :     HB_SEGMENT_PROPERTIES_DEFAULT, /* props */
     201             : 
     202             :     NULL, /* shaper_func */
     203             :     NULL, /* shaper_name */
     204             : 
     205             :     NULL, /* user_features */
     206             :     0,    /* num_user_featurs */
     207             : 
     208             :     NULL, /* coords */
     209             :     0,    /* num_coords */
     210             : 
     211             :     {
     212             : #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
     213             : #include "hb-shaper-list.hh"
     214             : #undef HB_SHAPER_IMPLEMENT
     215             :     }
     216             :   };
     217             : 
     218           0 :   return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil);
     219             : }
     220             : 
     221             : /**
     222             :  * hb_shape_plan_reference: (skip)
     223             :  * @shape_plan: a shape plan.
     224             :  *
     225             :  * 
     226             :  *
     227             :  * Return value: (transfer full):
     228             :  *
     229             :  * Since: 0.9.7
     230             :  **/
     231             : hb_shape_plan_t *
     232          34 : hb_shape_plan_reference (hb_shape_plan_t *shape_plan)
     233             : {
     234          34 :   return hb_object_reference (shape_plan);
     235             : }
     236             : 
     237             : /**
     238             :  * hb_shape_plan_destroy: (skip)
     239             :  * @shape_plan: a shape plan.
     240             :  *
     241             :  * 
     242             :  *
     243             :  * Since: 0.9.7
     244             :  **/
     245             : void
     246          34 : hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
     247             : {
     248          34 :   if (!hb_object_destroy (shape_plan)) return;
     249             : 
     250             : #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, shape_plan);
     251             : #include "hb-shaper-list.hh"
     252             : #undef HB_SHAPER_IMPLEMENT
     253             : 
     254           0 :   free (shape_plan->user_features);
     255           0 :   free (shape_plan->coords);
     256             : 
     257           0 :   free (shape_plan);
     258             : }
     259             : 
     260             : /**
     261             :  * hb_shape_plan_set_user_data: (skip)
     262             :  * @shape_plan: a shape plan.
     263             :  * @key: 
     264             :  * @data: 
     265             :  * @destroy: 
     266             :  * @replace: 
     267             :  *
     268             :  * 
     269             :  *
     270             :  * Return value: 
     271             :  *
     272             :  * Since: 0.9.7
     273             :  **/
     274             : hb_bool_t
     275           0 : hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
     276             :                              hb_user_data_key_t *key,
     277             :                              void *              data,
     278             :                              hb_destroy_func_t   destroy,
     279             :                              hb_bool_t           replace)
     280             : {
     281           0 :   return hb_object_set_user_data (shape_plan, key, data, destroy, replace);
     282             : }
     283             : 
     284             : /**
     285             :  * hb_shape_plan_get_user_data: (skip)
     286             :  * @shape_plan: a shape plan.
     287             :  * @key: 
     288             :  *
     289             :  * 
     290             :  *
     291             :  * Return value: (transfer none):
     292             :  *
     293             :  * Since: 0.9.7
     294             :  **/
     295             : void *
     296           0 : hb_shape_plan_get_user_data (hb_shape_plan_t    *shape_plan,
     297             :                              hb_user_data_key_t *key)
     298             : {
     299           0 :   return hb_object_get_user_data (shape_plan, key);
     300             : }
     301             : 
     302             : 
     303             : /**
     304             :  * hb_shape_plan_execute:
     305             :  * @shape_plan: a shape plan.
     306             :  * @font: a font.
     307             :  * @buffer: a buffer.
     308             :  * @features: (array length=num_features):
     309             :  * @num_features: 
     310             :  *
     311             :  * 
     312             :  *
     313             :  * Return value: 
     314             :  *
     315             :  * Since: 0.9.7
     316             :  **/
     317             : hb_bool_t
     318          34 : hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
     319             :                        hb_font_t          *font,
     320             :                        hb_buffer_t        *buffer,
     321             :                        const hb_feature_t *features,
     322             :                        unsigned int        num_features)
     323             : {
     324          34 :   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
     325             :                   "num_features=%d shaper_func=%p, shaper_name=%s",
     326             :                   num_features,
     327             :                   shape_plan->shaper_func,
     328          34 :                   shape_plan->shaper_name);
     329             : 
     330          34 :   if (unlikely (!buffer->len))
     331           0 :     return true;
     332             : 
     333          34 :   assert (!hb_object_is_inert (buffer));
     334          34 :   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
     335             : 
     336          34 :   if (unlikely (hb_object_is_inert (shape_plan)))
     337           0 :     return false;
     338             : 
     339          34 :   assert (shape_plan->face_unsafe == font->face);
     340          34 :   assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props));
     341             : 
     342             : #define HB_SHAPER_EXECUTE(shaper) \
     343             :         HB_STMT_START { \
     344             :           return HB_SHAPER_DATA (shaper, shape_plan) && \
     345             :                  hb_##shaper##_shaper_font_data_ensure (font) && \
     346             :                  _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \
     347             :         } HB_STMT_END
     348             : 
     349             :   if (0)
     350             :     ;
     351             : #define HB_SHAPER_IMPLEMENT(shaper) \
     352             :   else if (shape_plan->shaper_func == _hb_##shaper##_shape) \
     353             :     HB_SHAPER_EXECUTE (shaper);
     354             : #include "hb-shaper-list.hh"
     355             : #undef HB_SHAPER_IMPLEMENT
     356             : 
     357             : #undef HB_SHAPER_EXECUTE
     358             : 
     359           0 :   return false;
     360             : }
     361             : 
     362             : 
     363             : /*
     364             :  * caching
     365             :  */
     366             : 
     367             : #if 0
     368             : static unsigned int
     369             : hb_shape_plan_hash (const hb_shape_plan_t *shape_plan)
     370             : {
     371             :   return hb_segment_properties_hash (&shape_plan->props) +
     372             :          shape_plan->default_shaper_list ? 0 : (intptr_t) shape_plan->shaper_func;
     373             : }
     374             : #endif
     375             : 
     376             : /* User-feature caching is currently somewhat dumb:
     377             :  * it only finds matches where the feature array is identical,
     378             :  * not cases where the feature lists would be compatible for plan purposes
     379             :  * but have different ranges, for example.
     380             :  */
     381             : struct hb_shape_plan_proposal_t
     382             : {
     383             :   const hb_segment_properties_t  props;
     384             :   const char * const            *shaper_list;
     385             :   const hb_feature_t            *user_features;
     386             :   unsigned int                   num_user_features;
     387             :   const int                     *coords;
     388             :   unsigned int                   num_coords;
     389             :   hb_shape_func_t               *shaper_func;
     390             : };
     391             : 
     392             : static inline hb_bool_t
     393          32 : hb_shape_plan_user_features_match (const hb_shape_plan_t          *shape_plan,
     394             :                                    const hb_shape_plan_proposal_t *proposal)
     395             : {
     396          32 :   if (proposal->num_user_features != shape_plan->num_user_features)
     397           0 :     return false;
     398          32 :   for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++)
     399           0 :     if (proposal->user_features[i].tag   != shape_plan->user_features[i].tag   ||
     400           0 :         proposal->user_features[i].value != shape_plan->user_features[i].value ||
     401           0 :         proposal->user_features[i].start != shape_plan->user_features[i].start ||
     402           0 :         proposal->user_features[i].end   != shape_plan->user_features[i].end)
     403           0 :       return false;
     404          32 :   return true;
     405             : }
     406             : 
     407             : static inline hb_bool_t
     408          32 : hb_shape_plan_coords_match (const hb_shape_plan_t          *shape_plan,
     409             :                             const hb_shape_plan_proposal_t *proposal)
     410             : {
     411          32 :   if (proposal->num_coords != shape_plan->num_coords)
     412           0 :     return false;
     413          32 :   for (unsigned int i = 0, n = proposal->num_coords; i < n; i++)
     414           0 :     if (proposal->coords[i] != shape_plan->coords[i])
     415           0 :       return false;
     416          32 :   return true;
     417             : }
     418             : 
     419             : static hb_bool_t
     420          32 : hb_shape_plan_matches (const hb_shape_plan_t          *shape_plan,
     421             :                        const hb_shape_plan_proposal_t *proposal)
     422             : {
     423          64 :   return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
     424          64 :          hb_shape_plan_user_features_match (shape_plan, proposal) &&
     425         128 :          hb_shape_plan_coords_match (shape_plan, proposal) &&
     426          64 :          ((shape_plan->default_shaper_list && proposal->shaper_list == NULL) ||
     427          32 :           (shape_plan->shaper_func == proposal->shaper_func));
     428             : }
     429             : 
     430             : static inline hb_bool_t
     431           2 : hb_non_global_user_features_present (const hb_feature_t *user_features,
     432             :                                      unsigned int        num_user_features)
     433             : {
     434           2 :   while (num_user_features) {
     435           0 :     if (user_features->start != 0 || user_features->end != (unsigned int) -1)
     436           0 :       return true;
     437           0 :     num_user_features--;
     438           0 :     user_features++;
     439             :   }
     440           2 :   return false;
     441             : }
     442             : 
     443             : static inline hb_bool_t
     444           2 : hb_coords_present (const int *coords,
     445             :                    unsigned int num_coords)
     446             : {
     447           2 :   return num_coords != 0;
     448             : }
     449             : 
     450             : /**
     451             :  * hb_shape_plan_create_cached:
     452             :  * @face: 
     453             :  * @props: 
     454             :  * @user_features: (array length=num_user_features):
     455             :  * @num_user_features: 
     456             :  * @shaper_list: (array zero-terminated=1):
     457             :  *
     458             :  * 
     459             :  *
     460             :  * Return value: (transfer full):
     461             :  *
     462             :  * Since: 0.9.7
     463             :  **/
     464             : hb_shape_plan_t *
     465           0 : hb_shape_plan_create_cached (hb_face_t                     *face,
     466             :                              const hb_segment_properties_t *props,
     467             :                              const hb_feature_t            *user_features,
     468             :                              unsigned int                   num_user_features,
     469             :                              const char * const            *shaper_list)
     470             : {
     471             :   return hb_shape_plan_create_cached2 (face, props,
     472             :                                        user_features, num_user_features,
     473             :                                        NULL, 0,
     474           0 :                                        shaper_list);
     475             : }
     476             : 
     477             : hb_shape_plan_t *
     478          34 : hb_shape_plan_create_cached2 (hb_face_t                     *face,
     479             :                               const hb_segment_properties_t *props,
     480             :                               const hb_feature_t            *user_features,
     481             :                               unsigned int                   num_user_features,
     482             :                               const int                     *coords,
     483             :                               unsigned int                   num_coords,
     484             :                               const char * const            *shaper_list)
     485             : {
     486             :   DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
     487             :                   "face=%p num_features=%d shaper_list=%p",
     488             :                   face,
     489             :                   num_user_features,
     490          34 :                   shaper_list);
     491             : 
     492             :   hb_shape_plan_proposal_t proposal = {
     493             :     *props,
     494             :     shaper_list,
     495             :     user_features,
     496             :     num_user_features,
     497             :     NULL
     498          34 :   };
     499             : 
     500          34 :   if (shaper_list) {
     501             :     /* Choose shaper.  Adapted from hb_shape_plan_plan().
     502             :      * Must choose shaper exactly the same way as that function. */
     503           0 :     for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++)
     504             :       if (0)
     505             :         ;
     506             : #define HB_SHAPER_IMPLEMENT(shaper) \
     507             :       else if (0 == strcmp (*shaper_item, #shaper) && \
     508             :                hb_##shaper##_shaper_face_data_ensure (face)) \
     509             :       { \
     510             :         proposal.shaper_func = _hb_##shaper##_shape; \
     511             :         break; \
     512             :       }
     513             : #include "hb-shaper-list.hh"
     514             : #undef HB_SHAPER_IMPLEMENT
     515             : 
     516           0 :     if (unlikely (!proposal.shaper_func))
     517           0 :       return hb_shape_plan_get_empty ();
     518             :   }
     519             : 
     520             : 
     521             : retry:
     522          34 :   hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans);
     523          34 :   for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
     524          32 :     if (hb_shape_plan_matches (node->shape_plan, &proposal))
     525             :     {
     526          32 :       DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
     527          32 :       return hb_shape_plan_reference (node->shape_plan);
     528             :     }
     529             : 
     530             :   /* Not found. */
     531             : 
     532             :   hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props,
     533             :                                                        user_features, num_user_features,
     534             :                                                        coords, num_coords,
     535           2 :                                                        shaper_list);
     536             : 
     537             :   /* Don't add to the cache if face is inert. */
     538           2 :   if (unlikely (hb_object_is_inert (face)))
     539           0 :     return shape_plan;
     540             : 
     541             :   /* Don't add the plan to the cache if there were user features with non-global ranges */
     542           2 :   if (hb_non_global_user_features_present (user_features, num_user_features))
     543           0 :     return shape_plan;
     544             :   /* Don't add the plan to the cache if there were variation coordinates XXX Fix me. */
     545           2 :   if (hb_coords_present (coords, num_coords))
     546           0 :     return shape_plan;
     547             : 
     548           2 :   hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
     549           2 :   if (unlikely (!node))
     550           0 :     return shape_plan;
     551             : 
     552           2 :   node->shape_plan = shape_plan;
     553           2 :   node->next = cached_plan_nodes;
     554             : 
     555           2 :   if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) {
     556           0 :     hb_shape_plan_destroy (shape_plan);
     557           0 :     free (node);
     558           0 :     goto retry;
     559             :   }
     560           2 :   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "inserted into cache");
     561             : 
     562           2 :   return hb_shape_plan_reference (shape_plan);
     563             : }
     564             : 
     565             : /**
     566             :  * hb_shape_plan_get_shaper:
     567             :  * @shape_plan: a shape plan.
     568             :  *
     569             :  * 
     570             :  *
     571             :  * Return value: (transfer none):
     572             :  *
     573             :  * Since: 0.9.7
     574             :  **/
     575             : const char *
     576           0 : hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan)
     577             : {
     578           0 :   return shape_plan->shaper_name;
     579             : }

Generated by: LCOV version 1.13