[HB] Fix mix warnings
[profile/ivi/org.tizen.video-player.git] / src / hb-ot-layout.cc
1 /*
2  * Copyright (C) 1998-2004  David Turner and Werner Lemberg
3  * Copyright (C) 2006  Behdad Esfahbod
4  * Copyright (C) 2007,2008,2009  Red Hat, Inc.
5  *
6  *  This is part of HarfBuzz, an OpenType Layout engine library.
7  *
8  * Permission is hereby granted, without written agreement and without
9  * license or royalty fees, to use, copy, modify, and distribute this
10  * software and its documentation for any purpose, provided that the
11  * above copyright notice and the following two paragraphs appear in
12  * all copies of this software.
13  *
14  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
15  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
17  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18  * DAMAGE.
19  *
20  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
21  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
23  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
24  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25  *
26  * Red Hat Author(s): Behdad Esfahbod
27  */
28
29 #define HB_OT_LAYOUT_CC
30
31 #include "hb-ot-layout-private.h"
32
33 #include "hb-ot-layout-gdef-private.hh"
34 #include "hb-ot-layout-gsub-private.hh"
35 #include "hb-ot-layout-gpos-private.hh"
36
37
38 #include <stdlib.h>
39 #include <string.h>
40
41
42 void
43 _hb_ot_layout_init (hb_face_t *face)
44 {
45   hb_ot_layout_t *layout = &face->ot_layout;
46
47   /* XXX sanitize */
48
49   layout->gdef_blob = hb_face_get_table (face, HB_OT_TAG_GDEF);
50   layout->gdef = &GDEF::get_for_data (hb_blob_lock (layout->gdef_blob));
51
52   layout->gsub_blob = hb_face_get_table (face, HB_OT_TAG_GSUB);
53   layout->gsub = &GSUB::get_for_data (hb_blob_lock (layout->gsub_blob));
54
55   layout->gpos_blob = hb_face_get_table (face, HB_OT_TAG_GPOS);
56   layout->gpos = &GPOS::get_for_data (hb_blob_lock (layout->gpos_blob));
57 }
58
59 void
60 _hb_ot_layout_fini (hb_face_t *face)
61 {
62   hb_ot_layout_t *layout = &face->ot_layout;
63
64   hb_blob_unlock (layout->gdef_blob);
65   hb_blob_unlock (layout->gsub_blob);
66   hb_blob_unlock (layout->gpos_blob);
67
68   hb_blob_destroy (layout->gdef_blob);
69   hb_blob_destroy (layout->gsub_blob);
70   hb_blob_destroy (layout->gpos_blob);
71 }
72
73 static const GDEF&
74 _get_gdef (hb_face_t *face)
75 {
76   return HB_LIKELY (face->ot_layout.gdef) ? *face->ot_layout.gdef : Null(GDEF);
77 }
78
79 static const GSUB&
80 _get_gsub (hb_face_t *face)
81 {
82   return HB_LIKELY (face->ot_layout.gsub) ? *face->ot_layout.gsub : Null(GSUB);
83 }
84
85 static const GPOS&
86 _get_gpos (hb_face_t *face)
87 {
88   return HB_LIKELY (face->ot_layout.gpos) ? *face->ot_layout.gpos : Null(GPOS);
89 }
90
91
92 /*
93  * GDEF
94  */
95
96 /* TODO the public class_t is a mess */
97
98 hb_bool_t
99 hb_ot_layout_has_font_glyph_classes (hb_face_t *face)
100 {
101   return _get_gdef (face).has_glyph_classes ();
102 }
103
104 HB_INTERNAL hb_bool_t
105 _hb_ot_layout_has_new_glyph_classes (hb_face_t *face)
106 {
107   return face->ot_layout.new_gdef.len > 0;
108 }
109
110 static unsigned int
111 _hb_ot_layout_get_glyph_property (hb_face_t      *face,
112                                   hb_codepoint_t  glyph)
113 {
114   hb_ot_layout_class_t klass;
115   const GDEF &gdef = _get_gdef (face);
116
117   klass = gdef.get_glyph_class (glyph);
118
119   if (!klass && glyph < face->ot_layout.new_gdef.len)
120     klass = face->ot_layout.new_gdef.klasses[glyph];
121
122   switch (klass) {
123   default:
124   case GDEF::UnclassifiedGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
125   case GDEF::BaseGlyph:         return HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
126   case GDEF::LigatureGlyph:     return HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
127   case GDEF::ComponentGlyph:    return HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT;
128   case GDEF::MarkGlyph:
129         /* TODO old harfbuzz doesn't always parse mark attachments as it says it was
130          * introduced without a version bump, so it may not be safe */
131         klass = gdef.get_mark_attachment_type (glyph);
132         return HB_OT_LAYOUT_GLYPH_CLASS_MARK + (klass << 8);
133   }
134 }
135
136 HB_INTERNAL hb_bool_t
137 _hb_ot_layout_check_glyph_property (hb_face_t    *face,
138                                     hb_internal_glyph_info_t *ginfo,
139                                     unsigned int  lookup_flags,
140                                     unsigned int *property_out)
141 {
142   unsigned int property;
143
144   if (ginfo->gproperty == HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN)
145     ginfo->gproperty = _hb_ot_layout_get_glyph_property (face, ginfo->codepoint);
146   property = ginfo->gproperty;
147   if (property_out)
148     *property_out = property;
149
150   /* Not covered, if, for example, glyph class is ligature and
151    * lookup_flags includes LookupFlags::IgnoreLigatures
152    */
153   if (property & lookup_flags)
154     return false;
155
156   if (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
157   {
158     /* If using mark filtering sets, the high short of
159      * lookup_flags has the set index.
160      */
161     if (lookup_flags & LookupFlag::UseMarkFilteringSet)
162       return _get_gdef (face).mark_set_covers (lookup_flags >> 16, ginfo->codepoint);
163
164     /* The second byte of lookup_flags has the meaning
165      * "ignore marks of attachment type different than
166      * the attachment type specified."
167      */
168     if (lookup_flags & LookupFlag::MarkAttachmentType && property & LookupFlag::MarkAttachmentType)
169       return (lookup_flags & LookupFlag::MarkAttachmentType) == (property & LookupFlag::MarkAttachmentType);
170   }
171
172   return true;
173 }
174
175 HB_INTERNAL hb_bool_t
176 _hb_ot_layout_skip_mark (hb_face_t    *face,
177                          hb_internal_glyph_info_t *ginfo,
178                          unsigned int  lookup_flags,
179                          unsigned int *property_out)
180 {
181   unsigned int property;
182
183   if (ginfo->gproperty == HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN)
184     ginfo->gproperty = _hb_ot_layout_get_glyph_property (face, ginfo->codepoint);
185   property = ginfo->gproperty;
186   if (property_out)
187     *property_out = property;
188
189   if (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
190   {
191     /* Skip mark if lookup_flags includes LookupFlags::IgnoreMarks */
192     if (lookup_flags & LookupFlag::IgnoreMarks)
193       return true;
194
195     /* If using mark filtering sets, the high short of lookup_flags has the set index. */
196     if (lookup_flags & LookupFlag::UseMarkFilteringSet)
197       return !_get_gdef (face).mark_set_covers (lookup_flags >> 16, ginfo->codepoint);
198
199     /* The second byte of lookup_flags has the meaning "ignore marks of attachment type
200      * different than the attachment type specified." */
201     if (lookup_flags & LookupFlag::MarkAttachmentType && property & LookupFlag::MarkAttachmentType)
202       return (lookup_flags & LookupFlag::MarkAttachmentType) != (property & LookupFlag::MarkAttachmentType);
203   }
204
205   return false;
206 }
207
208 HB_INTERNAL void
209 _hb_ot_layout_set_glyph_class (hb_face_t                  *face,
210                                hb_codepoint_t              glyph,
211                                hb_ot_layout_glyph_class_t  klass)
212 {
213   if (HB_OBJECT_IS_INERT (face))
214     return;
215
216   /* TODO optimize this? similar to old harfbuzz code for example */
217
218   hb_ot_layout_t *layout = &face->ot_layout;
219   hb_ot_layout_class_t gdef_klass;
220   unsigned int len = layout->new_gdef.len;
221
222   if (HB_UNLIKELY (glyph > 65535))
223     return;
224
225   /* XXX this is not threadsafe */
226   if (glyph >= len) {
227     int new_len;
228     unsigned char *new_klasses;
229
230     new_len = len == 0 ? 120 : 2 * len;
231     if (new_len > 65535)
232       new_len = 65535;
233     new_klasses = (unsigned char *) realloc (layout->new_gdef.klasses, new_len * sizeof (unsigned char));
234
235     if (HB_UNLIKELY (!new_klasses))
236       return;
237
238     memset (new_klasses + len, 0, new_len - len);
239
240     layout->new_gdef.klasses = new_klasses;
241     layout->new_gdef.len = new_len;
242   }
243
244   switch (klass) {
245   default:
246   case HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED:   gdef_klass = GDEF::UnclassifiedGlyph;   break;
247   case HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH:     gdef_klass = GDEF::BaseGlyph;           break;
248   case HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE:       gdef_klass = GDEF::LigatureGlyph;       break;
249   case HB_OT_LAYOUT_GLYPH_CLASS_MARK:           gdef_klass = GDEF::MarkGlyph;           break;
250   case HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT:      gdef_klass = GDEF::ComponentGlyph;      break;
251   }
252
253   layout->new_gdef.klasses[glyph] = gdef_klass;
254   return;
255 }
256
257 HB_INTERNAL void
258 _hb_ot_layout_set_glyph_property (hb_face_t      *face,
259                                   hb_codepoint_t  glyph,
260                                   unsigned int    property)
261 { _hb_ot_layout_set_glyph_class (face, glyph, (hb_ot_layout_glyph_class_t) (property & 0xff)); }
262
263
264 hb_ot_layout_glyph_class_t
265 hb_ot_layout_get_glyph_class (hb_face_t      *face,
266                               hb_codepoint_t  glyph)
267 {
268   return (hb_ot_layout_glyph_class_t) (_hb_ot_layout_get_glyph_property (face, glyph) & 0xff);
269 }
270
271 void
272 hb_ot_layout_set_glyph_class (hb_face_t                 *face,
273                               hb_codepoint_t             glyph,
274                               hb_ot_layout_glyph_class_t klass)
275 {
276   _hb_ot_layout_set_glyph_class (face, glyph, klass);
277 }
278
279 void
280 hb_ot_layout_build_glyph_classes (hb_face_t      *face,
281                                   uint16_t        num_total_glyphs,
282                                   hb_codepoint_t *glyphs,
283                                   unsigned char  *klasses,
284                                   uint16_t        count)
285 {
286   if (HB_OBJECT_IS_INERT (face))
287     return;
288
289   hb_ot_layout_t *layout = &face->ot_layout;
290
291   if (HB_UNLIKELY (!count || !glyphs || !klasses))
292     return;
293
294   if (layout->new_gdef.len == 0) {
295     layout->new_gdef.klasses = (unsigned char *) calloc (num_total_glyphs, sizeof (unsigned char));
296     layout->new_gdef.len = count;
297   }
298
299   for (unsigned int i = 0; i < count; i++)
300     _hb_ot_layout_set_glyph_class (face, glyphs[i], (hb_ot_layout_glyph_class_t) klasses[i]);
301 }
302
303 hb_bool_t
304 hb_ot_layout_get_attach_points (hb_face_t      *face,
305                                 hb_codepoint_t  glyph,
306                                 unsigned int   *point_count /* IN/OUT */,
307                                 unsigned int   *point_array /* OUT */)
308 {
309   return _get_gdef (face).get_attach_points (glyph, point_count, point_array);
310 }
311
312 hb_bool_t
313 hb_ot_layout_get_lig_carets (hb_face_t      *face,
314                              hb_font_t      *font,
315                              hb_codepoint_t  glyph,
316                              unsigned int   *caret_count /* IN/OUT */,
317                              int            *caret_array /* OUT */)
318 {
319   hb_ot_layout_context_t context;
320   context.font = font;
321   context.face = face;
322   return _get_gdef (face).get_lig_carets (&context, glyph, caret_count, caret_array);
323 }
324
325 /*
326  * GSUB/GPOS
327  */
328
329 static const GSUBGPOS&
330 get_gsubgpos_table (hb_face_t *face,
331                     hb_tag_t   table_tag)
332 {
333   switch (table_tag) {
334     case HB_OT_TAG_GSUB: return _get_gsub (face);
335     case HB_OT_TAG_GPOS: return _get_gpos (face);
336     default:             return Null(GSUBGPOS);
337   }
338 }
339
340
341 unsigned int
342 hb_ot_layout_table_get_script_count (hb_face_t *face,
343                                      hb_tag_t   table_tag)
344 {
345   const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
346
347   return g.get_script_count ();
348 }
349
350 hb_tag_t
351 hb_ot_layout_table_get_script_tag (hb_face_t    *face,
352                                    hb_tag_t      table_tag,
353                                    unsigned int  script_index)
354 {
355   const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
356
357   return g.get_script_tag (script_index);
358 }
359
360 hb_bool_t
361 hb_ot_layout_table_find_script (hb_face_t    *face,
362                                 hb_tag_t      table_tag,
363                                 hb_tag_t      script_tag,
364                                 unsigned int *script_index)
365 {
366   ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
367   const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
368
369   if (g.find_script_index (script_tag, script_index))
370     return TRUE;
371
372   /* try finding 'DFLT' */
373   if (g.find_script_index (HB_OT_LAYOUT_TAG_DEFAULT_SCRIPT, script_index))
374     return FALSE;
375
376   /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
377   if (g.find_script_index (HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE, script_index))
378     return FALSE;
379
380   if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
381   return FALSE;
382 }
383
384 unsigned int
385 hb_ot_layout_table_get_feature_count (hb_face_t *face,
386                                       hb_tag_t   table_tag)
387 {
388   const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
389
390   return g.get_feature_count ();
391 }
392
393 hb_tag_t
394 hb_ot_layout_table_get_feature_tag (hb_face_t    *face,
395                                     hb_tag_t      table_tag,
396                                     unsigned int  feature_index)
397 {
398   const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
399
400   return g.get_feature_tag (feature_index);
401 }
402
403 hb_bool_t
404 hb_ot_layout_table_find_feature (hb_face_t    *face,
405                                  hb_tag_t      table_tag,
406                                  hb_tag_t      feature_tag,
407                                  unsigned int *feature_index)
408 {
409   ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
410   const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
411
412   if (g.find_feature_index (feature_tag, feature_index))
413     return TRUE;
414
415   if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
416   return FALSE;
417 }
418
419 unsigned int
420 hb_ot_layout_table_get_lookup_count (hb_face_t *face,
421                                      hb_tag_t   table_tag)
422 {
423   const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
424
425   return g.get_lookup_count ();
426 }
427
428
429 unsigned int
430 hb_ot_layout_script_get_language_count (hb_face_t    *face,
431                                         hb_tag_t      table_tag,
432                                         unsigned int  script_index)
433 {
434   const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
435
436   return s.get_lang_sys_count ();
437 }
438
439 hb_tag_t
440 hb_ot_layout_script_get_language_tag (hb_face_t    *face,
441                                       hb_tag_t      table_tag,
442                                       unsigned int  script_index,
443                                       unsigned int  language_index)
444 {
445   const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
446
447   return s.get_lang_sys_tag (language_index);
448 }
449
450 hb_bool_t
451 hb_ot_layout_script_find_language (hb_face_t    *face,
452                                    hb_tag_t      table_tag,
453                                    unsigned int  script_index,
454                                    hb_tag_t      language_tag,
455                                    unsigned int *language_index)
456 {
457   ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
458   const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
459
460   if (s.find_lang_sys_index (language_tag, language_index))
461     return TRUE;
462
463   /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
464   if (s.find_lang_sys_index (HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE, language_index))
465     return FALSE;
466
467   if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
468   return FALSE;
469 }
470
471 hb_bool_t
472 hb_ot_layout_language_get_required_feature_index (hb_face_t    *face,
473                                                   hb_tag_t      table_tag,
474                                                   unsigned int  script_index,
475                                                   unsigned int  language_index,
476                                                   unsigned int *feature_index)
477 {
478   const LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
479
480   if (feature_index) *feature_index = l.get_required_feature_index ();
481
482   return l.has_required_feature ();
483 }
484
485 unsigned int
486 hb_ot_layout_language_get_feature_count (hb_face_t    *face,
487                                          hb_tag_t      table_tag,
488                                          unsigned int  script_index,
489                                          unsigned int  language_index)
490 {
491   const LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
492
493   return l.get_feature_count ();
494 }
495
496 unsigned int
497 hb_ot_layout_language_get_feature_index (hb_face_t    *face,
498                                          hb_tag_t      table_tag,
499                                          unsigned int  script_index,
500                                          unsigned int  language_index,
501                                          unsigned int  num_feature)
502 {
503   const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
504   const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
505
506   return l.get_feature_index (num_feature);
507 }
508
509 hb_tag_t
510 hb_ot_layout_language_get_feature_tag (hb_face_t    *face,
511                                        hb_tag_t      table_tag,
512                                        unsigned int  script_index,
513                                        unsigned int  language_index,
514                                        unsigned int  num_feature)
515 {
516   const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
517   const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
518   unsigned int feature_index = l.get_feature_index (num_feature);
519
520   return g.get_feature_tag (feature_index);
521 }
522
523
524 hb_bool_t
525 hb_ot_layout_language_find_feature (hb_face_t    *face,
526                                     hb_tag_t      table_tag,
527                                     unsigned int  script_index,
528                                     unsigned int  language_index,
529                                     hb_tag_t      feature_tag,
530                                     unsigned int *feature_index)
531 {
532   ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
533   const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
534   const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
535
536   unsigned int num_features = l.get_feature_count ();
537   for (unsigned int i = 0; i < num_features; i++) {
538     unsigned int f_index = l.get_feature_index (i);
539
540     if (feature_tag == g.get_feature_tag (f_index)) {
541       if (feature_index) *feature_index = f_index;
542       return TRUE;
543     }
544   }
545
546   if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
547   return FALSE;
548 }
549
550 unsigned int
551 hb_ot_layout_feature_get_lookup_count (hb_face_t    *face,
552                                        hb_tag_t      table_tag,
553                                        unsigned int  feature_index)
554 {
555   const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
556   const Feature &f = g.get_feature (feature_index);
557
558   return f.get_lookup_count ();
559 }
560
561 unsigned int
562 hb_ot_layout_feature_get_lookup_index (hb_face_t    *face,
563                                        hb_tag_t      table_tag,
564                                        unsigned int  feature_index,
565                                        unsigned int  num_lookup)
566 {
567   const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
568   const Feature &f = g.get_feature (feature_index);
569
570   return f.get_lookup_index (num_lookup);
571 }
572
573 /*
574  * GSUB
575  */
576
577 hb_bool_t
578 hb_ot_layout_has_substitution (hb_face_t *face)
579 {
580   return &_get_gsub (face) != &Null(GSUB);
581 }
582
583 hb_bool_t
584 hb_ot_layout_substitute_lookup (hb_face_t                   *face,
585                                 hb_buffer_t                 *buffer,
586                                 unsigned int                 lookup_index,
587                                 hb_ot_layout_feature_mask_t  mask)
588 {
589   hb_ot_layout_context_t context;
590   context.font = NULL;
591   context.face = face;
592   return _get_gsub (face).substitute_lookup (&context, buffer, lookup_index, mask);
593 }
594
595 /*
596  * GPOS
597  */
598
599 hb_bool_t
600 hb_ot_layout_has_positioning (hb_face_t *face)
601 {
602   return &_get_gpos (face) != &Null(GPOS);
603 }
604
605 hb_bool_t
606 hb_ot_layout_position_lookup   (hb_face_t                   *face,
607                                 hb_font_t                   *font,
608                                 hb_buffer_t                 *buffer,
609                                 unsigned int                 lookup_index,
610                                 hb_ot_layout_feature_mask_t  mask)
611 {
612   hb_ot_layout_context_t context;
613   context.font = font;
614   context.face = face;
615   return _get_gpos (face).position_lookup (&context, buffer, lookup_index, mask);
616 }