OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (C) 2009,2010 Red Hat, Inc. |
| 3 * Copyright (C) 2010 Google, Inc. |
| 4 * |
| 5 * This is part of HarfBuzz, a text shaping library. |
| 6 * |
| 7 * Permission is hereby granted, without written agreement and without |
| 8 * license or royalty fees, to use, copy, modify, and distribute this |
| 9 * software and its documentation for any purpose, provided that the |
| 10 * above copyright notice and the following two paragraphs appear in |
| 11 * all copies of this software. |
| 12 * |
| 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
| 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
| 15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
| 16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
| 17 * DAMAGE. |
| 18 * |
| 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
| 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
| 21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
| 22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
| 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
| 24 * |
| 25 * Red Hat Author(s): Behdad Esfahbod |
| 26 * Google Author(s): Behdad Esfahbod |
| 27 */ |
| 28 |
| 29 #include "hb-ot-shape-private.hh" |
| 30 #include "hb-ot-shape-complex-private.hh" |
| 31 |
| 32 HB_BEGIN_DECLS |
| 33 |
| 34 |
| 35 /* XXX vertical */ |
| 36 hb_tag_t default_features[] = { |
| 37 HB_TAG('c','a','l','t'), |
| 38 HB_TAG('c','c','m','p'), |
| 39 HB_TAG('c','l','i','g'), |
| 40 HB_TAG('c','s','w','h'), |
| 41 HB_TAG('c','u','r','s'), |
| 42 HB_TAG('k','e','r','n'), |
| 43 HB_TAG('l','i','g','a'), |
| 44 HB_TAG('l','o','c','l'), |
| 45 HB_TAG('m','a','r','k'), |
| 46 HB_TAG('m','k','m','k'), |
| 47 HB_TAG('r','l','i','g') |
| 48 }; |
| 49 |
| 50 static void |
| 51 hb_ot_shape_collect_features (hb_ot_shape_plan_t *plan, |
| 52 const hb_segment_properties_t *props, |
| 53 const hb_feature_t *user_features, |
| 54 unsigned int num_user_features) |
| 55 { |
| 56 switch (props->direction) { |
| 57 case HB_DIRECTION_LTR: |
| 58 plan->map.add_bool_feature (HB_TAG ('l','t','r','a')); |
| 59 plan->map.add_bool_feature (HB_TAG ('l','t','r','m')); |
| 60 break; |
| 61 case HB_DIRECTION_RTL: |
| 62 plan->map.add_bool_feature (HB_TAG ('r','t','l','a')); |
| 63 plan->map.add_bool_feature (HB_TAG ('r','t','l','m'), false); |
| 64 break; |
| 65 case HB_DIRECTION_TTB: |
| 66 case HB_DIRECTION_BTT: |
| 67 default: |
| 68 break; |
| 69 } |
| 70 |
| 71 for (unsigned int i = 0; i < ARRAY_LENGTH (default_features); i++) |
| 72 plan->map.add_bool_feature (default_features[i]); |
| 73 |
| 74 hb_ot_shape_complex_collect_features (plan, props); |
| 75 |
| 76 for (unsigned int i = 0; i < num_user_features; i++) { |
| 77 const hb_feature_t *feature = &user_features[i]; |
| 78 plan->map.add_feature (feature->tag, feature->value, (feature->start == 0 &&
feature->end == (unsigned int) -1)); |
| 79 } |
| 80 } |
| 81 |
| 82 |
| 83 static void |
| 84 hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) |
| 85 { |
| 86 hb_mask_t global_mask = c->plan->map.get_global_mask (); |
| 87 c->buffer->reset_masks (global_mask); |
| 88 |
| 89 hb_ot_shape_complex_setup_masks (c); /* BUFFER: Clobbers var2 */ |
| 90 |
| 91 for (unsigned int i = 0; i < c->num_user_features; i++) |
| 92 { |
| 93 const hb_feature_t *feature = &c->user_features[i]; |
| 94 if (!(feature->start == 0 && feature->end == (unsigned int)-1)) { |
| 95 unsigned int shift; |
| 96 hb_mask_t mask = c->plan->map.get_mask (feature->tag, &shift); |
| 97 c->buffer->set_masks (feature->value << shift, mask, feature->start, featu
re->end); |
| 98 } |
| 99 } |
| 100 } |
| 101 |
| 102 |
| 103 static void |
| 104 hb_ot_substitute_complex (hb_ot_shape_context_t *c) |
| 105 { |
| 106 if (!hb_ot_layout_has_substitution (c->face)) |
| 107 return; |
| 108 |
| 109 c->plan->map.substitute (c->face, c->buffer); |
| 110 |
| 111 c->applied_substitute_complex = TRUE; |
| 112 return; |
| 113 } |
| 114 |
| 115 static void |
| 116 hb_ot_position_complex (hb_ot_shape_context_t *c) |
| 117 { |
| 118 |
| 119 if (!hb_ot_layout_has_positioning (c->face)) |
| 120 return; |
| 121 |
| 122 c->plan->map.position (c->font, c->face, c->buffer); |
| 123 |
| 124 hb_ot_layout_position_finish (c->buffer); |
| 125 |
| 126 c->applied_position_complex = TRUE; |
| 127 return; |
| 128 } |
| 129 |
| 130 |
| 131 /* Main shaper */ |
| 132 |
| 133 /* Prepare */ |
| 134 |
| 135 static inline hb_bool_t |
| 136 is_variation_selector (hb_codepoint_t unicode) |
| 137 { |
| 138 return unlikely ((unicode >= 0x180B && unicode <= 0x180D) || /* MONGOLIAN FR
EE VARIATION SELECTOR ONE..THREE */ |
| 139 (unicode >= 0xFE00 && unicode <= 0xFE0F) || /* VARIATION SE
LECTOR-1..16 */ |
| 140 (unicode >= 0xE0100 && unicode <= 0xE01EF)); /* VARIATION SE
LECTOR-17..256 */ |
| 141 } |
| 142 |
| 143 static void |
| 144 hb_set_unicode_props (hb_ot_shape_context_t *c) |
| 145 { |
| 146 hb_unicode_get_general_category_func_t get_general_category = c->buffer->unico
de->v.get_general_category; |
| 147 hb_unicode_get_combining_class_func_t get_combining_class = c->buffer->unicode
->v.get_combining_class; |
| 148 hb_glyph_info_t *info = c->buffer->info; |
| 149 |
| 150 unsigned int count = c->buffer->len; |
| 151 for (unsigned int i = 1; i < count; i++) { |
| 152 info[i].general_category() = get_general_category (info[i].codepoint); |
| 153 info[i].combining_class() = get_combining_class (info[i].codepoint); |
| 154 } |
| 155 } |
| 156 |
| 157 static void |
| 158 hb_form_clusters (hb_ot_shape_context_t *c) |
| 159 { |
| 160 unsigned int count = c->buffer->len; |
| 161 for (unsigned int i = 1; i < count; i++) |
| 162 if (c->buffer->info[i].general_category() == HB_CATEGORY_NON_SPACING_MARK) |
| 163 c->buffer->info[i].cluster = c->buffer->info[i - 1].cluster; |
| 164 } |
| 165 |
| 166 static void |
| 167 hb_ensure_native_direction (hb_ot_shape_context_t *c) |
| 168 { |
| 169 hb_direction_t direction = c->buffer->props.direction; |
| 170 |
| 171 /* TODO vertical */ |
| 172 if (HB_DIRECTION_IS_HORIZONTAL (direction) && |
| 173 direction != _hb_script_get_horizontal_direction (c->buffer->props.script)
) |
| 174 { |
| 175 hb_buffer_reverse_clusters (c->buffer); |
| 176 c->buffer->props.direction = HB_DIRECTION_REVERSE (c->buffer->props.directio
n); |
| 177 } |
| 178 } |
| 179 |
| 180 static void |
| 181 hb_reset_glyph_infos (hb_ot_shape_context_t *c) |
| 182 { |
| 183 unsigned int count = c->buffer->len; |
| 184 for (unsigned int i = 0; i < count; i++) |
| 185 c->buffer->info[i].var1.u32 = c->buffer->info[i].var2.u32 = 0; |
| 186 } |
| 187 |
| 188 |
| 189 /* Substitute */ |
| 190 |
| 191 static void |
| 192 hb_mirror_chars (hb_ot_shape_context_t *c) |
| 193 { |
| 194 hb_unicode_get_mirroring_func_t get_mirroring = c->buffer->unicode->v.get_mirr
oring; |
| 195 |
| 196 if (HB_DIRECTION_IS_FORWARD (c->target_direction)) |
| 197 return; |
| 198 |
| 199 hb_mask_t rtlm_mask = c->plan->map.get_1_mask (HB_TAG ('r','t','l','m')); |
| 200 |
| 201 unsigned int count = c->buffer->len; |
| 202 for (unsigned int i = 0; i < count; i++) { |
| 203 hb_codepoint_t codepoint = get_mirroring (c->buffer->info[i].codepoint); |
| 204 if (likely (codepoint == c->buffer->info[i].codepoint)) |
| 205 c->buffer->info[i].mask |= rtlm_mask; /* XXX this should be moved to befor
e setting user-feature masks */ |
| 206 else |
| 207 c->buffer->info[i].codepoint = codepoint; |
| 208 } |
| 209 } |
| 210 |
| 211 static void |
| 212 hb_map_glyphs (hb_font_t *font, |
| 213 hb_face_t *face, |
| 214 hb_buffer_t *buffer) |
| 215 { |
| 216 if (unlikely (!buffer->len)) |
| 217 return; |
| 218 |
| 219 buffer->clear_output (); |
| 220 unsigned int count = buffer->len - 1; |
| 221 for (buffer->i = 0; buffer->i < count;) { |
| 222 if (unlikely (is_variation_selector (buffer->info[buffer->i + 1].codepoint))
) { |
| 223 buffer->replace_glyph (hb_font_get_glyph (font, face, buffer->info[buffer-
>i].codepoint, buffer->info[buffer->i + 1].codepoint)); |
| 224 buffer->i++; |
| 225 } else { |
| 226 buffer->replace_glyph (hb_font_get_glyph (font, face, buffer->info[buffer-
>i].codepoint, 0)); |
| 227 } |
| 228 } |
| 229 if (likely (buffer->i < buffer->len)) |
| 230 buffer->replace_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i
].codepoint, 0)); |
| 231 buffer->swap (); |
| 232 } |
| 233 |
| 234 static void |
| 235 hb_substitute_default (hb_ot_shape_context_t *c) |
| 236 { |
| 237 hb_map_glyphs (c->font, c->face, c->buffer); |
| 238 } |
| 239 |
| 240 static void |
| 241 hb_substitute_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED) |
| 242 { |
| 243 /* TODO Arabic */ |
| 244 } |
| 245 |
| 246 |
| 247 /* Position */ |
| 248 |
| 249 static void |
| 250 hb_position_default (hb_ot_shape_context_t *c) |
| 251 { |
| 252 hb_buffer_clear_positions (c->buffer); |
| 253 |
| 254 unsigned int count = c->buffer->len; |
| 255 for (unsigned int i = 0; i < count; i++) { |
| 256 hb_font_get_glyph_advance (c->font, c->face, c->buffer->info[i].codepoint, |
| 257 &c->buffer->pos[i].x_advance, |
| 258 &c->buffer->pos[i].y_advance); |
| 259 } |
| 260 } |
| 261 |
| 262 static void |
| 263 hb_position_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED) |
| 264 { |
| 265 /* TODO Mark pos */ |
| 266 } |
| 267 |
| 268 static void |
| 269 hb_truetype_kern (hb_ot_shape_context_t *c) |
| 270 { |
| 271 /* TODO Check for kern=0 */ |
| 272 unsigned int count = c->buffer->len; |
| 273 for (unsigned int i = 1; i < count; i++) { |
| 274 hb_position_t kern, kern1, kern2; |
| 275 kern = hb_font_get_kerning (c->font, c->face, c->buffer->info[i - 1].codepoi
nt, c->buffer->info[i].codepoint); |
| 276 kern1 = kern >> 1; |
| 277 kern2 = kern - kern1; |
| 278 c->buffer->pos[i - 1].x_advance += kern1; |
| 279 c->buffer->pos[i].x_advance += kern2; |
| 280 c->buffer->pos[i].x_offset += kern2; |
| 281 } |
| 282 } |
| 283 |
| 284 static void |
| 285 hb_position_complex_fallback_visual (hb_ot_shape_context_t *c) |
| 286 { |
| 287 hb_truetype_kern (c); |
| 288 } |
| 289 |
| 290 |
| 291 /* Do it! */ |
| 292 |
| 293 static void |
| 294 hb_ot_shape_execute_internal (hb_ot_shape_context_t *c) |
| 295 { |
| 296 /* Save the original direction, we use it later. */ |
| 297 c->target_direction = c->buffer->props.direction; |
| 298 |
| 299 hb_reset_glyph_infos (c); /* BUFFER: Clear buffer var1 and var2 */ |
| 300 |
| 301 hb_set_unicode_props (c); /* BUFFER: Set general_category and combining_class
in var1 */ |
| 302 |
| 303 hb_ensure_native_direction (c); |
| 304 |
| 305 hb_form_clusters (c); |
| 306 |
| 307 hb_ot_shape_setup_masks (c); /* BUFFER: Clobbers var2 */ |
| 308 |
| 309 /* SUBSTITUTE */ |
| 310 { |
| 311 /* Mirroring needs to see the original direction */ |
| 312 hb_mirror_chars (c); |
| 313 |
| 314 hb_substitute_default (c); |
| 315 |
| 316 hb_ot_substitute_complex (c); |
| 317 |
| 318 if (!c->applied_substitute_complex) |
| 319 hb_substitute_complex_fallback (c); |
| 320 } |
| 321 |
| 322 /* POSITION */ |
| 323 { |
| 324 hb_position_default (c); |
| 325 |
| 326 hb_ot_position_complex (c); |
| 327 |
| 328 hb_bool_t position_fallback = !c->applied_position_complex; |
| 329 if (position_fallback) |
| 330 hb_position_complex_fallback (c); |
| 331 |
| 332 if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) |
| 333 hb_buffer_reverse (c->buffer); |
| 334 |
| 335 if (position_fallback) |
| 336 hb_position_complex_fallback_visual (c); |
| 337 } |
| 338 |
| 339 c->buffer->props.direction = c->target_direction; |
| 340 } |
| 341 |
| 342 void |
| 343 hb_ot_shape_plan_internal (hb_ot_shape_plan_t *plan, |
| 344 hb_face_t *face, |
| 345 const hb_segment_properties_t *props, |
| 346 const hb_feature_t *user_features, |
| 347 unsigned int num_user_features) |
| 348 { |
| 349 plan->shaper = hb_ot_shape_complex_categorize (props); |
| 350 |
| 351 hb_ot_shape_collect_features (plan, props, user_features, num_user_features); |
| 352 |
| 353 plan->map.compile (face, props); |
| 354 } |
| 355 |
| 356 void |
| 357 hb_ot_shape_execute (hb_ot_shape_plan_t *plan, |
| 358 hb_font_t *font, |
| 359 hb_face_t *face, |
| 360 hb_buffer_t *buffer, |
| 361 const hb_feature_t *user_features, |
| 362 unsigned int num_user_features) |
| 363 { |
| 364 hb_ot_shape_context_t c = {plan, font, face, buffer, user_features, num_user_f
eatures}; |
| 365 hb_ot_shape_execute_internal (&c); |
| 366 } |
| 367 |
| 368 void |
| 369 hb_ot_shape (hb_font_t *font, |
| 370 hb_face_t *face, |
| 371 hb_buffer_t *buffer, |
| 372 const hb_feature_t *user_features, |
| 373 unsigned int num_user_features) |
| 374 { |
| 375 hb_ot_shape_plan_t plan; |
| 376 |
| 377 hb_ot_shape_plan_internal (&plan, face, &buffer->props, user_features, num_use
r_features); |
| 378 hb_ot_shape_execute (&plan, font, face, buffer, user_features, num_user_featur
es); |
| 379 } |
| 380 |
| 381 |
| 382 HB_END_DECLS |
OLD | NEW |