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