bug 964240 - update harfbuzz to pick up Hangul shaper improvements and other fixes. r=jdaggett

This commit is contained in:
Jonathan Kew 2014-01-30 09:48:20 +00:00
parent 9c2572e5e5
commit db9c35e7da
44 changed files with 920 additions and 330 deletions

View File

@ -27,7 +27,6 @@ HBSOURCES = \
hb-buffer.cc \
hb-cache-private.hh \
hb-common.cc \
hb-fallback-shape.cc \
hb-face-private.hh \
hb-face.cc \
hb-font-private.hh \
@ -92,6 +91,8 @@ HBSOURCES += \
hb-ot-shape-complex-arabic-fallback.hh \
hb-ot-shape-complex-arabic-table.hh \
hb-ot-shape-complex-default.cc \
hb-ot-shape-complex-hangul.cc \
hb-ot-shape-complex-hebrew.cc \
hb-ot-shape-complex-indic.cc \
hb-ot-shape-complex-indic-machine.hh \
hb-ot-shape-complex-indic-private.hh \
@ -101,6 +102,7 @@ HBSOURCES += \
hb-ot-shape-complex-sea.cc \
hb-ot-shape-complex-sea-machine.hh \
hb-ot-shape-complex-thai.cc \
hb-ot-shape-complex-tibetan.cc \
hb-ot-shape-complex-private.hh \
hb-ot-shape-normalize-private.hh \
hb-ot-shape-normalize.cc \
@ -111,10 +113,15 @@ HBSOURCES += \
HBHEADERS += \
hb-ot.h \
hb-ot-layout.h \
hb-ot-shape.h \
hb-ot-tag.h \
$(NULL)
endif
if HAVE_FALLBACK
HBSOURCES += hb-fallback-shape.cc
endif
if HAVE_PTHREAD
HBCFLAGS += $(PTHREAD_CFLAGS)
HBLIBS += $(PTHREAD_LIBS)

View File

@ -29,7 +29,6 @@
#include "hb-private.hh"
#include "hb-blob.h"
#include "hb-object-private.hh"
#ifdef HAVE_SYS_MMAN_H

View File

@ -31,7 +31,6 @@
#define HB_BUFFER_PRIVATE_HH
#include "hb-private.hh"
#include "hb-buffer.h"
#include "hb-object-private.hh"
#include "hb-unicode-private.hh"

View File

@ -204,7 +204,7 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
*p++ = '+';
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
if (pos->y_advance)
if (pos[i].y_advance)
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
}

View File

@ -28,8 +28,6 @@
#include "hb-private.hh"
#include "hb-version.h"
#include "hb-mutex-private.hh"
#include "hb-object-private.hh"

View File

@ -94,6 +94,7 @@ typedef uint32_t hb_tag_t;
#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_MAX HB_TAG(0xff,0xff,0xff,0xff)
/* len=-1 means str is NUL-terminated. */
hb_tag_t
@ -270,7 +271,12 @@ typedef enum
/*6.1*/ HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'),
/* No script set. */
/*---*/ HB_SCRIPT_INVALID = HB_TAG_NONE
/*---*/ HB_SCRIPT_INVALID = HB_TAG_NONE,
/* Dummy value to ensure any hb_tag_t value can be passed/stored as hb_script_t
* without risking undefined behavior. */
/*---*/ _HB_SCRIPT_MAX_VALUE = HB_TAG_MAX
} hb_script_t;
/* These are moved out of hb_script_t because glib-mkenums chokes otherwise. */

View File

@ -591,7 +591,6 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (NULL, chars_len);
CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref);
CFRelease (string_ref);
CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
kCTFontAttributeName, font_data->ct_font);
@ -671,23 +670,33 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
if (buffer->in_error)
FAIL ("Buffer resize failed");
hb_glyph_info_t *info = buffer->info + buffer->len;
buffer->len += range.length;
for (CFIndex j = 0; j < range.length; j++)
CGGlyph notdef = 0;
double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFontHorizontalOrientation, &notdef, NULL, 1);
for (CFIndex j = range.location; j < range.location + range.length; j++)
{
CGGlyph notdef = 0;
double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFontHorizontalOrientation, &notdef, NULL, 1);
UniChar ch = CFStringGetCharacterAtIndex (string_ref, j);
if (hb_in_range<UniChar> (ch, 0xDC00, 0xDFFF) && range.location < j)
{
ch = CFStringGetCharacterAtIndex (string_ref, j - 1);
if (hb_in_range<UniChar> (ch, 0xD800, 0xDBFF))
/* This is the second of a surrogate pair. Don't need .notdef
* for this one. */
continue;
}
info->codepoint = notdef;
/* TODO We have to fixup clusters later. See vis_clusters in
* hb-uniscribe.cc for example. */
info->cluster = range.location + j;
info->cluster = j;
info->mask = advance;
info->var1.u32 = 0;
info->var2.u32 = 0;
info++;
buffer->len++;
}
continue;
}
@ -796,6 +805,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
}
}
CFRelease (string_ref);
CFRelease (line);
return true;

View File

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

View File

@ -31,7 +31,6 @@
#include "hb-ot-layout-private.hh"
#include "hb-font-private.hh"
#include "hb-blob.h"
#include "hb-open-file-private.hh"
#include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh"

View File

@ -105,8 +105,9 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
* shaper which many people unfortunately still request.
*/
bool has_space;
hb_codepoint_t space;
font->get_glyph (' ', 0, &space);
has_space = font->get_glyph (' ', 0, &space);
buffer->clear_positions ();
@ -114,7 +115,7 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
for (unsigned int i = 0; i < count; i++)
{
if (buffer->unicode->is_default_ignorable (buffer->info[i].codepoint)) {
if (has_space && buffer->unicode->is_default_ignorable (buffer->info[i].codepoint)) {
buffer->info[i].codepoint = space;
buffer->pos[i].x_advance = 0;
buffer->pos[i].y_advance = 0;

View File

@ -31,7 +31,6 @@
#include "hb-private.hh"
#include "hb-font.h"
#include "hb-object-private.hh"
#include "hb-face-private.hh"
#include "hb-shaper-private.hh"
@ -145,6 +144,12 @@ struct hb_font_t {
/* Public getters */
inline hb_bool_t has_glyph (hb_codepoint_t unicode)
{
hb_codepoint_t glyph;
return get_glyph (unicode, 0, &glyph);
}
inline hb_bool_t get_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
hb_codepoint_t *glyph)
{

View File

@ -31,7 +31,6 @@
#include "hb-ot-layout-private.hh"
#include "hb-font-private.hh"
#include "hb-blob.h"
#include "hb-open-file-private.hh"
#include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh"

View File

@ -34,8 +34,6 @@
#include <graphite2/Segment.h>
#include "hb-ot-tag.h"
HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, face)
HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, font)
@ -109,7 +107,7 @@ _hb_graphite2_shaper_face_data_create (hb_face_t *face)
hb_graphite2_shaper_face_data_t *data = (hb_graphite2_shaper_face_data_t *) calloc (1, sizeof (hb_graphite2_shaper_face_data_t));
if (unlikely (!data))
hb_blob_destroy (silf_blob);
return NULL;
data->face = face;
data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll);

View File

@ -31,8 +31,6 @@
#include "hb-private.hh"
#include "hb-blob.h"
namespace OT {
@ -594,7 +592,7 @@ struct LONGDATETIME
TRACE_SANITIZE (this);
return TRACE_RETURN (likely (c->check_struct (this)));
}
private:
protected:
LONG major;
ULONG minor;
public:

View File

@ -109,11 +109,13 @@ struct ValueFormat : USHORT
if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++));
if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++));
if (format & xAdvance) {
if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values++)); else values++;
if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values));
values++;
}
/* y_advance values grow downward but font-space grows upward, hence negation */
if (format & yAdvance) {
if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values++)); else values++;
if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values));
values++;
}
if (!has_device ()) return;
@ -125,17 +127,21 @@ struct ValueFormat : USHORT
/* pixel -> fractional pixel */
if (format & xPlaDevice) {
if (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_x_delta (font); else values++;
if (x_ppem) glyph_pos.x_offset += (base + get_device (values)).get_x_delta (font);
values++;
}
if (format & yPlaDevice) {
if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_y_delta (font); else values++;
if (y_ppem) glyph_pos.y_offset += (base + get_device (values)).get_y_delta (font);
values++;
}
if (format & xAdvDevice) {
if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (font); else values++;
if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font);
values++;
}
if (format & yAdvDevice) {
/* y_advance values grow downward but font-space grows upward, hence negation */
if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values++)).get_y_delta (font); else values++;
if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font);
values++;
}
}
@ -240,12 +246,12 @@ struct AnchorFormat2
unsigned int x_ppem = font->x_ppem;
unsigned int y_ppem = font->y_ppem;
hb_position_t cx, cy;
hb_bool_t ret = false;
hb_bool_t ret;
if (x_ppem || y_ppem)
ret = font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
*x = x_ppem && ret ? cx : font->em_scale_x (xCoordinate);
*y = y_ppem && ret ? cy : font->em_scale_y (yCoordinate);
ret = (x_ppem || y_ppem) &&
font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
*x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
*y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
}
inline bool sanitize (hb_sanitize_context_t *c) {

View File

@ -31,8 +31,6 @@
#include "hb-private.hh"
#include "hb-ot-layout.h"
#include "hb-font-private.hh"
#include "hb-buffer-private.hh"
#include "hb-set-private.hh"

View File

@ -193,11 +193,6 @@ hb_ot_layout_collect_lookups (hb_face_t *face,
const hb_tag_t *features,
hb_set_t *lookup_indexes /* OUT */);
void
hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
hb_tag_t table_tag,
hb_set_t *lookup_indexes /* OUT */);
void
hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
hb_tag_t table_tag,

View File

@ -199,7 +199,6 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
map->add_global_bool_feature (HB_TAG('c','a','l','t'));
map->add_gsub_pause (NULL);
map->add_global_bool_feature (HB_TAG('c','s','w','h'));
map->add_global_bool_feature (HB_TAG('m','s','e','t'));
}
@ -366,7 +365,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
data_create_arabic,
data_destroy_arabic,
NULL, /* preprocess_text_arabic */
NULL, /* normalization_preference */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */
setup_masks_arabic,

View File

@ -27,194 +27,18 @@
#include "hb-ot-shape-complex-private.hh"
/* TODO Add kana, and other small shapers here */
/* The default shaper *only* adds additional per-script features.*/
static const hb_tag_t hangul_features[] =
{
HB_TAG('l','j','m','o'),
HB_TAG('v','j','m','o'),
HB_TAG('t','j','m','o'),
HB_TAG_NONE
};
static const hb_tag_t tibetan_features[] =
{
HB_TAG('a','b','v','s'),
HB_TAG('b','l','w','s'),
HB_TAG('a','b','v','m'),
HB_TAG('b','l','w','m'),
HB_TAG_NONE
};
static void
collect_features_default (hb_ot_shape_planner_t *plan)
{
const hb_tag_t *script_features = NULL;
switch ((hb_tag_t) plan->props.script)
{
/* Unicode-1.1 additions */
case HB_SCRIPT_HANGUL:
script_features = hangul_features;
break;
/* Unicode-2.0 additions */
case HB_SCRIPT_TIBETAN:
script_features = tibetan_features;
break;
}
for (; script_features && *script_features; script_features++)
plan->map.add_global_bool_feature (*script_features);
}
static hb_ot_shape_normalization_mode_t
normalization_preference_default (const hb_segment_properties_t *props)
{
return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
}
static bool
compose_default (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab)
{
/* Hebrew presentation-form shaping.
* https://bugzilla.mozilla.org/show_bug.cgi?id=728866
* Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA;
* Note that some letters do not have a dagesh presForm encoded.
*/
static const hb_codepoint_t sDageshForms[0x05EA - 0x05D0 + 1] = {
0xFB30, /* ALEF */
0xFB31, /* BET */
0xFB32, /* GIMEL */
0xFB33, /* DALET */
0xFB34, /* HE */
0xFB35, /* VAV */
0xFB36, /* ZAYIN */
0x0000, /* HET */
0xFB38, /* TET */
0xFB39, /* YOD */
0xFB3A, /* FINAL KAF */
0xFB3B, /* KAF */
0xFB3C, /* LAMED */
0x0000, /* FINAL MEM */
0xFB3E, /* MEM */
0x0000, /* FINAL NUN */
0xFB40, /* NUN */
0xFB41, /* SAMEKH */
0x0000, /* AYIN */
0xFB43, /* FINAL PE */
0xFB44, /* PE */
0x0000, /* FINAL TSADI */
0xFB46, /* TSADI */
0xFB47, /* QOF */
0xFB48, /* RESH */
0xFB49, /* SHIN */
0xFB4A /* TAV */
};
bool found = c->unicode->compose (a, b, ab);
if (!found && (b & ~0x7F) == 0x0580) {
/* Special-case Hebrew presentation forms that are excluded from
* standard normalization, but wanted for old fonts. */
switch (b) {
case 0x05B4: /* HIRIQ */
if (a == 0x05D9) { /* YOD */
*ab = 0xFB1D;
found = true;
}
break;
case 0x05B7: /* patah */
if (a == 0x05F2) { /* YIDDISH YOD YOD */
*ab = 0xFB1F;
found = true;
} else if (a == 0x05D0) { /* ALEF */
*ab = 0xFB2E;
found = true;
}
break;
case 0x05B8: /* QAMATS */
if (a == 0x05D0) { /* ALEF */
*ab = 0xFB2F;
found = true;
}
break;
case 0x05B9: /* HOLAM */
if (a == 0x05D5) { /* VAV */
*ab = 0xFB4B;
found = true;
}
break;
case 0x05BC: /* DAGESH */
if (a >= 0x05D0 && a <= 0x05EA) {
*ab = sDageshForms[a - 0x05D0];
found = (*ab != 0);
} else if (a == 0xFB2A) { /* SHIN WITH SHIN DOT */
*ab = 0xFB2C;
found = true;
} else if (a == 0xFB2B) { /* SHIN WITH SIN DOT */
*ab = 0xFB2D;
found = true;
}
break;
case 0x05BF: /* RAFE */
switch (a) {
case 0x05D1: /* BET */
*ab = 0xFB4C;
found = true;
break;
case 0x05DB: /* KAF */
*ab = 0xFB4D;
found = true;
break;
case 0x05E4: /* PE */
*ab = 0xFB4E;
found = true;
break;
}
break;
case 0x05C1: /* SHIN DOT */
if (a == 0x05E9) { /* SHIN */
*ab = 0xFB2A;
found = true;
} else if (a == 0xFB49) { /* SHIN WITH DAGESH */
*ab = 0xFB2C;
found = true;
}
break;
case 0x05C2: /* SIN DOT */
if (a == 0x05E9) { /* SHIN */
*ab = 0xFB2B;
found = true;
} else if (a == 0xFB49) { /* SHIN WITH DAGESH */
*ab = 0xFB2D;
found = true;
}
break;
}
}
return found;
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
{
"default",
collect_features_default,
NULL, /* collect_features */
NULL, /* override_features */
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
normalization_preference_default,
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
compose_default,
NULL, /* compose */
NULL, /* setup_masks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
true, /* fallback_position */
};

View File

@ -0,0 +1,417 @@
/*
* 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
*/
#include "hb-ot-shape-complex-private.hh"
/* Hangul shaper */
/* Same order as the feature array below */
enum {
NONE,
LJMO,
VJMO,
TJMO,
FIRST_HANGUL_FEATURE = LJMO,
HANGUL_FEATURE_COUNT = TJMO + 1
};
static const hb_tag_t hangul_features[HANGUL_FEATURE_COUNT] =
{
HB_TAG_NONE,
HB_TAG('l','j','m','o'),
HB_TAG('v','j','m','o'),
HB_TAG('t','j','m','o')
};
static void
collect_features_hangul (hb_ot_shape_planner_t *plan)
{
hb_ot_map_builder_t *map = &plan->map;
for (unsigned int i = FIRST_HANGUL_FEATURE; i < HANGUL_FEATURE_COUNT; i++)
map->add_feature (hangul_features[i], 1, F_NONE);
}
struct hangul_shape_plan_t
{
ASSERT_POD ();
hb_mask_t mask_array[HANGUL_FEATURE_COUNT];
};
static void *
data_create_hangul (const hb_ot_shape_plan_t *plan)
{
hangul_shape_plan_t *hangul_plan = (hangul_shape_plan_t *) calloc (1, sizeof (hangul_shape_plan_t));
if (unlikely (!hangul_plan))
return NULL;
for (unsigned int i = 0; i < HANGUL_FEATURE_COUNT; i++)
hangul_plan->mask_array[i] = plan->map.get_1_mask (hangul_features[i]);
return hangul_plan;
}
static void
data_destroy_hangul (void *data)
{
free (data);
}
/* Constants for algorithmic hangul syllable [de]composition. */
#define LBase 0x1100
#define VBase 0x1161
#define TBase 0x11A7
#define LCount 19
#define VCount 21
#define TCount 28
#define SBase 0xAC00
#define NCount (VCount * TCount)
#define SCount (LCount * NCount)
#define isCombiningL(u) (hb_in_range<hb_codepoint_t> ((u), LBase, LBase+LCount-1))
#define isCombiningV(u) (hb_in_range<hb_codepoint_t> ((u), VBase, VBase+VCount-1))
#define isCombiningT(u) (hb_in_range<hb_codepoint_t> ((u), TBase+1, TBase+TCount-1))
#define isCombinedS(u) (hb_in_range<hb_codepoint_t> ((u), SBase, SBase+SCount-1))
#define isL(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x1100, 0x115F, 0xA960, 0xA97C))
#define isV(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x1160, 0x11A7, 0xD7B0, 0xD7C6))
#define isT(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x11A8, 0x11FF, 0xD7CB, 0xD7FB))
#define isHangulTone(u) (hb_in_range<hb_codepoint_t> ((u), 0x302e, 0x302f))
/* buffer var allocations */
#define hangul_shaping_feature() complex_var_u8_0() /* hangul jamo shaping feature */
static bool
is_zero_width_char (hb_font_t *font,
hb_codepoint_t unicode)
{
hb_codepoint_t glyph;
return hb_font_get_glyph (font, unicode, 0, &glyph) && hb_font_get_glyph_h_advance (font, glyph) == 0;
}
static void
preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font)
{
HB_BUFFER_ALLOCATE_VAR (buffer, hangul_shaping_feature);
/* Hangul syllables come in two shapes: LV, and LVT. Of those:
*
* - LV can be precomposed, or decomposed. Lets call those
* <LV> and <L,V>,
* - LVT can be fully precomposed, partically precomposed, or
* fully decomposed. Ie. <LVT>, <LV,T>, or <L,V,T>.
*
* The composition / decomposition is mechanical. However, not
* all <L,V> sequences compose, and not all <LV,T> sequences
* compose.
*
* Here are the specifics:
*
* - <L>: U+1100..115F, U+A960..A97F
* - <V>: U+1160..11A7, U+D7B0..D7C7
* - <T>: U+11A8..11FF, U+D7CB..D7FB
*
* - Only the <L,V> sequences for the 11xx ranges combine.
* - Only <LV,T> sequences for T in U+11A8..11C3 combine.
*
* Here is what we want to accomplish in this shaper:
*
* - If the whole syllable can be precomposed, do that,
* - Otherwise, fully decompose and apply ljmo/vjmo/tjmo features.
* - If a valid syllable is followed by a Hangul tone mark, reorder the tone
* mark to precede the whole syllable - unless it is a zero-width glyph, in
* which case we leave it untouched, assuming it's designed to overstrike.
*
* That is, of the different possible syllables:
*
* <L>
* <L,V>
* <L,V,T>
* <LV>
* <LVT>
* <LV, T>
*
* - <L> needs no work.
*
* - <LV> and <LVT> can stay the way they are if the font supports them, otherwise we
* should fully decompose them if font supports.
*
* - <L,V> and <L,V,T> we should compose if the whole thing can be composed.
*
* - <LV,T> we should compose if the whole thing can be composed, otherwise we should
* decompose.
*/
buffer->clear_output ();
unsigned int start = 0, end = 0; /* Extent of most recently seen syllable;
* valid only if start < end
*/
unsigned int count = buffer->len;
for (buffer->idx = 0; buffer->idx < count;)
{
hb_codepoint_t u = buffer->cur().codepoint;
if (isHangulTone (u))
{
/*
* We could cache the width of the tone marks and the existence of dotted-circle,
* but the use of the Hangul tone mark characters seems to be rare enough that
* I didn't bother for now.
*/
if (start < end && end == buffer->out_len)
{
/* Tone mark follows a valid syllable; move it in front, unless it's zero width. */
buffer->next_glyph ();
if (!is_zero_width_char (font, u))
{
hb_glyph_info_t *info = buffer->out_info;
hb_glyph_info_t tone = info[end];
memmove (&info[start + 1], &info[start], (end - start) * sizeof (hb_glyph_info_t));
info[start] = tone;
}
/* Merge clusters across the (possibly reordered) syllable+tone.
* We want to merge even in the zero-width tone mark case here,
* so that clustering behavior isn't dependent on how the tone mark
* is handled by the font.
*/
buffer->merge_out_clusters (start, end + 1);
}
else
{
/* No valid syllable as base for tone mark; try to insert dotted circle. */
if (font->has_glyph (0x25cc))
{
hb_codepoint_t chars[2];
if (!is_zero_width_char (font, u)) {
chars[0] = u;
chars[1] = 0x25cc;
} else {
chars[0] = 0x25cc;
chars[1] = u;
}
buffer->replace_glyphs (1, 2, chars);
}
else
{
/* No dotted circle available in the font; just leave tone mark untouched. */
buffer->next_glyph ();
}
}
start = end = buffer->out_len;
continue;
}
start = buffer->out_len; /* Remember current position as a potential syllable start;
* will only be used if we set end to a later position.
*/
if (isL (u) && buffer->idx + 1 < count)
{
hb_codepoint_t l = u;
hb_codepoint_t v = buffer->cur(+1).codepoint;
if (isV (v))
{
/* Have <L,V> or <L,V,T>. */
hb_codepoint_t t = 0;
unsigned int tindex = 0;
if (buffer->idx + 2 < count)
{
t = buffer->cur(+2).codepoint;
if (isT (t))
tindex = t - TBase; /* Only used if isCombiningT (t); otherwise invalid. */
else
t = 0; /* The next character was not a trailing jamo. */
}
/* We've got a syllable <L,V,T?>; see if it can potentially be composed. */
if (isCombiningL (l) && isCombiningV (v) && (t == 0 || isCombiningT (t)))
{
/* Try to compose; if this succeeds, end is set to start+1. */
hb_codepoint_t s = SBase + (l - LBase) * NCount + (v - VBase) * TCount + tindex;
if (font->has_glyph (s))
{
buffer->replace_glyphs (t ? 3 : 2, 1, &s);
if (unlikely (buffer->in_error))
return;
end = start + 1;
continue;
}
}
/* We didn't compose, either because it's an Old Hangul syllable without a
* precomposed character in Unicode, or because the font didn't support the
* necessary precomposed glyph.
* Set jamo features on the individual glyphs, and advance past them.
*/
buffer->cur().hangul_shaping_feature() = LJMO;
buffer->next_glyph ();
buffer->cur().hangul_shaping_feature() = VJMO;
buffer->next_glyph ();
if (t)
{
buffer->cur().hangul_shaping_feature() = TJMO;
buffer->next_glyph ();
end = start + 3;
}
else
end = start + 2;
buffer->merge_out_clusters (start, end);
continue;
}
}
else if (isCombinedS (u))
{
/* Have <LV>, <LVT>, or <LV,T> */
hb_codepoint_t s = u;
bool has_glyph = font->has_glyph (s);
unsigned int lindex = (s - SBase) / NCount;
unsigned int nindex = (s - SBase) % NCount;
unsigned int vindex = nindex / TCount;
unsigned int tindex = nindex % TCount;
if (!tindex &&
buffer->idx + 1 < count &&
isCombiningT (buffer->cur(+1).codepoint))
{
/* <LV,T>, try to combine. */
unsigned int new_tindex = buffer->cur(+1).codepoint - TBase;
hb_codepoint_t new_s = s + new_tindex;
if (font->has_glyph (new_s))
{
buffer->replace_glyphs (2, 1, &new_s);
if (unlikely (buffer->in_error))
return;
end = start + 1;
continue;
}
}
/* Otherwise, decompose if font doesn't support <LV> or <LVT>,
* or if having non-combining <LV,T>. Note that we already handled
* combining <LV,T> above. */
if (!has_glyph ||
(!tindex &&
buffer->idx + 1 < count &&
isT (buffer->cur(+1).codepoint)))
{
hb_codepoint_t decomposed[3] = {LBase + lindex,
VBase + vindex,
TBase + tindex};
if (font->has_glyph (decomposed[0]) &&
font->has_glyph (decomposed[1]) &&
(!tindex || font->has_glyph (decomposed[2])))
{
unsigned int s_len = tindex ? 3 : 2;
buffer->replace_glyphs (1, s_len, decomposed);
if (unlikely (buffer->in_error))
return;
/* We decomposed S: apply jamo features to the individual glyphs
* that are now in buffer->out_info.
*/
hb_glyph_info_t *info = buffer->out_info;
/* If we decomposed an LV because of a non-combining T following,
* we want to include this T in the syllable.
*/
if (has_glyph && !tindex)
{
buffer->next_glyph ();
s_len++;
}
end = start + s_len;
unsigned int i = start;
info[i++].hangul_shaping_feature() = LJMO;
info[i++].hangul_shaping_feature() = VJMO;
if (i < end)
info[i++].hangul_shaping_feature() = TJMO;
buffer->merge_out_clusters (start, end);
continue;
}
}
if (has_glyph)
{
/* We didn't decompose the S, so just advance past it. */
end = start + 1;
buffer->next_glyph ();
continue;
}
}
/* Didn't find a recognizable syllable, so we leave end <= start;
* this will prevent tone-mark reordering happening.
*/
buffer->next_glyph ();
}
buffer->swap_buffers ();
}
static void
setup_masks_hangul (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font HB_UNUSED)
{
const hangul_shape_plan_t *hangul_plan = (const hangul_shape_plan_t *) plan->data;
if (likely (hangul_plan))
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++, info++)
info->mask |= hangul_plan->mask_array[info->hangul_shaping_feature()];
}
HB_BUFFER_DEALLOCATE_VAR (buffer, hangul_shaping_feature);
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
{
"hangul",
collect_features_hangul,
NULL, /* override_features */
data_create_hangul, /* data_create */
data_destroy_hangul, /* data_destroy */
preprocess_text_hangul,
HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
NULL, /* decompose */
NULL, /* compose */
setup_masks_hangul, /* setup_masks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
};

View File

@ -0,0 +1,172 @@
/*
* Copyright © 2010,2012 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
*/
#include "hb-ot-shape-complex-private.hh"
static bool
compose_hebrew (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab)
{
/* Hebrew presentation-form shaping.
* https://bugzilla.mozilla.org/show_bug.cgi?id=728866
* Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA;
* Note that some letters do not have a dagesh presForm encoded.
*/
static const hb_codepoint_t sDageshForms[0x05EA - 0x05D0 + 1] = {
0xFB30, /* ALEF */
0xFB31, /* BET */
0xFB32, /* GIMEL */
0xFB33, /* DALET */
0xFB34, /* HE */
0xFB35, /* VAV */
0xFB36, /* ZAYIN */
0x0000, /* HET */
0xFB38, /* TET */
0xFB39, /* YOD */
0xFB3A, /* FINAL KAF */
0xFB3B, /* KAF */
0xFB3C, /* LAMED */
0x0000, /* FINAL MEM */
0xFB3E, /* MEM */
0x0000, /* FINAL NUN */
0xFB40, /* NUN */
0xFB41, /* SAMEKH */
0x0000, /* AYIN */
0xFB43, /* FINAL PE */
0xFB44, /* PE */
0x0000, /* FINAL TSADI */
0xFB46, /* TSADI */
0xFB47, /* QOF */
0xFB48, /* RESH */
0xFB49, /* SHIN */
0xFB4A /* TAV */
};
bool found = c->unicode->compose (a, b, ab);
if (!found)
{
/* Special-case Hebrew presentation forms that are excluded from
* standard normalization, but wanted for old fonts. */
switch (b) {
case 0x05B4: /* HIRIQ */
if (a == 0x05D9) { /* YOD */
*ab = 0xFB1D;
found = true;
}
break;
case 0x05B7: /* patah */
if (a == 0x05F2) { /* YIDDISH YOD YOD */
*ab = 0xFB1F;
found = true;
} else if (a == 0x05D0) { /* ALEF */
*ab = 0xFB2E;
found = true;
}
break;
case 0x05B8: /* QAMATS */
if (a == 0x05D0) { /* ALEF */
*ab = 0xFB2F;
found = true;
}
break;
case 0x05B9: /* HOLAM */
if (a == 0x05D5) { /* VAV */
*ab = 0xFB4B;
found = true;
}
break;
case 0x05BC: /* DAGESH */
if (a >= 0x05D0 && a <= 0x05EA) {
*ab = sDageshForms[a - 0x05D0];
found = (*ab != 0);
} else if (a == 0xFB2A) { /* SHIN WITH SHIN DOT */
*ab = 0xFB2C;
found = true;
} else if (a == 0xFB2B) { /* SHIN WITH SIN DOT */
*ab = 0xFB2D;
found = true;
}
break;
case 0x05BF: /* RAFE */
switch (a) {
case 0x05D1: /* BET */
*ab = 0xFB4C;
found = true;
break;
case 0x05DB: /* KAF */
*ab = 0xFB4D;
found = true;
break;
case 0x05E4: /* PE */
*ab = 0xFB4E;
found = true;
break;
}
break;
case 0x05C1: /* SHIN DOT */
if (a == 0x05E9) { /* SHIN */
*ab = 0xFB2A;
found = true;
} else if (a == 0xFB49) { /* SHIN WITH DAGESH */
*ab = 0xFB2C;
found = true;
}
break;
case 0x05C2: /* SIN DOT */
if (a == 0x05E9) { /* SHIN */
*ab = 0xFB2B;
found = true;
} else if (a == 0xFB49) { /* SHIN WITH DAGESH */
*ab = 0xFB2D;
found = true;
}
break;
}
}
return found;
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
{
"hebrew",
NULL, /* collect_features */
NULL, /* override_features */
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
compose_hebrew,
NULL, /* setup_masks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
true, /* fallback_position */
};

View File

@ -1690,12 +1690,6 @@ clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
static hb_ot_shape_normalization_mode_t
normalization_preference_indic (const hb_segment_properties_t *props HB_UNUSED)
{
return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT;
}
static bool
decompose_indic (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t ab,
@ -1806,7 +1800,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
data_create_indic,
data_destroy_indic,
NULL, /* preprocess_text */
normalization_preference_indic,
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
decompose_indic,
compose_indic,
setup_masks_indic,

View File

@ -541,13 +541,6 @@ final_reordering (const hb_ot_shape_plan_t *plan,
}
static hb_ot_shape_normalization_mode_t
normalization_preference_myanmar (const hb_segment_properties_t *props HB_UNUSED)
{
return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT;
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
{
"myanmar",
@ -556,7 +549,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
normalization_preference_myanmar,
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
NULL, /* decompose */
NULL, /* compose */
setup_masks_myanmar,

View File

@ -44,7 +44,9 @@ enum hb_ot_shape_zero_width_marks_type_t {
// HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT = HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE
};
@ -52,10 +54,13 @@ enum hb_ot_shape_zero_width_marks_type_t {
#define HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS \
HB_COMPLEX_SHAPER_IMPLEMENT (default) /* should be first */ \
HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \
HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \
HB_COMPLEX_SHAPER_IMPLEMENT (hebrew) \
HB_COMPLEX_SHAPER_IMPLEMENT (indic) \
HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \
HB_COMPLEX_SHAPER_IMPLEMENT (sea) \
HB_COMPLEX_SHAPER_IMPLEMENT (thai) \
HB_COMPLEX_SHAPER_IMPLEMENT (tibetan) \
/* ^--- Add new shapers here */
@ -105,12 +110,7 @@ struct hb_ot_complex_shaper_t
hb_font_t *font);
/* normalization_preference()
* Called during shape().
* May be NULL.
*/
hb_ot_shape_normalization_mode_t
(*normalization_preference) (const hb_segment_properties_t *props);
hb_ot_shape_normalization_mode_t normalization_preference;
/* decompose()
* Called during shape()'s normalization.
@ -189,19 +189,22 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
return &_hb_ot_complex_shaper_thai;
#if 0
/* Note:
* Currently we don't have a separate Hangul shaper. The default shaper handles
* Hangul by enabling jamo features. We may want to implement a separate shaper
* in the future. See this thread for details of what such a shaper would do:
*
* http://lists.freedesktop.org/archives/harfbuzz/2013-April/003070.html
*/
/* Unicode-1.1 additions */
case HB_SCRIPT_HANGUL:
return &_hb_ot_complex_shaper_hangul;
#endif
/* Unicode-2.0 additions */
case HB_SCRIPT_TIBETAN:
return &_hb_ot_complex_shaper_tibetan;
/* Unicode-1.1 additions */
case HB_SCRIPT_HEBREW:
return &_hb_ot_complex_shaper_hebrew;
/* ^--- Add new shapers here */
@ -241,9 +244,6 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
case HB_SCRIPT_LAO:
case HB_SCRIPT_THAI:
/* Unicode-2.0 additions */
case HB_SCRIPT_TIBETAN:
/* Unicode-3.2 additions */
case HB_SCRIPT_TAGALOG:
case HB_SCRIPT_TAGBANWA:

View File

@ -360,13 +360,6 @@ final_reordering (const hb_ot_shape_plan_t *plan,
}
static hb_ot_shape_normalization_mode_t
normalization_preference_sea (const hb_segment_properties_t *props HB_UNUSED)
{
return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT;
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_sea =
{
"sea",
@ -375,7 +368,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_sea =
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
normalization_preference_sea,
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
NULL, /* decompose */
NULL, /* compose */
setup_masks_sea,

View File

@ -369,10 +369,10 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
NULL, /* data_create */
NULL, /* data_destroy */
preprocess_text_thai,
NULL, /* normalization_preference */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
false,/* fallback_position */
};

View File

@ -0,0 +1,61 @@
/*
* Copyright © 2010,2012 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
*/
#include "hb-ot-shape-complex-private.hh"
static const hb_tag_t tibetan_features[] =
{
HB_TAG('a','b','v','s'),
HB_TAG('b','l','w','s'),
HB_TAG('a','b','v','m'),
HB_TAG('b','l','w','m'),
HB_TAG_NONE
};
static void
collect_features_tibetan (hb_ot_shape_planner_t *plan)
{
for (const hb_tag_t *script_features = tibetan_features; script_features && *script_features; script_features++)
plan->map.add_global_bool_feature (*script_features);
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_tibetan =
{
"default",
collect_features_tibetan,
NULL, /* override_features */
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
true, /* fallback_position */
};

View File

@ -430,14 +430,12 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
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'));
if (!kern_mask) return;
if (!plan->has_kern) return;
unsigned int count = buffer->len;
OT::hb_apply_context_t c (1, font, buffer);
c.set_lookup_mask (kern_mask);
c.set_lookup_mask (plan->kern_mask);
c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
hb_glyph_info_t *info = buffer->info;

View File

@ -29,8 +29,6 @@
#include "hb-private.hh"
#include "hb-font.h"
#include "hb-buffer.h"
/* buffer var allocations, used during the normalization process */
#define glyph_index() var1.u32
@ -38,6 +36,7 @@
struct hb_ot_shape_plan_t;
enum hb_ot_shape_normalization_mode_t {
HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED,
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS, /* never composes base-to-base */
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, /* always fully decomposes and then recompose back */

View File

@ -213,8 +213,9 @@ decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shor
}
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, bool short_circuit)
{
/* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
hb_buffer_t * const buffer = c->buffer;
hb_font_t * const font = c->font;
for (; buffer->idx < end - 1;) {
@ -250,27 +251,26 @@ handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, uns
}
static inline void
decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end)
decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
{
hb_buffer_t * const buffer = c->buffer;
/* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
for (unsigned int i = buffer->idx; i < end; i++)
if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) {
handle_variation_selector_cluster (c, end);
handle_variation_selector_cluster (c, end, short_circuit);
return;
}
while (buffer->idx < end)
decompose_current_character (c, false);
decompose_current_character (c, short_circuit);
}
static inline void
decompose_cluster (const hb_ot_shape_normalize_context_t *c, bool short_circuit, unsigned int end)
decompose_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool might_short_circuit, bool always_short_circuit)
{
if (likely (c->buffer->idx + 1 == end))
decompose_current_character (c, short_circuit);
decompose_current_character (c, might_short_circuit);
else
decompose_multi_char_cluster (c, end);
decompose_multi_char_cluster (c, end, always_short_circuit);
}
@ -289,9 +289,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font)
{
hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference ?
plan->shaper->normalization_preference (&buffer->props) :
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT;
hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference;
const hb_ot_shape_normalize_context_t c = {
plan,
buffer,
@ -301,8 +299,10 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
plan->shaper->compose ? plan->shaper->compose : compose_unicode
};
bool short_circuit = mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED &&
mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT;
bool always_short_circuit = mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE;
bool might_short_circuit = always_short_circuit ||
(mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED &&
mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT);
unsigned int count;
/* We do a fairly straightforward yet custom normalization process in three
@ -323,7 +323,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
if (buffer->cur().cluster != buffer->info[end].cluster)
break;
decompose_cluster (&c, short_circuit, end);
decompose_cluster (&c, end, might_short_circuit, always_short_circuit);
}
buffer->swap_buffers ();
@ -355,7 +355,8 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
}
if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED)
if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE ||
mode == HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED)
return;
/* Third round, recompose */
@ -393,8 +394,9 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
return;
buffer->merge_out_clusters (starter, buffer->out_len);
buffer->out_len--; /* Remove the second composable. */
buffer->out_info[starter].codepoint = composed; /* Modify starter and carry on. */
set_glyph (buffer->out_info[starter], font);
/* Modify starter and carry on. */
buffer->out_info[starter].codepoint = composed;
buffer->out_info[starter].glyph_index() = glyph;
_hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode);
continue;

View File

@ -40,6 +40,10 @@ struct hb_ot_shape_plan_t
const struct hb_ot_complex_shaper_t *shaper;
hb_ot_map_t map;
const void *data;
hb_mask_t rtlm_mask, frac_mask, numr_mask, dnom_mask;
hb_mask_t kern_mask;
unsigned int has_frac : 1;
unsigned int has_kern : 1;
inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
{
@ -77,6 +81,17 @@ struct hb_ot_shape_planner_t
plan.props = props;
plan.shaper = shaper;
map.compile (plan.map);
plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m'));
plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c'));
plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r'));
plan.dnom_mask = plan.map.get_1_mask (HB_TAG ('d','n','o','m'));
plan.kern_mask = plan.map.get_mask (HB_DIRECTION_IS_HORIZONTAL (plan.props.direction) ?
HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n'));
plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask);
plan.has_kern = !!plan.kern_mask;
}
private:

View File

@ -88,6 +88,10 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
break;
}
map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE);
map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE);
map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE);
if (planner->shaper->collect_features)
planner->shaper->collect_features (planner);
@ -234,8 +238,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
return;
hb_codepoint_t dottedcircle_glyph;
if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph))
if (!font->has_glyph (0x25CC))
return;
hb_glyph_info_t dottedcircle;
@ -292,7 +295,7 @@ hb_ot_mirror_chars (hb_ot_shape_context_t *c)
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->rtlm_mask;
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
@ -306,13 +309,58 @@ hb_ot_mirror_chars (hb_ot_shape_context_t *c)
}
static inline void
hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
{
if (!c->plan->has_frac)
return;
hb_buffer_t *buffer = c->buffer;
/* TODO look in pre/post context text also. */
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
{
if (info[i].codepoint == 0x2044) /* FRACTION SLASH */
{
unsigned int start = i, end = i + 1;
while (start &&
_hb_glyph_info_get_general_category (&info[start - 1]) ==
HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
start--;
while (end < count &&
_hb_glyph_info_get_general_category (&info[end]) ==
HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
end++;
for (unsigned int j = start; j < i; j++)
info[j].mask |= c->plan->numr_mask | c->plan->frac_mask;
info[i].mask |= c->plan->frac_mask;
for (unsigned int j = i + 1; j < end; j++)
info[j].mask |= c->plan->frac_mask | c->plan->dnom_mask;
i = end - 1;
}
}
}
static inline void
hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c)
{
hb_ot_map_t *map = &c->plan->map;
hb_buffer_t *buffer = c->buffer;
hb_mask_t global_mask = map->get_global_mask ();
buffer->reset_masks (global_mask);
}
static inline void
hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
{
hb_ot_map_t *map = &c->plan->map;
hb_buffer_t *buffer = c->buffer;
hb_ot_shape_setup_masks_fraction (c);
if (c->plan->shaper->setup_masks)
c->plan->shaper->setup_masks (c->plan, buffer, c->font);
@ -358,6 +406,8 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c)
if (c->plan->shaper->preprocess_text)
c->plan->shaper->preprocess_text (c->plan, buffer, c->font);
hb_ot_shape_initialize_masks (c);
hb_ot_mirror_chars (c);
HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);

View File

@ -0,0 +1,54 @@
/*
* Copyright © 2013 Red Hat, 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.
*
* Red Hat Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_SHAPE_H
#define HB_OT_SHAPE_H
#define HB_OT_SHAPE_H_IN
#include "hb.h"
#include "hb-ot-layout.h"
#include "hb-ot-tag.h"
HB_BEGIN_DECLS
/* TODO port to shape-plan / set. */
void
hb_ot_shape_glyphs_closure (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
hb_set_t *glyphs);
void
hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
hb_tag_t table_tag,
hb_set_t *lookup_indexes /* OUT */);
HB_END_DECLS
#undef HB_OT_SHAPE_H_IN
#endif /* HB_OT_SHAPE_H */

View File

@ -27,7 +27,6 @@
*/
#include "hb-private.hh"
#include "hb-ot.h"
#include <string.h>

View File

@ -32,17 +32,10 @@
#include "hb-ot-layout.h"
#include "hb-ot-tag.h"
#include "hb-ot-shape.h"
HB_BEGIN_DECLS
/* TODO remove */
void
hb_ot_shape_glyphs_closure (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
hb_set_t *glyphs);
HB_END_DECLS
#undef HB_OT_H_IN

View File

@ -807,6 +807,12 @@ hb_in_range (T u, T lo, T hi)
return lo <= u && u <= hi;
}
template <typename T> static inline bool
hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
{
return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
}
template <typename T> static inline bool
hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
{

View File

@ -28,7 +28,6 @@
#define HB_SET_PRIVATE_HH
#include "hb-private.hh"
#include "hb-set.h"
#include "hb-object-private.hh"

View File

@ -28,7 +28,6 @@
#define HB_SHAPE_PLAN_PRIVATE_HH
#include "hb-private.hh"
#include "hb-shape-plan.h"
#include "hb-object-private.hh"
#include "hb-shaper-private.hh"

View File

@ -52,4 +52,6 @@ HB_SHAPER_IMPLEMENT (uniscribe)
HB_SHAPER_IMPLEMENT (coretext)
#endif
#ifdef HAVE_FALLBACK
HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */
#endif

View File

@ -31,8 +31,6 @@
#include "hb-ot-hhea-table.hh"
#include "hb-ot-hmtx-table.hh"
#include "hb-blob.h"
#include <string.h>

View File

@ -32,8 +32,6 @@
#define HB_UNICODE_PRIVATE_HH
#include "hb-private.hh"
#include "hb-unicode.h"
#include "hb-object-private.hh"
@ -108,7 +106,11 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
modified_combining_class (hb_codepoint_t unicode)
{
/* XXX This hack belongs to the Myanmar shaper. */
if (unicode == 0x1037) unicode = 0x103A;
if (unlikely (unicode == 0x1037)) unicode = 0x103A;
/* XXX This hack belongs to the SEA shaper (for Tai Tham):
* Reorder SAKOT to ensure it comes after any tone marks. */
if (unlikely (unicode == 0x1A60)) return 254;
return _hb_modified_combining_class[combining_class (unicode)];
}
@ -132,10 +134,10 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
* 6.3 is also added manually. The new Unicode 6.3 bidi formatting
* characters are encoded in a block that was Default_Ignorable already.
*
* Note: While U+115F and U+1160 are Default_Ignorable, we do NOT want to
* hide them, as the way Uniscribe has implemented them is with regular
* spacing glyphs, and that's the way fonts are made to work. As such,
* we make exceptions for those two.
* Note: While U+115F, U+1160, U+3164 and U+FFA0 are Default_Ignorable,
* we do NOT want to hide them, as the way Uniscribe has implemented them
* is with regular spacing glyphs, and that's the way fonts are made to work.
* As such, we make exceptions for those four.
*
* Gathered from:
* http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:DI:]&abb=on&ucd=on&esc=on
@ -157,10 +159,10 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
* 200B..200F ;RIGHT-TO-LEFT MARK
* 202A..202E ;RIGHT-TO-LEFT OVERRIDE
* 2060..206F ;NOMINAL DIGIT SHAPES
* 3164 ;HANGUL FILLER
* #3164 ;HANGUL FILLER
* FE00..FE0F ;VARIATION SELECTOR-16
* FEFF ;ZERO WIDTH NO-BREAK SPACE
* FFA0 ;HALFWIDTH HANGUL FILLER
* #FFA0 ;HALFWIDTH HANGUL FILLER
* FFF0..FFF8 ;<unassigned-FFF8>
* 1D173..1D17A ;MUSICAL SYMBOL END PHRASE
* E0000..E0FFF ;<unassigned-E0FFF>
@ -182,9 +184,8 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
case 0x20: return hb_in_ranges<hb_codepoint_t> (ch, 0x200B, 0x200F,
0x202A, 0x202E,
0x2060, 0x206F);
case 0x31: return unlikely (ch == 0x3164);
case 0xFE: return hb_in_range<hb_codepoint_t> (ch, 0xFE00, 0xFE0F) || ch == 0xFEFF;
case 0xFF: return hb_in_range<hb_codepoint_t> (ch, 0xFFF0, 0xFFF8) || ch == 0xFFA0;
case 0xFF: return hb_in_range<hb_codepoint_t> (ch, 0xFFF0, 0xFFF8);
default: return false;
}
}

View File

@ -709,7 +709,7 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan,
for (unsigned int i = 0; i < range_records.len; i++)
{
range_record_t *range = &range_records[i];
range->props.potfRecords = feature_records.array + reinterpret_cast<unsigned int> (range->props.potfRecords);
range->props.potfRecords = feature_records.array + reinterpret_cast<uintptr_t> (range->props.potfRecords);
}
}
else
@ -776,13 +776,14 @@ retry:
}
}
/* All the following types are sized in multiples of sizeof(int). */
unsigned int glyphs_size = scratch_size / ((sizeof (WORD) +
sizeof (SCRIPT_GLYPHPROP) +
sizeof (int) +
sizeof (GOFFSET) +
sizeof (uint32_t))
/ sizeof (int));
/* The -2 in the following is to compensate for possible
* alignment needed after the WORD array. sizeof(WORD) == 2. */
unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
/ (sizeof (WORD) +
sizeof (SCRIPT_GLYPHPROP) +
sizeof (int) +
sizeof (GOFFSET) +
sizeof (uint32_t));
ALLOCATE_ARRAY (WORD, glyphs, glyphs_size);
ALLOCATE_ARRAY (SCRIPT_GLYPHPROP, glyph_props, glyphs_size);

View File

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

View File

@ -12,6 +12,7 @@ EXPORTS.harfbuzz += [
'hb-face.h',
'hb-font.h',
'hb-ot-layout.h',
'hb-ot-shape.h',
'hb-ot-tag.h',
'hb-ot.h',
'hb-set.h',
@ -25,6 +26,7 @@ EXPORTS.harfbuzz += [
SOURCES += [
'hb-blob.cc', # error: use of undeclared identifier 'snprintf' (FreeBSD)
'hb-common.cc', # error: use of undeclared identifier 'strdup'
'hb-ot-shape-complex-hangul.cc', # error: redefinition of enumerator 'NONE'
'hb-ot-shape-complex-indic.cc', # error: redefinition of enumerator 'INIT'
'hb-ot-shape-complex-sea.cc', # error: redefinition of 'basic_features'
'hb-ot-shape.cc', # error: functions that differ only in their return type cannot be overloaded
@ -40,9 +42,11 @@ UNIFIED_SOURCES += [
'hb-ot-map.cc',
'hb-ot-shape-complex-arabic.cc',
'hb-ot-shape-complex-default.cc',
'hb-ot-shape-complex-hebrew.cc',
'hb-ot-shape-complex-indic-table.cc',
'hb-ot-shape-complex-myanmar.cc',
'hb-ot-shape-complex-thai.cc',
'hb-ot-shape-complex-tibetan.cc',
'hb-ot-shape-fallback.cc',
'hb-ot-shape-normalize.cc',
'hb-ot-tag.cc',