hb-ot-layout.cc revision 590d55cbb9e21ef74dfd88eee51fd0a763958cd2
1/*
2 * Copyright (C) 2007,2008  Red Hat, Inc.
3 *
4 *  This is part of HarfBuzz, an OpenType Layout engine 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 * Red Hat Author(s): Behdad Esfahbod
25 */
26
27#define HB_OT_LAYOUT_CC
28
29#include "hb-ot-layout.h"
30#include "hb-ot-layout-private.h"
31
32#include "hb-ot-layout-open-private.h"
33#include "hb-ot-layout-gdef-private.h"
34#include "hb-ot-layout-gsub-private.h"
35
36#include <stdlib.h>
37#include <string.h>
38
39
40struct _HB_OT_Layout {
41  const GDEF *gdef;
42  const GSUB *gsub;
43//const GPOS *gpos;
44
45  struct {
46    unsigned char *klasses;
47    unsigned int len;
48  } new_gdef;
49
50};
51
52HB_OT_Layout *
53hb_ot_layout_create (const char *font_data,
54                     int         face_index)
55{
56  HB_OT_Layout *layout = (HB_OT_Layout *) calloc (1, sizeof (HB_OT_Layout));
57
58  const OpenTypeFontFile &font = OpenTypeFontFile::get_for_data (font_data);
59  const OpenTypeFontFace &face = font.get_face (face_index);
60
61  layout->gdef = &GDEF::get_for_data (font.get_table_data (face.get_table (GDEF::Tag)));
62  layout->gsub = &GSUB::get_for_data (font.get_table_data (face.get_table (GSUB::Tag)));
63//layout->gpos = &GPOS::get_for_data (font.get_table_data (face.get_table (GPOS::Tag)));
64
65  return layout;
66}
67
68void
69hb_ot_layout_destroy (HB_OT_Layout *layout)
70{
71  free (layout);
72}
73
74/*
75 * GDEF
76 */
77
78hb_bool_t
79hb_ot_layout_has_font_glyph_classes (HB_OT_Layout *layout)
80{
81  return layout->gdef->has_glyph_classes ();
82}
83
84static hb_bool_t
85_hb_ot_layout_has_new_glyph_classes (HB_OT_Layout *layout)
86{
87  return layout->new_gdef.len > 0;
88}
89
90static hb_ot_layout_glyph_properties_t
91_hb_ot_layout_get_glyph_properties (HB_OT_Layout *layout,
92				    hb_glyph_t    glyph)
93{
94  hb_ot_layout_class_t klass;
95
96  /* TODO old harfbuzz doesn't always parse mark attachments as it says it was
97   * introduced without a version bump, so it may not be safe */
98  klass = layout->gdef->get_mark_attachment_type (glyph);
99  if (klass)
100    return klass << 8;
101
102  klass = layout->gdef->get_glyph_class (glyph);
103
104  if (!klass && glyph < layout->new_gdef.len)
105    klass = layout->new_gdef.klasses[glyph];
106
107  switch (klass) {
108  default:
109  case GDEF::UnclassifiedGlyph:	return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
110  case GDEF::BaseGlyph:		return HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
111  case GDEF::LigatureGlyph:	return HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
112  case GDEF::MarkGlyph:		return HB_OT_LAYOUT_GLYPH_CLASS_MARK;
113  case GDEF::ComponentGlyph:	return HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT;
114  }
115}
116
117#if 0
118static bool
119_hb_ot_layout_check_glyph_properties (HB_OT_Layout *layout,
120				      HB_GlyphItem  gitem,
121				      HB_UShort     flags,
122				      HB_UShort*    property)
123{
124  HB_Error  error;
125
126  if ( gdef )
127  {
128    HB_UShort basic_glyph_class;
129    HB_UShort desired_attachment_class;
130
131    if ( gitem->gproperties == HB_GLYPH_PROPERTIES_UNKNOWN )
132    {
133      error = HB_GDEF_Get_Glyph_Property( gdef, gitem->gindex, &gitem->gproperties );
134      if ( error )
135	return error;
136    }
137
138    *property = gitem->gproperties;
139
140    /* If the glyph was found in the MarkAttachmentClass table,
141     * then that class value is the high byte of the result,
142     * otherwise the low byte contains the basic type of the glyph
143     * as defined by the GlyphClassDef table.
144     */
145    if ( *property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS  )
146      basic_glyph_class = HB_GDEF_MARK;
147    else
148      basic_glyph_class = *property;
149
150    /* Return Not_Covered, if, for example, basic_glyph_class
151     * is HB_GDEF_LIGATURE and LookFlags includes HB_LOOKUP_FLAG_IGNORE_LIGATURES
152     */
153    if ( flags & basic_glyph_class )
154      return HB_Err_Not_Covered;
155
156    /* The high byte of LookupFlags has the meaning
157     * "ignore marks of attachment type different than
158     * the attachment type specified."
159     */
160    desired_attachment_class = flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS;
161    if ( desired_attachment_class )
162    {
163      if ( basic_glyph_class == HB_GDEF_MARK &&
164	   *property != desired_attachment_class )
165	return HB_Err_Not_Covered;
166    }
167  } else {
168      *property = 0;
169  }
170
171  return HB_Err_Ok;
172}
173#endif
174
175
176hb_ot_layout_glyph_class_t
177hb_ot_layout_get_glyph_class (HB_OT_Layout *layout,
178			      hb_glyph_t    glyph)
179{
180  hb_ot_layout_glyph_properties_t properties;
181  hb_ot_layout_class_t klass;
182
183  properties = _hb_ot_layout_get_glyph_properties (layout, glyph);
184
185  if (properties & 0xFF)
186    return HB_OT_LAYOUT_GLYPH_CLASS_MARK;
187
188  return (hb_ot_layout_glyph_class_t) properties;
189}
190
191void
192hb_ot_layout_set_glyph_class (HB_OT_Layout               *layout,
193			      hb_glyph_t                  glyph,
194			      hb_ot_layout_glyph_class_t  klass)
195{
196  /* TODO optimize this, similar to old harfbuzz code for example */
197
198  hb_ot_layout_class_t gdef_klass;
199  int len = layout->new_gdef.len;
200
201  if (glyph >= len) {
202    int new_len;
203    unsigned char *new_klasses;
204
205    new_len = len == 0 ? 120 : 2 * len;
206    if (new_len > 65535)
207      new_len = 65535;
208    new_klasses = (unsigned char *) realloc (layout->new_gdef.klasses, new_len * sizeof (unsigned char));
209
210    if (G_UNLIKELY (!new_klasses))
211      return;
212
213    memset (new_klasses + len, 0, new_len - len);
214
215    layout->new_gdef.klasses = new_klasses;
216    layout->new_gdef.len = new_len;
217  }
218
219  switch (klass) {
220  default:
221  case HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED:	gdef_klass = GDEF::UnclassifiedGlyph;	break;
222  case HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH:	gdef_klass = GDEF::BaseGlyph;		break;
223  case HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE:	gdef_klass = GDEF::LigatureGlyph;	break;
224  case HB_OT_LAYOUT_GLYPH_CLASS_MARK:		gdef_klass = GDEF::MarkGlyph;		break;
225  case HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT:	gdef_klass = GDEF::ComponentGlyph;	break;
226  }
227
228  layout->new_gdef.klasses[glyph] = gdef_klass;
229  return;
230}
231
232void
233hb_ot_layout_build_glyph_classes (HB_OT_Layout  *layout,
234				  uint16_t       num_total_glyphs,
235				  hb_glyph_t    *glyphs,
236				  unsigned char *klasses,
237				  uint16_t       count)
238{
239  int i;
240
241  if (G_UNLIKELY (!count || !glyphs || !klasses))
242    return;
243
244  if (layout->new_gdef.len == 0) {
245    layout->new_gdef.klasses = (unsigned char *) calloc (num_total_glyphs, sizeof (unsigned char));
246    layout->new_gdef.len = count;
247  }
248
249  for (i = 0; i < count; i++)
250    hb_ot_layout_set_glyph_class (layout, glyphs[i], (hb_ot_layout_glyph_class_t) klasses[i]);
251}
252