2008-01-24 09:11:09 +01:00
|
|
|
/*
|
2011-04-21 23:14:28 +02:00
|
|
|
* Copyright © 1998-2004 David Turner and Werner Lemberg
|
|
|
|
* Copyright © 2006 Behdad Esfahbod
|
|
|
|
* Copyright © 2007,2008,2009 Red Hat, Inc.
|
2013-05-03 23:49:44 +02:00
|
|
|
* Copyright © 2012,2013 Google, Inc.
|
2008-01-24 09:11:09 +01:00
|
|
|
*
|
2010-04-22 06:11:43 +02:00
|
|
|
* This is part of HarfBuzz, a text shaping library.
|
2008-01-24 09:11:09 +01: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
|
2012-07-30 08:38:39 +02:00
|
|
|
* Google Author(s): Behdad Esfahbod
|
2008-01-24 09:11:09 +01:00
|
|
|
*/
|
|
|
|
|
2015-10-09 18:20:58 +02:00
|
|
|
#include "hb-open-type-private.hh"
|
2010-05-13 00:23:21 +02:00
|
|
|
#include "hb-ot-layout-private.hh"
|
2008-01-24 09:11:09 +01:00
|
|
|
|
2011-08-17 14:19:59 +02:00
|
|
|
#include "hb-ot-layout-gdef-table.hh"
|
|
|
|
#include "hb-ot-layout-gsub-table.hh"
|
|
|
|
#include "hb-ot-layout-gpos-table.hh"
|
2013-09-09 21:43:10 +02:00
|
|
|
#include "hb-ot-layout-jstf-table.hh"
|
2008-01-24 09:11:09 +01:00
|
|
|
|
2013-05-03 00:18:24 +02:00
|
|
|
#include "hb-ot-map-private.hh"
|
|
|
|
|
2008-01-24 09:11:09 +01:00
|
|
|
#include <stdlib.h>
|
2008-01-24 12:03:45 +01:00
|
|
|
#include <string.h>
|
|
|
|
|
2010-07-23 21:11:18 +02:00
|
|
|
|
2012-07-27 09:06:30 +02:00
|
|
|
HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
|
2012-07-30 08:36:46 +02:00
|
|
|
|
2010-05-19 21:45:06 +02:00
|
|
|
hb_ot_layout_t *
|
2011-05-03 06:35:53 +02:00
|
|
|
_hb_ot_layout_create (hb_face_t *face)
|
2008-01-28 13:40:10 +01:00
|
|
|
{
|
2010-05-19 21:45:06 +02:00
|
|
|
hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
|
2012-07-31 01:31:17 +02:00
|
|
|
if (unlikely (!layout))
|
|
|
|
return NULL;
|
2010-01-26 18:58:59 +01:00
|
|
|
|
2012-08-28 23:57:49 +02:00
|
|
|
layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
|
|
|
|
layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
|
2009-08-04 04:01:47 +02:00
|
|
|
|
2012-08-28 23:57:49 +02:00
|
|
|
layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
|
|
|
|
layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
|
2009-08-04 04:01:47 +02:00
|
|
|
|
2012-08-28 23:57:49 +02:00
|
|
|
layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
|
|
|
|
layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
|
2010-05-19 21:45:06 +02:00
|
|
|
|
2012-08-02 10:00:31 +02:00
|
|
|
layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
|
|
|
|
layout->gpos_lookup_count = layout->gpos->get_lookup_count ();
|
|
|
|
|
2013-05-03 00:06:51 +02:00
|
|
|
layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
|
|
|
|
layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
|
2012-08-02 03:46:36 +02:00
|
|
|
|
2013-05-03 00:06:51 +02:00
|
|
|
if (unlikely ((layout->gsub_lookup_count && !layout->gsub_accels) ||
|
|
|
|
(layout->gpos_lookup_count && !layout->gpos_accels)))
|
2012-08-02 03:46:36 +02:00
|
|
|
{
|
|
|
|
_hb_ot_layout_destroy (layout);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-02 10:00:31 +02:00
|
|
|
for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
|
2013-05-03 00:06:51 +02:00
|
|
|
layout->gsub_accels[i].init (layout->gsub->get_lookup (i));
|
2012-08-02 10:00:31 +02:00
|
|
|
for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
|
2013-05-03 00:06:51 +02:00
|
|
|
layout->gpos_accels[i].init (layout->gpos->get_lookup (i));
|
2012-08-02 03:46:36 +02:00
|
|
|
|
2010-05-19 21:45:06 +02:00
|
|
|
return layout;
|
2009-07-28 21:43:34 +02:00
|
|
|
}
|
|
|
|
|
2009-08-04 03:40:20 +02:00
|
|
|
void
|
2011-05-03 06:35:53 +02:00
|
|
|
_hb_ot_layout_destroy (hb_ot_layout_t *layout)
|
2008-01-24 09:11:09 +01:00
|
|
|
{
|
2013-05-03 00:06:51 +02:00
|
|
|
for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
|
2014-12-29 01:03:26 +01:00
|
|
|
layout->gsub_accels[i].fini ();
|
2013-05-03 00:06:51 +02:00
|
|
|
for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
|
2014-12-29 01:03:26 +01:00
|
|
|
layout->gpos_accels[i].fini ();
|
2013-05-03 00:06:51 +02:00
|
|
|
|
|
|
|
free (layout->gsub_accels);
|
|
|
|
free (layout->gpos_accels);
|
2012-08-02 03:46:36 +02:00
|
|
|
|
2013-06-22 00:02:18 +02:00
|
|
|
hb_blob_destroy (layout->gdef_blob);
|
|
|
|
hb_blob_destroy (layout->gsub_blob);
|
|
|
|
hb_blob_destroy (layout->gpos_blob);
|
|
|
|
|
2010-09-22 23:38:44 +02:00
|
|
|
free (layout);
|
2009-08-04 03:40:20 +02:00
|
|
|
}
|
2009-07-28 21:43:34 +02:00
|
|
|
|
2012-08-28 23:57:49 +02:00
|
|
|
static inline const OT::GDEF&
|
2009-08-04 03:40:20 +02:00
|
|
|
_get_gdef (hb_face_t *face)
|
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GDEF);
|
2012-07-27 08:12:28 +02:00
|
|
|
return *hb_ot_layout_from_face (face)->gdef;
|
2009-08-04 03:40:20 +02:00
|
|
|
}
|
2012-08-28 23:57:49 +02:00
|
|
|
static inline const OT::GSUB&
|
2009-08-04 03:40:20 +02:00
|
|
|
_get_gsub (hb_face_t *face)
|
2008-01-24 09:11:09 +01:00
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GSUB);
|
2012-07-27 08:12:28 +02:00
|
|
|
return *hb_ot_layout_from_face (face)->gsub;
|
2008-01-24 09:11:09 +01:00
|
|
|
}
|
2012-08-28 23:57:49 +02:00
|
|
|
static inline const OT::GPOS&
|
2009-08-04 03:40:20 +02:00
|
|
|
_get_gpos (hb_face_t *face)
|
2009-07-26 01:09:01 +02:00
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GPOS);
|
2012-07-27 08:12:28 +02:00
|
|
|
return *hb_ot_layout_from_face (face)->gpos;
|
2009-07-26 01:09:01 +02:00
|
|
|
}
|
|
|
|
|
2009-08-04 03:40:20 +02:00
|
|
|
|
2008-01-25 01:13:50 +01:00
|
|
|
/*
|
|
|
|
* GDEF
|
|
|
|
*/
|
|
|
|
|
|
|
|
hb_bool_t
|
2009-11-06 23:45:38 +01:00
|
|
|
hb_ot_layout_has_glyph_classes (hb_face_t *face)
|
2008-01-25 01:13:50 +01:00
|
|
|
{
|
2009-08-04 03:40:20 +02:00
|
|
|
return _get_gdef (face).has_glyph_classes ();
|
2008-01-25 01:13:50 +01:00
|
|
|
}
|
|
|
|
|
2015-06-01 13:22:01 +02:00
|
|
|
/**
|
|
|
|
* Since: 0.9.7
|
|
|
|
**/
|
2012-11-16 22:34:29 +01:00
|
|
|
hb_ot_layout_glyph_class_t
|
|
|
|
hb_ot_layout_get_glyph_class (hb_face_t *face,
|
|
|
|
hb_codepoint_t glyph)
|
|
|
|
{
|
|
|
|
return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph);
|
|
|
|
}
|
2010-11-03 20:28:56 +01:00
|
|
|
|
2015-06-01 13:22:01 +02:00
|
|
|
/**
|
|
|
|
* Since: 0.9.7
|
|
|
|
**/
|
2012-11-16 22:53:40 +01:00
|
|
|
void
|
|
|
|
hb_ot_layout_get_glyphs_in_class (hb_face_t *face,
|
|
|
|
hb_ot_layout_glyph_class_t klass,
|
|
|
|
hb_set_t *glyphs /* OUT */)
|
|
|
|
{
|
|
|
|
return _get_gdef (face).get_glyphs_in_class (klass, glyphs);
|
|
|
|
}
|
|
|
|
|
2009-11-04 22:36:14 +01:00
|
|
|
unsigned int
|
2009-08-02 23:41:36 +02:00
|
|
|
hb_ot_layout_get_attach_points (hb_face_t *face,
|
2009-05-26 18:24:16 +02:00
|
|
|
hb_codepoint_t glyph,
|
2009-11-04 22:36:14 +01:00
|
|
|
unsigned int start_offset,
|
2009-05-26 18:24:16 +02:00
|
|
|
unsigned int *point_count /* IN/OUT */,
|
|
|
|
unsigned int *point_array /* OUT */)
|
|
|
|
{
|
2009-11-04 22:36:14 +01:00
|
|
|
return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
|
2009-05-26 18:40:10 +02:00
|
|
|
}
|
|
|
|
|
2009-11-04 22:36:14 +01:00
|
|
|
unsigned int
|
2010-10-27 18:32:02 +02:00
|
|
|
hb_ot_layout_get_ligature_carets (hb_font_t *font,
|
|
|
|
hb_direction_t direction,
|
|
|
|
hb_codepoint_t glyph,
|
|
|
|
unsigned int start_offset,
|
|
|
|
unsigned int *caret_count /* IN/OUT */,
|
|
|
|
int *caret_array /* OUT */)
|
2009-05-26 18:40:10 +02:00
|
|
|
{
|
2011-05-11 06:02:02 +02:00
|
|
|
return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
|
2009-05-26 18:24:16 +02:00
|
|
|
}
|
|
|
|
|
2012-07-31 01:30:01 +02:00
|
|
|
|
2008-01-28 11:58:50 +01:00
|
|
|
/*
|
|
|
|
* GSUB/GPOS
|
|
|
|
*/
|
|
|
|
|
2012-08-28 23:57:49 +02:00
|
|
|
static const OT::GSUBGPOS&
|
2009-08-04 03:40:20 +02:00
|
|
|
get_gsubgpos_table (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag)
|
2008-01-28 11:58:50 +01:00
|
|
|
{
|
2009-08-02 23:41:36 +02:00
|
|
|
switch (table_tag) {
|
2009-08-04 03:40:20 +02:00
|
|
|
case HB_OT_TAG_GSUB: return _get_gsub (face);
|
|
|
|
case HB_OT_TAG_GPOS: return _get_gpos (face);
|
2012-08-28 23:57:49 +02:00
|
|
|
default: return OT::Null(OT::GSUBGPOS);
|
2008-01-28 11:58:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-11-04 22:36:14 +01:00
|
|
|
unsigned int
|
2009-08-08 01:46:30 +02:00
|
|
|
hb_ot_layout_table_get_script_tags (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
2009-11-04 22:36:14 +01:00
|
|
|
unsigned int start_offset,
|
2009-08-08 01:46:30 +02:00
|
|
|
unsigned int *script_count /* IN/OUT */,
|
|
|
|
hb_tag_t *script_tags /* OUT */)
|
2008-01-28 11:58:50 +01:00
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
2008-01-28 11:58:50 +01:00
|
|
|
|
2009-11-04 22:36:14 +01:00
|
|
|
return g.get_script_tags (start_offset, script_count, script_tags);
|
2008-01-28 11:58:50 +01:00
|
|
|
}
|
|
|
|
|
2013-01-17 05:07:50 +01:00
|
|
|
#define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n')
|
|
|
|
|
2008-01-28 11:58:50 +01:00
|
|
|
hb_bool_t
|
2009-08-02 23:41:36 +02:00
|
|
|
hb_ot_layout_table_find_script (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
|
|
|
hb_tag_t script_tag,
|
|
|
|
unsigned int *script_index)
|
2008-01-28 11:58:50 +01:00
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
|
|
|
|
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
2008-01-28 11:58:50 +01:00
|
|
|
|
|
|
|
if (g.find_script_index (script_tag, script_index))
|
2012-06-06 02:35:40 +02:00
|
|
|
return true;
|
2008-01-28 11:58:50 +01:00
|
|
|
|
|
|
|
/* try finding 'DFLT' */
|
2009-11-05 01:45:39 +01:00
|
|
|
if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
|
2012-06-06 02:35:40 +02:00
|
|
|
return false;
|
2008-01-28 11:58:50 +01:00
|
|
|
|
2010-09-28 22:25:23 +02:00
|
|
|
/* try with 'dflt'; MS site has had typos and many fonts use it now :(.
|
|
|
|
* including many versions of DejaVu Sans Mono! */
|
2009-11-05 01:45:39 +01:00
|
|
|
if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
|
2012-06-06 02:35:40 +02:00
|
|
|
return false;
|
2009-12-20 20:58:26 +01:00
|
|
|
|
2013-01-17 05:07:50 +01:00
|
|
|
/* try with 'latn'; some old fonts put their features there even though
|
|
|
|
they're really trying to support Thai, for example :( */
|
|
|
|
if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index))
|
|
|
|
return false;
|
|
|
|
|
2009-12-20 20:58:26 +01:00
|
|
|
if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
|
2012-06-06 02:35:40 +02:00
|
|
|
return false;
|
2009-12-20 20:58:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
hb_bool_t
|
|
|
|
hb_ot_layout_table_choose_script (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
|
|
|
const hb_tag_t *script_tags,
|
2011-07-31 02:57:01 +02:00
|
|
|
unsigned int *script_index,
|
|
|
|
hb_tag_t *chosen_script)
|
2009-12-20 20:58:26 +01:00
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
|
|
|
|
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
2009-12-20 20:58:26 +01:00
|
|
|
|
|
|
|
while (*script_tags)
|
|
|
|
{
|
2011-07-31 02:57:01 +02:00
|
|
|
if (g.find_script_index (*script_tags, script_index)) {
|
|
|
|
if (chosen_script)
|
|
|
|
*chosen_script = *script_tags;
|
2012-06-06 02:35:40 +02:00
|
|
|
return true;
|
2011-07-31 02:57:01 +02:00
|
|
|
}
|
2009-12-20 20:58:26 +01:00
|
|
|
script_tags++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* try finding 'DFLT' */
|
2011-07-31 02:57:01 +02:00
|
|
|
if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) {
|
|
|
|
if (chosen_script)
|
|
|
|
*chosen_script = HB_OT_TAG_DEFAULT_SCRIPT;
|
2012-06-06 02:35:40 +02:00
|
|
|
return false;
|
2011-07-31 02:57:01 +02:00
|
|
|
}
|
2009-12-20 20:58:26 +01:00
|
|
|
|
|
|
|
/* try with 'dflt'; MS site has had typos and many fonts use it now :( */
|
2011-07-31 02:57:01 +02:00
|
|
|
if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) {
|
|
|
|
if (chosen_script)
|
|
|
|
*chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE;
|
2012-06-06 02:35:40 +02:00
|
|
|
return false;
|
2011-07-31 02:57:01 +02:00
|
|
|
}
|
2008-01-28 11:58:50 +01:00
|
|
|
|
2012-01-22 21:31:44 +01:00
|
|
|
/* try with 'latn'; some old fonts put their features there even though
|
|
|
|
they're really trying to support Thai, for example :( */
|
|
|
|
if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) {
|
|
|
|
if (chosen_script)
|
|
|
|
*chosen_script = HB_OT_TAG_LATIN_SCRIPT;
|
2012-06-06 02:35:40 +02:00
|
|
|
return false;
|
2012-01-22 21:31:44 +01:00
|
|
|
}
|
|
|
|
|
2008-01-28 11:58:50 +01:00
|
|
|
if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
|
2011-07-31 02:57:01 +02:00
|
|
|
if (chosen_script)
|
|
|
|
*chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
|
2012-06-06 02:35:40 +02:00
|
|
|
return false;
|
2008-01-28 11:58:50 +01:00
|
|
|
}
|
|
|
|
|
2009-11-04 22:36:14 +01:00
|
|
|
unsigned int
|
2009-08-08 01:46:30 +02:00
|
|
|
hb_ot_layout_table_get_feature_tags (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
2009-11-04 22:36:14 +01:00
|
|
|
unsigned int start_offset,
|
2009-08-08 01:46:30 +02:00
|
|
|
unsigned int *feature_count /* IN/OUT */,
|
|
|
|
hb_tag_t *feature_tags /* OUT */)
|
2008-02-19 03:14:23 +01:00
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
2008-02-19 03:14:23 +01:00
|
|
|
|
2009-11-04 22:36:14 +01:00
|
|
|
return g.get_feature_tags (start_offset, feature_count, feature_tags);
|
2008-02-19 03:14:23 +01:00
|
|
|
}
|
|
|
|
|
2015-07-23 12:52:11 +02:00
|
|
|
hb_bool_t
|
|
|
|
hb_ot_layout_table_find_feature (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
|
|
|
hb_tag_t feature_tag,
|
|
|
|
unsigned int *feature_index)
|
|
|
|
{
|
|
|
|
ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
|
|
|
|
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
|
|
|
|
|
|
|
unsigned int num_features = g.get_feature_count ();
|
|
|
|
for (unsigned int i = 0; i < num_features; i++)
|
|
|
|
{
|
|
|
|
if (feature_tag == g.get_feature_tag (i)) {
|
|
|
|
if (feature_index) *feature_index = i;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-02-19 03:14:23 +01:00
|
|
|
|
2009-11-04 22:36:14 +01:00
|
|
|
unsigned int
|
2009-08-08 01:46:30 +02:00
|
|
|
hb_ot_layout_script_get_language_tags (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
|
|
|
unsigned int script_index,
|
2009-11-04 22:36:14 +01:00
|
|
|
unsigned int start_offset,
|
2009-08-08 01:46:30 +02:00
|
|
|
unsigned int *language_count /* IN/OUT */,
|
|
|
|
hb_tag_t *language_tags /* OUT */)
|
2008-01-28 11:58:50 +01:00
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
|
2008-01-28 11:58:50 +01:00
|
|
|
|
2009-11-04 22:36:14 +01:00
|
|
|
return s.get_lang_sys_tags (start_offset, language_count, language_tags);
|
2008-01-28 11:58:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
hb_bool_t
|
2009-08-02 23:41:36 +02:00
|
|
|
hb_ot_layout_script_find_language (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
|
|
|
unsigned int script_index,
|
|
|
|
hb_tag_t language_tag,
|
|
|
|
unsigned int *language_index)
|
2008-01-28 11:58:50 +01:00
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
|
|
|
|
const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
|
2008-01-28 11:58:50 +01:00
|
|
|
|
2008-01-28 13:40:10 +01:00
|
|
|
if (s.find_lang_sys_index (language_tag, language_index))
|
2012-06-06 02:35:40 +02:00
|
|
|
return true;
|
2008-01-28 11:58:50 +01:00
|
|
|
|
|
|
|
/* try with 'dflt'; MS site has had typos and many fonts use it now :( */
|
2009-11-05 01:45:39 +01:00
|
|
|
if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
|
2012-06-06 02:35:40 +02:00
|
|
|
return false;
|
2008-01-28 11:58:50 +01:00
|
|
|
|
2008-01-28 13:40:10 +01:00
|
|
|
if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
|
2012-06-06 02:35:40 +02:00
|
|
|
return false;
|
2008-01-28 13:40:10 +01:00
|
|
|
}
|
2008-01-28 11:58:50 +01:00
|
|
|
|
2014-06-24 18:20:36 +02:00
|
|
|
hb_bool_t
|
|
|
|
hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
|
|
|
unsigned int script_index,
|
|
|
|
unsigned int language_index,
|
|
|
|
unsigned int *feature_index)
|
|
|
|
{
|
|
|
|
return hb_ot_layout_language_get_required_feature (face,
|
|
|
|
table_tag,
|
|
|
|
script_index,
|
|
|
|
language_index,
|
|
|
|
feature_index,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2015-06-01 13:22:01 +02:00
|
|
|
/**
|
|
|
|
* Since: 0.9.30
|
|
|
|
**/
|
2008-01-28 13:40:10 +01:00
|
|
|
hb_bool_t
|
2014-04-27 15:05:24 +02:00
|
|
|
hb_ot_layout_language_get_required_feature (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
|
|
|
unsigned int script_index,
|
|
|
|
unsigned int language_index,
|
|
|
|
unsigned int *feature_index,
|
|
|
|
hb_tag_t *feature_tag)
|
2008-01-28 13:40:10 +01:00
|
|
|
{
|
2014-04-27 15:05:24 +02:00
|
|
|
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
|
|
|
const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
|
2008-01-28 11:58:50 +01:00
|
|
|
|
2014-04-27 15:05:24 +02:00
|
|
|
unsigned int index = l.get_required_feature_index ();
|
|
|
|
if (feature_index) *feature_index = index;
|
|
|
|
if (feature_tag) *feature_tag = g.get_feature_tag (index);
|
2008-01-28 11:58:50 +01:00
|
|
|
|
2008-01-28 13:40:10 +01:00
|
|
|
return l.has_required_feature ();
|
|
|
|
}
|
2008-01-28 11:58:50 +01:00
|
|
|
|
2009-11-04 22:36:14 +01:00
|
|
|
unsigned int
|
2009-08-08 01:46:30 +02:00
|
|
|
hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
|
|
|
unsigned int script_index,
|
|
|
|
unsigned int language_index,
|
2009-11-04 22:36:14 +01:00
|
|
|
unsigned int start_offset,
|
2009-08-08 01:46:30 +02:00
|
|
|
unsigned int *feature_count /* IN/OUT */,
|
|
|
|
unsigned int *feature_indexes /* OUT */)
|
2009-08-02 23:41:36 +02:00
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
|
|
|
const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
|
2008-01-28 13:40:10 +01:00
|
|
|
|
2009-11-04 22:36:14 +01:00
|
|
|
return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
|
2008-02-19 03:14:23 +01:00
|
|
|
}
|
|
|
|
|
2009-11-04 22:36:14 +01:00
|
|
|
unsigned int
|
2009-08-08 01:46:30 +02:00
|
|
|
hb_ot_layout_language_get_feature_tags (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
|
|
|
unsigned int script_index,
|
|
|
|
unsigned int language_index,
|
2009-11-04 22:36:14 +01:00
|
|
|
unsigned int start_offset,
|
2009-08-08 01:46:30 +02:00
|
|
|
unsigned int *feature_count /* IN/OUT */,
|
|
|
|
hb_tag_t *feature_tags /* OUT */)
|
2009-08-02 23:41:36 +02:00
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
|
|
|
const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
|
2008-01-28 13:40:10 +01:00
|
|
|
|
2009-08-08 01:46:30 +02:00
|
|
|
ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
|
2009-11-04 22:36:14 +01:00
|
|
|
unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
|
2009-08-08 01:46:30 +02:00
|
|
|
|
2009-08-27 07:32:17 +02:00
|
|
|
if (feature_tags) {
|
|
|
|
unsigned int count = *feature_count;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
|
feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
|
|
|
|
}
|
2009-08-08 01:46:30 +02:00
|
|
|
|
|
|
|
return ret;
|
2008-01-28 13:40:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
hb_bool_t
|
2009-08-02 23:41:36 +02:00
|
|
|
hb_ot_layout_language_find_feature (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
|
|
|
unsigned int script_index,
|
|
|
|
unsigned int language_index,
|
|
|
|
hb_tag_t feature_tag,
|
|
|
|
unsigned int *feature_index)
|
2008-01-28 13:40:10 +01:00
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
|
|
|
|
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
|
|
|
const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
|
2008-01-28 13:40:10 +01:00
|
|
|
|
2009-05-17 10:59:56 +02:00
|
|
|
unsigned int num_features = l.get_feature_count ();
|
|
|
|
for (unsigned int i = 0; i < num_features; i++) {
|
2008-01-28 13:40:10 +01:00
|
|
|
unsigned int f_index = l.get_feature_index (i);
|
|
|
|
|
|
|
|
if (feature_tag == g.get_feature_tag (f_index)) {
|
|
|
|
if (feature_index) *feature_index = f_index;
|
2012-06-06 02:35:40 +02:00
|
|
|
return true;
|
2008-01-28 13:40:10 +01:00
|
|
|
}
|
|
|
|
}
|
2008-01-28 11:58:50 +01:00
|
|
|
|
2008-01-28 13:40:10 +01:00
|
|
|
if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
|
2012-06-06 02:35:40 +02:00
|
|
|
return false;
|
2008-01-28 11:58:50 +01:00
|
|
|
}
|
2008-02-19 03:14:23 +01:00
|
|
|
|
2015-06-01 13:22:01 +02:00
|
|
|
/**
|
|
|
|
* Since: 0.9.7
|
|
|
|
**/
|
2009-11-04 22:36:14 +01:00
|
|
|
unsigned int
|
2012-11-16 03:39:46 +01:00
|
|
|
hb_ot_layout_feature_get_lookups (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
|
|
|
unsigned int feature_index,
|
|
|
|
unsigned int start_offset,
|
|
|
|
unsigned int *lookup_count /* IN/OUT */,
|
|
|
|
unsigned int *lookup_indexes /* OUT */)
|
2008-02-19 03:14:23 +01:00
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
|
|
|
const OT::Feature &f = g.get_feature (feature_index);
|
2008-02-19 03:14:23 +01:00
|
|
|
|
2009-11-04 22:36:14 +01:00
|
|
|
return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
|
2008-02-19 03:14:23 +01:00
|
|
|
}
|
|
|
|
|
2015-06-01 13:22:01 +02:00
|
|
|
/**
|
|
|
|
* Since: 0.9.22
|
|
|
|
**/
|
2013-10-03 20:54:50 +02:00
|
|
|
unsigned int
|
|
|
|
hb_ot_layout_table_get_lookup_count (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag)
|
|
|
|
{
|
|
|
|
switch (table_tag)
|
|
|
|
{
|
|
|
|
case HB_OT_TAG_GSUB:
|
|
|
|
{
|
|
|
|
return hb_ot_layout_from_face (face)->gsub_lookup_count;
|
|
|
|
}
|
|
|
|
case HB_OT_TAG_GPOS:
|
|
|
|
{
|
|
|
|
return hb_ot_layout_from_face (face)->gpos_lookup_count;
|
|
|
|
}
|
|
|
|
}
|
2013-10-14 13:06:36 +02:00
|
|
|
return 0;
|
2013-10-03 20:54:50 +02:00
|
|
|
}
|
|
|
|
|
2012-11-24 08:31:02 +01:00
|
|
|
static void
|
|
|
|
_hb_ot_layout_collect_lookups_lookups (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
|
|
|
unsigned int feature_index,
|
|
|
|
hb_set_t *lookup_indexes /* OUT */)
|
|
|
|
{
|
|
|
|
unsigned int lookup_indices[32];
|
|
|
|
unsigned int offset, len;
|
|
|
|
|
|
|
|
offset = 0;
|
|
|
|
do {
|
|
|
|
len = ARRAY_LENGTH (lookup_indices);
|
|
|
|
hb_ot_layout_feature_get_lookups (face,
|
|
|
|
table_tag,
|
|
|
|
feature_index,
|
|
|
|
offset, &len,
|
|
|
|
lookup_indices);
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < len; i++)
|
|
|
|
lookup_indexes->add (lookup_indices[i]);
|
|
|
|
|
|
|
|
offset += len;
|
|
|
|
} while (len == ARRAY_LENGTH (lookup_indices));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_hb_ot_layout_collect_lookups_features (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
|
|
|
unsigned int script_index,
|
|
|
|
unsigned int language_index,
|
|
|
|
const hb_tag_t *features,
|
|
|
|
hb_set_t *lookup_indexes /* OUT */)
|
|
|
|
{
|
|
|
|
if (!features)
|
|
|
|
{
|
2013-06-27 02:14:18 +02:00
|
|
|
unsigned int required_feature_index;
|
2014-04-27 15:05:24 +02:00
|
|
|
if (hb_ot_layout_language_get_required_feature (face,
|
|
|
|
table_tag,
|
|
|
|
script_index,
|
|
|
|
language_index,
|
|
|
|
&required_feature_index,
|
|
|
|
NULL))
|
2013-06-27 02:14:18 +02:00
|
|
|
_hb_ot_layout_collect_lookups_lookups (face,
|
|
|
|
table_tag,
|
|
|
|
required_feature_index,
|
|
|
|
lookup_indexes);
|
|
|
|
|
2012-11-24 08:31:02 +01:00
|
|
|
/* All features */
|
2013-01-03 07:04:40 +01:00
|
|
|
unsigned int feature_indices[32];
|
|
|
|
unsigned int offset, len;
|
|
|
|
|
|
|
|
offset = 0;
|
|
|
|
do {
|
|
|
|
len = ARRAY_LENGTH (feature_indices);
|
|
|
|
hb_ot_layout_language_get_feature_indexes (face,
|
|
|
|
table_tag,
|
|
|
|
script_index,
|
|
|
|
language_index,
|
|
|
|
offset, &len,
|
|
|
|
feature_indices);
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < len; i++)
|
|
|
|
_hb_ot_layout_collect_lookups_lookups (face,
|
|
|
|
table_tag,
|
|
|
|
feature_indices[i],
|
|
|
|
lookup_indexes);
|
|
|
|
|
|
|
|
offset += len;
|
|
|
|
} while (len == ARRAY_LENGTH (feature_indices));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-24 08:31:02 +01:00
|
|
|
for (; *features; features++)
|
|
|
|
{
|
|
|
|
unsigned int feature_index;
|
2013-01-03 07:00:23 +01:00
|
|
|
if (hb_ot_layout_language_find_feature (face,
|
|
|
|
table_tag,
|
|
|
|
script_index,
|
|
|
|
language_index,
|
|
|
|
*features,
|
|
|
|
&feature_index))
|
|
|
|
_hb_ot_layout_collect_lookups_lookups (face,
|
|
|
|
table_tag,
|
|
|
|
feature_index,
|
|
|
|
lookup_indexes);
|
2012-11-24 08:31:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_hb_ot_layout_collect_lookups_languages (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
|
|
|
unsigned int script_index,
|
|
|
|
const hb_tag_t *languages,
|
|
|
|
const hb_tag_t *features,
|
|
|
|
hb_set_t *lookup_indexes /* OUT */)
|
|
|
|
{
|
2013-01-03 07:07:16 +01:00
|
|
|
_hb_ot_layout_collect_lookups_features (face,
|
|
|
|
table_tag,
|
|
|
|
script_index,
|
|
|
|
HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
|
|
|
|
features,
|
|
|
|
lookup_indexes);
|
|
|
|
|
2012-11-24 08:31:02 +01:00
|
|
|
if (!languages)
|
|
|
|
{
|
|
|
|
/* All languages */
|
2013-01-03 07:00:23 +01:00
|
|
|
unsigned int count = hb_ot_layout_script_get_language_tags (face,
|
|
|
|
table_tag,
|
|
|
|
script_index,
|
|
|
|
0, NULL, NULL);
|
2012-11-24 08:31:02 +01:00
|
|
|
for (unsigned int language_index = 0; language_index < count; language_index++)
|
2013-01-03 07:00:23 +01:00
|
|
|
_hb_ot_layout_collect_lookups_features (face,
|
|
|
|
table_tag,
|
|
|
|
script_index,
|
|
|
|
language_index,
|
|
|
|
features,
|
|
|
|
lookup_indexes);
|
2013-01-03 07:04:40 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-24 08:31:02 +01:00
|
|
|
for (; *languages; languages++)
|
|
|
|
{
|
|
|
|
unsigned int language_index;
|
2013-01-03 07:00:23 +01:00
|
|
|
if (hb_ot_layout_script_find_language (face,
|
|
|
|
table_tag,
|
|
|
|
script_index,
|
|
|
|
*languages,
|
|
|
|
&language_index))
|
|
|
|
_hb_ot_layout_collect_lookups_features (face,
|
|
|
|
table_tag,
|
|
|
|
script_index,
|
|
|
|
language_index,
|
|
|
|
features,
|
|
|
|
lookup_indexes);
|
2012-11-24 08:31:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-01 13:22:01 +02:00
|
|
|
/**
|
|
|
|
* Since: 0.9.8
|
|
|
|
**/
|
2012-11-24 08:31:02 +01:00
|
|
|
void
|
|
|
|
hb_ot_layout_collect_lookups (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
|
|
|
const hb_tag_t *scripts,
|
|
|
|
const hb_tag_t *languages,
|
|
|
|
const hb_tag_t *features,
|
|
|
|
hb_set_t *lookup_indexes /* OUT */)
|
|
|
|
{
|
|
|
|
if (!scripts)
|
|
|
|
{
|
|
|
|
/* All scripts */
|
2013-01-03 07:00:23 +01:00
|
|
|
unsigned int count = hb_ot_layout_table_get_script_tags (face,
|
|
|
|
table_tag,
|
|
|
|
0, NULL, NULL);
|
2012-11-24 08:31:02 +01:00
|
|
|
for (unsigned int script_index = 0; script_index < count; script_index++)
|
2013-01-03 07:00:23 +01:00
|
|
|
_hb_ot_layout_collect_lookups_languages (face,
|
|
|
|
table_tag,
|
|
|
|
script_index,
|
|
|
|
languages,
|
|
|
|
features,
|
|
|
|
lookup_indexes);
|
2013-01-03 07:04:40 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-24 08:31:02 +01:00
|
|
|
for (; *scripts; scripts++)
|
|
|
|
{
|
|
|
|
unsigned int script_index;
|
2013-01-03 07:00:23 +01:00
|
|
|
if (hb_ot_layout_table_find_script (face,
|
|
|
|
table_tag,
|
|
|
|
*scripts,
|
|
|
|
&script_index))
|
|
|
|
_hb_ot_layout_collect_lookups_languages (face,
|
|
|
|
table_tag,
|
|
|
|
script_index,
|
|
|
|
languages,
|
|
|
|
features,
|
|
|
|
lookup_indexes);
|
2012-11-24 08:31:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-01 13:22:01 +02:00
|
|
|
/**
|
|
|
|
* Since: 0.9.7
|
|
|
|
**/
|
2012-11-17 04:07:06 +01:00
|
|
|
void
|
|
|
|
hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
|
|
|
|
hb_tag_t table_tag,
|
|
|
|
unsigned int lookup_index,
|
|
|
|
hb_set_t *glyphs_before, /* OUT. May be NULL */
|
|
|
|
hb_set_t *glyphs_input, /* OUT. May be NULL */
|
|
|
|
hb_set_t *glyphs_after, /* OUT. May be NULL */
|
|
|
|
hb_set_t *glyphs_output /* OUT. May be NULL */)
|
|
|
|
{
|
|
|
|
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
|
|
|
|
|
2013-01-03 07:00:23 +01:00
|
|
|
OT::hb_collect_glyphs_context_t c (face,
|
|
|
|
glyphs_before,
|
|
|
|
glyphs_input,
|
|
|
|
glyphs_after,
|
|
|
|
glyphs_output);
|
2012-11-17 04:07:06 +01:00
|
|
|
|
2013-01-03 07:04:40 +01:00
|
|
|
switch (table_tag)
|
|
|
|
{
|
2012-11-17 04:07:06 +01:00
|
|
|
case HB_OT_TAG_GSUB:
|
|
|
|
{
|
2012-11-24 07:38:41 +01:00
|
|
|
const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
|
2013-05-03 23:33:16 +02:00
|
|
|
l.collect_glyphs (&c);
|
2012-11-17 04:07:06 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
case HB_OT_TAG_GPOS:
|
|
|
|
{
|
2012-11-24 07:38:41 +01:00
|
|
|
const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
|
2013-05-03 23:33:16 +02:00
|
|
|
l.collect_glyphs (&c);
|
2012-11-17 04:07:06 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-16 01:50:16 +02:00
|
|
|
|
|
|
|
/*
|
2012-08-28 23:57:49 +02:00
|
|
|
* OT::GSUB
|
2009-04-16 01:50:16 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
hb_bool_t
|
2009-08-02 23:41:36 +02:00
|
|
|
hb_ot_layout_has_substitution (hb_face_t *face)
|
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
return &_get_gsub (face) != &OT::Null(OT::GSUB);
|
2009-08-02 23:41:36 +02:00
|
|
|
}
|
|
|
|
|
2015-06-01 13:22:01 +02:00
|
|
|
/**
|
|
|
|
* Since: 0.9.7
|
|
|
|
**/
|
2012-07-19 20:35:23 +02:00
|
|
|
hb_bool_t
|
2012-11-15 23:57:31 +01:00
|
|
|
hb_ot_layout_lookup_would_substitute (hb_face_t *face,
|
2012-08-23 22:22:28 +02:00
|
|
|
unsigned int lookup_index,
|
2012-07-19 20:35:23 +02:00
|
|
|
const hb_codepoint_t *glyphs,
|
|
|
|
unsigned int glyphs_length,
|
2012-08-23 22:22:28 +02:00
|
|
|
hb_bool_t zero_context)
|
2012-07-19 20:35:23 +02:00
|
|
|
{
|
2012-08-02 10:00:31 +02:00
|
|
|
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
|
2012-11-15 23:57:31 +01:00
|
|
|
return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
|
2012-07-19 20:35:23 +02:00
|
|
|
}
|
|
|
|
|
2012-07-30 08:38:39 +02:00
|
|
|
hb_bool_t
|
2012-11-15 23:57:31 +01:00
|
|
|
hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face,
|
2012-08-23 22:22:28 +02:00
|
|
|
unsigned int lookup_index,
|
2012-07-30 08:38:39 +02:00
|
|
|
const hb_codepoint_t *glyphs,
|
|
|
|
unsigned int glyphs_length,
|
2012-08-23 22:22:28 +02:00
|
|
|
hb_bool_t zero_context)
|
2012-07-30 08:38:39 +02:00
|
|
|
{
|
2012-08-02 10:00:31 +02:00
|
|
|
if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
|
2015-11-27 01:22:22 +01:00
|
|
|
OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context);
|
2012-09-04 21:15:19 +02:00
|
|
|
|
|
|
|
const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
|
|
|
|
|
2015-01-29 05:55:42 +01:00
|
|
|
return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index]);
|
2012-07-30 08:38:39 +02:00
|
|
|
}
|
|
|
|
|
2011-05-12 04:33:13 +02:00
|
|
|
void
|
2012-08-02 14:36:40 +02:00
|
|
|
hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
|
2011-05-12 04:33:13 +02:00
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
OT::GSUB::substitute_start (font, buffer);
|
2011-05-12 04:33:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-08-02 14:36:40 +02:00
|
|
|
hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
|
2011-05-12 04:33:13 +02:00
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
OT::GSUB::substitute_finish (font, buffer);
|
2011-05-12 04:33:13 +02:00
|
|
|
}
|
|
|
|
|
2015-06-01 13:22:01 +02:00
|
|
|
/**
|
|
|
|
* Since: 0.9.7
|
|
|
|
**/
|
2012-04-24 05:03:12 +02:00
|
|
|
void
|
2012-11-15 23:57:31 +01:00
|
|
|
hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
|
2012-08-23 22:22:28 +02:00
|
|
|
unsigned int lookup_index,
|
|
|
|
hb_set_t *glyphs)
|
2012-04-23 19:04:38 +02:00
|
|
|
{
|
2012-11-23 23:55:40 +01:00
|
|
|
OT::hb_closure_context_t c (face, glyphs);
|
|
|
|
|
|
|
|
const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index);
|
|
|
|
|
|
|
|
l.closure (&c);
|
2012-04-23 19:04:38 +02:00
|
|
|
}
|
2009-08-08 01:46:30 +02:00
|
|
|
|
2009-05-18 23:43:49 +02:00
|
|
|
/*
|
2012-08-28 23:57:49 +02:00
|
|
|
* OT::GPOS
|
2009-05-18 23:43:49 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
hb_bool_t
|
2009-08-02 23:41:36 +02:00
|
|
|
hb_ot_layout_has_positioning (hb_face_t *face)
|
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
return &_get_gpos (face) != &OT::Null(OT::GPOS);
|
2009-08-02 23:41:36 +02:00
|
|
|
}
|
|
|
|
|
2011-04-16 00:59:56 +02:00
|
|
|
void
|
2012-07-31 01:30:01 +02:00
|
|
|
hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
|
2011-04-16 00:59:56 +02:00
|
|
|
{
|
2012-08-28 23:57:49 +02:00
|
|
|
OT::GPOS::position_start (font, buffer);
|
2011-04-16 00:59:56 +02:00
|
|
|
}
|
|
|
|
|
2009-11-06 22:47:31 +01:00
|
|
|
void
|
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 15:44:57 +01:00
|
|
|
hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
|
2009-11-06 22:47:31 +01:00
|
|
|
{
|
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 15:44:57 +01:00
|
|
|
OT::GPOS::position_finish (font, buffer);
|
2009-11-06 22:47:31 +01:00
|
|
|
}
|
2012-11-26 13:02:31 +01:00
|
|
|
|
2015-06-01 13:22:01 +02:00
|
|
|
/**
|
2015-09-03 13:23:22 +02:00
|
|
|
* Since: 0.9.10
|
2015-06-01 13:22:01 +02:00
|
|
|
**/
|
2012-11-26 13:02:31 +01:00
|
|
|
hb_bool_t
|
2012-12-11 20:17:01 +01:00
|
|
|
hb_ot_layout_get_size_params (hb_face_t *face,
|
|
|
|
unsigned int *design_size, /* OUT. May be NULL */
|
|
|
|
unsigned int *subfamily_id, /* OUT. May be NULL */
|
|
|
|
unsigned int *subfamily_name_id, /* OUT. May be NULL */
|
|
|
|
unsigned int *range_start, /* OUT. May be NULL */
|
|
|
|
unsigned int *range_end /* OUT. May be NULL */)
|
2012-11-26 13:02:31 +01:00
|
|
|
{
|
|
|
|
const OT::GPOS &gpos = _get_gpos (face);
|
2012-12-18 05:21:05 +01:00
|
|
|
const hb_tag_t tag = HB_TAG ('s','i','z','e');
|
2012-11-26 13:02:31 +01:00
|
|
|
|
2012-11-30 07:14:20 +01:00
|
|
|
unsigned int num_features = gpos.get_feature_count ();
|
|
|
|
for (unsigned int i = 0; i < num_features; i++)
|
|
|
|
{
|
2012-12-18 05:21:05 +01:00
|
|
|
if (tag == gpos.get_feature_tag (i))
|
2012-11-26 13:02:31 +01:00
|
|
|
{
|
2012-11-30 07:14:20 +01:00
|
|
|
const OT::Feature &f = gpos.get_feature (i);
|
2012-12-18 05:21:05 +01:00
|
|
|
const OT::FeatureParamsSize ¶ms = f.get_feature_params ().get_size_params (tag);
|
2012-11-26 13:02:31 +01:00
|
|
|
|
2012-12-18 05:21:05 +01:00
|
|
|
if (params.designSize)
|
2012-12-12 17:38:49 +01:00
|
|
|
{
|
2012-12-18 05:21:05 +01:00
|
|
|
#define PARAM(a, A) if (a) *a = params.A
|
2012-12-12 17:38:49 +01:00
|
|
|
PARAM (design_size, designSize);
|
|
|
|
PARAM (subfamily_id, subfamilyID);
|
|
|
|
PARAM (subfamily_name_id, subfamilyNameID);
|
|
|
|
PARAM (range_start, rangeStart);
|
|
|
|
PARAM (range_end, rangeEnd);
|
|
|
|
#undef PARAM
|
2012-12-18 05:21:05 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2012-11-26 13:02:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-11 20:17:01 +01:00
|
|
|
#define PARAM(a, A) if (a) *a = 0
|
2012-12-18 05:21:05 +01:00
|
|
|
PARAM (design_size, designSize);
|
|
|
|
PARAM (subfamily_id, subfamilyID);
|
|
|
|
PARAM (subfamily_name_id, subfamilyNameID);
|
|
|
|
PARAM (range_start, rangeStart);
|
|
|
|
PARAM (range_end, rangeEnd);
|
2012-12-11 20:17:01 +01:00
|
|
|
#undef PARAM
|
2012-11-26 13:02:31 +01:00
|
|
|
|
2012-12-18 05:21:05 +01:00
|
|
|
return false;
|
2012-11-26 13:02:31 +01:00
|
|
|
}
|
2013-05-03 00:18:24 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
2013-05-03 00:52:24 +02:00
|
|
|
* Parts of different types are implemented here such that they have direct
|
2013-05-03 00:18:24 +02:00
|
|
|
* access to GSUB/GPOS lookups.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2013-05-03 00:52:24 +02:00
|
|
|
struct GSUBProxy
|
|
|
|
{
|
|
|
|
static const unsigned int table_index = 0;
|
2013-10-28 19:26:02 +01:00
|
|
|
static const bool inplace = false;
|
2013-05-03 00:52:24 +02:00
|
|
|
typedef OT::SubstLookup Lookup;
|
|
|
|
|
|
|
|
GSUBProxy (hb_face_t *face) :
|
|
|
|
table (*hb_ot_layout_from_face (face)->gsub),
|
|
|
|
accels (hb_ot_layout_from_face (face)->gsub_accels) {}
|
|
|
|
|
|
|
|
const OT::GSUB &table;
|
|
|
|
const hb_ot_layout_lookup_accelerator_t *accels;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct GPOSProxy
|
|
|
|
{
|
|
|
|
static const unsigned int table_index = 1;
|
2013-10-28 19:26:02 +01:00
|
|
|
static const bool inplace = true;
|
2013-05-03 00:52:24 +02:00
|
|
|
typedef OT::PosLookup Lookup;
|
|
|
|
|
|
|
|
GPOSProxy (hb_face_t *face) :
|
|
|
|
table (*hb_ot_layout_from_face (face)->gpos),
|
|
|
|
accels (hb_ot_layout_from_face (face)->gpos_accels) {}
|
|
|
|
|
|
|
|
const OT::GPOS &table;
|
|
|
|
const hb_ot_layout_lookup_accelerator_t *accels;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-02-19 15:15:05 +01:00
|
|
|
template <typename Obj>
|
|
|
|
static inline bool
|
|
|
|
apply_forward (OT::hb_apply_context_t *c,
|
|
|
|
const Obj &obj,
|
|
|
|
const hb_ot_layout_lookup_accelerator_t &accel)
|
|
|
|
{
|
|
|
|
bool ret = false;
|
|
|
|
hb_buffer_t *buffer = c->buffer;
|
2015-11-19 02:52:08 +01:00
|
|
|
while (buffer->idx < buffer->len && !buffer->in_error)
|
2015-02-19 15:15:05 +01:00
|
|
|
{
|
|
|
|
if (accel.may_have (buffer->cur().codepoint) &&
|
|
|
|
(buffer->cur().mask & c->lookup_mask) &&
|
2015-02-21 09:45:22 +01:00
|
|
|
c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
|
2015-02-19 15:15:05 +01:00
|
|
|
obj.apply (c))
|
|
|
|
ret = true;
|
|
|
|
else
|
|
|
|
buffer->next_glyph ();
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Obj>
|
|
|
|
static inline bool
|
|
|
|
apply_backward (OT::hb_apply_context_t *c,
|
|
|
|
const Obj &obj,
|
|
|
|
const hb_ot_layout_lookup_accelerator_t &accel)
|
|
|
|
{
|
|
|
|
bool ret = false;
|
|
|
|
hb_buffer_t *buffer = c->buffer;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (accel.may_have (buffer->cur().codepoint) &&
|
|
|
|
(buffer->cur().mask & c->lookup_mask) &&
|
2015-02-21 09:45:22 +01:00
|
|
|
c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
|
2015-02-19 15:15:05 +01:00
|
|
|
obj.apply (c))
|
|
|
|
ret = true;
|
|
|
|
/* The reverse lookup doesn't "advance" cursor (for good reason). */
|
|
|
|
buffer->idx--;
|
|
|
|
|
|
|
|
}
|
|
|
|
while ((int) buffer->idx >= 0);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-10-09 18:20:58 +02:00
|
|
|
struct hb_apply_forward_context_t :
|
|
|
|
OT::hb_dispatch_context_t<hb_apply_forward_context_t, bool, HB_DEBUG_APPLY>
|
2015-02-19 15:30:05 +01:00
|
|
|
{
|
2015-07-23 11:11:35 +02:00
|
|
|
inline const char *get_name (void) { return "APPLY_FWD"; }
|
2015-02-19 15:30:05 +01:00
|
|
|
template <typename T>
|
|
|
|
inline return_t dispatch (const T &obj) { return apply_forward (c, obj, accel); }
|
|
|
|
static return_t default_return_value (void) { return false; }
|
|
|
|
bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return true; }
|
|
|
|
|
|
|
|
hb_apply_forward_context_t (OT::hb_apply_context_t *c_,
|
|
|
|
const hb_ot_layout_lookup_accelerator_t &accel_) :
|
|
|
|
c (c_),
|
|
|
|
accel (accel_),
|
|
|
|
debug_depth (0) {}
|
|
|
|
|
|
|
|
OT::hb_apply_context_t *c;
|
|
|
|
const hb_ot_layout_lookup_accelerator_t &accel;
|
|
|
|
unsigned int debug_depth;
|
|
|
|
};
|
|
|
|
|
2013-05-03 23:49:44 +02:00
|
|
|
template <typename Proxy>
|
2015-02-19 09:33:30 +01:00
|
|
|
static inline void
|
2013-05-03 23:49:44 +02:00
|
|
|
apply_string (OT::hb_apply_context_t *c,
|
|
|
|
const typename Proxy::Lookup &lookup,
|
|
|
|
const hb_ot_layout_lookup_accelerator_t &accel)
|
|
|
|
{
|
2013-10-18 19:33:09 +02:00
|
|
|
hb_buffer_t *buffer = c->buffer;
|
2013-05-03 23:49:44 +02:00
|
|
|
|
2015-11-07 01:18:09 +01:00
|
|
|
if (unlikely (!buffer->len || !c->lookup_mask))
|
2015-02-19 09:33:30 +01:00
|
|
|
return;
|
2013-05-03 23:49:44 +02:00
|
|
|
|
2015-08-18 15:36:43 +02:00
|
|
|
c->set_lookup_props (lookup.get_props ());
|
2013-05-03 23:49:44 +02:00
|
|
|
|
|
|
|
if (likely (!lookup.is_reverse ()))
|
|
|
|
{
|
|
|
|
/* in/out forward substitution/positioning */
|
|
|
|
if (Proxy::table_index == 0)
|
2013-10-18 19:33:09 +02:00
|
|
|
buffer->clear_output ();
|
|
|
|
buffer->idx = 0;
|
2013-05-03 23:49:44 +02:00
|
|
|
|
2015-02-19 15:30:05 +01:00
|
|
|
bool ret;
|
|
|
|
if (lookup.get_subtable_count () == 1)
|
|
|
|
{
|
|
|
|
hb_apply_forward_context_t c_forward (c, accel);
|
|
|
|
ret = lookup.dispatch (&c_forward);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ret = apply_forward (c, lookup, accel);
|
|
|
|
if (ret)
|
2013-05-04 00:10:10 +02:00
|
|
|
{
|
2013-10-28 19:26:02 +01:00
|
|
|
if (!Proxy::inplace)
|
2013-10-18 19:33:09 +02:00
|
|
|
buffer->swap_buffers ();
|
2013-05-04 00:10:10 +02:00
|
|
|
else
|
2015-02-19 09:33:30 +01:00
|
|
|
assert (!buffer->has_separate_output ());
|
2013-05-04 00:10:10 +02:00
|
|
|
}
|
2013-05-03 23:49:44 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* in-place backward substitution/positioning */
|
|
|
|
if (Proxy::table_index == 0)
|
2013-10-18 19:33:09 +02:00
|
|
|
buffer->remove_output ();
|
|
|
|
buffer->idx = buffer->len - 1;
|
2013-05-03 23:49:44 +02:00
|
|
|
|
2015-02-19 15:15:05 +01:00
|
|
|
apply_backward (c, lookup, accel);
|
2013-05-03 23:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-03 00:52:24 +02:00
|
|
|
template <typename Proxy>
|
|
|
|
inline void hb_ot_map_t::apply (const Proxy &proxy,
|
2013-05-03 00:18:24 +02:00
|
|
|
const hb_ot_shape_plan_t *plan,
|
|
|
|
hb_font_t *font,
|
|
|
|
hb_buffer_t *buffer) const
|
|
|
|
{
|
2013-05-03 00:52:24 +02:00
|
|
|
const unsigned int table_index = proxy.table_index;
|
2013-05-03 00:18:24 +02:00
|
|
|
unsigned int i = 0;
|
2013-05-03 00:52:24 +02:00
|
|
|
OT::hb_apply_context_t c (table_index, font, buffer);
|
2013-05-03 23:49:44 +02:00
|
|
|
c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
|
2013-05-03 00:18:24 +02:00
|
|
|
|
|
|
|
for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) {
|
|
|
|
const stage_map_t *stage = &stages[table_index][stage_index];
|
|
|
|
for (; i < stage->last_lookup; i++)
|
2013-05-03 00:52:24 +02:00
|
|
|
{
|
2015-08-18 19:55:03 +02:00
|
|
|
#if 0
|
|
|
|
char buf[4096];
|
|
|
|
hb_buffer_serialize_glyphs (buffer, 0, buffer->len,
|
|
|
|
buf, sizeof (buf), NULL,
|
|
|
|
font,
|
|
|
|
HB_BUFFER_SERIALIZE_FORMAT_TEXT,
|
|
|
|
Proxy::table_index == 0 ?
|
|
|
|
HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS :
|
|
|
|
HB_BUFFER_SERIALIZE_FLAG_DEFAULT);
|
|
|
|
printf ("buf: [%s]\n", buf);
|
|
|
|
#endif
|
|
|
|
|
2013-05-03 00:52:24 +02:00
|
|
|
unsigned int lookup_index = lookups[table_index][i].index;
|
2015-08-18 15:36:43 +02:00
|
|
|
c.set_lookup_index (lookup_index);
|
2013-05-03 00:52:24 +02:00
|
|
|
c.set_lookup_mask (lookups[table_index][i].mask);
|
|
|
|
c.set_auto_zwj (lookups[table_index][i].auto_zwj);
|
2013-05-03 23:49:44 +02:00
|
|
|
apply_string<Proxy> (&c,
|
|
|
|
proxy.table.get_lookup (lookup_index),
|
|
|
|
proxy.accels[lookup_index]);
|
2013-05-03 00:52:24 +02:00
|
|
|
}
|
2013-05-03 00:18:24 +02:00
|
|
|
|
|
|
|
if (stage->pause_func)
|
|
|
|
{
|
|
|
|
buffer->clear_output ();
|
|
|
|
stage->pause_func (plan, font, buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
|
|
|
|
{
|
2013-05-03 00:52:24 +02:00
|
|
|
GSUBProxy proxy (font->face);
|
|
|
|
apply (proxy, plan, font, buffer);
|
2013-05-03 00:18:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
|
|
|
|
{
|
2013-05-03 00:52:24 +02:00
|
|
|
GPOSProxy proxy (font->face);
|
|
|
|
apply (proxy, plan, font, buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
HB_INTERNAL void
|
|
|
|
hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
|
|
|
|
const OT::SubstLookup &lookup,
|
|
|
|
const hb_ot_layout_lookup_accelerator_t &accel)
|
|
|
|
{
|
2013-05-03 23:49:44 +02:00
|
|
|
apply_string<GSUBProxy> (c, lookup, accel);
|
2013-05-03 00:18:24 +02:00
|
|
|
}
|