Home | History | Annotate | Download | only in src
      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 #define HB_SHAPER_IMPLEMENT(shaper) \
     33 	HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face) \
     34 	HB_SHAPER_DATA_ENSURE_DECLARE(shaper, font)
     35 #include "hb-shaper-list.hh"
     36 #undef HB_SHAPER_IMPLEMENT
     37 
     38 
     39 static void
     40 hb_shape_plan_plan (hb_shape_plan_t    *shape_plan,
     41 		    const hb_feature_t *user_features,
     42 		    unsigned int        num_user_features,
     43 		    const char * const *shaper_list)
     44 {
     45   const hb_shaper_pair_t *shapers = _hb_shapers_get ();
     46 
     47 #define HB_SHAPER_PLAN(shaper) \
     48 	HB_STMT_START { \
     49 	  if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face)) { \
     50 	    HB_SHAPER_DATA (shaper, shape_plan) = \
     51 	      HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \
     52 	    shape_plan->shaper_func = _hb_##shaper##_shape; \
     53 	    shape_plan->shaper_name = #shaper; \
     54 	    return; \
     55 	  } \
     56 	} HB_STMT_END
     57 
     58   if (likely (!shaper_list)) {
     59     for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
     60       if (0)
     61 	;
     62 #define HB_SHAPER_IMPLEMENT(shaper) \
     63       else if (shapers[i].func == _hb_##shaper##_shape) \
     64 	HB_SHAPER_PLAN (shaper);
     65 #include "hb-shaper-list.hh"
     66 #undef HB_SHAPER_IMPLEMENT
     67   } else {
     68     for (; *shaper_list; shaper_list++)
     69       if (0)
     70 	;
     71 #define HB_SHAPER_IMPLEMENT(shaper) \
     72       else if (0 == strcmp (*shaper_list, #shaper)) \
     73 	HB_SHAPER_PLAN (shaper);
     74 #include "hb-shaper-list.hh"
     75 #undef HB_SHAPER_IMPLEMENT
     76   }
     77 
     78 #undef HB_SHAPER_PLAN
     79 }
     80 
     81 
     82 /*
     83  * hb_shape_plan_t
     84  */
     85 
     86 hb_shape_plan_t *
     87 hb_shape_plan_create (hb_face_t                     *face,
     88 		      const hb_segment_properties_t *props,
     89 		      const hb_feature_t            *user_features,
     90 		      unsigned int                   num_user_features,
     91 		      const char * const            *shaper_list)
     92 {
     93   assert (props->direction != HB_DIRECTION_INVALID);
     94 
     95   hb_shape_plan_t *shape_plan;
     96 
     97   if (unlikely (!face))
     98     face = hb_face_get_empty ();
     99   if (unlikely (!props || hb_object_is_inert (face)))
    100     return hb_shape_plan_get_empty ();
    101   if (!(shape_plan = hb_object_create<hb_shape_plan_t> ()))
    102     return hb_shape_plan_get_empty ();
    103 
    104   hb_face_make_immutable (face);
    105   shape_plan->default_shaper_list = shaper_list == NULL;
    106   shape_plan->face = hb_face_reference (face);
    107   shape_plan->props = *props;
    108 
    109   hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list);
    110 
    111   return shape_plan;
    112 }
    113 
    114 hb_shape_plan_t *
    115 hb_shape_plan_get_empty (void)
    116 {
    117   static const hb_shape_plan_t _hb_shape_plan_nil = {
    118     HB_OBJECT_HEADER_STATIC,
    119 
    120     true, /* default_shaper_list */
    121     NULL, /* face */
    122     HB_SEGMENT_PROPERTIES_DEFAULT, /* props */
    123 
    124     NULL, /* shaper_func */
    125     NULL, /* shaper_name */
    126 
    127     {
    128 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
    129 #include "hb-shaper-list.hh"
    130 #undef HB_SHAPER_IMPLEMENT
    131     }
    132   };
    133 
    134   return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil);
    135 }
    136 
    137 hb_shape_plan_t *
    138 hb_shape_plan_reference (hb_shape_plan_t *shape_plan)
    139 {
    140   return hb_object_reference (shape_plan);
    141 }
    142 
    143 void
    144 hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
    145 {
    146   if (!hb_object_destroy (shape_plan)) return;
    147 
    148 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, shape_plan);
    149 #include "hb-shaper-list.hh"
    150 #undef HB_SHAPER_IMPLEMENT
    151 
    152   hb_face_destroy (shape_plan->face);
    153 
    154   free (shape_plan);
    155 }
    156 
    157 hb_bool_t
    158 hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
    159 			     hb_user_data_key_t *key,
    160 			     void *              data,
    161 			     hb_destroy_func_t   destroy,
    162 			     hb_bool_t           replace)
    163 {
    164   return hb_object_set_user_data (shape_plan, key, data, destroy, replace);
    165 }
    166 
    167 void *
    168 hb_shape_plan_get_user_data (hb_shape_plan_t    *shape_plan,
    169 			     hb_user_data_key_t *key)
    170 {
    171   return hb_object_get_user_data (shape_plan, key);
    172 }
    173 
    174 
    175 hb_bool_t
    176 hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
    177 		       hb_font_t          *font,
    178 		       hb_buffer_t        *buffer,
    179 		       const hb_feature_t *features,
    180 		       unsigned int        num_features)
    181 {
    182   if (unlikely (hb_object_is_inert (shape_plan) ||
    183 		hb_object_is_inert (font) ||
    184 		hb_object_is_inert (buffer)))
    185     return false;
    186 
    187   assert (shape_plan->face == font->face);
    188   assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props));
    189 
    190 #define HB_SHAPER_EXECUTE(shaper) \
    191 	HB_STMT_START { \
    192 	  return HB_SHAPER_DATA (shaper, shape_plan) && \
    193 		 hb_##shaper##_shaper_font_data_ensure (font) && \
    194 		 _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \
    195 	} HB_STMT_END
    196 
    197   if (0)
    198     ;
    199 #define HB_SHAPER_IMPLEMENT(shaper) \
    200   else if (shape_plan->shaper_func == _hb_##shaper##_shape) \
    201     HB_SHAPER_EXECUTE (shaper);
    202 #include "hb-shaper-list.hh"
    203 #undef HB_SHAPER_IMPLEMENT
    204 
    205 #undef HB_SHAPER_EXECUTE
    206 
    207   return false;
    208 }
    209 
    210 
    211 /*
    212  * caching
    213  */
    214 
    215 #if 0
    216 static unsigned int
    217 hb_shape_plan_hash (const hb_shape_plan_t *shape_plan)
    218 {
    219   return hb_segment_properties_hash (&shape_plan->props) +
    220 	 shape_plan->default_shaper_list ? 0 : (intptr_t) shape_plan->shaper_func;
    221 }
    222 #endif
    223 
    224 /* TODO no user-feature caching for now. */
    225 struct hb_shape_plan_proposal_t
    226 {
    227   const hb_segment_properties_t  props;
    228   const char * const            *shaper_list;
    229   hb_shape_func_t               *shaper_func;
    230 };
    231 
    232 static hb_bool_t
    233 hb_shape_plan_matches (const hb_shape_plan_t          *shape_plan,
    234 		       const hb_shape_plan_proposal_t *proposal)
    235 {
    236   return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
    237 	 ((shape_plan->default_shaper_list && proposal->shaper_list == NULL) ||
    238 	  (shape_plan->shaper_func == proposal->shaper_func));
    239 }
    240 
    241 hb_shape_plan_t *
    242 hb_shape_plan_create_cached (hb_face_t                     *face,
    243 			     const hb_segment_properties_t *props,
    244 			     const hb_feature_t            *user_features,
    245 			     unsigned int                   num_user_features,
    246 			     const char * const            *shaper_list)
    247 {
    248   if (num_user_features)
    249     return hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
    250 
    251   hb_shape_plan_proposal_t proposal = {
    252     *props,
    253     shaper_list,
    254     NULL
    255   };
    256 
    257   if (shaper_list) {
    258     /* Choose shaper.  Adapted from hb_shape_plan_plan(). */
    259 #define HB_SHAPER_PLAN(shaper) \
    260 	  HB_STMT_START { \
    261 	    if (hb_##shaper##_shaper_face_data_ensure (face)) \
    262 	      proposal.shaper_func = _hb_##shaper##_shape; \
    263 	  } HB_STMT_END
    264 
    265     for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++)
    266       if (0)
    267 	;
    268 #define HB_SHAPER_IMPLEMENT(shaper) \
    269       else if (0 == strcmp (*shaper_item, #shaper)) \
    270 	HB_SHAPER_PLAN (shaper);
    271 #include "hb-shaper-list.hh"
    272 #undef HB_SHAPER_IMPLEMENT
    273 
    274 #undef HB_SHAPER_PLAN
    275 
    276     if (unlikely (!proposal.shaper_list))
    277       return hb_shape_plan_get_empty ();
    278   }
    279 
    280 
    281 retry:
    282   hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans);
    283   for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
    284     if (hb_shape_plan_matches (node->shape_plan, &proposal))
    285       return hb_shape_plan_reference (node->shape_plan);
    286 
    287   /* Not found. */
    288 
    289   hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
    290 
    291   hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
    292   if (unlikely (!node))
    293     return shape_plan;
    294 
    295   node->shape_plan = shape_plan;
    296   node->next = cached_plan_nodes;
    297 
    298   if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) {
    299     hb_shape_plan_destroy (shape_plan);
    300     free (node);
    301     goto retry;
    302   }
    303 
    304   /* Release our reference on face. */
    305   hb_face_destroy (face);
    306 
    307   return hb_shape_plan_reference (shape_plan);
    308 }
    309 
    310 const char *
    311 hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan)
    312 {
    313   return shape_plan->shaper_name;
    314 }
    315