Update bundled HarfBuzz sources up to 0.9.25

Most important changes:
- Myanmar, Indic, Javanese / Buginese shaper improvements
- More aggressive shape-plan caching
- Additional OpenType language tags

Change-Id: I54ed62cfe936c06c18589d09ac119a0f5881a235
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
Konstantin Ritt 2013-12-16 08:49:48 +02:00 committed by The Qt Project
parent 4b2c73b476
commit 260fe98525
56 changed files with 3962 additions and 1034 deletions

View File

@ -1,3 +1,58 @@
Overview of changes leading to 0.9.25
Wednesday, December 4, 2013
=====================================
- Myanmar shaper improvements.
- Avoid font fallback in CoreText backend.
- Additional OpenType language tag mappiongs.
- More aggressive shape-plan caching.
- Build with / require automake 1.13.
- Build with libtool 2.4.2.418 alpha to support ppc64le.
Overview of changes leading to 0.9.24
Tuesday, November 13, 2013
=====================================
- Misc compiler warning fixes with clang.
- No functional changes.
Overview of changes leading to 0.9.23
Monday, October 28, 2013
=====================================
- "Udupi HarfBuzz Hackfest", Paris, October 14..18 2013.
- Fix (Chain)Context recursion with non-monotone lookup positions.
- Misc Indic bug fixes.
- New Javanese / Buginese shaping, similar to Windows 8.1.
Overview of changes leading to 0.9.22
Thursday, October 3, 2013
=====================================
- Fix use-after-end-of-scope in hb_language_from_string().
- Fix hiding of default_ignorables if font doesn't have space glyph.
- Protect against out-of-range lookup indices.
- API Changes:
* Added hb_ot_layout_table_get_lookup_count()
Overview of changes leading to 0.9.21
Monday, September 16, 2013
=====================================
- Rename gobject-introspection library name from harfbuzz to HarfBuzz.
- Remove (long disabled) hb-old and hb-icu-le test shapers.
- Misc gtk-doc and gobject-introspection annotations.
- Misc fixes.
- API changes:
* Add HB_SET_VALUE_INVALID
Overview of changes leading to 0.9.20 Overview of changes leading to 0.9.20
Thursday, August 29, 2013 Thursday, August 29, 2013
===================================== =====================================

View File

@ -12,6 +12,8 @@ General fixes:
- Warn at compile time (and runtime with HB_DEBUG?) if no Unicode / font - Warn at compile time (and runtime with HB_DEBUG?) if no Unicode / font
funcs found / set. funcs found / set.
- Do proper rounding when scaling from font space? May be a non-issue.
- Misc features: - Misc features:
* init/medi/fina/isol for non-cursive scripts * init/medi/fina/isol for non-cursive scripts
@ -43,11 +45,9 @@ API additions
- Add sanitize API (and a cached version, that saves result on blob user-data) - Add sanitize API (and a cached version, that saves result on blob user-data)
- Add glib GBoxedType stuff and introspection
- BCP 47 language handling / API (language_matches?) - BCP 47 language handling / API (language_matches?)
- Add hb_font_create_linear()? - Add hb_font_create_unscaled()?
- Add query / enumeration API for aalt-like features? - Add query / enumeration API for aalt-like features?
@ -61,7 +61,7 @@ API additions
hb-view / hb-shape enhancements: hb-view / hb-shape enhancements:
=============================== ===============================
- Add --width, --height, --auto-size, --align, etc? - Add --width, --height, --auto-size, --ink-box, --align, etc?
Tests to write: Tests to write:

View File

@ -78,7 +78,7 @@ typedef int32_t hb_atomic_int_t;
#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100) #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P)) #define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
#else #else
#if __ppc64__ || __x86_64__ #if __ppc64__ || __x86_64__ || __arm64__
#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P)) #define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
#else #else
#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P)) #define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))

View File

@ -29,7 +29,6 @@
#include "hb-private.hh" #include "hb-private.hh"
#include "hb-blob.h"
#include "hb-object-private.hh" #include "hb-object-private.hh"
#ifdef HAVE_SYS_MMAN_H #ifdef HAVE_SYS_MMAN_H
@ -76,6 +75,22 @@ _hb_blob_destroy_user_data (hb_blob_t *blob)
} }
} }
/**
* hb_blob_create: (Xconstructor)
* @data: (array length=length) (closure user_data) (destroy destroy) (scope notified) (transfer none): Pointer to blob data.
* @length: Length of @data in bytes.
* @mode: Memory mode for @data.
* @user_data: Data parameter to pass to @destroy.
* @destroy: Callback to call when @data is not needed anymore.
*
* Creates a new "blob" object wrapping @data. The @mode parameter is used
* to negotiate ownership and lifecycle of @data.
*
* Return value: New blob, or the empty blob if something failed or if @length is
* zero. Destroy with hb_blob_destroy().
*
* Since: 1.0
**/
hb_blob_t * hb_blob_t *
hb_blob_create (const char *data, hb_blob_create (const char *data,
unsigned int length, unsigned int length,
@ -109,6 +124,26 @@ hb_blob_create (const char *data,
return blob; return blob;
} }
/**
* hb_blob_create_sub_blob:
* @parent: Parent blob.
* @offset: Start offset of sub-blob within @parent, in bytes.
* @length: Length of sub-blob.
*
* Returns a blob that represents a range of bytes in @parent. The new
* blob is always created with %HB_MEMORY_MODE_READONLY, meaning that it
* will never modify data in the parent blob. The parent data is not
* expected to be modified, and will result in undefined behavior if it
* is.
*
* Makes @parent immutable.
*
* Return value: New blob, or the empty blob if something failed or if
* @length is zero or @offset is beyond the end of @parent's data. Destroy
* with hb_blob_destroy().
*
* Since: 1.0
**/
hb_blob_t * hb_blob_t *
hb_blob_create_sub_blob (hb_blob_t *parent, hb_blob_create_sub_blob (hb_blob_t *parent,
unsigned int offset, unsigned int offset,
@ -130,6 +165,17 @@ hb_blob_create_sub_blob (hb_blob_t *parent,
return blob; return blob;
} }
/**
* hb_blob_get_empty:
*
* Returns the singleton empty blob.
*
* See TODO:link object types for more information.
*
* Return value: (transfer full): the empty blob.
*
* Since: 1.0
**/
hb_blob_t * hb_blob_t *
hb_blob_get_empty (void) hb_blob_get_empty (void)
{ {
@ -149,12 +195,36 @@ hb_blob_get_empty (void)
return const_cast<hb_blob_t *> (&_hb_blob_nil); return const_cast<hb_blob_t *> (&_hb_blob_nil);
} }
/**
* hb_blob_reference: (skip)
* @blob: a blob.
*
* Increases the reference count on @blob.
*
* See TODO:link object types for more information.
*
* Return value: @blob.
*
* Since: 1.0
**/
hb_blob_t * hb_blob_t *
hb_blob_reference (hb_blob_t *blob) hb_blob_reference (hb_blob_t *blob)
{ {
return hb_object_reference (blob); return hb_object_reference (blob);
} }
/**
* hb_blob_destroy: (skip)
* @blob: a blob.
*
* Descreases the reference count on @blob, and if it reaches zero, destroys
* @blob, freeing all memory, possibly calling the destroy-callback the blob
* was created for if it has not been called already.
*
* See TODO:link object types for more information.
*
* Since: 1.0
**/
void void
hb_blob_destroy (hb_blob_t *blob) hb_blob_destroy (hb_blob_t *blob)
{ {
@ -165,6 +235,18 @@ hb_blob_destroy (hb_blob_t *blob)
free (blob); free (blob);
} }
/**
* hb_blob_set_user_data: (skip)
* @blob: a blob.
* @key: key for data to set.
* @data: data to set.
* @destroy: callback to call when @data is not needed anymore.
* @replace: whether to replace an existing data with the same key.
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_blob_set_user_data (hb_blob_t *blob, hb_blob_set_user_data (hb_blob_t *blob,
hb_user_data_key_t *key, hb_user_data_key_t *key,
@ -175,6 +257,17 @@ hb_blob_set_user_data (hb_blob_t *blob,
return hb_object_set_user_data (blob, key, data, destroy, replace); return hb_object_set_user_data (blob, key, data, destroy, replace);
} }
/**
* hb_blob_get_user_data: (skip)
* @blob: a blob.
* @key: key for data to get.
*
*
*
* Return value: (transfer none):
*
* Since: 1.0
**/
void * void *
hb_blob_get_user_data (hb_blob_t *blob, hb_blob_get_user_data (hb_blob_t *blob,
hb_user_data_key_t *key) hb_user_data_key_t *key)
@ -183,6 +276,14 @@ hb_blob_get_user_data (hb_blob_t *blob,
} }
/**
* hb_blob_make_immutable:
* @blob: a blob.
*
*
*
* Since: 1.0
**/
void void
hb_blob_make_immutable (hb_blob_t *blob) hb_blob_make_immutable (hb_blob_t *blob)
{ {
@ -192,6 +293,16 @@ hb_blob_make_immutable (hb_blob_t *blob)
blob->immutable = true; blob->immutable = true;
} }
/**
* hb_blob_is_immutable:
* @blob: a blob.
*
*
*
* Return value: TODO
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_blob_is_immutable (hb_blob_t *blob) hb_blob_is_immutable (hb_blob_t *blob)
{ {
@ -199,12 +310,33 @@ hb_blob_is_immutable (hb_blob_t *blob)
} }
/**
* hb_blob_get_length:
* @blob: a blob.
*
*
*
* Return value: the length of blob data in bytes.
*
* Since: 1.0
**/
unsigned int unsigned int
hb_blob_get_length (hb_blob_t *blob) hb_blob_get_length (hb_blob_t *blob)
{ {
return blob->length; return blob->length;
} }
/**
* hb_blob_get_data:
* @blob: a blob.
* @length: (out):
*
*
*
* Returns: (transfer none) (array length=length):
*
* Since: 1.0
**/
const char * const char *
hb_blob_get_data (hb_blob_t *blob, unsigned int *length) hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
{ {
@ -214,6 +346,22 @@ hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
return blob->data; return blob->data;
} }
/**
* hb_blob_get_data_writable:
* @blob: a blob.
* @length: (out): output length of the writable data.
*
* Tries to make blob data writable (possibly copying it) and
* return pointer to data.
*
* Fails if blob has been made immutable, or if memory allocation
* fails.
*
* Returns: (transfer none) (array length=length): Writable blob data,
* or %NULL if failed.
*
* Since: 1.0
**/
char * char *
hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length) hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
{ {
@ -324,5 +472,3 @@ _try_writable (hb_blob_t *blob)
return true; return true;
} }

View File

@ -31,7 +31,6 @@
#define HB_BUFFER_PRIVATE_HH #define HB_BUFFER_PRIVATE_HH
#include "hb-private.hh" #include "hb-private.hh"
#include "hb-buffer.h"
#include "hb-object-private.hh" #include "hb-object-private.hh"
#include "hb-unicode-private.hh" #include "hb-unicode-private.hh"
@ -103,6 +102,8 @@ struct hb_buffer_t {
inline unsigned int backtrack_len (void) const inline unsigned int backtrack_len (void) const
{ return have_output? out_len : idx; } { return have_output? out_len : idx; }
inline unsigned int lookahead_len (void) const
{ return len - idx; }
inline unsigned int next_serial (void) { return serial++; } inline unsigned int next_serial (void) { return serial++; }
HB_INTERNAL void allocate_var (unsigned int byte_i, unsigned int count, const char *owner); HB_INTERNAL void allocate_var (unsigned int byte_i, unsigned int count, const char *owner);
@ -134,6 +135,7 @@ struct hb_buffer_t {
HB_INTERNAL void output_info (const hb_glyph_info_t &glyph_info); HB_INTERNAL void output_info (const hb_glyph_info_t &glyph_info);
/* Copies glyph at idx to output but doesn't advance idx */ /* Copies glyph at idx to output but doesn't advance idx */
HB_INTERNAL void copy_glyph (void); HB_INTERNAL void copy_glyph (void);
HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
/* Copies glyph at idx to output and advance idx. /* Copies glyph at idx to output and advance idx.
* If there's no output, just advance idx. */ * If there's no output, just advance idx. */
inline void inline void
@ -178,11 +180,13 @@ struct hb_buffer_t {
HB_INTERNAL bool enlarge (unsigned int size); HB_INTERNAL bool enlarge (unsigned int size);
inline bool ensure (unsigned int size) inline bool ensure (unsigned int size)
{ return likely (size < allocated) ? true : enlarge (size); } { return likely (!size || size < allocated) ? true : enlarge (size); }
HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out); HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
HB_INTERNAL bool shift_forward (unsigned int count);
HB_INTERNAL void *get_scratch_buffer (unsigned int *size); typedef long scratch_buffer_t;
HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size);
inline void clear_context (unsigned int side) { context_len[side] = 0; } inline void clear_context (unsigned int side) { context_len[side] = 0; }
}; };

View File

@ -33,12 +33,32 @@ static const char *serialize_formats[] = {
NULL NULL
}; };
/**
* hb_buffer_serialize_list_formats:
*
*
*
* Return value: (transfer none):
*
* Since: 1.0
**/
const char ** const char **
hb_buffer_serialize_list_formats (void) hb_buffer_serialize_list_formats (void)
{ {
return serialize_formats; return serialize_formats;
} }
/**
* hb_buffer_serialize_format_from_string:
* @str:
* @len:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_buffer_serialize_format_t hb_buffer_serialize_format_t
hb_buffer_serialize_format_from_string (const char *str, int len) hb_buffer_serialize_format_from_string (const char *str, int len)
{ {
@ -46,6 +66,16 @@ hb_buffer_serialize_format_from_string (const char *str, int len)
return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020); return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020);
} }
/**
* hb_buffer_serialize_format_to_string:
* @format:
*
*
*
* Return value:
*
* Since: 1.0
**/
const char * const char *
hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format) hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
{ {
@ -116,9 +146,9 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
*p++ = '}'; *p++ = '}';
if (buf_size > (p - b)) unsigned int l = p - b;
if (buf_size > l)
{ {
unsigned int l = p - b;
memcpy (buf, b, l); memcpy (buf, b, l);
buf += l; buf += l;
buf_size -= l; buf_size -= l;
@ -178,9 +208,9 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance)); p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
} }
if (buf_size > (p - b)) unsigned int l = p - b;
if (buf_size > l)
{ {
unsigned int l = p - b;
memcpy (buf, b, l); memcpy (buf, b, l);
buf += l; buf += l;
buf_size -= l; buf_size -= l;
@ -194,6 +224,24 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
} }
/* Returns number of items, starting at start, that were serialized. */ /* Returns number of items, starting at start, that were serialized. */
/**
* hb_buffer_serialize_glyphs:
* @buffer: a buffer.
* @start:
* @end:
* @buf: (array length=buf_size):
* @buf_size:
* @buf_consumed: (out):
* @font:
* @format:
* @flags:
*
*
*
* Return value:
*
* Since: 1.0
**/
unsigned int unsigned int
hb_buffer_serialize_glyphs (hb_buffer_t *buffer, hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
unsigned int start, unsigned int start,
@ -286,6 +334,21 @@ parse_int (const char *pp, const char *end, int32_t *pv)
#include "hb-buffer-deserialize-json.hh" #include "hb-buffer-deserialize-json.hh"
#include "hb-buffer-deserialize-text.hh" #include "hb-buffer-deserialize-text.hh"
/**
* hb_buffer_deserialize_glyphs:
* @buffer: a buffer.
* @buf: (array length=buf_len):
* @buf_len:
* @end_ptr: (out):
* @font:
* @format:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
const char *buf, const char *buf,

View File

@ -139,7 +139,20 @@ hb_buffer_t::make_room_for (unsigned int num_in,
return true; return true;
} }
void * bool
hb_buffer_t::shift_forward (unsigned int count)
{
assert (have_output);
if (unlikely (!ensure (len + count))) return false;
memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));
len += count;
idx += count;
return true;
}
hb_buffer_t::scratch_buffer_t *
hb_buffer_t::get_scratch_buffer (unsigned int *size) hb_buffer_t::get_scratch_buffer (unsigned int *size)
{ {
have_output = false; have_output = false;
@ -148,8 +161,9 @@ hb_buffer_t::get_scratch_buffer (unsigned int *size)
out_len = 0; out_len = 0;
out_info = info; out_info = info;
*size = allocated * sizeof (pos[0]); assert ((uintptr_t) pos % sizeof (scratch_buffer_t) == 0);
return pos; *size = allocated * sizeof (pos[0]) / sizeof (scratch_buffer_t);
return (scratch_buffer_t *) (void *) pos;
} }
@ -345,6 +359,44 @@ hb_buffer_t::copy_glyph (void)
out_len++; out_len++;
} }
bool
hb_buffer_t::move_to (unsigned int i)
{
if (!have_output)
{
assert (i <= len);
idx = i;
return true;
}
assert (i <= out_len + (len - idx));
if (out_len < i)
{
unsigned int count = i - out_len;
if (unlikely (!make_room_for (count, count))) return false;
memmove (out_info + out_len, info + idx, count * sizeof (out_info[0]));
idx += count;
out_len += count;
}
else if (out_len > i)
{
/* Tricky part: rewinding... */
unsigned int count = out_len - i;
if (unlikely (idx < count && !shift_forward (count + 32))) return false;
assert (idx >= count);
idx -= count;
out_len -= count;
memmove (info + idx, out_info + out_len, count * sizeof (out_info[0]));
}
return true;
}
void void
hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index) hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
{ {
@ -603,6 +655,15 @@ void hb_buffer_t::deallocate_var_all (void)
/* Public API */ /* Public API */
/**
* hb_buffer_create: (Xconstructor)
*
*
*
* Return value: (transfer full)
*
* Since: 1.0
**/
hb_buffer_t * hb_buffer_t *
hb_buffer_create (void) hb_buffer_create (void)
{ {
@ -616,6 +677,15 @@ hb_buffer_create (void)
return buffer; return buffer;
} }
/**
* hb_buffer_get_empty:
*
*
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_buffer_t * hb_buffer_t *
hb_buffer_get_empty (void) hb_buffer_get_empty (void)
{ {
@ -637,12 +707,30 @@ hb_buffer_get_empty (void)
return const_cast<hb_buffer_t *> (&_hb_buffer_nil); return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
} }
/**
* hb_buffer_reference: (skip)
* @buffer: a buffer.
*
*
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_buffer_t * hb_buffer_t *
hb_buffer_reference (hb_buffer_t *buffer) hb_buffer_reference (hb_buffer_t *buffer)
{ {
return hb_object_reference (buffer); return hb_object_reference (buffer);
} }
/**
* hb_buffer_destroy: (skip)
* @buffer: a buffer.
*
*
*
* Since: 1.0
**/
void void
hb_buffer_destroy (hb_buffer_t *buffer) hb_buffer_destroy (hb_buffer_t *buffer)
{ {
@ -656,6 +744,20 @@ hb_buffer_destroy (hb_buffer_t *buffer)
free (buffer); free (buffer);
} }
/**
* hb_buffer_set_user_data: (skip)
* @buffer: a buffer.
* @key:
* @data:
* @destroy:
* @replace:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_buffer_set_user_data (hb_buffer_t *buffer, hb_buffer_set_user_data (hb_buffer_t *buffer,
hb_user_data_key_t *key, hb_user_data_key_t *key,
@ -666,6 +768,17 @@ hb_buffer_set_user_data (hb_buffer_t *buffer,
return hb_object_set_user_data (buffer, key, data, destroy, replace); return hb_object_set_user_data (buffer, key, data, destroy, replace);
} }
/**
* hb_buffer_get_user_data: (skip)
* @buffer: a buffer.
* @key:
*
*
*
* Return value:
*
* Since: 1.0
**/
void * void *
hb_buffer_get_user_data (hb_buffer_t *buffer, hb_buffer_get_user_data (hb_buffer_t *buffer,
hb_user_data_key_t *key) hb_user_data_key_t *key)
@ -674,6 +787,15 @@ hb_buffer_get_user_data (hb_buffer_t *buffer,
} }
/**
* hb_buffer_set_content_type:
* @buffer: a buffer.
* @content_type:
*
*
*
* Since: 1.0
**/
void void
hb_buffer_set_content_type (hb_buffer_t *buffer, hb_buffer_set_content_type (hb_buffer_t *buffer,
hb_buffer_content_type_t content_type) hb_buffer_content_type_t content_type)
@ -681,6 +803,16 @@ hb_buffer_set_content_type (hb_buffer_t *buffer,
buffer->content_type = content_type; buffer->content_type = content_type;
} }
/**
* hb_buffer_get_content_type:
* @buffer: a buffer.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_buffer_content_type_t hb_buffer_content_type_t
hb_buffer_get_content_type (hb_buffer_t *buffer) hb_buffer_get_content_type (hb_buffer_t *buffer)
{ {
@ -688,28 +820,56 @@ hb_buffer_get_content_type (hb_buffer_t *buffer)
} }
/**
* hb_buffer_set_unicode_funcs:
* @buffer: a buffer.
* @unicode_funcs:
*
*
*
* Since: 1.0
**/
void void
hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
hb_unicode_funcs_t *unicode) hb_unicode_funcs_t *unicode_funcs)
{ {
if (unlikely (hb_object_is_inert (buffer))) if (unlikely (hb_object_is_inert (buffer)))
return; return;
if (!unicode) if (!unicode_funcs)
unicode = hb_unicode_funcs_get_default (); unicode_funcs = hb_unicode_funcs_get_default ();
hb_unicode_funcs_reference (unicode); hb_unicode_funcs_reference (unicode_funcs);
hb_unicode_funcs_destroy (buffer->unicode); hb_unicode_funcs_destroy (buffer->unicode);
buffer->unicode = unicode; buffer->unicode = unicode_funcs;
} }
/**
* hb_buffer_get_unicode_funcs:
* @buffer: a buffer.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_unicode_funcs_t * hb_unicode_funcs_t *
hb_buffer_get_unicode_funcs (hb_buffer_t *buffer) hb_buffer_get_unicode_funcs (hb_buffer_t *buffer)
{ {
return buffer->unicode; return buffer->unicode;
} }
/**
* hb_buffer_set_direction:
* @buffer: a buffer.
* @direction:
*
*
*
* Since: 1.0
**/
void void
hb_buffer_set_direction (hb_buffer_t *buffer, hb_buffer_set_direction (hb_buffer_t *buffer,
hb_direction_t direction) hb_direction_t direction)
@ -721,12 +881,31 @@ hb_buffer_set_direction (hb_buffer_t *buffer,
buffer->props.direction = direction; buffer->props.direction = direction;
} }
/**
* hb_buffer_get_direction:
* @buffer: a buffer.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_direction_t hb_direction_t
hb_buffer_get_direction (hb_buffer_t *buffer) hb_buffer_get_direction (hb_buffer_t *buffer)
{ {
return buffer->props.direction; return buffer->props.direction;
} }
/**
* hb_buffer_set_script:
* @buffer: a buffer.
* @script:
*
*
*
* Since: 1.0
**/
void void
hb_buffer_set_script (hb_buffer_t *buffer, hb_buffer_set_script (hb_buffer_t *buffer,
hb_script_t script) hb_script_t script)
@ -737,12 +916,31 @@ hb_buffer_set_script (hb_buffer_t *buffer,
buffer->props.script = script; buffer->props.script = script;
} }
/**
* hb_buffer_get_script:
* @buffer: a buffer.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_script_t hb_script_t
hb_buffer_get_script (hb_buffer_t *buffer) hb_buffer_get_script (hb_buffer_t *buffer)
{ {
return buffer->props.script; return buffer->props.script;
} }
/**
* hb_buffer_set_language:
* @buffer: a buffer.
* @language:
*
*
*
* Since: 1.0
**/
void void
hb_buffer_set_language (hb_buffer_t *buffer, hb_buffer_set_language (hb_buffer_t *buffer,
hb_language_t language) hb_language_t language)
@ -753,12 +951,31 @@ hb_buffer_set_language (hb_buffer_t *buffer,
buffer->props.language = language; buffer->props.language = language;
} }
/**
* hb_buffer_get_language:
* @buffer: a buffer.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_language_t hb_language_t
hb_buffer_get_language (hb_buffer_t *buffer) hb_buffer_get_language (hb_buffer_t *buffer)
{ {
return buffer->props.language; return buffer->props.language;
} }
/**
* hb_buffer_set_segment_properties:
* @buffer: a buffer.
* @props:
*
*
*
* Since: 1.0
**/
void void
hb_buffer_set_segment_properties (hb_buffer_t *buffer, hb_buffer_set_segment_properties (hb_buffer_t *buffer,
const hb_segment_properties_t *props) const hb_segment_properties_t *props)
@ -769,6 +986,15 @@ hb_buffer_set_segment_properties (hb_buffer_t *buffer,
buffer->props = *props; buffer->props = *props;
} }
/**
* hb_buffer_get_segment_properties:
* @buffer: a buffer.
* @props:
*
*
*
* Since: 1.0
**/
void void
hb_buffer_get_segment_properties (hb_buffer_t *buffer, hb_buffer_get_segment_properties (hb_buffer_t *buffer,
hb_segment_properties_t *props) hb_segment_properties_t *props)
@ -777,6 +1003,15 @@ hb_buffer_get_segment_properties (hb_buffer_t *buffer,
} }
/**
* hb_buffer_set_flags:
* @buffer: a buffer.
* @flags:
*
*
*
* Since: 1.0
**/
void void
hb_buffer_set_flags (hb_buffer_t *buffer, hb_buffer_set_flags (hb_buffer_t *buffer,
hb_buffer_flags_t flags) hb_buffer_flags_t flags)
@ -787,6 +1022,16 @@ hb_buffer_set_flags (hb_buffer_t *buffer,
buffer->flags = flags; buffer->flags = flags;
} }
/**
* hb_buffer_get_flags:
* @buffer: a buffer.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_buffer_flags_t hb_buffer_flags_t
hb_buffer_get_flags (hb_buffer_t *buffer) hb_buffer_get_flags (hb_buffer_t *buffer)
{ {
@ -794,30 +1039,77 @@ hb_buffer_get_flags (hb_buffer_t *buffer)
} }
/**
* hb_buffer_reset:
* @buffer: a buffer.
*
*
*
* Since: 1.0
**/
void void
hb_buffer_reset (hb_buffer_t *buffer) hb_buffer_reset (hb_buffer_t *buffer)
{ {
buffer->reset (); buffer->reset ();
} }
/**
* hb_buffer_clear_contents:
* @buffer: a buffer.
*
*
*
* Since: 1.0
**/
void void
hb_buffer_clear_contents (hb_buffer_t *buffer) hb_buffer_clear_contents (hb_buffer_t *buffer)
{ {
buffer->clear (); buffer->clear ();
} }
/**
* hb_buffer_pre_allocate:
* @buffer: a buffer.
* @size:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size) hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
{ {
return buffer->ensure (size); return buffer->ensure (size);
} }
/**
* hb_buffer_allocation_successful:
* @buffer: a buffer.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_buffer_allocation_successful (hb_buffer_t *buffer) hb_buffer_allocation_successful (hb_buffer_t *buffer)
{ {
return !buffer->in_error; return !buffer->in_error;
} }
/**
* hb_buffer_add:
* @buffer: a buffer.
* @codepoint:
* @cluster:
*
*
*
* Since: 1.0
**/
void void
hb_buffer_add (hb_buffer_t *buffer, hb_buffer_add (hb_buffer_t *buffer,
hb_codepoint_t codepoint, hb_codepoint_t codepoint,
@ -827,6 +1119,17 @@ hb_buffer_add (hb_buffer_t *buffer,
buffer->clear_context (1); buffer->clear_context (1);
} }
/**
* hb_buffer_set_length:
* @buffer: a buffer.
* @length:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_buffer_set_length (hb_buffer_t *buffer, hb_buffer_set_length (hb_buffer_t *buffer,
unsigned int length) unsigned int length)
@ -847,19 +1150,43 @@ hb_buffer_set_length (hb_buffer_t *buffer,
buffer->len = length; buffer->len = length;
if (!length) if (!length)
{
buffer->content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
buffer->clear_context (0); buffer->clear_context (0);
}
buffer->clear_context (1); buffer->clear_context (1);
return true; return true;
} }
/**
* hb_buffer_get_length:
* @buffer: a buffer.
*
* Returns the number of items in the buffer.
*
* Return value: buffer length.
*
* Since: 1.0
**/
unsigned int unsigned int
hb_buffer_get_length (hb_buffer_t *buffer) hb_buffer_get_length (hb_buffer_t *buffer)
{ {
return buffer->len; return buffer->len;
} }
/* Return value valid as long as buffer not modified */ /**
* hb_buffer_get_glyph_infos:
* @buffer: a buffer.
* @length: (out): output array length.
*
* Returns buffer glyph information array. Returned pointer
* is valid as long as buffer contents are not modified.
*
* Return value: (transfer none) (array length=length): buffer glyph information array.
*
* Since: 1.0
**/
hb_glyph_info_t * hb_glyph_info_t *
hb_buffer_get_glyph_infos (hb_buffer_t *buffer, hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
unsigned int *length) unsigned int *length)
@ -870,7 +1197,18 @@ hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
return (hb_glyph_info_t *) buffer->info; return (hb_glyph_info_t *) buffer->info;
} }
/* Return value valid as long as buffer not modified */ /**
* hb_buffer_get_glyph_positions:
* @buffer: a buffer.
* @length: (out): output length.
*
* Returns buffer glyph position array. Returned pointer
* is valid as long as buffer contents are not modified.
*
* Return value: (transfer none) (array length=length): buffer glyph position array.
*
* Since: 1.0
**/
hb_glyph_position_t * hb_glyph_position_t *
hb_buffer_get_glyph_positions (hb_buffer_t *buffer, hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
unsigned int *length) unsigned int *length)
@ -884,18 +1222,60 @@ hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
return (hb_glyph_position_t *) buffer->pos; return (hb_glyph_position_t *) buffer->pos;
} }
/**
* hb_buffer_reverse:
* @buffer: a buffer.
*
* Reverses buffer contents.
*
* Since: 1.0
**/
void void
hb_buffer_reverse (hb_buffer_t *buffer) hb_buffer_reverse (hb_buffer_t *buffer)
{ {
buffer->reverse (); buffer->reverse ();
} }
/**
* hb_buffer_reverse_clusters:
* @buffer: a buffer.
*
* Reverses buffer clusters. That is, the buffer contents are
* reversed, then each cluster (consecutive items having the
* same cluster number) are reversed again.
*
* Since: 1.0
**/
void void
hb_buffer_reverse_clusters (hb_buffer_t *buffer) hb_buffer_reverse_clusters (hb_buffer_t *buffer)
{ {
buffer->reverse_clusters (); buffer->reverse_clusters ();
} }
/**
* hb_buffer_guess_segment_properties:
* @buffer: a buffer.
*
* Sets unset buffer segment properties based on buffer Unicode
* contents. If buffer is not empty, it must have content type
* %HB_BUFFER_CONTENT_TYPE_UNICODE.
*
* If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
* will be set to the Unicode script of the first character in
* the buffer that has a script other than %HB_SCRIPT_COMMON,
* %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN.
*
* Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
* it will be set to the natural horizontal direction of the
* buffer script as returned by hb_script_get_horizontal_direction().
*
* Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
* it will be set to the process's default language as returned by
* hb_language_get_default(). This may change in the future by
* taking buffer script into consideration when choosing a language.
*
* Since: 1.0
**/
void void
hb_buffer_guess_segment_properties (hb_buffer_t *buffer) hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
{ {
@ -968,6 +1348,18 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE; buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
} }
/**
* hb_buffer_add_utf8:
* @buffer: a buffer.
* @text: (array length=text_length):
* @text_length:
* @item_offset:
* @item_length:
*
*
*
* Since: 1.0
**/
void void
hb_buffer_add_utf8 (hb_buffer_t *buffer, hb_buffer_add_utf8 (hb_buffer_t *buffer,
const char *text, const char *text,
@ -978,16 +1370,40 @@ hb_buffer_add_utf8 (hb_buffer_t *buffer,
hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length); hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
} }
/**
* hb_buffer_add_utf16:
* @buffer: a buffer.
* @text: (array length=text_length):
* @text_length:
* @item_offset:
* @item_length:
*
*
*
* Since: 1.0
**/
void void
hb_buffer_add_utf16 (hb_buffer_t *buffer, hb_buffer_add_utf16 (hb_buffer_t *buffer,
const uint16_t *text, const uint16_t *text,
int text_length, int text_length,
unsigned int item_offset, unsigned int item_offset,
int item_length) int item_length)
{ {
hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length); hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
} }
/**
* hb_buffer_add_utf32:
* @buffer: a buffer.
* @text: (array length=text_length):
* @text_length:
* @item_offset:
* @item_length:
*
*
*
* Since: 1.0
**/
void void
hb_buffer_add_utf32 (hb_buffer_t *buffer, hb_buffer_add_utf32 (hb_buffer_t *buffer,
const uint32_t *text, const uint32_t *text,
@ -1054,6 +1470,14 @@ normalize_glyphs_cluster (hb_buffer_t *buffer,
} }
} }
/**
* hb_buffer_normalize_glyphs:
* @buffer: a buffer.
*
*
*
* Since: 1.0
**/
void void
hb_buffer_normalize_glyphs (hb_buffer_t *buffer) hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
{ {

View File

@ -172,10 +172,10 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
typedef enum { /*< flags >*/ typedef enum { /*< flags >*/
HB_BUFFER_FLAG_DEFAULT = 0x00000000, HB_BUFFER_FLAG_DEFAULT = 0x00000000u,
HB_BUFFER_FLAG_BOT = 0x00000001, /* Beginning-of-text */ HB_BUFFER_FLAG_BOT = 0x00000001u, /* Beginning-of-text */
HB_BUFFER_FLAG_EOT = 0x00000002, /* End-of-text */ HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */
HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004 HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u
} hb_buffer_flags_t; } hb_buffer_flags_t;
void void
@ -275,10 +275,10 @@ hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
*/ */
typedef enum { /*< flags >*/ typedef enum { /*< flags >*/
HB_BUFFER_SERIALIZE_FLAG_DEFAULT = 0x00000000, HB_BUFFER_SERIALIZE_FLAG_DEFAULT = 0x00000000u,
HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS = 0x00000001, HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS = 0x00000001u,
HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS = 0x00000002, HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS = 0x00000002u,
HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004 HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004u
} hb_buffer_serialize_flags_t; } hb_buffer_serialize_flags_t;
typedef enum { typedef enum {

View File

@ -28,8 +28,6 @@
#include "hb-private.hh" #include "hb-private.hh"
#include "hb-version.h"
#include "hb-mutex-private.hh" #include "hb-mutex-private.hh"
#include "hb-object-private.hh" #include "hb-object-private.hh"
@ -57,25 +55,45 @@ _hb_options_init (void)
/* hb_tag_t */ /* hb_tag_t */
/**
* hb_tag_from_string:
* @str: (array length=len):
* @len:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_tag_t hb_tag_t
hb_tag_from_string (const char *s, int len) hb_tag_from_string (const char *str, int len)
{ {
char tag[4]; char tag[4];
unsigned int i; unsigned int i;
if (!s || !len || !*s) if (!str || !len || !*str)
return HB_TAG_NONE; return HB_TAG_NONE;
if (len < 0 || len > 4) if (len < 0 || len > 4)
len = 4; len = 4;
for (i = 0; i < (unsigned) len && s[i]; i++) for (i = 0; i < (unsigned) len && str[i]; i++)
tag[i] = s[i]; tag[i] = str[i];
for (; i < 4; i++) for (; i < 4; i++)
tag[i] = ' '; tag[i] = ' ';
return HB_TAG_CHAR4 (tag); return HB_TAG_CHAR4 (tag);
} }
/**
* hb_tag_to_string:
* @tag:
* @buf: (array fixed-size=4):
*
*
*
* Since: 1.0
**/
void void
hb_tag_to_string (hb_tag_t tag, char *buf) hb_tag_to_string (hb_tag_t tag, char *buf)
{ {
@ -95,6 +113,17 @@ const char direction_strings[][4] = {
"btt" "btt"
}; };
/**
* hb_direction_from_string:
* @str: (array length=len):
* @len:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_direction_t hb_direction_t
hb_direction_from_string (const char *str, int len) hb_direction_from_string (const char *str, int len)
{ {
@ -112,6 +141,16 @@ hb_direction_from_string (const char *str, int len)
return HB_DIRECTION_INVALID; return HB_DIRECTION_INVALID;
} }
/**
* hb_direction_to_string:
* @direction:
*
*
*
* Return value: (transfer none):
*
* Since: 1.0
**/
const char * const char *
hb_direction_to_string (hb_direction_t direction) hb_direction_to_string (hb_direction_t direction)
{ {
@ -187,7 +226,7 @@ struct hb_language_item_t {
return *this; return *this;
} }
void finish (void) { free (lang); } void finish (void) { free ((void *) lang); }
}; };
@ -237,14 +276,27 @@ retry:
} }
/**
* hb_language_from_string:
* @str: (array length=len):
* @len:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_language_t hb_language_t
hb_language_from_string (const char *str, int len) hb_language_from_string (const char *str, int len)
{ {
char strbuf[64];
if (!str || !len || !*str) if (!str || !len || !*str)
return HB_LANGUAGE_INVALID; return HB_LANGUAGE_INVALID;
if (len >= 0) { if (len >= 0)
char strbuf[64]; {
len = MIN (len, (int) sizeof (strbuf) - 1); len = MIN (len, (int) sizeof (strbuf) - 1);
str = (char *) memcpy (strbuf, str, len); str = (char *) memcpy (strbuf, str, len);
strbuf[len] = '\0'; strbuf[len] = '\0';
@ -255,6 +307,16 @@ hb_language_from_string (const char *str, int len)
return likely (item) ? item->lang : HB_LANGUAGE_INVALID; return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
} }
/**
* hb_language_to_string:
* @language:
*
*
*
* Return value: (transfer none):
*
* Since: 1.0
**/
const char * const char *
hb_language_to_string (hb_language_t language) hb_language_to_string (hb_language_t language)
{ {
@ -262,6 +324,15 @@ hb_language_to_string (hb_language_t language)
return language->s; return language->s;
} }
/**
* hb_language_get_default:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_language_t hb_language_t
hb_language_get_default (void) hb_language_get_default (void)
{ {
@ -279,6 +350,16 @@ hb_language_get_default (void)
/* hb_script_t */ /* hb_script_t */
/**
* hb_script_from_iso15924_tag:
* @tag:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_script_t hb_script_t
hb_script_from_iso15924_tag (hb_tag_t tag) hb_script_from_iso15924_tag (hb_tag_t tag)
{ {
@ -313,18 +394,49 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
return HB_SCRIPT_UNKNOWN; return HB_SCRIPT_UNKNOWN;
} }
/**
* hb_script_from_string:
* @s: (array length=len):
* @len:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_script_t hb_script_t
hb_script_from_string (const char *s, int len) hb_script_from_string (const char *s, int len)
{ {
return hb_script_from_iso15924_tag (hb_tag_from_string (s, len)); return hb_script_from_iso15924_tag (hb_tag_from_string (s, len));
} }
/**
* hb_script_to_iso15924_tag:
* @script:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_tag_t hb_tag_t
hb_script_to_iso15924_tag (hb_script_t script) hb_script_to_iso15924_tag (hb_script_t script)
{ {
return (hb_tag_t) script; return (hb_tag_t) script;
} }
/**
* hb_script_get_horizontal_direction:
* @script:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_direction_t hb_direction_t
hb_script_get_horizontal_direction (hb_script_t script) hb_script_get_horizontal_direction (hb_script_t script)
{ {
@ -409,6 +521,16 @@ hb_user_data_array_t::get (hb_user_data_key_t *key)
/* hb_version */ /* hb_version */
/**
* hb_version:
* @major: (out): Library major version component.
* @minor: (out): Library minor version component.
* @micro: (out): Library micro version component.
*
* Returns library version as three integer components.
*
* Since: 1.0
**/
void void
hb_version (unsigned int *major, hb_version (unsigned int *major,
unsigned int *minor, unsigned int *minor,
@ -419,12 +541,33 @@ hb_version (unsigned int *major,
*micro = HB_VERSION_MICRO; *micro = HB_VERSION_MICRO;
} }
/**
* hb_version_string:
*
* Returns library version as a string with three components.
*
* Return value: library version string.
*
* Since: 1.0
**/
const char * const char *
hb_version_string (void) hb_version_string (void)
{ {
return HB_VERSION_STRING; return HB_VERSION_STRING;
} }
/**
* hb_version_check:
* @major:
* @minor:
* @micro:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_version_check (unsigned int major, hb_version_check (unsigned int major,
unsigned int minor, unsigned int minor,

View File

@ -90,7 +90,7 @@ typedef union _hb_var_int_t {
typedef uint32_t hb_tag_t; typedef uint32_t hb_tag_t;
#define HB_TAG(a,b,c,d) ((hb_tag_t)((((uint8_t)(a))<<24)|(((uint8_t)(b))<<16)|(((uint8_t)(c))<<8)|((uint8_t)(d)))) #define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint8_t)(c1))<<24)|(((uint8_t)(c2))<<16)|(((uint8_t)(c3))<<8)|((uint8_t)(c4))))
#define HB_UNTAG(tag) ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag)) #define HB_UNTAG(tag) ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag))
#define HB_TAG_NONE HB_TAG(0,0,0,0) #define HB_TAG_NONE HB_TAG(0,0,0,0)
@ -131,7 +131,7 @@ hb_direction_to_string (hb_direction_t direction);
/* hb_language_t */ /* hb_language_t */
typedef struct hb_language_impl_t *hb_language_t; typedef const struct hb_language_impl_t *hb_language_t;
/* len=-1 means str is NUL-terminated */ /* len=-1 means str is NUL-terminated */
hb_language_t hb_language_t

View File

@ -31,7 +31,6 @@
#include "hb-private.hh" #include "hb-private.hh"
#include "hb-font.h"
#include "hb-object-private.hh" #include "hb-object-private.hh"
#include "hb-shaper-private.hh" #include "hb-shaper-private.hh"
#include "hb-shape-plan-private.hh" #include "hb-shape-plan-private.hh"

View File

@ -31,7 +31,6 @@
#include "hb-ot-layout-private.hh" #include "hb-ot-layout-private.hh"
#include "hb-font-private.hh" #include "hb-font-private.hh"
#include "hb-blob.h"
#include "hb-open-file-private.hh" #include "hb-open-file-private.hh"
#include "hb-ot-head-table.hh" #include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh" #include "hb-ot-maxp-table.hh"
@ -68,6 +67,18 @@ const hb_face_t _hb_face_nil = {
}; };
/**
* hb_face_create_for_tables:
* @reference_table_func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Return value: (transfer full)
*
* Since: 1.0
**/
hb_face_t * hb_face_t *
hb_face_create_for_tables (hb_reference_table_func_t reference_table_func, hb_face_create_for_tables (hb_reference_table_func_t reference_table_func,
void *user_data, void *user_data,
@ -137,6 +148,17 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
return blob; return blob;
} }
/**
* hb_face_create: (Xconstructor)
* @blob:
* @index:
*
*
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_face_t * hb_face_t *
hb_face_create (hb_blob_t *blob, hb_face_create (hb_blob_t *blob,
unsigned int index) unsigned int index)
@ -160,6 +182,15 @@ hb_face_create (hb_blob_t *blob,
return face; return face;
} }
/**
* hb_face_get_empty:
*
*
*
* Return value: (transfer full)
*
* Since: 1.0
**/
hb_face_t * hb_face_t *
hb_face_get_empty (void) hb_face_get_empty (void)
{ {
@ -167,12 +198,30 @@ hb_face_get_empty (void)
} }
/**
* hb_face_reference: (skip)
* @face: a face.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_face_t * hb_face_t *
hb_face_reference (hb_face_t *face) hb_face_reference (hb_face_t *face)
{ {
return hb_object_reference (face); return hb_object_reference (face);
} }
/**
* hb_face_destroy: (skip)
* @face: a face.
*
*
*
* Since: 1.0
**/
void void
hb_face_destroy (hb_face_t *face) hb_face_destroy (hb_face_t *face)
{ {
@ -196,6 +245,20 @@ hb_face_destroy (hb_face_t *face)
free (face); free (face);
} }
/**
* hb_face_set_user_data: (skip)
* @face: a face.
* @key:
* @data:
* @destroy:
* @replace:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_face_set_user_data (hb_face_t *face, hb_face_set_user_data (hb_face_t *face,
hb_user_data_key_t *key, hb_user_data_key_t *key,
@ -206,6 +269,17 @@ hb_face_set_user_data (hb_face_t *face,
return hb_object_set_user_data (face, key, data, destroy, replace); return hb_object_set_user_data (face, key, data, destroy, replace);
} }
/**
* hb_face_get_user_data: (skip)
* @face: a face.
* @key:
*
*
*
* Return value: (transfer none):
*
* Since: 1.0
**/
void * void *
hb_face_get_user_data (hb_face_t *face, hb_face_get_user_data (hb_face_t *face,
hb_user_data_key_t *key) hb_user_data_key_t *key)
@ -213,6 +287,14 @@ hb_face_get_user_data (hb_face_t *face,
return hb_object_get_user_data (face, key); return hb_object_get_user_data (face, key);
} }
/**
* hb_face_make_immutable:
* @face: a face.
*
*
*
* Since: 1.0
**/
void void
hb_face_make_immutable (hb_face_t *face) hb_face_make_immutable (hb_face_t *face)
{ {
@ -222,6 +304,16 @@ hb_face_make_immutable (hb_face_t *face)
face->immutable = true; face->immutable = true;
} }
/**
* hb_face_is_immutable:
* @face: a face.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_face_is_immutable (hb_face_t *face) hb_face_is_immutable (hb_face_t *face)
{ {
@ -229,6 +321,17 @@ hb_face_is_immutable (hb_face_t *face)
} }
/**
* hb_face_reference_table:
* @face: a face.
* @tag:
*
*
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_blob_t * hb_blob_t *
hb_face_reference_table (hb_face_t *face, hb_face_reference_table (hb_face_t *face,
hb_tag_t tag) hb_tag_t tag)
@ -236,12 +339,31 @@ hb_face_reference_table (hb_face_t *face,
return face->reference_table (tag); return face->reference_table (tag);
} }
/**
* hb_face_reference_blob:
* @face: a face.
*
*
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_blob_t * hb_blob_t *
hb_face_reference_blob (hb_face_t *face) hb_face_reference_blob (hb_face_t *face)
{ {
return face->reference_table (HB_TAG_NONE); return face->reference_table (HB_TAG_NONE);
} }
/**
* hb_face_set_index:
* @face: a face.
* @index:
*
*
*
* Since: 1.0
**/
void void
hb_face_set_index (hb_face_t *face, hb_face_set_index (hb_face_t *face,
unsigned int index) unsigned int index)
@ -252,12 +374,31 @@ hb_face_set_index (hb_face_t *face,
face->index = index; face->index = index;
} }
/**
* hb_face_get_index:
* @face: a face.
*
*
*
* Return value:
*
* Since: 1.0
**/
unsigned int unsigned int
hb_face_get_index (hb_face_t *face) hb_face_get_index (hb_face_t *face)
{ {
return face->index; return face->index;
} }
/**
* hb_face_set_upem:
* @face: a face.
* @upem:
*
*
*
* Since: 1.0
**/
void void
hb_face_set_upem (hb_face_t *face, hb_face_set_upem (hb_face_t *face,
unsigned int upem) unsigned int upem)
@ -268,6 +409,16 @@ hb_face_set_upem (hb_face_t *face,
face->upem = upem; face->upem = upem;
} }
/**
* hb_face_get_upem:
* @face: a face.
*
*
*
* Return value:
*
* Since: 1.0
**/
unsigned int unsigned int
hb_face_get_upem (hb_face_t *face) hb_face_get_upem (hb_face_t *face)
{ {
@ -283,6 +434,15 @@ hb_face_t::load_upem (void) const
hb_blob_destroy (head_blob); hb_blob_destroy (head_blob);
} }
/**
* hb_face_set_glyph_count:
* @face: a face.
* @glyph_count:
*
*
*
* Since: 1.0
**/
void void
hb_face_set_glyph_count (hb_face_t *face, hb_face_set_glyph_count (hb_face_t *face,
unsigned int glyph_count) unsigned int glyph_count)
@ -293,6 +453,16 @@ hb_face_set_glyph_count (hb_face_t *face,
face->num_glyphs = glyph_count; face->num_glyphs = glyph_count;
} }
/**
* hb_face_get_glyph_count:
* @face: a face.
*
*
*
* Return value:
*
* Since: 1.0
**/
unsigned int unsigned int
hb_face_get_glyph_count (hb_face_t *face) hb_face_get_glyph_count (hb_face_t *face)
{ {

View File

@ -95,6 +95,16 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *features HB_UNUSED, const hb_feature_t *features HB_UNUSED,
unsigned int num_features HB_UNUSED) unsigned int num_features HB_UNUSED)
{ {
/* TODO
*
* - Apply fallback kern.
* - Handle Variation Selectors?
* - Apply normalization?
*
* This will make the fallback shaper into a dumb "TrueType"
* shaper which many people unfortunately still request.
*/
hb_codepoint_t space; hb_codepoint_t space;
font->get_glyph (' ', 0, &space); font->get_glyph (' ', 0, &space);

View File

@ -31,7 +31,6 @@
#include "hb-private.hh" #include "hb-private.hh"
#include "hb-font.h"
#include "hb-object-private.hh" #include "hb-object-private.hh"
#include "hb-face-private.hh" #include "hb-face-private.hh"
#include "hb-shaper-private.hh" #include "hb-shaper-private.hh"
@ -118,12 +117,12 @@ struct hb_font_t {
/* Convert from parent-font user-space to our user-space */ /* Convert from parent-font user-space to our user-space */
inline hb_position_t parent_scale_x_distance (hb_position_t v) { inline hb_position_t parent_scale_x_distance (hb_position_t v) {
if (unlikely (parent && parent->x_scale != x_scale)) if (unlikely (parent && parent->x_scale != x_scale))
return v * (int64_t) this->x_scale / this->parent->x_scale; return (hb_position_t) (v * (int64_t) this->x_scale / this->parent->x_scale);
return v; return v;
} }
inline hb_position_t parent_scale_y_distance (hb_position_t v) { inline hb_position_t parent_scale_y_distance (hb_position_t v) {
if (unlikely (parent && parent->y_scale != y_scale)) if (unlikely (parent && parent->y_scale != y_scale))
return v * (int64_t) this->y_scale / this->parent->y_scale; return (hb_position_t) (v * (int64_t) this->y_scale / this->parent->y_scale);
return v; return v;
} }
inline hb_position_t parent_scale_x_position (hb_position_t v) { inline hb_position_t parent_scale_x_position (hb_position_t v) {
@ -193,10 +192,10 @@ struct hb_font_t {
klass->user_data.glyph_h_kerning); klass->user_data.glyph_h_kerning);
} }
inline hb_position_t get_glyph_v_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph) inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
{ {
return klass->get.glyph_v_kerning (this, user_data, return klass->get.glyph_v_kerning (this, user_data,
left_glyph, right_glyph, top_glyph, bottom_glyph,
klass->user_data.glyph_v_kerning); klass->user_data.glyph_v_kerning);
} }
@ -397,11 +396,7 @@ struct hb_font_t {
} }
private: private:
inline hb_position_t em_scale (int16_t v, int scale) inline hb_position_t em_scale (int16_t v, int scale) { return (hb_position_t) (v * (int64_t) scale / face->get_upem ()); }
{
unsigned int upem = face->get_upem ();
return (v * (int64_t) scale + upem / 2) / upem;
}
}; };
#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS #define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS

View File

@ -31,7 +31,6 @@
#include "hb-ot-layout-private.hh" #include "hb-ot-layout-private.hh"
#include "hb-font-private.hh" #include "hb-font-private.hh"
#include "hb-blob.h"
#include "hb-open-file-private.hh" #include "hb-open-file-private.hh"
#include "hb-ot-head-table.hh" #include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh" #include "hb-ot-maxp-table.hh"
@ -230,6 +229,15 @@ static const hb_font_funcs_t _hb_font_funcs_nil = {
}; };
/**
* hb_font_funcs_create: (Xconstructor)
*
*
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_font_funcs_t * hb_font_funcs_t *
hb_font_funcs_create (void) hb_font_funcs_create (void)
{ {
@ -243,18 +251,45 @@ hb_font_funcs_create (void)
return ffuncs; return ffuncs;
} }
/**
* hb_font_funcs_get_empty:
*
*
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_font_funcs_t * hb_font_funcs_t *
hb_font_funcs_get_empty (void) hb_font_funcs_get_empty (void)
{ {
return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil); return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil);
} }
/**
* hb_font_funcs_reference: (skip)
* @ffuncs: font functions.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_font_funcs_t * hb_font_funcs_t *
hb_font_funcs_reference (hb_font_funcs_t *ffuncs) hb_font_funcs_reference (hb_font_funcs_t *ffuncs)
{ {
return hb_object_reference (ffuncs); return hb_object_reference (ffuncs);
} }
/**
* hb_font_funcs_destroy: (skip)
* @ffuncs: font functions.
*
*
*
* Since: 1.0
**/
void void
hb_font_funcs_destroy (hb_font_funcs_t *ffuncs) hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
{ {
@ -268,6 +303,20 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
free (ffuncs); free (ffuncs);
} }
/**
* hb_font_funcs_set_user_data: (skip)
* @ffuncs: font functions.
* @key:
* @data:
* @destroy:
* @replace:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs, hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
hb_user_data_key_t *key, hb_user_data_key_t *key,
@ -278,6 +327,17 @@ hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
return hb_object_set_user_data (ffuncs, key, data, destroy, replace); return hb_object_set_user_data (ffuncs, key, data, destroy, replace);
} }
/**
* hb_font_funcs_get_user_data: (skip)
* @ffuncs: font functions.
* @key:
*
*
*
* Return value: (transfer none):
*
* Since: 1.0
**/
void * void *
hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs, hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
hb_user_data_key_t *key) hb_user_data_key_t *key)
@ -286,6 +346,14 @@ hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
} }
/**
* hb_font_funcs_make_immutable:
* @ffuncs: font functions.
*
*
*
* Since: 1.0
**/
void void
hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs) hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
{ {
@ -295,6 +363,16 @@ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
ffuncs->immutable = true; ffuncs->immutable = true;
} }
/**
* hb_font_funcs_is_immutable:
* @ffuncs: font functions.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs) hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs)
{ {
@ -336,6 +414,19 @@ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
/* Public getters */ /* Public getters */
/**
* hb_font_get_glyph:
* @font: a font.
* @unicode:
* @variation_selector:
* @glyph: (out):
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_font_get_glyph (hb_font_t *font, hb_font_get_glyph (hb_font_t *font,
hb_codepoint_t unicode, hb_codepoint_t variation_selector, hb_codepoint_t unicode, hb_codepoint_t variation_selector,
@ -344,6 +435,17 @@ hb_font_get_glyph (hb_font_t *font,
return font->get_glyph (unicode, variation_selector, glyph); return font->get_glyph (unicode, variation_selector, glyph);
} }
/**
* hb_font_get_glyph_h_advance:
* @font: a font.
* @glyph:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_position_t hb_position_t
hb_font_get_glyph_h_advance (hb_font_t *font, hb_font_get_glyph_h_advance (hb_font_t *font,
hb_codepoint_t glyph) hb_codepoint_t glyph)
@ -351,6 +453,17 @@ hb_font_get_glyph_h_advance (hb_font_t *font,
return font->get_glyph_h_advance (glyph); return font->get_glyph_h_advance (glyph);
} }
/**
* hb_font_get_glyph_v_advance:
* @font: a font.
* @glyph:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_position_t hb_position_t
hb_font_get_glyph_v_advance (hb_font_t *font, hb_font_get_glyph_v_advance (hb_font_t *font,
hb_codepoint_t glyph) hb_codepoint_t glyph)
@ -358,6 +471,19 @@ hb_font_get_glyph_v_advance (hb_font_t *font,
return font->get_glyph_v_advance (glyph); return font->get_glyph_v_advance (glyph);
} }
/**
* hb_font_get_glyph_h_origin:
* @font: a font.
* @glyph:
* @x: (out):
* @y: (out):
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_font_get_glyph_h_origin (hb_font_t *font, hb_font_get_glyph_h_origin (hb_font_t *font,
hb_codepoint_t glyph, hb_codepoint_t glyph,
@ -366,6 +492,19 @@ hb_font_get_glyph_h_origin (hb_font_t *font,
return font->get_glyph_h_origin (glyph, x, y); return font->get_glyph_h_origin (glyph, x, y);
} }
/**
* hb_font_get_glyph_v_origin:
* @font: a font.
* @glyph:
* @x: (out):
* @y: (out):
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_font_get_glyph_v_origin (hb_font_t *font, hb_font_get_glyph_v_origin (hb_font_t *font,
hb_codepoint_t glyph, hb_codepoint_t glyph,
@ -374,6 +513,18 @@ hb_font_get_glyph_v_origin (hb_font_t *font,
return font->get_glyph_v_origin (glyph, x, y); return font->get_glyph_v_origin (glyph, x, y);
} }
/**
* hb_font_get_glyph_h_kerning:
* @font: a font.
* @left_glyph:
* @right_glyph:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_position_t hb_position_t
hb_font_get_glyph_h_kerning (hb_font_t *font, hb_font_get_glyph_h_kerning (hb_font_t *font,
hb_codepoint_t left_glyph, hb_codepoint_t right_glyph) hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
@ -381,13 +532,37 @@ hb_font_get_glyph_h_kerning (hb_font_t *font,
return font->get_glyph_h_kerning (left_glyph, right_glyph); return font->get_glyph_h_kerning (left_glyph, right_glyph);
} }
/**
* hb_font_get_glyph_v_kerning:
* @font: a font.
* @top_glyph:
* @bottom_glyph:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_position_t hb_position_t
hb_font_get_glyph_v_kerning (hb_font_t *font, hb_font_get_glyph_v_kerning (hb_font_t *font,
hb_codepoint_t left_glyph, hb_codepoint_t right_glyph) hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
{ {
return font->get_glyph_v_kerning (left_glyph, right_glyph); return font->get_glyph_v_kerning (top_glyph, bottom_glyph);
} }
/**
* hb_font_get_glyph_extents:
* @font: a font.
* @glyph:
* @extents: (out):
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_font_get_glyph_extents (hb_font_t *font, hb_font_get_glyph_extents (hb_font_t *font,
hb_codepoint_t glyph, hb_codepoint_t glyph,
@ -396,6 +571,20 @@ hb_font_get_glyph_extents (hb_font_t *font,
return font->get_glyph_extents (glyph, extents); return font->get_glyph_extents (glyph, extents);
} }
/**
* hb_font_get_glyph_contour_point:
* @font: a font.
* @glyph:
* @point_index:
* @x: (out):
* @y: (out):
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_font_get_glyph_contour_point (hb_font_t *font, hb_font_get_glyph_contour_point (hb_font_t *font,
hb_codepoint_t glyph, unsigned int point_index, hb_codepoint_t glyph, unsigned int point_index,
@ -404,6 +593,19 @@ hb_font_get_glyph_contour_point (hb_font_t *font,
return font->get_glyph_contour_point (glyph, point_index, x, y); return font->get_glyph_contour_point (glyph, point_index, x, y);
} }
/**
* hb_font_get_glyph_name:
* @font: a font.
* @glyph:
* @name: (array length=size):
* @size:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_font_get_glyph_name (hb_font_t *font, hb_font_get_glyph_name (hb_font_t *font,
hb_codepoint_t glyph, hb_codepoint_t glyph,
@ -412,6 +614,19 @@ hb_font_get_glyph_name (hb_font_t *font,
return font->get_glyph_name (glyph, name, size); return font->get_glyph_name (glyph, name, size);
} }
/**
* hb_font_get_glyph_from_name:
* @font: a font.
* @name: (array length=len):
* @len:
* @glyph: (out):
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_font_get_glyph_from_name (hb_font_t *font, hb_font_get_glyph_from_name (hb_font_t *font,
const char *name, int len, /* -1 means nul-terminated */ const char *name, int len, /* -1 means nul-terminated */
@ -423,6 +638,18 @@ hb_font_get_glyph_from_name (hb_font_t *font,
/* A bit higher-level, and with fallback */ /* A bit higher-level, and with fallback */
/**
* hb_font_get_glyph_advance_for_direction:
* @font: a font.
* @glyph:
* @direction:
* @x: (out):
* @y: (out):
*
*
*
* Since: 1.0
**/
void void
hb_font_get_glyph_advance_for_direction (hb_font_t *font, hb_font_get_glyph_advance_for_direction (hb_font_t *font,
hb_codepoint_t glyph, hb_codepoint_t glyph,
@ -432,6 +659,18 @@ hb_font_get_glyph_advance_for_direction (hb_font_t *font,
return font->get_glyph_advance_for_direction (glyph, direction, x, y); return font->get_glyph_advance_for_direction (glyph, direction, x, y);
} }
/**
* hb_font_get_glyph_origin_for_direction:
* @font: a font.
* @glyph:
* @direction:
* @x: (out):
* @y: (out):
*
*
*
* Since: 1.0
**/
void void
hb_font_get_glyph_origin_for_direction (hb_font_t *font, hb_font_get_glyph_origin_for_direction (hb_font_t *font,
hb_codepoint_t glyph, hb_codepoint_t glyph,
@ -441,6 +680,18 @@ hb_font_get_glyph_origin_for_direction (hb_font_t *font,
return font->get_glyph_origin_for_direction (glyph, direction, x, y); return font->get_glyph_origin_for_direction (glyph, direction, x, y);
} }
/**
* hb_font_add_glyph_origin_for_direction:
* @font: a font.
* @glyph:
* @direction:
* @x: (out):
* @y: (out):
*
*
*
* Since: 1.0
**/
void void
hb_font_add_glyph_origin_for_direction (hb_font_t *font, hb_font_add_glyph_origin_for_direction (hb_font_t *font,
hb_codepoint_t glyph, hb_codepoint_t glyph,
@ -450,6 +701,18 @@ hb_font_add_glyph_origin_for_direction (hb_font_t *font,
return font->add_glyph_origin_for_direction (glyph, direction, x, y); return font->add_glyph_origin_for_direction (glyph, direction, x, y);
} }
/**
* hb_font_subtract_glyph_origin_for_direction:
* @font: a font.
* @glyph:
* @direction:
* @x: (out):
* @y: (out):
*
*
*
* Since: 1.0
**/
void void
hb_font_subtract_glyph_origin_for_direction (hb_font_t *font, hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
hb_codepoint_t glyph, hb_codepoint_t glyph,
@ -459,6 +722,19 @@ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
return font->subtract_glyph_origin_for_direction (glyph, direction, x, y); return font->subtract_glyph_origin_for_direction (glyph, direction, x, y);
} }
/**
* hb_font_get_glyph_kerning_for_direction:
* @font: a font.
* @first_glyph:
* @second_glyph:
* @direction:
* @x: (out):
* @y: (out):
*
*
*
* Since: 1.0
**/
void void
hb_font_get_glyph_kerning_for_direction (hb_font_t *font, hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
@ -468,6 +744,19 @@ hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
return font->get_glyph_kerning_for_direction (first_glyph, second_glyph, direction, x, y); return font->get_glyph_kerning_for_direction (first_glyph, second_glyph, direction, x, y);
} }
/**
* hb_font_get_glyph_extents_for_origin:
* @font: a font.
* @glyph:
* @direction:
* @extents: (out):
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_font_get_glyph_extents_for_origin (hb_font_t *font, hb_font_get_glyph_extents_for_origin (hb_font_t *font,
hb_codepoint_t glyph, hb_codepoint_t glyph,
@ -477,6 +766,21 @@ hb_font_get_glyph_extents_for_origin (hb_font_t *font,
return font->get_glyph_extents_for_origin (glyph, direction, extents); return font->get_glyph_extents_for_origin (glyph, direction, extents);
} }
/**
* hb_font_get_glyph_contour_point_for_origin:
* @font: a font.
* @glyph:
* @point_index:
* @direction:
* @x: (out):
* @y: (out):
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_font_get_glyph_contour_point_for_origin (hb_font_t *font, hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
hb_codepoint_t glyph, unsigned int point_index, hb_codepoint_t glyph, unsigned int point_index,
@ -487,6 +791,17 @@ hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
} }
/* Generates gidDDD if glyph has no name. */ /* Generates gidDDD if glyph has no name. */
/**
* hb_font_glyph_to_string:
* @font: a font.
* @glyph:
* @s: (array length=size):
* @size:
*
*
*
* Since: 1.0
**/
void void
hb_font_glyph_to_string (hb_font_t *font, hb_font_glyph_to_string (hb_font_t *font,
hb_codepoint_t glyph, hb_codepoint_t glyph,
@ -496,6 +811,19 @@ hb_font_glyph_to_string (hb_font_t *font,
} }
/* Parses gidDDD and uniUUUU strings automatically. */ /* Parses gidDDD and uniUUUU strings automatically. */
/**
* hb_font_glyph_from_string:
* @font: a font.
* @s: (array length=len):
* @len:
* @glyph: (out):
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_font_glyph_from_string (hb_font_t *font, hb_font_glyph_from_string (hb_font_t *font,
const char *s, int len, /* -1 means nul-terminated */ const char *s, int len, /* -1 means nul-terminated */
@ -509,6 +837,16 @@ hb_font_glyph_from_string (hb_font_t *font,
* hb_font_t * hb_font_t
*/ */
/**
* hb_font_create: (Xconstructor)
* @face: a face.
*
*
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_font_t * hb_font_t *
hb_font_create (hb_face_t *face) hb_font_create (hb_face_t *face)
{ {
@ -528,6 +866,16 @@ hb_font_create (hb_face_t *face)
return font; return font;
} }
/**
* hb_font_create_sub_font:
* @parent: parent font.
*
*
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_font_t * hb_font_t *
hb_font_create_sub_font (hb_font_t *parent) hb_font_create_sub_font (hb_font_t *parent)
{ {
@ -550,6 +898,15 @@ hb_font_create_sub_font (hb_font_t *parent)
return font; return font;
} }
/**
* hb_font_get_empty:
*
*
*
* Return value: (transfer full)
*
* Since: 1.0
**/
hb_font_t * hb_font_t *
hb_font_get_empty (void) hb_font_get_empty (void)
{ {
@ -581,12 +938,30 @@ hb_font_get_empty (void)
return const_cast<hb_font_t *> (&_hb_font_nil); return const_cast<hb_font_t *> (&_hb_font_nil);
} }
/**
* hb_font_reference: (skip)
* @font: a font.
*
*
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_font_t * hb_font_t *
hb_font_reference (hb_font_t *font) hb_font_reference (hb_font_t *font)
{ {
return hb_object_reference (font); return hb_object_reference (font);
} }
/**
* hb_font_destroy: (skip)
* @font: a font.
*
*
*
* Since: 1.0
**/
void void
hb_font_destroy (hb_font_t *font) hb_font_destroy (hb_font_t *font)
{ {
@ -606,6 +981,20 @@ hb_font_destroy (hb_font_t *font)
free (font); free (font);
} }
/**
* hb_font_set_user_data: (skip)
* @font: a font.
* @key:
* @data:
* @destroy:
* @replace:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_font_set_user_data (hb_font_t *font, hb_font_set_user_data (hb_font_t *font,
hb_user_data_key_t *key, hb_user_data_key_t *key,
@ -616,6 +1005,17 @@ hb_font_set_user_data (hb_font_t *font,
return hb_object_set_user_data (font, key, data, destroy, replace); return hb_object_set_user_data (font, key, data, destroy, replace);
} }
/**
* hb_font_get_user_data: (skip)
* @font: a font.
* @key:
*
*
*
* Return value: (transfer none):
*
* Since: 1.0
**/
void * void *
hb_font_get_user_data (hb_font_t *font, hb_font_get_user_data (hb_font_t *font,
hb_user_data_key_t *key) hb_user_data_key_t *key)
@ -623,6 +1023,14 @@ hb_font_get_user_data (hb_font_t *font,
return hb_object_get_user_data (font, key); return hb_object_get_user_data (font, key);
} }
/**
* hb_font_make_immutable:
* @font: a font.
*
*
*
* Since: 1.0
**/
void void
hb_font_make_immutable (hb_font_t *font) hb_font_make_immutable (hb_font_t *font)
{ {
@ -632,18 +1040,48 @@ hb_font_make_immutable (hb_font_t *font)
font->immutable = true; font->immutable = true;
} }
/**
* hb_font_is_immutable:
* @font: a font.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_font_is_immutable (hb_font_t *font) hb_font_is_immutable (hb_font_t *font)
{ {
return font->immutable; return font->immutable;
} }
/**
* hb_font_get_parent:
* @font: a font.
*
*
*
* Return value: (transfer none):
*
* Since: 1.0
**/
hb_font_t * hb_font_t *
hb_font_get_parent (hb_font_t *font) hb_font_get_parent (hb_font_t *font)
{ {
return font->parent; return font->parent;
} }
/**
* hb_font_get_face:
* @font: a font.
*
*
*
* Return value: (transfer none):
*
* Since: 1.0
**/
hb_face_t * hb_face_t *
hb_font_get_face (hb_font_t *font) hb_font_get_face (hb_font_t *font)
{ {
@ -651,15 +1089,26 @@ hb_font_get_face (hb_font_t *font)
} }
/**
* hb_font_set_funcs:
* @font: a font.
* @klass: (closure font_data) (destroy destroy) (scope notified):
* @font_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_font_set_funcs (hb_font_t *font, hb_font_set_funcs (hb_font_t *font,
hb_font_funcs_t *klass, hb_font_funcs_t *klass,
void *user_data, void *font_data,
hb_destroy_func_t destroy) hb_destroy_func_t destroy)
{ {
if (font->immutable) { if (font->immutable) {
if (destroy) if (destroy)
destroy (user_data); destroy (font_data);
return; return;
} }
@ -672,30 +1121,50 @@ hb_font_set_funcs (hb_font_t *font,
hb_font_funcs_reference (klass); hb_font_funcs_reference (klass);
hb_font_funcs_destroy (font->klass); hb_font_funcs_destroy (font->klass);
font->klass = klass; font->klass = klass;
font->user_data = user_data; font->user_data = font_data;
font->destroy = destroy; font->destroy = destroy;
} }
/**
* hb_font_set_funcs_data:
* @font: a font.
* @font_data: (destroy destroy) (scope notified):
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_font_set_funcs_data (hb_font_t *font, hb_font_set_funcs_data (hb_font_t *font,
void *user_data, void *font_data,
hb_destroy_func_t destroy) hb_destroy_func_t destroy)
{ {
/* Destroy user_data? */ /* Destroy user_data? */
if (font->immutable) { if (font->immutable) {
if (destroy) if (destroy)
destroy (user_data); destroy (font_data);
return; return;
} }
if (font->destroy) if (font->destroy)
font->destroy (font->user_data); font->destroy (font->user_data);
font->user_data = user_data; font->user_data = font_data;
font->destroy = destroy; font->destroy = destroy;
} }
/**
* hb_font_set_scale:
* @font: a font.
* @x_scale:
* @y_scale:
*
*
*
* Since: 1.0
**/
void void
hb_font_set_scale (hb_font_t *font, hb_font_set_scale (hb_font_t *font,
int x_scale, int x_scale,
@ -708,6 +1177,16 @@ hb_font_set_scale (hb_font_t *font,
font->y_scale = y_scale; font->y_scale = y_scale;
} }
/**
* hb_font_get_scale:
* @font: a font.
* @x_scale: (out):
* @y_scale: (out):
*
*
*
* Since: 1.0
**/
void void
hb_font_get_scale (hb_font_t *font, hb_font_get_scale (hb_font_t *font,
int *x_scale, int *x_scale,
@ -717,6 +1196,16 @@ hb_font_get_scale (hb_font_t *font,
if (y_scale) *y_scale = font->y_scale; if (y_scale) *y_scale = font->y_scale;
} }
/**
* hb_font_set_ppem:
* @font: a font.
* @x_ppem:
* @y_ppem:
*
*
*
* Since: 1.0
**/
void void
hb_font_set_ppem (hb_font_t *font, hb_font_set_ppem (hb_font_t *font,
unsigned int x_ppem, unsigned int x_ppem,
@ -729,6 +1218,16 @@ hb_font_set_ppem (hb_font_t *font,
font->y_ppem = y_ppem; font->y_ppem = y_ppem;
} }
/**
* hb_font_get_ppem:
* @font: a font.
* @x_ppem: (out):
* @y_ppem: (out):
*
*
*
* Since: 1.0
**/
void void
hb_font_get_ppem (hb_font_t *font, hb_font_get_ppem (hb_font_t *font,
unsigned int *x_ppem, unsigned int *x_ppem,

View File

@ -139,54 +139,180 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
/* func setters */ /* func setters */
/**
* hb_font_funcs_set_glyph_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_func_t glyph_func, hb_font_get_glyph_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_h_advance_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs, hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_advance_func_t func, hb_font_get_glyph_h_advance_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_v_advance_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs, hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_advance_func_t func, hb_font_get_glyph_v_advance_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_h_origin_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs, hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_origin_func_t func, hb_font_get_glyph_h_origin_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_v_origin_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs, hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_origin_func_t func, hb_font_get_glyph_v_origin_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_h_kerning_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs, hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_kerning_func_t func, hb_font_get_glyph_h_kerning_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_v_kerning_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs, hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_kerning_func_t func, hb_font_get_glyph_v_kerning_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_extents_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs, hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_extents_func_t func, hb_font_get_glyph_extents_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_contour_point_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs, hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_contour_point_func_t func, hb_font_get_glyph_contour_point_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_name_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs, hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_name_func_t glyph_func, hb_font_get_glyph_name_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_from_name_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs, hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_from_name_func_t glyph_func, hb_font_get_glyph_from_name_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);

View File

@ -31,8 +31,6 @@
#include "hb-private.hh" #include "hb-private.hh"
#include "hb-blob.h"
namespace OT { namespace OT {

View File

@ -43,7 +43,7 @@ namespace OT {
struct head struct head
{ {
static const hb_tag_t Tag = HB_OT_TAG_head; static const hb_tag_t tableTag = HB_OT_TAG_head;
inline unsigned int get_upem (void) const { inline unsigned int get_upem (void) const {
unsigned int upem = unitsPerEm; unsigned int upem = unitsPerEm;

View File

@ -42,7 +42,7 @@ namespace OT {
struct hhea struct hhea
{ {
static const hb_tag_t Tag = HB_OT_TAG_hhea; static const hb_tag_t tableTag = HB_OT_TAG_hhea;
inline bool sanitize (hb_sanitize_context_t *c) { inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);

View File

@ -50,7 +50,7 @@ struct LongHorMetric
struct hmtx struct hmtx
{ {
static const hb_tag_t Tag = HB_OT_TAG_hmtx; static const hb_tag_t tableTag = HB_OT_TAG_hmtx;
inline bool sanitize (hb_sanitize_context_t *c) { inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);

View File

@ -39,6 +39,7 @@ namespace OT {
#define NOT_COVERED ((unsigned int) -1) #define NOT_COVERED ((unsigned int) -1)
#define MAX_NESTING_LEVEL 8 #define MAX_NESTING_LEVEL 8
#define MAX_CONTEXT_LENGTH 64
@ -376,7 +377,7 @@ struct FeatureParamsStylisticSet
return TRACE_RETURN (c->check_struct (this)); return TRACE_RETURN (c->check_struct (this));
} }
USHORT minorVersion; /* (set to 0): This corresponds to a “minor” USHORT version; /* (set to 0): This corresponds to a “minor”
* version number. Additional data may be * version number. Additional data may be
* added to the end of this Feature Parameters * added to the end of this Feature Parameters
* table in the future. */ * table in the future. */
@ -399,6 +400,7 @@ struct FeatureParamsStylisticSet
DEFINE_SIZE_STATIC (4); DEFINE_SIZE_STATIC (4);
}; };
/* http://www.microsoft.com/typography/otspec/features_ae.htm#cv01-cv99 */
struct FeatureParamsCharacterVariants struct FeatureParamsCharacterVariants
{ {
inline bool sanitize (hb_sanitize_context_t *c) { inline bool sanitize (hb_sanitize_context_t *c) {
@ -1111,7 +1113,7 @@ struct Device
if (!pixels) return 0; if (!pixels) return 0;
return pixels * (int64_t) scale / ppem; return (int) (pixels * (int64_t) scale / ppem);
} }

View File

@ -324,7 +324,7 @@ struct MarkGlyphSets
struct GDEF struct GDEF
{ {
static const hb_tag_t Tag = HB_OT_TAG_GDEF; static const hb_tag_t tableTag = HB_OT_TAG_GDEF;
enum GlyphClasses { enum GlyphClasses {
UnclassifiedGlyph = 0, UnclassifiedGlyph = 0,
@ -383,12 +383,14 @@ struct GDEF
{ {
unsigned int klass = get_glyph_class (glyph); unsigned int klass = get_glyph_class (glyph);
ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs);
ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures);
ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks);
switch (klass) { switch (klass) {
default: default: return 0;
case UnclassifiedGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_UNCLASSIFIED;
case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH; case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
case ComponentGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_COMPONENT;
case MarkGlyph: case MarkGlyph:
klass = get_mark_attachment_type (glyph); klass = get_mark_attachment_type (glyph);
return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8); return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);

View File

@ -390,6 +390,7 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde
unsigned int glyph_pos) const unsigned int glyph_pos) const
{ {
TRACE_APPLY (this); TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index); const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
unsigned int mark_class = record.klass; unsigned int mark_class = record.klass;
@ -402,15 +403,15 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde
hb_position_t mark_x, mark_y, base_x, base_y; hb_position_t mark_x, mark_y, base_x, base_y;
mark_anchor.get_anchor (c->font, c->buffer->cur().codepoint, &mark_x, &mark_y); mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y);
glyph_anchor.get_anchor (c->font, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y); glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
hb_glyph_position_t &o = c->buffer->cur_pos(); hb_glyph_position_t &o = buffer->cur_pos();
o.x_offset = base_x - mark_x; o.x_offset = base_x - mark_x;
o.y_offset = base_y - mark_y; o.y_offset = base_y - mark_y;
o.attach_lookback() = c->buffer->idx - glyph_pos; o.attach_lookback() = buffer->idx - glyph_pos;
c->buffer->idx++; buffer->idx++;
return TRACE_RETURN (true); return TRACE_RETURN (true);
} }
@ -439,13 +440,14 @@ struct SinglePosFormat1
inline bool apply (hb_apply_context_t *c) const inline bool apply (hb_apply_context_t *c) const
{ {
TRACE_APPLY (this); TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); hb_buffer_t *buffer = c->buffer;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
valueFormat.apply_value (c->font, c->direction, this, valueFormat.apply_value (c->font, c->direction, this,
values, c->buffer->cur_pos()); values, buffer->cur_pos());
c->buffer->idx++; buffer->idx++;
return TRACE_RETURN (true); return TRACE_RETURN (true);
} }
@ -484,16 +486,17 @@ struct SinglePosFormat2
inline bool apply (hb_apply_context_t *c) const inline bool apply (hb_apply_context_t *c) const
{ {
TRACE_APPLY (this); TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); hb_buffer_t *buffer = c->buffer;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
if (likely (index >= valueCount)) return TRACE_RETURN (false); if (likely (index >= valueCount)) return TRACE_RETURN (false);
valueFormat.apply_value (c->font, c->direction, this, valueFormat.apply_value (c->font, c->direction, this,
&values[index * valueFormat.get_len ()], &values[index * valueFormat.get_len ()],
c->buffer->cur_pos()); buffer->cur_pos());
c->buffer->idx++; buffer->idx++;
return TRACE_RETURN (true); return TRACE_RETURN (true);
} }
@ -588,6 +591,7 @@ struct PairSet
unsigned int pos) const unsigned int pos) const
{ {
TRACE_APPLY (this); TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
unsigned int len1 = valueFormats[0].get_len (); unsigned int len1 = valueFormats[0].get_len ();
unsigned int len2 = valueFormats[1].get_len (); unsigned int len2 = valueFormats[1].get_len ();
unsigned int record_size = USHORT::static_size * (1 + len1 + len2); unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
@ -597,15 +601,15 @@ struct PairSet
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
{ {
/* TODO bsearch */ /* TODO bsearch */
if (c->buffer->info[pos].codepoint == record->secondGlyph) if (buffer->info[pos].codepoint == record->secondGlyph)
{ {
valueFormats[0].apply_value (c->font, c->direction, this, valueFormats[0].apply_value (c->font, c->direction, this,
&record->values[0], c->buffer->cur_pos()); &record->values[0], buffer->cur_pos());
valueFormats[1].apply_value (c->font, c->direction, this, valueFormats[1].apply_value (c->font, c->direction, this,
&record->values[len1], c->buffer->pos[pos]); &record->values[len1], buffer->pos[pos]);
if (len2) if (len2)
pos++; pos++;
c->buffer->idx = pos; buffer->idx = pos;
return TRACE_RETURN (true); return TRACE_RETURN (true);
} }
record = &StructAtOffset<PairValueRecord> (record, record_size); record = &StructAtOffset<PairValueRecord> (record, record_size);
@ -659,10 +663,11 @@ struct PairPosFormat1
inline bool apply (hb_apply_context_t *c) const inline bool apply (hb_apply_context_t *c) const
{ {
TRACE_APPLY (this); TRACE_APPLY (this);
hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1); hb_buffer_t *buffer = c->buffer;
hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
if (!skippy_iter.next ()) return TRACE_RETURN (false); if (!skippy_iter.next ()) return TRACE_RETURN (false);
@ -729,10 +734,11 @@ struct PairPosFormat2
inline bool apply (hb_apply_context_t *c) const inline bool apply (hb_apply_context_t *c) const
{ {
TRACE_APPLY (this); TRACE_APPLY (this);
hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1); hb_buffer_t *buffer = c->buffer;
hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
if (!skippy_iter.next ()) return TRACE_RETURN (false); if (!skippy_iter.next ()) return TRACE_RETURN (false);
@ -741,19 +747,19 @@ struct PairPosFormat2
unsigned int len2 = valueFormat2.get_len (); unsigned int len2 = valueFormat2.get_len ();
unsigned int record_len = len1 + len2; unsigned int record_len = len1 + len2;
unsigned int klass1 = (this+classDef1).get_class (c->buffer->cur().codepoint); unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
unsigned int klass2 = (this+classDef2).get_class (c->buffer->info[skippy_iter.idx].codepoint); unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false); if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false);
const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
valueFormat1.apply_value (c->font, c->direction, this, valueFormat1.apply_value (c->font, c->direction, this,
v, c->buffer->cur_pos()); v, buffer->cur_pos());
valueFormat2.apply_value (c->font, c->direction, this, valueFormat2.apply_value (c->font, c->direction, this,
v + len1, c->buffer->pos[skippy_iter.idx]); v + len1, buffer->pos[skippy_iter.idx]);
c->buffer->idx = skippy_iter.idx; buffer->idx = skippy_iter.idx;
if (len2) if (len2)
c->buffer->idx++; buffer->idx++;
return TRACE_RETURN (true); return TRACE_RETURN (true);
} }
@ -875,29 +881,30 @@ struct CursivePosFormat1
inline bool apply (hb_apply_context_t *c) const inline bool apply (hb_apply_context_t *c) const
{ {
TRACE_APPLY (this); TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
/* We don't handle mark glyphs here. */ /* We don't handle mark glyphs here. */
if (c->buffer->cur().glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK) return TRACE_RETURN (false); if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return TRACE_RETURN (false);
hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1); hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (c->buffer->cur().codepoint)]; const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)];
if (!this_record.exitAnchor) return TRACE_RETURN (false); if (!this_record.exitAnchor) return TRACE_RETURN (false);
if (!skippy_iter.next ()) return TRACE_RETURN (false); if (!skippy_iter.next ()) return TRACE_RETURN (false);
const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage (c->buffer->info[skippy_iter.idx].codepoint)]; const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)];
if (!next_record.entryAnchor) return TRACE_RETURN (false); if (!next_record.entryAnchor) return TRACE_RETURN (false);
unsigned int i = c->buffer->idx; unsigned int i = buffer->idx;
unsigned int j = skippy_iter.idx; unsigned int j = skippy_iter.idx;
hb_position_t entry_x, entry_y, exit_x, exit_y; hb_position_t entry_x, entry_y, exit_x, exit_y;
(this+this_record.exitAnchor).get_anchor (c->font, c->buffer->info[i].codepoint, &exit_x, &exit_y); (this+this_record.exitAnchor).get_anchor (c->font, buffer->info[i].codepoint, &exit_x, &exit_y);
(this+next_record.entryAnchor).get_anchor (c->font, c->buffer->info[j].codepoint, &entry_x, &entry_y); (this+next_record.entryAnchor).get_anchor (c->font, buffer->info[j].codepoint, &entry_x, &entry_y);
hb_glyph_position_t *pos = c->buffer->pos; hb_glyph_position_t *pos = buffer->pos;
hb_position_t d; hb_position_t d;
/* Main-direction adjustment */ /* Main-direction adjustment */
@ -950,7 +957,7 @@ struct CursivePosFormat1
pos[j].x_offset = exit_x - entry_x; pos[j].x_offset = exit_x - entry_x;
} }
c->buffer->idx = j; buffer->idx = j;
return TRACE_RETURN (true); return TRACE_RETURN (true);
} }
@ -1022,23 +1029,24 @@ struct MarkBasePosFormat1
inline bool apply (hb_apply_context_t *c) const inline bool apply (hb_apply_context_t *c) const
{ {
TRACE_APPLY (this); TRACE_APPLY (this);
unsigned int mark_index = (this+markCoverage).get_coverage (c->buffer->cur().codepoint); hb_buffer_t *buffer = c->buffer;
unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false); if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
/* now we search backwards for a non-mark glyph */ /* now we search backwards for a non-mark glyph */
hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1); hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
do { do {
if (!skippy_iter.prev ()) return TRACE_RETURN (false); if (!skippy_iter.prev ()) return TRACE_RETURN (false);
/* We only want to attach to the first of a MultipleSubst sequence. Reject others. */ /* We only want to attach to the first of a MultipleSubst sequence. Reject others. */
if (0 == get_lig_comp (c->buffer->info[skippy_iter.idx])) break; if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
skippy_iter.reject (); skippy_iter.reject ();
} while (1); } while (1);
/* The following assertion is too strong, so we've disabled it. */ /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH)) {/*return TRACE_RETURN (false);*/} if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
unsigned int base_index = (this+baseCoverage).get_coverage (c->buffer->info[skippy_iter.idx].codepoint); unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint);
if (base_index == NOT_COVERED) return TRACE_RETURN (false); if (base_index == NOT_COVERED) return TRACE_RETURN (false);
return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
@ -1125,19 +1133,20 @@ struct MarkLigPosFormat1
inline bool apply (hb_apply_context_t *c) const inline bool apply (hb_apply_context_t *c) const
{ {
TRACE_APPLY (this); TRACE_APPLY (this);
unsigned int mark_index = (this+markCoverage).get_coverage (c->buffer->cur().codepoint); hb_buffer_t *buffer = c->buffer;
unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false); if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
/* now we search backwards for a non-mark glyph */ /* now we search backwards for a non-mark glyph */
hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1); hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
if (!skippy_iter.prev ()) return TRACE_RETURN (false); if (!skippy_iter.prev ()) return TRACE_RETURN (false);
/* The following assertion is too strong, so we've disabled it. */ /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE)) {/*return TRACE_RETURN (false);*/} if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
unsigned int j = skippy_iter.idx; unsigned int j = skippy_iter.idx;
unsigned int lig_index = (this+ligatureCoverage).get_coverage (c->buffer->info[j].codepoint); unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint);
if (lig_index == NOT_COVERED) return TRACE_RETURN (false); if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
const LigatureArray& lig_array = this+ligatureArray; const LigatureArray& lig_array = this+ligatureArray;
@ -1152,11 +1161,11 @@ struct MarkLigPosFormat1
* can directly use the component index. If not, we attach the mark * can directly use the component index. If not, we attach the mark
* glyph to the last component of the ligature. */ * glyph to the last component of the ligature. */
unsigned int comp_index; unsigned int comp_index;
unsigned int lig_id = get_lig_id (c->buffer->info[j]); unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
unsigned int mark_id = get_lig_id (c->buffer->cur()); unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
unsigned int mark_comp = get_lig_comp (c->buffer->cur()); unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
if (lig_id && lig_id == mark_id && mark_comp > 0) if (lig_id && lig_id == mark_id && mark_comp > 0)
comp_index = MIN (comp_count, get_lig_comp (c->buffer->cur())) - 1; comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
else else
comp_index = comp_count - 1; comp_index = comp_count - 1;
@ -1240,22 +1249,23 @@ struct MarkMarkPosFormat1
inline bool apply (hb_apply_context_t *c) const inline bool apply (hb_apply_context_t *c) const
{ {
TRACE_APPLY (this); TRACE_APPLY (this);
unsigned int mark1_index = (this+mark1Coverage).get_coverage (c->buffer->cur().codepoint); hb_buffer_t *buffer = c->buffer;
unsigned int mark1_index = (this+mark1Coverage).get_coverage (buffer->cur().codepoint);
if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false); if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
/* now we search backwards for a suitable mark glyph until a non-mark glyph */ /* now we search backwards for a suitable mark glyph until a non-mark glyph */
hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1); hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags); skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
if (!skippy_iter.prev ()) return TRACE_RETURN (false); if (!skippy_iter.prev ()) return TRACE_RETURN (false);
if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) { return TRACE_RETURN (false); } if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return TRACE_RETURN (false); }
unsigned int j = skippy_iter.idx; unsigned int j = skippy_iter.idx;
unsigned int id1 = get_lig_id (c->buffer->cur()); unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
unsigned int id2 = get_lig_id (c->buffer->info[j]); unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
unsigned int comp1 = get_lig_comp (c->buffer->cur()); unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
unsigned int comp2 = get_lig_comp (c->buffer->info[j]); unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
if (likely (id1 == id2)) { if (likely (id1 == id2)) {
if (id1 == 0) /* Marks belonging to the same base. */ if (id1 == 0) /* Marks belonging to the same base. */
@ -1273,7 +1283,7 @@ struct MarkMarkPosFormat1
return TRACE_RETURN (false); return TRACE_RETURN (false);
good: good:
unsigned int mark2_index = (this+mark2Coverage).get_coverage (c->buffer->info[j].codepoint); unsigned int mark2_index = (this+mark2Coverage).get_coverage (buffer->info[j].codepoint);
if (mark2_index == NOT_COVERED) return TRACE_RETURN (false); if (mark2_index == NOT_COVERED) return TRACE_RETURN (false);
return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j)); return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
@ -1434,12 +1444,6 @@ struct PosLookup : Lookup
return false; return false;
} }
inline hb_is_inplace_context_t::return_t is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
return TRACE_RETURN (true);
}
inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
TRACE_COLLECT_GLYPHS (this); TRACE_COLLECT_GLYPHS (this);
@ -1505,7 +1509,7 @@ typedef OffsetListOf<PosLookup> PosLookupList;
struct GPOS : GSUBGPOS struct GPOS : GSUBGPOS
{ {
static const hb_tag_t Tag = HB_OT_TAG_GPOS; static const hb_tag_t tableTag = HB_OT_TAG_GPOS;
inline const PosLookup& get_lookup (unsigned int i) const inline const PosLookup& get_lookup (unsigned int i) const
{ return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); } { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
@ -1591,9 +1595,7 @@ GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
for (unsigned int i = 0; i < len; i++) for (unsigned int i = 0; i < len; i++)
fix_mark_attachment (pos, i, direction); fix_mark_attachment (pos, i, direction);
HB_BUFFER_DEALLOCATE_VAR (buffer, syllable); _hb_buffer_deallocate_gsubgpos_vars (buffer);
HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
} }

View File

@ -37,12 +37,6 @@ namespace OT {
struct SingleSubstFormat1 struct SingleSubstFormat1
{ {
inline bool is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
return TRACE_RETURN (true);
}
inline void closure (hb_closure_context_t *c) const inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -121,12 +115,6 @@ struct SingleSubstFormat1
struct SingleSubstFormat2 struct SingleSubstFormat2
{ {
inline bool is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
return TRACE_RETURN (true);
}
inline void closure (hb_closure_context_t *c) const inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -263,13 +251,6 @@ struct SingleSubst
struct Sequence struct Sequence
{ {
inline bool is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
/* For len==0 we don't do anything, so it's harmless. */
return TRACE_RETURN (substitute.len <= 1);
}
inline void closure (hb_closure_context_t *c) const inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -291,8 +272,8 @@ struct Sequence
TRACE_APPLY (this); TRACE_APPLY (this);
if (unlikely (!substitute.len)) return TRACE_RETURN (false); if (unlikely (!substitute.len)) return TRACE_RETURN (false);
unsigned int klass = c->buffer->cur().glyph_props() & unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE ? HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0; HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
unsigned int count = substitute.len; unsigned int count = substitute.len;
if (count == 1) /* Special-case to make it in-place. */ if (count == 1) /* Special-case to make it in-place. */
{ {
@ -301,7 +282,7 @@ struct Sequence
else else
{ {
for (unsigned int i = 0; i < count; i++) { for (unsigned int i = 0; i < count; i++) {
set_lig_props_for_component (c->buffer->cur(), i); _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
c->output_glyph (substitute.array[i], klass); c->output_glyph (substitute.array[i], klass);
} }
c->buffer->skip_glyph (); c->buffer->skip_glyph ();
@ -334,18 +315,6 @@ struct Sequence
struct MultipleSubstFormat1 struct MultipleSubstFormat1
{ {
inline bool is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
/* Some tools generate MultipleSubst with each substitute having length 1!
* So, check them. */
unsigned int count = sequence.len;
for (unsigned int i = 0; i < count; i++)
if (!(this+sequence[i]).is_inplace (c))
return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
inline void closure (hb_closure_context_t *c) const inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -471,12 +440,6 @@ typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
struct AlternateSubstFormat1 struct AlternateSubstFormat1
{ {
inline bool is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
return TRACE_RETURN (true);
}
inline void closure (hb_closure_context_t *c) const inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -663,27 +626,26 @@ struct Ligature
unsigned int count = component.len; unsigned int count = component.len;
if (unlikely (count < 1)) return TRACE_RETURN (false); if (unlikely (count < 1)) return TRACE_RETURN (false);
unsigned int end_offset = 0;
bool is_mark_ligature = false; bool is_mark_ligature = false;
unsigned int total_component_count = 0; unsigned int total_component_count = 0;
unsigned int match_length = 0;
unsigned int match_positions[MAX_CONTEXT_LENGTH];
if (likely (!match_input (c, count, if (likely (!match_input (c, count,
&component[1], &component[1],
match_glyph, match_glyph,
NULL, NULL,
&end_offset, &match_length,
match_positions,
&is_mark_ligature, &is_mark_ligature,
&total_component_count))) &total_component_count)))
return TRACE_RETURN (false); return TRACE_RETURN (false);
/* Deal, we are forming the ligature. */
c->buffer->merge_clusters (c->buffer->idx, c->buffer->idx + end_offset);
ligate_input (c, ligate_input (c,
count, count,
&component[1], match_positions,
match_glyph, match_length,
NULL,
ligGlyph, ligGlyph,
is_mark_ligature, is_mark_ligature,
total_component_count); total_component_count);
@ -797,12 +759,6 @@ struct LigatureSet
struct LigatureSubstFormat1 struct LigatureSubstFormat1
{ {
inline bool is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
return TRACE_RETURN (false);
}
inline void closure (hb_closure_context_t *c) const inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -951,12 +907,6 @@ struct ExtensionSubst : Extension<ExtensionSubst>
struct ReverseChainSingleSubstFormat1 struct ReverseChainSingleSubstFormat1
{ {
inline bool is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
return TRACE_RETURN (true);
}
inline void closure (hb_closure_context_t *c) const inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -1038,7 +988,9 @@ struct ReverseChainSingleSubstFormat1
1)) 1))
{ {
c->replace_glyph_inplace (substitute[index]); c->replace_glyph_inplace (substitute[index]);
c->buffer->idx--; /* Reverse! */ /* Note: We DON'T decrease buffer->idx. The main loop does it
* for us. This is useful for preventing surprises if someone
* calls us through a Context lookup. */
return TRACE_RETURN (true); return TRACE_RETURN (true);
} }
@ -1194,13 +1146,6 @@ struct SubstLookup : Lookup
return lookup_type_is_reverse (type); return lookup_type_is_reverse (type);
} }
inline hb_is_inplace_context_t::return_t is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
c->set_recurse_func (dispatch_recurse_func<hb_is_inplace_context_t>);
return TRACE_RETURN (dispatch (c));
}
inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -1351,7 +1296,7 @@ typedef OffsetListOf<SubstLookup> SubstLookupList;
struct GSUB : GSUBGPOS struct GSUB : GSUBGPOS
{ {
static const hb_tag_t Tag = HB_OT_TAG_GSUB; static const hb_tag_t tableTag = HB_OT_TAG_GSUB;
inline const SubstLookup& get_lookup (unsigned int i) const inline const SubstLookup& get_lookup (unsigned int i) const
{ return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); } { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
@ -1373,15 +1318,15 @@ struct GSUB : GSUBGPOS
void void
GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer) GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
{ {
HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props); _hb_buffer_allocate_gsubgpos_vars (buffer);
HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef; const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
unsigned int count = buffer->len; unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++) { for (unsigned int i = 0; i < count; i++)
buffer->info[i].lig_props() = buffer->info[i].syllable() = 0; {
buffer->info[i].glyph_props() = gdef.get_glyph_props (buffer->info[i].codepoint); _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
_hb_glyph_info_clear_lig_props (&buffer->info[i]);
buffer->info[i].syllable() = 0;
} }
} }

View File

@ -43,56 +43,6 @@ namespace OT {
(&c->debug_depth, c->get_name (), this, HB_FUNC, \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \
""); "");
#ifndef HB_DEBUG_IS_INPLACE
#define HB_DEBUG_IS_INPLACE (HB_DEBUG+0)
#endif
#define TRACE_IS_INPLACE(this) \
hb_auto_trace_t<HB_DEBUG_IS_INPLACE, bool> trace \
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
"");
struct hb_is_inplace_context_t
{
inline const char *get_name (void) { return "IS_INPLACE"; }
static const unsigned int max_debug_depth = HB_DEBUG_IS_INPLACE;
typedef bool return_t;
typedef return_t (*recurse_func_t) (hb_is_inplace_context_t *c, unsigned int lookup_index);
template <typename T>
inline return_t dispatch (const T &obj) { return obj.is_inplace (this); }
static return_t default_return_value (void) { return true; }
bool stop_sublookup_iteration (return_t r) const { return !r; }
return_t recurse (unsigned int lookup_index)
{
if (unlikely (nesting_level_left == 0 || !recurse_func))
return default_return_value ();
nesting_level_left--;
bool ret = recurse_func (this, lookup_index);
nesting_level_left++;
return ret;
}
hb_face_t *face;
recurse_func_t recurse_func;
unsigned int nesting_level_left;
unsigned int debug_depth;
hb_is_inplace_context_t (hb_face_t *face_,
unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
face (face_),
recurse_func (NULL),
nesting_level_left (nesting_level_left_),
debug_depth (0) {}
void set_recurse_func (recurse_func_t func) { recurse_func = func; }
};
#ifndef HB_DEBUG_CLOSURE #ifndef HB_DEBUG_CLOSURE
#define HB_DEBUG_CLOSURE (HB_DEBUG+0) #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
#endif #endif
@ -401,7 +351,7 @@ struct hb_apply_context_t
{ {
unsigned int property; unsigned int property;
property = info.glyph_props(); property = _hb_glyph_info_get_glyph_props (&info);
if (!c->match_properties (info.codepoint, property, lookup_props)) if (!c->match_properties (info.codepoint, property, lookup_props))
return SKIP_YES; return SKIP_YES;
@ -409,7 +359,7 @@ struct hb_apply_context_t
if (unlikely (_hb_glyph_info_is_default_ignorable (&info) && if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
(ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) && (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
(ignore_zwj || !_hb_glyph_info_is_zwj (&info)) && (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) &&
!is_a_ligature (info))) !_hb_glyph_info_ligated (&info)))
return SKIP_MAYBE; return SKIP_MAYBE;
return SKIP_NO; return SKIP_NO;
@ -610,37 +560,48 @@ struct hb_apply_context_t
{ {
unsigned int property; unsigned int property;
property = info->glyph_props(); property = _hb_glyph_info_get_glyph_props (info);
return match_properties (info->codepoint, property, lookup_props); return match_properties (info->codepoint, property, lookup_props);
} }
inline void set_class (hb_codepoint_t glyph_index, unsigned int class_guess) const inline void _set_glyph_props (hb_codepoint_t glyph_index,
unsigned int class_guess = 0,
bool ligature = false) const
{ {
unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
if (ligature)
add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
if (likely (has_glyph_classes)) if (likely (has_glyph_classes))
buffer->cur().glyph_props() = gdef.get_glyph_props (glyph_index); _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
else if (class_guess) else if (class_guess)
buffer->cur().glyph_props() = class_guess; _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
} }
inline void output_glyph (hb_codepoint_t glyph_index, inline void replace_glyph (hb_codepoint_t glyph_index) const
unsigned int class_guess = 0) const
{ {
set_class (glyph_index, class_guess); _set_glyph_props (glyph_index);
buffer->output_glyph (glyph_index);
}
inline void replace_glyph (hb_codepoint_t glyph_index,
unsigned int class_guess = 0) const
{
set_class (glyph_index, class_guess);
buffer->replace_glyph (glyph_index); buffer->replace_glyph (glyph_index);
} }
inline void replace_glyph_inplace (hb_codepoint_t glyph_index, inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
unsigned int class_guess = 0) const
{ {
set_class (glyph_index, class_guess); _set_glyph_props (glyph_index);
buffer->cur().codepoint = glyph_index; buffer->cur().codepoint = glyph_index;
} }
inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
unsigned int class_guess) const
{
_set_glyph_props (glyph_index, class_guess, true);
buffer->replace_glyph (glyph_index);
}
inline void output_glyph (hb_codepoint_t glyph_index,
unsigned int class_guess) const
{
_set_glyph_props (glyph_index, class_guess);
buffer->output_glyph (glyph_index);
}
}; };
@ -752,13 +713,18 @@ static inline bool match_input (hb_apply_context_t *c,
const USHORT input[], /* Array of input values--start with second glyph */ const USHORT input[], /* Array of input values--start with second glyph */
match_func_t match_func, match_func_t match_func,
const void *match_data, const void *match_data,
unsigned int *end_offset = NULL, unsigned int *end_offset,
unsigned int match_positions[MAX_CONTEXT_LENGTH],
bool *p_is_mark_ligature = NULL, bool *p_is_mark_ligature = NULL,
unsigned int *p_total_component_count = NULL) unsigned int *p_total_component_count = NULL)
{ {
TRACE_APPLY (NULL); TRACE_APPLY (NULL);
hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1); if (unlikely (count > MAX_CONTEXT_LENGTH)) TRACE_RETURN (false);
hb_buffer_t *buffer = c->buffer;
hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, count - 1);
skippy_iter.set_match_func (match_func, match_data, input); skippy_iter.set_match_func (match_func, match_data, input);
if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
@ -780,20 +746,23 @@ static inline bool match_input (hb_apply_context_t *c,
* ligate with a conjunct...) * ligate with a conjunct...)
*/ */
bool is_mark_ligature = !!(c->buffer->cur().glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK); bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
unsigned int total_component_count = 0; unsigned int total_component_count = 0;
total_component_count += get_lig_num_comps (c->buffer->cur()); total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
unsigned int first_lig_id = get_lig_id (c->buffer->cur()); unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
unsigned int first_lig_comp = get_lig_comp (c->buffer->cur()); unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
match_positions[0] = buffer->idx;
for (unsigned int i = 1; i < count; i++) for (unsigned int i = 1; i < count; i++)
{ {
if (!skippy_iter.next ()) return TRACE_RETURN (false); if (!skippy_iter.next ()) return TRACE_RETURN (false);
unsigned int this_lig_id = get_lig_id (c->buffer->info[skippy_iter.idx]); match_positions[i] = skippy_iter.idx;
unsigned int this_lig_comp = get_lig_comp (c->buffer->info[skippy_iter.idx]);
unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
if (first_lig_id && first_lig_comp) { if (first_lig_id && first_lig_comp) {
/* If first component was attached to a previous ligature component, /* If first component was attached to a previous ligature component,
@ -809,12 +778,11 @@ static inline bool match_input (hb_apply_context_t *c,
return TRACE_RETURN (false); return TRACE_RETURN (false);
} }
is_mark_ligature = is_mark_ligature && (c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK); is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
total_component_count += get_lig_num_comps (c->buffer->info[skippy_iter.idx]); total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
} }
if (end_offset) *end_offset = skippy_iter.idx - buffer->idx + 1;
*end_offset = skippy_iter.idx - c->buffer->idx + 1;
if (p_is_mark_ligature) if (p_is_mark_ligature)
*p_is_mark_ligature = is_mark_ligature; *p_is_mark_ligature = is_mark_ligature;
@ -825,17 +793,18 @@ static inline bool match_input (hb_apply_context_t *c,
return TRACE_RETURN (true); return TRACE_RETURN (true);
} }
static inline void ligate_input (hb_apply_context_t *c, static inline void ligate_input (hb_apply_context_t *c,
unsigned int count, /* Including the first glyph (not matched) */ unsigned int count, /* Including the first glyph */
const USHORT input[], /* Array of input values--start with second glyph */ unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
match_func_t match_func, unsigned int match_length,
const void *match_data,
hb_codepoint_t lig_glyph, hb_codepoint_t lig_glyph,
bool is_mark_ligature, bool is_mark_ligature,
unsigned int total_component_count) unsigned int total_component_count)
{ {
hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1); TRACE_APPLY (NULL);
skippy_iter.set_match_func (match_func, match_data, input);
if (skippy_iter.has_no_chance ()) return; hb_buffer_t *buffer = c->buffer;
buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
/* /*
* - If it *is* a mark ligature, we don't allocate a new ligature id, and leave * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
@ -866,48 +835,49 @@ static inline void ligate_input (hb_apply_context_t *c,
*/ */
unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
unsigned int lig_id = is_mark_ligature ? 0 : allocate_lig_id (c->buffer); unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer);
unsigned int last_lig_id = get_lig_id (c->buffer->cur()); unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
unsigned int last_num_components = get_lig_num_comps (c->buffer->cur()); unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
unsigned int components_so_far = last_num_components; unsigned int components_so_far = last_num_components;
if (!is_mark_ligature) if (!is_mark_ligature)
{ {
set_lig_props_for_ligature (c->buffer->cur(), lig_id, total_component_count); _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
if (_hb_glyph_info_get_general_category (&c->buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
_hb_glyph_info_set_general_category (&c->buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER); {
_hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
_hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0);
}
} }
c->replace_glyph (lig_glyph, klass); c->replace_glyph_with_ligature (lig_glyph, klass);
for (unsigned int i = 1; i < count; i++) for (unsigned int i = 1; i < count; i++)
{ {
if (!skippy_iter.next ()) return; while (buffer->idx < match_positions[i])
while (c->buffer->idx < skippy_iter.idx)
{ {
if (!is_mark_ligature) { if (!is_mark_ligature) {
unsigned int new_lig_comp = components_so_far - last_num_components + unsigned int new_lig_comp = components_so_far - last_num_components +
MIN (MAX (get_lig_comp (c->buffer->cur()), 1u), last_num_components); MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components);
set_lig_props_for_mark (c->buffer->cur(), lig_id, new_lig_comp); _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
} }
c->buffer->next_glyph (); buffer->next_glyph ();
} }
last_lig_id = get_lig_id (c->buffer->cur()); last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
last_num_components = get_lig_num_comps (c->buffer->cur()); last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
components_so_far += last_num_components; components_so_far += last_num_components;
/* Skip the base glyph */ /* Skip the base glyph */
c->buffer->idx++; buffer->idx++;
} }
if (!is_mark_ligature && last_lig_id) { if (!is_mark_ligature && last_lig_id) {
/* Re-adjust components for any marks following. */ /* Re-adjust components for any marks following. */
for (unsigned int i = c->buffer->idx; i < c->buffer->len; i++) { for (unsigned int i = buffer->idx; i < buffer->len; i++) {
if (last_lig_id == get_lig_id (c->buffer->info[i])) { if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
unsigned int new_lig_comp = components_so_far - last_num_components + unsigned int new_lig_comp = components_so_far - last_num_components +
MIN (MAX (get_lig_comp (c->buffer->info[i]), 1u), last_num_components); MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components);
set_lig_props_for_mark (c->buffer->info[i], lig_id, new_lig_comp); _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
} else } else
break; break;
} }
@ -982,99 +952,82 @@ static inline void recurse_lookups (context_t *c,
static inline bool apply_lookup (hb_apply_context_t *c, static inline bool apply_lookup (hb_apply_context_t *c,
unsigned int count, /* Including the first glyph */ unsigned int count, /* Including the first glyph */
const USHORT input[], /* Array of input values--start with second glyph */ unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
match_func_t match_func,
const void *match_data,
unsigned int lookupCount, unsigned int lookupCount,
const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */) const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
unsigned int match_length)
{ {
TRACE_APPLY (NULL); TRACE_APPLY (NULL);
unsigned int end = c->buffer->len; hb_buffer_t *buffer = c->buffer;
if (unlikely (count == 0 || c->buffer->idx + count > end)) unsigned int end;
return TRACE_RETURN (false);
/* TODO We don't support lookupRecord arrays that are not increasing: /* All positions are distance from beginning of *output* buffer.
* Should be easy for in_place ones at least. */ * Adjust. */
/* Note: If sublookup is reverse, it will underflow after the first loop
* and we jump out of it. Not entirely disastrous. So we don't check
* for reverse lookup here.
*/
hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
skippy_iter.set_match_func (match_func, match_data, input);
uint8_t syllable = c->buffer->cur().syllable();
unsigned int i = 0;
if (lookupCount && 0 == lookupRecord->sequenceIndex)
{ {
unsigned int old_pos = c->buffer->idx; unsigned int bl = buffer->backtrack_len ();
end = bl + match_length;
/* Apply a lookup */ int delta = bl - buffer->idx;
bool done = c->recurse (lookupRecord->lookupListIndex); /* Convert positions to new indexing. */
for (unsigned int j = 0; j < count; j++)
lookupRecord++; match_positions[j] += delta;
lookupCount--;
i++;
if (!done)
goto not_applied;
else
{
if (c->table_index == 1)
c->buffer->idx = old_pos + 1;
/* Reinitialize iterator. */
hb_apply_context_t::skipping_forward_iterator_t tmp (c, c->buffer->idx - 1, count - i);
tmp.set_syllable (syllable);
skippy_iter = tmp;
}
} }
else
{
not_applied:
/* No lookup applied for this index */
c->buffer->next_glyph ();
i++;
}
while (i < count)
{
if (!skippy_iter.next ()) return TRACE_RETURN (true);
while (c->buffer->idx < skippy_iter.idx)
c->buffer->next_glyph ();
if (lookupCount && i == lookupRecord->sequenceIndex) for (unsigned int i = 0; i < lookupCount; i++)
{
unsigned int idx = lookupRecord[i].sequenceIndex;
if (idx >= count)
continue;
buffer->move_to (match_positions[idx]);
unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
if (!c->recurse (lookupRecord[i].lookupListIndex))
continue;
unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
int delta = new_len - orig_len;
if (!delta)
continue;
/* Recursed lookup changed buffer len. Adjust. */
/* end can't go back past the current match position. */
end = MAX ((int) match_positions[idx] + 1, int (end) + delta);
unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
if (delta > 0)
{ {
unsigned int old_pos = c->buffer->idx; if (unlikely (delta + count > MAX_CONTEXT_LENGTH))
break;
/* Apply a lookup */
bool done = c->recurse (lookupRecord->lookupListIndex);
lookupRecord++;
lookupCount--;
i++;
if (!done)
goto not_applied2;
else
{
if (c->table_index == 1)
c->buffer->idx = old_pos + 1;
/* Reinitialize iterator. */
hb_apply_context_t::skipping_forward_iterator_t tmp (c, c->buffer->idx - 1, count - i);
tmp.set_syllable (syllable);
skippy_iter = tmp;
}
} }
else else
{ {
not_applied2: /* NOTE: delta is negative. */
/* No lookup applied for this index */ delta = MAX (delta, (int) next - (int) count);
c->buffer->next_glyph (); next -= delta;
i++;
} }
/* Shift! */
memmove (match_positions + next + delta, match_positions + next,
(count - next) * sizeof (match_positions[0]));
next += delta;
count += delta;
/* Fill in new entries. */
for (unsigned int j = idx + 1; j < next; j++)
match_positions[j] = match_positions[j - 1] + 1;
/* And fixup the rest. */
for (; next < count; next++)
match_positions[next] += delta;
} }
buffer->move_to (end);
return TRACE_RETURN (true); return TRACE_RETURN (true);
} }
@ -1146,28 +1099,20 @@ static inline bool context_apply_lookup (hb_apply_context_t *c,
const LookupRecord lookupRecord[], const LookupRecord lookupRecord[],
ContextApplyLookupContext &lookup_context) ContextApplyLookupContext &lookup_context)
{ {
unsigned int match_length = 0;
unsigned int match_positions[MAX_CONTEXT_LENGTH];
return match_input (c, return match_input (c,
inputCount, input, inputCount, input,
lookup_context.funcs.match, lookup_context.match_data) lookup_context.funcs.match, lookup_context.match_data,
&match_length, match_positions)
&& apply_lookup (c, && apply_lookup (c,
inputCount, input, inputCount, match_positions,
lookup_context.funcs.match, lookup_context.match_data, lookupCount, lookupRecord,
lookupCount, lookupRecord); match_length);
} }
struct Rule struct Rule
{ {
inline bool is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
unsigned int count = lookupCount;
for (unsigned int i = 0; i < count; i++)
if (!c->recurse (lookupRecord[i].lookupListIndex))
return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -1227,16 +1172,6 @@ struct Rule
struct RuleSet struct RuleSet
{ {
inline bool is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
unsigned int num_rules = rule.len;
for (unsigned int i = 0; i < num_rules; i++)
if (!(this+rule[i]).is_inplace (c))
return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -1293,16 +1228,6 @@ struct RuleSet
struct ContextFormat1 struct ContextFormat1
{ {
inline bool is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
unsigned int count = ruleSet.len;
for (unsigned int i = 0; i < count; i++)
if (!(this+ruleSet[i]).is_inplace (c))
return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
inline void closure (hb_closure_context_t *c) const inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -1389,16 +1314,6 @@ struct ContextFormat1
struct ContextFormat2 struct ContextFormat2
{ {
inline bool is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
unsigned int count = ruleSet.len;
for (unsigned int i = 0; i < count; i++)
if (!(this+ruleSet[i]).is_inplace (c))
return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
inline void closure (hb_closure_context_t *c) const inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -1494,17 +1409,6 @@ struct ContextFormat2
struct ContextFormat3 struct ContextFormat3
{ {
inline bool is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
unsigned int count = lookupCount;
for (unsigned int i = 0; i < count; i++)
if (!c->recurse (lookupRecord[i].lookupListIndex))
return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
inline void closure (hb_closure_context_t *c) const inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -1726,39 +1630,27 @@ static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
const LookupRecord lookupRecord[], const LookupRecord lookupRecord[],
ChainContextApplyLookupContext &lookup_context) ChainContextApplyLookupContext &lookup_context)
{ {
unsigned int lookahead_offset = 0; unsigned int match_length = 0;
unsigned int match_positions[MAX_CONTEXT_LENGTH];
return match_input (c, return match_input (c,
inputCount, input, inputCount, input,
lookup_context.funcs.match, lookup_context.match_data[1], lookup_context.funcs.match, lookup_context.match_data[1],
&lookahead_offset) &match_length, match_positions)
&& match_backtrack (c, && match_backtrack (c,
backtrackCount, backtrack, backtrackCount, backtrack,
lookup_context.funcs.match, lookup_context.match_data[0]) lookup_context.funcs.match, lookup_context.match_data[0])
&& match_lookahead (c, && match_lookahead (c,
lookaheadCount, lookahead, lookaheadCount, lookahead,
lookup_context.funcs.match, lookup_context.match_data[2], lookup_context.funcs.match, lookup_context.match_data[2],
lookahead_offset) match_length)
&& apply_lookup (c, && apply_lookup (c,
inputCount, input, inputCount, match_positions,
lookup_context.funcs.match, lookup_context.match_data[1], lookupCount, lookupRecord,
lookupCount, lookupRecord); match_length);
} }
struct ChainRule struct ChainRule
{ {
inline bool is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
unsigned int count = lookup.len;
for (unsigned int i = 0; i < count; i++)
if (!c->recurse (lookup.array[i].lookupListIndex))
return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -1844,16 +1736,6 @@ struct ChainRule
struct ChainRuleSet struct ChainRuleSet
{ {
inline bool is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
unsigned int num_rules = rule.len;
for (unsigned int i = 0; i < num_rules; i++)
if (!(this+rule[i]).is_inplace (c))
return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -1907,16 +1789,6 @@ struct ChainRuleSet
struct ChainContextFormat1 struct ChainContextFormat1
{ {
inline bool is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
unsigned int count = ruleSet.len;
for (unsigned int i = 0; i < count; i++)
if (!(this+ruleSet[i]).is_inplace (c))
return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
inline void closure (hb_closure_context_t *c) const inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -2000,16 +1872,6 @@ struct ChainContextFormat1
struct ChainContextFormat2 struct ChainContextFormat2
{ {
inline bool is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
unsigned int count = ruleSet.len;
for (unsigned int i = 0; i < count; i++)
if (!(this+ruleSet[i]).is_inplace (c))
return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
inline void closure (hb_closure_context_t *c) const inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);
@ -2134,20 +1996,6 @@ struct ChainContextFormat2
struct ChainContextFormat3 struct ChainContextFormat3
{ {
inline bool is_inplace (hb_is_inplace_context_t *c) const
{
TRACE_IS_INPLACE (this);
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
unsigned int count = lookup.len;
for (unsigned int i = 0; i < count; i++)
if (!c->recurse (lookup.array[i].lookupListIndex))
return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
inline void closure (hb_closure_context_t *c) const inline void closure (hb_closure_context_t *c) const
{ {
TRACE_CLOSURE (this); TRACE_CLOSURE (this);

View File

@ -0,0 +1,229 @@
/*
* Copyright © 2013 Google, Inc.
*
* 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
*/
#ifndef HB_OT_LAYOUT_JSTF_TABLE_HH
#define HB_OT_LAYOUT_JSTF_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-ot-layout-gpos-table.hh"
namespace OT {
/*
* JstfModList -- Justification Modification List Tables
*/
typedef IndexArray JstfModList;
/*
* JstfMax -- Justification Maximum Table
*/
typedef OffsetListOf<PosLookup> JstfMax;
/*
* JstfPriority -- Justification Priority Table
*/
struct JstfPriority
{
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
shrinkageEnableGSUB.sanitize (c, this) &&
shrinkageDisableGSUB.sanitize (c, this) &&
shrinkageEnableGPOS.sanitize (c, this) &&
shrinkageDisableGPOS.sanitize (c, this) &&
shrinkageJstfMax.sanitize (c, this) &&
extensionEnableGSUB.sanitize (c, this) &&
extensionDisableGSUB.sanitize (c, this) &&
extensionEnableGPOS.sanitize (c, this) &&
extensionDisableGPOS.sanitize (c, this) &&
extensionJstfMax.sanitize (c, this));
}
protected:
OffsetTo<JstfModList>
shrinkageEnableGSUB; /* Offset to Shrinkage Enable GSUB
* JstfModList table--from beginning of
* JstfPriority table--may be NULL */
OffsetTo<JstfModList>
shrinkageDisableGSUB; /* Offset to Shrinkage Disable GSUB
* JstfModList table--from beginning of
* JstfPriority table--may be NULL */
OffsetTo<JstfModList>
shrinkageEnableGPOS; /* Offset to Shrinkage Enable GPOS
* JstfModList table--from beginning of
* JstfPriority table--may be NULL */
OffsetTo<JstfModList>
shrinkageDisableGPOS; /* Offset to Shrinkage Disable GPOS
* JstfModList table--from beginning of
* JstfPriority table--may be NULL */
OffsetTo<JstfMax>
shrinkageJstfMax; /* Offset to Shrinkage JstfMax table--
* from beginning of JstfPriority table
* --may be NULL */
OffsetTo<JstfModList>
extensionEnableGSUB; /* Offset to Extension Enable GSUB
* JstfModList table--from beginning of
* JstfPriority table--may be NULL */
OffsetTo<JstfModList>
extensionDisableGSUB; /* Offset to Extension Disable GSUB
* JstfModList table--from beginning of
* JstfPriority table--may be NULL */
OffsetTo<JstfModList>
extensionEnableGPOS; /* Offset to Extension Enable GPOS
* JstfModList table--from beginning of
* JstfPriority table--may be NULL */
OffsetTo<JstfModList>
extensionDisableGPOS; /* Offset to Extension Disable GPOS
* JstfModList table--from beginning of
* JstfPriority table--may be NULL */
OffsetTo<JstfMax>
extensionJstfMax; /* Offset to Extension JstfMax table--
* from beginning of JstfPriority table
* --may be NULL */
public:
DEFINE_SIZE_STATIC (20);
};
/*
* JstfLangSys -- Justification Language System Table
*/
struct JstfLangSys : OffsetListOf<JstfPriority>
{
inline bool sanitize (hb_sanitize_context_t *c,
const Record<JstfLangSys>::sanitize_closure_t * = NULL) {
TRACE_SANITIZE (this);
return TRACE_RETURN (OffsetListOf<JstfPriority>::sanitize (c));
}
};
/*
* ExtenderGlyphs -- Extender Glyph Table
*/
typedef SortedArrayOf<GlyphID> ExtenderGlyphs;
/*
* JstfScript -- The Justification Table
*/
struct JstfScript
{
inline unsigned int get_lang_sys_count (void) const
{ return langSys.len; }
inline const Tag& get_lang_sys_tag (unsigned int i) const
{ return langSys.get_tag (i); }
inline unsigned int get_lang_sys_tags (unsigned int start_offset,
unsigned int *lang_sys_count /* IN/OUT */,
hb_tag_t *lang_sys_tags /* OUT */) const
{ return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
inline const JstfLangSys& get_lang_sys (unsigned int i) const
{
if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
return this+langSys[i].offset;
}
inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
{ return langSys.find_index (tag, index); }
inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
inline const JstfLangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
inline bool sanitize (hb_sanitize_context_t *c,
const Record<JstfScript>::sanitize_closure_t * = NULL) {
TRACE_SANITIZE (this);
return TRACE_RETURN (extenderGlyphs.sanitize (c, this) &&
defaultLangSys.sanitize (c, this) &&
langSys.sanitize (c, this));
}
protected:
OffsetTo<ExtenderGlyphs>
extenderGlyphs; /* Offset to ExtenderGlyph table--from beginning
* of JstfScript table-may be NULL */
OffsetTo<JstfLangSys>
defaultLangSys; /* Offset to DefaultJstfLangSys table--from
* beginning of JstfScript table--may be Null */
RecordArrayOf<JstfLangSys>
langSys; /* Array of JstfLangSysRecords--listed
* alphabetically by LangSysTag */
public:
DEFINE_SIZE_ARRAY (6, langSys);
};
/*
* JSTF -- The Justification Table
*/
struct JSTF
{
static const hb_tag_t tableTag = HB_OT_TAG_JSTF;
inline unsigned int get_script_count (void) const
{ return scriptList.len; }
inline const Tag& get_script_tag (unsigned int i) const
{ return scriptList.get_tag (i); }
inline unsigned int get_script_tags (unsigned int start_offset,
unsigned int *script_count /* IN/OUT */,
hb_tag_t *script_tags /* OUT */) const
{ return scriptList.get_tags (start_offset, script_count, script_tags); }
inline const JstfScript& get_script (unsigned int i) const
{ return this+scriptList[i].offset; }
inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
{ return scriptList.find_index (tag, index); }
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
scriptList.sanitize (c, this));
}
protected:
FixedVersion version; /* Version of the JSTF table--initially set
* to 0x00010000 */
RecordArrayOf<JstfScript>
scriptList; /* Array of JstfScripts--listed
* alphabetically by ScriptTag */
public:
DEFINE_SIZE_ARRAY (6, scriptList);
};
} /* namespace OT */
#endif /* HB_OT_LAYOUT_JSTF_TABLE_HH */

View File

@ -1,6 +1,6 @@
/* /*
* Copyright © 2007,2008,2009 Red Hat, Inc. * Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2012 Google, Inc. * Copyright © 2012,2013 Google, Inc.
* *
* This is part of HarfBuzz, a text shaping library. * This is part of HarfBuzz, a text shaping library.
* *
@ -31,170 +31,35 @@
#include "hb-private.hh" #include "hb-private.hh"
#include "hb-ot-layout.h"
#include "hb-font-private.hh" #include "hb-font-private.hh"
#include "hb-buffer-private.hh" #include "hb-buffer-private.hh"
#include "hb-set-private.hh" #include "hb-set-private.hh"
/* buffer var allocations, used during the GSUB/GPOS processing */
#define glyph_props() var1.u16[0] /* GDEF glyph properties */
#define syllable() var1.u8[2] /* GSUB/GPOS shaping boundaries */
#define lig_props() var1.u8[3] /* GSUB/GPOS ligature tracking */
/* buffer var allocations, used during the entire shaping process */
#define unicode_props0() var2.u8[0]
#define unicode_props1() var2.u8[1]
inline void
_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
{
info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
(unicode->is_default_ignorable (info->codepoint) ? 0x80 : 0) |
(info->codepoint == 0x200C ? 0x40 : 0) |
(info->codepoint == 0x200D ? 0x20 : 0);
info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
}
inline void
_hb_glyph_info_set_general_category (hb_glyph_info_t *info, hb_unicode_general_category_t gen_cat)
{
info->unicode_props0() = (unsigned int) gen_cat | ((info->unicode_props0()) & ~0x1F);
}
inline hb_unicode_general_category_t
_hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
{
return (hb_unicode_general_category_t) (info->unicode_props0() & 0x1F);
}
inline void
_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info, unsigned int modified_class)
{
info->unicode_props1() = modified_class;
}
inline unsigned int
_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
{
return info->unicode_props1();
}
inline hb_bool_t
_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
{
return !!(info->unicode_props0() & 0x80);
}
inline hb_bool_t
_hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
{
return !!(info->unicode_props0() & 0x40);
}
inline hb_bool_t
_hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
{
return !!(info->unicode_props0() & 0x20);
}
#define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
/* /*
* GDEF * GDEF
*/ */
typedef enum { typedef enum
HB_OT_LAYOUT_GLYPH_PROPS_UNCLASSIFIED = 1 << HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED, {
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH = 1 << HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH, /* The following three match LookupFlags::Ignore* numbers. */
HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE = 1 << HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE, HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH = 0x02u,
HB_OT_LAYOUT_GLYPH_PROPS_MARK = 1 << HB_OT_LAYOUT_GLYPH_CLASS_MARK, HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE = 0x04u,
HB_OT_LAYOUT_GLYPH_PROPS_COMPONENT = 1 << HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT HB_OT_LAYOUT_GLYPH_PROPS_MARK = 0x08u,
} hb_ot_layout_glyph_class_mask_t;
/* The following are used internally; not derived from GDEF. */
HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED = 0x10u,
HB_OT_LAYOUT_GLYPH_PROPS_LIGATED = 0x20u,
HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
HB_OT_LAYOUT_GLYPH_PROPS_LIGATED
} hb_ot_layout_glyph_class_mask_t;
/* /*
* GSUB/GPOS * GSUB/GPOS
*/ */
/* lig_id / lig_comp
*
* When a ligature is formed:
*
* - The ligature glyph and any marks in between all the same newly allocated
* lig_id,
* - The ligature glyph will get lig_num_comps set to the number of components
* - The marks get lig_comp > 0, reflecting which component of the ligature
* they were applied to.
* - This is used in GPOS to attach marks to the right component of a ligature
* in MarkLigPos.
*
* When a multiple-substitution is done:
*
* - All resulting glyphs will have lig_id = 0,
* - The resulting glyphs will have lig_comp = 0, 1, 2, ... respectively.
* - This is used in GPOS to attach marks to the first component of a
* multiple substitution in MarkBasePos.
*
* The numbers are also used in GPOS to do mark-to-mark positioning only
* to marks that belong to the same component of a ligature in MarkMarPos.
*/
#define IS_LIG_BASE 0x10
static inline void
set_lig_props_for_ligature (hb_glyph_info_t &info, unsigned int lig_id, unsigned int lig_num_comps)
{
info.lig_props() = (lig_id << 5) | IS_LIG_BASE | (lig_num_comps & 0x0F);
}
static inline void
set_lig_props_for_mark (hb_glyph_info_t &info, unsigned int lig_id, unsigned int lig_comp)
{
info.lig_props() = (lig_id << 5) | (lig_comp & 0x0F);
}
static inline void
set_lig_props_for_component (hb_glyph_info_t &info, unsigned int comp)
{
set_lig_props_for_mark (info, 0, comp);
}
static inline unsigned int
get_lig_id (const hb_glyph_info_t &info)
{
return info.lig_props() >> 5;
}
static inline bool
is_a_ligature (const hb_glyph_info_t &info)
{
return !!(info.lig_props() & IS_LIG_BASE);
}
static inline unsigned int
get_lig_comp (const hb_glyph_info_t &info)
{
if (is_a_ligature (info))
return 0;
else
return info.lig_props() & 0x0F;
}
static inline unsigned int
get_lig_num_comps (const hb_glyph_info_t &info)
{
if ((info.glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE) && is_a_ligature (info))
return info.lig_props() & 0x0F;
else
return 1;
}
static inline uint8_t allocate_lig_id (hb_buffer_t *buffer) {
uint8_t lig_id = buffer->next_serial () & 0x07;
if (unlikely (!lig_id))
lig_id = allocate_lig_id (buffer); /* in case of overflow */
return lig_id;
}
HB_INTERNAL hb_bool_t HB_INTERNAL hb_bool_t
hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face, hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face,
unsigned int lookup_index, unsigned int lookup_index,
@ -292,5 +157,267 @@ HB_INTERNAL void
_hb_ot_layout_destroy (hb_ot_layout_t *layout); _hb_ot_layout_destroy (hb_ot_layout_t *layout);
#define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
/*
* Buffer var routines.
*/
/* buffer var allocations, used during the entire shaping process */
#define unicode_props0() var2.u8[0]
#define unicode_props1() var2.u8[1]
/* buffer var allocations, used during the GSUB/GPOS processing */
#define glyph_props() var1.u16[0] /* GDEF glyph properties */
#define lig_props() var1.u8[2] /* GSUB/GPOS ligature tracking */
#define syllable() var1.u8[3] /* GSUB/GPOS shaping boundaries */
/* unicode_props */
enum {
MASK0_ZWJ = 0x20u,
MASK0_ZWNJ = 0x40u,
MASK0_IGNORABLE = 0x80u,
MASK0_GEN_CAT = 0x1Fu
};
inline void
_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
{
/* XXX This shouldn't be inlined, or at least not while is_default_ignorable() is inline. */
info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
(unicode->is_default_ignorable (info->codepoint) ? MASK0_IGNORABLE : 0) |
(info->codepoint == 0x200C ? MASK0_ZWNJ : 0) |
(info->codepoint == 0x200D ? MASK0_ZWJ : 0);
info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
}
inline void
_hb_glyph_info_set_general_category (hb_glyph_info_t *info,
hb_unicode_general_category_t gen_cat)
{
info->unicode_props0() = (unsigned int) gen_cat | ((info->unicode_props0()) & ~MASK0_GEN_CAT);
}
inline hb_unicode_general_category_t
_hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
{
return (hb_unicode_general_category_t) (info->unicode_props0() & MASK0_GEN_CAT);
}
inline void
_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info,
unsigned int modified_class)
{
info->unicode_props1() = modified_class;
}
inline unsigned int
_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
{
return info->unicode_props1();
}
inline hb_bool_t
_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
{
return !!(info->unicode_props0() & MASK0_IGNORABLE);
}
inline hb_bool_t
_hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
{
return !!(info->unicode_props0() & MASK0_ZWNJ);
}
inline hb_bool_t
_hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
{
return !!(info->unicode_props0() & MASK0_ZWJ);
}
inline void
_hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
{
info->unicode_props0() ^= MASK0_ZWNJ | MASK0_ZWJ;
}
/* lig_props: aka lig_id / lig_comp
*
* When a ligature is formed:
*
* - The ligature glyph and any marks in between all the same newly allocated
* lig_id,
* - The ligature glyph will get lig_num_comps set to the number of components
* - The marks get lig_comp > 0, reflecting which component of the ligature
* they were applied to.
* - This is used in GPOS to attach marks to the right component of a ligature
* in MarkLigPos,
* - Note that when marks are ligated together, much of the above is skipped
* and the current lig_id reused.
*
* When a multiple-substitution is done:
*
* - All resulting glyphs will have lig_id = 0,
* - The resulting glyphs will have lig_comp = 0, 1, 2, ... respectively.
* - This is used in GPOS to attach marks to the first component of a
* multiple substitution in MarkBasePos.
*
* The numbers are also used in GPOS to do mark-to-mark positioning only
* to marks that belong to the same component of the same ligature.
*/
static inline void
_hb_glyph_info_clear_lig_props (hb_glyph_info_t *info)
{
info->lig_props() = 0;
}
#define IS_LIG_BASE 0x10
static inline void
_hb_glyph_info_set_lig_props_for_ligature (hb_glyph_info_t *info,
unsigned int lig_id,
unsigned int lig_num_comps)
{
info->lig_props() = (lig_id << 5) | IS_LIG_BASE | (lig_num_comps & 0x0F);
}
static inline void
_hb_glyph_info_set_lig_props_for_mark (hb_glyph_info_t *info,
unsigned int lig_id,
unsigned int lig_comp)
{
info->lig_props() = (lig_id << 5) | (lig_comp & 0x0F);
}
static inline void
_hb_glyph_info_set_lig_props_for_component (hb_glyph_info_t *info, unsigned int comp)
{
_hb_glyph_info_set_lig_props_for_mark (info, 0, comp);
}
static inline unsigned int
_hb_glyph_info_get_lig_id (const hb_glyph_info_t *info)
{
return info->lig_props() >> 5;
}
static inline bool
_hb_glyph_info_ligated_internal (const hb_glyph_info_t *info)
{
return !!(info->lig_props() & IS_LIG_BASE);
}
static inline unsigned int
_hb_glyph_info_get_lig_comp (const hb_glyph_info_t *info)
{
if (_hb_glyph_info_ligated_internal (info))
return 0;
else
return info->lig_props() & 0x0F;
}
static inline unsigned int
_hb_glyph_info_get_lig_num_comps (const hb_glyph_info_t *info)
{
if ((info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE) &&
_hb_glyph_info_ligated_internal (info))
return info->lig_props() & 0x0F;
else
return 1;
}
static inline uint8_t
_hb_allocate_lig_id (hb_buffer_t *buffer) {
uint8_t lig_id = buffer->next_serial () & 0x07;
if (unlikely (!lig_id))
lig_id = _hb_allocate_lig_id (buffer); /* in case of overflow */
return lig_id;
}
/* glyph_props: */
inline void
_hb_glyph_info_set_glyph_props (hb_glyph_info_t *info, unsigned int props)
{
info->glyph_props() = props;
}
inline unsigned int
_hb_glyph_info_get_glyph_props (const hb_glyph_info_t *info)
{
return info->glyph_props();
}
inline bool
_hb_glyph_info_is_base_glyph (const hb_glyph_info_t *info)
{
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
}
inline bool
_hb_glyph_info_is_ligature (const hb_glyph_info_t *info)
{
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE);
}
inline bool
_hb_glyph_info_is_mark (const hb_glyph_info_t *info)
{
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
}
static inline bool
_hb_glyph_info_substituted (const hb_glyph_info_t *info)
{
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
}
static inline bool
_hb_glyph_info_ligated (const hb_glyph_info_t *info)
{
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED);
}
/* Allocation / deallocation. */
inline void
_hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
{
HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props0);
HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props1);
}
inline void
_hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
{
HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props0);
HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props1);
}
inline void
_hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer)
{
HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
}
inline void
_hb_buffer_deallocate_gsubgpos_vars (hb_buffer_t *buffer)
{
HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
}
/* Make sure no one directly touches our props... */
#undef unicode_props0
#undef unicode_props1
#undef lig_props
#undef glyph_props
#endif /* HB_OT_LAYOUT_PRIVATE_HH */ #endif /* HB_OT_LAYOUT_PRIVATE_HH */

View File

@ -33,6 +33,7 @@
#include "hb-ot-layout-gdef-table.hh" #include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh" #include "hb-ot-layout-gpos-table.hh"
#include "hb-ot-layout-jstf-table.hh"
#include "hb-ot-map-private.hh" #include "hb-ot-map-private.hh"
@ -413,6 +414,24 @@ hb_ot_layout_feature_get_lookups (hb_face_t *face,
return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes); return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
} }
unsigned int
hb_ot_layout_table_get_lookup_count (hb_face_t *face,
hb_tag_t table_tag)
{
switch (table_tag)
{
case HB_OT_TAG_GSUB:
{
return hb_ot_layout_from_face (face)->gsub_lookup_count;
}
case HB_OT_TAG_GPOS:
{
return hb_ot_layout_from_face (face)->gpos_lookup_count;
}
}
return 0;
}
static void static void
_hb_ot_layout_collect_lookups_lookups (hb_face_t *face, _hb_ot_layout_collect_lookups_lookups (hb_face_t *face,
hb_tag_t table_tag, hb_tag_t table_tag,
@ -764,6 +783,7 @@ hb_ot_layout_get_size_params (hb_face_t *face,
struct GSUBProxy struct GSUBProxy
{ {
static const unsigned int table_index = 0; static const unsigned int table_index = 0;
static const bool inplace = false;
typedef OT::SubstLookup Lookup; typedef OT::SubstLookup Lookup;
GSUBProxy (hb_face_t *face) : GSUBProxy (hb_face_t *face) :
@ -777,6 +797,7 @@ struct GSUBProxy
struct GPOSProxy struct GPOSProxy
{ {
static const unsigned int table_index = 1; static const unsigned int table_index = 1;
static const bool inplace = true;
typedef OT::PosLookup Lookup; typedef OT::PosLookup Lookup;
GPOSProxy (hb_face_t *face) : GPOSProxy (hb_face_t *face) :
@ -804,10 +825,9 @@ apply_string (OT::hb_apply_context_t *c,
const hb_ot_layout_lookup_accelerator_t &accel) const hb_ot_layout_lookup_accelerator_t &accel)
{ {
bool ret = false; bool ret = false;
OT::hb_is_inplace_context_t inplace_c (c->face); hb_buffer_t *buffer = c->buffer;
bool inplace = lookup.is_inplace (&inplace_c);
if (unlikely (!c->buffer->len || !c->lookup_mask)) if (unlikely (!buffer->len || !c->lookup_mask))
return false; return false;
c->set_lookup (lookup); c->set_lookup (lookup);
@ -816,43 +836,43 @@ apply_string (OT::hb_apply_context_t *c,
{ {
/* in/out forward substitution/positioning */ /* in/out forward substitution/positioning */
if (Proxy::table_index == 0) if (Proxy::table_index == 0)
c->buffer->clear_output (); buffer->clear_output ();
c->buffer->idx = 0; buffer->idx = 0;
while (c->buffer->idx < c->buffer->len) while (buffer->idx < buffer->len)
{ {
if (accel.digest.may_have (c->buffer->cur().codepoint) && if (accel.digest.may_have (buffer->cur().codepoint) &&
(c->buffer->cur().mask & c->lookup_mask) && (buffer->cur().mask & c->lookup_mask) &&
apply_once (c, lookup)) apply_once (c, lookup))
ret = true; ret = true;
else else
c->buffer->next_glyph (); buffer->next_glyph ();
} }
if (ret) if (ret)
{ {
if (!inplace) if (!Proxy::inplace)
c->buffer->swap_buffers (); buffer->swap_buffers ();
else else
assert (!c->buffer->has_separate_output ()); assert (!buffer->has_separate_output ());
} }
} }
else else
{ {
/* in-place backward substitution/positioning */ /* in-place backward substitution/positioning */
if (Proxy::table_index == 0) if (Proxy::table_index == 0)
c->buffer->remove_output (); buffer->remove_output ();
c->buffer->idx = c->buffer->len - 1; buffer->idx = buffer->len - 1;
do do
{ {
if (accel.digest.may_have (c->buffer->cur().codepoint) && if (accel.digest.may_have (buffer->cur().codepoint) &&
(c->buffer->cur().mask & c->lookup_mask) && (buffer->cur().mask & c->lookup_mask) &&
apply_once (c, lookup)) apply_once (c, lookup))
ret = true; ret = true;
else /* The reverse lookup doesn't "advance" cursor (for good reason). */
c->buffer->idx--; buffer->idx--;
} }
while ((int) c->buffer->idx >= 0); while ((int) buffer->idx >= 0);
} }
return ret; return ret;

View File

@ -41,6 +41,7 @@ HB_BEGIN_DECLS
#define HB_OT_TAG_GDEF HB_TAG('G','D','E','F') #define HB_OT_TAG_GDEF HB_TAG('G','D','E','F')
#define HB_OT_TAG_GSUB HB_TAG('G','S','U','B') #define HB_OT_TAG_GSUB HB_TAG('G','S','U','B')
#define HB_OT_TAG_GPOS HB_TAG('G','P','O','S') #define HB_OT_TAG_GPOS HB_TAG('G','P','O','S')
#define HB_OT_TAG_JSTF HB_TAG('J','S','T','F')
/* /*
@ -179,6 +180,11 @@ hb_ot_layout_feature_get_lookups (hb_face_t *face,
unsigned int *lookup_count /* IN/OUT */, unsigned int *lookup_count /* IN/OUT */,
unsigned int *lookup_indexes /* OUT */); unsigned int *lookup_indexes /* OUT */);
unsigned int
hb_ot_layout_table_get_lookup_count (hb_face_t *face,
hb_tag_t table_tag);
void void
hb_ot_layout_collect_lookups (hb_face_t *face, hb_ot_layout_collect_lookups (hb_face_t *face,
hb_tag_t table_tag, hb_tag_t table_tag,

View File

@ -40,6 +40,9 @@ hb_ot_map_t::add_lookups (hb_face_t *face,
{ {
unsigned int lookup_indices[32]; unsigned int lookup_indices[32];
unsigned int offset, len; unsigned int offset, len;
unsigned int table_lookup_count;
table_lookup_count = hb_ot_layout_table_get_lookup_count (face, table_tags[table_index]);
offset = 0; offset = 0;
do { do {
@ -50,7 +53,10 @@ hb_ot_map_t::add_lookups (hb_face_t *face,
offset, &len, offset, &len,
lookup_indices); lookup_indices);
for (unsigned int i = 0; i < len; i++) { for (unsigned int i = 0; i < len; i++)
{
if (lookup_indices[i] >= table_lookup_count)
continue;
hb_ot_map_t::lookup_map_t *lookup = lookups[table_index].push (); hb_ot_map_t::lookup_map_t *lookup = lookups[table_index].push ();
if (unlikely (!lookup)) if (unlikely (!lookup))
return; return;
@ -175,7 +181,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
continue; /* Feature disabled, or not enough bits. */ continue; /* Feature disabled, or not enough bits. */
bool found = false; hb_bool_t found = false;
unsigned int feature_index[2]; unsigned int feature_index[2];
for (unsigned int table_index = 0; table_index < 2; table_index++) for (unsigned int table_index = 0; table_index < 2; table_index++)
found |= hb_ot_layout_language_find_feature (face, found |= hb_ot_layout_language_find_feature (face,

View File

@ -41,7 +41,7 @@ namespace OT {
struct maxp struct maxp
{ {
static const hb_tag_t Tag = HB_OT_TAG_maxp; static const hb_tag_t tableTag = HB_OT_TAG_maxp;
inline unsigned int get_num_glyphs (void) const { inline unsigned int get_num_glyphs (void) const {
return numGlyphs; return numGlyphs;

View File

@ -74,7 +74,7 @@ struct NameRecord
struct name struct name
{ {
static const hb_tag_t Tag = HB_OT_TAG_name; static const hb_tag_t tableTag = HB_OT_TAG_name;
inline unsigned int get_name (unsigned int platform_id, inline unsigned int get_name (unsigned int platform_id,
unsigned int encoding_id, unsigned int encoding_id,

View File

@ -156,6 +156,11 @@ static const struct arabic_state_table_entry {
}; };
static void
nuke_joiners (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
static void static void
arabic_fallback_shape (const hb_ot_shape_plan_t *plan, arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
hb_font_t *font, hb_font_t *font,
@ -176,6 +181,8 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
* TODO: Add test cases for these two. * TODO: Add test cases for these two.
*/ */
map->add_gsub_pause (nuke_joiners);
map->add_global_bool_feature (HB_TAG('c','c','m','p')); map->add_global_bool_feature (HB_TAG('c','c','m','p'));
map->add_global_bool_feature (HB_TAG('l','o','c','l')); map->add_global_bool_feature (HB_TAG('l','o','c','l'));
@ -273,7 +280,8 @@ arabic_joining (hb_buffer_t *buffer)
const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
if (entry->prev_action != NONE && prev != (unsigned int) -1) if (entry->prev_action != NONE && prev != (unsigned int) -1)
buffer->info[prev].arabic_shaping_action() = entry->prev_action; for (; prev < i; prev++)
buffer->info[prev].arabic_shaping_action() = entry->prev_action;
buffer->info[i].arabic_shaping_action() = entry->curr_action; buffer->info[i].arabic_shaping_action() = entry->curr_action;
@ -313,6 +321,17 @@ setup_masks_arabic (const hb_ot_shape_plan_t *plan,
} }
static void
nuke_joiners (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
if (_hb_glyph_info_is_zwj (&buffer->info[i]))
_hb_glyph_info_flip_joiners (&buffer->info[i]);
}
static void static void
arabic_fallback_shape (const hb_ot_shape_plan_t *plan, arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
hb_font_t *font, hb_font_t *font,

View File

@ -43,23 +43,25 @@
* Not sure how to avoid duplication. */ * Not sure how to avoid duplication. */
enum indic_category_t { enum indic_category_t {
OT_X = 0, OT_X = 0,
OT_C, OT_C = 1,
OT_V, OT_V = 2,
OT_N, OT_N = 3,
OT_H, OT_H = 4,
OT_ZWNJ, OT_ZWNJ = 5,
OT_ZWJ, OT_ZWJ = 6,
OT_M, OT_M = 7,
OT_SM, OT_SM = 8,
OT_VD, OT_VD = 9,
OT_A, OT_A = 10,
OT_NBSP, OT_NBSP = 11,
OT_DOTTEDCIRCLE, /* Not in the spec, but special in Uniscribe. /Very very/ special! */ OT_DOTTEDCIRCLE = 12,
OT_RS, /* Register Shifter, used in Khmer OT spec */ OT_RS = 13, /* Register Shifter, used in Khmer OT spec. */
OT_Coeng, OT_Coeng = 14, /* Khmer-style Virama. */
OT_Repha, OT_Repha = 15, /* Atomically-encoded logical or visual repha. */
OT_Ra, /* Not explicitly listed in the OT spec, but used in the grammar. */ OT_Ra = 16,
OT_CM OT_CM = 17, /* Consonant-Medial. */
OT_Avag = 18, /* Avagraha. */
OT_CM2 = 31 /* Consonant-Medial, second slot. */
}; };
/* Visual positions in a syllable from left to right. */ /* Visual positions in a syllable from left to right. */
@ -93,7 +95,7 @@ enum indic_position_t {
enum indic_syllabic_category_t { enum indic_syllabic_category_t {
INDIC_SYLLABIC_CATEGORY_OTHER = OT_X, INDIC_SYLLABIC_CATEGORY_OTHER = OT_X,
INDIC_SYLLABIC_CATEGORY_AVAGRAHA = OT_X, INDIC_SYLLABIC_CATEGORY_AVAGRAHA = OT_Avag,
INDIC_SYLLABIC_CATEGORY_BINDU = OT_SM, INDIC_SYLLABIC_CATEGORY_BINDU = OT_SM,
INDIC_SYLLABIC_CATEGORY_CONSONANT = OT_C, INDIC_SYLLABIC_CATEGORY_CONSONANT = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD = OT_C, INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD = OT_C,
@ -101,7 +103,7 @@ enum indic_syllabic_category_t {
INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C, INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_CM, INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_CM,
INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_NBSP, INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_NBSP,
INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_C, INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_CM,
INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA = OT_Repha, INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA = OT_Repha,
INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER = OT_X, INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER = OT_X,
INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N, INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N,

View File

@ -128,14 +128,6 @@ static const hb_codepoint_t ra_chars[] = {
0x179A, /* Khmer */ /* No Reph, Visual Repha */ 0x179A, /* Khmer */ /* No Reph, Visual Repha */
}; };
static inline indic_position_t
consonant_position (hb_codepoint_t u)
{
if ((u & ~0x007F) == 0x1780)
return POS_BELOW_C; /* In Khmer coeng model, post and below forms should not be reordered. */
return POS_BASE_C; /* Will recategorize later based on font lookups. */
}
static inline bool static inline bool
is_ra (hb_codepoint_t u) is_ra (hb_codepoint_t u)
{ {
@ -149,7 +141,7 @@ static inline bool
is_one_of (const hb_glyph_info_t &info, unsigned int flags) is_one_of (const hb_glyph_info_t &info, unsigned int flags)
{ {
/* If it ligated, all bets are off. */ /* If it ligated, all bets are off. */
if (is_a_ligature (info)) return false; if (_hb_glyph_info_ligated (&info)) return false;
return !!(FLAG (info.indic_category()) & flags); return !!(FLAG (info.indic_category()) & flags);
} }
@ -160,12 +152,14 @@ is_joiner (const hb_glyph_info_t &info)
return is_one_of (info, JOINER_FLAGS); return is_one_of (info, JOINER_FLAGS);
} }
#define MEDIAL_FLAGS (FLAG (OT_CM) | FLAG (OT_CM2))
/* Note: /* Note:
* *
* We treat Vowels and placeholders as if they were consonants. This is safe because Vowels * We treat Vowels and placeholders as if they were consonants. This is safe because Vowels
* cannot happen in a consonant syllable. The plus side however is, we can call the * cannot happen in a consonant syllable. The plus side however is, we can call the
* consonant syllable logic from the vowel syllable function and get it all right! */ * consonant syllable logic from the vowel syllable function and get it all right! */
#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CM) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE)) #define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_Ra) | MEDIAL_FLAGS | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE))
static inline bool static inline bool
is_consonant (const hb_glyph_info_t &info) is_consonant (const hb_glyph_info_t &info)
{ {
@ -194,15 +188,15 @@ set_indic_properties (hb_glyph_info_t &info)
/* The spec says U+0952 is OT_A. However, testing shows that Uniscribe /* The spec says U+0952 is OT_A. However, testing shows that Uniscribe
* treats U+0951..U+0952 all as OT_VD. * treats U+0951..U+0954 all behave similarly.
* TESTS: * TESTS:
* U+092E,U+0947,U+0952 * U+092E,U+0947,U+0952
* U+092E,U+0952,U+0947 * U+092E,U+0952,U+0947
* U+092E,U+0947,U+0951 * U+092E,U+0947,U+0951
* U+092E,U+0951,U+0947 * U+092E,U+0951,U+0947
* */ */
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x0951, 0x0954))) if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x0951, 0x0954)))
cat = OT_VD; cat = OT_A;
if (unlikely (u == 0x17D1)) if (unlikely (u == 0x17D1))
cat = OT_X; cat = OT_X;
@ -220,7 +214,10 @@ set_indic_properties (hb_glyph_info_t &info)
else if (unlikely (u == 0x200C)) cat = OT_ZWNJ; else if (unlikely (u == 0x200C)) cat = OT_ZWNJ;
else if (unlikely (u == 0x200D)) cat = OT_ZWJ; else if (unlikely (u == 0x200D)) cat = OT_ZWJ;
else if (unlikely (u == 0x25CC)) cat = OT_DOTTEDCIRCLE; else if (unlikely (u == 0x25CC)) cat = OT_DOTTEDCIRCLE;
else if (unlikely (u == 0x0A71)) cat = OT_SM; /* GURMUKHI ADDAK. More like consonant medial. like 0A75. */ else if (unlikely (u == 0x0A71)) cat = OT_SM; /* GURMUKHI ADDAK. Move it to the end. */
else if (unlikely (u == 0xA982)) cat = OT_SM; /* Javanese repha. */
else if (unlikely (u == 0xA9BE)) cat = OT_CM2; /* Javanese medial ya. */
else if (unlikely (u == 0xA9BD)) { cat = OT_M; pos = POS_POST_C; } /* Javanese vocalic r. */
if (cat == OT_Repha) { if (cat == OT_Repha) {
/* There are two kinds of characters marked as Repha: /* There are two kinds of characters marked as Repha:
@ -241,7 +238,7 @@ set_indic_properties (hb_glyph_info_t &info)
if ((FLAG (cat) & CONSONANT_FLAGS)) if ((FLAG (cat) & CONSONANT_FLAGS))
{ {
pos = consonant_position (u); pos = POS_BASE_C;
if (is_ra (u)) if (is_ra (u))
cat = OT_Ra; cat = OT_Ra;
} }
@ -249,7 +246,7 @@ set_indic_properties (hb_glyph_info_t &info)
{ {
pos = matra_position (u, pos); pos = matra_position (u, pos);
} }
else if (cat == OT_SM || cat == OT_VD) else if ((FLAG (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Avag))))
{ {
pos = POS_SMVD; pos = POS_SMVD;
} }
@ -277,16 +274,16 @@ set_indic_properties (hb_glyph_info_t &info)
enum base_position_t { enum base_position_t {
BASE_POS_FIRST, BASE_POS_FIRST,
BASE_POS_LAST_SINHALA,
BASE_POS_LAST BASE_POS_LAST
}; };
enum reph_position_t { enum reph_position_t {
REPH_POS_DEFAULT = POS_BEFORE_POST,
REPH_POS_AFTER_MAIN = POS_AFTER_MAIN, REPH_POS_AFTER_MAIN = POS_AFTER_MAIN,
REPH_POS_BEFORE_SUB = POS_BEFORE_SUB, REPH_POS_BEFORE_SUB = POS_BEFORE_SUB,
REPH_POS_AFTER_SUB = POS_AFTER_SUB, REPH_POS_AFTER_SUB = POS_AFTER_SUB,
REPH_POS_BEFORE_POST = POS_BEFORE_POST, REPH_POS_BEFORE_POST = POS_BEFORE_POST,
REPH_POS_AFTER_POST = POS_AFTER_POST REPH_POS_AFTER_POST = POS_AFTER_POST,
REPH_POS_DONT_CARE = POS_RA_TO_BECOME_REPH
}; };
enum reph_mode_t { enum reph_mode_t {
REPH_MODE_IMPLICIT, /* Reph formed out of initial Ra,H sequence. */ REPH_MODE_IMPLICIT, /* Reph formed out of initial Ra,H sequence. */
@ -294,6 +291,15 @@ enum reph_mode_t {
REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */ REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */
REPH_MODE_LOG_REPHA /* Encoded Repha character, needs reordering. */ REPH_MODE_LOG_REPHA /* Encoded Repha character, needs reordering. */
}; };
enum blwf_mode_t {
BLWF_MODE_PRE_AND_POST, /* Below-forms feature applied to pre-base and post-base. */
BLWF_MODE_POST_ONLY /* Below-forms feature applied to post-base only. */
};
enum pref_len_t {
PREF_LEN_1 = 1,
PREF_LEN_2 = 2,
PREF_LEN_DONT_CARE = PREF_LEN_2
};
struct indic_config_t struct indic_config_t
{ {
hb_script_t script; hb_script_t script;
@ -302,24 +308,27 @@ struct indic_config_t
base_position_t base_pos; base_position_t base_pos;
reph_position_t reph_pos; reph_position_t reph_pos;
reph_mode_t reph_mode; reph_mode_t reph_mode;
blwf_mode_t blwf_mode;
pref_len_t pref_len;
}; };
static const indic_config_t indic_configs[] = static const indic_config_t indic_configs[] =
{ {
/* Default. Should be first. */ /* Default. Should be first. */
{HB_SCRIPT_INVALID, false, 0,BASE_POS_LAST, REPH_POS_DEFAULT, REPH_MODE_IMPLICIT}, {HB_SCRIPT_INVALID, false, 0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
{HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT}, {HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_BENGALI, true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT}, {HB_SCRIPT_BENGALI, true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_GURMUKHI, true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT}, {HB_SCRIPT_GURMUKHI, true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_GUJARATI, true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT}, {HB_SCRIPT_GUJARATI, true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_ORIYA, true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT}, {HB_SCRIPT_ORIYA, true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_TAMIL, true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT}, {HB_SCRIPT_TAMIL, true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
{HB_SCRIPT_TELUGU, true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT}, {HB_SCRIPT_TELUGU, true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2},
{HB_SCRIPT_KANNADA, true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT}, {HB_SCRIPT_KANNADA, true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2},
{HB_SCRIPT_MALAYALAM, true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA}, {HB_SCRIPT_MALAYALAM, true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
{HB_SCRIPT_SINHALA, false,0x0DCA,BASE_POS_FIRST,REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT}, {HB_SCRIPT_SINHALA, false,0x0DCA,BASE_POS_LAST_SINHALA,
{HB_SCRIPT_KHMER, false,0x17D2,BASE_POS_FIRST,REPH_POS_DEFAULT, REPH_MODE_VIS_REPHA}, REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_JAVANESE, false,0xA9C0,BASE_POS_LAST, REPH_POS_DEFAULT, REPH_MODE_IMPLICIT}, {HB_SCRIPT_KHMER, false,0x17D2,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
{HB_SCRIPT_JAVANESE, false,0xA9C0,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
}; };
@ -346,15 +355,17 @@ indic_features[] =
{HB_TAG('r','k','r','f'), F_GLOBAL}, {HB_TAG('r','k','r','f'), F_GLOBAL},
{HB_TAG('p','r','e','f'), F_NONE}, {HB_TAG('p','r','e','f'), F_NONE},
{HB_TAG('b','l','w','f'), F_NONE}, {HB_TAG('b','l','w','f'), F_NONE},
{HB_TAG('h','a','l','f'), F_NONE},
{HB_TAG('a','b','v','f'), F_NONE}, {HB_TAG('a','b','v','f'), F_NONE},
{HB_TAG('h','a','l','f'), F_NONE},
{HB_TAG('p','s','t','f'), F_NONE}, {HB_TAG('p','s','t','f'), F_NONE},
{HB_TAG('c','f','a','r'), F_NONE},
{HB_TAG('v','a','t','u'), F_GLOBAL}, {HB_TAG('v','a','t','u'), F_GLOBAL},
{HB_TAG('c','j','c','t'), F_GLOBAL}, {HB_TAG('c','j','c','t'), F_GLOBAL},
{HB_TAG('c','f','a','r'), F_NONE},
/* /*
* Other features. * Other features.
* These features are applied all at once, after final_reordering. * These features are applied all at once, after final_reordering.
* Default Bengali font in Windows for example has intermixed
* lookups for init,pres,abvs,blws features.
*/ */
{HB_TAG('i','n','i','t'), F_NONE}, {HB_TAG('i','n','i','t'), F_NONE},
{HB_TAG('p','r','e','s'), F_GLOBAL}, {HB_TAG('p','r','e','s'), F_GLOBAL},
@ -378,12 +389,12 @@ enum {
_RKRF, _RKRF,
PREF, PREF,
BLWF, BLWF,
HALF,
ABVF, ABVF,
HALF,
PSTF, PSTF,
CFAR,
_VATU, _VATU,
_CJCT, _CJCT,
CFAR,
INIT, INIT,
_PRES, _PRES,
@ -411,6 +422,10 @@ static void
final_reordering (const hb_ot_shape_plan_t *plan, final_reordering (const hb_ot_shape_plan_t *plan,
hb_font_t *font, hb_font_t *font,
hb_buffer_t *buffer); hb_buffer_t *buffer);
static void
clear_syllables (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
static void static void
collect_features_indic (hb_ot_shape_planner_t *plan) collect_features_indic (hb_ot_shape_planner_t *plan)
@ -436,14 +451,26 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
for (; i < INDIC_NUM_FEATURES; i++) { for (; i < INDIC_NUM_FEATURES; i++) {
map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ); map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ);
} }
map->add_global_bool_feature (HB_TAG('c','a','l','t'));
map->add_global_bool_feature (HB_TAG('c','l','i','g'));
map->add_gsub_pause (clear_syllables);
} }
static void static void
override_features_indic (hb_ot_shape_planner_t *plan) override_features_indic (hb_ot_shape_planner_t *plan)
{ {
/* Uniscribe does not apply 'kern'. */ /* Uniscribe does not apply 'kern' in Khmer. */
if (hb_options ().uniscribe_bug_compatible) if (hb_options ().uniscribe_bug_compatible)
plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL); {
switch ((hb_tag_t) plan->props.script)
{
case HB_SCRIPT_KHMER:
plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL);
break;
}
}
plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL); plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
} }
@ -451,8 +478,9 @@ override_features_indic (hb_ot_shape_planner_t *plan)
struct would_substitute_feature_t struct would_substitute_feature_t
{ {
inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag) inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_)
{ {
zero_context = zero_context_;
map->get_stage_lookups (0/*GSUB*/, map->get_stage_lookups (0/*GSUB*/,
map->get_feature_stage (0/*GSUB*/, feature_tag), map->get_feature_stage (0/*GSUB*/, feature_tag),
&lookups, &count); &lookups, &count);
@ -460,7 +488,6 @@ struct would_substitute_feature_t
inline bool would_substitute (const hb_codepoint_t *glyphs, inline bool would_substitute (const hb_codepoint_t *glyphs,
unsigned int glyphs_count, unsigned int glyphs_count,
bool zero_context,
hb_face_t *face) const hb_face_t *face) const
{ {
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
@ -472,6 +499,7 @@ struct would_substitute_feature_t
private: private:
const hb_ot_map_t::lookup_map_t *lookups; const hb_ot_map_t::lookup_map_t *lookups;
unsigned int count; unsigned int count;
bool zero_context;
}; };
struct indic_shape_plan_t struct indic_shape_plan_t
@ -527,10 +555,13 @@ data_create_indic (const hb_ot_shape_plan_t *plan)
indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FF) != '2'); indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FF) != '2');
indic_plan->virama_glyph = (hb_codepoint_t) -1; indic_plan->virama_glyph = (hb_codepoint_t) -1;
indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f')); /* Use zero-context would_substitute() matching for new-spec of the main
indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f')); * Indic scripts, but not for old-spec or scripts with one spec only. */
indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f')); bool zero_context = indic_plan->config->has_old_spec || !indic_plan->is_old_spec;
indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f')); indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'), zero_context);
indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context);
indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context);
indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'), zero_context);
for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++) for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++)
indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ? indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ?
@ -547,7 +578,8 @@ data_destroy_indic (void *data)
static indic_position_t static indic_position_t
consonant_position_from_face (const indic_shape_plan_t *indic_plan, consonant_position_from_face (const indic_shape_plan_t *indic_plan,
const hb_codepoint_t glyphs[2], const hb_codepoint_t consonant,
const hb_codepoint_t virama,
hb_face_t *face) hb_face_t *face)
{ {
/* For old-spec, the order of glyphs is Consonant,Virama, /* For old-spec, the order of glyphs is Consonant,Virama,
@ -560,16 +592,19 @@ consonant_position_from_face (const indic_shape_plan_t *indic_plan,
* 930,94D in 'blwf', not the expected 94D,930 (with new-spec * 930,94D in 'blwf', not the expected 94D,930 (with new-spec
* table). As such, we simply match both sequences. Seems * table). As such, we simply match both sequences. Seems
* to work. */ * to work. */
bool zero_context = indic_plan->is_old_spec ? false : true; hb_codepoint_t glyphs[3] = {virama, consonant, virama};
hb_codepoint_t glyphs_r[2] = {glyphs[1], glyphs[0]}; if (indic_plan->blwf.would_substitute (glyphs , 2, face) ||
if (indic_plan->pref.would_substitute (glyphs , 2, zero_context, face) || indic_plan->blwf.would_substitute (glyphs+1, 2, face))
indic_plan->pref.would_substitute (glyphs_r, 2, zero_context, face))
return POS_POST_C;
if (indic_plan->blwf.would_substitute (glyphs , 2, zero_context, face) ||
indic_plan->blwf.would_substitute (glyphs_r, 2, zero_context, face))
return POS_BELOW_C; return POS_BELOW_C;
if (indic_plan->pstf.would_substitute (glyphs , 2, zero_context, face) || if (indic_plan->pstf.would_substitute (glyphs , 2, face) ||
indic_plan->pstf.would_substitute (glyphs_r, 2, zero_context, face)) indic_plan->pstf.would_substitute (glyphs+1, 2, face))
return POS_POST_C;
unsigned int pref_len = indic_plan->config->pref_len;
if ((pref_len == PREF_LEN_2 &&
(indic_plan->pref.would_substitute (glyphs , 2, face) ||
indic_plan->pref.would_substitute (glyphs+1, 2, face)))
|| (pref_len == PREF_LEN_1 &&
indic_plan->pref.would_substitute (glyphs+1, 1, face)))
return POS_POST_C; return POS_POST_C;
return POS_BASE_C; return POS_BASE_C;
} }
@ -579,6 +614,7 @@ enum syllable_type_t {
consonant_syllable, consonant_syllable,
vowel_syllable, vowel_syllable,
standalone_cluster, standalone_cluster,
avagraha_cluster,
broken_cluster, broken_cluster,
non_indic_cluster, non_indic_cluster,
}; };
@ -628,15 +664,18 @@ update_consonant_positions (const hb_ot_shape_plan_t *plan,
{ {
const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
hb_codepoint_t glyphs[2]; if (indic_plan->config->base_pos != BASE_POS_LAST)
if (indic_plan->get_virama_glyph (font, &glyphs[0])) return;
hb_codepoint_t virama;
if (indic_plan->get_virama_glyph (font, &virama))
{ {
hb_face_t *face = font->face; hb_face_t *face = font->face;
unsigned int count = buffer->len; unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if (buffer->info[i].indic_position() == POS_BASE_C) { if (buffer->info[i].indic_position() == POS_BASE_C) {
glyphs[1] = buffer->info[i].codepoint; hb_codepoint_t consonant = buffer->info[i].codepoint;
buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, glyphs, face); buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, consonant, virama, face);
} }
} }
} }
@ -677,7 +716,8 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
* and has more than one consonant, Ra is excluded from candidates for * and has more than one consonant, Ra is excluded from candidates for
* base consonants. */ * base consonants. */
unsigned int limit = start; unsigned int limit = start;
if (indic_plan->mask_array[RPHF] && if (indic_plan->config->reph_pos != REPH_POS_DONT_CARE &&
indic_plan->mask_array[RPHF] &&
start + 3 <= end && start + 3 <= end &&
( (
(indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) || (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) ||
@ -686,7 +726,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
{ {
/* See if it matches the 'rphf' feature. */ /* See if it matches the 'rphf' feature. */
hb_codepoint_t glyphs[2] = {info[start].codepoint, info[start + 1].codepoint}; hb_codepoint_t glyphs[2] = {info[start].codepoint, info[start + 1].codepoint};
if (indic_plan->rphf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face)) if (indic_plan->rphf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face))
{ {
limit += 2; limit += 2;
while (limit < end && is_joiner (info[limit])) while (limit < end && is_joiner (info[limit]))
@ -758,9 +798,12 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
} }
break; break;
case BASE_POS_FIRST: case BASE_POS_LAST_SINHALA:
{ {
/* In scripts without half forms (eg. Khmer), the first consonant is always the base. */ /* Sinhala base positioning is slightly different from main Indic, in that:
* 1. It's ZWJ behavior is different,
* 2. We don't need to look into the font for consonant positions.
*/
if (!has_reph) if (!has_reph)
base = limit; base = limit;
@ -768,7 +811,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
/* Find the last base consonant that is not blocked by ZWJ. If there is /* Find the last base consonant that is not blocked by ZWJ. If there is
* a ZWJ right before a base consonant, that would request a subjoined form. */ * a ZWJ right before a base consonant, that would request a subjoined form. */
for (unsigned int i = limit; i < end; i++) for (unsigned int i = limit; i < end; i++)
if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) if (is_consonant (info[i]))
{ {
if (limit < i && info[i - 1].indic_category() == OT_ZWJ) if (limit < i && info[i - 1].indic_category() == OT_ZWJ)
break; break;
@ -778,7 +821,23 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
/* Mark all subsequent consonants as below. */ /* Mark all subsequent consonants as below. */
for (unsigned int i = base + 1; i < end; i++) for (unsigned int i = base + 1; i < end; i++)
if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) if (is_consonant (info[i]))
info[i].indic_position() = POS_BELOW_C;
}
break;
case BASE_POS_FIRST:
{
/* The first consonant is always the base. */
assert (indic_plan->config->reph_mode == REPH_MODE_VIS_REPHA);
assert (!has_reph);
base = start;
/* Mark all subsequent consonants as below. */
for (unsigned int i = base + 1; i < end; i++)
if (is_consonant (info[i]))
info[i].indic_position() = POS_BELOW_C; info[i].indic_position() = POS_BELOW_C;
} }
break; break;
@ -877,7 +936,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
indic_position_t last_pos = POS_START; indic_position_t last_pos = POS_START;
for (unsigned int i = start; i < end; i++) for (unsigned int i = start; i < end; i++)
{ {
if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | HALANT_OR_COENG_FLAGS))) if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | HALANT_OR_COENG_FLAGS)))
{ {
info[i].indic_position() = last_pos; info[i].indic_position() = last_pos;
if (unlikely (info[i].indic_category() == OT_H && if (unlikely (info[i].indic_category() == OT_H &&
@ -903,33 +962,68 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
} }
} }
} }
/* Re-attach ZWJ, ZWNJ, and halant to next char, for after-base consonants. */ /* For post-base consonants let them own anything before them
* since the last consonant or matra. */
{ {
unsigned int last_halant = end; unsigned int last = base;
for (unsigned int i = base + 1; i < end; i++) for (unsigned int i = base + 1; i < end; i++)
if (is_halant_or_coeng (info[i])) if (is_consonant (info[i]))
last_halant = i; {
else if (is_consonant (info[i])) { for (unsigned int j = last + 1; j < i; j++)
for (unsigned int j = last_halant; j < i; j++) if (info[j].indic_position() < POS_SMVD)
if (info[j].indic_position() != POS_SMVD)
info[j].indic_position() = info[i].indic_position(); info[j].indic_position() = info[i].indic_position();
} last = i;
} else if (info[i].indic_category() == OT_M)
last = i;
} }
{ {
/* Things are out-of-control for post base positions, they may shuffle /* Use syllable() for sort accounting temporarily. */
* around like crazy, so merge clusters. For pre-base stuff, we handle unsigned int syllable = info[start].syllable();
* cluster issues in final reordering. */ for (unsigned int i = start; i < end; i++)
buffer->merge_clusters (base, end); info[i].syllable() = i - start;
/* Sit tight, rock 'n roll! */ /* Sit tight, rock 'n roll! */
hb_bubble_sort (info + start, end - start, compare_indic_order); hb_bubble_sort (info + start, end - start, compare_indic_order);
/* Find base again */ /* Find base again */
base = end; base = end;
for (unsigned int i = start; i < end; i++) for (unsigned int i = start; i < end; i++)
if (info[i].indic_position() == POS_BASE_C) { if (info[i].indic_position() == POS_BASE_C)
base = i; {
base = i;
break; break;
} }
/* Things are out-of-control for post base positions, they may shuffle
* around like crazy. In old-spec mode, we move halants around, so in
* that case merge all clusters after base. Otherwise, check the sort
* order and merge as needed.
* For pre-base stuff, we handle cluster issues in final reordering. */
if (indic_plan->is_old_spec || end - base > 127)
buffer->merge_clusters (base, end);
else
{
/* Note! syllable() is a one-byte field. */
for (unsigned int i = base; i < end; i++)
if (info[i].syllable() != 255)
{
unsigned int max = i;
unsigned int j = start + info[i].syllable();
while (j != i)
{
max = MAX (max, j);
unsigned int next = start + info[j].syllable();
info[j].syllable() = 255; /* So we don't process j later again. */
j = next;
}
if (i != max)
buffer->merge_clusters (i, max + 1);
}
}
/* Put syllable back in. */
for (unsigned int i = start; i < end; i++)
info[i].syllable() = syllable;
} }
/* Setup masks now */ /* Setup masks now */
@ -943,6 +1037,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
/* Pre-base */ /* Pre-base */
mask = indic_plan->mask_array[HALF]; mask = indic_plan->mask_array[HALF];
if (!indic_plan->is_old_spec &&
indic_plan->config->blwf_mode == BLWF_MODE_PRE_AND_POST)
mask |= indic_plan->mask_array[BLWF];
for (unsigned int i = start; i < base; i++) for (unsigned int i = start; i < base; i++)
info[i].mask |= mask; info[i].mask |= mask;
/* Base */ /* Base */
@ -987,15 +1084,19 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
} }
} }
if (indic_plan->mask_array[PREF] && base + 2 < end) unsigned int pref_len = indic_plan->config->pref_len;
if (indic_plan->mask_array[PREF] && base + pref_len < end)
{ {
assert (1 <= pref_len && pref_len <= 2);
/* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */ /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */
for (unsigned int i = base + 1; i + 1 < end; i++) { for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) {
hb_codepoint_t glyphs[2] = {info[i].codepoint, info[i + 1].codepoint}; hb_codepoint_t glyphs[2];
if (indic_plan->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face)) for (unsigned int j = 0; j < pref_len; j++)
glyphs[j] = info[i + j].codepoint;
if (indic_plan->pref.would_substitute (glyphs, pref_len, face))
{ {
info[i++].mask |= indic_plan->mask_array[PREF]; for (unsigned int j = 0; j < pref_len; j++)
info[i++].mask |= indic_plan->mask_array[PREF]; info[i++].mask |= indic_plan->mask_array[PREF];
/* Mark the subsequent stuff with 'cfar'. Used in Khmer. /* Mark the subsequent stuff with 'cfar'. Used in Khmer.
* Read the feature spec. * Read the feature spec.
@ -1003,8 +1104,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
* U+1784,U+17D2,U+179A,U+17D2,U+1782 * U+1784,U+17D2,U+179A,U+17D2,U+1782
* U+1784,U+17D2,U+1782,U+17D2,U+179A * U+1784,U+17D2,U+1782,U+17D2,U+179A
*/ */
for (; i < end; i++) if (indic_plan->mask_array[CFAR])
info[i].mask |= indic_plan->mask_array[CFAR]; for (; i < end; i++)
info[i].mask |= indic_plan->mask_array[CFAR];
break; break;
} }
@ -1074,6 +1176,16 @@ initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
initial_reordering_standalone_cluster (plan, face, buffer, start, end); initial_reordering_standalone_cluster (plan, face, buffer, start, end);
} }
static void
initial_reordering_avagraha_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_face_t *face HB_UNUSED,
hb_buffer_t *buffer HB_UNUSED,
unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
{
/* Nothing to do right now. If we ever switch to using the output
* buffer in the reordering process, we'd need to next_glyph() here. */
}
static void static void
initial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, initial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_face_t *face HB_UNUSED, hb_face_t *face HB_UNUSED,
@ -1096,6 +1208,7 @@ initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return; case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return;
case vowel_syllable: initial_reordering_vowel_syllable (plan, face, buffer, start, end); return; case vowel_syllable: initial_reordering_vowel_syllable (plan, face, buffer, start, end); return;
case standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); return; case standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); return;
case avagraha_cluster: initial_reordering_avagraha_cluster (plan, face, buffer, start, end); return;
case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return; case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return;
case non_indic_cluster: initial_reordering_non_indic_cluster (plan, face, buffer, start, end); return; case non_indic_cluster: initial_reordering_non_indic_cluster (plan, face, buffer, start, end); return;
} }
@ -1265,9 +1378,9 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
info[new_pos] = tmp; info[new_pos] = tmp;
if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. */ if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. */
base--; base--;
buffer->merge_clusters (new_pos, MIN (end, base + 1));
new_pos--; new_pos--;
} }
buffer->merge_clusters (new_pos, MIN (end, base + 1));
} else { } else {
for (unsigned int i = start; i < base; i++) for (unsigned int i = start; i < base; i++)
if (info[i].indic_position () == POS_PRE_M) { if (info[i].indic_position () == POS_PRE_M) {
@ -1287,17 +1400,24 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
* before post-base consonant forms, and after post-base consonant forms. * before post-base consonant forms, and after post-base consonant forms.
*/ */
/* If there's anything after the Ra that has the REPH pos, it ought to be halant. /* Two cases:
* Which means that the font has failed to ligate the Reph. In which case, we *
* shouldn't move. */ * - If repha is encoded as a sequence of characters (Ra,H or Ra,H,ZWJ), then
* we should only move it if the sequence ligated to the repha form.
*
* - If repha is encoded separately and in the logical position, we should only
* move it if it did NOT ligate. If it ligated, it's probably the font trying
* to make it work without the reordering.
*/
if (start + 1 < end && if (start + 1 < end &&
info[start].indic_position() == POS_RA_TO_BECOME_REPH && info[start].indic_position() == POS_RA_TO_BECOME_REPH &&
info[start + 1].indic_position() != POS_RA_TO_BECOME_REPH) ((info[start].indic_category() == OT_Repha) ^
_hb_glyph_info_ligated (&info[start])))
{ {
unsigned int new_reph_pos; unsigned int new_reph_pos;
reph_position_t reph_pos = indic_plan->config->reph_pos; reph_position_t reph_pos = indic_plan->config->reph_pos;
/* XXX Figure out old behavior too */ assert (reph_pos != REPH_POS_DONT_CARE);
/* 1. If reph should be positioned after post-base consonant forms, /* 1. If reph should be positioned after post-base consonant forms,
* proceed to step 5. * proceed to step 5.
@ -1339,7 +1459,6 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
if (reph_pos == REPH_POS_AFTER_MAIN) if (reph_pos == REPH_POS_AFTER_MAIN)
{ {
new_reph_pos = base; new_reph_pos = base;
/* XXX Skip potential pre-base reordering Ra. */
while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN) while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN)
new_reph_pos++; new_reph_pos++;
if (new_reph_pos < end) if (new_reph_pos < end)
@ -1412,8 +1531,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
reph_move: reph_move:
{ {
/* Yay, one big cluster! Merge before moving. */ buffer->merge_clusters (start, new_reph_pos + 1);
buffer->merge_clusters (start, end);
/* Move */ /* Move */
hb_glyph_info_t reph = info[start]; hb_glyph_info_t reph = info[start];
@ -1433,6 +1551,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */ if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */
{ {
unsigned int pref_len = indic_plan->config->pref_len;
for (unsigned int i = base + 1; i < end; i++) for (unsigned int i = base + 1; i < end; i++)
if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
{ {
@ -1440,7 +1559,13 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
* of the <pref> feature. (Note that a font may shape a Ra consonant with * of the <pref> feature. (Note that a font may shape a Ra consonant with
* the feature generally but block it in certain contexts.) * the feature generally but block it in certain contexts.)
*/ */
if (i + 1 == end || (info[i + 1].mask & indic_plan->mask_array[PREF]) == 0) /* Note: We just check that something got substituted. We don't check that
* the <pref> feature actually did it...
*
* If pref len is longer than one, then only reorder if it ligated. If
* pref len is one, only reorder if it didn't ligate with other things. */
if (_hb_glyph_info_substituted (&info[i]) &&
((pref_len == 1) ^ _hb_glyph_info_ligated (&info[i])))
{ {
/* /*
* 2. Try to find a target position the same way as for pre-base matra. * 2. Try to find a target position the same way as for pre-base matra.
@ -1461,7 +1586,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
!(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS))) !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS)))
new_pos--; new_pos--;
/* In Khmer coeng model, a V,Ra can go *after* matras. If it goes after a /* In Khmer coeng model, a H,Ra can go *after* matras. If it goes after a
* split matra, it should be reordered to *before* the left part of such matra. */ * split matra, it should be reordered to *before* the left part of such matra. */
if (new_pos > start && info[new_pos - 1].indic_category() == OT_M) if (new_pos > start && info[new_pos - 1].indic_category() == OT_M)
{ {
@ -1511,11 +1636,20 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
*/ */
if (hb_options ().uniscribe_bug_compatible) if (hb_options ().uniscribe_bug_compatible)
{ {
/* Uniscribe merges the entire cluster. switch ((hb_tag_t) plan->props.script)
* This means, half forms are submerged into the main consonants cluster. {
* This is unnecessary, and makes cursor positioning harder, but that's what case HB_SCRIPT_TAMIL:
* Uniscribe does. */ case HB_SCRIPT_SINHALA:
buffer->merge_clusters (start, end); break;
default:
/* Uniscribe merges the entire cluster... Except for Tamil & Sinhala.
* This means, half forms are submerged into the main consonants cluster.
* This is unnecessary, and makes cursor positioning harder, but that's what
* Uniscribe does. */
buffer->merge_clusters (start, end);
break;
}
} }
} }
@ -1539,15 +1673,23 @@ final_reordering (const hb_ot_shape_plan_t *plan,
} }
final_reordering_syllable (plan, buffer, last, count); final_reordering_syllable (plan, buffer, last, count);
/* Zero syllables now... */
for (unsigned int i = 0; i < count; i++)
info[i].syllable() = 0;
HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
} }
static void
clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
{
hb_glyph_info_t *info = buffer->info;
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
info[i].syllable() = 0;
}
static hb_ot_shape_normalization_mode_t static hb_ot_shape_normalization_mode_t
normalization_preference_indic (const hb_segment_properties_t *props HB_UNUSED) normalization_preference_indic (const hb_segment_properties_t *props HB_UNUSED)
{ {
@ -1627,7 +1769,7 @@ decompose_indic (const hb_ot_shape_normalize_context_t *c,
if (hb_options ().uniscribe_bug_compatible || if (hb_options ().uniscribe_bug_compatible ||
(c->font->get_glyph (ab, 0, &glyph) && (c->font->get_glyph (ab, 0, &glyph) &&
indic_plan->pstf.would_substitute (&glyph, 1, true, c->font->face))) indic_plan->pstf.would_substitute (&glyph, 1, c->font->face)))
{ {
/* Ok, safe to use Uniscribe-style decomposition. */ /* Ok, safe to use Uniscribe-style decomposition. */
*a = 0x0DD9; *a = 0x0DD9;

View File

@ -60,6 +60,16 @@ other_features[] =
HB_TAG('p','s','t','s'), HB_TAG('p','s','t','s'),
/* Positioning features, though we don't care about the types. */ /* Positioning features, though we don't care about the types. */
HB_TAG('d','i','s','t'), HB_TAG('d','i','s','t'),
/* Pre-release version of Windows 8 Myanmar font had abvm,blwm
* features. The released Windows 8 version of the font (as well
* as the released spec) used 'mark' instead. The Windows 8
* shaper however didn't apply 'mark' but did apply 'mkmk'.
* Perhaps it applied abvm/blwm. This was fixed in a Windows 8
* update, so now it applies mark/mkmk. We are guessing that
* it still applies abvm/blwm too.
*/
HB_TAG('a','b','v','m'),
HB_TAG('b','l','w','m'),
}; };
static void static void
@ -109,6 +119,7 @@ override_features_myanmar (hb_ot_shape_planner_t *plan)
enum syllable_type_t { enum syllable_type_t {
consonant_syllable, consonant_syllable,
punctuation_cluster,
broken_cluster, broken_cluster,
non_myanmar_cluster, non_myanmar_cluster,
}; };
@ -133,7 +144,8 @@ enum myanmar_category_t {
OT_VBlw = 27, OT_VBlw = 27,
OT_VPre = 28, OT_VPre = 28,
OT_VPst = 29, OT_VPst = 29,
OT_VS = 30 /* Variation selectors */ OT_VS = 30, /* Variation selectors */
OT_P = 31 /* Punctuation */
}; };
@ -141,7 +153,7 @@ static inline bool
is_one_of (const hb_glyph_info_t &info, unsigned int flags) is_one_of (const hb_glyph_info_t &info, unsigned int flags)
{ {
/* If it ligated, all bets are off. */ /* If it ligated, all bets are off. */
if (is_a_ligature (info)) return false; if (_hb_glyph_info_ligated (&info)) return false;
return !!(FLAG (info.myanmar_category()) & flags); return !!(FLAG (info.myanmar_category()) & flags);
} }
@ -176,6 +188,10 @@ set_myanmar_properties (hb_glyph_info_t &info)
switch (u) switch (u)
{ {
case 0x104E:
cat = (indic_category_t) OT_C; /* The spec says C, IndicSyllableCategory doesn't have. */
break;
case 0x002D: case 0x00A0: case 0x00D7: case 0x2012: case 0x002D: case 0x00A0: case 0x00D7: case 0x2012:
case 0x2013: case 0x2014: case 0x2015: case 0x2022: case 0x2013: case 0x2014: case 0x2015: case 0x2022:
case 0x25CC: case 0x25FB: case 0x25FC: case 0x25FD: case 0x25CC: case 0x25FB: case 0x25FC: case 0x25FD:
@ -233,6 +249,10 @@ set_myanmar_properties (hb_glyph_info_t &info)
case 0x108F: case 0x109A: case 0x109B: case 0x109C: case 0x108F: case 0x109A: case 0x109B: case 0x109C:
cat = (indic_category_t) OT_SM; cat = (indic_category_t) OT_SM;
break; break;
case 0x104A: case 0x104B:
cat = (indic_category_t) OT_P;
break;
} }
if (cat == OT_M) if (cat == OT_M)
@ -395,6 +415,16 @@ initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
initial_reordering_consonant_syllable (plan, face, buffer, start, end); initial_reordering_consonant_syllable (plan, face, buffer, start, end);
} }
static void
initial_reordering_punctuation_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_face_t *face HB_UNUSED,
hb_buffer_t *buffer HB_UNUSED,
unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
{
/* Nothing to do right now. If we ever switch to using the output
* buffer in the reordering process, we'd need to next_glyph() here. */
}
static void static void
initial_reordering_non_myanmar_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, initial_reordering_non_myanmar_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_face_t *face HB_UNUSED, hb_face_t *face HB_UNUSED,
@ -415,6 +445,7 @@ initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
switch (syllable_type) { switch (syllable_type) {
case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return; case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return;
case punctuation_cluster: initial_reordering_punctuation_cluster (plan, face, buffer, start, end); return;
case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return; case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return;
case non_myanmar_cluster: initial_reordering_non_myanmar_cluster (plan, face, buffer, start, end); return; case non_myanmar_cluster: initial_reordering_non_myanmar_cluster (plan, face, buffer, start, end); return;
} }

View File

@ -279,9 +279,6 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
/* Unicode-3.0 additions */ /* Unicode-3.0 additions */
case HB_SCRIPT_SINHALA: case HB_SCRIPT_SINHALA:
/* Unicode-4.1 additions */
case HB_SCRIPT_BUGINESE:
/* Unicode-5.0 additions */ /* Unicode-5.0 additions */
case HB_SCRIPT_BALINESE: case HB_SCRIPT_BALINESE:
@ -336,6 +333,7 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
return &_hb_ot_complex_shaper_default; return &_hb_ot_complex_shaper_default;
/* Unicode-4.1 additions */ /* Unicode-4.1 additions */
case HB_SCRIPT_BUGINESE:
case HB_SCRIPT_NEW_TAI_LUE: case HB_SCRIPT_NEW_TAI_LUE:
/* Unicode-5.1 additions */ /* Unicode-5.1 additions */

View File

@ -266,7 +266,7 @@ initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
switch (syllable_type) { switch (syllable_type) {
case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return; case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return;
case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return; case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return;
case non_sea_cluster: initial_reordering_non_sea_cluster (plan, face, buffer, start, end); return; case non_sea_cluster: initial_reordering_non_sea_cluster (plan, face, buffer, start, end); return;
} }
} }

View File

@ -260,7 +260,13 @@ position_mark (const hb_ot_shape_plan_t *plan,
case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT: case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW: case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
pos.y_offset += base_extents.y_bearing + base_extents.height - mark_extents.y_bearing; pos.y_offset = base_extents.y_bearing + base_extents.height - mark_extents.y_bearing;
/* Never shift up "below" marks. */
if ((y_gap > 0) == (pos.y_offset > 0))
{
base_extents.height -= pos.y_offset;
pos.y_offset = 0;
}
base_extents.height += mark_extents.height; base_extents.height += mark_extents.height;
break; break;
@ -274,7 +280,15 @@ position_mark (const hb_ot_shape_plan_t *plan,
case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE: case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT: case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
pos.y_offset += base_extents.y_bearing - (mark_extents.y_bearing + mark_extents.height); pos.y_offset = base_extents.y_bearing - (mark_extents.y_bearing + mark_extents.height);
/* Don't shift down "above" marks too much. */
if ((y_gap > 0) != (pos.y_offset > 0))
{
unsigned int correction = -pos.y_offset / 2;
base_extents.y_bearing += correction;
base_extents.height -= correction;
pos.y_offset += correction;
}
base_extents.y_bearing -= mark_extents.height; base_extents.y_bearing -= mark_extents.height;
base_extents.height += mark_extents.height; base_extents.height += mark_extents.height;
break; break;
@ -300,8 +314,8 @@ position_around_base (const hb_ot_shape_plan_t *plan,
base_extents.x_bearing += buffer->pos[base].x_offset; base_extents.x_bearing += buffer->pos[base].x_offset;
base_extents.y_bearing += buffer->pos[base].y_offset; base_extents.y_bearing += buffer->pos[base].y_offset;
unsigned int lig_id = get_lig_id (buffer->info[base]); unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[base]);
unsigned int num_lig_components = get_lig_num_comps (buffer->info[base]); unsigned int num_lig_components = _hb_glyph_info_get_lig_num_comps (&buffer->info[base]);
hb_position_t x_offset = 0, y_offset = 0; hb_position_t x_offset = 0, y_offset = 0;
if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) { if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
@ -317,8 +331,8 @@ position_around_base (const hb_ot_shape_plan_t *plan,
if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i])) if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]))
{ {
if (num_lig_components > 1) { if (num_lig_components > 1) {
unsigned int this_lig_id = get_lig_id (buffer->info[i]); unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[i]);
unsigned int this_lig_component = get_lig_comp (buffer->info[i]) - 1; unsigned int this_lig_component = _hb_glyph_info_get_lig_comp (&buffer->info[i]) - 1;
/* Conditions for attaching to the last component. */ /* Conditions for attaching to the last component. */
if (!lig_id || lig_id != this_lig_id || this_lig_component >= num_lig_components) if (!lig_id || lig_id != this_lig_id || this_lig_component >= num_lig_components)
this_lig_component = num_lig_components - 1; this_lig_component = num_lig_components - 1;
@ -416,41 +430,52 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
hb_font_t *font, hb_font_t *font,
hb_buffer_t *buffer) hb_buffer_t *buffer)
{ {
unsigned int count = buffer->len;
hb_mask_t kern_mask = plan->map.get_1_mask (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ? hb_mask_t kern_mask = plan->map.get_1_mask (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ?
HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n')); HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n'));
if (!kern_mask) return;
unsigned int count = buffer->len;
OT::hb_apply_context_t c (1, font, buffer); OT::hb_apply_context_t c (1, font, buffer);
c.set_lookup_mask (kern_mask); c.set_lookup_mask (kern_mask);
c.set_lookup_props (OT::LookupFlag::IgnoreMarks); c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
for (buffer->idx = 0; buffer->idx < count;) hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
for (unsigned int idx = 0; idx < count;)
{ {
OT::hb_apply_context_t::skipping_forward_iterator_t skippy_iter (&c, buffer->idx, 1); OT::hb_apply_context_t::skipping_forward_iterator_t skippy_iter (&c, idx, 1);
if (!skippy_iter.next ()) if (!skippy_iter.next ())
{ {
buffer->idx++; idx++;
continue; continue;
} }
hb_position_t x_kern, y_kern, kern1, kern2; hb_position_t x_kern, y_kern;
font->get_glyph_kerning_for_direction (buffer->info[buffer->idx].codepoint, font->get_glyph_kerning_for_direction (info[idx].codepoint,
buffer->info[skippy_iter.idx].codepoint, info[skippy_iter.idx].codepoint,
buffer->props.direction, buffer->props.direction,
&x_kern, &y_kern); &x_kern, &y_kern);
kern1 = x_kern >> 1; if (x_kern)
kern2 = x_kern - kern1; {
buffer->pos[buffer->idx].x_advance += kern1; hb_position_t kern1 = x_kern >> 1;
buffer->pos[skippy_iter.idx].x_advance += kern2; hb_position_t kern2 = x_kern - kern1;
buffer->pos[skippy_iter.idx].x_offset += kern2; pos[idx].x_advance += kern1;
pos[skippy_iter.idx].x_advance += kern2;
pos[skippy_iter.idx].x_offset += kern2;
}
kern1 = y_kern >> 1; if (y_kern)
kern2 = y_kern - kern1; {
buffer->pos[buffer->idx].y_advance += kern1; hb_position_t kern1 = y_kern >> 1;
buffer->pos[skippy_iter.idx].y_advance += kern2; hb_position_t kern2 = y_kern - kern1;
buffer->pos[skippy_iter.idx].y_offset += kern2; pos[idx].y_advance += kern1;
pos[skippy_iter.idx].y_advance += kern2;
pos[skippy_iter.idx].y_offset += kern2;
}
buffer->idx = skippy_iter.idx; idx = skippy_iter.idx;
} }
} }

View File

@ -29,8 +29,6 @@
#include "hb-private.hh" #include "hb-private.hh"
#include "hb-font.h"
#include "hb-buffer.h"
/* buffer var allocations, used during the normalization process */ /* buffer var allocations, used during the normalization process */
#define glyph_index() var1.u32 #define glyph_index() var1.u32

View File

@ -132,17 +132,19 @@ static inline unsigned int
decompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint_t ab) decompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint_t ab)
{ {
hb_codepoint_t a, b, a_glyph, b_glyph; hb_codepoint_t a, b, a_glyph, b_glyph;
hb_buffer_t * const buffer = c->buffer;
hb_font_t * const font = c->font;
if (!c->decompose (c, ab, &a, &b) || if (!c->decompose (c, ab, &a, &b) ||
(b && !c->font->get_glyph (b, 0, &b_glyph))) (b && !font->get_glyph (b, 0, &b_glyph)))
return 0; return 0;
bool has_a = c->font->get_glyph (a, 0, &a_glyph); bool has_a = font->get_glyph (a, 0, &a_glyph);
if (shortest && has_a) { if (shortest && has_a) {
/* Output a and b */ /* Output a and b */
output_char (c->buffer, a, a_glyph); output_char (buffer, a, a_glyph);
if (likely (b)) { if (likely (b)) {
output_char (c->buffer, b, b_glyph); output_char (buffer, b, b_glyph);
return 2; return 2;
} }
return 1; return 1;
@ -151,16 +153,16 @@ decompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint
unsigned int ret; unsigned int ret;
if ((ret = decompose (c, shortest, a))) { if ((ret = decompose (c, shortest, a))) {
if (b) { if (b) {
output_char (c->buffer, b, b_glyph); output_char (buffer, b, b_glyph);
return ret + 1; return ret + 1;
} }
return ret; return ret;
} }
if (has_a) { if (has_a) {
output_char (c->buffer, a, a_glyph); output_char (buffer, a, a_glyph);
if (likely (b)) { if (likely (b)) {
output_char (c->buffer, b, b_glyph); output_char (buffer, b, b_glyph);
return 2; return 2;
} }
return 1; return 1;
@ -214,34 +216,35 @@ static inline void
handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end) handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end)
{ {
hb_buffer_t * const buffer = c->buffer; hb_buffer_t * const buffer = c->buffer;
hb_font_t * const font = c->font;
for (; buffer->idx < end - 1;) { for (; buffer->idx < end - 1;) {
if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) { if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
/* The next two lines are some ugly lines... But work. */ /* The next two lines are some ugly lines... But work. */
if (c->font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index())) if (font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
{ {
buffer->replace_glyphs (2, 1, &buffer->cur().codepoint); buffer->replace_glyphs (2, 1, &buffer->cur().codepoint);
} }
else else
{ {
/* Just pass on the two characters separately, let GSUB do its magic. */ /* Just pass on the two characters separately, let GSUB do its magic. */
set_glyph (buffer->cur(), c->font); set_glyph (buffer->cur(), font);
buffer->next_glyph (); buffer->next_glyph ();
set_glyph (buffer->cur(), c->font); set_glyph (buffer->cur(), font);
buffer->next_glyph (); buffer->next_glyph ();
} }
/* Skip any further variation selectors. */ /* Skip any further variation selectors. */
while (buffer->idx < end && unlikely (buffer->unicode->is_variation_selector (buffer->cur().codepoint))) while (buffer->idx < end && unlikely (buffer->unicode->is_variation_selector (buffer->cur().codepoint)))
{ {
set_glyph (buffer->cur(), c->font); set_glyph (buffer->cur(), font);
buffer->next_glyph (); buffer->next_glyph ();
} }
} else { } else {
set_glyph (buffer->cur(), c->font); set_glyph (buffer->cur(), font);
buffer->next_glyph (); buffer->next_glyph ();
} }
} }
if (likely (buffer->idx < end)) { if (likely (buffer->idx < end)) {
set_glyph (buffer->cur(), c->font); set_glyph (buffer->cur(), font);
buffer->next_glyph (); buffer->next_glyph ();
} }
} }

View File

@ -66,7 +66,7 @@ struct hb_ot_shape_planner_t
hb_ot_map_builder_t map; hb_ot_map_builder_t map;
hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan) : hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan) :
face (master_plan->face), face (master_plan->face_unsafe),
props (master_plan->props), props (master_plan->props),
shaper (NULL), shaper (NULL),
map (face, &props) {} map (face, &props) {}

View File

@ -290,16 +290,18 @@ hb_ot_mirror_chars (hb_ot_shape_context_t *c)
if (HB_DIRECTION_IS_FORWARD (c->target_direction)) if (HB_DIRECTION_IS_FORWARD (c->target_direction))
return; return;
hb_unicode_funcs_t *unicode = c->buffer->unicode; hb_buffer_t *buffer = c->buffer;
hb_unicode_funcs_t *unicode = buffer->unicode;
hb_mask_t rtlm_mask = c->plan->map.get_1_mask (HB_TAG ('r','t','l','m')); hb_mask_t rtlm_mask = c->plan->map.get_1_mask (HB_TAG ('r','t','l','m'));
unsigned int count = c->buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) { for (unsigned int i = 0; i < count; i++) {
hb_codepoint_t codepoint = unicode->mirroring (c->buffer->info[i].codepoint); hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
if (likely (codepoint == c->buffer->info[i].codepoint)) if (likely (codepoint == info[i].codepoint))
c->buffer->info[i].mask |= rtlm_mask; info[i].mask |= rtlm_mask;
else else
c->buffer->info[i].codepoint = codepoint; info[i].codepoint = codepoint;
} }
} }
@ -307,12 +309,13 @@ static inline void
hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
{ {
hb_ot_map_t *map = &c->plan->map; hb_ot_map_t *map = &c->plan->map;
hb_buffer_t *buffer = c->buffer;
hb_mask_t global_mask = map->get_global_mask (); hb_mask_t global_mask = map->get_global_mask ();
c->buffer->reset_masks (global_mask); buffer->reset_masks (global_mask);
if (c->plan->shaper->setup_masks) if (c->plan->shaper->setup_masks)
c->plan->shaper->setup_masks (c->plan, c->buffer, c->font); c->plan->shaper->setup_masks (c->plan, buffer, c->font);
for (unsigned int i = 0; i < c->num_user_features; i++) for (unsigned int i = 0; i < c->num_user_features; i++)
{ {
@ -320,7 +323,7 @@ hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
if (!(feature->start == 0 && feature->end == (unsigned int)-1)) { if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
unsigned int shift; unsigned int shift;
hb_mask_t mask = map->get_mask (feature->tag, &shift); hb_mask_t mask = map->get_mask (feature->tag, &shift);
c->buffer->set_masks (feature->value << shift, mask, feature->start, feature->end); buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
} }
} }
} }
@ -338,46 +341,53 @@ static inline void
hb_synthesize_glyph_classes (hb_ot_shape_context_t *c) hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
{ {
unsigned int count = c->buffer->len; unsigned int count = c->buffer->len;
hb_glyph_info_t *info = c->buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
c->buffer->info[i].glyph_props() = _hb_glyph_info_get_general_category (&c->buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ? _hb_glyph_info_set_glyph_props (&info[i],
HB_OT_LAYOUT_GLYPH_PROPS_MARK : _hb_glyph_info_get_general_category (&info[i])
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH; == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ?
HB_OT_LAYOUT_GLYPH_PROPS_MARK :
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
} }
static inline void static inline void
hb_ot_substitute_default (hb_ot_shape_context_t *c) hb_ot_substitute_default (hb_ot_shape_context_t *c)
{ {
hb_buffer_t *buffer = c->buffer;
if (c->plan->shaper->preprocess_text) if (c->plan->shaper->preprocess_text)
c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font); c->plan->shaper->preprocess_text (c->plan, buffer, c->font);
hb_ot_mirror_chars (c); hb_ot_mirror_chars (c);
HB_BUFFER_ALLOCATE_VAR (c->buffer, glyph_index); HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
_hb_ot_shape_normalize (c->plan, c->buffer, c->font); _hb_ot_shape_normalize (c->plan, buffer, c->font);
hb_ot_shape_setup_masks (c); hb_ot_shape_setup_masks (c);
/* This is unfortunate to go here, but necessary... */ /* This is unfortunate to go here, but necessary... */
if (!hb_ot_layout_has_positioning (c->face)) if (!hb_ot_layout_has_positioning (c->face))
_hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, c->buffer); _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer);
hb_ot_map_glyphs_fast (c->buffer); hb_ot_map_glyphs_fast (buffer);
HB_BUFFER_DEALLOCATE_VAR (c->buffer, glyph_index); HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index);
} }
static inline void static inline void
hb_ot_substitute_complex (hb_ot_shape_context_t *c) hb_ot_substitute_complex (hb_ot_shape_context_t *c)
{ {
hb_ot_layout_substitute_start (c->font, c->buffer); hb_buffer_t *buffer = c->buffer;
hb_ot_layout_substitute_start (c->font, buffer);
if (!hb_ot_layout_has_glyph_classes (c->face)) if (!hb_ot_layout_has_glyph_classes (c->face))
hb_synthesize_glyph_classes (c); hb_synthesize_glyph_classes (c);
c->plan->substitute (c->font, c->buffer); c->plan->substitute (c->font, buffer);
hb_ot_layout_substitute_finish (c->font, c->buffer); hb_ot_layout_substitute_finish (c->font, buffer);
return; return;
} }
@ -408,7 +418,7 @@ zero_mark_widths_by_gdef (hb_buffer_t *buffer)
{ {
unsigned int count = buffer->len; unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if ((buffer->info[i].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) if (_hb_glyph_info_is_mark (&buffer->info[i]))
{ {
buffer->pos[i].x_advance = 0; buffer->pos[i].x_advance = 0;
buffer->pos[i].y_advance = 0; buffer->pos[i].y_advance = 0;
@ -418,21 +428,29 @@ zero_mark_widths_by_gdef (hb_buffer_t *buffer)
static inline void static inline void
hb_ot_position_default (hb_ot_shape_context_t *c) hb_ot_position_default (hb_ot_shape_context_t *c)
{ {
hb_ot_layout_position_start (c->font, c->buffer); hb_direction_t direction = c->buffer->props.direction;
unsigned int count = c->buffer->len; unsigned int count = c->buffer->len;
hb_glyph_info_t *info = c->buffer->info;
hb_glyph_position_t *pos = c->buffer->pos;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
{ {
c->font->get_glyph_advance_for_direction (c->buffer->info[i].codepoint, c->font->get_glyph_advance_for_direction (info[i].codepoint,
c->buffer->props.direction, direction,
&c->buffer->pos[i].x_advance, &pos[i].x_advance,
&c->buffer->pos[i].y_advance); &pos[i].y_advance);
c->font->subtract_glyph_origin_for_direction (c->buffer->info[i].codepoint, c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
c->buffer->props.direction, direction,
&c->buffer->pos[i].x_offset, &pos[i].x_offset,
&c->buffer->pos[i].y_offset); &pos[i].y_offset);
} }
}
static inline bool
hb_ot_position_complex (hb_ot_shape_context_t *c)
{
bool ret = false;
unsigned int count = c->buffer->len;
switch (c->plan->shaper->zero_width_marks) switch (c->plan->shaper->zero_width_marks)
{ {
@ -452,32 +470,28 @@ hb_ot_position_default (hb_ot_shape_context_t *c)
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
break; break;
} }
}
static inline bool
hb_ot_position_complex (hb_ot_shape_context_t *c)
{
bool ret = false;
unsigned int count = c->buffer->len;
if (hb_ot_layout_has_positioning (c->face)) if (hb_ot_layout_has_positioning (c->face))
{ {
hb_glyph_info_t *info = c->buffer->info;
hb_glyph_position_t *pos = c->buffer->pos;
/* Change glyph origin to what GPOS expects, apply GPOS, change it back. */ /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */
for (unsigned int i = 0; i < count; i++) { for (unsigned int i = 0; i < count; i++) {
c->font->add_glyph_origin_for_direction (c->buffer->info[i].codepoint, c->font->add_glyph_origin_for_direction (info[i].codepoint,
HB_DIRECTION_LTR, HB_DIRECTION_LTR,
&c->buffer->pos[i].x_offset, &pos[i].x_offset,
&c->buffer->pos[i].y_offset); &pos[i].y_offset);
} }
c->plan->position (c->font, c->buffer); c->plan->position (c->font, c->buffer);
for (unsigned int i = 0; i < count; i++) { for (unsigned int i = 0; i < count; i++) {
c->font->subtract_glyph_origin_for_direction (c->buffer->info[i].codepoint, c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
HB_DIRECTION_LTR, HB_DIRECTION_LTR,
&c->buffer->pos[i].x_offset, &pos[i].x_offset,
&c->buffer->pos[i].y_offset); &pos[i].y_offset);
} }
ret = true; ret = true;
@ -500,18 +514,20 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
break; break;
} }
hb_ot_layout_position_finish (c->font, c->buffer);
return ret; return ret;
} }
static inline void static inline void
hb_ot_position (hb_ot_shape_context_t *c) hb_ot_position (hb_ot_shape_context_t *c)
{ {
hb_ot_layout_position_start (c->font, c->buffer);
hb_ot_position_default (c); hb_ot_position_default (c);
hb_bool_t fallback = !hb_ot_position_complex (c); hb_bool_t fallback = !hb_ot_position_complex (c);
hb_ot_layout_position_finish (c->font, c->buffer);
if (fallback && c->plan->shaper->fallback_position) if (fallback && c->plan->shaper->fallback_position)
_hb_ot_shape_fallback_position (c->plan, c->font, c->buffer); _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
@ -533,22 +549,42 @@ hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES) if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
return; return;
hb_codepoint_t space = 0; hb_codepoint_t space;
enum {
SPACE_DONT_KNOW,
SPACE_AVAILABLE,
SPACE_UNAVAILABLE
} space_status = SPACE_DONT_KNOW;
unsigned int count = c->buffer->len; unsigned int count = c->buffer->len;
hb_glyph_info_t *info = c->buffer->info;
hb_glyph_position_t *pos = c->buffer->pos;
unsigned int j = 0;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if (unlikely (!is_a_ligature (c->buffer->info[i]) && {
_hb_glyph_info_is_default_ignorable (&c->buffer->info[i]))) if (unlikely (!_hb_glyph_info_ligated (&info[i]) &&
_hb_glyph_info_is_default_ignorable (&info[i])))
{ {
if (!space) { if (space_status == SPACE_DONT_KNOW)
/* We assume that the space glyph is not gid0. */ space_status = c->font->get_glyph (' ', 0, &space) ? SPACE_AVAILABLE : SPACE_UNAVAILABLE;
if (unlikely (!c->font->get_glyph (' ', 0, &space)) || !space)
return; /* No point! */ if (space_status == SPACE_AVAILABLE)
{
info[i].codepoint = space;
pos[i].x_advance = 0;
pos[i].y_advance = 0;
} }
c->buffer->info[i].codepoint = space; else
c->buffer->pos[i].x_advance = 0; continue; /* Delete it. */
c->buffer->pos[i].y_advance = 0;
} }
if (j != i)
{
info[j] = info[i];
pos[j] = pos[i];
}
j++;
}
c->buffer->len = j;
} }
@ -562,8 +598,7 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
/* Save the original direction, we use it later. */ /* Save the original direction, we use it later. */
c->target_direction = c->buffer->props.direction; c->target_direction = c->buffer->props.direction;
HB_BUFFER_ALLOCATE_VAR (c->buffer, unicode_props0); _hb_buffer_allocate_unicode_vars (c->buffer);
HB_BUFFER_ALLOCATE_VAR (c->buffer, unicode_props1);
c->buffer->clear_output (); c->buffer->clear_output ();
@ -578,8 +613,7 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
hb_ot_hide_default_ignorables (c); hb_ot_hide_default_ignorables (c);
HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props1); _hb_buffer_deallocate_unicode_vars (c->buffer);
HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props0);
c->buffer->props.direction = c->target_direction; c->buffer->props.direction = c->target_direction;

View File

@ -27,7 +27,6 @@
*/ */
#include "hb-private.hh" #include "hb-private.hh"
#include "hb-ot.h"
#include <string.h> #include <string.h>
@ -167,9 +166,12 @@ typedef struct {
* *
* Generated by intersecting the OpenType language tag list from * Generated by intersecting the OpenType language tag list from
* Draft OpenType 1.5 spec, with with the ISO 639-3 codes from * Draft OpenType 1.5 spec, with with the ISO 639-3 codes from
* 2008/08/04, matching on name, and finally adjusted manually. * 2008-08-04, matching on name, and finally adjusted manually.
* *
* Updated on 2012/12/07 with more research into remaining codes. * Updated on 2012-12-07 with more research into remaining codes.
*
* Updated on 2013-11-23 based on usage in SIL and Microsoft fonts,
* the new proposal from Microsoft, and latest ISO 639-3 names.
* *
* Some items still missing. Those are commented out at the end. * Some items still missing. Those are commented out at the end.
* Keep sorted for bsearch. * Keep sorted for bsearch.
@ -179,57 +181,90 @@ static const LangTag ot_languages[] = {
{"aa", HB_TAG('A','F','R',' ')}, /* Afar */ {"aa", HB_TAG('A','F','R',' ')}, /* Afar */
{"ab", HB_TAG('A','B','K',' ')}, /* Abkhazian */ {"ab", HB_TAG('A','B','K',' ')}, /* Abkhazian */
{"abq", HB_TAG('A','B','A',' ')}, /* Abaza */ {"abq", HB_TAG('A','B','A',' ')}, /* Abaza */
{"ach", HB_TAG('A','C','H',' ')}, /* Acoli */
{"ada", HB_TAG('D','N','G',' ')}, /* Dangme */ {"ada", HB_TAG('D','N','G',' ')}, /* Dangme */
{"ady", HB_TAG('A','D','Y',' ')}, /* Adyghe */ {"ady", HB_TAG('A','D','Y',' ')}, /* Adyghe */
{"af", HB_TAG('A','F','K',' ')}, /* Afrikaans */ {"af", HB_TAG('A','F','K',' ')}, /* Afrikaans */
{"aii", HB_TAG('S','W','A',' ')}, /* Swadaya Aramaic */ {"aii", HB_TAG('S','W','A',' ')}, /* Swadaya Aramaic */
{"aio", HB_TAG('A','I','O',' ')}, /* Aiton */
{"aiw", HB_TAG('A','R','I',' ')}, /* Aari */ {"aiw", HB_TAG('A','R','I',' ')}, /* Aari */
{"ak", HB_TAG('T','W','I',' ')}, /* Akan [macrolanguage] */
{"alt", HB_TAG('A','L','T',' ')}, /* [Southern] Altai */ {"alt", HB_TAG('A','L','T',' ')}, /* [Southern] Altai */
{"am", HB_TAG('A','M','H',' ')}, /* Amharic */ {"am", HB_TAG('A','M','H',' ')}, /* Amharic */
{"amf", HB_TAG('H','B','N',' ')}, /* Hammer-Banna */ {"amf", HB_TAG('H','B','N',' ')}, /* Hammer-Banna */
{"ar", HB_TAG('A','R','A',' ')}, /* Arabic */ {"an", HB_TAG('A','R','G',' ')}, /* Aragonese */
{"ang", HB_TAG('A','N','G',' ')}, /* Old English (ca. 450-1100) */
{"ar", HB_TAG('A','R','A',' ')}, /* Arabic [macrolanguage] */
{"arb", HB_TAG('A','R','A',' ')}, /* Standard Arabic */
{"arn", HB_TAG('M','A','P',' ')}, /* Mapudungun */ {"arn", HB_TAG('M','A','P',' ')}, /* Mapudungun */
{"ary", HB_TAG('M','O','R',' ')}, /* Moroccan Arabic */
{"as", HB_TAG('A','S','M',' ')}, /* Assamese */ {"as", HB_TAG('A','S','M',' ')}, /* Assamese */
{"ast", HB_TAG('A','S','T',' ')}, /* Asturian/Asturleonese/Bable/Leonese */
{"ath", HB_TAG('A','T','H',' ')}, /* Athapaskan [family] */ {"ath", HB_TAG('A','T','H',' ')}, /* Athapaskan [family] */
{"atv", HB_TAG('A','L','T',' ')}, /* [Northern] Altai */ {"atv", HB_TAG('A','L','T',' ')}, /* [Northern] Altai */
{"av", HB_TAG('A','V','R',' ')}, /* Avaric */ {"av", HB_TAG('A','V','R',' ')}, /* Avaric */
{"awa", HB_TAG('A','W','A',' ')}, /* Awadhi */ {"awa", HB_TAG('A','W','A',' ')}, /* Awadhi */
{"ay", HB_TAG('A','Y','M',' ')}, /* Aymara */ {"ay", HB_TAG('A','Y','M',' ')}, /* Aymara [macrolanguage] */
{"az", HB_TAG('A','Z','E',' ')}, /* Azerbaijani */ {"az", HB_TAG('A','Z','E',' ')}, /* Azerbaijani [macrolanguage] */
{"azb", HB_TAG('A','Z','B',' ')}, /* South Azerbaijani */
{"azj", HB_TAG('A','Z','E',' ')}, /* North Azerbaijani */
{"ba", HB_TAG('B','S','H',' ')}, /* Bashkir */ {"ba", HB_TAG('B','S','H',' ')}, /* Bashkir */
{"bai", HB_TAG('B','M','L',' ')}, /* Bamileke [family] */ {"bai", HB_TAG('B','M','L',' ')}, /* Bamileke [family] */
{"bal", HB_TAG('B','L','I',' ')}, /* Baluchi */ {"bal", HB_TAG('B','L','I',' ')}, /* Baluchi [macrolangauge] */
{"bci", HB_TAG('B','A','U',' ')}, /* Baule */ {"ban", HB_TAG('B','A','N',' ')}, /* Balinese */
{"bar", HB_TAG('B','A','R',' ')}, /* Bavarian */
{"bbc", HB_TAG('B','B','C',' ')}, /* Batak Toba */
{"bci", HB_TAG('B','A','U',' ')}, /* Baoulé */
{"bcl", HB_TAG('B','I','K',' ')}, /* Central Bikol */
{"bcq", HB_TAG('B','C','H',' ')}, /* Bench */ {"bcq", HB_TAG('B','C','H',' ')}, /* Bench */
{"be", HB_TAG('B','E','L',' ')}, /* Belarussian */ {"be", HB_TAG('B','E','L',' ')}, /* Belarusian */
{"bem", HB_TAG('B','E','M',' ')}, /* Bemba (Zambia) */ {"bem", HB_TAG('B','E','M',' ')}, /* Bemba (Zambia) */
{"ber", HB_TAG('B','E','R',' ')}, /* Berber [family] */ {"ber", HB_TAG('B','E','R',' ')}, /* Berber [family] */
{"bfq", HB_TAG('B','A','D',' ')}, /* Badaga */ {"bfq", HB_TAG('B','A','D',' ')}, /* Badaga */
{"bft", HB_TAG('B','L','T',' ')}, /* Balti */ {"bft", HB_TAG('B','L','T',' ')}, /* Balti */
{"bfy", HB_TAG('B','A','G',' ')}, /* Baghelkhandi */ {"bfy", HB_TAG('B','A','G',' ')}, /* Baghelkhandi */
{"bg", HB_TAG('B','G','R',' ')}, /* Bulgarian */ {"bg", HB_TAG('B','G','R',' ')}, /* Bulgarian */
{"bgc", HB_TAG('B','G','C',' ')}, /* Haryanvi */
{"bgq", HB_TAG('B','G','Q',' ')}, /* Bagri */
{"bhb", HB_TAG('B','H','I',' ')}, /* Bhili */ {"bhb", HB_TAG('B','H','I',' ')}, /* Bhili */
{"bhk", HB_TAG('B','I','K',' ')}, /* Albay Bicolano (retired code) */
{"bho", HB_TAG('B','H','O',' ')}, /* Bhojpuri */ {"bho", HB_TAG('B','H','O',' ')}, /* Bhojpuri */
{"bik", HB_TAG('B','I','K',' ')}, /* Bikol */ {"bi", HB_TAG('B','I','S',' ')}, /* Bislama */
{"bik", HB_TAG('B','I','K',' ')}, /* Bikol [macrolanguage] */
{"bin", HB_TAG('E','D','O',' ')}, /* Bini */ {"bin", HB_TAG('E','D','O',' ')}, /* Bini */
{"bjj", HB_TAG('B','J','J',' ')}, /* Kanauji */
{"bjt", HB_TAG('B','L','N',' ')}, /* Balanta-Ganja */ {"bjt", HB_TAG('B','L','N',' ')}, /* Balanta-Ganja */
{"bla", HB_TAG('B','K','F',' ')}, /* Blackfoot */ {"bla", HB_TAG('B','K','F',' ')}, /* Blackfoot */
{"ble", HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe */ {"ble", HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe */
{"blk", HB_TAG('B','L','K',' ')}, /* Pa'O/Pa'o Karen */
{"bln", HB_TAG('B','I','K',' ')}, /* Southern Catanduanes Bikol */
{"bm", HB_TAG('B','M','B',' ')}, /* Bambara */ {"bm", HB_TAG('B','M','B',' ')}, /* Bambara */
{"bn", HB_TAG('B','E','N',' ')}, /* Bengali */ {"bn", HB_TAG('B','E','N',' ')}, /* Bengali */
{"bo", HB_TAG('T','I','B',' ')}, /* Tibetan */ {"bo", HB_TAG('T','I','B',' ')}, /* Tibetan */
{"bpy", HB_TAG('B','P','Y',' ')}, /* Bishnupriya */
{"bqi", HB_TAG('L','R','C',' ')}, /* Bakhtiari */
{"br", HB_TAG('B','R','E',' ')}, /* Breton */ {"br", HB_TAG('B','R','E',' ')}, /* Breton */
{"bra", HB_TAG('B','R','I',' ')}, /* Braj Bhasha */ {"bra", HB_TAG('B','R','I',' ')}, /* Braj Bhasha */
{"brh", HB_TAG('B','R','H',' ')}, /* Brahui */ {"brh", HB_TAG('B','R','H',' ')}, /* Brahui */
{"brx", HB_TAG('B','R','X',' ')}, /* Bodo (India) */
{"bs", HB_TAG('B','O','S',' ')}, /* Bosnian */ {"bs", HB_TAG('B','O','S',' ')}, /* Bosnian */
{"btb", HB_TAG('B','T','I',' ')}, /* Beti (Cameroon) */ {"btb", HB_TAG('B','T','I',' ')}, /* Beti (Cameroon) */
{"bto", HB_TAG('B','I','K',' ')}, /* Rinconada Bikol */
{"bts", HB_TAG('B','T','S',' ')}, /* Batak Simalungun */
{"bug", HB_TAG('B','U','G',' ')}, /* Buginese */
{"bxr", HB_TAG('R','B','U',' ')}, /* Russian Buriat */ {"bxr", HB_TAG('R','B','U',' ')}, /* Russian Buriat */
{"byn", HB_TAG('B','I','L',' ')}, /* Bilen */ {"byn", HB_TAG('B','I','L',' ')}, /* Bilen */
{"ca", HB_TAG('C','A','T',' ')}, /* Catalan */ {"ca", HB_TAG('C','A','T',' ')}, /* Catalan */
{"cbk", HB_TAG('C','B','K',' ')}, /* Chavacano */
{"ce", HB_TAG('C','H','E',' ')}, /* Chechen */ {"ce", HB_TAG('C','H','E',' ')}, /* Chechen */
{"ceb", HB_TAG('C','E','B',' ')}, /* Cebuano */ {"ceb", HB_TAG('C','E','B',' ')}, /* Cebuano */
{"cgg", HB_TAG('C','G','G',' ')}, /* Chiga */
{"ch", HB_TAG('C','H','A',' ')}, /* Chamorro */
{"cho", HB_TAG('C','H','O',' ')}, /* Choctaw */
{"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */ {"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */
{"chr", HB_TAG('C','H','R',' ')}, /* Cherokee */ {"chr", HB_TAG('C','H','R',' ')}, /* Cherokee */
{"chy", HB_TAG('C','H','Y',' ')}, /* Cheyenne */
{"ckb", HB_TAG('K','U','R',' ')}, /* Central Kurdish (Sorani) */
{"ckt", HB_TAG('C','H','K',' ')}, /* Chukchi */ {"ckt", HB_TAG('C','H','K',' ')}, /* Chukchi */
{"cop", HB_TAG('C','O','P',' ')}, /* Coptic */ {"cop", HB_TAG('C','O','P',' ')}, /* Coptic */
{"cr", HB_TAG('C','R','E',' ')}, /* Cree */ {"cr", HB_TAG('C','R','E',' ')}, /* Cree */
@ -239,6 +274,9 @@ static const LangTag ot_languages[] = {
{"crm", HB_TAG('M','C','R',' ')}, /* Moose Cree */ {"crm", HB_TAG('M','C','R',' ')}, /* Moose Cree */
{"crx", HB_TAG('C','R','R',' ')}, /* Carrier */ {"crx", HB_TAG('C','R','R',' ')}, /* Carrier */
{"cs", HB_TAG('C','S','Y',' ')}, /* Czech */ {"cs", HB_TAG('C','S','Y',' ')}, /* Czech */
{"csb", HB_TAG('C','S','B',' ')}, /* Kashubian */
{"ctg", HB_TAG('C','T','G',' ')}, /* Chittagonian */
{"cts", HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol */
{"cu", HB_TAG('C','S','L',' ')}, /* Church Slavic */ {"cu", HB_TAG('C','S','L',' ')}, /* Church Slavic */
{"cv", HB_TAG('C','H','U',' ')}, /* Chuvash */ {"cv", HB_TAG('C','H','U',' ')}, /* Chuvash */
{"cwd", HB_TAG('D','C','R',' ')}, /* Woods Cree */ {"cwd", HB_TAG('D','C','R',' ')}, /* Woods Cree */
@ -247,34 +285,42 @@ static const LangTag ot_languages[] = {
{"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) */ {"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) */
{"dar", HB_TAG('D','A','R',' ')}, /* Dargwa */ {"dar", HB_TAG('D','A','R',' ')}, /* Dargwa */
{"de", HB_TAG('D','E','U',' ')}, /* German */ {"de", HB_TAG('D','E','U',' ')}, /* German */
{"din", HB_TAG('D','N','K',' ')}, /* Dinka */ {"dgo", HB_TAG('D','G','O',' ')}, /* Dogri */
{"dje", HB_TAG('D','J','R',' ')}, /* Djerma */ {"dhd", HB_TAG('M','A','W',' ')}, /* Dhundari */
{"din", HB_TAG('D','N','K',' ')}, /* Dinka [macrolanguage] */
{"diq", HB_TAG('D','I','Q',' ')}, /* Dimli */
{"dje", HB_TAG('D','J','R',' ')}, /* Zarma */
{"dng", HB_TAG('D','U','N',' ')}, /* Dungan */ {"dng", HB_TAG('D','U','N',' ')}, /* Dungan */
{"doi", HB_TAG('D','G','R',' ')}, /* Dogri */ {"doi", HB_TAG('D','G','R',' ')}, /* Dogri [macrolanguage] */
{"dsb", HB_TAG('L','S','B',' ')}, /* Lower Sorbian */ {"dsb", HB_TAG('L','S','B',' ')}, /* Lower Sorbian */
{"dv", HB_TAG('D','I','V',' ')}, /* Dhivehi */ {"dv", HB_TAG('D','I','V',' ')}, /* Dhivehi/Divehi/Maldivian */
{"dyu", HB_TAG('J','U','L',' ')}, /* Jula */ {"dyu", HB_TAG('J','U','L',' ')}, /* Jula */
{"dz", HB_TAG('D','Z','N',' ')}, /* Dzongkha */ {"dz", HB_TAG('D','Z','N',' ')}, /* Dzongkha */
{"ee", HB_TAG('E','W','E',' ')}, /* Ewe */ {"ee", HB_TAG('E','W','E',' ')}, /* Ewe */
{"efi", HB_TAG('E','F','I',' ')}, /* Efik */ {"efi", HB_TAG('E','F','I',' ')}, /* Efik */
{"ekk", HB_TAG('E','T','I',' ')}, /* Standard Estonian */
{"el", HB_TAG('E','L','L',' ')}, /* Modern Greek (1453-) */ {"el", HB_TAG('E','L','L',' ')}, /* Modern Greek (1453-) */
{"emk", HB_TAG('M','N','K',' ')}, /* Eastern Maninkakan */
{"en", HB_TAG('E','N','G',' ')}, /* English */ {"en", HB_TAG('E','N','G',' ')}, /* English */
{"eo", HB_TAG('N','T','O',' ')}, /* Esperanto */ {"eo", HB_TAG('N','T','O',' ')}, /* Esperanto */
{"eot", HB_TAG('B','T','I',' ')}, /* Beti (Côte d'Ivoire) */ {"eot", HB_TAG('B','T','I',' ')}, /* Beti (Côte d'Ivoire) */
{"es", HB_TAG('E','S','P',' ')}, /* Spanish */ {"es", HB_TAG('E','S','P',' ')}, /* Spanish */
{"et", HB_TAG('E','T','I',' ')}, /* Estonian */ {"et", HB_TAG('E','T','I',' ')}, /* Estonian [macrolanguage] */
{"eu", HB_TAG('E','U','Q',' ')}, /* Basque */ {"eu", HB_TAG('E','U','Q',' ')}, /* Basque */
{"eve", HB_TAG('E','V','N',' ')}, /* Even */ {"eve", HB_TAG('E','V','N',' ')}, /* Even */
{"evn", HB_TAG('E','V','K',' ')}, /* Evenki */ {"evn", HB_TAG('E','V','K',' ')}, /* Evenki */
{"fa", HB_TAG('F','A','R',' ')}, /* Persian */ {"fa", HB_TAG('F','A','R',' ')}, /* Persian [macrolanguage] */
{"ff", HB_TAG('F','U','L',' ')}, /* Fulah */ {"ff", HB_TAG('F','U','L',' ')}, /* Fulah [macrolanguage] */
{"fi", HB_TAG('F','I','N',' ')}, /* Finnish */ {"fi", HB_TAG('F','I','N',' ')}, /* Finnish */
{"fil", HB_TAG('P','I','L',' ')}, /* Filipino */ {"fil", HB_TAG('P','I','L',' ')}, /* Filipino */
{"fj", HB_TAG('F','J','I',' ')}, /* Fijian */ {"fj", HB_TAG('F','J','I',' ')}, /* Fijian */
{"fo", HB_TAG('F','O','S',' ')}, /* Faroese */ {"fo", HB_TAG('F','O','S',' ')}, /* Faroese */
{"fon", HB_TAG('F','O','N',' ')}, /* Fon */ {"fon", HB_TAG('F','O','N',' ')}, /* Fon */
{"fr", HB_TAG('F','R','A',' ')}, /* French */ {"fr", HB_TAG('F','R','A',' ')}, /* French */
{"frc", HB_TAG('F','R','C',' ')}, /* Cajun French */
{"frp", HB_TAG('F','R','P',' ')}, /* Arpitan/Francoprovençal */
{"fur", HB_TAG('F','R','L',' ')}, /* Friulian */ {"fur", HB_TAG('F','R','L',' ')}, /* Friulian */
{"fuv", HB_TAG('F','U','V',' ')}, /* Nigerian Fulfulde */
{"fy", HB_TAG('F','R','I',' ')}, /* Western Frisian */ {"fy", HB_TAG('F','R','I',' ')}, /* Western Frisian */
{"ga", HB_TAG('I','R','I',' ')}, /* Irish */ {"ga", HB_TAG('I','R','I',' ')}, /* Irish */
{"gaa", HB_TAG('G','A','D',' ')}, /* Ga */ {"gaa", HB_TAG('G','A','D',' ')}, /* Ga */
@ -282,113 +328,167 @@ static const LangTag ot_languages[] = {
{"gbm", HB_TAG('G','A','W',' ')}, /* Garhwali */ {"gbm", HB_TAG('G','A','W',' ')}, /* Garhwali */
{"gd", HB_TAG('G','A','E',' ')}, /* Scottish Gaelic */ {"gd", HB_TAG('G','A','E',' ')}, /* Scottish Gaelic */
{"gez", HB_TAG('G','E','Z',' ')}, /* Ge'ez */ {"gez", HB_TAG('G','E','Z',' ')}, /* Ge'ez */
{"ggo", HB_TAG('G','O','N',' ')}, /* Southern Gondi */
{"gl", HB_TAG('G','A','L',' ')}, /* Galician */ {"gl", HB_TAG('G','A','L',' ')}, /* Galician */
{"gld", HB_TAG('N','A','N',' ')}, /* Nanai */ {"gld", HB_TAG('N','A','N',' ')}, /* Nanai */
{"gn", HB_TAG('G','U','A',' ')}, /* Guarani */ {"glk", HB_TAG('G','L','K',' ')}, /* Gilaki */
{"gon", HB_TAG('G','O','N',' ')}, /* Gondi */ {"gn", HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */
{"gno", HB_TAG('G','O','N',' ')}, /* Northern Gondi */
{"gog", HB_TAG('G','O','G',' ')}, /* Gogo */
{"gon", HB_TAG('G','O','N',' ')}, /* Gondi [macrolanguage] */
{"grt", HB_TAG('G','R','O',' ')}, /* Garo */ {"grt", HB_TAG('G','R','O',' ')}, /* Garo */
{"gru", HB_TAG('S','O','G',' ')}, /* Sodo Gurage */ {"gru", HB_TAG('S','O','G',' ')}, /* Sodo Gurage */
{"gu", HB_TAG('G','U','J',' ')}, /* Gujarati */ {"gu", HB_TAG('G','U','J',' ')}, /* Gujarati */
{"guc", HB_TAG('G','U','C',' ')}, /* Wayuu */
{"guk", HB_TAG('G','M','Z',' ')}, /* Gumuz */ {"guk", HB_TAG('G','M','Z',' ')}, /* Gumuz */
{"gv", HB_TAG('M','N','X',' ')}, /* Manx Gaelic */ /*{"guk", HB_TAG('G','U','K',' ')},*/ /* Gumuz (in SIL fonts) */
{"guz", HB_TAG('G','U','Z',' ')}, /* Ekegusii/Gusii */
{"gv", HB_TAG('M','N','X',' ')}, /* Manx */
{"ha", HB_TAG('H','A','U',' ')}, /* Hausa */ {"ha", HB_TAG('H','A','U',' ')}, /* Hausa */
{"har", HB_TAG('H','R','I',' ')}, /* Harari */ {"har", HB_TAG('H','R','I',' ')}, /* Harari */
{"haw", HB_TAG('H','A','W',' ')}, /* Hawaiin */ {"haw", HB_TAG('H','A','W',' ')}, /* Hawaiian */
{"hay", HB_TAG('H','A','Y',' ')}, /* Haya */
{"haz", HB_TAG('H','A','Z',' ')}, /* Hazaragi */
{"he", HB_TAG('I','W','R',' ')}, /* Hebrew */ {"he", HB_TAG('I','W','R',' ')}, /* Hebrew */
{"hz", HB_TAG('H','E','R',' ')}, /* Herero */
{"hi", HB_TAG('H','I','N',' ')}, /* Hindi */ {"hi", HB_TAG('H','I','N',' ')}, /* Hindi */
{"hil", HB_TAG('H','I','L',' ')}, /* Hiligaynon */ {"hil", HB_TAG('H','I','L',' ')}, /* Hiligaynon */
{"hnd", HB_TAG('H','N','D',' ')}, /* [Southern] Hindko */ {"hnd", HB_TAG('H','N','D',' ')}, /* [Southern] Hindko */
{"hne", HB_TAG('C','H','H',' ')}, /* Chattisgarhi */ {"hne", HB_TAG('C','H','H',' ')}, /* Chattisgarhi */
{"hno", HB_TAG('H','N','D',' ')}, /* [Northern] Hindko */ {"hno", HB_TAG('H','N','D',' ')}, /* [Northern] Hindko */
{"ho", HB_TAG('H','M','O',' ')}, /* Hiri Motu */
{"hoc", HB_TAG('H','O',' ',' ')}, /* Ho */ {"hoc", HB_TAG('H','O',' ',' ')}, /* Ho */
{"hoj", HB_TAG('H','A','R',' ')}, /* Harauti */ {"hoj", HB_TAG('H','A','R',' ')}, /* Harauti */
{"hr", HB_TAG('H','R','V',' ')}, /* Croatian */ {"hr", HB_TAG('H','R','V',' ')}, /* Croatian */
{"hsb", HB_TAG('U','S','B',' ')}, /* Upper Sorbian */ {"hsb", HB_TAG('U','S','B',' ')}, /* Upper Sorbian */
{"ht", HB_TAG('H','A','I',' ')}, /* Haitian */ {"ht", HB_TAG('H','A','I',' ')}, /* Haitian/Haitian Creole */
{"hu", HB_TAG('H','U','N',' ')}, /* Hungarian */ {"hu", HB_TAG('H','U','N',' ')}, /* Hungarian */
{"hy", HB_TAG('H','Y','E',' ')}, /* Armenian */ {"hy", HB_TAG('H','Y','E',' ')}, /* Armenian */
{"hz", HB_TAG('H','E','R',' ')}, /* Herero */
{"ia", HB_TAG('I','N','A',' ')}, /* Interlingua (International Auxiliary Language Association) */
{"ibb", HB_TAG('I','B','B',' ')}, /* Ibibio */
{"id", HB_TAG('I','N','D',' ')}, /* Indonesian */ {"id", HB_TAG('I','N','D',' ')}, /* Indonesian */
{"ie", HB_TAG('I','L','E',' ')}, /* Interlingue/Occidental */
{"ig", HB_TAG('I','B','O',' ')}, /* Igbo */ {"ig", HB_TAG('I','B','O',' ')}, /* Igbo */
{"igb", HB_TAG('E','B','I',' ')}, /* Ebira */ {"igb", HB_TAG('E','B','I',' ')}, /* Ebira */
{"ijc", HB_TAG('I','J','O',' ')}, /* Izon */
{"ijo", HB_TAG('I','J','O',' ')}, /* Ijo [family] */ {"ijo", HB_TAG('I','J','O',' ')}, /* Ijo [family] */
{"ik", HB_TAG('I','P','K',' ')}, /* Inupiaq [macrolanguage] */
{"ilo", HB_TAG('I','L','O',' ')}, /* Ilokano */ {"ilo", HB_TAG('I','L','O',' ')}, /* Ilokano */
{"inh", HB_TAG('I','N','G',' ')}, /* Ingush */ {"inh", HB_TAG('I','N','G',' ')}, /* Ingush */
{"io", HB_TAG('I','D','O',' ')}, /* Ido */
{"is", HB_TAG('I','S','L',' ')}, /* Icelandic */ {"is", HB_TAG('I','S','L',' ')}, /* Icelandic */
{"it", HB_TAG('I','T','A',' ')}, /* Italian */ {"it", HB_TAG('I','T','A',' ')}, /* Italian */
{"iu", HB_TAG('I','N','U',' ')}, /* Inuktitut */ {"iu", HB_TAG('I','N','U',' ')}, /* Inuktitut [macrolanguage] */
{"ja", HB_TAG('J','A','N',' ')}, /* Japanese */ {"ja", HB_TAG('J','A','N',' ')}, /* Japanese */
{"jam", HB_TAG('J','A','M',' ')}, /* Jamaican Creole English */
{"jbo", HB_TAG('J','B','O',' ')}, /* Lojban */
{"jv", HB_TAG('J','A','V',' ')}, /* Javanese */ {"jv", HB_TAG('J','A','V',' ')}, /* Javanese */
{"ka", HB_TAG('K','A','T',' ')}, /* Georgian */ {"ka", HB_TAG('K','A','T',' ')}, /* Georgian */
{"kaa", HB_TAG('K','R','K',' ')}, /* Karakalpak */ {"kaa", HB_TAG('K','R','K',' ')}, /* Karakalpak */
{"kab", HB_TAG('K','A','B',' ')}, /* Kabyle */
{"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */ {"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */
{"kar", HB_TAG('K','R','N',' ')}, /* Karen [family] */ {"kar", HB_TAG('K','R','N',' ')}, /* Karen [family] */
{"kbd", HB_TAG('K','A','B',' ')}, /* Kabardian */ {"kbd", HB_TAG('K','A','B',' ')}, /* Kabardian */
{"kde", HB_TAG('K','D','E',' ')}, /* Makonde */
{"kdr", HB_TAG('K','R','M',' ')}, /* Karaim */ {"kdr", HB_TAG('K','R','M',' ')}, /* Karaim */
{"kdt", HB_TAG('K','U','Y',' ')}, /* Kuy */ {"kdt", HB_TAG('K','U','Y',' ')}, /* Kuy */
{"kex", HB_TAG('K','K','N',' ')}, /* Kokni */ {"kex", HB_TAG('K','K','N',' ')}, /* Kokni */
{"kfr", HB_TAG('K','A','C',' ')}, /* Kachchi */ {"kfr", HB_TAG('K','A','C',' ')}, /* Kachchi */
{"kfy", HB_TAG('K','M','N',' ')}, /* Kumaoni */ {"kfy", HB_TAG('K','M','N',' ')}, /* Kumaoni */
{"kg", HB_TAG('K','O','N',' ')}, /* Kongo [macrolanguage] */
{"kha", HB_TAG('K','S','I',' ')}, /* Khasi */ {"kha", HB_TAG('K','S','I',' ')}, /* Khasi */
{"khb", HB_TAG('X','B','D',' ')}, /* Tai Lue */ {"khb", HB_TAG('X','B','D',' ')}, /* Lü */
{"kht", HB_TAG('K','H','N',' ')}, /* Khamti (Microsoft fonts) */
/*{"kht", HB_TAG('K','H','T',' ')},*/ /* Khamti (OpenType spec and SIL fonts) */
{"khw", HB_TAG('K','H','W',' ')}, /* Khowar */ {"khw", HB_TAG('K','H','W',' ')}, /* Khowar */
{"ki", HB_TAG('K','I','K',' ')}, /* Kikuyu */ {"ki", HB_TAG('K','I','K',' ')}, /* Gikuyu/Kikuyu */
{"kj", HB_TAG('K','U','A',' ')}, /* Kuanyama/Kwanyama */
{"kjh", HB_TAG('K','H','A',' ')}, /* Khakass */ {"kjh", HB_TAG('K','H','A',' ')}, /* Khakass */
{"kjp", HB_TAG('K','J','P',' ')}, /* Pwo Eastern Karen */
{"kk", HB_TAG('K','A','Z',' ')}, /* Kazakh */ {"kk", HB_TAG('K','A','Z',' ')}, /* Kazakh */
{"kl", HB_TAG('G','R','N',' ')}, /* Kalaallisut */ {"kl", HB_TAG('G','R','N',' ')}, /* Kalaallisut */
{"kln", HB_TAG('K','A','L',' ')}, /* Kalenjin */ {"kln", HB_TAG('K','A','L',' ')}, /* Kalenjin */
{"km", HB_TAG('K','H','M',' ')}, /* Central Khmer */ {"km", HB_TAG('K','H','M',' ')}, /* Central Khmer */
{"kmb", HB_TAG('M','B','N',' ')}, /* [North] Mbundu */ {"kmb", HB_TAG('M','B','N',' ')}, /* Kimbundu */
{"kmw", HB_TAG('K','M','O',' ')}, /* Komo (Democratic Republic of Congo) */ {"kmw", HB_TAG('K','M','O',' ')}, /* Komo (Democratic Republic of Congo) */
{"kn", HB_TAG('K','A','N',' ')}, /* Kannada */ {"kn", HB_TAG('K','A','N',' ')}, /* Kannada */
{"knn", HB_TAG('K','O','K',' ')}, /* Konkani */
{"ko", HB_TAG('K','O','R',' ')}, /* Korean */ {"ko", HB_TAG('K','O','R',' ')}, /* Korean */
{"koi", HB_TAG('K','O','P',' ')}, /* Komi-Permyak */ {"koi", HB_TAG('K','O','P',' ')}, /* Komi-Permyak */
{"kok", HB_TAG('K','O','K',' ')}, /* Konkani */ {"kok", HB_TAG('K','O','K',' ')}, /* Konkani [macrolanguage] */
{"kpe", HB_TAG('K','P','L',' ')}, /* Kpelle */ {"kpe", HB_TAG('K','P','L',' ')}, /* Kpelle [macrolanguage] */
{"kpv", HB_TAG('K','O','Z',' ')}, /* Komi-Zyrian */ {"kpv", HB_TAG('K','O','Z',' ')}, /* Komi-Zyrian */
{"kpy", HB_TAG('K','Y','K',' ')}, /* Koryak */ {"kpy", HB_TAG('K','Y','K',' ')}, /* Koryak */
{"kqy", HB_TAG('K','R','T',' ')}, /* Koorete */ {"kqy", HB_TAG('K','R','T',' ')}, /* Koorete */
{"kr", HB_TAG('K','N','R',' ')}, /* Kanuri */ {"kr", HB_TAG('K','N','R',' ')}, /* Kanuri [macrolanguage] */
{"kri", HB_TAG('K','R','I',' ')}, /* Krio */ {"kri", HB_TAG('K','R','I',' ')}, /* Krio */
{"krl", HB_TAG('K','R','L',' ')}, /* Karelian */ {"krl", HB_TAG('K','R','L',' ')}, /* Karelian */
{"kru", HB_TAG('K','U','U',' ')}, /* Kurukh */ {"kru", HB_TAG('K','U','U',' ')}, /* Kurukh */
{"ks", HB_TAG('K','S','H',' ')}, /* Kashmiri */ {"ks", HB_TAG('K','S','H',' ')}, /* Kashmiri */
{"ku", HB_TAG('K','U','R',' ')}, /* Kurdish */ {"ksh", HB_TAG('K','S','H',' ')}, /* Kölsch */
/*{"ksw", HB_TAG('K','R','N',' ')},*/ /* S'gaw Karen (Microsoft fonts?) */
{"ksw", HB_TAG('K','S','W',' ')}, /* S'gaw Karen (OpenType spec and SIL fonts) */
{"ku", HB_TAG('K','U','R',' ')}, /* Kurdish [macrolanguage] */
{"kum", HB_TAG('K','U','M',' ')}, /* Kumyk */ {"kum", HB_TAG('K','U','M',' ')}, /* Kumyk */
{"kv", HB_TAG('K','O','M',' ')}, /* Komi [macrolanguage] */
{"kvd", HB_TAG('K','U','I',' ')}, /* Kui (Indonesia) */ {"kvd", HB_TAG('K','U','I',' ')}, /* Kui (Indonesia) */
{"kw", HB_TAG('C','O','R',' ')}, /* Cornish */
{"kxc", HB_TAG('K','M','S',' ')}, /* Komso */ {"kxc", HB_TAG('K','M','S',' ')}, /* Komso */
{"kxu", HB_TAG('K','U','I',' ')}, /* Kui (India) */ {"kxu", HB_TAG('K','U','I',' ')}, /* Kui (India) */
{"ky", HB_TAG('K','I','R',' ')}, /* Kirghiz */ {"ky", HB_TAG('K','I','R',' ')}, /* Kirghiz/Kyrgyz */
{"kyu", HB_TAG('K','Y','U',' ')}, /* Western Kayah */
{"la", HB_TAG('L','A','T',' ')}, /* Latin */ {"la", HB_TAG('L','A','T',' ')}, /* Latin */
{"lad", HB_TAG('J','U','D',' ')}, /* Ladino */ {"lad", HB_TAG('J','U','D',' ')}, /* Ladino */
{"lb", HB_TAG('L','T','Z',' ')}, /* Luxembourgish */ {"lb", HB_TAG('L','T','Z',' ')}, /* Luxembourgish */
{"lbe", HB_TAG('L','A','K',' ')}, /* Lak */ {"lbe", HB_TAG('L','A','K',' ')}, /* Lak */
{"lbj", HB_TAG('L','D','K',' ')}, /* Ladakhi */ {"lbj", HB_TAG('L','D','K',' ')}, /* Ladakhi */
{"lez", HB_TAG('L','E','Z',' ')}, /* Lezgi */ {"lez", HB_TAG('L','E','Z',' ')}, /* Lezgi */
{"lg", HB_TAG('L','U','G',' ')}, /* Luganda */ {"lg", HB_TAG('L','U','G',' ')}, /* Ganda */
{"li", HB_TAG('L','I','M',' ')}, /* Limburgan/Limburger/Limburgish */
{"lif", HB_TAG('L','M','B',' ')}, /* Limbu */ {"lif", HB_TAG('L','M','B',' ')}, /* Limbu */
{"lij", HB_TAG('L','I','J',' ')}, /* Ligurian */
{"lis", HB_TAG('L','I','S',' ')}, /* Lisu */
{"ljp", HB_TAG('L','J','P',' ')}, /* Lampung Api */
{"lki", HB_TAG('L','K','I',' ')}, /* Laki */
{"lld", HB_TAG('L','A','D',' ')}, /* Ladin */ {"lld", HB_TAG('L','A','D',' ')}, /* Ladin */
{"lmn", HB_TAG('L','A','M',' ')}, /* Lambani */ {"lmn", HB_TAG('L','A','M',' ')}, /* Lambani */
{"lmo", HB_TAG('L','M','O',' ')}, /* Lombard */
{"ln", HB_TAG('L','I','N',' ')}, /* Lingala */ {"ln", HB_TAG('L','I','N',' ')}, /* Lingala */
{"lo", HB_TAG('L','A','O',' ')}, /* Lao */ {"lo", HB_TAG('L','A','O',' ')}, /* Lao */
{"lrc", HB_TAG('L','R','C',' ')}, /* Northern Luri */
{"lt", HB_TAG('L','T','H',' ')}, /* Lithuanian */ {"lt", HB_TAG('L','T','H',' ')}, /* Lithuanian */
{"lu", HB_TAG('L','U','B',' ')}, /* Luba-Katanga */ {"lu", HB_TAG('L','U','B',' ')}, /* Luba-Katanga */
{"lua", HB_TAG('L','U','B',' ')}, /* Luba-Kasai */ {"lua", HB_TAG('L','U','B',' ')}, /* Luba-Kasai */
{"luo", HB_TAG('L','U','O',' ')}, /* Luo (Kenya and Tanzania) */ {"luo", HB_TAG('L','U','O',' ')}, /* Luo (Kenya and Tanzania) */
{"lus", HB_TAG('M','I','Z',' ')}, /* Mizo */ {"lus", HB_TAG('M','I','Z',' ')}, /* Mizo */
{"luy", HB_TAG('L','U','H',' ')}, /* Luhya [macrolanguage] */ {"luy", HB_TAG('L','U','H',' ')}, /* Luyia/Oluluyia [macrolanguage] */
{"luz", HB_TAG('L','R','C',' ')}, /* Southern Luri */
{"lv", HB_TAG('L','V','I',' ')}, /* Latvian */ {"lv", HB_TAG('L','V','I',' ')}, /* Latvian */
{"lzz", HB_TAG('L','A','Z',' ')}, /* Laz */ {"lzz", HB_TAG('L','A','Z',' ')}, /* Laz */
{"mad", HB_TAG('M','A','D',' ')}, /* Madurese */
{"mag", HB_TAG('M','A','G',' ')}, /* Magahi */
{"mai", HB_TAG('M','T','H',' ')}, /* Maithili */ {"mai", HB_TAG('M','T','H',' ')}, /* Maithili */
{"mak", HB_TAG('M','K','R',' ')}, /* Makasar */
{"man", HB_TAG('M','N','K',' ')}, /* Manding/Mandingo [macrolanguage] */
{"mdc", HB_TAG('M','L','E',' ')}, /* Male (Papua New Guinea) */ {"mdc", HB_TAG('M','L','E',' ')}, /* Male (Papua New Guinea) */
{"mdf", HB_TAG('M','O','K',' ')}, /* Moksha */ {"mdf", HB_TAG('M','O','K',' ')}, /* Moksha */
{"mdr", HB_TAG('M','D','R',' ')}, /* Mandar */
{"mdy", HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */ {"mdy", HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */
{"men", HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */ {"men", HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */
{"mg", HB_TAG('M','L','G',' ')}, /* Malagasy */ {"mer", HB_TAG('M','E','R',' ')}, /* Meru */
{"mfe", HB_TAG('M','F','E',' ')}, /* Morisyen */
{"mg", HB_TAG('M','L','G',' ')}, /* Malagasy [macrolanguage] */
{"mh", HB_TAG('M','A','H',' ')}, /* Marshallese */
{"mhr", HB_TAG('L','M','A',' ')}, /* Low Mari */ {"mhr", HB_TAG('L','M','A',' ')}, /* Low Mari */
{"mi", HB_TAG('M','R','I',' ')}, /* Maori */ {"mi", HB_TAG('M','R','I',' ')}, /* Maori */
{"min", HB_TAG('M','I','N',' ')}, /* Minangkabau */
{"mk", HB_TAG('M','K','D',' ')}, /* Macedonian */ {"mk", HB_TAG('M','K','D',' ')}, /* Macedonian */
{"mku", HB_TAG('M','N','K',' ')}, /* Konyanka Maninka */
{"mkw", HB_TAG('M','K','W',' ')}, /* Kituba (Congo) */
{"ml", HB_TAG('M','L','R',' ')}, /* Malayalam */ {"ml", HB_TAG('M','L','R',' ')}, /* Malayalam */
{"mn", HB_TAG('M','N','G',' ')}, /* Mongolian */ {"mlq", HB_TAG('M','N','K',' ')}, /* Western Maninkakan */
{"mn", HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */
{"mnc", HB_TAG('M','C','H',' ')}, /* Manchu */ {"mnc", HB_TAG('M','C','H',' ')}, /* Manchu */
{"mni", HB_TAG('M','N','I',' ')}, /* Manipuri */ {"mni", HB_TAG('M','N','I',' ')}, /* Manipuri */
{"mnk", HB_TAG('M','N','D',' ')}, /* Mandinka */ {"mnk", HB_TAG('M','N','D',' ')}, /* Mandinka */
@ -396,72 +496,119 @@ static const LangTag ot_languages[] = {
{"mnw", HB_TAG('M','O','N',' ')}, /* Mon */ {"mnw", HB_TAG('M','O','N',' ')}, /* Mon */
{"mo", HB_TAG('M','O','L',' ')}, /* Moldavian */ {"mo", HB_TAG('M','O','L',' ')}, /* Moldavian */
{"moh", HB_TAG('M','O','H',' ')}, /* Mohawk */ {"moh", HB_TAG('M','O','H',' ')}, /* Mohawk */
{"mos", HB_TAG('M','O','S',' ')}, /* Mossi */
{"mpe", HB_TAG('M','A','J',' ')}, /* Majang */ {"mpe", HB_TAG('M','A','J',' ')}, /* Majang */
{"mr", HB_TAG('M','A','R',' ')}, /* Marathi */ {"mr", HB_TAG('M','A','R',' ')}, /* Marathi */
{"mrj", HB_TAG('H','M','A',' ')}, /* High Mari */ {"mrj", HB_TAG('H','M','A',' ')}, /* High Mari */
{"ms", HB_TAG('M','L','Y',' ')}, /* Malay */ {"ms", HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */
{"msc", HB_TAG('M','N','K',' ')}, /* Sankaran Maninka */
{"mt", HB_TAG('M','T','S',' ')}, /* Maltese */ {"mt", HB_TAG('M','T','S',' ')}, /* Maltese */
{"mwr", HB_TAG('M','A','W',' ')}, /* Marwari */ {"mtr", HB_TAG('M','A','W',' ')}, /* Mewari */
{"mus", HB_TAG('M','U','S',' ')}, /* Creek */
{"mve", HB_TAG('M','A','W',' ')}, /* Marwari (Pakistan) */
{"mwk", HB_TAG('M','N','K',' ')}, /* Kita Maninkakan */
{"mwl", HB_TAG('M','W','L',' ')}, /* Mirandese */
{"mwr", HB_TAG('M','A','W',' ')}, /* Marwari [macrolanguage] */
{"mww", HB_TAG('M','W','W',' ')}, /* Hmong Daw */
{"my", HB_TAG('B','R','M',' ')}, /* Burmese */ {"my", HB_TAG('B','R','M',' ')}, /* Burmese */
{"mym", HB_TAG('M','E','N',' ')}, /* Me'en */ {"mym", HB_TAG('M','E','N',' ')}, /* Me'en */
{"myq", HB_TAG('M','N','K',' ')}, /* Forest Maninka (retired code) */
{"myv", HB_TAG('E','R','Z',' ')}, /* Erzya */ {"myv", HB_TAG('E','R','Z',' ')}, /* Erzya */
{"mzn", HB_TAG('M','Z','N',' ')}, /* Mazanderani */
{"na", HB_TAG('N','A','U',' ')}, /* Nauru */
{"nag", HB_TAG('N','A','G',' ')}, /* Naga-Assamese */ {"nag", HB_TAG('N','A','G',' ')}, /* Naga-Assamese */
{"nah", HB_TAG('N','A','H',' ')}, /* Nahuatl [family] */
{"nap", HB_TAG('N','A','P',' ')}, /* Neapolitan */
{"nb", HB_TAG('N','O','R',' ')}, /* Norwegian Bokmål */ {"nb", HB_TAG('N','O','R',' ')}, /* Norwegian Bokmål */
{"nco", HB_TAG('S','I','B',' ')}, /* Sibe */ {"nco", HB_TAG('S','I','B',' ')}, /* Sibe */
{"nd", HB_TAG('N','D','B',' ')}, /* [North] Ndebele */ {"nd", HB_TAG('N','D','B',' ')}, /* [North] Ndebele */
{"ndc", HB_TAG('N','D','C',' ')}, /* Ndau */
{"nds", HB_TAG('N','D','S',' ')}, /* Low German/Low Saxon */
{"ne", HB_TAG('N','E','P',' ')}, /* Nepali */ {"ne", HB_TAG('N','E','P',' ')}, /* Nepali */
{"new", HB_TAG('N','E','W',' ')}, /* Newari */ {"new", HB_TAG('N','E','W',' ')}, /* Newari */
{"ng", HB_TAG('N','D','G',' ')}, /* Ndonga */ {"ng", HB_TAG('N','D','G',' ')}, /* Ndonga */
{"nga", HB_TAG('N','G','A',' ')}, /* Ngabaka */
{"ngl", HB_TAG('L','M','W',' ')}, /* Lomwe */ {"ngl", HB_TAG('L','M','W',' ')}, /* Lomwe */
{"niu", HB_TAG('N','I','U',' ')}, /* Niuean */ {"niu", HB_TAG('N','I','U',' ')}, /* Niuean */
{"niv", HB_TAG('G','I','L',' ')}, /* Gilyak */ {"niv", HB_TAG('G','I','L',' ')}, /* Gilyak */
{"nl", HB_TAG('N','L','D',' ')}, /* Dutch */ {"nl", HB_TAG('N','L','D',' ')}, /* Dutch */
{"nn", HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk */ {"nn", HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk */
{"no", HB_TAG('N','O','R',' ')}, /* Norwegian (deprecated) */ {"no", HB_TAG('N','O','R',' ')}, /* Norwegian [macrolanguage] */
{"nod", HB_TAG('N','T','A',' ')}, /* Northern Tai */ {"nod", HB_TAG('N','T','A',' ')}, /* Northern Thai */
{"noe", HB_TAG('N','O','E',' ')}, /* Nimadi */
{"nog", HB_TAG('N','O','G',' ')}, /* Nogai */ {"nog", HB_TAG('N','O','G',' ')}, /* Nogai */
{"nov", HB_TAG('N','O','V',' ')}, /* Novial */
{"nqo", HB_TAG('N','K','O',' ')}, /* N'Ko */ {"nqo", HB_TAG('N','K','O',' ')}, /* N'Ko */
{"nr", HB_TAG('N','D','B',' ')}, /* [South] Ndebele */ {"nr", HB_TAG('N','D','B',' ')}, /* [South] Ndebele */
{"nsk", HB_TAG('N','A','S',' ')}, /* Naskapi */ {"nsk", HB_TAG('N','A','S',' ')}, /* Naskapi */
{"nso", HB_TAG('S','O','T',' ')}, /* [Northern] Sotho */ {"nso", HB_TAG('S','O','T',' ')}, /* [Northern] Sotho */
{"ny", HB_TAG('C','H','I',' ')}, /* Nyanja */ {"ny", HB_TAG('C','H','I',' ')}, /* Chewa/Chichwa/Nyanja */
{"nyn", HB_TAG('N','K','L',' ')}, /* Nkole */ {"nym", HB_TAG('N','Y','M',' ')}, /* Nyamwezi */
{"nyn", HB_TAG('N','K','L',' ')}, /* Nyankole */
{"oc", HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */ {"oc", HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */
{"oj", HB_TAG('O','J','B',' ')}, /* Ojibwa */ {"oj", HB_TAG('O','J','B',' ')}, /* Ojibwa [macrolanguage] */
{"ojs", HB_TAG('O','C','R',' ')}, /* Oji-Cree */ {"ojs", HB_TAG('O','C','R',' ')}, /* Oji-Cree */
{"om", HB_TAG('O','R','O',' ')}, /* Oromo */ {"om", HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */
{"or", HB_TAG('O','R','I',' ')}, /* Oriya */ {"or", HB_TAG('O','R','I',' ')}, /* Oriya */
{"os", HB_TAG('O','S','S',' ')}, /* Ossetian */ {"os", HB_TAG('O','S','S',' ')}, /* Ossetian */
{"pa", HB_TAG('P','A','N',' ')}, /* Panjabi */ {"pa", HB_TAG('P','A','N',' ')}, /* Panjabi */
{"pag", HB_TAG('P','A','G',' ')}, /* Pangasinan */
{"pam", HB_TAG('P','A','M',' ')}, /* Kapampangan/Pampanga */
{"pap", HB_TAG('P','A','P',' ')}, /* Papiamento */
{"pcc", HB_TAG('P','C','C',' ')}, /* Bouyei */
{"pcd", HB_TAG('P','C','D',' ')}, /* Picard */
{"pce", HB_TAG('P','L','G',' ')}, /* [Ruching] Palaung */ {"pce", HB_TAG('P','L','G',' ')}, /* [Ruching] Palaung */
{"pdc", HB_TAG('P','D','C',' ')}, /* Pennsylvania German */
{"pes", HB_TAG('F','A','R',' ')}, /* Iranian Persian */
{"phk", HB_TAG('P','H','K',' ')}, /* Phake */
{"pi", HB_TAG('P','A','L',' ')}, /* Pali */ {"pi", HB_TAG('P','A','L',' ')}, /* Pali */
{"pih", HB_TAG('P','I','H',' ')}, /* Pitcairn-Norfolk */
{"pl", HB_TAG('P','L','K',' ')}, /* Polish */ {"pl", HB_TAG('P','L','K',' ')}, /* Polish */
{"pll", HB_TAG('P','L','G',' ')}, /* [Shwe] Palaung */ {"pll", HB_TAG('P','L','G',' ')}, /* [Shwe] Palaung */
{"plp", HB_TAG('P','A','P',' ')}, /* Palpa */ {"plp", HB_TAG('P','A','P',' ')}, /* Palpa */
{"prs", HB_TAG('D','R','I',' ')}, /* Dari */ {"pms", HB_TAG('P','M','S',' ')}, /* Piemontese */
{"ps", HB_TAG('P','A','S',' ')}, /* Pushto */ {"pnb", HB_TAG('P','N','B',' ')}, /* Western Panjabi */
{"prs", HB_TAG('D','R','I',' ')}, /* Afghan Persian/Dari */
{"ps", HB_TAG('P','A','S',' ')}, /* Pashto/Pushto [macrolanguage] */
{"pt", HB_TAG('P','T','G',' ')}, /* Portuguese */ {"pt", HB_TAG('P','T','G',' ')}, /* Portuguese */
{"raj", HB_TAG('R','A','J',' ')}, /* Rajasthani */ {"pwo", HB_TAG('P','W','O',' ')}, /* Pwo Western Karen */
{"rbb", HB_TAG('P','L','G',' ')}, /* [Rumai] Palaung */ {"qu", HB_TAG('Q','U','Z',' ')}, /* Quechua [macrolanguage] */
{"quc", HB_TAG('Q','U','C',' ')}, /* K'iche'/Quiché */
{"quz", HB_TAG('Q','U','Z',' ')}, /* Cusco Quechua */
{"raj", HB_TAG('R','A','J',' ')}, /* Rajasthani [macrolanguage] */
{"rbb", HB_TAG('P','L','G',' ')}, /* Rumai Palaung */
{"rej", HB_TAG('R','E','J',' ')}, /* Rejang */
{"ria", HB_TAG('R','I','A',' ')}, /* Riang (India) */ {"ria", HB_TAG('R','I','A',' ')}, /* Riang (India) */
{"ril", HB_TAG('R','I','A',' ')}, /* Riang (Myanmar) */ {"ril", HB_TAG('R','I','A',' ')}, /* Riang (Myanmar) */
{"rki", HB_TAG('A','R','K',' ')}, /* Arakanese */ {"rki", HB_TAG('A','R','K',' ')}, /* Rakhine */
{"rm", HB_TAG('R','M','S',' ')}, /* Rhaeto-Romanic */ {"rm", HB_TAG('R','M','S',' ')}, /* Romansh */
{"rmy", HB_TAG('R','M','Y',' ')}, /* Vlax Romani */
{"rn", HB_TAG('R','U','N',' ')}, /* Rundi */
{"ro", HB_TAG('R','O','M',' ')}, /* Romanian */ {"ro", HB_TAG('R','O','M',' ')}, /* Romanian */
{"rom", HB_TAG('R','O','Y',' ')}, /* Romany */ {"rom", HB_TAG('R','O','Y',' ')}, /* Romany [macrolanguage] */
{"ru", HB_TAG('R','U','S',' ')}, /* Russian */ {"ru", HB_TAG('R','U','S',' ')}, /* Russian */
{"rue", HB_TAG('R','S','Y',' ')}, /* Rusyn */ {"rue", HB_TAG('R','S','Y',' ')}, /* Rusyn */
{"rw", HB_TAG('R','U','A',' ')}, /* Ruanda */ {"rup", HB_TAG('R','U','P',' ')}, /* Aromanian/Arumanian/Macedo-Romanian */
{"rw", HB_TAG('R','U','A',' ')}, /* Kinyarwanda */
{"rwr", HB_TAG('M','A','W',' ')}, /* Marwari (India) */
{"sa", HB_TAG('S','A','N',' ')}, /* Sanskrit */ {"sa", HB_TAG('S','A','N',' ')}, /* Sanskrit */
{"sah", HB_TAG('Y','A','K',' ')}, /* Yakut */ {"sah", HB_TAG('Y','A','K',' ')}, /* Yakut */
{"sas", HB_TAG('S','A','S',' ')}, /* Sasak */
{"sat", HB_TAG('S','A','T',' ')}, /* Santali */ {"sat", HB_TAG('S','A','T',' ')}, /* Santali */
{"sck", HB_TAG('S','A','D',' ')}, /* Sadri */ {"sck", HB_TAG('S','A','D',' ')}, /* Sadri */
{"sc", HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */
{"scn", HB_TAG('S','C','N',' ')}, /* Sicilian */
{"sco", HB_TAG('S','C','O',' ')}, /* Scots */
{"scs", HB_TAG('S','L','A',' ')}, /* [North] Slavey */ {"scs", HB_TAG('S','L','A',' ')}, /* [North] Slavey */
{"sd", HB_TAG('S','N','D',' ')}, /* Sindhi */ {"sd", HB_TAG('S','N','D',' ')}, /* Sindhi */
{"se", HB_TAG('N','S','M',' ')}, /* Northern Sami */ {"se", HB_TAG('N','S','M',' ')}, /* Northern Sami */
{"seh", HB_TAG('S','N','A',' ')}, /* Sena */ {"seh", HB_TAG('S','N','A',' ')}, /* Sena */
{"sel", HB_TAG('S','E','L',' ')}, /* Selkup */ {"sel", HB_TAG('S','E','L',' ')}, /* Selkup */
{"sg", HB_TAG('S','G','O',' ')}, /* Sango */ {"sg", HB_TAG('S','G','O',' ')}, /* Sango */
{"sga", HB_TAG('S','G','A',' ')}, /* Old Irish (to 900) */
{"sgs", HB_TAG('S','G','S',' ')}, /* Samogitian */
{"sgw", HB_TAG('C','H','G',' ')}, /* Sebat Bet Gurage */
/*{"sgw", HB_TAG('S','G','W',' ')},*/ /* Sebat Bet Gurage (in SIL fonts) */
{"shn", HB_TAG('S','H','N',' ')}, /* Shan */ {"shn", HB_TAG('S','H','N',' ')}, /* Shan */
{"si", HB_TAG('S','N','H',' ')}, /* Sinhala */ {"si", HB_TAG('S','N','H',' ')}, /* Sinhala */
{"sid", HB_TAG('S','I','D',' ')}, /* Sidamo */ {"sid", HB_TAG('S','I','D',' ')}, /* Sidamo */
@ -474,60 +621,98 @@ static const LangTag ot_languages[] = {
{"smj", HB_TAG('L','S','M',' ')}, /* Lule Sami */ {"smj", HB_TAG('L','S','M',' ')}, /* Lule Sami */
{"smn", HB_TAG('I','S','M',' ')}, /* Inari Sami */ {"smn", HB_TAG('I','S','M',' ')}, /* Inari Sami */
{"sms", HB_TAG('S','K','S',' ')}, /* Skolt Sami */ {"sms", HB_TAG('S','K','S',' ')}, /* Skolt Sami */
{"sn", HB_TAG('S','N','A',' ')}, /* Shona */
{"snk", HB_TAG('S','N','K',' ')}, /* Soninke */ {"snk", HB_TAG('S','N','K',' ')}, /* Soninke */
{"so", HB_TAG('S','M','L',' ')}, /* Somali */ {"so", HB_TAG('S','M','L',' ')}, /* Somali */
{"sq", HB_TAG('S','Q','I',' ')}, /* Albanian */ {"sop", HB_TAG('S','O','P',' ')}, /* Songe */
{"sq", HB_TAG('S','Q','I',' ')}, /* Albanian [macrolanguage] */
{"sr", HB_TAG('S','R','B',' ')}, /* Serbian */ {"sr", HB_TAG('S','R','B',' ')}, /* Serbian */
{"srr", HB_TAG('S','R','R',' ')}, /* Serer */ {"srr", HB_TAG('S','R','R',' ')}, /* Serer */
{"ss", HB_TAG('S','W','Z',' ')}, /* Swazi */ {"ss", HB_TAG('S','W','Z',' ')}, /* Swati */
{"st", HB_TAG('S','O','T',' ')}, /* [Southern] Sotho */ {"st", HB_TAG('S','O','T',' ')}, /* [Southern] Sotho */
{"stq", HB_TAG('S','T','Q',' ')}, /* Saterfriesisch */
{"stv", HB_TAG('S','I','G',' ')}, /* Silt'e */
{"su", HB_TAG('S','U','N',' ')}, /* Sundanese */
{"suk", HB_TAG('S','U','K',' ')}, /* Sukama */
{"suq", HB_TAG('S','U','R',' ')}, /* Suri */ {"suq", HB_TAG('S','U','R',' ')}, /* Suri */
{"sv", HB_TAG('S','V','E',' ')}, /* Swedish */ {"sv", HB_TAG('S','V','E',' ')}, /* Swedish */
{"sva", HB_TAG('S','V','A',' ')}, /* Svan */ {"sva", HB_TAG('S','V','A',' ')}, /* Svan */
{"sw", HB_TAG('S','W','K',' ')}, /* Swahili */ {"sw", HB_TAG('S','W','K',' ')}, /* Swahili [macrolanguage] */
{"swb", HB_TAG('C','M','R',' ')}, /* Comorian */ {"swb", HB_TAG('C','M','R',' ')}, /* Comorian */
{"syr", HB_TAG('S','Y','R',' ')}, /* Syriac */ {"swh", HB_TAG('S','W','K',' ')}, /* Kiswahili/Swahili */
{"swv", HB_TAG('M','A','W',' ')}, /* Shekhawati */
{"sxu", HB_TAG('S','X','U',' ')}, /* Upper Saxon */
{"syl", HB_TAG('S','Y','L',' ')}, /* Sylheti */
{"syr", HB_TAG('S','Y','R',' ')}, /* Syriac [macrolanguage] */
{"szl", HB_TAG('S','Z','L',' ')}, /* Silesian */
{"ta", HB_TAG('T','A','M',' ')}, /* Tamil */ {"ta", HB_TAG('T','A','M',' ')}, /* Tamil */
{"tab", HB_TAG('T','A','B',' ')}, /* Tabasaran */ {"tab", HB_TAG('T','A','B',' ')}, /* Tabasaran */
{"tcy", HB_TAG('T','U','L',' ')}, /* Tulu */ {"tcy", HB_TAG('T','U','L',' ')}, /* Tulu */
{"tdd", HB_TAG('T','D','D',' ')}, /* Tai Nüa */
{"te", HB_TAG('T','E','L',' ')}, /* Telugu */ {"te", HB_TAG('T','E','L',' ')}, /* Telugu */
{"tem", HB_TAG('T','M','N',' ')}, /* Temne */ {"tem", HB_TAG('T','M','N',' ')}, /* Temne */
{"tet", HB_TAG('T','E','T',' ')}, /* Tetum */
{"tg", HB_TAG('T','A','J',' ')}, /* Tajik */ {"tg", HB_TAG('T','A','J',' ')}, /* Tajik */
{"th", HB_TAG('T','H','A',' ')}, /* Thai */ {"th", HB_TAG('T','H','A',' ')}, /* Thai */
{"ti", HB_TAG('T','G','Y',' ')}, /* Tigrinya */ {"ti", HB_TAG('T','G','Y',' ')}, /* Tigrinya */
{"tig", HB_TAG('T','G','R',' ')}, /* Tigre */ {"tig", HB_TAG('T','G','R',' ')}, /* Tigre */
{"tiv", HB_TAG('T','I','V',' ')}, /* Tiv */
{"tk", HB_TAG('T','K','M',' ')}, /* Turkmen */ {"tk", HB_TAG('T','K','M',' ')}, /* Turkmen */
{"tl", HB_TAG('T','G','L',' ')}, /* Tagalog */
{"tmh", HB_TAG('t','m','h',' ')}, /* Tamashek [macrolanguage] */
{"tn", HB_TAG('T','N','A',' ')}, /* Tswana */ {"tn", HB_TAG('T','N','A',' ')}, /* Tswana */
{"to", HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) */ {"to", HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) */
{"tpi", HB_TAG('T','P','I',' ')}, /* Tok Pisin */
{"tr", HB_TAG('T','R','K',' ')}, /* Turkish */ {"tr", HB_TAG('T','R','K',' ')}, /* Turkish */
{"tru", HB_TAG('T','U','A',' ')}, /* Turoyo Aramaic */ {"tru", HB_TAG('T','U','A',' ')}, /* Turoyo Aramaic */
{"ts", HB_TAG('T','S','G',' ')}, /* Tsonga */ {"ts", HB_TAG('T','S','G',' ')}, /* Tsonga */
{"tt", HB_TAG('T','A','T',' ')}, /* Tatar */ {"tt", HB_TAG('T','A','T',' ')}, /* Tatar */
{"tum", HB_TAG('T','U','M',' ')}, /* Tumbuka */
{"tw", HB_TAG('T','W','I',' ')}, /* Twi */ {"tw", HB_TAG('T','W','I',' ')}, /* Twi */
{"ty", HB_TAG('T','H','T',' ')}, /* Tahitian */ {"ty", HB_TAG('T','H','T',' ')}, /* Tahitian */
{"tyv", HB_TAG('T','U','V',' ')}, /* Tuvin */ {"tyv", HB_TAG('T','U','V',' ')}, /* Tuvin */
{"tyz", HB_TAG('T','Y','Z',' ')}, /* Tày */
{"tzm", HB_TAG('T','Z','M',' ')}, /* Central Atlas Tamazight */
{"udm", HB_TAG('U','D','M',' ')}, /* Udmurt */ {"udm", HB_TAG('U','D','M',' ')}, /* Udmurt */
{"ug", HB_TAG('U','Y','G',' ')}, /* Uighur */ {"ug", HB_TAG('U','Y','G',' ')}, /* Uighur */
{"uk", HB_TAG('U','K','R',' ')}, /* Ukrainian */ {"uk", HB_TAG('U','K','R',' ')}, /* Ukrainian */
{"umb", HB_TAG('M','B','N',' ')}, /* [South] Mbundu */ {"umb", HB_TAG('U','M','B',' ')}, /* Umbundu */
{"unr", HB_TAG('M','U','N',' ')}, /* Mundari */ {"unr", HB_TAG('M','U','N',' ')}, /* Mundari */
{"ur", HB_TAG('U','R','D',' ')}, /* Urdu */ {"ur", HB_TAG('U','R','D',' ')}, /* Urdu */
{"uz", HB_TAG('U','Z','B',' ')}, /* Uzbek */ {"uz", HB_TAG('U','Z','B',' ')}, /* Uzbek [macrolanguage] */
{"uzn", HB_TAG('U','Z','B',' ')}, /* Northern Uzbek */
{"uzs", HB_TAG('U','Z','B',' ')}, /* Southern Uzbek */
{"ve", HB_TAG('V','E','N',' ')}, /* Venda */ {"ve", HB_TAG('V','E','N',' ')}, /* Venda */
{"vec", HB_TAG('V','E','C',' ')}, /* Venetian */
{"vls", HB_TAG('F','L','E',' ')}, /* Vlaams */
{"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */ {"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */
{"vmw", HB_TAG('M','A','K',' ')}, /* Makua */ {"vmw", HB_TAG('M','A','K',' ')}, /* Makhuwa */
{"vo", HB_TAG('V','O','L',' ')}, /* Volapük */
{"vro", HB_TAG('V','R','O',' ')}, /* Võro */
{"wa", HB_TAG('W','L','N',' ')}, /* Walloon */
{"war", HB_TAG('W','A','R',' ')}, /* Waray (Philippines) */
{"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */ {"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */
{"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */ {"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */
{"wle", HB_TAG('S','I','G',' ')}, /* Wolane */
{"wry", HB_TAG('M','A','W',' ')}, /* Merwari */
{"wtm", HB_TAG('W','T','M',' ')}, /* Mewati */
{"wo", HB_TAG('W','L','F',' ')}, /* Wolof */ {"wo", HB_TAG('W','L','F',' ')}, /* Wolof */
{"xal", HB_TAG('K','L','M',' ')}, /* Kalmyk */ {"xal", HB_TAG('K','L','M',' ')}, /* Kalmyk */
{"xh", HB_TAG('X','H','S',' ')}, /* Xhosa */ {"xh", HB_TAG('X','H','S',' ')}, /* Xhosa */
{"xog", HB_TAG('X','O','G',' ')}, /* Soga */
{"xom", HB_TAG('K','M','O',' ')}, /* Komo (Sudan) */ {"xom", HB_TAG('K','M','O',' ')}, /* Komo (Sudan) */
{"xsl", HB_TAG('S','S','L',' ')}, /* South Slavey */ {"xsl", HB_TAG('S','S','L',' ')}, /* South Slavey */
{"yi", HB_TAG('J','I','I',' ')}, /* Yiddish */ {"xst", HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) */
{"xwo", HB_TAG('T','O','D',' ')}, /* Written Oirat (Todo) */
{"yao", HB_TAG('Y','A','O',' ')}, /* Yao */
{"yi", HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */
{"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */ {"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */
{"yso", HB_TAG('N','I','S',' ')}, /* Nisi (China) */ {"yso", HB_TAG('N','I','S',' ')}, /* Nisi (China) */
{"za", HB_TAG('Z','H','A',' ')}, /* Chuang/Zhuang [macrolanguage] */
{"zea", HB_TAG('Z','E','A',' ')}, /* Zeeuws */
{"zne", HB_TAG('Z','N','D',' ')}, /* Zande */ {"zne", HB_TAG('Z','N','D',' ')}, /* Zande */
{"zu", HB_TAG('Z','U','L',' ')} /* Zulu */ {"zu", HB_TAG('Z','U','L',' ')}, /* Zulu */
{"zum", HB_TAG('L','R','C',' ')} /* Kumzari */
/* The corresponding languages IDs for the following IDs are unclear, /* The corresponding languages IDs for the following IDs are unclear,
* overlap, or are architecturally weird. Needs more research. */ * overlap, or are architecturally weird. Needs more research. */
@ -536,13 +721,13 @@ static const LangTag ot_languages[] = {
/*{"gsw?/gsw-FR?", HB_TAG('A','L','S',' ')},*/ /* Alsatian */ /*{"gsw?/gsw-FR?", HB_TAG('A','L','S',' ')},*/ /* Alsatian */
/*{"krc", HB_TAG('B','A','L',' ')},*/ /* Balkar */ /*{"krc", HB_TAG('B','A','L',' ')},*/ /* Balkar */
/*{"??", HB_TAG('B','C','R',' ')},*/ /* Bible Cree */ /*{"??", HB_TAG('B','C','R',' ')},*/ /* Bible Cree */
/*{"sgw?", HB_TAG('C','H','G',' ')},*/ /* Chaha Gurage */ /*{"zh?", HB_TAG('C','H','N',' ')},*/ /* Chinese (seen in Microsoft fonts) */
/*{"acf/gcf?", HB_TAG('F','A','N',' ')},*/ /* French Antillean */ /*{"acf/gcf?", HB_TAG('F','A','N',' ')},*/ /* French Antillean */
/*{"vls/nl-be", HB_TAG('F','L','E',' ')},*/ /* Flemish */
/*{"enf?/yrk?", HB_TAG('F','N','E',' ')},*/ /* Forest Nenets */ /*{"enf?/yrk?", HB_TAG('F','N','E',' ')},*/ /* Forest Nenets */
/*{"fuf?", HB_TAG('F','T','A',' ')},*/ /* Futa */ /*{"fuf?", HB_TAG('F','T','A',' ')},*/ /* Futa */
/*{"ar-Syrc?", HB_TAG('G','A','R',' ')},*/ /* Garshuni */ /*{"ar-Syrc?", HB_TAG('G','A','R',' ')},*/ /* Garshuni */
/*{"cfm/rnl?", HB_TAG('H','A','L',' ')},*/ /* Halam */ /*{"cfm/rnl?", HB_TAG('H','A','L',' ')},*/ /* Halam */
/*{"fonipa", HB_TAG('I','P','P','H')},*/ /* Phonetic transcription—IPA conventions */
/*{"ga-Latg?/Latg?", HB_TAG('I','R','T',' ')},*/ /* Irish Traditional */ /*{"ga-Latg?/Latg?", HB_TAG('I','R','T',' ')},*/ /* Irish Traditional */
/*{"krc", HB_TAG('K','A','R',' ')},*/ /* Karachay */ /*{"krc", HB_TAG('K','A','R',' ')},*/ /* Karachay */
/*{"alw?/ktb?", HB_TAG('K','E','B',' ')},*/ /* Kebena */ /*{"alw?/ktb?", HB_TAG('K','E','B',' ')},*/ /* Kebena */
@ -559,8 +744,6 @@ static const LangTag ot_languages[] = {
/*{"??", HB_TAG('L','C','R',' ')},*/ /* L-Cree */ /*{"??", HB_TAG('L','C','R',' ')},*/ /* L-Cree */
/*{"??", HB_TAG('M','A','L',' ')},*/ /* Malayalam Traditional */ /*{"??", HB_TAG('M','A','L',' ')},*/ /* Malayalam Traditional */
/*{"mnk?/mlq?/...", HB_TAG('M','L','N',' ')},*/ /* Malinke */ /*{"mnk?/mlq?/...", HB_TAG('M','L','N',' ')},*/ /* Malinke */
/*{"man?/myq?/mku?/msc?/...", HB_TAG('M','N','K',' ')},*/ /* Maninka */
/*{"??", HB_TAG('M','O','R',' ')},*/ /* Moroccan */
/*{"??", HB_TAG('N','C','R',' ')},*/ /* N-Cree */ /*{"??", HB_TAG('N','C','R',' ')},*/ /* N-Cree */
/*{"??", HB_TAG('N','H','C',' ')},*/ /* Norway House Cree */ /*{"??", HB_TAG('N','H','C',' ')},*/ /* Norway House Cree */
/*{"jpa?/sam?", HB_TAG('P','A','A',' ')},*/ /* Palestinian Aramaic */ /*{"jpa?/sam?", HB_TAG('P','A','A',' ')},*/ /* Palestinian Aramaic */
@ -569,14 +752,12 @@ static const LangTag ot_languages[] = {
/*{"??", HB_TAG('R','C','R',' ')},*/ /* R-Cree */ /*{"??", HB_TAG('R','C','R',' ')},*/ /* R-Cree */
/*{"chp?", HB_TAG('S','A','Y',' ')},*/ /* Sayisi */ /*{"chp?", HB_TAG('S','A','Y',' ')},*/ /* Sayisi */
/*{"xan?", HB_TAG('S','E','K',' ')},*/ /* Sekota */ /*{"xan?", HB_TAG('S','E','K',' ')},*/ /* Sekota */
/*{"stv/wle?/xst?", HB_TAG('S','I','G',' ')},*/ /* Silte Gurage */
/*{"ngo?", HB_TAG('S','X','T',' ')},*/ /* Sutu */ /*{"ngo?", HB_TAG('S','X','T',' ')},*/ /* Sutu */
/*{"??", HB_TAG('T','C','R',' ')},*/ /* TH-Cree */ /*{"??", HB_TAG('T','C','R',' ')},*/ /* TH-Cree */
/*{"tnz?/tog?/toi?", HB_TAG('T','N','G',' ')},*/ /* Tonga */ /*{"tnz?/tog?/toi?", HB_TAG('T','N','G',' ')},*/ /* Tonga */
/*{"enh?/yrk?", HB_TAG('T','N','E',' ')},*/ /* Tundra Nenets */ /*{"enh?/yrk?", HB_TAG('T','N','E',' ')},*/ /* Tundra Nenets */
/*{"??", HB_TAG('T','O','D',' ')},*/ /* Todo */
/*{"??", HB_TAG('W','C','R',' ')},*/ /* West-Cree */ /*{"??", HB_TAG('W','C','R',' ')},*/ /* West-Cree */
/*{"??", HB_TAG('Y','C','R',' ')},*/ /* Y-Cree */ /*{"cre?", HB_TAG('Y','C','R',' ')},*/ /* Y-Cree */
/*{"??", HB_TAG('Y','I','C',' ')},*/ /* Yi Classic */ /*{"??", HB_TAG('Y','I','C',' ')},*/ /* Yi Classic */
/*{"ii?/Yiii?", HB_TAG('Y','I','M',' ')},*/ /* Yi Modern */ /*{"ii?/Yiii?", HB_TAG('Y','I','M',' ')},*/ /* Yi Modern */
/*{"??", HB_TAG('Z','H','P',' ')},*/ /* Chinese Phonetic */ /*{"??", HB_TAG('Z','H','P',' ')},*/ /* Chinese Phonetic */

View File

@ -79,6 +79,9 @@ static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
template <typename Type> template <typename Type>
static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; } static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
{ return (a + (b - 1)) / b; }
#undef ARRAY_LENGTH #undef ARRAY_LENGTH
template <typename Type, unsigned int n> template <typename Type, unsigned int n>

View File

@ -28,7 +28,6 @@
#define HB_SET_PRIVATE_HH #define HB_SET_PRIVATE_HH
#include "hb-private.hh" #include "hb-private.hh"
#include "hb-set.h"
#include "hb-object-private.hh" #include "hb-object-private.hh"
@ -171,7 +170,7 @@ struct hb_set_t
inline void add (hb_codepoint_t g) inline void add (hb_codepoint_t g)
{ {
if (unlikely (in_error)) return; if (unlikely (in_error)) return;
if (unlikely (g == SENTINEL)) return; if (unlikely (g == INVALID)) return;
if (unlikely (g > MAX_G)) return; if (unlikely (g > MAX_G)) return;
elt (g) |= mask (g); elt (g) |= mask (g);
} }
@ -256,19 +255,22 @@ struct hb_set_t
} }
inline bool next (hb_codepoint_t *codepoint) const inline bool next (hb_codepoint_t *codepoint) const
{ {
if (unlikely (*codepoint == SENTINEL)) { if (unlikely (*codepoint == INVALID)) {
hb_codepoint_t i = get_min (); hb_codepoint_t i = get_min ();
if (i != SENTINEL) { if (i != INVALID) {
*codepoint = i; *codepoint = i;
return true; return true;
} else } else {
*codepoint = INVALID;
return false; return false;
}
} }
for (hb_codepoint_t i = *codepoint + 1; i < MAX_G + 1; i++) for (hb_codepoint_t i = *codepoint + 1; i < MAX_G + 1; i++)
if (has (i)) { if (has (i)) {
*codepoint = i; *codepoint = i;
return true; return true;
} }
*codepoint = INVALID;
return false; return false;
} }
inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
@ -277,7 +279,10 @@ struct hb_set_t
i = *last; i = *last;
if (!next (&i)) if (!next (&i))
{
*last = *first = INVALID;
return false; return false;
}
*last = *first = i; *last = *first = i;
while (next (&i) && i == *last + 1) while (next (&i) && i == *last + 1)
@ -300,7 +305,7 @@ struct hb_set_t
for (unsigned int j = 0; j < BITS; j++) for (unsigned int j = 0; j < BITS; j++)
if (elts[i] & (1 << j)) if (elts[i] & (1 << j))
return i * BITS + j; return i * BITS + j;
return SENTINEL; return INVALID;
} }
inline hb_codepoint_t get_max (void) const inline hb_codepoint_t get_max (void) const
{ {
@ -309,7 +314,7 @@ struct hb_set_t
for (unsigned int j = BITS; j; j--) for (unsigned int j = BITS; j; j--)
if (elts[i - 1] & (1 << (j - 1))) if (elts[i - 1] & (1 << (j - 1)))
return (i - 1) * BITS + (j - 1); return (i - 1) * BITS + (j - 1);
return SENTINEL; return INVALID;
} }
typedef uint32_t elt_t; typedef uint32_t elt_t;
@ -318,7 +323,7 @@ struct hb_set_t
static const unsigned int BITS = (1 << SHIFT); static const unsigned int BITS = (1 << SHIFT);
static const unsigned int MASK = BITS - 1; static const unsigned int MASK = BITS - 1;
static const unsigned int ELTS = (MAX_G + 1 + (BITS - 1)) / BITS; static const unsigned int ELTS = (MAX_G + 1 + (BITS - 1)) / BITS;
static const hb_codepoint_t SENTINEL = (hb_codepoint_t) -1; static const hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
elt_t &elt (hb_codepoint_t g) { return elts[g >> SHIFT]; } elt_t &elt (hb_codepoint_t g) { return elts[g >> SHIFT]; }
elt_t elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; } elt_t elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }

View File

@ -30,6 +30,13 @@
/* Public API */ /* Public API */
/**
* hb_set_create: (Xconstructor)
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_set_t * hb_set_t *
hb_set_create (void) hb_set_create (void)
{ {
@ -43,6 +50,13 @@ hb_set_create (void)
return set; return set;
} }
/**
* hb_set_get_empty:
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_set_t * hb_set_t *
hb_set_get_empty (void) hb_set_get_empty (void)
{ {
@ -56,12 +70,26 @@ hb_set_get_empty (void)
return const_cast<hb_set_t *> (&_hb_set_nil); return const_cast<hb_set_t *> (&_hb_set_nil);
} }
/**
* hb_set_reference: (skip)
* @set: a set.
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_set_t * hb_set_t *
hb_set_reference (hb_set_t *set) hb_set_reference (hb_set_t *set)
{ {
return hb_object_reference (set); return hb_object_reference (set);
} }
/**
* hb_set_destroy: (skip)
* @set: a set.
*
* Since: 1.0
**/
void void
hb_set_destroy (hb_set_t *set) hb_set_destroy (hb_set_t *set)
{ {
@ -72,6 +100,18 @@ hb_set_destroy (hb_set_t *set)
free (set); free (set);
} }
/**
* hb_set_set_user_data: (skip)
* @set: a set.
* @key:
* @data:
* @destroy (closure data):
* @replace:
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_set_set_user_data (hb_set_t *set, hb_set_set_user_data (hb_set_t *set,
hb_user_data_key_t *key, hb_user_data_key_t *key,
@ -82,6 +122,15 @@ hb_set_set_user_data (hb_set_t *set,
return hb_object_set_user_data (set, key, data, destroy, replace); return hb_object_set_user_data (set, key, data, destroy, replace);
} }
/**
* hb_set_get_user_data: (skip)
* @set: a set.
* @key:
*
* Return value: (transfer none):
*
* Since: 1.0
**/
void * void *
hb_set_get_user_data (hb_set_t *set, hb_set_get_user_data (hb_set_t *set,
hb_user_data_key_t *key) hb_user_data_key_t *key)
@ -90,24 +139,63 @@ hb_set_get_user_data (hb_set_t *set,
} }
/**
* hb_set_allocation_successful:
* @set: a set.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_set_allocation_successful (const hb_set_t *set HB_UNUSED) hb_set_allocation_successful (const hb_set_t *set HB_UNUSED)
{ {
return !set->in_error; return !set->in_error;
} }
/**
* hb_set_clear:
* @set: a set.
*
*
*
* Since: 1.0
**/
void void
hb_set_clear (hb_set_t *set) hb_set_clear (hb_set_t *set)
{ {
set->clear (); set->clear ();
} }
/**
* hb_set_is_empty:
* @set: a set.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_set_is_empty (const hb_set_t *set) hb_set_is_empty (const hb_set_t *set)
{ {
return set->is_empty (); return set->is_empty ();
} }
/**
* hb_set_has:
* @set: a set.
* @codepoint:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_set_has (const hb_set_t *set, hb_set_has (const hb_set_t *set,
hb_codepoint_t codepoint) hb_codepoint_t codepoint)
@ -115,6 +203,15 @@ hb_set_has (const hb_set_t *set,
return set->has (codepoint); return set->has (codepoint);
} }
/**
* hb_set_add:
* @set: a set.
* @codepoint:
*
*
*
* Since: 1.0
**/
void void
hb_set_add (hb_set_t *set, hb_set_add (hb_set_t *set,
hb_codepoint_t codepoint) hb_codepoint_t codepoint)
@ -122,6 +219,16 @@ hb_set_add (hb_set_t *set,
set->add (codepoint); set->add (codepoint);
} }
/**
* hb_set_add_range:
* @set: a set.
* @first:
* @last:
*
*
*
* Since: 1.0
**/
void void
hb_set_add_range (hb_set_t *set, hb_set_add_range (hb_set_t *set,
hb_codepoint_t first, hb_codepoint_t first,
@ -130,6 +237,15 @@ hb_set_add_range (hb_set_t *set,
set->add_range (first, last); set->add_range (first, last);
} }
/**
* hb_set_del:
* @set: a set.
* @codepoint:
*
*
*
* Since: 1.0
**/
void void
hb_set_del (hb_set_t *set, hb_set_del (hb_set_t *set,
hb_codepoint_t codepoint) hb_codepoint_t codepoint)
@ -137,6 +253,16 @@ hb_set_del (hb_set_t *set,
set->del (codepoint); set->del (codepoint);
} }
/**
* hb_set_del_range:
* @set: a set.
* @first:
* @last:
*
*
*
* Since: 1.0
**/
void void
hb_set_del_range (hb_set_t *set, hb_set_del_range (hb_set_t *set,
hb_codepoint_t first, hb_codepoint_t first,
@ -145,6 +271,17 @@ hb_set_del_range (hb_set_t *set,
set->del_range (first, last); set->del_range (first, last);
} }
/**
* hb_set_is_equal:
* @set: a set.
* @other:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_set_is_equal (const hb_set_t *set, hb_set_is_equal (const hb_set_t *set,
const hb_set_t *other) const hb_set_t *other)
@ -152,6 +289,15 @@ hb_set_is_equal (const hb_set_t *set,
return set->is_equal (other); return set->is_equal (other);
} }
/**
* hb_set_set:
* @set: a set.
* @other:
*
*
*
* Since: 1.0
**/
void void
hb_set_set (hb_set_t *set, hb_set_set (hb_set_t *set,
const hb_set_t *other) const hb_set_t *other)
@ -159,6 +305,15 @@ hb_set_set (hb_set_t *set,
set->set (other); set->set (other);
} }
/**
* hb_set_union:
* @set: a set.
* @other:
*
*
*
* Since: 1.0
**/
void void
hb_set_union (hb_set_t *set, hb_set_union (hb_set_t *set,
const hb_set_t *other) const hb_set_t *other)
@ -166,6 +321,15 @@ hb_set_union (hb_set_t *set,
set->union_ (other); set->union_ (other);
} }
/**
* hb_set_intersect:
* @set: a set.
* @other:
*
*
*
* Since: 1.0
**/
void void
hb_set_intersect (hb_set_t *set, hb_set_intersect (hb_set_t *set,
const hb_set_t *other) const hb_set_t *other)
@ -173,6 +337,15 @@ hb_set_intersect (hb_set_t *set,
set->intersect (other); set->intersect (other);
} }
/**
* hb_set_subtract:
* @set: a set.
* @other:
*
*
*
* Since: 1.0
**/
void void
hb_set_subtract (hb_set_t *set, hb_set_subtract (hb_set_t *set,
const hb_set_t *other) const hb_set_t *other)
@ -180,6 +353,15 @@ hb_set_subtract (hb_set_t *set,
set->subtract (other); set->subtract (other);
} }
/**
* hb_set_symmetric_difference:
* @set: a set.
* @other:
*
*
*
* Since: 1.0
**/
void void
hb_set_symmetric_difference (hb_set_t *set, hb_set_symmetric_difference (hb_set_t *set,
const hb_set_t *other) const hb_set_t *other)
@ -187,30 +369,79 @@ hb_set_symmetric_difference (hb_set_t *set,
set->symmetric_difference (other); set->symmetric_difference (other);
} }
/**
* hb_set_invert:
* @set: a set.
*
*
*
* Since: 1.0
**/
void void
hb_set_invert (hb_set_t *set) hb_set_invert (hb_set_t *set)
{ {
set->invert (); set->invert ();
} }
/**
* hb_set_get_population:
* @set: a set.
*
* Returns the number of numbers in the set.
*
* Return value: set population.
*
* Since: 1.0
**/
unsigned int unsigned int
hb_set_get_population (const hb_set_t *set) hb_set_get_population (const hb_set_t *set)
{ {
return set->get_population (); return set->get_population ();
} }
/**
* hb_set_get_min:
* @set: a set.
*
* Finds the minimum number in the set.
*
* Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty.
*
* Since: 1.0
**/
hb_codepoint_t hb_codepoint_t
hb_set_get_min (const hb_set_t *set) hb_set_get_min (const hb_set_t *set)
{ {
return set->get_min (); return set->get_min ();
} }
/**
* hb_set_get_max:
* @set: a set.
*
* Finds the maximum number in the set.
*
* Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty.
*
* Since: 1.0
**/
hb_codepoint_t hb_codepoint_t
hb_set_get_max (const hb_set_t *set) hb_set_get_max (const hb_set_t *set)
{ {
return set->get_max (); return set->get_max ();
} }
/**
* hb_set_next:
* @set: a set.
* @codepoint: (inout):
*
*
*
* Return value: whether there was a next value.
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_set_next (const hb_set_t *set, hb_set_next (const hb_set_t *set,
hb_codepoint_t *codepoint) hb_codepoint_t *codepoint)
@ -218,6 +449,19 @@ hb_set_next (const hb_set_t *set,
return set->next (codepoint); return set->next (codepoint);
} }
/**
* hb_set_next_range:
* @set: a set.
* @first: (out): output first codepoint in the range.
* @last: (inout): input current last and output last codepoint in the range.
*
* Gets the next consecutive range of numbers in @set that
* are greater than current value of @last.
*
* Return value: whether there was a next range.
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_set_next_range (const hb_set_t *set, hb_set_next_range (const hb_set_t *set,
hb_codepoint_t *first, hb_codepoint_t *first,

View File

@ -36,6 +36,8 @@
HB_BEGIN_DECLS HB_BEGIN_DECLS
#define HB_SET_VALUE_INVALID ((hb_codepoint_t) -1)
typedef struct hb_set_t hb_set_t; typedef struct hb_set_t hb_set_t;

View File

@ -28,7 +28,6 @@
#define HB_SHAPE_PLAN_PRIVATE_HH #define HB_SHAPE_PLAN_PRIVATE_HH
#include "hb-private.hh" #include "hb-private.hh"
#include "hb-shape-plan.h"
#include "hb-object-private.hh" #include "hb-object-private.hh"
#include "hb-shaper-private.hh" #include "hb-shaper-private.hh"
@ -39,12 +38,15 @@ struct hb_shape_plan_t
ASSERT_POD (); ASSERT_POD ();
hb_bool_t default_shaper_list; hb_bool_t default_shaper_list;
hb_face_t *face; hb_face_t *face_unsafe; /* We don't carry a reference to face. */
hb_segment_properties_t props; hb_segment_properties_t props;
hb_shape_func_t *shaper_func; hb_shape_func_t *shaper_func;
const char *shaper_name; const char *shaper_name;
hb_feature_t *user_features;
unsigned int num_user_features;
struct hb_shaper_data_t shaper_data; struct hb_shaper_data_t shaper_data;
}; };

View File

@ -46,7 +46,7 @@ hb_shape_plan_plan (hb_shape_plan_t *shape_plan,
#define HB_SHAPER_PLAN(shaper) \ #define HB_SHAPER_PLAN(shaper) \
HB_STMT_START { \ HB_STMT_START { \
if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face)) { \ if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) { \
HB_SHAPER_DATA (shaper, shape_plan) = \ HB_SHAPER_DATA (shaper, shape_plan) = \
HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \ HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \
shape_plan->shaper_func = _hb_##shaper##_shape; \ shape_plan->shaper_func = _hb_##shaper##_shape; \
@ -83,6 +83,20 @@ hb_shape_plan_plan (hb_shape_plan_t *shape_plan,
* hb_shape_plan_t * hb_shape_plan_t
*/ */
/**
* hb_shape_plan_create: (Xconstructor)
* @face:
* @props:
* @user_features: (array length=num_user_features):
* @num_user_features:
* @shaper_list: (array zero-terminated=1):
*
*
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_shape_plan_t * hb_shape_plan_t *
hb_shape_plan_create (hb_face_t *face, hb_shape_plan_create (hb_face_t *face,
const hb_segment_properties_t *props, const hb_segment_properties_t *props,
@ -93,24 +107,42 @@ hb_shape_plan_create (hb_face_t *face,
assert (props->direction != HB_DIRECTION_INVALID); assert (props->direction != HB_DIRECTION_INVALID);
hb_shape_plan_t *shape_plan; hb_shape_plan_t *shape_plan;
hb_feature_t *features = NULL;
if (unlikely (!face)) if (unlikely (!face))
face = hb_face_get_empty (); face = hb_face_get_empty ();
if (unlikely (!props || hb_object_is_inert (face))) if (unlikely (!props || hb_object_is_inert (face)))
return hb_shape_plan_get_empty (); return hb_shape_plan_get_empty ();
if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) if (num_user_features && !(features = (hb_feature_t *) malloc (num_user_features * sizeof (hb_feature_t))))
return hb_shape_plan_get_empty (); return hb_shape_plan_get_empty ();
if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) {
free (features);
return hb_shape_plan_get_empty ();
}
hb_face_make_immutable (face); hb_face_make_immutable (face);
shape_plan->default_shaper_list = shaper_list == NULL; shape_plan->default_shaper_list = shaper_list == NULL;
shape_plan->face = hb_face_reference (face); shape_plan->face_unsafe = face;
shape_plan->props = *props; shape_plan->props = *props;
shape_plan->num_user_features = num_user_features;
shape_plan->user_features = features;
if (num_user_features)
memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list); hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list);
return shape_plan; return shape_plan;
} }
/**
* hb_shape_plan_get_empty:
*
*
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_shape_plan_t * hb_shape_plan_t *
hb_shape_plan_get_empty (void) hb_shape_plan_get_empty (void)
{ {
@ -124,6 +156,9 @@ hb_shape_plan_get_empty (void)
NULL, /* shaper_func */ NULL, /* shaper_func */
NULL, /* shaper_name */ NULL, /* shaper_name */
NULL, /* user_features */
0, /* num_user_featurs */
{ {
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID, #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
#include "hb-shaper-list.hh" #include "hb-shaper-list.hh"
@ -134,12 +169,30 @@ hb_shape_plan_get_empty (void)
return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil); return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil);
} }
/**
* hb_shape_plan_reference: (skip)
* @shape_plan: a shape plan.
*
*
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_shape_plan_t * hb_shape_plan_t *
hb_shape_plan_reference (hb_shape_plan_t *shape_plan) hb_shape_plan_reference (hb_shape_plan_t *shape_plan)
{ {
return hb_object_reference (shape_plan); return hb_object_reference (shape_plan);
} }
/**
* hb_shape_plan_destroy: (skip)
* @shape_plan: a shape plan.
*
*
*
* Since: 1.0
**/
void void
hb_shape_plan_destroy (hb_shape_plan_t *shape_plan) hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
{ {
@ -149,11 +202,25 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
#include "hb-shaper-list.hh" #include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT #undef HB_SHAPER_IMPLEMENT
hb_face_destroy (shape_plan->face); free (shape_plan->user_features);
free (shape_plan); free (shape_plan);
} }
/**
* hb_shape_plan_set_user_data: (skip)
* @shape_plan: a shape plan.
* @key:
* @data:
* @destroy:
* @replace:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan, hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
hb_user_data_key_t *key, hb_user_data_key_t *key,
@ -164,6 +231,17 @@ hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
return hb_object_set_user_data (shape_plan, key, data, destroy, replace); return hb_object_set_user_data (shape_plan, key, data, destroy, replace);
} }
/**
* hb_shape_plan_get_user_data: (skip)
* @shape_plan: a shape plan.
* @key:
*
*
*
* Return value: (transfer none):
*
* Since: 1.0
**/
void * void *
hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan, hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
hb_user_data_key_t *key) hb_user_data_key_t *key)
@ -172,6 +250,20 @@ hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
} }
/**
* hb_shape_plan_execute:
* @shape_plan: a shape plan.
* @font: a font.
* @buffer: a buffer.
* @features: (array length=num_features):
* @num_features:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_shape_plan_execute (hb_shape_plan_t *shape_plan, hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
hb_font_t *font, hb_font_t *font,
@ -184,7 +276,7 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
hb_object_is_inert (buffer))) hb_object_is_inert (buffer)))
return false; return false;
assert (shape_plan->face == font->face); assert (shape_plan->face_unsafe == font->face);
assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props)); assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props));
#define HB_SHAPER_EXECUTE(shaper) \ #define HB_SHAPER_EXECUTE(shaper) \
@ -221,23 +313,69 @@ hb_shape_plan_hash (const hb_shape_plan_t *shape_plan)
} }
#endif #endif
/* TODO no user-feature caching for now. */ /* User-feature caching is currently somewhat dumb:
* it only finds matches where the feature array is identical,
* not cases where the feature lists would be compatible for plan purposes
* but have different ranges, for example.
*/
struct hb_shape_plan_proposal_t struct hb_shape_plan_proposal_t
{ {
const hb_segment_properties_t props; const hb_segment_properties_t props;
const char * const *shaper_list; const char * const *shaper_list;
const hb_feature_t *user_features;
unsigned int num_user_features;
hb_shape_func_t *shaper_func; hb_shape_func_t *shaper_func;
}; };
static inline hb_bool_t
hb_shape_plan_user_features_match (const hb_shape_plan_t *shape_plan,
const hb_shape_plan_proposal_t *proposal)
{
if (proposal->num_user_features != shape_plan->num_user_features) return false;
for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++)
if (proposal->user_features[i].tag != shape_plan->user_features[i].tag ||
proposal->user_features[i].value != shape_plan->user_features[i].value ||
proposal->user_features[i].start != shape_plan->user_features[i].start ||
proposal->user_features[i].end != shape_plan->user_features[i].end) return false;
return true;
}
static hb_bool_t static hb_bool_t
hb_shape_plan_matches (const hb_shape_plan_t *shape_plan, hb_shape_plan_matches (const hb_shape_plan_t *shape_plan,
const hb_shape_plan_proposal_t *proposal) const hb_shape_plan_proposal_t *proposal)
{ {
return hb_segment_properties_equal (&shape_plan->props, &proposal->props) && return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
hb_shape_plan_user_features_match (shape_plan, proposal) &&
((shape_plan->default_shaper_list && proposal->shaper_list == NULL) || ((shape_plan->default_shaper_list && proposal->shaper_list == NULL) ||
(shape_plan->shaper_func == proposal->shaper_func)); (shape_plan->shaper_func == proposal->shaper_func));
} }
static inline hb_bool_t
hb_non_global_user_features_present (const hb_feature_t *user_features,
unsigned int num_user_features)
{
while (num_user_features)
if (user_features->start != 0 || user_features->end != (unsigned int) -1)
return true;
else
num_user_features--, user_features++;
return false;
}
/**
* hb_shape_plan_create_cached:
* @face:
* @props:
* @user_features: (array length=num_user_features):
* @num_user_features:
* @shaper_list: (array zero-terminated=1):
*
*
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_shape_plan_t * hb_shape_plan_t *
hb_shape_plan_create_cached (hb_face_t *face, hb_shape_plan_create_cached (hb_face_t *face,
const hb_segment_properties_t *props, const hb_segment_properties_t *props,
@ -245,12 +383,11 @@ hb_shape_plan_create_cached (hb_face_t *face,
unsigned int num_user_features, unsigned int num_user_features,
const char * const *shaper_list) const char * const *shaper_list)
{ {
if (num_user_features)
return hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
hb_shape_plan_proposal_t proposal = { hb_shape_plan_proposal_t proposal = {
*props, *props,
shaper_list, shaper_list,
user_features,
num_user_features,
NULL NULL
}; };
@ -288,6 +425,11 @@ retry:
hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list); hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
/* Don't add the plan to the cache if there were user features with non-global ranges */
if (hb_non_global_user_features_present (user_features, num_user_features))
return shape_plan;
hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t)); hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
if (unlikely (!node)) if (unlikely (!node))
return shape_plan; return shape_plan;
@ -301,12 +443,19 @@ retry:
goto retry; goto retry;
} }
/* Release our reference on face. */
hb_face_destroy (face);
return hb_shape_plan_reference (shape_plan); return hb_shape_plan_reference (shape_plan);
} }
/**
* hb_shape_plan_get_shaper:
* @shape_plan: a shape plan.
*
*
*
* Return value: (transfer none):
*
* Since: 1.0
**/
const char * const char *
hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan) hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan)
{ {

View File

@ -153,6 +153,18 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
*pp == end; *pp == end;
} }
/**
* hb_feature_from_string:
* @str: (array length=len):
* @len:
* @feature: (out):
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_feature_from_string (const char *str, int len, hb_feature_from_string (const char *str, int len,
hb_feature_t *feature) hb_feature_t *feature)
@ -163,6 +175,16 @@ hb_feature_from_string (const char *str, int len,
return parse_one_feature (&str, str + len, feature); return parse_one_feature (&str, str + len, feature);
} }
/**
* hb_feature_to_string:
* @feature:
* @buf: (array length=size):
* @size:
*
*
*
* Since: 1.0
**/
void void
hb_feature_to_string (hb_feature_t *feature, hb_feature_to_string (hb_feature_t *feature,
char *buf, unsigned int size) char *buf, unsigned int size)
@ -209,6 +231,15 @@ void free_static_shaper_list (void)
free (static_shaper_list); free (static_shaper_list);
} }
/**
* hb_shape_list_shapers:
*
*
*
* Return value: (transfer none):
*
* Since: 1.0
**/
const char ** const char **
hb_shape_list_shapers (void) hb_shape_list_shapers (void)
{ {
@ -244,6 +275,20 @@ retry:
} }
/**
* hb_shape_full:
* @font: a font.
* @buffer: a buffer.
* @features: (array length=num_features):
* @num_features:
* @shaper_list: (array zero-terminated=1):
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_shape_full (hb_font_t *font, hb_shape_full (hb_font_t *font,
hb_buffer_t *buffer, hb_buffer_t *buffer,
@ -265,6 +310,17 @@ hb_shape_full (hb_font_t *font,
return res; return res;
} }
/**
* hb_shape:
* @font: a font.
* @buffer: a buffer.
* @features: (array length=num_features):
* @num_features:
*
*
*
* Since: 1.0
**/
void void
hb_shape (hb_font_t *font, hb_shape (hb_font_t *font,
hb_buffer_t *buffer, hb_buffer_t *buffer,

View File

@ -32,8 +32,6 @@
#define HB_UNICODE_PRIVATE_HH #define HB_UNICODE_PRIVATE_HH
#include "hb-private.hh" #include "hb-private.hh"
#include "hb-unicode.h"
#include "hb-object-private.hh" #include "hb-object-private.hh"

View File

@ -150,6 +150,16 @@ hb_unicode_funcs_get_default (void)
#pragma message("To suppress this warnings, define HB_NO_UNICODE_FUNCS.") #pragma message("To suppress this warnings, define HB_NO_UNICODE_FUNCS.")
#endif #endif
/**
* hb_unicode_funcs_create: (Xconstructor)
* @parent: (allow-none):
*
*
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_unicode_funcs_t * hb_unicode_funcs_t *
hb_unicode_funcs_create (hb_unicode_funcs_t *parent) hb_unicode_funcs_create (hb_unicode_funcs_t *parent)
{ {
@ -187,18 +197,45 @@ const hb_unicode_funcs_t _hb_unicode_funcs_nil = {
} }
}; };
/**
* hb_unicode_funcs_get_empty:
*
*
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_unicode_funcs_t * hb_unicode_funcs_t *
hb_unicode_funcs_get_empty (void) hb_unicode_funcs_get_empty (void)
{ {
return const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil); return const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil);
} }
/**
* hb_unicode_funcs_reference: (skip)
* @ufuncs: Unicode functions.
*
*
*
* Return value: (transfer full):
*
* Since: 1.0
**/
hb_unicode_funcs_t * hb_unicode_funcs_t *
hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs) hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs)
{ {
return hb_object_reference (ufuncs); return hb_object_reference (ufuncs);
} }
/**
* hb_unicode_funcs_destroy: (skip)
* @ufuncs: Unicode functions.
*
*
*
* Since: 1.0
**/
void void
hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs) hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
{ {
@ -214,6 +251,20 @@ hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
free (ufuncs); free (ufuncs);
} }
/**
* hb_unicode_funcs_set_user_data: (skip)
* @ufuncs: Unicode functions.
* @key:
* @data:
* @destroy:
* @replace:
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs, hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
hb_user_data_key_t *key, hb_user_data_key_t *key,
@ -224,6 +275,17 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
return hb_object_set_user_data (ufuncs, key, data, destroy, replace); return hb_object_set_user_data (ufuncs, key, data, destroy, replace);
} }
/**
* hb_unicode_funcs_get_user_data: (skip)
* @ufuncs: Unicode functions.
* @key:
*
*
*
* Return value: (transfer none):
*
* Since: 1.0
**/
void * void *
hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs, hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
hb_user_data_key_t *key) hb_user_data_key_t *key)
@ -232,6 +294,14 @@ hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
} }
/**
* hb_unicode_funcs_make_immutable:
* @ufuncs: Unicode functions.
*
*
*
* Since: 1.0
**/
void void
hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs) hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
{ {
@ -241,12 +311,32 @@ hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
ufuncs->immutable = true; ufuncs->immutable = true;
} }
/**
* hb_unicode_funcs_is_immutable:
* @ufuncs: Unicode functions.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs) hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs)
{ {
return ufuncs->immutable; return ufuncs->immutable;
} }
/**
* hb_unicode_funcs_get_parent:
* @ufuncs: Unicode functions.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_unicode_funcs_t * hb_unicode_funcs_t *
hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs) hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs)
{ {
@ -294,6 +384,19 @@ hb_unicode_##name (hb_unicode_funcs_t *ufuncs, \
HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
#undef HB_UNICODE_FUNC_IMPLEMENT #undef HB_UNICODE_FUNC_IMPLEMENT
/**
* hb_unicode_compose:
* @ufuncs: Unicode functions.
* @a:
* @b:
* @ab: (out):
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_unicode_compose (hb_unicode_funcs_t *ufuncs, hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t a, hb_codepoint_t a,
@ -303,6 +406,19 @@ hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
return ufuncs->compose (a, b, ab); return ufuncs->compose (a, b, ab);
} }
/**
* hb_unicode_decompose:
* @ufuncs: Unicode functions.
* @ab:
* @a: (out):
* @b: (out):
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_bool_t hb_bool_t
hb_unicode_decompose (hb_unicode_funcs_t *ufuncs, hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t ab, hb_codepoint_t ab,
@ -312,6 +428,18 @@ hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
return ufuncs->decompose (ab, a, b); return ufuncs->decompose (ab, a, b);
} }
/**
* hb_unicode_decompose_compatibility:
* @ufuncs: Unicode functions.
* @u:
* @decomposed: (out):
*
*
*
* Return value:
*
* Since: 1.0
**/
unsigned int unsigned int
hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs, hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t u, hb_codepoint_t u,

View File

@ -248,7 +248,7 @@ typedef hb_bool_t (*hb_unicode_decompose_func_t) (hb_unicode_funcs_t *ufuncs,
/** /**
* hb_unicode_decompose_compatibility_func_t: * hb_unicode_decompose_compatibility_func_t:
* @ufuncs: Unicode function structure * @ufuncs: a Unicode function structure
* @u: codepoint to decompose * @u: codepoint to decompose
* @decomposed: address of codepoint array (of length %HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into * @decomposed: address of codepoint array (of length %HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into
* @user_data: user data pointer as passed to hb_unicode_funcs_set_decompose_compatibility_func() * @user_data: user data pointer as passed to hb_unicode_funcs_set_decompose_compatibility_func()
@ -274,44 +274,132 @@ typedef unsigned int (*hb_unicode_decompose_compatibility_func_t) (hb_unicode_
/* setters */ /* setters */
/**
* hb_unicode_funcs_set_combining_class_func:
* @ufuncs: a Unicode function structure
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs, hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_combining_class_func_t combining_class_func, hb_unicode_combining_class_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/**
* hb_unicode_funcs_set_eastasian_width_func:
* @ufuncs: a Unicode function structure
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs, hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_eastasian_width_func_t eastasian_width_func, hb_unicode_eastasian_width_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/**
* hb_unicode_funcs_set_general_category_func:
* @ufuncs: a Unicode function structure
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs, hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_general_category_func_t general_category_func, hb_unicode_general_category_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/**
* hb_unicode_funcs_set_mirroring_func:
* @ufuncs: a Unicode function structure
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs, hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_mirroring_func_t mirroring_func, hb_unicode_mirroring_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/**
* hb_unicode_funcs_set_script_func:
* @ufuncs: a Unicode function structure
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs, hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_script_func_t script_func, hb_unicode_script_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/**
* hb_unicode_funcs_set_compose_func:
* @ufuncs: a Unicode function structure
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_unicode_funcs_set_compose_func (hb_unicode_funcs_t *ufuncs, hb_unicode_funcs_set_compose_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_compose_func_t compose_func, hb_unicode_compose_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/**
* hb_unicode_funcs_set_decompose_func:
* @ufuncs: a Unicode function structure
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_unicode_funcs_set_decompose_func (hb_unicode_funcs_t *ufuncs, hb_unicode_funcs_set_decompose_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_decompose_func_t decompose_func, hb_unicode_decompose_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/**
* hb_unicode_funcs_set_decompose_compatibility_func:
* @ufuncs: a Unicode function structure
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.0
**/
void void
hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs, hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_decompose_compatibility_func_t decompose_compatibility_func, hb_unicode_decompose_compatibility_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);
/* accessors */ /* accessors */

View File

@ -38,9 +38,9 @@ HB_BEGIN_DECLS
#define HB_VERSION_MAJOR 0 #define HB_VERSION_MAJOR 0
#define HB_VERSION_MINOR 9 #define HB_VERSION_MINOR 9
#define HB_VERSION_MICRO 20 #define HB_VERSION_MICRO 25
#define HB_VERSION_STRING "0.9.20" #define HB_VERSION_STRING "0.9.25"
#define HB_VERSION_CHECK(major,minor,micro) \ #define HB_VERSION_CHECK(major,minor,micro) \
((major)*10000+(minor)*100+(micro) >= \ ((major)*10000+(minor)*100+(micro) >= \

View File

@ -79,6 +79,7 @@ contains(QT_CONFIG, harfbuzz) {
$$QT_HARFBUZZ_DIR/src/hb-ot-layout-gpos-table.hh \ $$QT_HARFBUZZ_DIR/src/hb-ot-layout-gpos-table.hh \
$$QT_HARFBUZZ_DIR/src/hb-ot-layout-gsubgpos-private.hh \ $$QT_HARFBUZZ_DIR/src/hb-ot-layout-gsubgpos-private.hh \
$$QT_HARFBUZZ_DIR/src/hb-ot-layout-gsub-table.hh \ $$QT_HARFBUZZ_DIR/src/hb-ot-layout-gsub-table.hh \
$$QT_HARFBUZZ_DIR/src/hb-ot-layout-jstf-table.hh \
$$QT_HARFBUZZ_DIR/src/hb-ot-layout-private.hh \ $$QT_HARFBUZZ_DIR/src/hb-ot-layout-private.hh \
$$QT_HARFBUZZ_DIR/src/hb-ot-map-private.hh \ $$QT_HARFBUZZ_DIR/src/hb-ot-map-private.hh \
$$QT_HARFBUZZ_DIR/src/hb-ot-shape-complex-arabic-fallback.hh \ $$QT_HARFBUZZ_DIR/src/hb-ot-shape-complex-arabic-fallback.hh \