2009-12-20 19:58:26 +00:00
|
|
|
/*
|
2011-04-21 21:14:28 +00:00
|
|
|
* Copyright © 2009,2010 Red Hat, Inc.
|
2012-08-10 07:28:50 +00:00
|
|
|
* Copyright © 2010,2011,2012 Google, Inc.
|
2009-12-20 19:58:26 +00:00
|
|
|
*
|
2010-04-22 04:11:43 +00:00
|
|
|
* This is part of HarfBuzz, a text shaping library.
|
2009-12-20 19:58:26 +00:00
|
|
|
*
|
|
|
|
* Permission is hereby granted, without written agreement and without
|
|
|
|
* license or royalty fees, to use, copy, modify, and distribute this
|
|
|
|
* software and its documentation for any purpose, provided that the
|
|
|
|
* above copyright notice and the following two paragraphs appear in
|
|
|
|
* all copies of this software.
|
|
|
|
*
|
|
|
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
|
|
|
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
|
|
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
|
|
|
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
|
|
|
* DAMAGE.
|
|
|
|
*
|
|
|
|
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
|
|
|
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
|
|
|
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
|
|
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
|
|
*
|
|
|
|
* Red Hat Author(s): Behdad Esfahbod
|
2010-10-07 21:47:33 +00:00
|
|
|
* Google Author(s): Behdad Esfahbod
|
2009-12-20 19:58:26 +00:00
|
|
|
*/
|
|
|
|
|
2012-07-26 21:34:25 +00:00
|
|
|
#define HB_SHAPER ot
|
2018-08-26 05:36:36 +00:00
|
|
|
#include "hb-shaper-impl.hh"
|
2012-07-26 21:34:25 +00:00
|
|
|
|
2018-08-26 05:36:36 +00:00
|
|
|
#include "hb-ot-shape.hh"
|
|
|
|
#include "hb-ot-shape-complex.hh"
|
|
|
|
#include "hb-ot-shape-fallback.hh"
|
|
|
|
#include "hb-ot-shape-normalize.hh"
|
2009-12-20 19:58:26 +00:00
|
|
|
|
2018-08-26 08:15:47 +00:00
|
|
|
#include "hb-ot-face.hh"
|
2018-10-02 11:11:18 +00:00
|
|
|
|
2018-08-26 05:36:36 +00:00
|
|
|
#include "hb-set.hh"
|
2011-05-03 00:46:32 +00:00
|
|
|
|
2018-08-26 05:36:36 +00:00
|
|
|
#include "hb-aat-layout.hh"
|
2010-07-23 19:11:18 +00:00
|
|
|
|
2018-10-02 11:04:05 +00:00
|
|
|
|
2018-10-27 11:58:32 +00:00
|
|
|
/**
|
|
|
|
* SECTION:hb-ot-shape
|
|
|
|
* @title: hb-ot-shape
|
|
|
|
* @short_description: OpenType shaping support
|
|
|
|
* @include: hb-ot.h
|
|
|
|
*
|
|
|
|
* Support functions for OpenType shaping related queries.
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
2018-11-12 02:32:01 +00:00
|
|
|
static void
|
|
|
|
hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
|
|
|
|
const hb_feature_t *user_features,
|
|
|
|
unsigned int num_user_features);
|
|
|
|
|
2018-10-10 21:44:46 +00:00
|
|
|
static bool
|
|
|
|
_hb_apply_morx (hb_face_t *face)
|
|
|
|
{
|
|
|
|
if (hb_options ().aat &&
|
|
|
|
hb_aat_layout_has_substitution (face))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return !hb_ot_layout_has_substitution (face) &&
|
|
|
|
hb_aat_layout_has_substitution (face);
|
|
|
|
}
|
|
|
|
|
2018-11-12 03:51:34 +00:00
|
|
|
hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t *face,
|
|
|
|
const hb_segment_properties_t *props) :
|
|
|
|
face (face),
|
|
|
|
props (*props),
|
|
|
|
map (face, props),
|
|
|
|
aat_map (face, props),
|
2018-10-23 20:09:30 +00:00
|
|
|
apply_morx (_hb_apply_morx (face)),
|
|
|
|
shaper (apply_morx ?
|
|
|
|
&_hb_ot_complex_shaper_default :
|
|
|
|
hb_ot_shape_complex_categorize (this)) {}
|
|
|
|
|
2018-10-02 11:04:05 +00:00
|
|
|
void
|
2018-11-12 23:48:10 +00:00
|
|
|
hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
|
|
|
|
const hb_ot_shape_plan_key_t &key)
|
2018-10-02 11:04:05 +00:00
|
|
|
{
|
|
|
|
plan.props = props;
|
|
|
|
plan.shaper = shaper;
|
2018-11-12 23:48:10 +00:00
|
|
|
map.compile (plan.map, key);
|
2018-10-23 21:31:51 +00:00
|
|
|
if (apply_morx)
|
2018-11-12 23:48:10 +00:00
|
|
|
aat_map.compile (plan.aat_map);
|
2018-10-02 11:04:05 +00:00
|
|
|
|
|
|
|
plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c'));
|
|
|
|
plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r'));
|
|
|
|
plan.dnom_mask = plan.map.get_1_mask (HB_TAG ('d','n','o','m'));
|
|
|
|
plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask);
|
2018-10-23 10:10:56 +00:00
|
|
|
plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m'));
|
2018-11-12 02:32:01 +00:00
|
|
|
hb_tag_t kern_tag = HB_DIRECTION_IS_HORIZONTAL (props.direction) ?
|
2018-10-10 14:42:10 +00:00
|
|
|
HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n');
|
|
|
|
plan.kern_mask = plan.map.get_mask (kern_tag);
|
2018-10-23 10:10:56 +00:00
|
|
|
plan.trak_mask = plan.map.get_mask (HB_TAG ('t','r','a','k'));
|
2018-10-10 14:42:10 +00:00
|
|
|
|
2018-10-10 22:10:05 +00:00
|
|
|
plan.requested_kerning = !!plan.kern_mask;
|
2018-10-23 10:10:56 +00:00
|
|
|
plan.requested_tracking = !!plan.trak_mask;
|
2018-10-10 14:57:28 +00:00
|
|
|
bool has_gpos_kern = plan.map.get_feature_index (1, kern_tag) != HB_OT_LAYOUT_NO_FEATURE_INDEX;
|
2018-10-10 14:42:10 +00:00
|
|
|
bool disable_gpos = plan.shaper->gpos_tag &&
|
|
|
|
plan.shaper->gpos_tag != plan.map.chosen_script[1];
|
2018-10-02 11:24:40 +00:00
|
|
|
|
2018-10-10 14:49:45 +00:00
|
|
|
/*
|
|
|
|
* Decide who provides glyph classes. GDEF or Unicode.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!hb_ot_layout_has_glyph_classes (face))
|
|
|
|
plan.fallback_glyph_classes = true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Decide who does substitutions. GSUB, morx, or fallback.
|
|
|
|
*/
|
2018-10-10 14:16:09 +00:00
|
|
|
|
2018-10-23 20:09:30 +00:00
|
|
|
plan.apply_morx = apply_morx;
|
2018-10-04 09:34:21 +00:00
|
|
|
|
2018-10-10 14:49:45 +00:00
|
|
|
/*
|
|
|
|
* Decide who does positioning. GPOS, kerx, kern, or fallback.
|
|
|
|
*/
|
2018-10-10 14:16:09 +00:00
|
|
|
|
2018-10-10 21:44:46 +00:00
|
|
|
if (hb_options ().aat && hb_aat_layout_has_positioning (face))
|
|
|
|
plan.apply_kerx = true;
|
|
|
|
else if (!disable_gpos && hb_ot_layout_has_positioning (face))
|
2018-10-10 14:49:45 +00:00
|
|
|
plan.apply_gpos = true;
|
|
|
|
else if (hb_aat_layout_has_positioning (face))
|
|
|
|
plan.apply_kerx = true;
|
|
|
|
|
2018-11-07 19:04:04 +00:00
|
|
|
if (!plan.apply_kerx && !has_gpos_kern)
|
2018-10-10 14:49:45 +00:00
|
|
|
{
|
2018-10-11 17:26:58 +00:00
|
|
|
/* Apparently Apple applies kerx if GPOS kern was not applied. */
|
|
|
|
if (hb_aat_layout_has_positioning (face))
|
|
|
|
plan.apply_kerx = true;
|
2018-11-07 21:07:22 +00:00
|
|
|
else if (hb_ot_layout_has_kerning (face))
|
2018-10-11 17:26:58 +00:00
|
|
|
plan.apply_kern = true;
|
2018-10-10 14:49:45 +00:00
|
|
|
}
|
2018-10-10 14:16:09 +00:00
|
|
|
|
2018-11-07 21:19:51 +00:00
|
|
|
bool has_kern_mark = plan.apply_kern && hb_ot_layout_has_cross_kerning (face);
|
2018-11-14 02:10:10 +00:00
|
|
|
plan.zero_marks = !plan.apply_morx && !plan.apply_kerx && !has_kern_mark;
|
2018-10-10 14:16:09 +00:00
|
|
|
plan.has_gpos_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k'));
|
2018-11-14 02:10:10 +00:00
|
|
|
plan.fallback_mark_positioning = !plan.apply_gpos && plan.zero_marks;
|
2018-10-11 17:24:17 +00:00
|
|
|
|
|
|
|
/* Currently we always apply trak. */
|
2018-10-23 10:10:56 +00:00
|
|
|
plan.apply_trak = plan.requested_tracking && hb_aat_layout_has_tracking (face);
|
2018-10-02 11:04:05 +00:00
|
|
|
}
|
|
|
|
|
2018-11-12 02:32:01 +00:00
|
|
|
bool
|
2018-11-12 03:51:34 +00:00
|
|
|
hb_ot_shape_plan_t::init0 (hb_face_t *face,
|
2018-11-12 23:05:02 +00:00
|
|
|
const hb_shape_plan_key_t *key)
|
2018-11-12 02:32:01 +00:00
|
|
|
{
|
|
|
|
map.init ();
|
|
|
|
aat_map.init ();
|
|
|
|
|
2018-11-12 23:05:02 +00:00
|
|
|
hb_ot_shape_planner_t planner (face,
|
|
|
|
&key->props);
|
|
|
|
hb_ot_shape_collect_features (&planner,
|
|
|
|
key->user_features,
|
|
|
|
key->num_user_features);
|
2018-11-12 02:32:01 +00:00
|
|
|
|
2018-11-12 23:48:10 +00:00
|
|
|
planner.compile (*this, key->ot);
|
2018-11-12 02:32:01 +00:00
|
|
|
|
|
|
|
if (shaper->data_create)
|
|
|
|
{
|
|
|
|
data = shaper->data_create (this);
|
|
|
|
if (unlikely (!data))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
hb_ot_shape_plan_t::fini (void)
|
|
|
|
{
|
|
|
|
if (shaper->data_destroy)
|
|
|
|
shaper->data_destroy (const_cast<void *> (data));
|
|
|
|
|
|
|
|
map.fini ();
|
|
|
|
aat_map.fini ();
|
|
|
|
}
|
|
|
|
|
2018-10-02 11:04:05 +00:00
|
|
|
|
2018-10-02 12:45:09 +00:00
|
|
|
static const hb_ot_map_feature_t
|
|
|
|
common_features[] =
|
2018-10-02 11:04:05 +00:00
|
|
|
{
|
2018-10-02 12:45:09 +00:00
|
|
|
{HB_TAG('c','c','m','p'), F_GLOBAL},
|
|
|
|
{HB_TAG('l','o','c','l'), F_GLOBAL},
|
|
|
|
{HB_TAG('m','a','r','k'), F_GLOBAL_MANUAL_JOINERS},
|
|
|
|
{HB_TAG('m','k','m','k'), F_GLOBAL_MANUAL_JOINERS},
|
|
|
|
{HB_TAG('r','l','i','g'), F_GLOBAL},
|
2011-05-31 19:18:13 +00:00
|
|
|
};
|
|
|
|
|
2012-05-09 13:04:13 +00:00
|
|
|
|
2018-10-02 12:45:09 +00:00
|
|
|
static const hb_ot_map_feature_t
|
|
|
|
horizontal_features[] =
|
2018-10-02 11:04:05 +00:00
|
|
|
{
|
2018-10-02 12:45:09 +00:00
|
|
|
{HB_TAG('c','a','l','t'), F_GLOBAL},
|
|
|
|
{HB_TAG('c','l','i','g'), F_GLOBAL},
|
|
|
|
{HB_TAG('c','u','r','s'), F_GLOBAL},
|
|
|
|
{HB_TAG('k','e','r','n'), F_GLOBAL_HAS_FALLBACK},
|
|
|
|
{HB_TAG('l','i','g','a'), F_GLOBAL},
|
|
|
|
{HB_TAG('r','c','l','t'), F_GLOBAL},
|
2011-05-31 19:18:13 +00:00
|
|
|
};
|
|
|
|
|
2009-12-20 19:58:26 +00:00
|
|
|
static void
|
2011-05-27 22:13:31 +00:00
|
|
|
hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
|
|
|
|
const hb_feature_t *user_features,
|
|
|
|
unsigned int num_user_features)
|
2009-12-20 19:58:26 +00:00
|
|
|
{
|
2012-08-02 14:07:58 +00:00
|
|
|
hb_ot_map_builder_t *map = &planner->map;
|
|
|
|
|
2018-09-24 22:01:53 +00:00
|
|
|
map->enable_feature (HB_TAG('r','v','r','n'));
|
2017-10-15 10:11:08 +00:00
|
|
|
map->add_gsub_pause (nullptr);
|
2016-09-28 15:05:43 +00:00
|
|
|
|
2018-11-12 23:05:02 +00:00
|
|
|
switch (planner->props.direction) {
|
2010-05-29 00:21:47 +00:00
|
|
|
case HB_DIRECTION_LTR:
|
2018-09-24 22:01:53 +00:00
|
|
|
map->enable_feature (HB_TAG ('l','t','r','a'));
|
|
|
|
map->enable_feature (HB_TAG ('l','t','r','m'));
|
2010-05-29 00:21:47 +00:00
|
|
|
break;
|
|
|
|
case HB_DIRECTION_RTL:
|
2018-09-24 22:01:53 +00:00
|
|
|
map->enable_feature (HB_TAG ('r','t','l','a'));
|
|
|
|
map->add_feature (HB_TAG ('r','t','l','m'));
|
2010-05-29 00:21:47 +00:00
|
|
|
break;
|
|
|
|
case HB_DIRECTION_TTB:
|
|
|
|
case HB_DIRECTION_BTT:
|
2011-03-16 17:53:32 +00:00
|
|
|
case HB_DIRECTION_INVALID:
|
2010-05-29 00:21:47 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-09-10 14:24:52 +00:00
|
|
|
/* Automatic fractions. */
|
2018-09-24 22:01:53 +00:00
|
|
|
map->add_feature (HB_TAG ('f','r','a','c'));
|
|
|
|
map->add_feature (HB_TAG ('n','u','m','r'));
|
|
|
|
map->add_feature (HB_TAG ('d','n','o','m'));
|
2013-12-22 21:17:54 +00:00
|
|
|
|
2018-09-10 14:24:52 +00:00
|
|
|
/* Random! */
|
2018-10-02 12:48:39 +00:00
|
|
|
map->enable_feature (HB_TAG ('r','a','n','d'), F_RANDOM, HB_OT_MAP_MAX_VALUE);
|
2018-09-10 14:24:52 +00:00
|
|
|
|
2018-10-23 10:10:56 +00:00
|
|
|
/* Tracking. We enable dummy feature here just to allow disabling
|
|
|
|
* AAT 'trak' table using features.
|
|
|
|
* https://github.com/harfbuzz/harfbuzz/issues/1303 */
|
2018-10-22 21:22:05 +00:00
|
|
|
map->enable_feature (HB_TAG ('t','r','a','k'), F_HAS_FALLBACK);
|
|
|
|
|
|
|
|
map->enable_feature (HB_TAG ('H','A','R','F'));
|
2018-10-04 11:00:37 +00:00
|
|
|
|
2012-07-31 01:08:51 +00:00
|
|
|
if (planner->shaper->collect_features)
|
2012-08-02 13:38:28 +00:00
|
|
|
planner->shaper->collect_features (planner);
|
2010-05-29 00:37:06 +00:00
|
|
|
|
2018-10-22 21:22:05 +00:00
|
|
|
map->enable_feature (HB_TAG ('B','U','Z','Z'));
|
2018-10-04 11:00:37 +00:00
|
|
|
|
2013-02-15 11:22:26 +00:00
|
|
|
for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++)
|
2018-10-02 12:45:09 +00:00
|
|
|
map->add_feature (common_features[i]);
|
2011-05-31 19:18:13 +00:00
|
|
|
|
2018-11-12 23:05:02 +00:00
|
|
|
if (HB_DIRECTION_IS_HORIZONTAL (planner->props.direction))
|
2013-02-15 11:22:26 +00:00
|
|
|
for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++)
|
2018-10-02 12:45:09 +00:00
|
|
|
map->add_feature (horizontal_features[i]);
|
2011-05-31 19:18:13 +00:00
|
|
|
else
|
2015-07-23 10:32:59 +00:00
|
|
|
{
|
2015-07-23 10:52:11 +00:00
|
|
|
/* We really want to find a 'vert' feature if there's any in the font, no
|
|
|
|
* matter which script/langsys it is listed (or not) under.
|
|
|
|
* See various bugs referenced from:
|
2017-11-20 19:49:22 +00:00
|
|
|
* https://github.com/harfbuzz/harfbuzz/issues/63 */
|
2018-10-02 12:48:39 +00:00
|
|
|
map->enable_feature (HB_TAG ('v','e','r','t'), F_GLOBAL_SEARCH);
|
2015-07-23 10:32:59 +00:00
|
|
|
}
|
2011-05-31 19:18:13 +00:00
|
|
|
|
2012-07-31 01:08:51 +00:00
|
|
|
if (planner->shaper->override_features)
|
2012-08-02 13:38:28 +00:00
|
|
|
planner->shaper->override_features (planner);
|
2012-07-17 00:26:57 +00:00
|
|
|
|
2018-09-10 14:24:52 +00:00
|
|
|
for (unsigned int i = 0; i < num_user_features; i++)
|
|
|
|
{
|
2010-10-12 20:00:21 +00:00
|
|
|
const hb_feature_t *feature = &user_features[i];
|
2018-09-24 22:01:53 +00:00
|
|
|
map->add_feature (feature->tag,
|
2018-09-24 22:11:59 +00:00
|
|
|
(feature->start == HB_FEATURE_GLOBAL_START &&
|
|
|
|
feature->end == HB_FEATURE_GLOBAL_END) ? F_GLOBAL : F_NONE,
|
2018-09-24 22:01:53 +00:00
|
|
|
feature->value);
|
2018-10-23 21:31:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (planner->apply_morx)
|
|
|
|
{
|
|
|
|
hb_aat_map_builder_t *aat_map = &planner->aat_map;
|
|
|
|
for (unsigned int i = 0; i < num_user_features; i++)
|
|
|
|
{
|
|
|
|
const hb_feature_t *feature = &user_features[i];
|
|
|
|
aat_map->add_feature (feature->tag, feature->value);
|
|
|
|
}
|
2010-05-29 00:37:06 +00:00
|
|
|
}
|
2010-10-08 16:29:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-27 06:29:32 +00:00
|
|
|
/*
|
|
|
|
* shaper face data
|
|
|
|
*/
|
|
|
|
|
2018-11-11 21:35:28 +00:00
|
|
|
HB_SHAPER_DATA_ENSURE_DEFINE(ot, face);
|
2017-02-04 00:43:25 +00:00
|
|
|
|
2018-11-06 03:39:50 +00:00
|
|
|
struct hb_ot_face_data_t {};
|
|
|
|
|
2018-08-02 01:03:32 +00:00
|
|
|
hb_ot_face_data_t *
|
2012-07-27 06:29:32 +00:00
|
|
|
_hb_ot_shaper_face_data_create (hb_face_t *face)
|
|
|
|
{
|
2018-11-06 03:39:50 +00:00
|
|
|
return (hb_ot_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
2012-07-27 06:29:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2018-08-02 01:03:32 +00:00
|
|
|
_hb_ot_shaper_face_data_destroy (hb_ot_face_data_t *data)
|
2012-07-27 06:29:32 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* shaper font data
|
|
|
|
*/
|
|
|
|
|
2018-11-11 21:35:28 +00:00
|
|
|
HB_SHAPER_DATA_ENSURE_DEFINE(ot, font);
|
2017-02-04 00:43:25 +00:00
|
|
|
|
2018-08-02 01:03:32 +00:00
|
|
|
struct hb_ot_font_data_t {};
|
2012-07-27 06:29:32 +00:00
|
|
|
|
2018-08-02 01:03:32 +00:00
|
|
|
hb_ot_font_data_t *
|
2016-02-22 07:00:59 +00:00
|
|
|
_hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED)
|
2012-07-27 06:29:32 +00:00
|
|
|
{
|
2018-08-02 01:03:32 +00:00
|
|
|
return (hb_ot_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
2012-07-27 06:29:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2018-10-27 04:01:11 +00:00
|
|
|
_hb_ot_shaper_font_data_destroy (hb_ot_font_data_t *data HB_UNUSED)
|
2012-07-27 06:29:32 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* shaper
|
|
|
|
*/
|
|
|
|
|
2012-04-15 00:23:58 +00:00
|
|
|
struct hb_ot_shape_context_t
|
|
|
|
{
|
|
|
|
hb_ot_shape_plan_t *plan;
|
|
|
|
hb_font_t *font;
|
|
|
|
hb_face_t *face;
|
|
|
|
hb_buffer_t *buffer;
|
|
|
|
const hb_feature_t *user_features;
|
|
|
|
unsigned int num_user_features;
|
|
|
|
|
|
|
|
/* Transient stuff */
|
|
|
|
hb_direction_t target_direction;
|
|
|
|
};
|
|
|
|
|
2009-12-20 19:58:26 +00:00
|
|
|
|
|
|
|
|
2010-05-21 13:34:23 +00:00
|
|
|
/* Main shaper */
|
|
|
|
|
2012-08-10 01:58:07 +00:00
|
|
|
|
2010-05-21 13:34:23 +00:00
|
|
|
/* Prepare */
|
|
|
|
|
2012-04-15 00:23:58 +00:00
|
|
|
static void
|
|
|
|
hb_set_unicode_props (hb_buffer_t *buffer)
|
2010-11-03 20:37:24 +00:00
|
|
|
{
|
2018-10-03 17:44:15 +00:00
|
|
|
/* Implement enough of Unicode Graphemes here that shaping
|
|
|
|
* in reverse-direction wouldn't break graphemes. Namely,
|
|
|
|
* we mark all marks and ZWJ and ZWJ,Extended_Pictographic
|
|
|
|
* sequences as continuations. The foreach_grapheme()
|
|
|
|
* macro uses this bit.
|
|
|
|
*
|
|
|
|
* https://www.unicode.org/reports/tr29/#Regex_Definitions
|
|
|
|
*/
|
2011-07-21 15:34:59 +00:00
|
|
|
unsigned int count = buffer->len;
|
2014-07-17 18:22:11 +00:00
|
|
|
hb_glyph_info_t *info = buffer->info;
|
2012-04-12 14:06:52 +00:00
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2018-10-03 17:44:15 +00:00
|
|
|
{
|
2015-11-05 02:46:22 +00:00
|
|
|
_hb_glyph_info_set_unicode_props (&info[i], buffer);
|
2018-10-03 17:44:15 +00:00
|
|
|
|
|
|
|
/* Marks are already set as continuation by the above line.
|
2018-10-03 19:17:59 +00:00
|
|
|
* Handle Emoji_Modifier and ZWJ-continuation. */
|
|
|
|
if (unlikely (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL &&
|
|
|
|
hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x1F3FBu, 0x1F3FFu)))
|
|
|
|
{
|
|
|
|
_hb_glyph_info_set_continuation (&info[i]);
|
|
|
|
}
|
|
|
|
else if (unlikely (_hb_glyph_info_is_zwj (&info[i])))
|
2018-10-03 17:44:15 +00:00
|
|
|
{
|
|
|
|
_hb_glyph_info_set_continuation (&info[i]);
|
|
|
|
if (i + 1 < count &&
|
|
|
|
_hb_unicode_is_emoji_Extended_Pictographic (info[i + 1].codepoint))
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
_hb_glyph_info_set_unicode_props (&info[i], buffer);
|
|
|
|
_hb_glyph_info_set_continuation (&info[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-11-03 20:37:24 +00:00
|
|
|
}
|
|
|
|
|
2012-09-02 00:38:45 +00:00
|
|
|
static void
|
|
|
|
hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
|
|
|
|
{
|
2012-11-13 22:42:35 +00:00
|
|
|
if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
|
Make it easier to use HB_BUFFER_FLAG_BOT/EOT
Previously, we expected users to provide BOT/EOT flags when the
text *segment* was at paragraph boundaries. This meant that for
clients that provide full paragraph to HarfBuzz (eg. Pango), they
had code like this:
hb_buffer_set_flags (hb_buffer,
(item_offset == 0 ? HB_BUFFER_FLAG_BOT : 0) |
(item_offset + item_length == paragraph_length ?
HB_BUFFER_FLAG_EOT : 0));
hb_buffer_add_utf8 (hb_buffer,
paragraph_text, paragraph_length,
item_offset, item_length);
After this change such clients can simply say:
hb_buffer_set_flags (hb_buffer,
HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT);
hb_buffer_add_utf8 (hb_buffer,
paragraph_text, paragraph_length,
item_offset, item_length);
Ie, HarfBuzz itself checks whether the segment is at the beginning/end
of the paragraph. Clients that only pass item-at-a-time to HarfBuzz
continue not setting any flags whatsoever.
Another way to put it is: if there's pre-context text in the buffer,
HarfBuzz ignores the BOT flag. If there's post-context, it ignores
EOT flag.
2014-08-02 20:17:44 +00:00
|
|
|
buffer->context_len[0] ||
|
2018-10-03 17:19:51 +00:00
|
|
|
!_hb_glyph_info_is_unicode_mark (&buffer->info[0]))
|
2012-09-02 00:38:45 +00:00
|
|
|
return;
|
|
|
|
|
2014-07-11 18:54:42 +00:00
|
|
|
if (!font->has_glyph (0x25CCu))
|
2012-09-02 00:38:45 +00:00
|
|
|
return;
|
|
|
|
|
2014-07-26 22:44:15 +00:00
|
|
|
hb_glyph_info_t dottedcircle = {0};
|
2014-07-11 18:54:42 +00:00
|
|
|
dottedcircle.codepoint = 0x25CCu;
|
2015-11-05 02:46:22 +00:00
|
|
|
_hb_glyph_info_set_unicode_props (&dottedcircle, buffer);
|
2012-09-02 00:38:45 +00:00
|
|
|
|
|
|
|
buffer->clear_output ();
|
|
|
|
|
|
|
|
buffer->idx = 0;
|
|
|
|
hb_glyph_info_t info = dottedcircle;
|
|
|
|
info.cluster = buffer->cur().cluster;
|
|
|
|
info.mask = buffer->cur().mask;
|
|
|
|
buffer->output_info (info);
|
2018-06-01 03:03:00 +00:00
|
|
|
while (buffer->idx < buffer->len && buffer->successful)
|
2012-09-02 00:38:45 +00:00
|
|
|
buffer->next_glyph ();
|
|
|
|
buffer->swap_buffers ();
|
|
|
|
}
|
|
|
|
|
2010-05-21 13:34:23 +00:00
|
|
|
static void
|
2011-07-21 15:34:59 +00:00
|
|
|
hb_form_clusters (hb_buffer_t *buffer)
|
2010-05-21 13:34:23 +00:00
|
|
|
{
|
2017-09-05 03:04:59 +00:00
|
|
|
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
|
2015-07-22 15:51:12 +00:00
|
|
|
return;
|
|
|
|
|
2017-09-05 03:04:59 +00:00
|
|
|
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
|
2018-10-03 19:02:16 +00:00
|
|
|
foreach_grapheme (buffer, start, end)
|
|
|
|
buffer->merge_clusters (start, end);
|
2017-09-05 03:04:59 +00:00
|
|
|
else
|
2018-10-03 19:02:16 +00:00
|
|
|
foreach_grapheme (buffer, start, end)
|
|
|
|
buffer->unsafe_to_break (start, end);
|
2010-05-21 13:34:23 +00:00
|
|
|
}
|
|
|
|
|
2010-10-06 03:00:05 +00:00
|
|
|
static void
|
2011-07-21 15:34:59 +00:00
|
|
|
hb_ensure_native_direction (hb_buffer_t *buffer)
|
2010-05-21 13:34:23 +00:00
|
|
|
{
|
2011-07-21 15:34:59 +00:00
|
|
|
hb_direction_t direction = buffer->props.direction;
|
2018-05-07 20:58:32 +00:00
|
|
|
hb_direction_t horiz_dir = hb_script_get_horizontal_direction (buffer->props.script);
|
2010-05-21 13:34:23 +00:00
|
|
|
|
2011-05-25 01:04:15 +00:00
|
|
|
/* TODO vertical:
|
|
|
|
* The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
|
|
|
|
* Ogham fonts are supposed to be implemented BTT or not. Need to research that
|
|
|
|
* first. */
|
2018-05-07 20:58:32 +00:00
|
|
|
if ((HB_DIRECTION_IS_HORIZONTAL (direction) &&
|
|
|
|
direction != horiz_dir && horiz_dir != HB_DIRECTION_INVALID) ||
|
|
|
|
(HB_DIRECTION_IS_VERTICAL (direction) &&
|
|
|
|
direction != HB_DIRECTION_TTB))
|
2010-05-21 13:34:23 +00:00
|
|
|
{
|
2015-09-01 15:23:40 +00:00
|
|
|
|
2015-07-22 15:51:12 +00:00
|
|
|
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
|
2018-10-03 19:02:16 +00:00
|
|
|
foreach_grapheme (buffer, start, end)
|
|
|
|
{
|
|
|
|
buffer->merge_clusters (start, end);
|
|
|
|
buffer->reverse_range (start, end);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
foreach_grapheme (buffer, start, end)
|
|
|
|
/* form_clusters() merged clusters already, we don't merge. */
|
|
|
|
buffer->reverse_range (start, end);
|
2015-07-22 14:49:08 +00:00
|
|
|
|
|
|
|
buffer->reverse ();
|
|
|
|
|
2011-07-21 15:34:59 +00:00
|
|
|
buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
|
2010-05-21 13:34:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-07 22:19:21 +00:00
|
|
|
/*
|
|
|
|
* Substitute
|
|
|
|
*/
|
2010-05-21 13:34:23 +00:00
|
|
|
|
2012-08-10 01:58:07 +00:00
|
|
|
static inline void
|
2018-10-08 20:32:44 +00:00
|
|
|
hb_ot_mirror_chars (const hb_ot_shape_context_t *c)
|
2010-05-21 13:34:23 +00:00
|
|
|
{
|
2010-12-07 21:22:02 +00:00
|
|
|
if (HB_DIRECTION_IS_FORWARD (c->target_direction))
|
2010-05-21 13:34:23 +00:00
|
|
|
return;
|
|
|
|
|
2013-10-18 17:33:09 +00:00
|
|
|
hb_buffer_t *buffer = c->buffer;
|
|
|
|
hb_unicode_funcs_t *unicode = buffer->unicode;
|
2013-12-23 01:48:53 +00:00
|
|
|
hb_mask_t rtlm_mask = c->plan->rtlm_mask;
|
2010-07-23 21:22:11 +00:00
|
|
|
|
2013-10-18 17:33:09 +00:00
|
|
|
unsigned int count = buffer->len;
|
|
|
|
hb_glyph_info_t *info = buffer->info;
|
2010-05-21 13:34:23 +00:00
|
|
|
for (unsigned int i = 0; i < count; i++) {
|
2013-10-18 17:33:09 +00:00
|
|
|
hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
|
2015-07-22 14:24:26 +00:00
|
|
|
if (likely (codepoint == info[i].codepoint || !c->font->has_glyph (codepoint)))
|
2013-10-18 17:33:09 +00:00
|
|
|
info[i].mask |= rtlm_mask;
|
2010-05-21 16:58:20 +00:00
|
|
|
else
|
2013-10-18 17:33:09 +00:00
|
|
|
info[i].codepoint = codepoint;
|
2010-05-21 13:34:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-22 21:17:54 +00:00
|
|
|
static inline void
|
2018-10-08 20:32:44 +00:00
|
|
|
hb_ot_shape_setup_masks_fraction (const hb_ot_shape_context_t *c)
|
2013-12-22 21:17:54 +00:00
|
|
|
{
|
2015-11-05 02:58:02 +00:00
|
|
|
if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
|
|
|
|
!c->plan->has_frac)
|
2013-12-23 01:48:53 +00:00
|
|
|
return;
|
|
|
|
|
2013-12-22 21:17:54 +00:00
|
|
|
hb_buffer_t *buffer = c->buffer;
|
|
|
|
|
2017-01-18 20:48:13 +00:00
|
|
|
hb_mask_t pre_mask, post_mask;
|
|
|
|
if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))
|
|
|
|
{
|
|
|
|
pre_mask = c->plan->numr_mask | c->plan->frac_mask;
|
|
|
|
post_mask = c->plan->frac_mask | c->plan->dnom_mask;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pre_mask = c->plan->frac_mask | c->plan->dnom_mask;
|
|
|
|
post_mask = c->plan->numr_mask | c->plan->frac_mask;
|
|
|
|
}
|
|
|
|
|
2013-12-22 21:17:54 +00:00
|
|
|
unsigned int count = buffer->len;
|
|
|
|
hb_glyph_info_t *info = buffer->info;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
|
{
|
2014-07-11 18:54:42 +00:00
|
|
|
if (info[i].codepoint == 0x2044u) /* FRACTION SLASH */
|
2013-12-22 21:17:54 +00:00
|
|
|
{
|
|
|
|
unsigned int start = i, end = i + 1;
|
|
|
|
while (start &&
|
|
|
|
_hb_glyph_info_get_general_category (&info[start - 1]) ==
|
|
|
|
HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
|
|
|
|
start--;
|
|
|
|
while (end < count &&
|
|
|
|
_hb_glyph_info_get_general_category (&info[end]) ==
|
|
|
|
HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
|
|
|
|
end++;
|
|
|
|
|
2017-08-31 00:28:22 +00:00
|
|
|
buffer->unsafe_to_break (start, end);
|
|
|
|
|
2013-12-23 00:33:35 +00:00
|
|
|
for (unsigned int j = start; j < i; j++)
|
2017-01-18 20:48:13 +00:00
|
|
|
info[j].mask |= pre_mask;
|
2013-12-23 01:48:53 +00:00
|
|
|
info[i].mask |= c->plan->frac_mask;
|
2013-12-23 00:33:35 +00:00
|
|
|
for (unsigned int j = i + 1; j < end; j++)
|
2017-01-18 20:48:13 +00:00
|
|
|
info[j].mask |= post_mask;
|
2013-12-22 21:17:54 +00:00
|
|
|
|
|
|
|
i = end - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-10 01:58:07 +00:00
|
|
|
static inline void
|
2018-10-08 20:32:44 +00:00
|
|
|
hb_ot_shape_initialize_masks (const hb_ot_shape_context_t *c)
|
2012-08-10 01:58:07 +00:00
|
|
|
{
|
|
|
|
hb_ot_map_t *map = &c->plan->map;
|
2013-10-18 17:33:09 +00:00
|
|
|
hb_buffer_t *buffer = c->buffer;
|
2012-08-10 01:58:07 +00:00
|
|
|
|
|
|
|
hb_mask_t global_mask = map->get_global_mask ();
|
2013-10-18 17:33:09 +00:00
|
|
|
buffer->reset_masks (global_mask);
|
2013-12-21 05:18:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2018-10-08 20:32:44 +00:00
|
|
|
hb_ot_shape_setup_masks (const hb_ot_shape_context_t *c)
|
2013-12-21 05:18:18 +00:00
|
|
|
{
|
|
|
|
hb_ot_map_t *map = &c->plan->map;
|
|
|
|
hb_buffer_t *buffer = c->buffer;
|
2012-08-10 01:58:07 +00:00
|
|
|
|
2013-12-22 21:17:54 +00:00
|
|
|
hb_ot_shape_setup_masks_fraction (c);
|
|
|
|
|
2012-08-10 01:58:07 +00:00
|
|
|
if (c->plan->shaper->setup_masks)
|
2013-10-18 17:33:09 +00:00
|
|
|
c->plan->shaper->setup_masks (c->plan, buffer, c->font);
|
2012-08-10 01:58:07 +00:00
|
|
|
|
|
|
|
for (unsigned int i = 0; i < c->num_user_features; i++)
|
|
|
|
{
|
|
|
|
const hb_feature_t *feature = &c->user_features[i];
|
|
|
|
if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
|
|
|
|
unsigned int shift;
|
|
|
|
hb_mask_t mask = map->get_mask (feature->tag, &shift);
|
2013-10-18 17:33:09 +00:00
|
|
|
buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
|
2012-08-10 01:58:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-22 17:41:10 +00:00
|
|
|
static void
|
2018-11-07 22:19:21 +00:00
|
|
|
hb_ot_zero_width_default_ignorables (const hb_buffer_t *buffer)
|
2015-07-22 17:41:10 +00:00
|
|
|
{
|
2015-11-05 02:46:22 +00:00
|
|
|
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
|
2018-01-10 02:35:20 +00:00
|
|
|
(buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES) ||
|
|
|
|
(buffer->flags & HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES))
|
2015-07-22 17:41:10 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
unsigned int count = buffer->len;
|
|
|
|
hb_glyph_info_t *info = buffer->info;
|
|
|
|
hb_glyph_position_t *pos = buffer->pos;
|
|
|
|
unsigned int i = 0;
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
|
|
|
|
pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
|
|
|
|
}
|
2015-07-22 16:36:23 +00:00
|
|
|
|
|
|
|
static void
|
2018-11-07 22:19:21 +00:00
|
|
|
hb_ot_hide_default_ignorables (hb_buffer_t *buffer,
|
|
|
|
hb_font_t *font)
|
2015-07-22 16:36:23 +00:00
|
|
|
{
|
2015-11-05 02:46:22 +00:00
|
|
|
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
|
|
|
|
(buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
|
2015-07-22 16:36:23 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
unsigned int count = buffer->len;
|
|
|
|
hb_glyph_info_t *info = buffer->info;
|
|
|
|
|
2018-11-07 22:19:21 +00:00
|
|
|
hb_codepoint_t invisible = buffer->invisible;
|
2018-01-10 02:35:20 +00:00
|
|
|
if (!(buffer->flags & HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES) &&
|
2018-11-07 22:19:21 +00:00
|
|
|
(invisible || font->get_nominal_glyph (' ', &invisible)))
|
2015-07-22 16:36:23 +00:00
|
|
|
{
|
2018-10-07 16:41:52 +00:00
|
|
|
/* Replace default-ignorables with a zero-advance invisible glyph. */
|
2018-10-07 22:52:12 +00:00
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2015-07-22 16:36:23 +00:00
|
|
|
{
|
2015-07-22 16:41:31 +00:00
|
|
|
if (_hb_glyph_info_is_default_ignorable (&info[i]))
|
2018-10-07 16:41:52 +00:00
|
|
|
info[i].codepoint = invisible;
|
2015-07-22 16:36:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2018-11-07 22:19:21 +00:00
|
|
|
hb_ot_layout_delete_glyphs_inplace (buffer, _hb_glyph_info_is_default_ignorable);
|
2015-07-22 16:36:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-10 01:58:07 +00:00
|
|
|
static inline void
|
2012-08-10 02:33:32 +00:00
|
|
|
hb_ot_map_glyphs_fast (hb_buffer_t *buffer)
|
2010-05-21 13:34:23 +00:00
|
|
|
{
|
2012-08-10 02:33:32 +00:00
|
|
|
/* Normalization process sets up glyph_index(), we just copy it. */
|
|
|
|
unsigned int count = buffer->len;
|
2014-07-17 18:22:11 +00:00
|
|
|
hb_glyph_info_t *info = buffer->info;
|
2012-08-10 02:33:32 +00:00
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2014-07-17 18:22:11 +00:00
|
|
|
info[i].codepoint = info[i].glyph_index();
|
2015-08-18 17:42:47 +00:00
|
|
|
|
|
|
|
buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
|
2010-05-21 13:34:23 +00:00
|
|
|
}
|
|
|
|
|
2016-12-22 19:33:54 +00:00
|
|
|
static inline void
|
2018-11-07 22:19:21 +00:00
|
|
|
hb_synthesize_glyph_classes (hb_buffer_t *buffer)
|
2016-12-22 19:33:54 +00:00
|
|
|
{
|
2018-11-07 22:19:21 +00:00
|
|
|
unsigned int count = buffer->len;
|
|
|
|
hb_glyph_info_t *info = buffer->info;
|
2016-12-22 19:33:54 +00:00
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
hb_ot_layout_glyph_props_flags_t klass;
|
|
|
|
|
|
|
|
/* Never mark default-ignorables as marks.
|
|
|
|
* They won't get in the way of lookups anyway,
|
|
|
|
* but having them as mark will cause them to be skipped
|
|
|
|
* over if the lookup-flag says so, but at least for the
|
|
|
|
* Mongolian variation selectors, looks like Uniscribe
|
|
|
|
* marks them as non-mark. Some Mongolian fonts without
|
|
|
|
* GDEF rely on this. Another notable character that
|
|
|
|
* this applies to is COMBINING GRAPHEME JOINER. */
|
|
|
|
klass = (_hb_glyph_info_get_general_category (&info[i]) !=
|
|
|
|
HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
|
|
|
|
_hb_glyph_info_is_default_ignorable (&info[i])) ?
|
|
|
|
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
|
|
|
|
HB_OT_LAYOUT_GLYPH_PROPS_MARK;
|
|
|
|
_hb_glyph_info_set_glyph_props (&info[i], klass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-10 01:58:07 +00:00
|
|
|
static inline void
|
2018-10-08 20:32:44 +00:00
|
|
|
hb_ot_substitute_default (const hb_ot_shape_context_t *c)
|
2010-05-21 13:34:23 +00:00
|
|
|
{
|
2013-10-18 17:33:09 +00:00
|
|
|
hb_buffer_t *buffer = c->buffer;
|
|
|
|
|
2012-08-10 01:58:07 +00:00
|
|
|
hb_ot_mirror_chars (c);
|
|
|
|
|
2013-10-18 17:33:09 +00:00
|
|
|
HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
|
2012-08-10 02:33:32 +00:00
|
|
|
|
2013-10-18 17:33:09 +00:00
|
|
|
_hb_ot_shape_normalize (c->plan, buffer, c->font);
|
2012-08-10 01:58:07 +00:00
|
|
|
|
|
|
|
hb_ot_shape_setup_masks (c);
|
2011-07-28 20:48:43 +00:00
|
|
|
|
2012-09-01 23:20:41 +00:00
|
|
|
/* This is unfortunate to go here, but necessary... */
|
2018-10-09 03:30:24 +00:00
|
|
|
if (c->plan->fallback_mark_positioning)
|
|
|
|
_hb_ot_shape_fallback_mark_position_recategorize_marks (c->plan, c->font, buffer);
|
2012-09-01 23:20:41 +00:00
|
|
|
|
2013-10-18 17:33:09 +00:00
|
|
|
hb_ot_map_glyphs_fast (buffer);
|
2012-08-10 02:33:32 +00:00
|
|
|
|
2013-10-18 17:33:09 +00:00
|
|
|
HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index);
|
2010-05-21 13:34:23 +00:00
|
|
|
}
|
|
|
|
|
2012-08-10 01:58:07 +00:00
|
|
|
static inline void
|
2018-10-08 20:32:44 +00:00
|
|
|
hb_ot_substitute_complex (const hb_ot_shape_context_t *c)
|
2011-07-25 04:44:50 +00:00
|
|
|
{
|
2013-10-18 17:33:09 +00:00
|
|
|
hb_buffer_t *buffer = c->buffer;
|
|
|
|
|
|
|
|
hb_ot_layout_substitute_start (c->font, buffer);
|
2012-07-30 23:30:01 +00:00
|
|
|
|
2018-10-02 11:27:11 +00:00
|
|
|
if (c->plan->fallback_glyph_classes)
|
2018-11-07 22:19:21 +00:00
|
|
|
hb_synthesize_glyph_classes (c->buffer);
|
2016-12-22 19:33:54 +00:00
|
|
|
|
2018-10-04 09:34:21 +00:00
|
|
|
if (unlikely (c->plan->apply_morx))
|
2018-10-10 02:35:22 +00:00
|
|
|
hb_aat_layout_substitute (c->plan, c->font, c->buffer);
|
2018-10-04 09:34:21 +00:00
|
|
|
else
|
|
|
|
c->plan->substitute (c->font, buffer);
|
2011-07-25 04:44:50 +00:00
|
|
|
}
|
|
|
|
|
2012-08-10 01:58:07 +00:00
|
|
|
static inline void
|
2018-11-07 22:19:21 +00:00
|
|
|
hb_ot_substitute_pre (const hb_ot_shape_context_t *c)
|
2012-08-10 01:58:07 +00:00
|
|
|
{
|
|
|
|
hb_ot_substitute_default (c);
|
2015-11-05 06:28:44 +00:00
|
|
|
|
|
|
|
_hb_buffer_allocate_gsubgpos_vars (c->buffer);
|
|
|
|
|
2012-08-10 01:58:07 +00:00
|
|
|
hb_ot_substitute_complex (c);
|
|
|
|
}
|
2010-05-21 13:34:23 +00:00
|
|
|
|
2018-11-07 22:19:21 +00:00
|
|
|
static inline void
|
|
|
|
hb_ot_substitute_post (const hb_ot_shape_context_t *c)
|
|
|
|
{
|
|
|
|
hb_ot_hide_default_ignorables (c->buffer, c->font);
|
|
|
|
if (c->plan->apply_morx)
|
|
|
|
hb_aat_layout_remove_deleted_glyphs (c->buffer);
|
|
|
|
|
|
|
|
if (c->plan->shaper->postprocess_glyphs)
|
|
|
|
c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Position
|
|
|
|
*/
|
2010-05-21 13:34:23 +00:00
|
|
|
|
2013-05-20 13:18:52 +00:00
|
|
|
static inline void
|
2014-06-10 12:10:30 +00:00
|
|
|
adjust_mark_offsets (hb_glyph_position_t *pos)
|
|
|
|
{
|
|
|
|
pos->x_offset -= pos->x_advance;
|
|
|
|
pos->y_offset -= pos->y_advance;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
zero_mark_width (hb_glyph_position_t *pos)
|
|
|
|
{
|
|
|
|
pos->x_advance = 0;
|
|
|
|
pos->y_advance = 0;
|
|
|
|
}
|
|
|
|
|
2013-05-20 13:18:52 +00:00
|
|
|
static inline void
|
2014-06-10 12:10:30 +00:00
|
|
|
zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
|
2013-05-20 13:18:52 +00:00
|
|
|
{
|
|
|
|
unsigned int count = buffer->len;
|
2014-07-17 18:22:11 +00:00
|
|
|
hb_glyph_info_t *info = buffer->info;
|
2013-05-20 13:18:52 +00:00
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2014-07-17 18:22:11 +00:00
|
|
|
if (_hb_glyph_info_is_mark (&info[i]))
|
2013-05-20 13:18:52 +00:00
|
|
|
{
|
2014-06-10 12:10:30 +00:00
|
|
|
if (adjust_offsets)
|
|
|
|
adjust_mark_offsets (&buffer->pos[i]);
|
|
|
|
zero_mark_width (&buffer->pos[i]);
|
2013-05-20 13:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-10 01:58:07 +00:00
|
|
|
static inline void
|
2018-10-08 20:32:44 +00:00
|
|
|
hb_ot_position_default (const hb_ot_shape_context_t *c)
|
2010-05-21 13:34:23 +00:00
|
|
|
{
|
2013-10-18 17:33:09 +00:00
|
|
|
hb_direction_t direction = c->buffer->props.direction;
|
2010-10-06 03:00:05 +00:00
|
|
|
unsigned int count = c->buffer->len;
|
2013-10-18 17:33:09 +00:00
|
|
|
hb_glyph_info_t *info = c->buffer->info;
|
|
|
|
hb_glyph_position_t *pos = c->buffer->pos;
|
Adjust mark advance-width zeroing logic for Myanmar
Before, we were zeroing advance width of attached marks for
non-Indic scripts, and not doing it for Indic.
We have now three different behaviors, which seem to better
reflect what Uniscribe is doing:
- For Indic, no explicit zeroing happens whatsoever, which
is the same as before,
- For Myanmar, zero advance width of glyphs marked as marks
*in GDEF*, and do that *before* applying GPOS. This seems
to be what the new Win8 Myanmar shaper does,
- For everything else, zero advance width of glyphs that are
from General_Category=Mn Unicode characters, and do so
before applying GPOS. This seems to be what Uniscribe does
for Latin at least.
With these changes, positioning of all tests matches for Myanmar,
except for the glitch in Uniscribe not applying 'mark'. See preivous
commit.
2013-02-12 14:44:57 +00:00
|
|
|
|
2015-11-05 03:28:17 +00:00
|
|
|
if (HB_DIRECTION_IS_HORIZONTAL (direction))
|
|
|
|
{
|
2018-08-01 04:01:08 +00:00
|
|
|
c->font->get_glyph_h_advances (count, &info[0].codepoint, sizeof(info[0]),
|
|
|
|
&pos[0].x_advance, sizeof(pos[0]));
|
2015-11-26 23:48:42 +00:00
|
|
|
/* The nil glyph_h_origin() func returns 0, so no need to apply it. */
|
2015-11-05 05:53:16 +00:00
|
|
|
if (c->font->has_glyph_h_origin_func ())
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
|
c->font->subtract_glyph_h_origin (info[i].codepoint,
|
|
|
|
&pos[i].x_offset,
|
|
|
|
&pos[i].y_offset);
|
2015-11-05 03:28:17 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-08-06 16:45:17 +00:00
|
|
|
c->font->get_glyph_v_advances (count, &info[0].codepoint, sizeof(info[0]),
|
|
|
|
&pos[0].y_advance, sizeof(pos[0]));
|
2015-11-05 03:28:17 +00:00
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2015-11-26 23:48:42 +00:00
|
|
|
{
|
|
|
|
c->font->subtract_glyph_v_origin (info[i].codepoint,
|
|
|
|
&pos[i].x_offset,
|
|
|
|
&pos[i].y_offset);
|
|
|
|
}
|
Adjust mark advance-width zeroing logic for Myanmar
Before, we were zeroing advance width of attached marks for
non-Indic scripts, and not doing it for Indic.
We have now three different behaviors, which seem to better
reflect what Uniscribe is doing:
- For Indic, no explicit zeroing happens whatsoever, which
is the same as before,
- For Myanmar, zero advance width of glyphs marked as marks
*in GDEF*, and do that *before* applying GPOS. This seems
to be what the new Win8 Myanmar shaper does,
- For everything else, zero advance width of glyphs that are
from General_Category=Mn Unicode characters, and do so
before applying GPOS. This seems to be what Uniscribe does
for Latin at least.
With these changes, positioning of all tests matches for Myanmar,
except for the glitch in Uniscribe not applying 'mark'. See preivous
commit.
2013-02-12 14:44:57 +00:00
|
|
|
}
|
2015-11-05 01:27:07 +00:00
|
|
|
if (c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK)
|
|
|
|
_hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer);
|
2013-09-14 00:17:42 +00:00
|
|
|
}
|
|
|
|
|
2016-12-22 20:40:19 +00:00
|
|
|
static inline void
|
2018-10-08 20:32:44 +00:00
|
|
|
hb_ot_position_complex (const hb_ot_shape_context_t *c)
|
2013-09-14 00:17:42 +00:00
|
|
|
{
|
|
|
|
unsigned int count = c->buffer->len;
|
2017-10-03 15:22:43 +00:00
|
|
|
hb_glyph_info_t *info = c->buffer->info;
|
|
|
|
hb_glyph_position_t *pos = c->buffer->pos;
|
2016-02-11 09:27:41 +00:00
|
|
|
|
2014-06-10 12:10:30 +00:00
|
|
|
/* If the font has no GPOS, AND, no fallback positioning will
|
|
|
|
* happen, AND, direction is forward, then when zeroing mark
|
|
|
|
* widths, we shift the mark with it, such that the mark
|
|
|
|
* is positioned hanging over the previous glyph. When
|
|
|
|
* direction is backward we don't shift and it will end up
|
|
|
|
* hanging over the next glyph after the final reordering.
|
|
|
|
* If fallback positinoing happens or GPOS is present, we don't
|
|
|
|
* care.
|
|
|
|
*/
|
2018-10-09 03:30:24 +00:00
|
|
|
bool adjust_offsets_when_zeroing = c->plan->fallback_mark_positioning &&
|
2016-12-22 20:40:19 +00:00
|
|
|
!c->plan->shaper->fallback_position &&
|
|
|
|
HB_DIRECTION_IS_FORWARD (c->buffer->props.direction);
|
Adjust mark advance-width zeroing logic for Myanmar
Before, we were zeroing advance width of attached marks for
non-Indic scripts, and not doing it for Indic.
We have now three different behaviors, which seem to better
reflect what Uniscribe is doing:
- For Indic, no explicit zeroing happens whatsoever, which
is the same as before,
- For Myanmar, zero advance width of glyphs marked as marks
*in GDEF*, and do that *before* applying GPOS. This seems
to be what the new Win8 Myanmar shaper does,
- For everything else, zero advance width of glyphs that are
from General_Category=Mn Unicode characters, and do so
before applying GPOS. This seems to be what Uniscribe does
for Latin at least.
With these changes, positioning of all tests matches for Myanmar,
except for the glitch in Uniscribe not applying 'mark'. See preivous
commit.
2013-02-12 14:44:57 +00:00
|
|
|
|
2017-10-03 15:22:43 +00:00
|
|
|
/* We change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */
|
|
|
|
|
|
|
|
/* The nil glyph_h_origin() func returns 0, so no need to apply it. */
|
|
|
|
if (c->font->has_glyph_h_origin_func ())
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
|
c->font->add_glyph_h_origin (info[i].codepoint,
|
|
|
|
&pos[i].x_offset,
|
|
|
|
&pos[i].y_offset);
|
|
|
|
|
|
|
|
hb_ot_layout_position_start (c->font, c->buffer);
|
|
|
|
|
2018-11-07 21:19:51 +00:00
|
|
|
if (c->plan->zero_marks)
|
2018-10-11 01:29:46 +00:00
|
|
|
switch (c->plan->shaper->zero_width_marks)
|
|
|
|
{
|
|
|
|
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
|
|
|
|
zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
|
|
|
|
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
|
|
|
|
break;
|
|
|
|
}
|
2011-07-25 04:44:50 +00:00
|
|
|
|
2018-10-04 09:34:21 +00:00
|
|
|
if (c->plan->apply_gpos)
|
2018-10-11 02:17:07 +00:00
|
|
|
c->plan->position (c->font, c->buffer);
|
2018-10-10 17:24:51 +00:00
|
|
|
else if (c->plan->apply_kerx)
|
|
|
|
hb_aat_layout_position (c->plan, c->font, c->buffer);
|
2018-11-07 18:58:41 +00:00
|
|
|
else if (c->plan->apply_kern)
|
|
|
|
hb_ot_layout_kern (c->plan, c->font, c->buffer);
|
2018-11-07 21:19:51 +00:00
|
|
|
else
|
2018-11-07 18:58:41 +00:00
|
|
|
_hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer);
|
2011-07-25 04:44:50 +00:00
|
|
|
|
2018-10-11 17:24:17 +00:00
|
|
|
if (c->plan->apply_trak)
|
|
|
|
hb_aat_layout_track (c->plan, c->font, c->buffer);
|
2018-10-11 15:10:06 +00:00
|
|
|
|
2018-11-07 21:19:51 +00:00
|
|
|
if (c->plan->zero_marks)
|
2018-10-11 01:29:46 +00:00
|
|
|
switch (c->plan->shaper->zero_width_marks)
|
|
|
|
{
|
|
|
|
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
|
|
|
|
zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
|
|
|
|
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
|
|
|
|
break;
|
|
|
|
}
|
2013-02-13 10:57:24 +00:00
|
|
|
|
2018-11-07 22:19:21 +00:00
|
|
|
/* Finish off. Has to follow a certain order. */
|
2016-02-11 09:34:28 +00:00
|
|
|
hb_ot_layout_position_finish_advances (c->font, c->buffer);
|
2018-11-07 22:19:21 +00:00
|
|
|
hb_ot_zero_width_default_ignorables (c->buffer);
|
|
|
|
if (c->plan->apply_morx)
|
|
|
|
hb_aat_layout_zero_width_deleted_glyphs (c->buffer);
|
2016-02-11 09:34:28 +00:00
|
|
|
hb_ot_layout_position_finish_offsets (c->font, c->buffer);
|
2017-10-03 15:22:43 +00:00
|
|
|
|
|
|
|
/* The nil glyph_h_origin() func returns 0, so no need to apply it. */
|
|
|
|
if (c->font->has_glyph_h_origin_func ())
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
|
c->font->subtract_glyph_h_origin (info[i].codepoint,
|
|
|
|
&pos[i].x_offset,
|
|
|
|
&pos[i].y_offset);
|
2018-11-07 21:05:36 +00:00
|
|
|
|
|
|
|
if (c->plan->fallback_mark_positioning && c->plan->shaper->fallback_position)
|
|
|
|
_hb_ot_shape_fallback_mark_position (c->plan, c->font, c->buffer);
|
2011-07-25 04:44:50 +00:00
|
|
|
}
|
|
|
|
|
2012-08-10 01:58:07 +00:00
|
|
|
static inline void
|
2018-10-08 20:32:44 +00:00
|
|
|
hb_ot_position (const hb_ot_shape_context_t *c)
|
2012-08-10 01:58:07 +00:00
|
|
|
{
|
2016-02-11 09:27:41 +00:00
|
|
|
c->buffer->clear_positions ();
|
2013-09-14 00:17:42 +00:00
|
|
|
|
2012-08-10 01:58:07 +00:00
|
|
|
hb_ot_position_default (c);
|
|
|
|
|
2016-12-22 20:40:19 +00:00
|
|
|
hb_ot_position_complex (c);
|
2012-08-10 01:58:07 +00:00
|
|
|
|
|
|
|
if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
|
|
|
|
hb_buffer_reverse (c->buffer);
|
|
|
|
|
2014-08-02 21:18:46 +00:00
|
|
|
_hb_buffer_deallocate_gsubgpos_vars (c->buffer);
|
2010-05-21 13:34:23 +00:00
|
|
|
}
|
|
|
|
|
2017-08-12 02:06:07 +00:00
|
|
|
static inline void
|
|
|
|
hb_propagate_flags (hb_buffer_t *buffer)
|
|
|
|
{
|
|
|
|
/* Propagate cluster-level glyph flags to be the same on all cluster glyphs.
|
|
|
|
* Simplifies using them. */
|
|
|
|
|
|
|
|
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK))
|
|
|
|
return;
|
|
|
|
|
|
|
|
hb_glyph_info_t *info = buffer->info;
|
|
|
|
|
|
|
|
foreach_cluster (buffer, start, end)
|
|
|
|
{
|
|
|
|
unsigned int mask = 0;
|
|
|
|
for (unsigned int i = start; i < end; i++)
|
|
|
|
if (info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
|
|
|
|
{
|
|
|
|
mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (mask)
|
|
|
|
for (unsigned int i = start; i < end; i++)
|
|
|
|
info[i].mask |= mask;
|
|
|
|
}
|
|
|
|
}
|
2012-08-10 01:58:07 +00:00
|
|
|
|
|
|
|
/* Pull it all together! */
|
2010-05-21 13:34:23 +00:00
|
|
|
|
2010-10-06 03:00:05 +00:00
|
|
|
static void
|
2012-07-27 06:29:32 +00:00
|
|
|
hb_ot_shape_internal (hb_ot_shape_context_t *c)
|
2010-05-21 13:34:23 +00:00
|
|
|
{
|
2011-07-28 20:48:43 +00:00
|
|
|
c->buffer->deallocate_var_all ();
|
2015-11-05 01:27:07 +00:00
|
|
|
c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
|
2018-07-10 12:12:37 +00:00
|
|
|
if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR)))
|
2015-11-06 07:44:59 +00:00
|
|
|
{
|
2017-11-15 05:53:48 +00:00
|
|
|
c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR,
|
2015-11-06 07:44:59 +00:00
|
|
|
(unsigned) HB_BUFFER_MAX_LEN_MIN);
|
|
|
|
}
|
2018-07-10 12:12:37 +00:00
|
|
|
if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR)))
|
2017-11-15 05:53:48 +00:00
|
|
|
{
|
|
|
|
c->buffer->max_ops = MAX (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR,
|
|
|
|
(unsigned) HB_BUFFER_MAX_OPS_MIN);
|
|
|
|
}
|
2011-07-28 20:48:43 +00:00
|
|
|
|
2010-10-12 19:35:45 +00:00
|
|
|
/* Save the original direction, we use it later. */
|
2010-12-07 21:22:02 +00:00
|
|
|
c->target_direction = c->buffer->props.direction;
|
2010-10-12 19:35:45 +00:00
|
|
|
|
2013-10-17 22:42:39 +00:00
|
|
|
_hb_buffer_allocate_unicode_vars (c->buffer);
|
2011-07-28 20:48:43 +00:00
|
|
|
|
2012-06-09 00:40:02 +00:00
|
|
|
c->buffer->clear_output ();
|
|
|
|
|
2017-09-05 03:04:59 +00:00
|
|
|
hb_ot_shape_initialize_masks (c);
|
2012-05-09 13:04:13 +00:00
|
|
|
hb_set_unicode_props (c->buffer);
|
2012-09-02 00:38:45 +00:00
|
|
|
hb_insert_dotted_circle (c->buffer, c->font);
|
2017-09-05 03:04:59 +00:00
|
|
|
|
2011-07-22 20:15:32 +00:00
|
|
|
hb_form_clusters (c->buffer);
|
|
|
|
|
2011-07-21 15:34:59 +00:00
|
|
|
hb_ensure_native_direction (c->buffer);
|
2011-07-21 05:11:09 +00:00
|
|
|
|
2015-11-05 21:24:15 +00:00
|
|
|
if (c->plan->shaper->preprocess_text)
|
|
|
|
c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
|
|
|
|
|
2018-11-07 22:19:21 +00:00
|
|
|
hb_ot_substitute_pre (c);
|
2012-08-10 01:58:07 +00:00
|
|
|
hb_ot_position (c);
|
2018-11-07 22:19:21 +00:00
|
|
|
hb_ot_substitute_post (c);
|
2015-11-05 21:24:15 +00:00
|
|
|
|
2017-08-12 02:06:07 +00:00
|
|
|
hb_propagate_flags (c->buffer);
|
|
|
|
|
2013-10-17 22:42:39 +00:00
|
|
|
_hb_buffer_deallocate_unicode_vars (c->buffer);
|
2011-07-28 20:48:43 +00:00
|
|
|
|
2010-12-07 21:22:02 +00:00
|
|
|
c->buffer->props.direction = c->target_direction;
|
2011-07-28 21:06:46 +00:00
|
|
|
|
2015-11-06 07:44:59 +00:00
|
|
|
c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
|
2017-11-15 05:53:48 +00:00
|
|
|
c->buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
|
2011-07-28 21:06:46 +00:00
|
|
|
c->buffer->deallocate_var_all ();
|
2010-10-06 03:00:05 +00:00
|
|
|
}
|
|
|
|
|
2010-10-12 20:57:47 +00:00
|
|
|
|
2011-08-05 02:31:05 +00:00
|
|
|
hb_bool_t
|
2012-07-27 02:05:39 +00:00
|
|
|
_hb_ot_shape (hb_shape_plan_t *shape_plan,
|
|
|
|
hb_font_t *font,
|
2012-04-12 18:53:53 +00:00
|
|
|
hb_buffer_t *buffer,
|
|
|
|
const hb_feature_t *features,
|
|
|
|
unsigned int num_features)
|
2010-10-06 03:00:05 +00:00
|
|
|
{
|
2018-11-12 02:32:01 +00:00
|
|
|
hb_ot_shape_context_t c = {&shape_plan->ot, font, font->face, buffer, features, num_features};
|
2012-07-27 06:29:32 +00:00
|
|
|
hb_ot_shape_internal (&c);
|
2011-08-05 02:31:05 +00:00
|
|
|
|
2012-06-06 00:35:40 +00:00
|
|
|
return true;
|
2010-05-21 13:34:23 +00:00
|
|
|
}
|
2012-04-24 20:56:37 +00:00
|
|
|
|
|
|
|
|
2015-06-01 11:22:01 +00:00
|
|
|
/**
|
2015-11-27 00:30:37 +00:00
|
|
|
* hb_ot_shape_plan_collect_lookups:
|
|
|
|
*
|
2015-06-01 11:22:01 +00:00
|
|
|
* Since: 0.9.7
|
|
|
|
**/
|
2012-11-16 02:39:46 +00:00
|
|
|
void
|
|
|
|
hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
|
|
|
|
hb_tag_t table_tag,
|
|
|
|
hb_set_t *lookup_indexes /* OUT */)
|
|
|
|
{
|
2018-11-12 02:32:01 +00:00
|
|
|
shape_plan->ot.collect_lookups (table_tag, lookup_indexes);
|
2012-11-16 02:39:46 +00:00
|
|
|
}
|
2012-08-10 02:33:32 +00:00
|
|
|
|
2012-11-16 02:39:46 +00:00
|
|
|
|
|
|
|
/* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
|
|
|
|
static void
|
|
|
|
add_char (hb_font_t *font,
|
|
|
|
hb_unicode_funcs_t *unicode,
|
|
|
|
hb_bool_t mirror,
|
|
|
|
hb_codepoint_t u,
|
|
|
|
hb_set_t *glyphs)
|
2012-08-10 02:33:32 +00:00
|
|
|
{
|
2012-11-16 02:39:46 +00:00
|
|
|
hb_codepoint_t glyph;
|
2016-02-24 10:05:23 +00:00
|
|
|
if (font->get_nominal_glyph (u, &glyph))
|
2012-11-16 02:39:46 +00:00
|
|
|
glyphs->add (glyph);
|
|
|
|
if (mirror)
|
|
|
|
{
|
|
|
|
hb_codepoint_t m = unicode->mirroring (u);
|
2016-02-24 10:05:23 +00:00
|
|
|
if (m != u && font->get_nominal_glyph (m, &glyph))
|
2012-11-16 02:39:46 +00:00
|
|
|
glyphs->add (glyph);
|
|
|
|
}
|
2012-08-10 02:33:32 +00:00
|
|
|
}
|
|
|
|
|
2012-11-16 02:39:46 +00:00
|
|
|
|
2015-06-01 11:22:01 +00:00
|
|
|
/**
|
2015-11-27 00:30:37 +00:00
|
|
|
* hb_ot_shape_glyphs_closure:
|
|
|
|
*
|
2015-06-01 11:22:01 +00:00
|
|
|
* Since: 0.9.2
|
|
|
|
**/
|
2012-04-24 20:56:37 +00:00
|
|
|
void
|
|
|
|
hb_ot_shape_glyphs_closure (hb_font_t *font,
|
|
|
|
hb_buffer_t *buffer,
|
|
|
|
const hb_feature_t *features,
|
|
|
|
unsigned int num_features,
|
|
|
|
hb_set_t *glyphs)
|
|
|
|
{
|
2017-10-15 10:11:08 +00:00
|
|
|
const char *shapers[] = {"ot", nullptr};
|
2012-11-16 02:39:46 +00:00
|
|
|
hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
|
|
|
|
features, num_features, shapers);
|
2012-04-24 20:56:37 +00:00
|
|
|
|
2012-11-16 02:39:46 +00:00
|
|
|
bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL;
|
2012-04-24 20:56:37 +00:00
|
|
|
|
|
|
|
unsigned int count = buffer->len;
|
2014-07-17 18:22:11 +00:00
|
|
|
hb_glyph_info_t *info = buffer->info;
|
2012-04-24 20:56:37 +00:00
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2014-07-17 18:22:11 +00:00
|
|
|
add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs);
|
2012-11-16 02:39:46 +00:00
|
|
|
|
2017-10-22 21:48:06 +00:00
|
|
|
hb_set_t *lookups = hb_set_create ();
|
|
|
|
hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, lookups);
|
2018-06-06 23:02:51 +00:00
|
|
|
hb_ot_layout_lookups_substitute_closure (font->face, lookups, glyphs);
|
2017-10-22 21:48:06 +00:00
|
|
|
|
|
|
|
hb_set_destroy (lookups);
|
2012-07-27 06:29:32 +00:00
|
|
|
|
|
|
|
hb_shape_plan_destroy (shape_plan);
|
2012-04-24 20:56:37 +00:00
|
|
|
}
|