From a5a72e004bb7123445c2c3a94352d358fc80d904 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 21 May 2010 15:12:52 +0100 Subject: [PATCH 1/6] Add hb-ot-shape.h, oops. --- src/hb-ot-shape.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/hb-ot-shape.h diff --git a/src/hb-ot-shape.h b/src/hb-ot-shape.h new file mode 100644 index 000000000..6d6a3beb4 --- /dev/null +++ b/src/hb-ot-shape.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010 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 + +#include "hb-shape.h" + + +HB_BEGIN_DECLS + +void +hb_ot_shape (hb_font_t *font, + hb_face_t *face, + hb_buffer_t *buffer, + hb_feature_t *features, + unsigned int num_features); + +HB_END_DECLS + +#endif /* HB_OT_SHAPE_PRIVATE_H */ From 0375bdd2027767ee7bebef1ed289b33dc64f430e Mon Sep 17 00:00:00 2001 From: Martin Hosken Date: Fri, 21 May 2010 15:01:37 +0100 Subject: [PATCH 2/6] Rename classes from Grxxx to HbGrxxx --- src/hb-graphite.cc | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/hb-graphite.cc b/src/hb-graphite.cc index 1b887f4ea..168c73d86 100644 --- a/src/hb-graphite.cc +++ b/src/hb-graphite.cc @@ -46,10 +46,10 @@ typedef struct _featureSetting { int value; } featureSetting; -class GrBufferTextSrc : public gr::ITextSource +class HbGrBufferTextSrc : public gr::ITextSource { public: - GrBufferTextSrc(hb_buffer_t *buff, hb_feature_t *feats, unsigned int num_features) + HbGrBufferTextSrc(hb_buffer_t *buff, hb_feature_t *feats, unsigned int num_features) { hb_feature_t *aFeat = feats; featureSetting *aNewFeat; @@ -64,7 +64,7 @@ public: aNewFeat->value = aFeat->value; } }; - ~GrBufferTextSrc() { hb_buffer_destroy(buffer); delete[] features; }; + ~HbGrBufferTextSrc() { hb_buffer_destroy(buffer); delete[] features; }; virtual gr::UtfType utfEncodingForm() { return gr::kutf32; }; virtual size_t getLength() { return buffer->len; }; virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf32 * prgchBuffer) @@ -120,12 +120,12 @@ private: unsigned int nFeatures; }; -class GrHbFont : public gr::Font +class HbGrFont : public gr::Font { public: - GrHbFont(hb_font_t *font, hb_face_t *face) : gr::Font() + HbGrFont(hb_font_t *font, hb_face_t *face) : gr::Font() { m_font = hb_font_reference(font); m_face = hb_face_reference(face); initfont(); }; - ~GrHbFont() + ~HbGrFont() { std::map::iterator p = m_blobs.begin(); while (p != m_blobs.end()) @@ -133,7 +133,7 @@ public: hb_font_destroy(m_font); hb_face_destroy(m_face); }; - GrHbFont (const GrHbFont &font) : gr::Font(font) + HbGrFont (const HbGrFont &font) : gr::Font(font) { *this = font; m_blobs = std::map(font.m_blobs); @@ -142,7 +142,7 @@ public: hb_font_reference(m_font); hb_face_reference(m_face); }; - virtual GrHbFont *copyThis() { return new GrHbFont(*this); }; + virtual HbGrFont *copyThis() { return new HbGrFont(*this); }; virtual bool bold() { return m_bold; }; virtual bool italic() { return m_italic; }; virtual float ascent() { float asc; getFontMetrics(&asc, NULL, NULL); return asc; }; @@ -210,7 +210,7 @@ private: std::map m_blobs; }; -void GrHbFont::initfont() +void HbGrFont::initfont() { const void *pOS2 = getTable(gr::kttiOs2, NULL); const void *pHead = getTable(gr::kttiHead, NULL); @@ -228,10 +228,10 @@ hb_graphite_shape (hb_font_t *font, unsigned int num_features) { /* create text source */ - GrBufferTextSrc textSrc(buffer, features, num_features); + HbGrBufferTextSrc textSrc(buffer, features, num_features); /* create grfont */ - GrHbFont grfont(font, face); + HbGrFont grfont(font, face); /* create segment */ int *firsts; From dd22a8f7bfd424a69286e90f79d2a23af6e89ec1 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 21 May 2010 16:43:17 +0100 Subject: [PATCH 3/6] Add note --- src/hb-ot-layout-gsub-private.hh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hb-ot-layout-gsub-private.hh b/src/hb-ot-layout-gsub-private.hh index d64c0958a..9af5b63f3 100644 --- a/src/hb-ot-layout-gsub-private.hh +++ b/src/hb-ot-layout-gsub-private.hh @@ -286,6 +286,7 @@ struct AlternateSubstFormat1 if (unlikely (!alt_set.len)) return false; + /* Note: This breaks badly if two features enabled this lookup together. */ unsigned int shift = _hb_ctz (lookup_mask); unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift); From 1ce7b87c4d8d1ab3ec1d5198351d71b7199f7c64 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 21 May 2010 17:31:45 +0100 Subject: [PATCH 4/6] Cleanup bitmask allocation --- src/hb-buffer-private.hh | 16 +++++++++++ src/hb-buffer.cc | 36 ++++++++++++++++++++++++ src/hb-ot-shape.cc | 60 +++++++++++++++++----------------------- 3 files changed, 78 insertions(+), 34 deletions(-) diff --git a/src/hb-buffer-private.hh b/src/hb-buffer-private.hh index d89762723..d05322b8d 100644 --- a/src/hb-buffer-private.hh +++ b/src/hb-buffer-private.hh @@ -94,6 +94,15 @@ HB_INTERNAL void _hb_buffer_next_glyph (hb_buffer_t *buffer); +HB_INTERNAL void +_hb_buffer_clear_masks (hb_buffer_t *buffer); + +HB_INTERNAL void +_hb_buffer_or_masks (hb_buffer_t *buffer, + hb_mask_t mask, + unsigned int cluster_start, + unsigned int cluster_end); + struct _hb_buffer_t { hb_reference_count_t ref_count; @@ -147,6 +156,13 @@ struct _hb_buffer_t { unsigned short ligID = 0xFFFF) { _hb_buffer_add_output_glyph (this, glyph_index, component, ligID); } inline void replace_glyph (hb_codepoint_t glyph_index) { add_output_glyph (glyph_index); } + + inline void clear_masks (void) { _hb_buffer_clear_masks (this); } + inline void or_masks (hb_mask_t mask, + unsigned int cluster_start, + unsigned int cluster_end) + { _hb_buffer_or_masks (this, mask, cluster_start, cluster_end); } + }; diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc index 0b77919be..c20de778e 100644 --- a/src/hb-buffer.cc +++ b/src/hb-buffer.cc @@ -457,6 +457,42 @@ _hb_buffer_next_glyph (hb_buffer_t *buffer) buffer->i++; } +void +_hb_buffer_clear_masks (hb_buffer_t *buffer) +{ + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + buffer->info[i].mask = 1; +} + +void +_hb_buffer_or_masks (hb_buffer_t *buffer, + hb_mask_t mask, + unsigned int cluster_start, + unsigned int cluster_end) +{ + if (cluster_start == 0 && cluster_end == (unsigned int)-1) { + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + buffer->info[i].mask |= mask; + return; + } + + /* Binary search to find the start position and go from there. */ + unsigned int min = 0, max = buffer->len; + while (min < max) + { + unsigned int mid = min + ((max - min) / 2); + if (buffer->info[mid].cluster < cluster_start) + min = mid + 1; + else + max = mid; + } + unsigned int count = buffer->len; + for (unsigned int i = min; i < count && buffer->info[i].cluster < cluster_end; i++) + buffer->info[i].mask |= mask; +} + /* Public API again */ diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc index 3d8966c33..411087b51 100644 --- a/src/hb-ot-shape.cc +++ b/src/hb-ot-shape.cc @@ -117,54 +117,46 @@ setup_lookups (hb_face_t *face, } /* Clear buffer masks. */ - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - buffer->info[i].mask = 1; + buffer->clear_masks (); - unsigned int last_bit_used = 1; - unsigned int global_values = 0; + unsigned int next_bit = 1; + hb_mask_t global_mask = 0; for (i = 0; i < num_features; i++) { + hb_feature_t *feature = &features[i]; if (!hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index, - features[i].tag, + feature->tag, &feature_index)) continue; - unsigned int bits_needed = _hb_bit_storage (features[i].value); - if (!bits_needed) + if (feature->value == 1 && feature->start == 0 && feature->end == (unsigned int) -1) { + add_feature (face, table_tag, feature_index, 1, lookups, num_lookups, room_lookups); continue; - unsigned int mask = (1 << (last_bit_used + bits_needed)) - (1 << last_bit_used); - unsigned int value = features[i].value << last_bit_used; - last_bit_used += bits_needed; + } + + /* Allocate bits for the features */ + + unsigned int bits_needed = _hb_bit_storage (feature->value); + if (!bits_needed) + continue; /* Feature disabled */ + + if (next_bit + bits_needed > 8 * sizeof (hb_mask_t)) + continue; /* Oh well... */ + + unsigned int mask = (1 << (next_bit + bits_needed)) - (1 << next_bit); + unsigned int value = feature->value << next_bit; + next_bit += bits_needed; add_feature (face, table_tag, feature_index, mask, lookups, num_lookups, room_lookups); - if (features[i].start == 0 && features[i].end == (unsigned int)-1) - global_values |= value; + if (feature->start == 0 && feature->end == (unsigned int) -1) + global_mask |= value; else - { - unsigned int start = features[i].start, end = features[i].end; - unsigned int a = 0, b = buffer->len; - while (a < b) - { - unsigned int h = a + ((b - a) / 2); - if (buffer->info[h].cluster < start) - a = h + 1; - else - b = h; - } - unsigned int count = buffer->len; - for (unsigned int j = a; j < count && buffer->info[j].cluster < end; j++) - buffer->info[j].mask |= value; - } + buffer->or_masks (mask, feature->start, feature->end); } - if (global_values) - { - unsigned int count = buffer->len; - for (unsigned int j = 0; j < count; j++) - buffer->info[j].mask |= global_values; - } + if (global_mask) + buffer->or_masks (global_mask, 0, (unsigned int) -1); qsort (lookups, *num_lookups, sizeof (lookups[0]), cmp_lookups); From 074ea787493a37ae8f68d17be7820f13fff57520 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 21 May 2010 17:53:10 +0100 Subject: [PATCH 5/6] Add ltra, ltrm, and rtla features --- src/hb-ot-shape.cc | 60 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc index 411087b51..0452f8e4c 100644 --- a/src/hb-ot-shape.cc +++ b/src/hb-ot-shape.cc @@ -74,6 +74,28 @@ add_feature (hb_face_t *face, } } +static hb_bool_t +maybe_add_feature (hb_face_t *face, + hb_tag_t table_tag, + unsigned int script_index, + unsigned int language_index, + hb_tag_t feature_tag, + hb_mask_t mask, + lookup_map *lookups, + unsigned int *num_lookups, + unsigned int room_lookups) +{ + unsigned int feature_index; + if (hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index, + feature_tag, + &feature_index)) + { + add_feature (face, table_tag, feature_index, mask, lookups, num_lookups, room_lookups); + return TRUE; + } + return FALSE; +} + static int cmp_lookups (const void *p1, const void *p2) { @@ -90,7 +112,8 @@ setup_lookups (hb_face_t *face, unsigned int num_features, hb_tag_t table_tag, lookup_map *lookups, - unsigned int *num_lookups) + unsigned int *num_lookups, + hb_direction_t original_direction) { unsigned int i, j, script_index, language_index, feature_index, room_lookups; @@ -109,11 +132,20 @@ setup_lookups (hb_face_t *face, add_feature (face, table_tag, feature_index, 1, lookups, num_lookups, room_lookups); for (i = 0; i < ARRAY_LENGTH (default_features); i++) - { - if (hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index, - default_features[i], - &feature_index)) - add_feature (face, table_tag, feature_index, 1, lookups, num_lookups, room_lookups); + maybe_add_feature (face, table_tag, script_index, language_index, default_features[i], 1, lookups, num_lookups, room_lookups); + + switch (original_direction) { + case HB_DIRECTION_LTR: + maybe_add_feature (face, table_tag, script_index, language_index, HB_TAG ('l','t','r','a'), 1, lookups, num_lookups, room_lookups); + maybe_add_feature (face, table_tag, script_index, language_index, HB_TAG ('l','t','r','m'), 1, lookups, num_lookups, room_lookups); + break; + case HB_DIRECTION_RTL: + maybe_add_feature (face, table_tag, script_index, language_index, HB_TAG ('r','t','l','a'), 1, lookups, num_lookups, room_lookups); + break; + case HB_DIRECTION_TTB: + case HB_DIRECTION_BTT: + default: + break; } /* Clear buffer masks. */ @@ -178,7 +210,8 @@ hb_ot_substitute_complex (hb_font_t *font HB_UNUSED, hb_face_t *face, hb_buffer_t *buffer, hb_feature_t *features, - unsigned int num_features) + unsigned int num_features, + hb_direction_t original_direction) { lookup_map lookups[1000]; unsigned int num_lookups = ARRAY_LENGTH (lookups); @@ -189,7 +222,8 @@ hb_ot_substitute_complex (hb_font_t *font HB_UNUSED, setup_lookups (face, buffer, features, num_features, HB_OT_TAG_GSUB, - lookups, &num_lookups); + lookups, &num_lookups, + original_direction); for (i = 0; i < num_lookups; i++) hb_ot_layout_substitute_lookup (face, buffer, lookups[i].index, lookups[i].mask); @@ -202,7 +236,8 @@ hb_ot_position_complex (hb_font_t *font, hb_face_t *face, hb_buffer_t *buffer, hb_feature_t *features, - unsigned int num_features) + unsigned int num_features, + hb_direction_t original_direction) { lookup_map lookups[1000]; unsigned int num_lookups = ARRAY_LENGTH (lookups); @@ -213,7 +248,8 @@ hb_ot_position_complex (hb_font_t *font, setup_lookups (face, buffer, features, num_features, HB_OT_TAG_GPOS, - lookups, &num_lookups); + lookups, &num_lookups, + original_direction); for (i = 0; i < num_lookups; i++) hb_ot_layout_position_lookup (font, face, buffer, lookups[i].index, lookups[i].mask); @@ -401,14 +437,14 @@ hb_ot_shape (hb_font_t *font, * see the original direction. */ original_direction = hb_ensure_native_direction (buffer); - substitute_fallback = !hb_ot_substitute_complex (font, face, buffer, features, num_features); + substitute_fallback = !hb_ot_substitute_complex (font, face, buffer, features, num_features, original_direction); if (substitute_fallback) hb_substitute_complex_fallback (font, face, buffer, features, num_features); hb_position_default (font, face, buffer, features, num_features); - position_fallback = !hb_ot_position_complex (font, face, buffer, features, num_features); + position_fallback = !hb_ot_position_complex (font, face, buffer, features, num_features, original_direction); if (position_fallback) hb_position_complex_fallback (font, face, buffer, features, num_features); From 1094a294f6a44c47fc75867983f2b135a6442bab Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 21 May 2010 17:58:20 +0100 Subject: [PATCH 6/6] Add rtlm --- src/hb-ot-shape.cc | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc index 0452f8e4c..8b1863cae 100644 --- a/src/hb-ot-shape.cc +++ b/src/hb-ot-shape.cc @@ -42,6 +42,12 @@ hb_tag_t default_features[] = { HB_TAG('m','k','m','k'), }; +enum { + MASK_ALWAYS_ON = 1 << 0, + MASK_RTLM = 1 << 1 +}; +#define MASK_BITS_USED 2 + struct lookup_map { unsigned int index; hb_mask_t mask; @@ -148,10 +154,7 @@ setup_lookups (hb_face_t *face, break; } - /* Clear buffer masks. */ - buffer->clear_masks (); - - unsigned int next_bit = 1; + unsigned int next_bit = MASK_BITS_USED; hb_mask_t global_mask = 0; for (i = 0; i < num_features; i++) { @@ -310,7 +313,11 @@ hb_mirror_chars (hb_buffer_t *buffer) unsigned int count = buffer->len; for (unsigned int i = 0; i < count; i++) { - buffer->info[i].codepoint = get_mirroring (buffer->info[i].codepoint); + hb_codepoint_t codepoint = get_mirroring (buffer->info[i].codepoint); + if (likely (codepoint == buffer->info[i].codepoint)) + buffer->info[i].mask |= MASK_RTLM; + else + buffer->info[i].codepoint = codepoint; } } @@ -431,6 +438,10 @@ hb_ot_shape (hb_font_t *font, hb_form_clusters (buffer); + /* SUBSTITUTE */ + + buffer->clear_masks (); + hb_substitute_default (font, face, buffer, features, num_features); /* We do this after substitute_default because mirroring needs to @@ -442,6 +453,11 @@ hb_ot_shape (hb_font_t *font, if (substitute_fallback) hb_substitute_complex_fallback (font, face, buffer, features, num_features); + + /* POSITION */ + + buffer->clear_masks (); + hb_position_default (font, face, buffer, features, num_features); position_fallback = !hb_ot_position_complex (font, face, buffer, features, num_features, original_direction);