1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/harfbuzz/src/hb-ot-shape.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,751 @@ 1.4 +/* 1.5 + * Copyright © 2009,2010 Red Hat, Inc. 1.6 + * Copyright © 2010,2011,2012 Google, Inc. 1.7 + * 1.8 + * This is part of HarfBuzz, a text shaping library. 1.9 + * 1.10 + * Permission is hereby granted, without written agreement and without 1.11 + * license or royalty fees, to use, copy, modify, and distribute this 1.12 + * software and its documentation for any purpose, provided that the 1.13 + * above copyright notice and the following two paragraphs appear in 1.14 + * all copies of this software. 1.15 + * 1.16 + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 1.17 + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 1.18 + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 1.19 + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 1.20 + * DAMAGE. 1.21 + * 1.22 + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 1.23 + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 1.24 + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 1.25 + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 1.26 + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 1.27 + * 1.28 + * Red Hat Author(s): Behdad Esfahbod 1.29 + * Google Author(s): Behdad Esfahbod 1.30 + */ 1.31 + 1.32 +#define HB_SHAPER ot 1.33 +#define hb_ot_shaper_face_data_t hb_ot_layout_t 1.34 +#define hb_ot_shaper_shape_plan_data_t hb_ot_shape_plan_t 1.35 +#include "hb-shaper-impl-private.hh" 1.36 + 1.37 +#include "hb-ot-shape-private.hh" 1.38 +#include "hb-ot-shape-complex-private.hh" 1.39 +#include "hb-ot-shape-fallback-private.hh" 1.40 +#include "hb-ot-shape-normalize-private.hh" 1.41 + 1.42 +#include "hb-ot-layout-private.hh" 1.43 +#include "hb-set-private.hh" 1.44 + 1.45 + 1.46 +static hb_tag_t common_features[] = { 1.47 + HB_TAG('c','c','m','p'), 1.48 + HB_TAG('l','i','g','a'), 1.49 + HB_TAG('l','o','c','l'), 1.50 + HB_TAG('m','a','r','k'), 1.51 + HB_TAG('m','k','m','k'), 1.52 + HB_TAG('r','l','i','g'), 1.53 +}; 1.54 + 1.55 + 1.56 +static hb_tag_t horizontal_features[] = { 1.57 + HB_TAG('c','a','l','t'), 1.58 + HB_TAG('c','l','i','g'), 1.59 + HB_TAG('c','u','r','s'), 1.60 + HB_TAG('k','e','r','n'), 1.61 + HB_TAG('r','c','l','t'), 1.62 +}; 1.63 + 1.64 +static hb_tag_t vertical_features[] = { 1.65 + HB_TAG('v','e','r','t'), 1.66 +}; 1.67 + 1.68 + 1.69 + 1.70 +static void 1.71 +hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, 1.72 + const hb_segment_properties_t *props, 1.73 + const hb_feature_t *user_features, 1.74 + unsigned int num_user_features) 1.75 +{ 1.76 + hb_ot_map_builder_t *map = &planner->map; 1.77 + 1.78 + switch (props->direction) { 1.79 + case HB_DIRECTION_LTR: 1.80 + map->add_global_bool_feature (HB_TAG ('l','t','r','a')); 1.81 + map->add_global_bool_feature (HB_TAG ('l','t','r','m')); 1.82 + break; 1.83 + case HB_DIRECTION_RTL: 1.84 + map->add_global_bool_feature (HB_TAG ('r','t','l','a')); 1.85 + map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE); 1.86 + break; 1.87 + case HB_DIRECTION_TTB: 1.88 + case HB_DIRECTION_BTT: 1.89 + case HB_DIRECTION_INVALID: 1.90 + default: 1.91 + break; 1.92 + } 1.93 + 1.94 + map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE); 1.95 + map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE); 1.96 + map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE); 1.97 + 1.98 + if (planner->shaper->collect_features) 1.99 + planner->shaper->collect_features (planner); 1.100 + 1.101 + for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++) 1.102 + map->add_global_bool_feature (common_features[i]); 1.103 + 1.104 + if (HB_DIRECTION_IS_HORIZONTAL (props->direction)) 1.105 + for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++) 1.106 + map->add_feature (horizontal_features[i], 1, F_GLOBAL | 1.107 + (horizontal_features[i] == HB_TAG('k','e','r','n') ? 1.108 + F_HAS_FALLBACK : F_NONE)); 1.109 + else 1.110 + for (unsigned int i = 0; i < ARRAY_LENGTH (vertical_features); i++) 1.111 + map->add_feature (vertical_features[i], 1, F_GLOBAL | 1.112 + (vertical_features[i] == HB_TAG('v','k','r','n') ? 1.113 + F_HAS_FALLBACK : F_NONE)); 1.114 + 1.115 + if (planner->shaper->override_features) 1.116 + planner->shaper->override_features (planner); 1.117 + 1.118 + for (unsigned int i = 0; i < num_user_features; i++) { 1.119 + const hb_feature_t *feature = &user_features[i]; 1.120 + map->add_feature (feature->tag, feature->value, 1.121 + (feature->start == 0 && feature->end == (unsigned int) -1) ? 1.122 + F_GLOBAL : F_NONE); 1.123 + } 1.124 +} 1.125 + 1.126 + 1.127 +/* 1.128 + * shaper face data 1.129 + */ 1.130 + 1.131 +hb_ot_shaper_face_data_t * 1.132 +_hb_ot_shaper_face_data_create (hb_face_t *face) 1.133 +{ 1.134 + return _hb_ot_layout_create (face); 1.135 +} 1.136 + 1.137 +void 1.138 +_hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data) 1.139 +{ 1.140 + _hb_ot_layout_destroy (data); 1.141 +} 1.142 + 1.143 + 1.144 +/* 1.145 + * shaper font data 1.146 + */ 1.147 + 1.148 +struct hb_ot_shaper_font_data_t {}; 1.149 + 1.150 +hb_ot_shaper_font_data_t * 1.151 +_hb_ot_shaper_font_data_create (hb_font_t *font) 1.152 +{ 1.153 + return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; 1.154 +} 1.155 + 1.156 +void 1.157 +_hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data) 1.158 +{ 1.159 +} 1.160 + 1.161 + 1.162 +/* 1.163 + * shaper shape_plan data 1.164 + */ 1.165 + 1.166 +hb_ot_shaper_shape_plan_data_t * 1.167 +_hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan, 1.168 + const hb_feature_t *user_features, 1.169 + unsigned int num_user_features) 1.170 +{ 1.171 + hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t)); 1.172 + if (unlikely (!plan)) 1.173 + return NULL; 1.174 + 1.175 + hb_ot_shape_planner_t planner (shape_plan); 1.176 + 1.177 + planner.shaper = hb_ot_shape_complex_categorize (&planner); 1.178 + 1.179 + hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features); 1.180 + 1.181 + planner.compile (*plan); 1.182 + 1.183 + if (plan->shaper->data_create) { 1.184 + plan->data = plan->shaper->data_create (plan); 1.185 + if (unlikely (!plan->data)) 1.186 + return NULL; 1.187 + } 1.188 + 1.189 + return plan; 1.190 +} 1.191 + 1.192 +void 1.193 +_hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan) 1.194 +{ 1.195 + if (plan->shaper->data_destroy) 1.196 + plan->shaper->data_destroy (const_cast<void *> (plan->data)); 1.197 + 1.198 + plan->finish (); 1.199 + 1.200 + free (plan); 1.201 +} 1.202 + 1.203 + 1.204 +/* 1.205 + * shaper 1.206 + */ 1.207 + 1.208 +struct hb_ot_shape_context_t 1.209 +{ 1.210 + hb_ot_shape_plan_t *plan; 1.211 + hb_font_t *font; 1.212 + hb_face_t *face; 1.213 + hb_buffer_t *buffer; 1.214 + const hb_feature_t *user_features; 1.215 + unsigned int num_user_features; 1.216 + 1.217 + /* Transient stuff */ 1.218 + hb_direction_t target_direction; 1.219 +}; 1.220 + 1.221 + 1.222 + 1.223 +/* Main shaper */ 1.224 + 1.225 + 1.226 +/* Prepare */ 1.227 + 1.228 +static void 1.229 +hb_set_unicode_props (hb_buffer_t *buffer) 1.230 +{ 1.231 + unsigned int count = buffer->len; 1.232 + for (unsigned int i = 0; i < count; i++) 1.233 + _hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode); 1.234 +} 1.235 + 1.236 +static void 1.237 +hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font) 1.238 +{ 1.239 + if (!(buffer->flags & HB_BUFFER_FLAG_BOT) || 1.240 + _hb_glyph_info_get_general_category (&buffer->info[0]) != 1.241 + HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 1.242 + return; 1.243 + 1.244 + if (!font->has_glyph (0x25CC)) 1.245 + return; 1.246 + 1.247 + hb_glyph_info_t dottedcircle; 1.248 + dottedcircle.codepoint = 0x25CC; 1.249 + _hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode); 1.250 + 1.251 + buffer->clear_output (); 1.252 + 1.253 + buffer->idx = 0; 1.254 + hb_glyph_info_t info = dottedcircle; 1.255 + info.cluster = buffer->cur().cluster; 1.256 + info.mask = buffer->cur().mask; 1.257 + buffer->output_info (info); 1.258 + while (buffer->idx < buffer->len) 1.259 + buffer->next_glyph (); 1.260 + 1.261 + buffer->swap_buffers (); 1.262 +} 1.263 + 1.264 +static void 1.265 +hb_form_clusters (hb_buffer_t *buffer) 1.266 +{ 1.267 + unsigned int count = buffer->len; 1.268 + for (unsigned int i = 1; i < count; i++) 1.269 + if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[i]))) 1.270 + buffer->merge_clusters (i - 1, i + 1); 1.271 +} 1.272 + 1.273 +static void 1.274 +hb_ensure_native_direction (hb_buffer_t *buffer) 1.275 +{ 1.276 + hb_direction_t direction = buffer->props.direction; 1.277 + 1.278 + /* TODO vertical: 1.279 + * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType 1.280 + * Ogham fonts are supposed to be implemented BTT or not. Need to research that 1.281 + * first. */ 1.282 + if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_horizontal_direction (buffer->props.script)) || 1.283 + (HB_DIRECTION_IS_VERTICAL (direction) && direction != HB_DIRECTION_TTB)) 1.284 + { 1.285 + hb_buffer_reverse_clusters (buffer); 1.286 + buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction); 1.287 + } 1.288 +} 1.289 + 1.290 + 1.291 +/* Substitute */ 1.292 + 1.293 +static inline void 1.294 +hb_ot_mirror_chars (hb_ot_shape_context_t *c) 1.295 +{ 1.296 + if (HB_DIRECTION_IS_FORWARD (c->target_direction)) 1.297 + return; 1.298 + 1.299 + hb_buffer_t *buffer = c->buffer; 1.300 + hb_unicode_funcs_t *unicode = buffer->unicode; 1.301 + hb_mask_t rtlm_mask = c->plan->rtlm_mask; 1.302 + 1.303 + unsigned int count = buffer->len; 1.304 + hb_glyph_info_t *info = buffer->info; 1.305 + for (unsigned int i = 0; i < count; i++) { 1.306 + hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint); 1.307 + if (likely (codepoint == info[i].codepoint)) 1.308 + info[i].mask |= rtlm_mask; 1.309 + else 1.310 + info[i].codepoint = codepoint; 1.311 + } 1.312 +} 1.313 + 1.314 +static inline void 1.315 +hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c) 1.316 +{ 1.317 + if (!c->plan->has_frac) 1.318 + return; 1.319 + 1.320 + hb_buffer_t *buffer = c->buffer; 1.321 + 1.322 + /* TODO look in pre/post context text also. */ 1.323 + unsigned int count = buffer->len; 1.324 + hb_glyph_info_t *info = buffer->info; 1.325 + for (unsigned int i = 0; i < count; i++) 1.326 + { 1.327 + if (info[i].codepoint == 0x2044) /* FRACTION SLASH */ 1.328 + { 1.329 + unsigned int start = i, end = i + 1; 1.330 + while (start && 1.331 + _hb_glyph_info_get_general_category (&info[start - 1]) == 1.332 + HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) 1.333 + start--; 1.334 + while (end < count && 1.335 + _hb_glyph_info_get_general_category (&info[end]) == 1.336 + HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) 1.337 + end++; 1.338 + 1.339 + for (unsigned int j = start; j < i; j++) 1.340 + info[j].mask |= c->plan->numr_mask | c->plan->frac_mask; 1.341 + info[i].mask |= c->plan->frac_mask; 1.342 + for (unsigned int j = i + 1; j < end; j++) 1.343 + info[j].mask |= c->plan->frac_mask | c->plan->dnom_mask; 1.344 + 1.345 + i = end - 1; 1.346 + } 1.347 + } 1.348 +} 1.349 + 1.350 +static inline void 1.351 +hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c) 1.352 +{ 1.353 + hb_ot_map_t *map = &c->plan->map; 1.354 + hb_buffer_t *buffer = c->buffer; 1.355 + 1.356 + hb_mask_t global_mask = map->get_global_mask (); 1.357 + buffer->reset_masks (global_mask); 1.358 +} 1.359 + 1.360 +static inline void 1.361 +hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) 1.362 +{ 1.363 + hb_ot_map_t *map = &c->plan->map; 1.364 + hb_buffer_t *buffer = c->buffer; 1.365 + 1.366 + hb_ot_shape_setup_masks_fraction (c); 1.367 + 1.368 + if (c->plan->shaper->setup_masks) 1.369 + c->plan->shaper->setup_masks (c->plan, buffer, c->font); 1.370 + 1.371 + for (unsigned int i = 0; i < c->num_user_features; i++) 1.372 + { 1.373 + const hb_feature_t *feature = &c->user_features[i]; 1.374 + if (!(feature->start == 0 && feature->end == (unsigned int)-1)) { 1.375 + unsigned int shift; 1.376 + hb_mask_t mask = map->get_mask (feature->tag, &shift); 1.377 + buffer->set_masks (feature->value << shift, mask, feature->start, feature->end); 1.378 + } 1.379 + } 1.380 +} 1.381 + 1.382 +static inline void 1.383 +hb_ot_map_glyphs_fast (hb_buffer_t *buffer) 1.384 +{ 1.385 + /* Normalization process sets up glyph_index(), we just copy it. */ 1.386 + unsigned int count = buffer->len; 1.387 + for (unsigned int i = 0; i < count; i++) 1.388 + buffer->info[i].codepoint = buffer->info[i].glyph_index(); 1.389 +} 1.390 + 1.391 +static inline void 1.392 +hb_synthesize_glyph_classes (hb_ot_shape_context_t *c) 1.393 +{ 1.394 + unsigned int count = c->buffer->len; 1.395 + hb_glyph_info_t *info = c->buffer->info; 1.396 + for (unsigned int i = 0; i < count; i++) 1.397 + _hb_glyph_info_set_glyph_props (&info[i], 1.398 + _hb_glyph_info_get_general_category (&info[i]) 1.399 + == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ? 1.400 + HB_OT_LAYOUT_GLYPH_PROPS_MARK : 1.401 + HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH); 1.402 +} 1.403 + 1.404 +static inline void 1.405 +hb_ot_substitute_default (hb_ot_shape_context_t *c) 1.406 +{ 1.407 + hb_buffer_t *buffer = c->buffer; 1.408 + 1.409 + if (c->plan->shaper->preprocess_text) 1.410 + c->plan->shaper->preprocess_text (c->plan, buffer, c->font); 1.411 + 1.412 + hb_ot_shape_initialize_masks (c); 1.413 + 1.414 + hb_ot_mirror_chars (c); 1.415 + 1.416 + HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index); 1.417 + 1.418 + _hb_ot_shape_normalize (c->plan, buffer, c->font); 1.419 + 1.420 + hb_ot_shape_setup_masks (c); 1.421 + 1.422 + /* This is unfortunate to go here, but necessary... */ 1.423 + if (!hb_ot_layout_has_positioning (c->face)) 1.424 + _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer); 1.425 + 1.426 + hb_ot_map_glyphs_fast (buffer); 1.427 + 1.428 + HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index); 1.429 +} 1.430 + 1.431 +static inline void 1.432 +hb_ot_substitute_complex (hb_ot_shape_context_t *c) 1.433 +{ 1.434 + hb_buffer_t *buffer = c->buffer; 1.435 + 1.436 + hb_ot_layout_substitute_start (c->font, buffer); 1.437 + 1.438 + if (!hb_ot_layout_has_glyph_classes (c->face)) 1.439 + hb_synthesize_glyph_classes (c); 1.440 + 1.441 + c->plan->substitute (c->font, buffer); 1.442 + 1.443 + hb_ot_layout_substitute_finish (c->font, buffer); 1.444 + 1.445 + return; 1.446 +} 1.447 + 1.448 +static inline void 1.449 +hb_ot_substitute (hb_ot_shape_context_t *c) 1.450 +{ 1.451 + hb_ot_substitute_default (c); 1.452 + hb_ot_substitute_complex (c); 1.453 +} 1.454 + 1.455 +/* Position */ 1.456 + 1.457 +static inline void 1.458 +zero_mark_widths_by_unicode (hb_buffer_t *buffer) 1.459 +{ 1.460 + unsigned int count = buffer->len; 1.461 + for (unsigned int i = 0; i < count; i++) 1.462 + if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 1.463 + { 1.464 + buffer->pos[i].x_advance = 0; 1.465 + buffer->pos[i].y_advance = 0; 1.466 + } 1.467 +} 1.468 + 1.469 +static inline void 1.470 +zero_mark_widths_by_gdef (hb_buffer_t *buffer) 1.471 +{ 1.472 + unsigned int count = buffer->len; 1.473 + for (unsigned int i = 0; i < count; i++) 1.474 + if (_hb_glyph_info_is_mark (&buffer->info[i])) 1.475 + { 1.476 + buffer->pos[i].x_advance = 0; 1.477 + buffer->pos[i].y_advance = 0; 1.478 + } 1.479 +} 1.480 + 1.481 +static inline void 1.482 +hb_ot_position_default (hb_ot_shape_context_t *c) 1.483 +{ 1.484 + hb_direction_t direction = c->buffer->props.direction; 1.485 + unsigned int count = c->buffer->len; 1.486 + hb_glyph_info_t *info = c->buffer->info; 1.487 + hb_glyph_position_t *pos = c->buffer->pos; 1.488 + for (unsigned int i = 0; i < count; i++) 1.489 + { 1.490 + c->font->get_glyph_advance_for_direction (info[i].codepoint, 1.491 + direction, 1.492 + &pos[i].x_advance, 1.493 + &pos[i].y_advance); 1.494 + c->font->subtract_glyph_origin_for_direction (info[i].codepoint, 1.495 + direction, 1.496 + &pos[i].x_offset, 1.497 + &pos[i].y_offset); 1.498 + 1.499 + } 1.500 +} 1.501 + 1.502 +static inline bool 1.503 +hb_ot_position_complex (hb_ot_shape_context_t *c) 1.504 +{ 1.505 + bool ret = false; 1.506 + unsigned int count = c->buffer->len; 1.507 + 1.508 + switch (c->plan->shaper->zero_width_marks) 1.509 + { 1.510 + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: 1.511 + zero_mark_widths_by_gdef (c->buffer); 1.512 + break; 1.513 + 1.514 + /* Not currently used for any shaper: 1.515 + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY: 1.516 + zero_mark_widths_by_unicode (c->buffer); 1.517 + break; 1.518 + */ 1.519 + 1.520 + default: 1.521 + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: 1.522 + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE: 1.523 + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: 1.524 + break; 1.525 + } 1.526 + 1.527 + if (hb_ot_layout_has_positioning (c->face)) 1.528 + { 1.529 + hb_glyph_info_t *info = c->buffer->info; 1.530 + hb_glyph_position_t *pos = c->buffer->pos; 1.531 + 1.532 + /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */ 1.533 + 1.534 + for (unsigned int i = 0; i < count; i++) { 1.535 + c->font->add_glyph_origin_for_direction (info[i].codepoint, 1.536 + HB_DIRECTION_LTR, 1.537 + &pos[i].x_offset, 1.538 + &pos[i].y_offset); 1.539 + } 1.540 + 1.541 + c->plan->position (c->font, c->buffer); 1.542 + 1.543 + for (unsigned int i = 0; i < count; i++) { 1.544 + c->font->subtract_glyph_origin_for_direction (info[i].codepoint, 1.545 + HB_DIRECTION_LTR, 1.546 + &pos[i].x_offset, 1.547 + &pos[i].y_offset); 1.548 + } 1.549 + 1.550 + ret = true; 1.551 + } 1.552 + 1.553 + switch (c->plan->shaper->zero_width_marks) 1.554 + { 1.555 + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE: 1.556 + zero_mark_widths_by_unicode (c->buffer); 1.557 + break; 1.558 + 1.559 + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: 1.560 + zero_mark_widths_by_gdef (c->buffer); 1.561 + break; 1.562 + 1.563 + default: 1.564 + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: 1.565 + //case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY: 1.566 + case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: 1.567 + break; 1.568 + } 1.569 + 1.570 + return ret; 1.571 +} 1.572 + 1.573 +static inline void 1.574 +hb_ot_position (hb_ot_shape_context_t *c) 1.575 +{ 1.576 + hb_ot_layout_position_start (c->font, c->buffer); 1.577 + 1.578 + hb_ot_position_default (c); 1.579 + 1.580 + hb_bool_t fallback = !hb_ot_position_complex (c); 1.581 + 1.582 + hb_ot_layout_position_finish (c->font, c->buffer); 1.583 + 1.584 + if (fallback && c->plan->shaper->fallback_position) 1.585 + _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer); 1.586 + 1.587 + if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) 1.588 + hb_buffer_reverse (c->buffer); 1.589 + 1.590 + /* Visual fallback goes here. */ 1.591 + 1.592 + if (fallback) 1.593 + _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer); 1.594 +} 1.595 + 1.596 + 1.597 +/* Post-process */ 1.598 + 1.599 +static void 1.600 +hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c) 1.601 +{ 1.602 + if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES) 1.603 + return; 1.604 + 1.605 + hb_codepoint_t space; 1.606 + enum { 1.607 + SPACE_DONT_KNOW, 1.608 + SPACE_AVAILABLE, 1.609 + SPACE_UNAVAILABLE 1.610 + } space_status = SPACE_DONT_KNOW; 1.611 + 1.612 + unsigned int count = c->buffer->len; 1.613 + hb_glyph_info_t *info = c->buffer->info; 1.614 + hb_glyph_position_t *pos = c->buffer->pos; 1.615 + unsigned int j = 0; 1.616 + for (unsigned int i = 0; i < count; i++) 1.617 + { 1.618 + if (unlikely (!_hb_glyph_info_ligated (&info[i]) && 1.619 + _hb_glyph_info_is_default_ignorable (&info[i]))) 1.620 + { 1.621 + if (space_status == SPACE_DONT_KNOW) 1.622 + space_status = c->font->get_glyph (' ', 0, &space) ? SPACE_AVAILABLE : SPACE_UNAVAILABLE; 1.623 + 1.624 + if (space_status == SPACE_AVAILABLE) 1.625 + { 1.626 + info[i].codepoint = space; 1.627 + pos[i].x_advance = 0; 1.628 + pos[i].y_advance = 0; 1.629 + } 1.630 + else 1.631 + continue; /* Delete it. */ 1.632 + } 1.633 + if (j != i) 1.634 + { 1.635 + info[j] = info[i]; 1.636 + pos[j] = pos[i]; 1.637 + } 1.638 + j++; 1.639 + } 1.640 + c->buffer->len = j; 1.641 +} 1.642 + 1.643 + 1.644 +/* Pull it all together! */ 1.645 + 1.646 +static void 1.647 +hb_ot_shape_internal (hb_ot_shape_context_t *c) 1.648 +{ 1.649 + c->buffer->deallocate_var_all (); 1.650 + 1.651 + /* Save the original direction, we use it later. */ 1.652 + c->target_direction = c->buffer->props.direction; 1.653 + 1.654 + _hb_buffer_allocate_unicode_vars (c->buffer); 1.655 + 1.656 + c->buffer->clear_output (); 1.657 + 1.658 + hb_set_unicode_props (c->buffer); 1.659 + hb_insert_dotted_circle (c->buffer, c->font); 1.660 + hb_form_clusters (c->buffer); 1.661 + 1.662 + hb_ensure_native_direction (c->buffer); 1.663 + 1.664 + hb_ot_substitute (c); 1.665 + hb_ot_position (c); 1.666 + 1.667 + hb_ot_hide_default_ignorables (c); 1.668 + 1.669 + _hb_buffer_deallocate_unicode_vars (c->buffer); 1.670 + 1.671 + c->buffer->props.direction = c->target_direction; 1.672 + 1.673 + c->buffer->deallocate_var_all (); 1.674 +} 1.675 + 1.676 + 1.677 +hb_bool_t 1.678 +_hb_ot_shape (hb_shape_plan_t *shape_plan, 1.679 + hb_font_t *font, 1.680 + hb_buffer_t *buffer, 1.681 + const hb_feature_t *features, 1.682 + unsigned int num_features) 1.683 +{ 1.684 + hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features}; 1.685 + hb_ot_shape_internal (&c); 1.686 + 1.687 + return true; 1.688 +} 1.689 + 1.690 + 1.691 +void 1.692 +hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan, 1.693 + hb_tag_t table_tag, 1.694 + hb_set_t *lookup_indexes /* OUT */) 1.695 +{ 1.696 + /* XXX Does the first part always succeed? */ 1.697 + HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes); 1.698 +} 1.699 + 1.700 + 1.701 +/* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */ 1.702 +static void 1.703 +add_char (hb_font_t *font, 1.704 + hb_unicode_funcs_t *unicode, 1.705 + hb_bool_t mirror, 1.706 + hb_codepoint_t u, 1.707 + hb_set_t *glyphs) 1.708 +{ 1.709 + hb_codepoint_t glyph; 1.710 + if (font->get_glyph (u, 0, &glyph)) 1.711 + glyphs->add (glyph); 1.712 + if (mirror) 1.713 + { 1.714 + hb_codepoint_t m = unicode->mirroring (u); 1.715 + if (m != u && font->get_glyph (m, 0, &glyph)) 1.716 + glyphs->add (glyph); 1.717 + } 1.718 +} 1.719 + 1.720 + 1.721 +void 1.722 +hb_ot_shape_glyphs_closure (hb_font_t *font, 1.723 + hb_buffer_t *buffer, 1.724 + const hb_feature_t *features, 1.725 + unsigned int num_features, 1.726 + hb_set_t *glyphs) 1.727 +{ 1.728 + hb_ot_shape_plan_t plan; 1.729 + 1.730 + const char *shapers[] = {"ot", NULL}; 1.731 + hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, 1.732 + features, num_features, shapers); 1.733 + 1.734 + bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL; 1.735 + 1.736 + unsigned int count = buffer->len; 1.737 + for (unsigned int i = 0; i < count; i++) 1.738 + add_char (font, buffer->unicode, mirror, buffer->info[i].codepoint, glyphs); 1.739 + 1.740 + hb_set_t lookups; 1.741 + lookups.init (); 1.742 + hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups); 1.743 + 1.744 + /* And find transitive closure. */ 1.745 + hb_set_t copy; 1.746 + copy.init (); 1.747 + do { 1.748 + copy.set (glyphs); 1.749 + for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);) 1.750 + hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs); 1.751 + } while (!copy.is_equal (glyphs)); 1.752 + 1.753 + hb_shape_plan_destroy (shape_plan); 1.754 +}