gfx/harfbuzz/src/hb-ot-shape.cc

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /*
michael@0 2 * Copyright © 2009,2010 Red Hat, Inc.
michael@0 3 * Copyright © 2010,2011,2012 Google, Inc.
michael@0 4 *
michael@0 5 * This is part of HarfBuzz, a text shaping library.
michael@0 6 *
michael@0 7 * Permission is hereby granted, without written agreement and without
michael@0 8 * license or royalty fees, to use, copy, modify, and distribute this
michael@0 9 * software and its documentation for any purpose, provided that the
michael@0 10 * above copyright notice and the following two paragraphs appear in
michael@0 11 * all copies of this software.
michael@0 12 *
michael@0 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
michael@0 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
michael@0 15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
michael@0 16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
michael@0 17 * DAMAGE.
michael@0 18 *
michael@0 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
michael@0 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
michael@0 21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
michael@0 22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
michael@0 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
michael@0 24 *
michael@0 25 * Red Hat Author(s): Behdad Esfahbod
michael@0 26 * Google Author(s): Behdad Esfahbod
michael@0 27 */
michael@0 28
michael@0 29 #define HB_SHAPER ot
michael@0 30 #define hb_ot_shaper_face_data_t hb_ot_layout_t
michael@0 31 #define hb_ot_shaper_shape_plan_data_t hb_ot_shape_plan_t
michael@0 32 #include "hb-shaper-impl-private.hh"
michael@0 33
michael@0 34 #include "hb-ot-shape-private.hh"
michael@0 35 #include "hb-ot-shape-complex-private.hh"
michael@0 36 #include "hb-ot-shape-fallback-private.hh"
michael@0 37 #include "hb-ot-shape-normalize-private.hh"
michael@0 38
michael@0 39 #include "hb-ot-layout-private.hh"
michael@0 40 #include "hb-set-private.hh"
michael@0 41
michael@0 42
michael@0 43 static hb_tag_t common_features[] = {
michael@0 44 HB_TAG('c','c','m','p'),
michael@0 45 HB_TAG('l','i','g','a'),
michael@0 46 HB_TAG('l','o','c','l'),
michael@0 47 HB_TAG('m','a','r','k'),
michael@0 48 HB_TAG('m','k','m','k'),
michael@0 49 HB_TAG('r','l','i','g'),
michael@0 50 };
michael@0 51
michael@0 52
michael@0 53 static hb_tag_t horizontal_features[] = {
michael@0 54 HB_TAG('c','a','l','t'),
michael@0 55 HB_TAG('c','l','i','g'),
michael@0 56 HB_TAG('c','u','r','s'),
michael@0 57 HB_TAG('k','e','r','n'),
michael@0 58 HB_TAG('r','c','l','t'),
michael@0 59 };
michael@0 60
michael@0 61 static hb_tag_t vertical_features[] = {
michael@0 62 HB_TAG('v','e','r','t'),
michael@0 63 };
michael@0 64
michael@0 65
michael@0 66
michael@0 67 static void
michael@0 68 hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
michael@0 69 const hb_segment_properties_t *props,
michael@0 70 const hb_feature_t *user_features,
michael@0 71 unsigned int num_user_features)
michael@0 72 {
michael@0 73 hb_ot_map_builder_t *map = &planner->map;
michael@0 74
michael@0 75 switch (props->direction) {
michael@0 76 case HB_DIRECTION_LTR:
michael@0 77 map->add_global_bool_feature (HB_TAG ('l','t','r','a'));
michael@0 78 map->add_global_bool_feature (HB_TAG ('l','t','r','m'));
michael@0 79 break;
michael@0 80 case HB_DIRECTION_RTL:
michael@0 81 map->add_global_bool_feature (HB_TAG ('r','t','l','a'));
michael@0 82 map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE);
michael@0 83 break;
michael@0 84 case HB_DIRECTION_TTB:
michael@0 85 case HB_DIRECTION_BTT:
michael@0 86 case HB_DIRECTION_INVALID:
michael@0 87 default:
michael@0 88 break;
michael@0 89 }
michael@0 90
michael@0 91 map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE);
michael@0 92 map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE);
michael@0 93 map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE);
michael@0 94
michael@0 95 if (planner->shaper->collect_features)
michael@0 96 planner->shaper->collect_features (planner);
michael@0 97
michael@0 98 for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++)
michael@0 99 map->add_global_bool_feature (common_features[i]);
michael@0 100
michael@0 101 if (HB_DIRECTION_IS_HORIZONTAL (props->direction))
michael@0 102 for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++)
michael@0 103 map->add_feature (horizontal_features[i], 1, F_GLOBAL |
michael@0 104 (horizontal_features[i] == HB_TAG('k','e','r','n') ?
michael@0 105 F_HAS_FALLBACK : F_NONE));
michael@0 106 else
michael@0 107 for (unsigned int i = 0; i < ARRAY_LENGTH (vertical_features); i++)
michael@0 108 map->add_feature (vertical_features[i], 1, F_GLOBAL |
michael@0 109 (vertical_features[i] == HB_TAG('v','k','r','n') ?
michael@0 110 F_HAS_FALLBACK : F_NONE));
michael@0 111
michael@0 112 if (planner->shaper->override_features)
michael@0 113 planner->shaper->override_features (planner);
michael@0 114
michael@0 115 for (unsigned int i = 0; i < num_user_features; i++) {
michael@0 116 const hb_feature_t *feature = &user_features[i];
michael@0 117 map->add_feature (feature->tag, feature->value,
michael@0 118 (feature->start == 0 && feature->end == (unsigned int) -1) ?
michael@0 119 F_GLOBAL : F_NONE);
michael@0 120 }
michael@0 121 }
michael@0 122
michael@0 123
michael@0 124 /*
michael@0 125 * shaper face data
michael@0 126 */
michael@0 127
michael@0 128 hb_ot_shaper_face_data_t *
michael@0 129 _hb_ot_shaper_face_data_create (hb_face_t *face)
michael@0 130 {
michael@0 131 return _hb_ot_layout_create (face);
michael@0 132 }
michael@0 133
michael@0 134 void
michael@0 135 _hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data)
michael@0 136 {
michael@0 137 _hb_ot_layout_destroy (data);
michael@0 138 }
michael@0 139
michael@0 140
michael@0 141 /*
michael@0 142 * shaper font data
michael@0 143 */
michael@0 144
michael@0 145 struct hb_ot_shaper_font_data_t {};
michael@0 146
michael@0 147 hb_ot_shaper_font_data_t *
michael@0 148 _hb_ot_shaper_font_data_create (hb_font_t *font)
michael@0 149 {
michael@0 150 return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
michael@0 151 }
michael@0 152
michael@0 153 void
michael@0 154 _hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data)
michael@0 155 {
michael@0 156 }
michael@0 157
michael@0 158
michael@0 159 /*
michael@0 160 * shaper shape_plan data
michael@0 161 */
michael@0 162
michael@0 163 hb_ot_shaper_shape_plan_data_t *
michael@0 164 _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan,
michael@0 165 const hb_feature_t *user_features,
michael@0 166 unsigned int num_user_features)
michael@0 167 {
michael@0 168 hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
michael@0 169 if (unlikely (!plan))
michael@0 170 return NULL;
michael@0 171
michael@0 172 hb_ot_shape_planner_t planner (shape_plan);
michael@0 173
michael@0 174 planner.shaper = hb_ot_shape_complex_categorize (&planner);
michael@0 175
michael@0 176 hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features);
michael@0 177
michael@0 178 planner.compile (*plan);
michael@0 179
michael@0 180 if (plan->shaper->data_create) {
michael@0 181 plan->data = plan->shaper->data_create (plan);
michael@0 182 if (unlikely (!plan->data))
michael@0 183 return NULL;
michael@0 184 }
michael@0 185
michael@0 186 return plan;
michael@0 187 }
michael@0 188
michael@0 189 void
michael@0 190 _hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan)
michael@0 191 {
michael@0 192 if (plan->shaper->data_destroy)
michael@0 193 plan->shaper->data_destroy (const_cast<void *> (plan->data));
michael@0 194
michael@0 195 plan->finish ();
michael@0 196
michael@0 197 free (plan);
michael@0 198 }
michael@0 199
michael@0 200
michael@0 201 /*
michael@0 202 * shaper
michael@0 203 */
michael@0 204
michael@0 205 struct hb_ot_shape_context_t
michael@0 206 {
michael@0 207 hb_ot_shape_plan_t *plan;
michael@0 208 hb_font_t *font;
michael@0 209 hb_face_t *face;
michael@0 210 hb_buffer_t *buffer;
michael@0 211 const hb_feature_t *user_features;
michael@0 212 unsigned int num_user_features;
michael@0 213
michael@0 214 /* Transient stuff */
michael@0 215 hb_direction_t target_direction;
michael@0 216 };
michael@0 217
michael@0 218
michael@0 219
michael@0 220 /* Main shaper */
michael@0 221
michael@0 222
michael@0 223 /* Prepare */
michael@0 224
michael@0 225 static void
michael@0 226 hb_set_unicode_props (hb_buffer_t *buffer)
michael@0 227 {
michael@0 228 unsigned int count = buffer->len;
michael@0 229 for (unsigned int i = 0; i < count; i++)
michael@0 230 _hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode);
michael@0 231 }
michael@0 232
michael@0 233 static void
michael@0 234 hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
michael@0 235 {
michael@0 236 if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
michael@0 237 _hb_glyph_info_get_general_category (&buffer->info[0]) !=
michael@0 238 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
michael@0 239 return;
michael@0 240
michael@0 241 if (!font->has_glyph (0x25CC))
michael@0 242 return;
michael@0 243
michael@0 244 hb_glyph_info_t dottedcircle;
michael@0 245 dottedcircle.codepoint = 0x25CC;
michael@0 246 _hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode);
michael@0 247
michael@0 248 buffer->clear_output ();
michael@0 249
michael@0 250 buffer->idx = 0;
michael@0 251 hb_glyph_info_t info = dottedcircle;
michael@0 252 info.cluster = buffer->cur().cluster;
michael@0 253 info.mask = buffer->cur().mask;
michael@0 254 buffer->output_info (info);
michael@0 255 while (buffer->idx < buffer->len)
michael@0 256 buffer->next_glyph ();
michael@0 257
michael@0 258 buffer->swap_buffers ();
michael@0 259 }
michael@0 260
michael@0 261 static void
michael@0 262 hb_form_clusters (hb_buffer_t *buffer)
michael@0 263 {
michael@0 264 unsigned int count = buffer->len;
michael@0 265 for (unsigned int i = 1; i < count; i++)
michael@0 266 if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[i])))
michael@0 267 buffer->merge_clusters (i - 1, i + 1);
michael@0 268 }
michael@0 269
michael@0 270 static void
michael@0 271 hb_ensure_native_direction (hb_buffer_t *buffer)
michael@0 272 {
michael@0 273 hb_direction_t direction = buffer->props.direction;
michael@0 274
michael@0 275 /* TODO vertical:
michael@0 276 * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
michael@0 277 * Ogham fonts are supposed to be implemented BTT or not. Need to research that
michael@0 278 * first. */
michael@0 279 if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_horizontal_direction (buffer->props.script)) ||
michael@0 280 (HB_DIRECTION_IS_VERTICAL (direction) && direction != HB_DIRECTION_TTB))
michael@0 281 {
michael@0 282 hb_buffer_reverse_clusters (buffer);
michael@0 283 buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
michael@0 284 }
michael@0 285 }
michael@0 286
michael@0 287
michael@0 288 /* Substitute */
michael@0 289
michael@0 290 static inline void
michael@0 291 hb_ot_mirror_chars (hb_ot_shape_context_t *c)
michael@0 292 {
michael@0 293 if (HB_DIRECTION_IS_FORWARD (c->target_direction))
michael@0 294 return;
michael@0 295
michael@0 296 hb_buffer_t *buffer = c->buffer;
michael@0 297 hb_unicode_funcs_t *unicode = buffer->unicode;
michael@0 298 hb_mask_t rtlm_mask = c->plan->rtlm_mask;
michael@0 299
michael@0 300 unsigned int count = buffer->len;
michael@0 301 hb_glyph_info_t *info = buffer->info;
michael@0 302 for (unsigned int i = 0; i < count; i++) {
michael@0 303 hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
michael@0 304 if (likely (codepoint == info[i].codepoint))
michael@0 305 info[i].mask |= rtlm_mask;
michael@0 306 else
michael@0 307 info[i].codepoint = codepoint;
michael@0 308 }
michael@0 309 }
michael@0 310
michael@0 311 static inline void
michael@0 312 hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
michael@0 313 {
michael@0 314 if (!c->plan->has_frac)
michael@0 315 return;
michael@0 316
michael@0 317 hb_buffer_t *buffer = c->buffer;
michael@0 318
michael@0 319 /* TODO look in pre/post context text also. */
michael@0 320 unsigned int count = buffer->len;
michael@0 321 hb_glyph_info_t *info = buffer->info;
michael@0 322 for (unsigned int i = 0; i < count; i++)
michael@0 323 {
michael@0 324 if (info[i].codepoint == 0x2044) /* FRACTION SLASH */
michael@0 325 {
michael@0 326 unsigned int start = i, end = i + 1;
michael@0 327 while (start &&
michael@0 328 _hb_glyph_info_get_general_category (&info[start - 1]) ==
michael@0 329 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
michael@0 330 start--;
michael@0 331 while (end < count &&
michael@0 332 _hb_glyph_info_get_general_category (&info[end]) ==
michael@0 333 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
michael@0 334 end++;
michael@0 335
michael@0 336 for (unsigned int j = start; j < i; j++)
michael@0 337 info[j].mask |= c->plan->numr_mask | c->plan->frac_mask;
michael@0 338 info[i].mask |= c->plan->frac_mask;
michael@0 339 for (unsigned int j = i + 1; j < end; j++)
michael@0 340 info[j].mask |= c->plan->frac_mask | c->plan->dnom_mask;
michael@0 341
michael@0 342 i = end - 1;
michael@0 343 }
michael@0 344 }
michael@0 345 }
michael@0 346
michael@0 347 static inline void
michael@0 348 hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c)
michael@0 349 {
michael@0 350 hb_ot_map_t *map = &c->plan->map;
michael@0 351 hb_buffer_t *buffer = c->buffer;
michael@0 352
michael@0 353 hb_mask_t global_mask = map->get_global_mask ();
michael@0 354 buffer->reset_masks (global_mask);
michael@0 355 }
michael@0 356
michael@0 357 static inline void
michael@0 358 hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
michael@0 359 {
michael@0 360 hb_ot_map_t *map = &c->plan->map;
michael@0 361 hb_buffer_t *buffer = c->buffer;
michael@0 362
michael@0 363 hb_ot_shape_setup_masks_fraction (c);
michael@0 364
michael@0 365 if (c->plan->shaper->setup_masks)
michael@0 366 c->plan->shaper->setup_masks (c->plan, buffer, c->font);
michael@0 367
michael@0 368 for (unsigned int i = 0; i < c->num_user_features; i++)
michael@0 369 {
michael@0 370 const hb_feature_t *feature = &c->user_features[i];
michael@0 371 if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
michael@0 372 unsigned int shift;
michael@0 373 hb_mask_t mask = map->get_mask (feature->tag, &shift);
michael@0 374 buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
michael@0 375 }
michael@0 376 }
michael@0 377 }
michael@0 378
michael@0 379 static inline void
michael@0 380 hb_ot_map_glyphs_fast (hb_buffer_t *buffer)
michael@0 381 {
michael@0 382 /* Normalization process sets up glyph_index(), we just copy it. */
michael@0 383 unsigned int count = buffer->len;
michael@0 384 for (unsigned int i = 0; i < count; i++)
michael@0 385 buffer->info[i].codepoint = buffer->info[i].glyph_index();
michael@0 386 }
michael@0 387
michael@0 388 static inline void
michael@0 389 hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
michael@0 390 {
michael@0 391 unsigned int count = c->buffer->len;
michael@0 392 hb_glyph_info_t *info = c->buffer->info;
michael@0 393 for (unsigned int i = 0; i < count; i++)
michael@0 394 _hb_glyph_info_set_glyph_props (&info[i],
michael@0 395 _hb_glyph_info_get_general_category (&info[i])
michael@0 396 == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ?
michael@0 397 HB_OT_LAYOUT_GLYPH_PROPS_MARK :
michael@0 398 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
michael@0 399 }
michael@0 400
michael@0 401 static inline void
michael@0 402 hb_ot_substitute_default (hb_ot_shape_context_t *c)
michael@0 403 {
michael@0 404 hb_buffer_t *buffer = c->buffer;
michael@0 405
michael@0 406 if (c->plan->shaper->preprocess_text)
michael@0 407 c->plan->shaper->preprocess_text (c->plan, buffer, c->font);
michael@0 408
michael@0 409 hb_ot_shape_initialize_masks (c);
michael@0 410
michael@0 411 hb_ot_mirror_chars (c);
michael@0 412
michael@0 413 HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
michael@0 414
michael@0 415 _hb_ot_shape_normalize (c->plan, buffer, c->font);
michael@0 416
michael@0 417 hb_ot_shape_setup_masks (c);
michael@0 418
michael@0 419 /* This is unfortunate to go here, but necessary... */
michael@0 420 if (!hb_ot_layout_has_positioning (c->face))
michael@0 421 _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer);
michael@0 422
michael@0 423 hb_ot_map_glyphs_fast (buffer);
michael@0 424
michael@0 425 HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index);
michael@0 426 }
michael@0 427
michael@0 428 static inline void
michael@0 429 hb_ot_substitute_complex (hb_ot_shape_context_t *c)
michael@0 430 {
michael@0 431 hb_buffer_t *buffer = c->buffer;
michael@0 432
michael@0 433 hb_ot_layout_substitute_start (c->font, buffer);
michael@0 434
michael@0 435 if (!hb_ot_layout_has_glyph_classes (c->face))
michael@0 436 hb_synthesize_glyph_classes (c);
michael@0 437
michael@0 438 c->plan->substitute (c->font, buffer);
michael@0 439
michael@0 440 hb_ot_layout_substitute_finish (c->font, buffer);
michael@0 441
michael@0 442 return;
michael@0 443 }
michael@0 444
michael@0 445 static inline void
michael@0 446 hb_ot_substitute (hb_ot_shape_context_t *c)
michael@0 447 {
michael@0 448 hb_ot_substitute_default (c);
michael@0 449 hb_ot_substitute_complex (c);
michael@0 450 }
michael@0 451
michael@0 452 /* Position */
michael@0 453
michael@0 454 static inline void
michael@0 455 zero_mark_widths_by_unicode (hb_buffer_t *buffer)
michael@0 456 {
michael@0 457 unsigned int count = buffer->len;
michael@0 458 for (unsigned int i = 0; i < count; i++)
michael@0 459 if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
michael@0 460 {
michael@0 461 buffer->pos[i].x_advance = 0;
michael@0 462 buffer->pos[i].y_advance = 0;
michael@0 463 }
michael@0 464 }
michael@0 465
michael@0 466 static inline void
michael@0 467 zero_mark_widths_by_gdef (hb_buffer_t *buffer)
michael@0 468 {
michael@0 469 unsigned int count = buffer->len;
michael@0 470 for (unsigned int i = 0; i < count; i++)
michael@0 471 if (_hb_glyph_info_is_mark (&buffer->info[i]))
michael@0 472 {
michael@0 473 buffer->pos[i].x_advance = 0;
michael@0 474 buffer->pos[i].y_advance = 0;
michael@0 475 }
michael@0 476 }
michael@0 477
michael@0 478 static inline void
michael@0 479 hb_ot_position_default (hb_ot_shape_context_t *c)
michael@0 480 {
michael@0 481 hb_direction_t direction = c->buffer->props.direction;
michael@0 482 unsigned int count = c->buffer->len;
michael@0 483 hb_glyph_info_t *info = c->buffer->info;
michael@0 484 hb_glyph_position_t *pos = c->buffer->pos;
michael@0 485 for (unsigned int i = 0; i < count; i++)
michael@0 486 {
michael@0 487 c->font->get_glyph_advance_for_direction (info[i].codepoint,
michael@0 488 direction,
michael@0 489 &pos[i].x_advance,
michael@0 490 &pos[i].y_advance);
michael@0 491 c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
michael@0 492 direction,
michael@0 493 &pos[i].x_offset,
michael@0 494 &pos[i].y_offset);
michael@0 495
michael@0 496 }
michael@0 497 }
michael@0 498
michael@0 499 static inline bool
michael@0 500 hb_ot_position_complex (hb_ot_shape_context_t *c)
michael@0 501 {
michael@0 502 bool ret = false;
michael@0 503 unsigned int count = c->buffer->len;
michael@0 504
michael@0 505 switch (c->plan->shaper->zero_width_marks)
michael@0 506 {
michael@0 507 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
michael@0 508 zero_mark_widths_by_gdef (c->buffer);
michael@0 509 break;
michael@0 510
michael@0 511 /* Not currently used for any shaper:
michael@0 512 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
michael@0 513 zero_mark_widths_by_unicode (c->buffer);
michael@0 514 break;
michael@0 515 */
michael@0 516
michael@0 517 default:
michael@0 518 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
michael@0 519 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
michael@0 520 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
michael@0 521 break;
michael@0 522 }
michael@0 523
michael@0 524 if (hb_ot_layout_has_positioning (c->face))
michael@0 525 {
michael@0 526 hb_glyph_info_t *info = c->buffer->info;
michael@0 527 hb_glyph_position_t *pos = c->buffer->pos;
michael@0 528
michael@0 529 /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */
michael@0 530
michael@0 531 for (unsigned int i = 0; i < count; i++) {
michael@0 532 c->font->add_glyph_origin_for_direction (info[i].codepoint,
michael@0 533 HB_DIRECTION_LTR,
michael@0 534 &pos[i].x_offset,
michael@0 535 &pos[i].y_offset);
michael@0 536 }
michael@0 537
michael@0 538 c->plan->position (c->font, c->buffer);
michael@0 539
michael@0 540 for (unsigned int i = 0; i < count; i++) {
michael@0 541 c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
michael@0 542 HB_DIRECTION_LTR,
michael@0 543 &pos[i].x_offset,
michael@0 544 &pos[i].y_offset);
michael@0 545 }
michael@0 546
michael@0 547 ret = true;
michael@0 548 }
michael@0 549
michael@0 550 switch (c->plan->shaper->zero_width_marks)
michael@0 551 {
michael@0 552 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
michael@0 553 zero_mark_widths_by_unicode (c->buffer);
michael@0 554 break;
michael@0 555
michael@0 556 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
michael@0 557 zero_mark_widths_by_gdef (c->buffer);
michael@0 558 break;
michael@0 559
michael@0 560 default:
michael@0 561 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
michael@0 562 //case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
michael@0 563 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
michael@0 564 break;
michael@0 565 }
michael@0 566
michael@0 567 return ret;
michael@0 568 }
michael@0 569
michael@0 570 static inline void
michael@0 571 hb_ot_position (hb_ot_shape_context_t *c)
michael@0 572 {
michael@0 573 hb_ot_layout_position_start (c->font, c->buffer);
michael@0 574
michael@0 575 hb_ot_position_default (c);
michael@0 576
michael@0 577 hb_bool_t fallback = !hb_ot_position_complex (c);
michael@0 578
michael@0 579 hb_ot_layout_position_finish (c->font, c->buffer);
michael@0 580
michael@0 581 if (fallback && c->plan->shaper->fallback_position)
michael@0 582 _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
michael@0 583
michael@0 584 if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
michael@0 585 hb_buffer_reverse (c->buffer);
michael@0 586
michael@0 587 /* Visual fallback goes here. */
michael@0 588
michael@0 589 if (fallback)
michael@0 590 _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer);
michael@0 591 }
michael@0 592
michael@0 593
michael@0 594 /* Post-process */
michael@0 595
michael@0 596 static void
michael@0 597 hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
michael@0 598 {
michael@0 599 if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
michael@0 600 return;
michael@0 601
michael@0 602 hb_codepoint_t space;
michael@0 603 enum {
michael@0 604 SPACE_DONT_KNOW,
michael@0 605 SPACE_AVAILABLE,
michael@0 606 SPACE_UNAVAILABLE
michael@0 607 } space_status = SPACE_DONT_KNOW;
michael@0 608
michael@0 609 unsigned int count = c->buffer->len;
michael@0 610 hb_glyph_info_t *info = c->buffer->info;
michael@0 611 hb_glyph_position_t *pos = c->buffer->pos;
michael@0 612 unsigned int j = 0;
michael@0 613 for (unsigned int i = 0; i < count; i++)
michael@0 614 {
michael@0 615 if (unlikely (!_hb_glyph_info_ligated (&info[i]) &&
michael@0 616 _hb_glyph_info_is_default_ignorable (&info[i])))
michael@0 617 {
michael@0 618 if (space_status == SPACE_DONT_KNOW)
michael@0 619 space_status = c->font->get_glyph (' ', 0, &space) ? SPACE_AVAILABLE : SPACE_UNAVAILABLE;
michael@0 620
michael@0 621 if (space_status == SPACE_AVAILABLE)
michael@0 622 {
michael@0 623 info[i].codepoint = space;
michael@0 624 pos[i].x_advance = 0;
michael@0 625 pos[i].y_advance = 0;
michael@0 626 }
michael@0 627 else
michael@0 628 continue; /* Delete it. */
michael@0 629 }
michael@0 630 if (j != i)
michael@0 631 {
michael@0 632 info[j] = info[i];
michael@0 633 pos[j] = pos[i];
michael@0 634 }
michael@0 635 j++;
michael@0 636 }
michael@0 637 c->buffer->len = j;
michael@0 638 }
michael@0 639
michael@0 640
michael@0 641 /* Pull it all together! */
michael@0 642
michael@0 643 static void
michael@0 644 hb_ot_shape_internal (hb_ot_shape_context_t *c)
michael@0 645 {
michael@0 646 c->buffer->deallocate_var_all ();
michael@0 647
michael@0 648 /* Save the original direction, we use it later. */
michael@0 649 c->target_direction = c->buffer->props.direction;
michael@0 650
michael@0 651 _hb_buffer_allocate_unicode_vars (c->buffer);
michael@0 652
michael@0 653 c->buffer->clear_output ();
michael@0 654
michael@0 655 hb_set_unicode_props (c->buffer);
michael@0 656 hb_insert_dotted_circle (c->buffer, c->font);
michael@0 657 hb_form_clusters (c->buffer);
michael@0 658
michael@0 659 hb_ensure_native_direction (c->buffer);
michael@0 660
michael@0 661 hb_ot_substitute (c);
michael@0 662 hb_ot_position (c);
michael@0 663
michael@0 664 hb_ot_hide_default_ignorables (c);
michael@0 665
michael@0 666 _hb_buffer_deallocate_unicode_vars (c->buffer);
michael@0 667
michael@0 668 c->buffer->props.direction = c->target_direction;
michael@0 669
michael@0 670 c->buffer->deallocate_var_all ();
michael@0 671 }
michael@0 672
michael@0 673
michael@0 674 hb_bool_t
michael@0 675 _hb_ot_shape (hb_shape_plan_t *shape_plan,
michael@0 676 hb_font_t *font,
michael@0 677 hb_buffer_t *buffer,
michael@0 678 const hb_feature_t *features,
michael@0 679 unsigned int num_features)
michael@0 680 {
michael@0 681 hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features};
michael@0 682 hb_ot_shape_internal (&c);
michael@0 683
michael@0 684 return true;
michael@0 685 }
michael@0 686
michael@0 687
michael@0 688 void
michael@0 689 hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
michael@0 690 hb_tag_t table_tag,
michael@0 691 hb_set_t *lookup_indexes /* OUT */)
michael@0 692 {
michael@0 693 /* XXX Does the first part always succeed? */
michael@0 694 HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes);
michael@0 695 }
michael@0 696
michael@0 697
michael@0 698 /* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
michael@0 699 static void
michael@0 700 add_char (hb_font_t *font,
michael@0 701 hb_unicode_funcs_t *unicode,
michael@0 702 hb_bool_t mirror,
michael@0 703 hb_codepoint_t u,
michael@0 704 hb_set_t *glyphs)
michael@0 705 {
michael@0 706 hb_codepoint_t glyph;
michael@0 707 if (font->get_glyph (u, 0, &glyph))
michael@0 708 glyphs->add (glyph);
michael@0 709 if (mirror)
michael@0 710 {
michael@0 711 hb_codepoint_t m = unicode->mirroring (u);
michael@0 712 if (m != u && font->get_glyph (m, 0, &glyph))
michael@0 713 glyphs->add (glyph);
michael@0 714 }
michael@0 715 }
michael@0 716
michael@0 717
michael@0 718 void
michael@0 719 hb_ot_shape_glyphs_closure (hb_font_t *font,
michael@0 720 hb_buffer_t *buffer,
michael@0 721 const hb_feature_t *features,
michael@0 722 unsigned int num_features,
michael@0 723 hb_set_t *glyphs)
michael@0 724 {
michael@0 725 hb_ot_shape_plan_t plan;
michael@0 726
michael@0 727 const char *shapers[] = {"ot", NULL};
michael@0 728 hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
michael@0 729 features, num_features, shapers);
michael@0 730
michael@0 731 bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL;
michael@0 732
michael@0 733 unsigned int count = buffer->len;
michael@0 734 for (unsigned int i = 0; i < count; i++)
michael@0 735 add_char (font, buffer->unicode, mirror, buffer->info[i].codepoint, glyphs);
michael@0 736
michael@0 737 hb_set_t lookups;
michael@0 738 lookups.init ();
michael@0 739 hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups);
michael@0 740
michael@0 741 /* And find transitive closure. */
michael@0 742 hb_set_t copy;
michael@0 743 copy.init ();
michael@0 744 do {
michael@0 745 copy.set (glyphs);
michael@0 746 for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);)
michael@0 747 hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs);
michael@0 748 } while (!copy.is_equal (glyphs));
michael@0 749
michael@0 750 hb_shape_plan_destroy (shape_plan);
michael@0 751 }

mercurial