HarfBuzz: Update to version 4.0.0

This commit is contained in:
bruvzg 2022-03-02 10:48:37 +02:00
parent b7a852a05d
commit 9b0fbfa06d
No known key found for this signature in database
GPG Key ID: 7960FCF39844EC38
51 changed files with 2569 additions and 549 deletions

View File

@ -49,6 +49,7 @@ if env["builtin_harfbuzz"]:
"src/hb-aat-map.cc",
"src/hb-blob.cc",
"src/hb-buffer-serialize.cc",
"src/hb-buffer-verify.cc",
"src/hb-buffer.cc",
"src/hb-common.cc",
#'src/hb-coretext.cc',

View File

@ -206,7 +206,7 @@ Files extracted from upstream source:
## harfbuzz
- Upstream: https://github.com/harfbuzz/harfbuzz
- Version: 3.3.2 (ac46c3248e8b0316235943175c4d4a11c24dd4a9, 2022)
- Version: 4.0.0 (8d1b000a3edc90c12267b836b4ef3f81c0e53edc, 2022)
- License: MIT
Files extracted from upstream source:

View File

@ -498,7 +498,7 @@ struct hb_pair_t
template <typename Q1, typename Q2,
hb_enable_if (hb_is_convertible (T1, Q1) &&
hb_is_convertible (T2, T2))>
hb_is_convertible (T2, Q2))>
operator hb_pair_t<Q1, Q2> () { return hb_pair_t<Q1, Q2> (first, second); }
hb_pair_t<T1, T2> reverse () const

View File

@ -0,0 +1,422 @@
/*
* Copyright © 2022 Behdad Esfahbod
*
* This is part of HarfBuzz, a text shaping library.
*
* 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.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#ifndef HB_NO_BUFFER_VERIFY
#include "hb-buffer.hh"
#define BUFFER_VERIFY_ERROR "buffer verify error: "
static inline void
buffer_verify_error (hb_buffer_t *buffer,
hb_font_t *font,
const char *fmt,
...) HB_PRINTF_FUNC(3, 4);
static inline void
buffer_verify_error (hb_buffer_t *buffer,
hb_font_t *font,
const char *fmt,
...)
{
va_list ap;
va_start (ap, fmt);
if (buffer->messaging ())
{
buffer->message_impl (font, fmt, ap);
}
else
{
fprintf (stderr, "harfbuzz ");
vfprintf (stderr, fmt, ap);
fprintf (stderr, "\n");
}
va_end (ap);
}
static bool
buffer_verify_monotone (hb_buffer_t *buffer,
hb_font_t *font)
{
/* Check that clusters are monotone. */
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES ||
buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
{
bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
unsigned int num_glyphs;
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
for (unsigned int i = 1; i < num_glyphs; i++)
if (info[i-1].cluster != info[i].cluster &&
(info[i-1].cluster < info[i].cluster) != is_forward)
{
buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone.");
return false;
}
}
return true;
}
static bool
buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
hb_buffer_t *text_buffer,
hb_font_t *font,
const hb_feature_t *features,
unsigned int num_features,
const char * const *shapers)
{
if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
{
/* Cannot perform this check without monotone clusters. */
return true;
}
/* Check that breaking up shaping at safe-to-break is indeed safe. */
hb_buffer_t *fragment = hb_buffer_create_similar (buffer);
hb_buffer_set_flags (fragment, hb_buffer_get_flags (fragment) & ~HB_BUFFER_FLAG_VERIFY);
hb_buffer_t *reconstruction = hb_buffer_create_similar (buffer);
hb_buffer_set_flags (reconstruction, hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY);
unsigned int num_glyphs;
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
unsigned int num_chars;
hb_glyph_info_t *text = hb_buffer_get_glyph_infos (text_buffer, &num_chars);
/* Chop text and shape fragments. */
bool forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
unsigned int start = 0;
unsigned int text_start = forward ? 0 : num_chars;
unsigned int text_end = text_start;
for (unsigned int end = 1; end < num_glyphs + 1; end++)
{
if (end < num_glyphs &&
(info[end].cluster == info[end-1].cluster ||
info[end-(forward?0:1)].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK))
continue;
/* Shape segment corresponding to glyphs start..end. */
if (end == num_glyphs)
{
if (forward)
text_end = num_chars;
else
text_start = 0;
}
else
{
if (forward)
{
unsigned int cluster = info[end].cluster;
while (text_end < num_chars && text[text_end].cluster < cluster)
text_end++;
}
else
{
unsigned int cluster = info[end - 1].cluster;
while (text_start && text[text_start - 1].cluster >= cluster)
text_start--;
}
}
assert (text_start < text_end);
if (0)
printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end);
hb_buffer_clear_contents (fragment);
hb_buffer_flags_t flags = hb_buffer_get_flags (fragment);
if (0 < text_start)
flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT);
if (text_end < num_chars)
flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT);
hb_buffer_set_flags (fragment, flags);
hb_buffer_append (fragment, text_buffer, text_start, text_end);
if (!hb_shape_full (font, fragment, features, num_features, shapers))
{
buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
hb_buffer_destroy (reconstruction);
hb_buffer_destroy (fragment);
return false;
}
hb_buffer_append (reconstruction, fragment, 0, -1);
start = end;
if (forward)
text_start = text_end;
else
text_end = text_start;
}
bool ret = true;
hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
if (diff)
{
buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed.");
ret = false;
/* Return the reconstructed result instead so it can be inspected. */
hb_buffer_set_length (buffer, 0);
hb_buffer_append (buffer, reconstruction, 0, -1);
}
hb_buffer_destroy (reconstruction);
hb_buffer_destroy (fragment);
return ret;
}
static bool
buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
hb_buffer_t *text_buffer,
hb_font_t *font,
const hb_feature_t *features,
unsigned int num_features,
const char * const *shapers)
{
if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
{
/* Cannot perform this check without monotone clusters. */
return true;
}
/* Check that shuffling up text before shaping at safe-to-concat points
* is indeed safe. */
/* This is what we do:
*
* 1. We shape text once. Then segment the text at all the safe-to-concat
* points;
*
* 2. Then we create two buffers, one containing all the even segments and
* one all the odd segments.
*
* 3. Because all these segments were safe-to-concat at both ends, we
* expect that concatenating them and shaping should NOT change the
* shaping results of each segment. As such, we expect that after
* shaping the two buffers, we still get cluster boundaries at the
* segment boundaries, and that those all are safe-to-concat points.
* Moreover, that there are NOT any safe-to-concat points within the
* segments.
*
* 4. Finally, we reconstruct the shaping results of the original text by
* simply interleaving the shaping results of the segments from the two
* buffers, and assert that the total shaping results is the same as
* the one from original buffer in step 1.
*/
hb_buffer_t *fragments[2] {hb_buffer_create_similar (buffer),
hb_buffer_create_similar (buffer)};
hb_buffer_set_flags (fragments[0], hb_buffer_get_flags (fragments[0]) & ~HB_BUFFER_FLAG_VERIFY);
hb_buffer_set_flags (fragments[1], hb_buffer_get_flags (fragments[1]) & ~HB_BUFFER_FLAG_VERIFY);
hb_buffer_t *reconstruction = hb_buffer_create_similar (buffer);
hb_buffer_set_flags (reconstruction, hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY);
hb_segment_properties_t props;
hb_buffer_get_segment_properties (buffer, &props);
hb_buffer_set_segment_properties (fragments[0], &props);
hb_buffer_set_segment_properties (fragments[1], &props);
hb_buffer_set_segment_properties (reconstruction, &props);
unsigned num_glyphs;
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
unsigned num_chars;
hb_glyph_info_t *text = hb_buffer_get_glyph_infos (text_buffer, &num_chars);
bool forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
if (!forward)
hb_buffer_reverse (buffer);
/*
* Split text into segments and collect into to fragment streams.
*/
{
unsigned fragment_idx = 0;
unsigned start = 0;
unsigned text_start = 0;
unsigned text_end = 0;
for (unsigned end = 1; end < num_glyphs + 1; end++)
{
if (end < num_glyphs &&
(info[end].cluster == info[end-1].cluster ||
info[end].mask & HB_GLYPH_FLAG_UNSAFE_TO_CONCAT))
continue;
/* Accumulate segment corresponding to glyphs start..end. */
if (end == num_glyphs)
text_end = num_chars;
else
{
unsigned cluster = info[end].cluster;
while (text_end < num_chars && text[text_end].cluster < cluster)
text_end++;
}
assert (text_start < text_end);
if (0)
printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end);
#if 0
hb_buffer_flags_t flags = hb_buffer_get_flags (fragment);
if (0 < text_start)
flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT);
if (text_end < num_chars)
flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT);
hb_buffer_set_flags (fragment, flags);
#endif
hb_buffer_append (fragments[fragment_idx], text_buffer, text_start, text_end);
start = end;
text_start = text_end;
fragment_idx = 1 - fragment_idx;
}
}
bool ret = true;
hb_buffer_diff_flags_t diff;
/*
* Shape the two fragment streams.
*/
if (!hb_shape_full (font, fragments[0], features, num_features, shapers))
{
buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
ret = false;
goto out;
}
if (!hb_shape_full (font, fragments[1], features, num_features, shapers))
{
buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
ret = false;
goto out;
}
if (!forward)
{
hb_buffer_reverse (fragments[0]);
hb_buffer_reverse (fragments[1]);
}
/*
* Reconstruct results.
*/
{
unsigned fragment_idx = 0;
unsigned fragment_start[2] {0, 0};
unsigned fragment_num_glyphs[2];
hb_glyph_info_t *fragment_info[2];
for (unsigned i = 0; i < 2; i++)
fragment_info[i] = hb_buffer_get_glyph_infos (fragments[i], &fragment_num_glyphs[i]);
while (fragment_start[0] < fragment_num_glyphs[0] ||
fragment_start[1] < fragment_num_glyphs[1])
{
unsigned fragment_end = fragment_start[fragment_idx] + 1;
while (fragment_end < fragment_num_glyphs[fragment_idx] &&
(fragment_info[fragment_idx][fragment_end].cluster == fragment_info[fragment_idx][fragment_end - 1].cluster ||
fragment_info[fragment_idx][fragment_end].mask & HB_GLYPH_FLAG_UNSAFE_TO_CONCAT))
fragment_end++;
hb_buffer_append (reconstruction, fragments[fragment_idx], fragment_start[fragment_idx], fragment_end);
fragment_start[fragment_idx] = fragment_end;
fragment_idx = 1 - fragment_idx;
}
}
if (!forward)
{
hb_buffer_reverse (buffer);
hb_buffer_reverse (reconstruction);
}
/*
* Diff results.
*/
diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
if (diff)
{
buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed.");
ret = false;
/* Return the reconstructed result instead so it can be inspected. */
hb_buffer_set_length (buffer, 0);
hb_buffer_append (buffer, reconstruction, 0, -1);
}
out:
hb_buffer_destroy (reconstruction);
hb_buffer_destroy (fragments[0]);
hb_buffer_destroy (fragments[1]);
return ret;
}
bool
hb_buffer_t::verify (hb_buffer_t *text_buffer,
hb_font_t *font,
const hb_feature_t *features,
unsigned int num_features,
const char * const *shapers)
{
bool ret = true;
if (!buffer_verify_monotone (this, font))
ret = false;
if (!buffer_verify_unsafe_to_break (this, text_buffer, font, features, num_features, shapers))
ret = false;
if ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) != 0 &&
!buffer_verify_unsafe_to_concat (this, text_buffer, font, features, num_features, shapers))
ret = false;
if (!ret)
{
unsigned len = text_buffer->len;
hb_vector_t<char> bytes;
if (likely (bytes.resize (len * 10 + 16)))
{
hb_buffer_serialize_unicode (text_buffer,
0, len,
bytes.arrayZ, bytes.length,
&len,
HB_BUFFER_SERIALIZE_FORMAT_TEXT,
HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS);
buffer_verify_error (this, font, BUFFER_VERIFY_ERROR "text was: %s.", bytes.arrayZ);
}
}
return ret;
}
#endif

View File

@ -1789,7 +1789,7 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer,
**/
HB_EXTERN void
hb_buffer_append (hb_buffer_t *buffer,
hb_buffer_t *source,
const hb_buffer_t *source,
unsigned int start,
unsigned int end)
{

View File

@ -137,7 +137,11 @@ typedef struct hb_glyph_info_t {
* clusters.
* The #HB_GLYPH_FLAG_UNSAFE_TO_BREAK flag will
* always imply this flag.
* Since: 3.3.0
* To use this flag, you must enable the buffer flag
* @HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT during
* shaping, otherwise the buffer flag will not be
* reliably produced.
* Since: 4.0.0
* @HB_GLYPH_FLAG_DEFINED: All the currently defined flags.
*
* Flags for #hb_glyph_info_t.
@ -356,7 +360,19 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
* @HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE:
* flag indicating that a dotted circle should
* not be inserted in the rendering of incorrect
* character sequences (such at <0905 093E>). Since: 2.4
* character sequences (such at <0905 093E>). Since: 2.4.0
* @HB_BUFFER_FLAG_VERIFY:
* flag indicating that the hb_shape() call and its variants
* should perform various verification processes on the results
* of the shaping operation on the buffer. If the verification
* fails, then either a buffer message is sent, if a message
* handler is installed on the buffer, or a message is written
* to standard error. In either case, the shaping result might
* be modified to show the failed output. Since: 3.4.0
* @HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT:
* flag indicating that the @HB_GLYPH_FLAG_UNSAFE_TO_CONCAT
* glyph-flag should be produced by the shaper. By default
* it will not be produced since it incurs a cost. Since: 4.0.0
*
* Flags for #hb_buffer_t.
*
@ -368,7 +384,9 @@ typedef enum { /*< flags >*/
HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */
HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u,
HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u,
HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u
HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u,
HB_BUFFER_FLAG_VERIFY = 0x00000020u,
HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT = 0x00000040u
} hb_buffer_flags_t;
HB_EXTERN void
@ -522,7 +540,7 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer,
HB_EXTERN void
hb_buffer_append (hb_buffer_t *buffer,
hb_buffer_t *source,
const hb_buffer_t *source,
unsigned int start,
unsigned int end);

View File

@ -212,6 +212,20 @@ struct hb_buffer_t
HB_INTERNAL void enter ();
HB_INTERNAL void leave ();
#ifndef HB_NO_BUFFER_VERIFY
HB_INTERNAL
#endif
bool verify (hb_buffer_t *text_buffer,
hb_font_t *font,
const hb_feature_t *features,
unsigned int num_features,
const char * const *shapers)
#ifndef HB_NO_BUFFER_VERIFY
;
#else
{ return true; }
#endif
unsigned int backtrack_len () const { return have_output ? out_len : idx; }
unsigned int lookahead_len () const { return len - idx; }
uint8_t next_serial () { return ++serial ? serial : ++serial; }
@ -446,6 +460,8 @@ struct hb_buffer_t
}
void unsafe_to_concat (unsigned int start = 0, unsigned int end = -1)
{
if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
return;
_set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
start, end,
true);
@ -458,6 +474,8 @@ struct hb_buffer_t
}
void unsafe_to_concat_from_outbuffer (unsigned int start = 0, unsigned int end = -1)
{
if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
return;
_set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
start, end,
false, true);

View File

@ -130,6 +130,16 @@ typedef union _hb_var_int_t {
int8_t i8[4];
} hb_var_int_t;
typedef union _hb_var_num_t {
float f;
uint32_t u32;
int32_t i32;
uint16_t u16[2];
int16_t i16[2];
uint8_t u8[4];
int8_t i8[4];
} hb_var_num_t;
/* hb_tag_t */
@ -481,6 +491,7 @@ hb_language_get_default (void);
* @HB_SCRIPT_TANGSA: `Tnsa`, Since: 3.0.0
* @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0
* @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0
* @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0
* @HB_SCRIPT_INVALID: No script set
*
* Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
@ -697,6 +708,11 @@ typedef enum
HB_SCRIPT_TOTO = HB_TAG ('T','o','t','o'), /*14.0*/
HB_SCRIPT_VITHKUQI = HB_TAG ('V','i','t','h'), /*14.0*/
/*
* Since 3.4.0
*/
HB_SCRIPT_MATH = HB_TAG ('Z','m','t','h'),
/* No script set. */
HB_SCRIPT_INVALID = HB_TAG_NONE,

View File

@ -55,6 +55,7 @@
#define HB_NO_ATEXIT
#define HB_NO_BUFFER_MESSAGE
#define HB_NO_BUFFER_SERIALIZE
#define HB_NO_BUFFER_VERIFY
#define HB_NO_BITMAP
#define HB_NO_CFF
#define HB_NO_COLOR
@ -84,6 +85,7 @@
#ifdef HB_MINI
#define HB_NO_AAT
#define HB_NO_LEGACY
#define HB_NO_BORING_EXPANSION
#endif
#if defined(HAVE_CONFIG_OVERRIDE_H) || defined(HB_CONFIG_OVERRIDE_H)

View File

@ -25,237 +25,313 @@
#include "hb.hh"
#ifndef HB_NO_DRAW
#ifdef HB_EXPERIMENTAL_API
#include "hb-draw.hh"
#include "hb-ot.h"
#include "hb-ot-glyf-table.hh"
#include "hb-ot-cff1-table.hh"
#include "hb-ot-cff2-table.hh"
/**
* hb_draw_funcs_set_move_to_func:
* @funcs: draw functions object
* @move_to: move-to callback
* SECTION:hb-draw
* @title: hb-draw
* @short_description: Glyph drawing
* @include: hb.h
*
* Sets move-to callback to the draw functions object.
*
* Since: EXPERIMENTAL
* Functions for drawing (extracting) glyph shapes.
**/
void
hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *funcs,
hb_draw_move_to_func_t move_to)
{
if (unlikely (hb_object_is_immutable (funcs))) return;
funcs->move_to = move_to;
}
/**
* hb_draw_funcs_set_line_to_func:
* @funcs: draw functions object
* @line_to: line-to callback
*
* Sets line-to callback to the draw functions object.
*
* Since: EXPERIMENTAL
**/
void
hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *funcs,
hb_draw_line_to_func_t line_to)
{
if (unlikely (hb_object_is_immutable (funcs))) return;
funcs->line_to = line_to;
}
/**
* hb_draw_funcs_set_quadratic_to_func:
* @funcs: draw functions object
* @move_to: quadratic-to callback
*
* Sets quadratic-to callback to the draw functions object.
*
* Since: EXPERIMENTAL
**/
void
hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *funcs,
hb_draw_quadratic_to_func_t quadratic_to)
{
if (unlikely (hb_object_is_immutable (funcs))) return;
funcs->quadratic_to = quadratic_to;
funcs->is_quadratic_to_set = true;
}
/**
* hb_draw_funcs_set_cubic_to_func:
* @funcs: draw functions
* @cubic_to: cubic-to callback
*
* Sets cubic-to callback to the draw functions object.
*
* Since: EXPERIMENTAL
**/
void
hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *funcs,
hb_draw_cubic_to_func_t cubic_to)
{
if (unlikely (hb_object_is_immutable (funcs))) return;
funcs->cubic_to = cubic_to;
}
/**
* hb_draw_funcs_set_close_path_func:
* @funcs: draw functions object
* @close_path: close-path callback
*
* Sets close-path callback to the draw functions object.
*
* Since: EXPERIMENTAL
**/
void
hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *funcs,
hb_draw_close_path_func_t close_path)
{
if (unlikely (hb_object_is_immutable (funcs))) return;
funcs->close_path = close_path;
}
static void
_move_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
static void
_line_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
static void
_quadratic_to_nil (hb_position_t control_x HB_UNUSED, hb_position_t control_y HB_UNUSED,
hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
hb_draw_move_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
hb_draw_state_t *st HB_UNUSED,
float to_x HB_UNUSED, float to_y HB_UNUSED,
void *user_data HB_UNUSED) {}
static void
_cubic_to_nil (hb_position_t control1_x HB_UNUSED, hb_position_t control1_y HB_UNUSED,
hb_position_t control2_x HB_UNUSED, hb_position_t control2_y HB_UNUSED,
hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
hb_draw_line_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
hb_draw_state_t *st HB_UNUSED,
float to_x HB_UNUSED, float to_y HB_UNUSED,
void *user_data HB_UNUSED) {}
static void
_close_path_nil (void *user_data HB_UNUSED) {}
hb_draw_quadratic_to_nil (hb_draw_funcs_t *dfuncs, void *draw_data,
hb_draw_state_t *st,
float control_x, float control_y,
float to_x, float to_y,
void *user_data HB_UNUSED)
{
dfuncs->emit_cubic_to (draw_data, *st,
(st->current_x + 2.f * control_x) / 3.f,
(st->current_y + 2.f * control_y) / 3.f,
(to_x + 2.f * control_x) / 3.f,
(to_y + 2.f * control_y) / 3.f,
to_x, to_y);
}
static void
hb_draw_cubic_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
hb_draw_state_t *st HB_UNUSED,
float control1_x HB_UNUSED, float control1_y HB_UNUSED,
float control2_x HB_UNUSED, float control2_y HB_UNUSED,
float to_x HB_UNUSED, float to_y HB_UNUSED,
void *user_data HB_UNUSED) {}
static void
hb_draw_close_path_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
hb_draw_state_t *st HB_UNUSED,
void *user_data HB_UNUSED) {}
#define HB_DRAW_FUNC_IMPLEMENT(name) \
\
void \
hb_draw_funcs_set_##name##_func (hb_draw_funcs_t *dfuncs, \
hb_draw_##name##_func_t func, \
void *user_data, \
hb_destroy_func_t destroy) \
{ \
if (hb_object_is_immutable (dfuncs)) \
return; \
\
if (dfuncs->destroy.name) \
dfuncs->destroy.name (dfuncs->user_data.name); \
\
if (func) { \
dfuncs->func.name = func; \
dfuncs->user_data.name = user_data; \
dfuncs->destroy.name = destroy; \
} else { \
dfuncs->func.name = hb_draw_##name##_nil; \
dfuncs->user_data.name = nullptr; \
dfuncs->destroy.name = nullptr; \
} \
}
HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_DRAW_FUNC_IMPLEMENT
/**
* hb_draw_funcs_create:
* hb_draw_funcs_create: (Xconstructor)
*
* Creates a new draw callbacks object.
*
* Since: EXPERIMENTAL
* Return value: (transfer full):
* A newly allocated #hb_draw_funcs_t with a reference count of 1. The initial
* reference count should be released with hb_draw_funcs_destroy when you are
* done using the #hb_draw_funcs_t. This function never returns %NULL. If
* memory cannot be allocated, a special singleton #hb_draw_funcs_t object will
* be returned.
*
* Since: 4.0.0
**/
hb_draw_funcs_t *
hb_draw_funcs_create ()
{
hb_draw_funcs_t *funcs;
if (unlikely (!(funcs = hb_object_create<hb_draw_funcs_t> ())))
hb_draw_funcs_t *dfuncs;
if (unlikely (!(dfuncs = hb_object_create<hb_draw_funcs_t> ())))
return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t));
funcs->move_to = (hb_draw_move_to_func_t) _move_to_nil;
funcs->line_to = (hb_draw_line_to_func_t) _line_to_nil;
funcs->quadratic_to = (hb_draw_quadratic_to_func_t) _quadratic_to_nil;
funcs->is_quadratic_to_set = false;
funcs->cubic_to = (hb_draw_cubic_to_func_t) _cubic_to_nil;
funcs->close_path = (hb_draw_close_path_func_t) _close_path_nil;
return funcs;
dfuncs->func = Null (hb_draw_funcs_t).func;
return dfuncs;
}
DEFINE_NULL_INSTANCE (hb_draw_funcs_t) =
{
HB_OBJECT_HEADER_STATIC,
{
#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_nil,
HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_DRAW_FUNC_IMPLEMENT
}
};
/**
* hb_draw_funcs_reference:
* @funcs: draw functions
* hb_draw_funcs_reference: (skip)
* @dfuncs: draw functions
*
* Add to callbacks object refcount.
* Increases the reference count on @dfuncs by one. This prevents @buffer from
* being destroyed until a matching call to hb_draw_funcs_destroy() is made.
*
* Returns: The same object.
* Since: EXPERIMENTAL
* Return value: (transfer full):
* The referenced #hb_draw_funcs_t.
*
* Since: 4.0.0
**/
hb_draw_funcs_t *
hb_draw_funcs_reference (hb_draw_funcs_t *funcs)
hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs)
{
return hb_object_reference (funcs);
return hb_object_reference (dfuncs);
}
/**
* hb_draw_funcs_destroy:
* @funcs: draw functions
* hb_draw_funcs_destroy: (skip)
* @dfuncs: draw functions
*
* Decreases refcount of callbacks object and deletes the object if it reaches
* to zero.
* Deallocate the @dfuncs.
* Decreases the reference count on @dfuncs by one. If the result is zero, then
* @dfuncs and all associated resources are freed. See hb_draw_funcs_reference().
*
* Since: EXPERIMENTAL
* Since: 4.0.0
**/
void
hb_draw_funcs_destroy (hb_draw_funcs_t *funcs)
hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs)
{
if (!hb_object_destroy (funcs)) return;
if (!hb_object_destroy (dfuncs)) return;
hb_free (funcs);
#define HB_DRAW_FUNC_IMPLEMENT(name) \
if (dfuncs->destroy.name) dfuncs->destroy.name (dfuncs->user_data.name);
HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_DRAW_FUNC_IMPLEMENT
hb_free (dfuncs);
}
/**
* hb_draw_funcs_make_immutable:
* @funcs: draw functions
* @dfuncs: draw functions
*
* Makes funcs object immutable.
* Makes @dfuncs object immutable.
*
* Since: EXPERIMENTAL
* Since: 4.0.0
**/
void
hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs)
hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs)
{
if (hb_object_is_immutable (funcs))
if (hb_object_is_immutable (dfuncs))
return;
hb_object_make_immutable (funcs);
hb_object_make_immutable (dfuncs);
}
/**
* hb_draw_funcs_is_immutable:
* @funcs: draw functions
* @dfuncs: draw functions
*
* Checks whether funcs is immutable.
* Checks whether @dfuncs is immutable.
*
* Returns: If is immutable.
* Since: EXPERIMENTAL
* Return value: %true if @dfuncs is immutable, %false otherwise
*
* Since: 4.0.0
**/
hb_bool_t
hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs)
hb_draw_funcs_is_immutable (hb_draw_funcs_t *dfuncs)
{
return hb_object_is_immutable (funcs);
return hb_object_is_immutable (dfuncs);
}
/**
* hb_draw_move_to:
* @dfuncs: draw functions
* @draw_data: associated draw data passed by the caller
* @st: current draw state
* @to_x: X component of target point
* @to_y: Y component of target point
*
* Perform a "move-to" draw operation.
*
* Since: 4.0.0
**/
void
hb_draw_move_to (hb_draw_funcs_t *dfuncs, void *draw_data,
hb_draw_state_t *st,
float to_x, float to_y)
{
dfuncs->move_to (draw_data, *st,
to_x, to_y);
}
/**
* hb_font_draw_glyph:
* @font: a font object
* @glyph: a glyph id
* @funcs: draw callbacks object
* @user_data: parameter you like be passed to the callbacks when are called
* hb_draw_line_to:
* @dfuncs: draw functions
* @draw_data: associated draw data passed by the caller
* @st: current draw state
* @to_x: X component of target point
* @to_y: Y component of target point
*
* Draw a glyph.
* Perform a "line-to" draw operation.
*
* Returns: Whether the font had the glyph and the operation completed successfully.
* Since: EXPERIMENTAL
* Since: 4.0.0
**/
hb_bool_t
hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph,
const hb_draw_funcs_t *funcs,
void *user_data)
void
hb_draw_line_to (hb_draw_funcs_t *dfuncs, void *draw_data,
hb_draw_state_t *st,
float to_x, float to_y)
{
if (unlikely (funcs == &Null (hb_draw_funcs_t) ||
glyph >= font->face->get_num_glyphs ()))
return false;
draw_helper_t draw_helper (funcs, user_data);
if (font->face->table.glyf->get_path (font, glyph, draw_helper)) return true;
#ifndef HB_NO_CFF
if (font->face->table.cff1->get_path (font, glyph, draw_helper)) return true;
if (font->face->table.cff2->get_path (font, glyph, draw_helper)) return true;
#endif
return false;
dfuncs->line_to (draw_data, *st,
to_x, to_y);
}
#endif
/**
* hb_draw_quadratic_to:
* @dfuncs: draw functions
* @draw_data: associated draw data passed by the caller
* @st: current draw state
* @control_x: X component of control point
* @control_y: Y component of control point
* @to_x: X component of target point
* @to_y: Y component of target point
*
* Perform a "quadratic-to" draw operation.
*
* Since: 4.0.0
**/
void
hb_draw_quadratic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
hb_draw_state_t *st,
float control_x, float control_y,
float to_x, float to_y)
{
dfuncs->quadratic_to (draw_data, *st,
control_x, control_y,
to_x, to_y);
}
/**
* hb_draw_cubic_to:
* @dfuncs: draw functions
* @draw_data: associated draw data passed by the caller
* @st: current draw state
* @control1_x: X component of first control point
* @control1_y: Y component of first control point
* @control2_x: X component of second control point
* @control2_y: Y component of second control point
* @to_x: X component of target point
* @to_y: Y component of target point
*
* Perform a "cubic-to" draw operation.
*
* Since: 4.0.0
**/
void
hb_draw_cubic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
hb_draw_state_t *st,
float control1_x, float control1_y,
float control2_x, float control2_y,
float to_x, float to_y)
{
dfuncs->cubic_to (draw_data, *st,
control1_x, control1_y,
control2_x, control2_y,
to_x, to_y);
}
/**
* hb_draw_close_path:
* @dfuncs: draw functions
* @draw_data: associated draw data passed by the caller
* @st: current draw state
*
* Perform a "close-path" draw operation.
*
* Since: 4.0.0
**/
void
hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data,
hb_draw_state_t *st)
{
dfuncs->close_path (draw_data, *st);
}
#endif

View File

@ -33,65 +33,292 @@
HB_BEGIN_DECLS
#ifdef HB_EXPERIMENTAL_API
typedef void (*hb_draw_move_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data);
typedef void (*hb_draw_line_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data);
typedef void (*hb_draw_quadratic_to_func_t) (hb_position_t control_x, hb_position_t control_y,
hb_position_t to_x, hb_position_t to_y,
void *user_data);
typedef void (*hb_draw_cubic_to_func_t) (hb_position_t control1_x, hb_position_t control1_y,
hb_position_t control2_x, hb_position_t control2_y,
hb_position_t to_x, hb_position_t to_y,
void *user_data);
typedef void (*hb_draw_close_path_func_t) (void *user_data);
/**
* hb_draw_state_t
* @path_open: Whether there is an open path
* @path_start_x: X component of the start of current path
* @path_start_y: Y component of the start of current path
* @current_x: X component of current point
* @current_y: Y component of current point
*
* Current drawing state.
*
* Since: 4.0.0
**/
typedef struct hb_draw_state_t {
hb_bool_t path_open;
float path_start_x;
float path_start_y;
float current_x;
float current_y;
/*< private >*/
hb_var_num_t reserved1;
hb_var_num_t reserved2;
hb_var_num_t reserved3;
hb_var_num_t reserved4;
hb_var_num_t reserved5;
hb_var_num_t reserved6;
hb_var_num_t reserved7;
} hb_draw_state_t;
/**
* HB_DRAW_STATE_DEFAULT:
*
* The default #hb_draw_state_t at the start of glyph drawing.
*/
#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}}
/**
* hb_draw_funcs_t:
*
* Glyph draw callbacks.
*
* _move_to, _line_to and _cubic_to calls are necessary to be defined but we
* translate _quadratic_to calls to _cubic_to if the callback isn't defined.
* #hb_draw_move_to_func_t, #hb_draw_line_to_func_t and
* #hb_draw_cubic_to_func_t calls are necessary to be defined but we translate
* #hb_draw_quadratic_to_func_t calls to #hb_draw_cubic_to_func_t if the
* callback isn't defined.
*
* Since: EXPERIMENTAL
* Since: 4.0.0
**/
typedef struct hb_draw_funcs_t hb_draw_funcs_t;
HB_EXTERN void
hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *funcs,
hb_draw_move_to_func_t move_to);
HB_EXTERN void
hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *funcs,
hb_draw_line_to_func_t line_to);
/**
* hb_draw_move_to_func_t:
* @dfuncs: draw functions object
* @draw_data: The data accompanying the draw functions
* @st: current draw state
* @to_x: X component of target point
* @to_y: Y component of target point
* @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_draw_funcs_t to perform a "move-to" draw
* operation.
*
* Since: 4.0.0
*
**/
typedef void (*hb_draw_move_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
hb_draw_state_t *st,
float to_x, float to_y,
void *user_data);
HB_EXTERN void
hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *funcs,
hb_draw_quadratic_to_func_t quadratic_to);
/**
* hb_draw_line_to_func_t:
* @dfuncs: draw functions object
* @draw_data: The data accompanying the draw functions
* @st: current draw state
* @to_x: X component of target point
* @to_y: Y component of target point
* @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_draw_funcs_t to perform a "line-to" draw
* operation.
*
* Since: 4.0.0
*
**/
typedef void (*hb_draw_line_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
hb_draw_state_t *st,
float to_x, float to_y,
void *user_data);
HB_EXTERN void
hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *funcs,
hb_draw_cubic_to_func_t cubic_to);
/**
* hb_draw_quadratic_to_func_t:
* @dfuncs: draw functions object
* @draw_data: The data accompanying the draw functions
* @st: current draw state
* @control_x: X component of control point
* @control_y: Y component of control point
* @to_x: X component of target point
* @to_y: Y component of target point
* @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_draw_funcs_t to perform a "quadratic-to" draw
* operation.
*
* Since: 4.0.0
*
**/
typedef void (*hb_draw_quadratic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
hb_draw_state_t *st,
float control_x, float control_y,
float to_x, float to_y,
void *user_data);
/**
* hb_draw_cubic_to_func_t:
* @dfuncs: draw functions object
* @draw_data: The data accompanying the draw functions
* @st: current draw state
* @control1_x: X component of first control point
* @control1_y: Y component of first control point
* @control2_x: X component of second control point
* @control2_y: Y component of second control point
* @to_x: X component of target point
* @to_y: Y component of target point
* @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_draw_funcs_t to perform a "cubic-to" draw
* operation.
*
* Since: 4.0.0
*
**/
typedef void (*hb_draw_cubic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
hb_draw_state_t *st,
float control1_x, float control1_y,
float control2_x, float control2_y,
float to_x, float to_y,
void *user_data);
/**
* hb_draw_close_path_func_t:
* @dfuncs: draw functions object
* @draw_data: The data accompanying the draw functions
* @st: current draw state
* @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_draw_funcs_t to perform a "close-path" draw
* operation.
*
* Since: 4.0.0
*
**/
typedef void (*hb_draw_close_path_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
hb_draw_state_t *st,
void *user_data);
/**
* hb_draw_funcs_set_move_to_func:
* @dfuncs: draw functions object
* @func: (closure user_data) (destroy destroy) (scope notified): move-to callback
* @user_data: Data to pass to @func
* @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets move-to callback to the draw functions object.
*
* Since: 4.0.0
**/
HB_EXTERN void
hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *funcs,
hb_draw_close_path_func_t close_path);
hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *dfuncs,
hb_draw_move_to_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_draw_funcs_set_line_to_func:
* @dfuncs: draw functions object
* @func: (closure user_data) (destroy destroy) (scope notified): line-to callback
* @user_data: Data to pass to @func
* @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets line-to callback to the draw functions object.
*
* Since: 4.0.0
**/
HB_EXTERN void
hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *dfuncs,
hb_draw_line_to_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_draw_funcs_set_quadratic_to_func:
* @dfuncs: draw functions object
* @func: (closure user_data) (destroy destroy) (scope notified): quadratic-to callback
* @user_data: Data to pass to @func
* @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets quadratic-to callback to the draw functions object.
*
* Since: 4.0.0
**/
HB_EXTERN void
hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *dfuncs,
hb_draw_quadratic_to_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_draw_funcs_set_cubic_to_func:
* @dfuncs: draw functions
* @func: (closure user_data) (destroy destroy) (scope notified): cubic-to callback
* @user_data: Data to pass to @func
* @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets cubic-to callback to the draw functions object.
*
* Since: 4.0.0
**/
HB_EXTERN void
hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *dfuncs,
hb_draw_cubic_to_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_draw_funcs_set_close_path_func:
* @dfuncs: draw functions object
* @func: (closure user_data) (destroy destroy) (scope notified): close-path callback
* @user_data: Data to pass to @func
* @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets close-path callback to the draw functions object.
*
* Since: 4.0.0
**/
HB_EXTERN void
hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *dfuncs,
hb_draw_close_path_func_t func,
void *user_data, hb_destroy_func_t destroy);
HB_EXTERN hb_draw_funcs_t *
hb_draw_funcs_create (void);
HB_EXTERN hb_draw_funcs_t *
hb_draw_funcs_reference (hb_draw_funcs_t *funcs);
hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs);
HB_EXTERN void
hb_draw_funcs_destroy (hb_draw_funcs_t *funcs);
hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs);
HB_EXTERN void
hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs);
hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs);
HB_EXTERN hb_bool_t
hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs);
#endif
hb_draw_funcs_is_immutable (hb_draw_funcs_t *dfuncs);
HB_EXTERN void
hb_draw_move_to (hb_draw_funcs_t *dfuncs, void *draw_data,
hb_draw_state_t *st,
float to_x, float to_y);
HB_EXTERN void
hb_draw_line_to (hb_draw_funcs_t *dfuncs, void *draw_data,
hb_draw_state_t *st,
float to_x, float to_y);
HB_EXTERN void
hb_draw_quadratic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
hb_draw_state_t *st,
float control_x, float control_y,
float to_x, float to_y);
HB_EXTERN void
hb_draw_cubic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
hb_draw_state_t *st,
float control1_x, float control1_y,
float control2_x, float control2_y,
float to_x, float to_y);
HB_EXTERN void
hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data,
hb_draw_state_t *st);
HB_END_DECLS

View File

@ -27,113 +27,205 @@
#include "hb.hh"
#ifdef HB_EXPERIMENTAL_API
/*
* hb_draw_funcs_t
*/
#define HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS \
HB_DRAW_FUNC_IMPLEMENT (move_to) \
HB_DRAW_FUNC_IMPLEMENT (line_to) \
HB_DRAW_FUNC_IMPLEMENT (quadratic_to) \
HB_DRAW_FUNC_IMPLEMENT (cubic_to) \
HB_DRAW_FUNC_IMPLEMENT (close_path) \
/* ^--- Add new callbacks here */
struct hb_draw_funcs_t
{
hb_object_header_t header;
hb_draw_move_to_func_t move_to;
hb_draw_line_to_func_t line_to;
hb_draw_quadratic_to_func_t quadratic_to;
bool is_quadratic_to_set;
hb_draw_cubic_to_func_t cubic_to;
hb_draw_close_path_func_t close_path;
};
struct {
#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_func_t name;
HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_DRAW_FUNC_IMPLEMENT
} func;
struct draw_helper_t
{
draw_helper_t (const hb_draw_funcs_t *funcs_, void *user_data_)
{
funcs = funcs_;
user_data = user_data_;
path_open = false;
path_start_x = current_x = path_start_y = current_y = 0;
}
~draw_helper_t () { end_path (); }
struct {
#define HB_DRAW_FUNC_IMPLEMENT(name) void *name;
HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_DRAW_FUNC_IMPLEMENT
} user_data;
void move_to (hb_position_t x, hb_position_t y)
struct {
#define HB_DRAW_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_DRAW_FUNC_IMPLEMENT
} destroy;
void emit_move_to (void *draw_data, hb_draw_state_t &st,
float to_x, float to_y)
{ func.move_to (this, draw_data, &st,
to_x, to_y,
user_data.move_to); }
void emit_line_to (void *draw_data, hb_draw_state_t &st,
float to_x, float to_y)
{ func.line_to (this, draw_data, &st,
to_x, to_y,
user_data.line_to); }
void emit_quadratic_to (void *draw_data, hb_draw_state_t &st,
float control_x, float control_y,
float to_x, float to_y)
{ func.quadratic_to (this, draw_data, &st,
control_x, control_y,
to_x, to_y,
user_data.quadratic_to); }
void emit_cubic_to (void *draw_data, hb_draw_state_t &st,
float control1_x, float control1_y,
float control2_x, float control2_y,
float to_x, float to_y)
{ func.cubic_to (this, draw_data, &st,
control1_x, control1_y,
control2_x, control2_y,
to_x, to_y,
user_data.cubic_to); }
void emit_close_path (void *draw_data, hb_draw_state_t &st)
{ func.close_path (this, draw_data, &st,
user_data.close_path); }
void move_to (void *draw_data, hb_draw_state_t &st,
float to_x, float to_y)
{
if (path_open) end_path ();
current_x = path_start_x = x;
current_y = path_start_y = y;
if (st.path_open) close_path (draw_data, st);
st.current_x = to_x;
st.current_y = to_y;
}
void line_to (hb_position_t x, hb_position_t y)
void line_to (void *draw_data, hb_draw_state_t &st,
float to_x, float to_y)
{
if (equal_to_current (x, y)) return;
if (!path_open) start_path ();
funcs->line_to (x, y, user_data);
current_x = x;
current_y = y;
if (!st.path_open) start_path (draw_data, st);
emit_line_to (draw_data, st, to_x, to_y);
st.current_x = to_x;
st.current_y = to_y;
}
void
quadratic_to (hb_position_t control_x, hb_position_t control_y,
hb_position_t to_x, hb_position_t to_y)
quadratic_to (void *draw_data, hb_draw_state_t &st,
float control_x, float control_y,
float to_x, float to_y)
{
if (equal_to_current (control_x, control_y) && equal_to_current (to_x, to_y))
return;
if (!path_open) start_path ();
if (funcs->is_quadratic_to_set)
funcs->quadratic_to (control_x, control_y, to_x, to_y, user_data);
else
funcs->cubic_to (roundf ((current_x + 2.f * control_x) / 3.f),
roundf ((current_y + 2.f * control_y) / 3.f),
roundf ((to_x + 2.f * control_x) / 3.f),
roundf ((to_y + 2.f * control_y) / 3.f),
to_x, to_y, user_data);
current_x = to_x;
current_y = to_y;
if (!st.path_open) start_path (draw_data, st);
emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y);
st.current_x = to_x;
st.current_y = to_y;
}
void
cubic_to (hb_position_t control1_x, hb_position_t control1_y,
hb_position_t control2_x, hb_position_t control2_y,
hb_position_t to_x, hb_position_t to_y)
cubic_to (void *draw_data, hb_draw_state_t &st,
float control1_x, float control1_y,
float control2_x, float control2_y,
float to_x, float to_y)
{
if (equal_to_current (control1_x, control1_y) &&
equal_to_current (control2_x, control2_y) &&
equal_to_current (to_x, to_y))
return;
if (!path_open) start_path ();
funcs->cubic_to (control1_x, control1_y, control2_x, control2_y, to_x, to_y, user_data);
current_x = to_x;
current_y = to_y;
if (!st.path_open) start_path (draw_data, st);
emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);
st.current_x = to_x;
st.current_y = to_y;
}
void end_path ()
void
close_path (void *draw_data, hb_draw_state_t &st)
{
if (path_open)
if (st.path_open)
{
if ((path_start_x != current_x) || (path_start_y != current_y))
funcs->line_to (path_start_x, path_start_y, user_data);
funcs->close_path (user_data);
if ((st.path_start_x != st.current_x) || (st.path_start_y != st.current_y))
emit_line_to (draw_data, st, st.path_start_x, st.path_start_y);
emit_close_path (draw_data, st);
}
path_open = false;
path_start_x = current_x = path_start_y = current_y = 0;
st.path_open = false;
st.path_start_x = st.current_x = st.path_start_y = st.current_y = 0;
}
protected:
bool equal_to_current (hb_position_t x, hb_position_t y)
{ return current_x == x && current_y == y; }
void start_path ()
void start_path (void *draw_data, hb_draw_state_t &st)
{
if (path_open) end_path ();
path_open = true;
funcs->move_to (path_start_x, path_start_y, user_data);
assert (!st.path_open);
emit_move_to (draw_data, st, st.current_x, st.current_y);
st.path_open = true;
st.path_start_x = st.current_x;
st.path_start_y = st.current_y;
}
};
DECLARE_NULL_INSTANCE (hb_draw_funcs_t);
struct hb_draw_session_t
{
hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_ = 0.f)
: slant {slant_}, not_slanted {slant == 0.f},
funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT
{}
~hb_draw_session_t () { close_path (); }
void move_to (float to_x, float to_y)
{
if (likely (not_slanted))
funcs->move_to (draw_data, st,
to_x, to_y);
else
funcs->move_to (draw_data, st,
to_x + to_y * slant, to_y);
}
void line_to (float to_x, float to_y)
{
if (likely (not_slanted))
funcs->line_to (draw_data, st,
to_x, to_y);
else
funcs->line_to (draw_data, st,
to_x + to_y * slant, to_y);
}
void
quadratic_to (float control_x, float control_y,
float to_x, float to_y)
{
if (likely (not_slanted))
funcs->quadratic_to (draw_data, st,
control_x, control_y,
to_x, to_y);
else
funcs->quadratic_to (draw_data, st,
control_x + control_y * slant, control_y,
to_x + to_y * slant, to_y);
}
void
cubic_to (float control1_x, float control1_y,
float control2_x, float control2_y,
float to_x, float to_y)
{
if (likely (not_slanted))
funcs->cubic_to (draw_data, st,
control1_x, control1_y,
control2_x, control2_y,
to_x, to_y);
else
funcs->cubic_to (draw_data, st,
control1_x + control1_y * slant, control1_y,
control2_x + control2_y * slant, control2_y,
to_x + to_y * slant, to_y);
}
void close_path ()
{
funcs->close_path (draw_data, st);
}
hb_position_t path_start_x;
hb_position_t path_start_y;
hb_position_t current_x;
hb_position_t current_y;
bool path_open;
const hb_draw_funcs_t *funcs;
void *user_data;
protected:
float slant;
bool not_slanted;
hb_draw_funcs_t *funcs;
void *draw_data;
hb_draw_state_t st;
};
#endif
#endif /* HB_DRAW_HH */

View File

@ -29,6 +29,7 @@
#include "hb.hh"
#include "hb-font.hh"
#include "hb-draw.hh"
#include "hb-machinery.hh"
#include "hb-ot.h"
@ -501,6 +502,136 @@ hb_font_get_glyph_from_name_default (hb_font_t *font,
return font->parent->get_glyph_from_name (name, len, glyph);
}
static void
hb_font_get_glyph_shape_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_draw_funcs_t *draw_funcs,
void *draw_data,
void *user_data HB_UNUSED)
{
}
typedef struct hb_font_get_glyph_shape_default_adaptor_t {
hb_draw_funcs_t *draw_funcs;
void *draw_data;
float x_scale;
float y_scale;
} hb_font_get_glyph_shape_default_adaptor_t;
static void
hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED,
void *draw_data,
hb_draw_state_t *st,
float to_x, float to_y,
void *user_data HB_UNUSED)
{
hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
float x_scale = adaptor->x_scale;
float y_scale = adaptor->y_scale;
adaptor->draw_funcs->emit_move_to (adaptor->draw_data, *st,
x_scale * to_x, y_scale * to_y);
}
static void
hb_draw_line_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
hb_draw_state_t *st,
float to_x, float to_y,
void *user_data HB_UNUSED)
{
hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
float x_scale = adaptor->x_scale;
float y_scale = adaptor->y_scale;
st->current_x *= x_scale;
st->current_y *= y_scale;
adaptor->draw_funcs->emit_line_to (adaptor->draw_data, *st,
x_scale * to_x, y_scale * to_y);
}
static void
hb_draw_quadratic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
hb_draw_state_t *st,
float control_x, float control_y,
float to_x, float to_y,
void *user_data HB_UNUSED)
{
hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
float x_scale = adaptor->x_scale;
float y_scale = adaptor->y_scale;
st->current_x *= x_scale;
st->current_y *= y_scale;
adaptor->draw_funcs->emit_quadratic_to (adaptor->draw_data, *st,
x_scale * control_x, y_scale * control_y,
x_scale * to_x, y_scale * to_y);
}
static void
hb_draw_cubic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
hb_draw_state_t *st,
float control1_x, float control1_y,
float control2_x, float control2_y,
float to_x, float to_y,
void *user_data HB_UNUSED)
{
hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
float x_scale = adaptor->x_scale;
float y_scale = adaptor->y_scale;
st->current_x *= x_scale;
st->current_y *= y_scale;
adaptor->draw_funcs->emit_cubic_to (adaptor->draw_data, *st,
x_scale * control1_x, y_scale * control1_y,
x_scale * control2_x, y_scale * control2_y,
x_scale * to_x, y_scale * to_y);
}
static void
hb_draw_close_path_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
hb_draw_state_t *st,
void *user_data HB_UNUSED)
{
hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
adaptor->draw_funcs->emit_close_path (adaptor->draw_data, *st);
}
static const hb_draw_funcs_t _hb_draw_funcs_default = {
HB_OBJECT_HEADER_STATIC,
{
#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_default,
HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_DRAW_FUNC_IMPLEMENT
}
};
static void
hb_font_get_glyph_shape_default (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_draw_funcs_t *draw_funcs,
void *draw_data,
void *user_data HB_UNUSED)
{
hb_font_get_glyph_shape_default_adaptor_t adaptor = {
draw_funcs,
draw_data,
(float) font->x_scale / (float) font->parent->x_scale,
(float) font->y_scale / (float) font->parent->y_scale
};
font->parent->get_glyph_shape (glyph,
const_cast<hb_draw_funcs_t *> (&_hb_draw_funcs_default),
&adaptor);
}
DEFINE_NULL_INSTANCE (hb_font_funcs_t) =
{
HB_OBJECT_HEADER_STATIC,
@ -1168,6 +1299,26 @@ hb_font_get_glyph_from_name (hb_font_t *font,
return font->get_glyph_from_name (name, len, glyph);
}
/**
* hb_font_get_glyph_shape:
* @font: #hb_font_t to work upon
* @glyph: : The glyph ID
* @dfuncs: #hb_draw_funcs_t to draw to
* @draw_data: User data to pass to draw callbacks
*
* Fetches the glyph shape that corresponds to a glyph in the specified @font.
* The shape is returned by way of calls to the callsbacks of the @dfuncs
* objects, with @draw_data passed to them.
*
* Since: 4.0.0
**/
void
hb_font_get_glyph_shape (hb_font_t *font,
hb_codepoint_t glyph,
hb_draw_funcs_t *dfuncs, void *draw_data)
{
font->get_glyph_shape (glyph, dfuncs, draw_data);
}
/* A bit higher-level, and with fallback */
@ -1190,7 +1341,7 @@ hb_font_get_extents_for_direction (hb_font_t *font,
hb_direction_t direction,
hb_font_extents_t *extents)
{
return font->get_extents_for_direction (direction, extents);
font->get_extents_for_direction (direction, extents);
}
/**
* hb_font_get_glyph_advance_for_direction:
@ -1215,7 +1366,7 @@ hb_font_get_glyph_advance_for_direction (hb_font_t *font,
hb_position_t *x,
hb_position_t *y)
{
return font->get_glyph_advance_for_direction (glyph, direction, x, y);
font->get_glyph_advance_for_direction (glyph, direction, x, y);
}
/**
* hb_font_get_glyph_advances_for_direction:
@ -2044,12 +2195,16 @@ hb_font_get_ptem (hb_font_t *font)
* @slant: synthetic slant value.
*
* Sets the "synthetic slant" of a font. By default is zero.
* Synthetic slant is the graphical skew that the renderer
* applies to the font at rendering time.
* Synthetic slant is the graphical skew applied to the font
* at rendering time.
*
* HarfBuzz needs to know this value to adjust shaping results,
* metrics, and style values to match the slanted rendering.
*
* <note>Note: The glyph shape fetched via the
* hb_font_get_glyph_shape() is slanted to reflect this value
* as well.</note>
*
* <note>Note: The slant value is a ratio. For example, a
* 20% slant would be represented as a 0.2 value.</note>
*

View File

@ -511,6 +511,25 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
hb_codepoint_t *glyph,
void *user_data);
/**
* hb_font_get_glyph_shape_func_t:
* @font: #hb_font_t to work upon
* @font_data: @font user data pointer
* @glyph: The glyph ID to query
* @draw_funcs: The draw functions to send the shape data to
* @draw_data: The data accompanying the draw functions
* @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* Since: 4.0.0
*
**/
typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
hb_draw_funcs_t *draw_funcs, void *draw_data,
void *user_data);
/* func setters */
@ -770,6 +789,22 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_from_name_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_shape_func:
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
* @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_shape_func_t.
*
* Since: 4.0.0
**/
HB_EXTERN void
hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_shape_func_t func,
void *user_data, hb_destroy_func_t destroy);
/* func dispatch */
HB_EXTERN hb_bool_t
@ -850,6 +885,11 @@ hb_font_get_glyph_from_name (hb_font_t *font,
const char *name, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph);
HB_EXTERN void
hb_font_get_glyph_shape (hb_font_t *font,
hb_codepoint_t glyph,
hb_draw_funcs_t *dfuncs, void *draw_data);
/* high-level funcs, with fallback */
@ -1056,11 +1096,6 @@ HB_EXTERN void
hb_font_set_var_named_instance (hb_font_t *font,
unsigned instance_index);
#ifdef HB_EXPERIMENTAL_API
HB_EXTERN hb_bool_t
hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph,
const hb_draw_funcs_t *funcs, void *user_data);
#endif
HB_END_DECLS

View File

@ -57,6 +57,7 @@
HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
HB_FONT_FUNC_IMPLEMENT (glyph_name) \
HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \
HB_FONT_FUNC_IMPLEMENT (glyph_shape) \
/* ^--- Add new callbacks here */
struct hb_font_funcs_t
@ -140,6 +141,8 @@ struct hb_font_t
hb_position_t em_scalef_y (float v) { return em_scalef (v, y_scale); }
float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); }
float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); }
float em_fscalef_x (float v) { return em_fscalef (v, x_scale); }
float em_fscalef_y (float v) { return em_fscalef (v, y_scale); }
hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
{ return em_mult (v, dir_mult (direction)); }
@ -373,6 +376,15 @@ struct hb_font_t
klass->user_data.glyph_from_name);
}
void get_glyph_shape (hb_codepoint_t glyph,
hb_draw_funcs_t *draw_funcs, void *draw_data)
{
klass->get.f.glyph_shape (this, user_data,
glyph,
draw_funcs, draw_data,
klass->user_data.glyph_shape);
}
/* A bit higher-level, and with fallback */
@ -625,7 +637,9 @@ struct hb_font_t
hb_position_t em_mult (int16_t v, int64_t mult)
{ return (hb_position_t) ((v * mult + 32768) >> 16); }
hb_position_t em_scalef (float v, int scale)
{ return (hb_position_t) roundf (v * scale / face->get_upem ()); }
{ return (hb_position_t) roundf (em_fscalef (v, scale)); }
float em_fscalef (float v, int scale)
{ return v * scale / face->get_upem (); }
float em_fscale (int16_t v, int scale)
{ return (float) v * scale / face->get_upem (); }
};

View File

@ -33,12 +33,14 @@
#include "hb-ft.h"
#include "hb-draw.hh"
#include "hb-font.hh"
#include "hb-machinery.hh"
#include "hb-cache.hh"
#include FT_ADVANCES_H
#include FT_MULTIPLE_MASTERS_H
#include FT_OUTLINE_H
#include FT_TRUETYPE_TABLES_H
@ -565,6 +567,82 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
return true;
}
#ifndef HB_NO_DRAW
static int
_hb_ft_move_to (const FT_Vector *to,
hb_draw_session_t *drawing)
{
drawing->move_to (to->x, to->y);
return FT_Err_Ok;
}
static int
_hb_ft_line_to (const FT_Vector *to,
hb_draw_session_t *drawing)
{
drawing->line_to (to->x, to->y);
return FT_Err_Ok;
}
static int
_hb_ft_conic_to (const FT_Vector *control,
const FT_Vector *to,
hb_draw_session_t *drawing)
{
drawing->quadratic_to (control->x, control->y,
to->x, to->y);
return FT_Err_Ok;
}
static int
_hb_ft_cubic_to (const FT_Vector *control1,
const FT_Vector *control2,
const FT_Vector *to,
hb_draw_session_t *drawing)
{
drawing->cubic_to (control1->x, control1->y,
control2->x, control2->y,
to->x, to->y);
return FT_Err_Ok;
}
static void
hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
hb_draw_funcs_t *draw_funcs, void *draw_data,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
if (unlikely (FT_Load_Glyph (ft_face, glyph,
FT_LOAD_NO_BITMAP | ft_font->load_flags)))
return;
if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
return;
const FT_Outline_Funcs outline_funcs = {
(FT_Outline_MoveToFunc) _hb_ft_move_to,
(FT_Outline_LineToFunc) _hb_ft_line_to,
(FT_Outline_ConicToFunc) _hb_ft_conic_to,
(FT_Outline_CubicToFunc) _hb_ft_cubic_to,
0, /* shift */
0, /* delta */
};
hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy);
FT_Outline_Decompose (&ft_face->glyph->outline,
&outline_funcs,
&draw_session);
}
#endif
static inline void free_static_ft_funcs ();
static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
@ -596,6 +674,10 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
#ifndef HB_NO_DRAW
hb_font_funcs_set_glyph_shape_func (funcs, hb_ft_get_glyph_shape, nullptr, nullptr);
#endif
hb_font_funcs_make_immutable (funcs);
hb_atexit (free_static_ft_funcs);

View File

@ -90,6 +90,7 @@ hb_gobject_##name##_get_type () \
HB_DEFINE_OBJECT_TYPE (buffer)
HB_DEFINE_OBJECT_TYPE (blob)
HB_DEFINE_OBJECT_TYPE (draw_funcs)
HB_DEFINE_OBJECT_TYPE (face)
HB_DEFINE_OBJECT_TYPE (font)
HB_DEFINE_OBJECT_TYPE (font_funcs)

View File

@ -48,6 +48,10 @@ HB_EXTERN GType
hb_gobject_buffer_get_type (void);
#define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ())
HB_EXTERN GType
hb_gobject_draw_funcs_get_type (void);
#define HB_GOBJECT_TYPE_DRAW_FUNCS (hb_gobject_draw_funcs_get_type ())
HB_EXTERN GType
hb_gobject_face_get_type (void);
#define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ())

View File

@ -194,7 +194,8 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
}
const Returned * operator -> () const { return get (); }
const Returned & operator * () const { return *get (); }
template <typename U = Returned, hb_enable_if (!hb_is_same (U, void))>
const U & operator * () const { return *get (); }
explicit operator bool () const
{ return get_stored () != Funcs::get_null (); }
template <typename C> operator const C * () const { return get (); }
@ -272,14 +273,19 @@ struct hb_face_lazy_loader_t : hb_lazy_loader_t<T,
hb_face_lazy_loader_t<T, WheresFace>,
hb_face_t, WheresFace> {};
template <typename T, unsigned int WheresFace>
template <typename T, unsigned int WheresFace, bool core=false>
struct hb_table_lazy_loader_t : hb_lazy_loader_t<T,
hb_table_lazy_loader_t<T, WheresFace>,
hb_table_lazy_loader_t<T, WheresFace, core>,
hb_face_t, WheresFace,
hb_blob_t>
{
static hb_blob_t *create (hb_face_t *face)
{ return hb_sanitize_context_t ().reference_table<T> (face); }
{
auto c = hb_sanitize_context_t ();
if (core)
c.set_num_glyphs (0); // So we don't recurse ad infinitum...
return c.reference_table<T> (face);
}
static void destroy (hb_blob_t *p) { hb_blob_destroy (p); }
static const hb_blob_t *get_null ()

View File

@ -442,13 +442,12 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph
return true;
}
#ifdef HB_EXPERIMENTAL_API
struct cff1_path_param_t
{
cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_,
draw_helper_t &draw_helper_, point_t *delta_)
hb_draw_session_t &draw_session_, point_t *delta_)
{
draw_helper = &draw_helper_;
draw_session = &draw_session_;
cff = cff_;
font = font_;
delta = delta_;
@ -458,14 +457,14 @@ struct cff1_path_param_t
{
point_t point = p;
if (delta) point.move (*delta);
draw_helper->move_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ()));
draw_session->move_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
}
void line_to (const point_t &p)
{
point_t point = p;
if (delta) point.move (*delta);
draw_helper->line_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ()));
draw_session->line_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
}
void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
@ -477,15 +476,15 @@ struct cff1_path_param_t
point2.move (*delta);
point3.move (*delta);
}
draw_helper->cubic_to (font->em_scalef_x (point1.x.to_real ()), font->em_scalef_y (point1.y.to_real ()),
font->em_scalef_x (point2.x.to_real ()), font->em_scalef_y (point2.y.to_real ()),
font->em_scalef_x (point3.x.to_real ()), font->em_scalef_y (point3.y.to_real ()));
draw_session->cubic_to (font->em_fscalef_x (point1.x.to_real ()), font->em_fscalef_y (point1.y.to_real ()),
font->em_fscalef_x (point2.x.to_real ()), font->em_fscalef_y (point2.y.to_real ()),
font->em_fscalef_x (point3.x.to_real ()), font->em_fscalef_y (point3.y.to_real ()));
}
void end_path () { draw_helper->end_path (); }
void end_path () { draw_session->close_path (); }
hb_font_t *font;
draw_helper_t *draw_helper;
hb_draw_session_t *draw_session;
point_t *delta;
const OT::cff1::accelerator_t *cff;
@ -513,7 +512,7 @@ struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_int
};
static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
draw_helper_t &draw_helper, bool in_seac = false, point_t *delta = nullptr);
hb_draw_session_t &draw_session, bool in_seac = false, point_t *delta = nullptr);
struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_param_t, cff1_path_procs_path_t>
{
@ -530,14 +529,14 @@ struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_pa
hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
if (unlikely (!(!env.in_seac && base && accent
&& _get_path (param.cff, param.font, base, *param.draw_helper, true)
&& _get_path (param.cff, param.font, accent, *param.draw_helper, true, &delta))))
&& _get_path (param.cff, param.font, base, *param.draw_session, true)
&& _get_path (param.cff, param.font, accent, *param.draw_session, true, &delta))))
env.set_error ();
}
};
bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
draw_helper_t &draw_helper, bool in_seac, point_t *delta)
hb_draw_session_t &draw_session, bool in_seac, point_t *delta)
{
if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
@ -546,7 +545,7 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin
const byte_str_t str = (*cff->charStrings)[glyph];
interp.env.init (str, *cff, fd);
interp.env.set_in_seac (in_seac);
cff1_path_param_t param (cff, font, draw_helper, delta);
cff1_path_param_t param (cff, font, draw_session, delta);
if (unlikely (!interp.interpret (param))) return false;
/* Let's end the path specially since it is called inside seac also */
@ -555,16 +554,15 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin
return true;
}
bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const
bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const
{
#ifdef HB_NO_OT_FONT_CFF
/* XXX Remove check when this code moves to .hh file. */
return true;
#endif
return _get_path (this, font, glyph, draw_helper);
return _get_path (this, font, glyph, draw_session);
}
#endif
struct get_seac_param_t
{

View File

@ -1347,9 +1347,7 @@ struct cff1
HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const;
HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const;
#ifdef HB_EXPERIMENTAL_API
HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const;
#endif
HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
private:
struct gname_t

View File

@ -143,30 +143,29 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
return true;
}
#ifdef HB_EXPERIMENTAL_API
struct cff2_path_param_t
{
cff2_path_param_t (hb_font_t *font_, draw_helper_t &draw_helper_)
cff2_path_param_t (hb_font_t *font_, hb_draw_session_t &draw_session_)
{
draw_helper = &draw_helper_;
draw_session = &draw_session_;
font = font_;
}
void move_to (const point_t &p)
{ draw_helper->move_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); }
{ draw_session->move_to (font->em_fscalef_x (p.x.to_real ()), font->em_fscalef_y (p.y.to_real ())); }
void line_to (const point_t &p)
{ draw_helper->line_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); }
{ draw_session->line_to (font->em_fscalef_x (p.x.to_real ()), font->em_fscalef_y (p.y.to_real ())); }
void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
{
draw_helper->cubic_to (font->em_scalef_x (p1.x.to_real ()), font->em_scalef_y (p1.y.to_real ()),
font->em_scalef_x (p2.x.to_real ()), font->em_scalef_y (p2.y.to_real ()),
font->em_scalef_x (p3.x.to_real ()), font->em_scalef_y (p3.y.to_real ()));
draw_session->cubic_to (font->em_fscalef_x (p1.x.to_real ()), font->em_fscalef_y (p1.y.to_real ()),
font->em_fscalef_x (p2.x.to_real ()), font->em_fscalef_y (p2.y.to_real ()),
font->em_fscalef_x (p3.x.to_real ()), font->em_fscalef_y (p3.y.to_real ()));
}
protected:
draw_helper_t *draw_helper;
hb_draw_session_t *draw_session;
hb_font_t *font;
};
@ -193,7 +192,7 @@ struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_int
struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, cff2_path_procs_path_t> {};
bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const
bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const
{
#ifdef HB_NO_OT_FONT_CFF
/* XXX Remove check when this code moves to .hh file. */
@ -206,10 +205,9 @@ bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, d
cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t> interp;
const byte_str_t str = (*charStrings)[glyph];
interp.env.init (str, *this, fd, font->coords, font->num_coords);
cff2_path_param_t param (font, draw_helper);
cff2_path_param_t param (font, draw_session);
if (unlikely (!interp.interpret (param))) return false;
return true;
}
#endif
#endif

View File

@ -515,9 +515,7 @@ struct cff2
HB_INTERNAL bool get_extents (hb_font_t *font,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents) const;
#ifdef HB_EXPERIMENTAL_API
HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const;
#endif
HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
};
typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t;

View File

@ -50,6 +50,21 @@ HB_BEGIN_DECLS
*/
#define HB_MATH_GLYPH_PART_FLAG_EXTENDER HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER
/* https://github.com/harfbuzz/harfbuzz/pull/3417 */
/**
* HB_OT_MATH_SCRIPT:
*
* Use #HB_SCRIPT_MATH or #HB_OT_TAG_MATH_SCRIPT instead.
*
* <note>Previous versions of this documentation recommended passing
* #HB_OT_MATH_SCRIPT to hb_buffer_set_script() to enable math shaping, but this
* usage is no longer supported. Use #HB_SCRIPT_MATH instead.</note>
*
* Since: 1.3.3
* Deprecated: 3.4.0
*/
#define HB_OT_MATH_SCRIPT HB_OT_TAG_MATH_SCRIPT
/* Like hb_ot_layout_table_find_script, but takes zero-terminated array of scripts to test */
HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) hb_bool_t

View File

@ -32,6 +32,11 @@
#define HB_OT_FACE_TABLE_LIST_HH
#endif /* HB_OT_FACE_TABLE_LIST_HH */ /* Dummy header guards */
#ifndef HB_OT_CORE_TABLE
#define HB_OT_CORE_TABLE(Namespace, Type) HB_OT_TABLE (Namespace, Type)
#define _HB_OT_CORE_TABLE_UNDEF
#endif
#ifndef HB_OT_ACCELERATOR
#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
#define _HB_OT_ACCELERATOR_UNDEF
@ -46,7 +51,8 @@
/* OpenType fundamentals. */
HB_OT_TABLE (OT, head)
HB_OT_CORE_TABLE (OT, head)
HB_OT_CORE_TABLE (OT, maxp)
#if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT)
HB_OT_ACCELERATOR (OT, cmap)
#endif
@ -74,6 +80,7 @@ HB_OT_TABLE (OT, VORG)
#endif
/* TrueType outlines. */
HB_OT_CORE_TABLE (OT, loca) // Also used to determine number of glyphs
HB_OT_ACCELERATOR (OT, glyf)
/* CFF outlines. */
@ -138,3 +145,7 @@ HB_OT_TABLE (OT, MATH)
#ifdef _HB_OT_ACCELERATOR_UNDEF
#undef HB_OT_ACCELERATOR
#endif
#ifdef _HB_OT_CORE_TABLE_UNDEF
#undef HB_OT_CORE_TABLE
#endif

View File

@ -63,10 +63,13 @@ struct hb_ot_face_t
hb_face_t *face; /* MUST be JUST before the lazy loaders. */
#define HB_OT_TABLE(Namespace, Type) \
hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type)> Type;
#define HB_OT_CORE_TABLE(Namespace, Type) \
hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type), true> Type;
#define HB_OT_ACCELERATOR(Namespace, Type) \
hb_face_lazy_loader_t<Namespace::Type##_accelerator_t, HB_OT_TABLE_ORDER (Namespace, Type)> Type;
#include "hb-ot-face-table-list.hh"
#undef HB_OT_ACCELERATOR
#undef HB_OT_CORE_TABLE
#undef HB_OT_TABLE
};

View File

@ -257,6 +257,23 @@ hb_ot_get_font_v_extents (hb_font_t *font,
}
#endif
#ifndef HB_NO_DRAW
static void
hb_ot_get_glyph_shape (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_draw_funcs_t *draw_funcs, void *draw_data,
void *user_data)
{
hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy);
if (font->face->table.glyf->get_path (font, glyph, draw_session)) return;
#ifndef HB_NO_CFF
if (font->face->table.cff1->get_path (font, glyph, draw_session)) return;
if (font->face->table.cff2->get_path (font, glyph, draw_session)) return;
#endif
}
#endif
static inline void free_static_ot_funcs ();
static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t>
@ -279,6 +296,10 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr);
#endif
#ifndef HB_NO_DRAW
hb_font_funcs_set_glyph_shape_func (funcs, hb_ot_get_glyph_shape, nullptr, nullptr);
#endif
hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr);
//hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr);

View File

@ -936,7 +936,7 @@ struct glyf
return;
short_offset = 0 == head.indexToLocFormat;
loca_table = hb_sanitize_context_t ().reference_table<loca> (face);
loca_table = face->table.loca.get_blob (); // Needs no destruct!
glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
#ifndef HB_NO_VAR
gvar = face->table.gvar;
@ -951,7 +951,6 @@ struct glyf
}
~accelerator_t ()
{
loca_table.destroy ();
glyf_table.destroy ();
}
@ -1152,11 +1151,10 @@ struct glyf
return operation_count;
}
#ifdef HB_EXPERIMENTAL_API
struct path_builder_t
{
hb_font_t *font;
draw_helper_t *draw_helper;
hb_draw_session_t *draw_session;
struct optional_point_t
{
@ -1171,10 +1169,10 @@ struct glyf
{ return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); }
} first_oncurve, first_offcurve, last_offcurve;
path_builder_t (hb_font_t *font_, draw_helper_t &draw_helper_)
path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_)
{
font = font_;
draw_helper = &draw_helper_;
draw_session = &draw_session_;
first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
}
@ -1184,10 +1182,6 @@ struct glyf
* https://stackoverflow.com/a/20772557 */
void consume_point (const contour_point_t &point)
{
/* Skip empty contours */
if (unlikely (point.is_end_point && !first_oncurve.has_data && !first_offcurve.has_data))
return;
bool is_on_curve = point.flag & Glyph::FLAG_ON_CURVE;
optional_point_t p (point.x, point.y);
if (!first_oncurve.has_data)
@ -1195,7 +1189,7 @@ struct glyf
if (is_on_curve)
{
first_oncurve = p;
draw_helper->move_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y));
draw_session->move_to (font->em_fscalef_x (p.x), font->em_fscalef_y (p.y));
}
else
{
@ -1204,7 +1198,7 @@ struct glyf
optional_point_t mid = first_offcurve.lerp (p, .5f);
first_oncurve = mid;
last_offcurve = p;
draw_helper->move_to (font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
draw_session->move_to (font->em_fscalef_x (mid.x), font->em_fscalef_y (mid.y));
}
else
first_offcurve = p;
@ -1216,22 +1210,22 @@ struct glyf
{
if (is_on_curve)
{
draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
font->em_scalef_x (p.x), font->em_scalef_y (p.y));
draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y),
font->em_fscalef_x (p.x), font->em_fscalef_y (p.y));
last_offcurve = optional_point_t ();
}
else
{
optional_point_t mid = last_offcurve.lerp (p, .5f);
draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y),
font->em_fscalef_x (mid.x), font->em_fscalef_y (mid.y));
last_offcurve = p;
}
}
else
{
if (is_on_curve)
draw_helper->line_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y));
draw_session->line_to (font->em_fscalef_x (p.x), font->em_fscalef_y (p.y));
else
last_offcurve = p;
}
@ -1242,24 +1236,30 @@ struct glyf
if (first_offcurve.has_data && last_offcurve.has_data)
{
optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f);
draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y),
font->em_fscalef_x (mid.x), font->em_fscalef_y (mid.y));
last_offcurve = optional_point_t ();
/* now check the rest */
}
if (first_offcurve.has_data && first_oncurve.has_data)
draw_helper->quadratic_to (font->em_scalef_x (first_offcurve.x), font->em_scalef_y (first_offcurve.y),
font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
draw_session->quadratic_to (font->em_fscalef_x (first_offcurve.x), font->em_fscalef_y (first_offcurve.y),
font->em_fscalef_x (first_oncurve.x), font->em_fscalef_y (first_oncurve.y));
else if (last_offcurve.has_data && first_oncurve.has_data)
draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y),
font->em_fscalef_x (first_oncurve.x), font->em_fscalef_y (first_oncurve.y));
else if (first_oncurve.has_data)
draw_helper->line_to (font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
draw_session->line_to (font->em_fscalef_x (first_oncurve.x), font->em_fscalef_y (first_oncurve.y));
else if (first_offcurve.has_data)
{
float x = font->em_fscalef_x (first_offcurve.x), y = font->em_fscalef_x (first_offcurve.y);
draw_session->move_to (x, y);
draw_session->quadratic_to (x, y, x, y);
}
/* Getting ready for the next contour */
first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
draw_helper->end_path ();
draw_session->close_path ();
}
}
void points_end () {}
@ -1269,9 +1269,8 @@ struct glyf
};
bool
get_path (hb_font_t *font, hb_codepoint_t gid, draw_helper_t &draw_helper) const
{ return get_points (font, gid, path_builder_t (font, draw_helper)); }
#endif
get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
{ return get_points (font, gid, path_builder_t (font, draw_session)); }
#ifndef HB_NO_VAR
const gvar_accelerator_t *gvar;

View File

@ -28,6 +28,7 @@
#define HB_OT_HMTX_TABLE_HH
#include "hb-open-type.hh"
#include "hb-ot-maxp-table.hh"
#include "hb-ot-hhea-table.hh"
#include "hb-ot-var-hvar-table.hh"
#include "hb-ot-metrics.hh"
@ -98,12 +99,12 @@ struct hmtxvmtx
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
Iterator it,
unsigned num_advances)
unsigned num_long_metrics)
{
unsigned idx = 0;
for (auto _ : it)
{
if (idx < num_advances)
if (idx < num_long_metrics)
{
LongMetric lm;
lm.advance = _.first;
@ -128,7 +129,19 @@ struct hmtxvmtx
if (unlikely (!table_prime)) return_trace (false);
accelerator_t _mtx (c->plan->source);
unsigned num_advances = _mtx.num_advances_for_subset (c->plan);
unsigned num_long_metrics;
{
/* Determine num_long_metrics to encode. */
auto& plan = c->plan;
num_long_metrics = plan->num_output_glyphs ();
hb_codepoint_t old_gid = 0;
unsigned int last_advance = plan->old_gid_for_new_gid (num_long_metrics - 1, &old_gid) ? _mtx.get_advance (old_gid) : 0;
while (num_long_metrics > 1 &&
last_advance == (plan->old_gid_for_new_gid (num_long_metrics - 2, &old_gid) ? _mtx.get_advance (old_gid) : 0))
{
num_long_metrics--;
}
}
auto it =
+ hb_range (c->plan->num_output_glyphs ())
@ -141,13 +154,13 @@ struct hmtxvmtx
})
;
table_prime->serialize (c->serializer, it, num_advances);
table_prime->serialize (c->serializer, it, num_long_metrics);
if (unlikely (c->serializer->in_error ()))
return_trace (false);
// Amend header num hmetrics
if (unlikely (!subset_update_header (c->plan, num_advances)))
if (unlikely (!subset_update_header (c->plan, num_long_metrics)))
return_trace (false);
return_trace (true);
@ -160,9 +173,18 @@ struct hmtxvmtx
accelerator_t (hb_face_t *face,
unsigned int default_advance_ = 0)
{
table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag);
default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face);
num_advances = T::is_horizontal ?
/* Populate count variables and sort them out as we go */
unsigned int len = table.get_length ();
if (len & 1)
len--;
num_long_metrics = T::is_horizontal ?
face->table.hhea->numberOfLongMetrics :
#ifndef HB_NO_VERTICAL
face->table.vhea->numberOfLongMetrics
@ -170,25 +192,27 @@ struct hmtxvmtx
0
#endif
;
if (unlikely (num_long_metrics * 4 > len))
num_long_metrics = len / 4;
len -= num_long_metrics * 4;
table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
num_bearings = face->table.maxp->get_num_glyphs ();
/* Cap num_metrics() and num_advances() based on table length. */
unsigned int len = table.get_length ();
if (unlikely (num_advances * 4 > len))
num_advances = len / 4;
num_metrics = num_advances + (len - 4 * num_advances) / 2;
if (unlikely (num_bearings < num_long_metrics))
num_bearings = num_long_metrics;
if (unlikely ((num_bearings - num_long_metrics) * 2 > len))
num_bearings = num_long_metrics + len / 2;
len -= (num_bearings - num_long_metrics) * 2;
/* We MUST set num_metrics to zero if num_advances is zero.
/* We MUST set num_bearings to zero if num_long_metrics is zero.
* Our get_advance() depends on that. */
if (unlikely (!num_advances))
{
num_metrics = num_advances = 0;
table.destroy ();
table = hb_blob_get_empty ();
}
if (unlikely (!num_long_metrics))
num_bearings = num_long_metrics = 0;
var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag);
num_advances = num_bearings + len / 2;
num_glyphs = face->get_num_glyphs ();
if (num_glyphs < num_advances)
num_glyphs = num_advances;
}
~accelerator_t ()
{
@ -198,14 +222,14 @@ struct hmtxvmtx
int get_side_bearing (hb_codepoint_t glyph) const
{
if (glyph < num_advances)
if (glyph < num_long_metrics)
return table->longMetricZ[glyph].sb;
if (unlikely (glyph >= num_metrics))
if (unlikely (glyph >= num_bearings))
return 0;
const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_advances];
return bearings[glyph - num_advances];
const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
return bearings[glyph - num_long_metrics];
}
int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const
@ -213,7 +237,7 @@ struct hmtxvmtx
int side_bearing = get_side_bearing (glyph);
#ifndef HB_NO_VAR
if (unlikely (glyph >= num_metrics) || !font->num_coords)
if (unlikely (glyph >= num_bearings) || !font->num_coords)
return side_bearing;
if (var_table.get_length ())
@ -227,18 +251,35 @@ struct hmtxvmtx
unsigned int get_advance (hb_codepoint_t glyph) const
{
if (unlikely (glyph >= num_metrics))
{
/* If num_metrics is zero, it means we don't have the metrics table
* for this direction: return default advance. Otherwise, it means that the
* glyph index is out of bound: return zero. */
if (num_metrics)
return 0;
else
return default_advance;
}
/* OpenType case. */
if (glyph < num_bearings)
return table->longMetricZ[hb_min (glyph, (uint32_t) num_long_metrics - 1)].advance;
return table->longMetricZ[hb_min (glyph, (uint32_t) num_advances - 1)].advance;
/* If num_advances is zero, it means we don't have the metrics table
* for this direction: return default advance. Otherwise, there's a
* well-defined answer. */
if (unlikely (!num_advances))
return default_advance;
#ifdef HB_NO_BORING_EXPANSION
return 0;
#endif
if (unlikely (glyph >= num_glyphs))
return 0;
/* num_bearings <= glyph < num_glyphs;
* num_bearings <= num_advances */
/* TODO Optimize */
if (num_bearings == num_advances)
return get_advance (num_bearings - 1);
const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics];
return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)];
}
unsigned int get_advance (hb_codepoint_t glyph,
@ -247,7 +288,7 @@ struct hmtxvmtx
unsigned int advance = get_advance (glyph);
#ifndef HB_NO_VAR
if (unlikely (glyph >= num_metrics) || !font->num_coords)
if (unlikely (glyph >= num_bearings) || !font->num_coords)
return advance;
if (var_table.get_length ())
@ -259,35 +300,13 @@ struct hmtxvmtx
#endif
}
unsigned int num_advances_for_subset (const hb_subset_plan_t *plan) const
{
unsigned int num_advances = plan->num_output_glyphs ();
unsigned int last_advance = _advance_for_new_gid (plan,
num_advances - 1);
while (num_advances > 1 &&
last_advance == _advance_for_new_gid (plan,
num_advances - 2))
{
num_advances--;
}
return num_advances;
}
private:
unsigned int _advance_for_new_gid (const hb_subset_plan_t *plan,
hb_codepoint_t new_gid) const
{
hb_codepoint_t old_gid;
if (!plan->old_gid_for_new_gid (new_gid, &old_gid))
return 0;
return get_advance (old_gid);
}
protected:
unsigned int num_metrics;
unsigned int num_advances;
// 0 <= num_long_metrics <= num_bearings <= num_advances <= num_glyphs
unsigned num_long_metrics;
unsigned num_bearings;
unsigned num_advances;
unsigned num_glyphs;
unsigned int default_advance;
private:
@ -319,6 +338,8 @@ struct hmtxvmtx
* the end. This allows a monospaced
* font to vary the side bearing
* values for each glyph. */
/*UnsizedArrayOf<UFWORD>advancesX;*/
/* TODO Document. */
public:
DEFINE_SIZE_ARRAY (0, longMetricZ);
};

View File

@ -361,6 +361,13 @@ hb_ot_layout_get_attach_points (hb_face_t *face,
* Fetches a list of the caret positions defined for a ligature glyph in the GDEF
* table of the font. The list returned will begin at the offset provided.
*
* Note that a ligature that is formed from n characters will have n-1
* caret positions. The first character is not represented in the array,
* since its caret position is the glyph position.
*
* The positions returned by this function are 'unshaped', and will have to
* be fixed up for kerning that may be applied to the ligature glyph.
*
* Return value: Total number of ligature caret positions for @glyph.
*
**/
@ -1959,6 +1966,77 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
}
#ifndef HB_NO_BASE
/**
* hb_ot_layout_get_horizontal_baseline_tag_for_script:
* @script: a script tag.
*
* Fetches the dominant horizontal baseline tag used by @script.
*
* Return value: dominant baseline tag for the @script.
*
* Since: 4.0.0
**/
hb_ot_layout_baseline_tag_t
hb_ot_layout_get_horizontal_baseline_tag_for_script (hb_script_t script)
{
/* Keep in sync with hb_ot_layout_get_baseline_with_fallback */
switch ((int) script)
{
/* Unicode-1.1 additions */
case HB_SCRIPT_BENGALI:
case HB_SCRIPT_DEVANAGARI:
case HB_SCRIPT_GUJARATI:
case HB_SCRIPT_GURMUKHI:
/* Unicode-2.0 additions */
case HB_SCRIPT_TIBETAN:
/* Unicode-4.0 additions */
case HB_SCRIPT_LIMBU:
/* Unicode-4.1 additions */
case HB_SCRIPT_SYLOTI_NAGRI:
/* Unicode-5.0 additions */
case HB_SCRIPT_PHAGS_PA:
/* Unicode-5.2 additions */
case HB_SCRIPT_MEETEI_MAYEK:
/* Unicode-6.1 additions */
case HB_SCRIPT_SHARADA:
case HB_SCRIPT_TAKRI:
/* Unicode-7.0 additions */
case HB_SCRIPT_MODI:
case HB_SCRIPT_SIDDHAM:
case HB_SCRIPT_TIRHUTA:
/* Unicode-9.0 additions */
case HB_SCRIPT_MARCHEN:
case HB_SCRIPT_NEWA:
/* Unicode-10.0 additions */
case HB_SCRIPT_SOYOMBO:
case HB_SCRIPT_ZANABAZAR_SQUARE:
/* Unicode-11.0 additions */
case HB_SCRIPT_DOGRA:
case HB_SCRIPT_GUNJALA_GONDI:
/* Unicode-12.0 additions */
case HB_SCRIPT_NANDINAGARI:
return HB_OT_LAYOUT_BASELINE_TAG_HANGING;
/* Unicode-1.1 additions */
case HB_SCRIPT_HANGUL:
case HB_SCRIPT_HAN:
case HB_SCRIPT_HIRAGANA:
case HB_SCRIPT_KATAKANA:
/* Unicode-3.0 additions */
case HB_SCRIPT_BOPOMOFO:
/* Unicode-9.0 additions */
case HB_SCRIPT_TANGUT:
/* Unicode-10.0 additions */
case HB_SCRIPT_NUSHU:
/* Unicode-13.0 additions */
case HB_SCRIPT_KHITAN_SMALL_SCRIPT:
return HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT;
default:
return HB_OT_LAYOUT_BASELINE_TAG_ROMAN;
}
}
/**
* hb_ot_layout_get_baseline:
* @font: a font
@ -1966,7 +2044,7 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
* @direction: text direction.
* @script_tag: script tag.
* @language_tag: language tag, currently unused.
* @coord: (out): baseline value if found.
* @coord: (out) (nullable): baseline value if found.
*
* Fetches a baseline value from the face.
*
@ -1989,6 +2067,227 @@ hb_ot_layout_get_baseline (hb_font_t *font,
return result;
}
/**
* hb_ot_layout_get_baseline_with_fallback:
* @font: a font
* @baseline_tag: a baseline tag
* @direction: text direction.
* @script_tag: script tag.
* @language_tag: language tag, currently unused.
* @coord: (out): baseline value if found.
*
* Fetches a baseline value from the face, and synthesizes
* it if the font does not have it.
*
* Since: 4.0.0
**/
void
hb_ot_layout_get_baseline_with_fallback (hb_font_t *font,
hb_ot_layout_baseline_tag_t baseline_tag,
hb_direction_t direction,
hb_tag_t script_tag,
hb_tag_t language_tag,
hb_position_t *coord /* OUT */)
{
if (hb_ot_layout_get_baseline (font,
baseline_tag,
direction,
script_tag,
language_tag,
coord))
return;
/* Synthesize missing baselines.
* See https://www.w3.org/TR/css-inline-3/#baseline-synthesis-fonts
*/
switch (baseline_tag)
{
case HB_OT_LAYOUT_BASELINE_TAG_ROMAN:
*coord = 0; // FIXME origin ?
break;
case HB_OT_LAYOUT_BASELINE_TAG_MATH:
{
hb_codepoint_t glyph;
hb_glyph_extents_t extents;
if (HB_DIRECTION_IS_HORIZONTAL (direction) &&
(hb_font_get_nominal_glyph (font, 0x2212u, &glyph) ||
hb_font_get_nominal_glyph (font, '-', &glyph)) &&
hb_font_get_glyph_extents (font, glyph, &extents))
{
*coord = extents.y_bearing + extents.height / 2;
}
else
{
hb_position_t x_height = 0;
hb_ot_metrics_get_position (font, HB_OT_METRICS_TAG_X_HEIGHT, &x_height);
*coord = x_height / 2;
}
}
break;
case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT:
case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT:
{
hb_position_t embox_top, embox_bottom;
hb_ot_layout_get_baseline_with_fallback (font,
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
direction,
script_tag,
language_tag,
&embox_top);
hb_ot_layout_get_baseline_with_fallback (font,
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
direction,
script_tag,
language_tag,
&embox_bottom);
if (baseline_tag == HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT)
*coord = embox_top + (embox_bottom - embox_top) / 10;
else
*coord = embox_bottom + (embox_top - embox_bottom) / 10;
}
break;
case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT:
if (hb_ot_layout_get_baseline (font,
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
direction,
script_tag,
language_tag,
coord))
*coord += HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale;
else
{
hb_font_extents_t font_extents;
hb_font_get_extents_for_direction (font, direction, &font_extents);
*coord = font_extents.ascender;
}
break;
case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT:
if (hb_ot_layout_get_baseline (font,
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
direction,
script_tag,
language_tag,
coord))
*coord -= HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale;
else
{
hb_font_extents_t font_extents;
hb_font_get_extents_for_direction (font, direction, &font_extents);
*coord = font_extents.descender;
}
break;
case HB_OT_LAYOUT_BASELINE_TAG_HANGING:
if (HB_DIRECTION_IS_HORIZONTAL (direction))
{
hb_codepoint_t ch;
hb_codepoint_t glyph;
hb_glyph_extents_t extents;
/* Keep in sync with hb_ot_layout_get_horizontal_baseline_for_script */
switch ((int) script_tag)
{
/* Unicode-1.1 additions */
case HB_SCRIPT_BENGALI: ch = 0x0995u; break;
case HB_SCRIPT_DEVANAGARI: ch = 0x0915u; break;
case HB_SCRIPT_GUJARATI: ch = 0x0a95u; break;
case HB_SCRIPT_GURMUKHI: ch = 0x0a15u; break;
/* Unicode-2.0 additions */
case HB_SCRIPT_TIBETAN: ch = 0x0f40u; break;
/* Unicode-4.0 additions */
case HB_SCRIPT_LIMBU: ch = 0x1901u; break;
/* Unicode-4.1 additions */
case HB_SCRIPT_SYLOTI_NAGRI: ch = 0xa807u; break;
/* Unicode-5.0 additions */
case HB_SCRIPT_PHAGS_PA: ch = 0xa840u; break;
/* Unicode-5.2 additions */
case HB_SCRIPT_MEETEI_MAYEK: ch = 0xabc0u; break;
/* Unicode-6.1 additions */
case HB_SCRIPT_SHARADA: ch = 0x11191u; break;
case HB_SCRIPT_TAKRI: ch = 0x1168cu; break;
/* Unicode-7.0 additions */
case HB_SCRIPT_MODI: ch = 0x1160eu;break;
case HB_SCRIPT_SIDDHAM: ch = 0x11590u; break;
case HB_SCRIPT_TIRHUTA: ch = 0x1148fu; break;
/* Unicode-9.0 additions */
case HB_SCRIPT_MARCHEN: ch = 0x11c72u; break;
case HB_SCRIPT_NEWA: ch = 0x1140eu; break;
/* Unicode-10.0 additions */
case HB_SCRIPT_SOYOMBO: ch = 0x11a5cu; break;
case HB_SCRIPT_ZANABAZAR_SQUARE: ch = 0x11a0bu; break;
/* Unicode-11.0 additions */
case HB_SCRIPT_DOGRA: ch = 0x1180au; break;
case HB_SCRIPT_GUNJALA_GONDI: ch = 0x11d6cu; break;
/* Unicode-12.0 additions */
case HB_SCRIPT_NANDINAGARI: ch = 0x119b0u; break;
default: ch = 0; break;
}
if (ch &&
hb_font_get_nominal_glyph (font, ch, &glyph) &&
hb_font_get_glyph_extents (font, glyph, &extents))
*coord = extents.y_bearing;
else
*coord = font->y_scale * 6 / 10; // FIXME makes assumptions about origin
}
else
*coord = font->x_scale * 6 / 10; // FIXME makes assumptions about origin
break;
case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL:
{
hb_position_t top, bottom;
hb_ot_layout_get_baseline_with_fallback (font,
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
direction,
script_tag,
language_tag,
&top);
hb_ot_layout_get_baseline_with_fallback (font,
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
direction,
script_tag,
language_tag,
&bottom);
*coord = (top + bottom) / 2;
}
break;
case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL:
{
hb_position_t top, bottom;
hb_ot_layout_get_baseline_with_fallback (font,
HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT,
direction,
script_tag,
language_tag,
&top);
hb_ot_layout_get_baseline_with_fallback (font,
HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT,
direction,
script_tag,
language_tag,
&bottom);
*coord = (top + bottom) / 2;
}
break;
case _HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE:
default:
*coord = 0;
break;
}
}
#endif

View File

@ -332,31 +332,6 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
hb_set_t *glyphs_after, /* OUT. May be NULL */
hb_set_t *glyphs_output /* OUT. May be NULL */);
#ifdef HB_NOT_IMPLEMENTED
typedef struct
{
const hb_codepoint_t *before,
unsigned int before_length,
const hb_codepoint_t *input,
unsigned int input_length,
const hb_codepoint_t *after,
unsigned int after_length,
} hb_ot_layout_glyph_sequence_t;
typedef hb_bool_t
(*hb_ot_layout_glyph_sequence_func_t) (hb_font_t *font,
hb_tag_t table_tag,
unsigned int lookup_index,
const hb_ot_layout_glyph_sequence_t *sequence,
void *user_data);
HB_EXTERN void
Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t *face,
hb_tag_t table_tag,
unsigned int lookup_index,
hb_ot_layout_glyph_sequence_func_t callback,
void *user_data);
#endif
/* Variations support */
@ -411,19 +386,6 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
hb_set_t *glyphs);
#ifdef HB_NOT_IMPLEMENTED
/* Note: You better have GDEF when using this API, or marks won't do much. */
HB_EXTERN hb_bool_t
Xhb_ot_layout_lookup_substitute (hb_font_t *font,
unsigned int lookup_index,
const hb_ot_layout_glyph_sequence_t *sequence,
unsigned int out_size,
hb_codepoint_t *glyphs_out, /* OUT */
unsigned int *clusters_out, /* OUT */
unsigned int *out_length /* OUT */);
#endif
/*
* GPOS
*/
@ -431,15 +393,6 @@ Xhb_ot_layout_lookup_substitute (hb_font_t *font,
HB_EXTERN hb_bool_t
hb_ot_layout_has_positioning (hb_face_t *face);
#ifdef HB_NOT_IMPLEMENTED
/* Note: You better have GDEF when using this API, or marks won't do much. */
HB_EXTERN hb_bool_t
Xhb_ot_layout_lookup_position (hb_font_t *font,
unsigned int lookup_index,
const hb_ot_layout_glyph_sequence_t *sequence,
hb_glyph_position_t *positions /* IN / OUT */);
#endif
/* Optical 'size' feature info. Returns true if found.
* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
HB_EXTERN hb_bool_t
@ -487,9 +440,11 @@ hb_ot_layout_feature_get_characters (hb_face_t *face,
* if the direction is horizontal or vertical, respectively.
* @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT: Ideographic character face top or right edge,
* if the direction is horizontal or vertical, respectively.
* @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL: The center of the ideographic character face. Since: 4.0.0
* @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT: Ideographic em-box bottom or left edge,
* if the direction is horizontal or vertical, respectively.
* @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT: Ideographic em-box top or right edge baseline,
* @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL: The center of the ideographic em-box. Since: 4.0.0
* if the direction is horizontal or vertical, respectively.
* @HB_OT_LAYOUT_BASELINE_TAG_MATH: The baseline about which mathematical characters are centered.
* In vertical writing mode when mathematical characters rotated 90 degrees clockwise, are centered.
@ -503,14 +458,19 @@ typedef enum {
HB_OT_LAYOUT_BASELINE_TAG_HANGING = HB_TAG ('h','a','n','g'),
HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT = HB_TAG ('i','c','f','b'),
HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT = HB_TAG ('i','c','f','t'),
HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL = HB_TAG ('I','c','f','c'),
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT = HB_TAG ('i','d','e','o'),
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT = HB_TAG ('i','d','t','p'),
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL = HB_TAG ('I','d','c','e'),
HB_OT_LAYOUT_BASELINE_TAG_MATH = HB_TAG ('m','a','t','h'),
/*< private >*/
_HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_ot_layout_baseline_tag_t;
HB_EXTERN hb_ot_layout_baseline_tag_t
hb_ot_layout_get_horizontal_baseline_tag_for_script (hb_script_t script);
HB_EXTERN hb_bool_t
hb_ot_layout_get_baseline (hb_font_t *font,
hb_ot_layout_baseline_tag_t baseline_tag,
@ -519,6 +479,14 @@ hb_ot_layout_get_baseline (hb_font_t *font,
hb_tag_t language_tag,
hb_position_t *coord /* OUT. May be NULL. */);
HB_EXTERN void
hb_ot_layout_get_baseline_with_fallback (hb_font_t *font,
hb_ot_layout_baseline_tag_t baseline_tag,
hb_direction_t direction,
hb_tag_t script_tag,
hb_tag_t language_tag,
hb_position_t *coord /* OUT */);
HB_END_DECLS
#endif /* HB_OT_LAYOUT_H */

View File

@ -369,6 +369,37 @@ struct MathKern
return kernValue[i].get_x_value (font, this);
}
unsigned int get_entries (unsigned int start_offset,
unsigned int *entries_count, /* IN/OUT */
hb_ot_math_kern_entry_t *kern_entries, /* OUT */
hb_font_t *font) const
{
const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
const unsigned int entriesCount = heightCount + 1;
if (entries_count)
{
unsigned int start = hb_min (start_offset, entriesCount);
unsigned int end = hb_min (start + *entries_count, entriesCount);
*entries_count = end - start;
for (unsigned int i = 0; i < *entries_count; i++) {
unsigned int j = start + i;
hb_position_t max_height;
if (j == heightCount) {
max_height = INT32_MAX;
} else {
max_height = correctionHeight[j].get_y_value (font, this);
}
kern_entries[i] = {max_height, kernValue[j].get_x_value (font, this)};
}
}
return entriesCount;
}
protected:
HBUINT16 heightCount;
UnsizedArrayOf<MathValueRecord>
@ -423,6 +454,24 @@ struct MathKernInfoRecord
return (base+mathKern[idx]).get_value (correction_height, font);
}
unsigned int get_kernings (hb_ot_math_kern_t kern,
unsigned int start_offset,
unsigned int *entries_count, /* IN/OUT */
hb_ot_math_kern_entry_t *kern_entries, /* OUT */
hb_font_t *font,
const void *base) const
{
unsigned int idx = kern;
if (unlikely (idx >= ARRAY_LENGTH (mathKern)) || !mathKern[idx]) {
if (entries_count) *entries_count = 0;
return 0;
}
return (base+mathKern[idx]).get_entries (start_offset,
entries_count,
kern_entries,
font);
}
protected:
/* Offset to MathKern table for each corner -
* from the beginning of MathKernInfo table. May be NULL. */
@ -473,6 +522,22 @@ struct MathKernInfo
return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this);
}
unsigned int get_kernings (hb_codepoint_t glyph,
hb_ot_math_kern_t kern,
unsigned int start_offset,
unsigned int *entries_count, /* IN/OUT */
hb_ot_math_kern_entry_t *kern_entries, /* OUT */
hb_font_t *font) const
{
unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
return mathKernInfoRecords[index].get_kernings (kern,
start_offset,
entries_count,
kern_entries,
font,
this);
}
protected:
Offset16To<Coverage>
mathKernCoverage;
@ -545,6 +610,19 @@ struct MathGlyphInfo
hb_font_t *font) const
{ return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); }
hb_position_t get_kernings (hb_codepoint_t glyph,
hb_ot_math_kern_t kern,
unsigned int start_offset,
unsigned int *entries_count, /* IN/OUT */
hb_ot_math_kern_entry_t *kern_entries, /* OUT */
hb_font_t *font) const
{ return (this+mathKernInfo).get_kernings (glyph,
kern,
start_offset,
entries_count,
kern_entries,
font); }
protected:
/* Offset to MathItalicsCorrectionInfo table -
* from the beginning of MathGlyphInfo table. */

View File

@ -184,6 +184,51 @@ hb_ot_math_get_glyph_kerning (hb_font_t *font,
font);
}
/**
* hb_ot_math_get_glyph_kernings:
* @font: #hb_font_t to work upon
* @glyph: The glyph index from which to retrieve the kernings
* @kern: The #hb_ot_math_kern_t from which to retrieve the kernings
* @start_offset: offset of the first kern entry to retrieve
* @entries_count: (inout) (optional): Input = the maximum number of kern entries to return;
* Output = the actual number of kern entries returned
* @kern_entries: (out caller-allocates) (array length=entries_count): array of kern entries returned
*
* Fetches the raw MathKern (cut-in) data for the specified font, glyph index,
* and @kern. The corresponding list of kern values and correction heights is
* returned as a list of #hb_ot_math_kern_entry_t structs.
*
* See also #hb_ot_math_get_glyph_kerning, which handles selecting the
* appropriate kern value for a given correction height.
*
* <note>For a glyph with @n defined kern values (where @n > 0), there are only
* @n1 defined correction heights, as each correction height defines a boundary
* past which the next kern value should be selected. Therefore, only the
* #hb_ot_math_kern_entry_t.kern_value of the uppermost #hb_ot_math_kern_entry_t
* actually comes from the font; its corresponding
* #hb_ot_math_kern_entry_t.max_correction_height is always set to
* <code>INT32_MAX</code>.</note>
*
* Return value: the total number of kern values available or zero
*
* Since: 3.4.0
**/
unsigned int
hb_ot_math_get_glyph_kernings (hb_font_t *font,
hb_codepoint_t glyph,
hb_ot_math_kern_t kern,
unsigned int start_offset,
unsigned int *entries_count, /* IN/OUT */
hb_ot_math_kern_entry_t *kern_entries /* OUT */)
{
return font->face->table.MATH->get_glyph_info().get_kernings (glyph,
kern,
start_offset,
entries_count,
kern_entries,
font);
}
/**
* hb_ot_math_get_glyph_variants:
* @font: #hb_font_t to work upon

View File

@ -50,14 +50,18 @@ HB_BEGIN_DECLS
#define HB_OT_TAG_MATH HB_TAG('M','A','T','H')
/**
* HB_OT_MATH_SCRIPT:
* HB_OT_TAG_MATH_SCRIPT:
*
* OpenType script tag for math shaping, for use with
* Use with hb_buffer_set_script().
* OpenType script tag, `math`, for features specific to math shaping.
*
* Since: 1.3.3
* <note>#HB_OT_TAG_MATH_SCRIPT is not a valid #hb_script_t and should only be
* used with functions that accept raw OpenType script tags, such as
* #hb_ot_layout_collect_features. In other cases, #HB_SCRIPT_MATH should be
* used instead.</note>
*
* Since: 3.4.0
*/
#define HB_OT_MATH_SCRIPT HB_TAG('m','a','t','h')
#define HB_OT_TAG_MATH_SCRIPT HB_TAG('m','a','t','h')
/* Types */
@ -204,6 +208,20 @@ typedef enum {
HB_OT_MATH_KERN_BOTTOM_LEFT = 3
} hb_ot_math_kern_t;
/**
* hb_ot_math_kern_entry_t:
* @max_correction_height: The maximum height at which this entry should be used
* @kern_value: The kern value of the entry
*
* Data type to hold math kerning (cut-in) information for a glyph.
*
* Since: 3.4.0
*/
typedef struct {
hb_position_t max_correction_height;
hb_position_t kern_value;
} hb_ot_math_kern_entry_t;
/**
* hb_ot_math_glyph_variant_t:
* @glyph: The glyph index of the variant
@ -280,6 +298,14 @@ hb_ot_math_get_glyph_kerning (hb_font_t *font,
hb_ot_math_kern_t kern,
hb_position_t correction_height);
HB_EXTERN unsigned int
hb_ot_math_get_glyph_kernings (hb_font_t *font,
hb_codepoint_t glyph,
hb_ot_math_kern_t kern,
unsigned int start_offset,
unsigned int *entries_count, /* IN/OUT */
hb_ot_math_kern_entry_t *kern_entries /* OUT */);
HB_EXTERN unsigned int
hb_ot_math_get_glyph_variants (hb_font_t *font,
hb_codepoint_t glyph,

View File

@ -238,6 +238,145 @@ hb_ot_metrics_get_position (hb_font_t *font,
}
}
/**
* hb_ot_metrics_get_position_with_fallback:
* @font: an #hb_font_t object.
* @metrics_tag: tag of metrics value you like to fetch.
* @position: (out) (optional): result of metrics value from the font.
*
* Fetches metrics value corresponding to @metrics_tag from @font,
* and synthesizes a value if it the value is missing in the font.
*
* Since: 4.0.0
**/
void
hb_ot_metrics_get_position_with_fallback (hb_font_t *font,
hb_ot_metrics_tag_t metrics_tag,
hb_position_t *position /* OUT */)
{
hb_font_extents_t font_extents;
hb_codepoint_t glyph;
hb_glyph_extents_t extents;
if (hb_ot_metrics_get_position (font, metrics_tag, position))
{
if ((metrics_tag != HB_OT_METRICS_TAG_STRIKEOUT_SIZE &&
metrics_tag != HB_OT_METRICS_TAG_UNDERLINE_SIZE) ||
*position != 0)
return;
}
switch (metrics_tag)
{
case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER:
case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT:
hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
*position = font_extents.ascender;
break;
case HB_OT_METRICS_TAG_VERTICAL_ASCENDER:
hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents);
*position = font_extents.ascender;
break;
case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER:
case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT:
hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
*position = font_extents.descender;
break;
case HB_OT_METRICS_TAG_VERTICAL_DESCENDER:
hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents);
*position = font_extents.ascender;
break;
case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP:
hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
*position = font_extents.line_gap;
break;
case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP:
hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents);
*position = font_extents.line_gap;
break;
case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE:
case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE:
*position = 1;
break;
case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN:
case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN:
*position = 0;
break;
case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET:
case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET:
*position = 0;
break;
case HB_OT_METRICS_TAG_X_HEIGHT:
if (hb_font_get_nominal_glyph (font, 'o', &glyph) &&
hb_font_get_glyph_extents (font, glyph, &extents))
*position = extents.height + 2 * extents.y_bearing;
else
*position = font->y_scale / 2;
break;
case HB_OT_METRICS_TAG_CAP_HEIGHT:
if (hb_font_get_nominal_glyph (font, 'O', &glyph) &&
hb_font_get_glyph_extents (font, glyph, &extents))
*position = extents.height + 2 * extents.y_bearing;
else
*position = font->y_scale * 2 / 3;
break;
case HB_OT_METRICS_TAG_STRIKEOUT_SIZE:
case HB_OT_METRICS_TAG_UNDERLINE_SIZE:
*position = font->y_scale / 18;
break;
case HB_OT_METRICS_TAG_STRIKEOUT_OFFSET:
{
hb_position_t ascender;
hb_ot_metrics_get_position_with_fallback (font,
HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER,
&ascender);
*position = ascender / 2;
}
break;
case HB_OT_METRICS_TAG_UNDERLINE_OFFSET:
*position = - font->y_scale / 18;
break;
case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE:
case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE:
*position = font->x_scale * 10 / 12;
break;
case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE:
case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE:
*position = font->y_scale * 10 / 12;
break;
case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET:
case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET:
*position = 0;
break;
case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET:
case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET:
*position = font->y_scale / 5;
break;
case _HB_OT_METRICS_TAG_MAX_VALUE:
default:
*position = 0;
break;
}
}
#ifndef HB_NO_VAR
/**
* hb_ot_metrics_get_variation:

View File

@ -110,6 +110,11 @@ hb_ot_metrics_get_position (hb_font_t *font,
hb_ot_metrics_tag_t metrics_tag,
hb_position_t *position /* OUT. May be NULL. */);
HB_EXTERN void
hb_ot_metrics_get_position_with_fallback (hb_font_t *font,
hb_ot_metrics_tag_t metrics_tag,
hb_position_t *position /* OUT */);
HB_EXTERN float
hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag);

View File

@ -52,7 +52,7 @@
* array is owned by the @face and should not be modified. It can be
* used as long as @face is alive.
*
* Returns: (out) (transfer none) (array length=num_entries): Array of available name entries.
* Returns: (transfer none) (array length=num_entries): Array of available name entries.
* Since: 2.1.0
**/
const hb_ot_name_entry_t *

View File

@ -635,6 +635,11 @@ modifier_combining_marks[] =
0x06E3u, /* ARABIC SMALL LOW SEEN */
0x06E7u, /* ARABIC SMALL HIGH YEH */
0x06E8u, /* ARABIC SMALL HIGH NOON */
0x08CAu, /* ARABIC SMALL HIGH FARSI YEH */
0x08CBu, /* ARABIC SMALL HIGH YEH BARREE WITH TWO DOTS BELOW */
0x08CDu, /* ARABIC SMALL HIGH ZAH */
0x08CEu, /* ARABIC LARGE ROUND DOT ABOVE */
0x08CFu, /* ARABIC LARGE ROUND DOT BELOW */
0x08D3u, /* ARABIC SMALL LOW WAW */
0x08F3u, /* ARABIC SMALL HIGH WAW */
};

View File

@ -385,7 +385,9 @@ struct machine_index_t :
typename Iter::item_t>
{
machine_index_t (const Iter& it) : it (it) {}
machine_index_t (const machine_index_t& o) : it (o.it) {}
machine_index_t (const machine_index_t& o) : hb_iter_with_fallback_t<machine_index_t<Iter>,
typename Iter::item_t> (),
it (o.it) {}
static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;

View File

@ -497,14 +497,14 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
#endif
#ifndef HB_DISABLE_DEPRECATED
if (!buffer->message (font, "start fallback kern"))
return;
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ?
!font->has_glyph_h_kerning_func () :
!font->has_glyph_v_kerning_func ())
return;
if (!buffer->message (font, "start fallback kern"))
return;
bool reverse = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
if (reverse)

View File

@ -41,6 +41,7 @@ hb_ot_old_tag_from_script (hb_script_t script)
switch ((hb_tag_t) script)
{
case HB_SCRIPT_INVALID: return HB_OT_TAG_DEFAULT_SCRIPT;
case HB_SCRIPT_MATH: return HB_OT_TAG_MATH_SCRIPT;
/* KATAKANA and HIRAGANA both map to 'kana' */
case HB_SCRIPT_HIRAGANA: return HB_TAG('k','a','n','a');
@ -63,6 +64,8 @@ hb_ot_old_tag_to_script (hb_tag_t tag)
{
if (unlikely (tag == HB_OT_TAG_DEFAULT_SCRIPT))
return HB_SCRIPT_INVALID;
if (unlikely (tag == HB_OT_TAG_MATH_SCRIPT))
return HB_SCRIPT_MATH;
/* This side of the conversion is fully algorithmic. */

View File

@ -126,6 +126,13 @@ hb_shape_full (hb_font_t *font,
unsigned int num_features,
const char * const *shaper_list)
{
hb_buffer_t *text_buffer = nullptr;
if (buffer->flags & HB_BUFFER_FLAG_VERIFY)
{
text_buffer = hb_buffer_create ();
hb_buffer_append (text_buffer, buffer, 0, -1);
}
hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached2 (font->face, &buffer->props,
features, num_features,
font->coords, font->num_coords,
@ -133,6 +140,17 @@ hb_shape_full (hb_font_t *font,
hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
hb_shape_plan_destroy (shape_plan);
if (text_buffer)
{
if (res && !buffer->verify (text_buffer,
font,
features,
num_features,
shaper_list))
res = false;
hb_buffer_destroy (text_buffer);
}
return res;
}

View File

@ -33,6 +33,7 @@
#include "hb-aat-layout-feat-table.hh"
#include "hb-ot-layout-common.hh"
#include "hb-ot-cmap-table.hh"
#include "hb-ot-glyf-table.hh"
#include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh"
@ -55,17 +56,41 @@ const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF};
/* hb_face_t */
static inline unsigned
load_num_glyphs_from_loca (const hb_face_t *face)
{
unsigned ret = 0;
unsigned indexToLocFormat = face->table.head->indexToLocFormat;
if (indexToLocFormat <= 1)
{
bool short_offset = 0 == indexToLocFormat;
hb_blob_t *loca_blob = face->table.loca.get_blob ();
ret = hb_max (1u, loca_blob->length / (short_offset ? 2 : 4)) - 1;
}
return ret;
}
static inline unsigned
load_num_glyphs_from_maxp (const hb_face_t *face)
{
return face->table.maxp->get_num_glyphs ();
}
unsigned int
hb_face_t::load_num_glyphs () const
{
hb_sanitize_context_t c = hb_sanitize_context_t ();
c.set_num_glyphs (0); /* So we don't recurse ad infinitum. */
hb_blob_t *maxp_blob = c.reference_table<OT::maxp> (this);
const OT::maxp *maxp_table = maxp_blob->as<OT::maxp> ();
unsigned ret = 0;
#ifndef HB_NO_BORING_EXPANSION
ret = hb_max (ret, load_num_glyphs_from_loca (this));
#endif
ret = hb_max (ret, load_num_glyphs_from_maxp (this));
unsigned int ret = maxp_table->get_num_glyphs ();
num_glyphs.set_relaxed (ret);
hb_blob_destroy (maxp_blob);
return ret;
}

View File

@ -46,13 +46,13 @@
static inline float
_hb_angle_to_ratio (float a)
{
return tanf (a * float (M_PI / 180.));
return tanf (a * float (-M_PI / 180.));
}
static inline float
_hb_ratio_to_angle (float r)
{
return atanf (r) * float (180. / M_PI);
return atanf (r) * float (-180. / M_PI);
}
/**
@ -72,8 +72,7 @@ float
hb_style_get_value (hb_font_t *font, hb_style_tag_t style_tag)
{
if (unlikely (style_tag == HB_STYLE_TAG_SLANT_RATIO))
return _hb_angle_to_ratio (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE))
+ font->slant;
return _hb_angle_to_ratio (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE));
hb_face_t *face = font->face;

View File

@ -43,8 +43,10 @@ HB_BEGIN_DECLS
* @HB_STYLE_TAG_SLANT_ANGLE: Used to vary between upright and slanted text. Values
* must be greater than -90 and less than +90. Values can be interpreted as
* the angle, in counter-clockwise degrees, of oblique slant from whatever the
* designer considers to be upright for that font design.
* designer considers to be upright for that font design. Typical right-leaning
* Italic fonts have a negative slant angle (typically around -12)
* @HB_STYLE_TAG_SLANT_RATIO: same as @HB_STYLE_TAG_SLANT_ANGLE expression as ratio.
* Typical right-leaning Italic fonts have a positive slant ratio (typically around 0.2)
* @HB_STYLE_TAG_WIDTH: Used to vary width of text from narrower to wider.
* Non-zero. Values can be interpreted as a percentage of whatever the font
* designer considers normal width for that font design.

View File

@ -458,7 +458,7 @@ _nameid_closure (hb_face_t *face,
}
/**
* hb_subset_plan_create:
* hb_subset_plan_create_or_fail:
* @face: font face to create the plan for.
* @input: a #hb_subset_input_t input.
*
@ -467,17 +467,18 @@ _nameid_closure (hb_face_t *face,
* which tables and glyphs should be retained.
*
* Return value: (transfer full): New subset plan. Destroy with
* hb_subset_plan_destroy().
* hb_subset_plan_destroy(). If there is a failure creating the plan
* nullptr will be returned.
*
* Since: 1.7.5
* Since: 4.0.0
**/
hb_subset_plan_t *
hb_subset_plan_create (hb_face_t *face,
hb_subset_plan_create_or_fail (hb_face_t *face,
const hb_subset_input_t *input)
{
hb_subset_plan_t *plan;
if (unlikely (!(plan = hb_object_create<hb_subset_plan_t> ())))
return const_cast<hb_subset_plan_t *> (&Null (hb_subset_plan_t));
return nullptr;
plan->successful = true;
plan->flags = input->flags;
@ -514,8 +515,9 @@ hb_subset_plan_create (hb_face_t *face,
plan->layout_variation_indices = hb_set_create ();
plan->layout_variation_idx_map = hb_map_create ();
if (plan->in_error ()) {
return plan;
if (unlikely (plan->in_error ())) {
hb_subset_plan_destroy (plan);
return nullptr;
}
_populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, plan);
@ -532,6 +534,10 @@ hb_subset_plan_create (hb_face_t *face,
plan->reverse_glyph_map,
&plan->_num_output_glyphs);
if (unlikely (plan->in_error ())) {
hb_subset_plan_destroy (plan);
return nullptr;
}
return plan;
}
@ -542,7 +548,7 @@ hb_subset_plan_create (hb_face_t *face,
* Decreases the reference count on @plan, and if it reaches zero, destroys
* @plan, freeing all memory.
*
* Since: 1.7.5
* Since: 4.0.0
**/
void
hb_subset_plan_destroy (hb_subset_plan_t *plan)
@ -596,3 +602,116 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
hb_free (plan);
}
/**
* hb_subset_plan_old_to_new_glyph_mapping:
* @plan: a subsetting plan.
*
* Returns the mapping between glyphs in the original font to glyphs in the
* subset that will be produced by @plan
*
* Return value: (transfer none):
* A pointer to the #hb_map_t of the mapping.
*
* Since: 4.0.0
**/
const hb_map_t*
hb_subset_plan_old_to_new_glyph_mapping (const hb_subset_plan_t *plan)
{
return plan->glyph_map;
}
/**
* hb_subset_plan_new_to_old_glyph_mapping:
* @plan: a subsetting plan.
*
* Returns the mapping between glyphs in the subset that will be produced by
* @plan and the glyph in the original font.
*
* Return value: (transfer none):
* A pointer to the #hb_map_t of the mapping.
*
* Since: 4.0.0
**/
const hb_map_t*
hb_subset_plan_new_to_old_glyph_mapping (const hb_subset_plan_t *plan)
{
return plan->reverse_glyph_map;
}
/**
* hb_subset_plan_unicode_to_old_glyph_mapping:
* @plan: a subsetting plan.
*
* Returns the mapping between codepoints in the original font and the
* associated glyph id in the original font.
*
* Return value: (transfer none):
* A pointer to the #hb_map_t of the mapping.
*
* Since: 4.0.0
**/
const hb_map_t*
hb_subset_plan_unicode_to_old_glyph_mapping (const hb_subset_plan_t *plan)
{
return plan->codepoint_to_glyph;
}
/**
* hb_subset_plan_reference: (skip)
* @plan: a #hb_subset_plan_t object.
*
* Increases the reference count on @plan.
*
* Return value: @plan.
*
* Since: 4.0.0
**/
hb_subset_plan_t *
hb_subset_plan_reference (hb_subset_plan_t *plan)
{
return hb_object_reference (plan);
}
/**
* hb_subset_plan_set_user_data: (skip)
* @plan: a #hb_subset_plan_t object.
* @key: The user-data key to set
* @data: A pointer to the user data
* @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the given subset plan object.
*
* Return value: %true if success, %false otherwise
*
* Since: 4.0.0
**/
hb_bool_t
hb_subset_plan_set_user_data (hb_subset_plan_t *plan,
hb_user_data_key_t *key,
void *data,
hb_destroy_func_t destroy,
hb_bool_t replace)
{
return hb_object_set_user_data (plan, key, data, destroy, replace);
}
/**
* hb_subset_plan_get_user_data: (skip)
* @plan: a #hb_subset_plan_t object.
* @key: The user-data key to query
*
* Fetches the user data associated with the specified key,
* attached to the specified subset plan object.
*
* Return value: (transfer none): A pointer to the user data
*
* Since: 4.0.0
**/
void *
hb_subset_plan_get_user_data (const hb_subset_plan_t *plan,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (plan, key);
}

View File

@ -198,13 +198,4 @@ struct hb_subset_plan_t
}
};
typedef struct hb_subset_plan_t hb_subset_plan_t;
HB_INTERNAL hb_subset_plan_t *
hb_subset_plan_create (hb_face_t *face,
const hb_subset_input_t *input);
HB_INTERNAL void
hb_subset_plan_destroy (hb_subset_plan_t *plan);
#endif /* HB_SUBSET_PLAN_HH */

View File

@ -343,9 +343,33 @@ hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input)
{
if (unlikely (!input || !source)) return hb_face_get_empty ();
hb_subset_plan_t *plan = hb_subset_plan_create (source, input);
if (unlikely (plan->in_error ())) {
hb_subset_plan_t *plan = hb_subset_plan_create_or_fail (source, input);
if (unlikely (!plan)) {
return nullptr;
}
hb_face_t * result = hb_subset_plan_execute_or_fail (plan);
hb_subset_plan_destroy (plan);
return result;
}
/**
* hb_subset_plan_execute_or_fail:
* @plan: a subsetting plan.
*
* Executes the provided subsetting @plan.
*
* Return value:
* on success returns a reference to generated font subset. If the subsetting operation fails
* returns nullptr.
*
* Since: 4.0.0
**/
hb_face_t *
hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
{
if (unlikely (!plan || plan->in_error ())) {
return nullptr;
}
@ -353,7 +377,7 @@ hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input)
bool success = true;
hb_tag_t table_tags[32];
unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags);
while ((hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables))
while ((hb_face_get_table_tags (plan->source, offset, &num_tables, table_tags), num_tables))
{
for (unsigned i = 0; i < num_tables; ++i)
{
@ -367,8 +391,5 @@ hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input)
}
end:
hb_face_t *result = success ? hb_face_reference (plan->dest) : nullptr;
hb_subset_plan_destroy (plan);
return result;
return success ? hb_face_reference (plan->dest) : nullptr;
}

View File

@ -39,6 +39,15 @@ HB_BEGIN_DECLS
typedef struct hb_subset_input_t hb_subset_input_t;
/**
* hb_subset_plan_t:
*
* Contains information about how the subset operation will be executed.
* Such as mappings from the old glyph ids to the new ones in the subset.
*/
typedef struct hb_subset_plan_t hb_subset_plan_t;
/**
* hb_subset_flags_t:
* @HB_SUBSET_FLAGS_DEFAULT: all flags at their default value of false.
@ -145,6 +154,41 @@ hb_subset_input_set_flags (hb_subset_input_t *input,
HB_EXTERN hb_face_t *
hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input);
HB_EXTERN hb_face_t *
hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan);
HB_EXTERN hb_subset_plan_t *
hb_subset_plan_create_or_fail (hb_face_t *face,
const hb_subset_input_t *input);
HB_EXTERN void
hb_subset_plan_destroy (hb_subset_plan_t *plan);
HB_EXTERN const hb_map_t*
hb_subset_plan_old_to_new_glyph_mapping (const hb_subset_plan_t *plan);
HB_EXTERN const hb_map_t*
hb_subset_plan_new_to_old_glyph_mapping (const hb_subset_plan_t *plan);
HB_EXTERN const hb_map_t*
hb_subset_plan_unicode_to_old_glyph_mapping (const hb_subset_plan_t *plan);
HB_EXTERN hb_subset_plan_t *
hb_subset_plan_reference (hb_subset_plan_t *plan);
HB_EXTERN hb_bool_t
hb_subset_plan_set_user_data (hb_subset_plan_t *plan,
hb_user_data_key_t *key,
void *data,
hb_destroy_func_t destroy,
hb_bool_t replace);
HB_EXTERN void *
hb_subset_plan_get_user_data (const hb_subset_plan_t *plan,
hb_user_data_key_t *key);
HB_END_DECLS
#endif /* HB_SUBSET_H */

View File

@ -41,26 +41,26 @@ HB_BEGIN_DECLS
*
* The major component of the library version available at compile-time.
*/
#define HB_VERSION_MAJOR 3
#define HB_VERSION_MAJOR 4
/**
* HB_VERSION_MINOR:
*
* The minor component of the library version available at compile-time.
*/
#define HB_VERSION_MINOR 3
#define HB_VERSION_MINOR 0
/**
* HB_VERSION_MICRO:
*
* The micro component of the library version available at compile-time.
*/
#define HB_VERSION_MICRO 2
#define HB_VERSION_MICRO 0
/**
* HB_VERSION_STRING:
*
* A string literal containing the library version available at compile-time.
*/
#define HB_VERSION_STRING "3.3.2"
#define HB_VERSION_STRING "4.0.0"
/**
* HB_VERSION_ATLEAST: