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