w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

hb-shape-plan.cc
Go to the documentation of this file.
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.hh"
28 #include "hb-shape-plan.hh"
29 #include "hb-shaper.hh"
30 #include "hb-font.hh"
31 #include "hb-buffer.hh"
32 
33 
34 /**
35  * SECTION:hb-shape-plan
36  * @title: hb-shape-plan
37  * @short_description: Object representing a shaping plan
38  * @include: hb.h
39  *
40  * Shape plans are an internal mechanism. Each plan contains state
41  * describing how HarfBuzz will shape a particular text segment, based on
42  * the combination of segment properties and the capabilities in the
43  * font face in use.
44  *
45  * Shape plans are not used for shaping directly, but can be queried to
46  * access certain information about how shaping will perform, given a set
47  * of specific input parameters (script, language, direction, features,
48  * etc.).
49  *
50  * Most client programs will not need to deal with shape plans directly.
51  **/
52 
53 
54 /*
55  * hb_shape_plan_key_t
56  */
57 
58 bool
60  hb_face_t *face,
61  const hb_segment_properties_t *props,
62  const hb_feature_t *user_features,
63  unsigned int num_user_features,
64  const int *coords,
65  unsigned int num_coords,
66  const char * const *shaper_list)
67 {
68  hb_feature_t *features = nullptr;
70  goto bail;
71 
72  this->props = *props;
73  this->num_user_features = num_user_features;
74  this->user_features = copy ? features : user_features;
75  if (copy && num_user_features)
76  {
78  /* Make start/end uniform to easier catch bugs. */
79  for (unsigned int i = 0; i < num_user_features; i++)
80  {
82  features[0].start = 1;
84  features[0].end = 2;
85  }
86  }
87  this->shaper_func = nullptr;
88  this->shaper_name = nullptr;
89 #ifndef HB_NO_OT_SHAPE
90  this->ot.init (face, coords, num_coords);
91 #endif
92 
93  /*
94  * Choose shaper.
95  */
96 
97 #define HB_SHAPER_PLAN(shaper) \
98  HB_STMT_START { \
99  if (face->data.shaper) \
100  { \
101  this->shaper_func = _hb_##shaper##_shape; \
102  this->shaper_name = #shaper; \
103  return true; \
104  } \
105  } HB_STMT_END
106 
107  if (unlikely (shaper_list))
108  {
109  for (; *shaper_list; shaper_list++)
110  if (false)
111  ;
112 #define HB_SHAPER_IMPLEMENT(shaper) \
113  else if (0 == strcmp (*shaper_list, #shaper)) \
114  HB_SHAPER_PLAN (shaper);
115 #include "hb-shaper-list.hh"
116 #undef HB_SHAPER_IMPLEMENT
117  }
118  else
119  {
120  const hb_shaper_entry_t *shapers = _hb_shapers_get ();
121  for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
122  if (false)
123  ;
124 #define HB_SHAPER_IMPLEMENT(shaper) \
125  else if (shapers[i].func == _hb_##shaper##_shape) \
126  HB_SHAPER_PLAN (shaper);
127 #include "hb-shaper-list.hh"
128 #undef HB_SHAPER_IMPLEMENT
129  }
130 #undef HB_SHAPER_PLAN
131 
132 bail:
133  ::free (features);
134  return false;
135 }
136 
137 bool
139 {
140  if (this->num_user_features != other->num_user_features)
141  return false;
142  for (unsigned int i = 0; i < num_user_features; i++)
143  {
144  if (this->user_features[i].tag != other->user_features[i].tag ||
145  this->user_features[i].value != other->user_features[i].value ||
146  (this->user_features[i].start == HB_FEATURE_GLOBAL_START &&
147  this->user_features[i].end == HB_FEATURE_GLOBAL_END) !=
148  (other->user_features[i].start == HB_FEATURE_GLOBAL_START &&
149  other->user_features[i].end == HB_FEATURE_GLOBAL_END))
150  return false;
151  }
152  return true;
153 }
154 
155 bool
157 {
158  return hb_segment_properties_equal (&this->props, &other->props) &&
159  this->user_features_match (other) &&
160 #ifndef HB_NO_OT_SHAPE
161  this->ot.equal (&other->ot) &&
162 #endif
163  this->shaper_func == other->shaper_func;
164 }
165 
166 
167 /*
168  * hb_shape_plan_t
169  */
170 
171 
172 /**
173  * hb_shape_plan_create: (Xconstructor)
174  * @face: #hb_face_t to use
175  * @props: The #hb_segment_properties_t of the segment
176  * @user_features: (array length=num_user_features): The list of user-selected features
177  * @num_user_features: The number of user-selected features
178  * @shaper_list: (array zero-terminated=1): List of shapers to try
179  *
180  * Constructs a shaping plan for a combination of @face, @user_features, @props,
181  * and @shaper_list.
182  *
183  * Return value: (transfer full): The shaping plan
184  *
185  * Since: 0.9.7
186  **/
189  const hb_segment_properties_t *props,
190  const hb_feature_t *user_features,
191  unsigned int num_user_features,
192  const char * const *shaper_list)
193 {
194  return hb_shape_plan_create2 (face, props,
195  user_features, num_user_features,
196  nullptr, 0,
197  shaper_list);
198 }
199 
200 /**
201  * hb_shape_plan_create2: (Xconstructor)
202  * @face: #hb_face_t to use
203  * @props: The #hb_segment_properties_t of the segment
204  * @user_features: (array length=num_user_features): The list of user-selected features
205  * @num_user_features: The number of user-selected features
206  * @coords: (array length=num_coords): The list of variation-space coordinates
207  * @num_coords: The number of variation-space coordinates
208  * @shaper_list: (array zero-terminated=1): List of shapers to try
209  *
210  * The variable-font version of #hb_shape_plan_create.
211  * Constructs a shaping plan for a combination of @face, @user_features, @props,
212  * and @shaper_list, plus the variation-space coordinates @coords.
213  *
214  * Return value: (transfer full): The shaping plan
215  *
216  * Since: 1.4.0
217  **/
220  const hb_segment_properties_t *props,
221  const hb_feature_t *user_features,
222  unsigned int num_user_features,
223  const int *coords,
224  unsigned int num_coords,
225  const char * const *shaper_list)
226 {
227  DEBUG_MSG_FUNC (SHAPE_PLAN, nullptr,
228  "face=%p num_features=%d num_coords=%d shaper_list=%p",
229  face,
230  num_user_features,
231  num_coords,
232  shaper_list);
233 
235 
236  hb_shape_plan_t *shape_plan;
237 
238  if (unlikely (!props))
239  goto bail;
240  if (!(shape_plan = hb_object_create<hb_shape_plan_t> ()))
241  goto bail;
242 
243  if (unlikely (!face))
244  face = hb_face_get_empty ();
246  shape_plan->face_unsafe = face;
247 
248  if (unlikely (!shape_plan->key.init (true,
249  face,
250  props,
251  user_features,
252  num_user_features,
253  coords,
254  num_coords,
255  shaper_list)))
256  goto bail2;
257 #ifndef HB_NO_OT_SHAPE
258  if (unlikely (!shape_plan->ot.init0 (face, &shape_plan->key)))
259  goto bail3;
260 #endif
261 
262  return shape_plan;
263 
264 #ifndef HB_NO_OT_SHAPE
265 bail3:
266 #endif
267  shape_plan->key.free ();
268 bail2:
269  free (shape_plan);
270 bail:
271  return hb_shape_plan_get_empty ();
272 }
273 
274 /**
275  * hb_shape_plan_get_empty:
276  *
277  * Fetches the singleton empty shaping plan.
278  *
279  * Return value: (transfer full): The empty shaping plan
280  *
281  * Since: 0.9.7
282  **/
285 {
286  return const_cast<hb_shape_plan_t *> (&Null (hb_shape_plan_t));
287 }
288 
289 /**
290  * hb_shape_plan_reference: (skip)
291  * @shape_plan: A shaping plan
292  *
293  * Increases the reference count on the given shaping plan.
294  *
295  * Return value: (transfer full): @shape_plan
296  *
297  * Since: 0.9.7
298  **/
301 {
302  return hb_object_reference (shape_plan);
303 }
304 
305 /**
306  * hb_shape_plan_destroy: (skip)
307  * @shape_plan: A shaping plan
308  *
309  * Decreases the reference count on the given shaping plan. When the
310  * reference count reaches zero, the shaping plan is destroyed,
311  * freeing all memory.
312  *
313  * Since: 0.9.7
314  **/
315 void
317 {
318  if (!hb_object_destroy (shape_plan)) return;
319 
320 #ifndef HB_NO_OT_SHAPE
321  shape_plan->ot.fini ();
322 #endif
323  shape_plan->key.free ();
324  free (shape_plan);
325 }
326 
327 /**
328  * hb_shape_plan_set_user_data: (skip)
329  * @shape_plan: A shaping plan
330  * @key: The user-data key to set
331  * @data: A pointer to the user data
332  * @destroy: (optional): A callback to call when @data is not needed anymore
333  * @replace: Whether to replace an existing data with the same key
334  *
335  * Attaches a user-data key/data pair to the given shaping plan.
336  *
337  * Return value:
338  *
339  * Since: 0.9.7
340  **/
341 hb_bool_t
344  void * data,
345  hb_destroy_func_t destroy,
347 {
348  return hb_object_set_user_data (shape_plan, key, data, destroy, replace);
349 }
350 
351 /**
352  * hb_shape_plan_get_user_data: (skip)
353  * @shape_plan: A shaping plan
354  * @key: The user-data key to query
355  *
356  * Fetches the user data associated with the specified key,
357  * attached to the specified shaping plan.
358  *
359  * Return value: (transfer none): A pointer to the user data
360  *
361  * Since: 0.9.7
362  **/
363 void *
366 {
367  return hb_object_get_user_data (shape_plan, key);
368 }
369 
370 /**
371  * hb_shape_plan_get_shaper:
372  * @shape_plan: A shaping plan
373  *
374  * Fetches the shaper from a given shaping plan.
375  *
376  * Return value: (transfer none): The shaper
377  *
378  * Since: 0.9.7
379  **/
380 const char *
382 {
383  return shape_plan->key.shaper_name;
384 }
385 
386 
387 static bool
389  hb_font_t *font,
391  const hb_feature_t *features,
392  unsigned int num_features)
393 {
394  DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
395  "num_features=%d shaper_func=%p, shaper_name=%s",
396  num_features,
397  shape_plan->key.shaper_func,
398  shape_plan->key.shaper_name);
399 
400  if (unlikely (!buffer->len))
401  return true;
402 
404 
405  buffer->assert_unicode ();
406 
407  if (unlikely (hb_object_is_inert (shape_plan)))
408  return false;
409 
410  assert (shape_plan->face_unsafe == font->face);
411  assert (hb_segment_properties_equal (&shape_plan->key.props, &buffer->props));
412 
413 #define HB_SHAPER_EXECUTE(shaper) \
414  HB_STMT_START { \
415  return font->data.shaper && \
416  _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \
417  } HB_STMT_END
418 
419  if (false)
420  ;
421 #define HB_SHAPER_IMPLEMENT(shaper) \
422  else if (shape_plan->key.shaper_func == _hb_##shaper##_shape) \
423  HB_SHAPER_EXECUTE (shaper);
424 #include "hb-shaper-list.hh"
425 #undef HB_SHAPER_IMPLEMENT
426 
427 #undef HB_SHAPER_EXECUTE
428 
429  return false;
430 }
431 /**
432  * hb_shape_plan_execute:
433  * @shape_plan: A shaping plan
434  * @font: The #hb_font_t to use
435  * @buffer: The #hb_buffer_t to work upon
436  * @features: (array length=num_features): Features to enable
437  * @num_features: The number of features to enable
438  *
439  * Executes the given shaping plan on the specified buffer, using
440  * the given @font and @features.
441  *
442  * Return value:
443  *
444  * Since: 0.9.7
445  **/
446 hb_bool_t
448  hb_font_t *font,
450  const hb_feature_t *features,
451  unsigned int num_features)
452 {
453  bool ret = _hb_shape_plan_execute_internal (shape_plan, font, buffer,
454  features, num_features);
455 
456  if (ret && buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE)
457  buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
458 
459  return ret;
460 }
461 
462 
463 /*
464  * Caching
465  */
466 
467 /**
468  * hb_shape_plan_create_cached:
469  * @face: #hb_face_t to use
470  * @props: The #hb_segment_properties_t of the segment
471  * @user_features: (array length=num_user_features): The list of user-selected features
472  * @num_user_features: The number of user-selected features
473  * @shaper_list: (array zero-terminated=1): List of shapers to try
474  *
475  * Creates a cached shaping plan suitable for reuse, for a combination
476  * of @face, @user_features, @props, and @shaper_list.
477  *
478  * Return value: (transfer full): The shaping plan
479  *
480  * Since: 0.9.7
481  **/
484  const hb_segment_properties_t *props,
485  const hb_feature_t *user_features,
486  unsigned int num_user_features,
487  const char * const *shaper_list)
488 {
489  return hb_shape_plan_create_cached2 (face, props,
490  user_features, num_user_features,
491  nullptr, 0,
492  shaper_list);
493 }
494 
495 /**
496  * hb_shape_plan_create_cached2:
497  * @face: #hb_face_t to use
498  * @props: The #hb_segment_properties_t of the segment
499  * @user_features: (array length=num_user_features): The list of user-selected features
500  * @num_user_features: The number of user-selected features
501  * @coords: (array length=num_coords): The list of variation-space coordinates
502  * @num_coords: The number of variation-space coordinates
503  * @shaper_list: (array zero-terminated=1): List of shapers to try
504  *
505  * The variable-font version of #hb_shape_plan_create_cached.
506  * Creates a cached shaping plan suitable for reuse, for a combination
507  * of @face, @user_features, @props, and @shaper_list, plus the
508  * variation-space coordinates @coords.
509  *
510  * Return value: (transfer full): The shaping plan
511  *
512  * Since: 1.4.0
513  **/
516  const hb_segment_properties_t *props,
517  const hb_feature_t *user_features,
518  unsigned int num_user_features,
519  const int *coords,
520  unsigned int num_coords,
521  const char * const *shaper_list)
522 {
523  DEBUG_MSG_FUNC (SHAPE_PLAN, nullptr,
524  "face=%p num_features=%d shaper_list=%p",
525  face,
526  num_user_features,
527  shaper_list);
528 
529 retry:
530  hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans;
531 
532  bool dont_cache = hb_object_is_inert (face);
533 
534  if (likely (!dont_cache))
535  {
537  if (!key.init (false,
538  face,
539  props,
540  user_features,
541  num_user_features,
542  coords,
543  num_coords,
544  shaper_list))
545  return hb_shape_plan_get_empty ();
546 
547  for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
548  if (node->shape_plan->key.equal (&key))
549  {
550  DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
551  return hb_shape_plan_reference (node->shape_plan);
552  }
553  }
554 
555  hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props,
556  user_features, num_user_features,
557  coords, num_coords,
558  shaper_list);
559 
560  if (unlikely (dont_cache))
561  return shape_plan;
562 
564  if (unlikely (!node))
565  return shape_plan;
566 
567  node->shape_plan = shape_plan;
568  node->next = cached_plan_nodes;
569 
570  if (unlikely (!face->shape_plans.cmpexch (cached_plan_nodes, node)))
571  {
572  hb_shape_plan_destroy (shape_plan);
573  free (node);
574  goto retry;
575  }
576  DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "inserted into cache");
577 
578  return hb_shape_plan_reference (shape_plan);
579 }
mrb_ast_node node
Definition: codegen.c:30
#define free(a)
Definition: decNumber.cpp:310
struct rect data
Definition: dvipdfm.c:64
void replace(char *, char *)
Definition: dvispc.c:2100
static void copy(GlyphCachePtr *root)
Definition: gcache.c:378
#define memcpy(d, s, n)
Definition: gsftopk.c:64
assert(pcxLoadImage24((char *)((void *) 0), fp, pinfo, hdr))
#define likely(x)
Definition: jbig2arith.cc:115
#define unlikely(x)
Definition: jbig2arith.cc:116
small capitals from c petite p scientific i
Definition: afcover.h:80
FT_Face face
Definition: cffdrivr.c:659
voidp calloc()
static int ret
Definition: convert.c:72
@ other
Definition: mtxline.h:22
static const Mapping features[]
Definition: otfdescrip.cc:537
hb_bool_t hb_segment_properties_equal(const hb_segment_properties_t *a, const hb_segment_properties_t *b)
Definition: hb-buffer.cc:59
@ HB_BUFFER_CONTENT_TYPE_GLYPHS
Definition: hb-buffer.h:210
@ HB_BUFFER_CONTENT_TYPE_UNICODE
Definition: hb-buffer.h:209
void(* hb_destroy_func_t)(void *user_data)
Definition: hb-common.h:690
int hb_bool_t
Definition: hb-common.h:97
#define HB_FEATURE_GLOBAL_END
Definition: hb-common.h:706
@ HB_DIRECTION_INVALID
Definition: hb-common.h:194
#define HB_FEATURE_GLOBAL_START
Definition: hb-common.h:700
#define DEBUG_MSG_FUNC(WHAT, OBJ,...)
Definition: hb-debug.hh:233
void hb_face_make_immutable(hb_face_t *face)
Definition: hb-face.cc:349
hb_face_t * hb_face_get_empty()
Definition: hb-face.cc:243
#define Null(Type)
Definition: hb-null.hh:94
static bool hb_object_is_inert(const Type *obj)
Definition: hb-object.hh:244
static void * hb_object_get_user_data(Type *obj, hb_user_data_key_t *key)
Definition: hb-object.hh:329
static bool hb_object_destroy(Type *obj)
Definition: hb-object.hh:274
static bool hb_object_is_immutable(const Type *obj)
Definition: hb-object.hh:254
static Type * hb_object_reference(Type *obj)
Definition: hb-object.hh:264
static bool hb_object_set_user_data(Type *obj, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy, hb_bool_t replace)
Definition: hb-object.hh:299
hb_shape_plan_t * hb_shape_plan_create2(hb_face_t *face, const hb_segment_properties_t *props, const hb_feature_t *user_features, unsigned int num_user_features, const int *coords, unsigned int num_coords, const char *const *shaper_list)
void hb_shape_plan_destroy(hb_shape_plan_t *shape_plan)
hb_shape_plan_t * hb_shape_plan_get_empty()
hb_bool_t hb_shape_plan_set_user_data(hb_shape_plan_t *shape_plan, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy, hb_bool_t replace)
hb_bool_t hb_shape_plan_execute(hb_shape_plan_t *shape_plan, hb_font_t *font, hb_buffer_t *buffer, const hb_feature_t *features, unsigned int num_features)
hb_shape_plan_t * hb_shape_plan_reference(hb_shape_plan_t *shape_plan)
void * hb_shape_plan_get_user_data(hb_shape_plan_t *shape_plan, hb_user_data_key_t *key)
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)
hb_shape_plan_t * hb_shape_plan_create_cached2(hb_face_t *face, const hb_segment_properties_t *props, const hb_feature_t *user_features, unsigned int num_user_features, const int *coords, unsigned int num_coords, const char *const *shaper_list)
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)
const char * hb_shape_plan_get_shaper(hb_shape_plan_t *shape_plan)
const hb_shaper_entry_t * _hb_shapers_get()
Definition: hb-shaper.cc:105
@ HB_SHAPERS_COUNT
Definition: hb-shaper.hh:66
static bool _hb_shape_plan_execute_internal(hb_shape_plan_t *shape_plan, hb_font_t *font, hb_buffer_t *buffer, const hb_feature_t *features, unsigned int num_features)
Definition: utils.c:300
Definition: pbmfont.h:11
void init(hb_face_t *face, const int *coords, unsigned num_coords)
Definition: hb-ot-shape.hh:40
bool equal(const hb_ot_shape_plan_key_t *other)
Definition: hb-ot-shape.hh:52
bool init0(hb_face_t *face, const hb_shape_plan_key_t *key)
Definition: hb-ot-shape.cc:202
hb_direction_t direction
Definition: hb-buffer.h:145
hb_shape_func_t * shaper_func
hb_ot_shape_plan_key_t ot
unsigned int num_user_features
const char * shaper_name
bool equal(const hb_shape_plan_key_t *other)
hb_segment_properties_t props
const hb_feature_t * user_features
bool init(bool copy, hb_face_t *face, const hb_segment_properties_t *props, const hb_feature_t *user_features, unsigned int num_user_features, const int *coords, unsigned int num_coords, const char *const *shaper_list)
bool user_features_match(const hb_shape_plan_key_t *other)
hb_face_t * face_unsafe
hb_ot_shape_plan_t ot
hb_shape_plan_key_t key
Definition: hb-shaper.hh:44
Definition: xmlparse.c:179
#define key
Definition: tex2xindy.c:753
@ start
Definition: preamble.c:52
#define end(cp)
Definition: zic.c:71