[HarfBuzz] harfbuzz: Branch 'master' - 7 commits

Behdad Esfahbod behdad at kemper.freedesktop.org
Tue Sep 11 08:48:09 UTC 2018


 src/hb-ot-layout-gsub-table.hh                                                |    7 +++++
 src/hb-ot-layout-gsubgpos.hh                                                  |   11 +++++++--
 src/hb-ot-layout.cc                                                           |    5 ++++
 src/hb-ot-map.cc                                                              |   12 ++++++----
 src/hb-ot-map.hh                                                              |   11 +++++++--
 src/hb-ot-shape.cc                                                            |    7 +++++
 test/shaping/data/in-house/Makefile.sources                                   |    1 
 test/shaping/data/in-house/fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf |binary
 test/shaping/data/in-house/tests/rand.tests                                   |    3 ++
 9 files changed, 48 insertions(+), 9 deletions(-)

New commits:
commit 71c9f84e7c0afe41a8987b8a4ebc2b45a22fac56
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Sep 10 22:37:19 2018 +0200

    Make --features rand=1 available to the user
    
    Use rand=255 to mean "randomize".
    
    Part of https://github.com/harfbuzz/harfbuzz/pull/803

diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 255a2827..dfa50979 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -541,18 +541,15 @@ struct AlternateSet
     unsigned int shift = hb_ctz (lookup_mask);
     unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
 
-    if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
-
-    /* This is ugly...  If alt_index is 1, we take it as "on", and randomize
-     * feature if it is the rand feature.  If it's > 1, it's a user-set value
-     * for sure, so respect it.  So, user cannot set rand=1 and expect it to
-     * choose the first alternate... */
-    if (alt_index == 1 && c->random)
+    /* If alt_index is MAX, randomize feature if it is the rand feature. */
+    if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
     {
       c->random_state = (0x5DEECE66Dull * c->random_state + 11) & (((uint64_t) 1 << 48) - 1);
       alt_index = (c->random_state >> 32) % count + 1;
     }
 
+    if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
+
     c->replace_glyph (alternates[alt_index - 1]);
 
     return_trace (true);
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index df032264..be1b449c 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -33,6 +33,7 @@
 #include "hb-buffer.hh"
 #include "hb-map.hh"
 #include "hb-set.hh"
+#include "hb-ot-map.hh"
 #include "hb-ot-layout-common.hh"
 #include "hb-ot-layout-gdef-table.hh"
 
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index 8617f054..cb70583f 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -210,8 +210,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t  &m,
       /* Uses the global bit */
       bits_needed = 0;
     else
-      /* Limit to 8 bits per feature. */
-      bits_needed = MIN(8u, hb_bit_storage (info->max_value));
+      /* Limit bits per feature. */
+      bits_needed = MIN(HB_OT_MAP_MAX_BITS, hb_bit_storage (info->max_value));
 
     if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
       continue; /* Feature disabled, or not enough bits. */
diff --git a/src/hb-ot-map.hh b/src/hb-ot-map.hh
index 091cb3b6..cc36fa27 100644
--- a/src/hb-ot-map.hh
+++ b/src/hb-ot-map.hh
@@ -32,6 +32,9 @@
 #include "hb-buffer.hh"
 
 
+#define HB_OT_MAP_MAX_BITS 8u
+#define HB_OT_MAP_MAX_VALUE ((1u << HB_OT_MAP_MAX_BITS) - 1u)
+
 struct hb_ot_shape_plan_t;
 
 static const hb_tag_t table_tags[2] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS};
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 00a8a647..437b0feb 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -96,7 +96,7 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
   map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE);
 
   /* Random! */
-  map->add_feature (HB_TAG ('r','a','n','d'), 1, F_GLOBAL | F_RANDOM);
+  map->add_feature (HB_TAG ('r','a','n','d'), HB_OT_MAP_MAX_VALUE, F_GLOBAL | F_RANDOM);
 
   if (planner->shaper->collect_features)
     planner->shaper->collect_features (planner);
commit cc1c4fdf88f6953dcd07fb42ee963404657cdef4
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Sep 10 16:36:05 2018 +0200

    Respect user's wish if they set rand feature manually
    
    Except if the set it to 1, which would mean "randomize"... Ugly.

diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index ae679441..255a2827 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -534,25 +534,27 @@ struct AlternateSet
 
     if (unlikely (!count)) return_trace (false);
 
-    if (c->random)
-    {
-      c->random_state = (0x5DEECE66Dull * c->random_state + 11) & (((uint64_t) 1 << 48) - 1);
-      c->replace_glyph (alternates[(c->random_state >> 32) % count]);
-    }
-    else
-    {
-      hb_mask_t glyph_mask = c->buffer->cur().mask;
-      hb_mask_t lookup_mask = c->lookup_mask;
+    hb_mask_t glyph_mask = c->buffer->cur().mask;
+    hb_mask_t lookup_mask = c->lookup_mask;
 
-      /* 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);
+    /* 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);
 
-      if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
+    if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
 
-      c->replace_glyph (alternates[alt_index - 1]);
+    /* This is ugly...  If alt_index is 1, we take it as "on", and randomize
+     * feature if it is the rand feature.  If it's > 1, it's a user-set value
+     * for sure, so respect it.  So, user cannot set rand=1 and expect it to
+     * choose the first alternate... */
+    if (alt_index == 1 && c->random)
+    {
+      c->random_state = (0x5DEECE66Dull * c->random_state + 11) & (((uint64_t) 1 << 48) - 1);
+      alt_index = (c->random_state >> 32) % count + 1;
     }
 
+    c->replace_glyph (alternates[alt_index - 1]);
+
     return_trace (true);
   }
 
commit 80de4bcd2677bfb0907ea7059524f918b109ac37
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Sep 10 16:24:52 2018 +0200

    Minor clean up of 'rand' patchset

diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index db24a284..ae679441 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -534,10 +534,13 @@ struct AlternateSet
 
     if (unlikely (!count)) return_trace (false);
 
-    if (c->random) {
+    if (c->random)
+    {
       c->random_state = (0x5DEECE66Dull * c->random_state + 11) & (((uint64_t) 1 << 48) - 1);
       c->replace_glyph (alternates[(c->random_state >> 32) % count]);
-    } else {
+    }
+    else
+    {
       hb_mask_t glyph_mask = c->buffer->cur().mask;
       hb_mask_t lookup_mask = c->lookup_mask;
 
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index 3a028f34..df032264 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -478,11 +478,12 @@ struct hb_ot_apply_context_t :
   unsigned int nesting_level_left;
   unsigned int debug_depth;
 
+  bool has_glyph_classes;
   bool auto_zwnj;
   bool auto_zwj;
   bool random;
+
   uint64_t random_state;
-  bool has_glyph_classes;
 
 
   hb_ot_apply_context_t (unsigned int table_index_,
@@ -500,11 +501,11 @@ struct hb_ot_apply_context_t :
 			lookup_props (0),
 			nesting_level_left (HB_MAX_NESTING_LEVEL),
 			debug_depth (0),
+			has_glyph_classes (gdef.has_glyph_classes ()),
 			auto_zwnj (true),
 			auto_zwj (true),
 			random (false),
-			random_state (1),
-			has_glyph_classes (gdef.has_glyph_classes ()) {}
+			random_state (1) {}
 
   inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
   inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 0007e0ab..00a8a647 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -70,7 +70,6 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
 			      unsigned int                    num_user_features)
 {
   hb_ot_map_builder_t *map = &planner->map;
-  bool default_rand = true;
 
   map->add_global_bool_feature (HB_TAG('r','v','r','n'));
   map->add_gsub_pause (nullptr);
@@ -91,10 +90,14 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
       break;
   }
 
+  /* Automatic fractions. */
   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);
 
+  /* Random! */
+  map->add_feature (HB_TAG ('r','a','n','d'), 1, F_GLOBAL | F_RANDOM);
+
   if (planner->shaper->collect_features)
     planner->shaper->collect_features (planner);
 
@@ -118,17 +121,13 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
   if (planner->shaper->override_features)
     planner->shaper->override_features (planner);
 
-  for (unsigned int i = 0; i < num_user_features; i++) {
+  for (unsigned int i = 0; i < num_user_features; i++)
+  {
     const hb_feature_t *feature = &user_features[i];
     map->add_feature (feature->tag, feature->value,
 		      (feature->start == 0 && feature->end == (unsigned int) -1) ?
 		       F_GLOBAL : F_NONE);
-    if (feature->tag == HB_TAG ('r','a','n','d'))
-      default_rand = false;
   }
-
-  if (default_rand)
-    map->add_feature (HB_TAG ('r','a','n','d'), 1, F_GLOBAL | F_RANDOM);
 }
 
 
diff --git a/test/shaping/data/in-house/tests/rand.tests b/test/shaping/data/in-house/tests/rand.tests
index 781abf42..5ea0fc04 100644
--- a/test/shaping/data/in-house/tests/rand.tests
+++ b/test/shaping/data/in-house/tests/rand.tests
@@ -1,3 +1,3 @@
 ../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names --features=-rand:U+0054,U+0055,U+0056:[1=0+560|2=1+602|3=2+602]
-../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names --features=rand=2:U+0054,U+0055,U+0056:[5=0+560|8=1+602|11=2+602]
+#../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names --features=rand=2:U+0054,U+0055,U+0056:[5=0+560|8=1+602|11=2+602]
 ../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names:U+0054,U+0055,U+0056,U+0054,U+0055,U+0056,U+0054,U+0055,U+0056,U+0054,U+0055,U+0056:[6=0+560|9=1+602|10=2+602|6=3+560|9=4+602|12=5+602|5=6+560|8=7+602|11=8+602|6=9+560|8=10+602|10=11+602]
commit b545e27d8891f1e7f1fd034dd84abe44c839c380
Author: David Corbett <corbett.dav at husky.neu.edu>
Date:   Fri Feb 23 12:22:32 2018 -0500

    Don't seed the RNG from the contents of the buffer

diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index 113433d9..3a028f34 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -503,16 +503,13 @@ struct hb_ot_apply_context_t :
 			auto_zwnj (true),
 			auto_zwj (true),
 			random (false),
-			random_state (0),
+			random_state (1),
 			has_glyph_classes (gdef.has_glyph_classes ()) {}
 
   inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
   inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
   inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; }
-  inline void set_random_state (uint64_t random_state_) {
-    random = true;
-    random_state = random_state_;
-  }
+  inline void set_random (bool random_) { random = random_; }
   inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
   inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
   inline void set_lookup_props (unsigned int lookup_props_)
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index b31dbbca..51c11985 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -1270,10 +1270,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
       c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
       if (lookups[table_index][i].random)
       {
-	uint64_t random_state = 1;
-	for (unsigned int j = 0; j < buffer->len; j++)
-	  random_state = 31 * random_state + buffer->info[j].codepoint;
-	c.set_random_state (random_state);
+	c.set_random (true);
 	buffer->unsafe_to_break_all ();
       }
       apply_string<Proxy> (&c,
diff --git a/test/shaping/data/in-house/tests/rand.tests b/test/shaping/data/in-house/tests/rand.tests
index f1023e82..781abf42 100644
--- a/test/shaping/data/in-house/tests/rand.tests
+++ b/test/shaping/data/in-house/tests/rand.tests
@@ -1,3 +1,3 @@
 ../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names --features=-rand:U+0054,U+0055,U+0056:[1=0+560|2=1+602|3=2+602]
 ../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names --features=rand=2:U+0054,U+0055,U+0056:[5=0+560|8=1+602|11=2+602]
-../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names:U+0054,U+0055,U+0056,U+0054,U+0055,U+0056,U+0054,U+0055,U+0056,U+0054,U+0055,U+0056:[4=0+560|7=1+602|11=2+602|6=3+560|8=4+602|10=5+602|5=6+560|9=7+602|10=8+602|5=9+560|7=10+602|12=11+602]
+../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names:U+0054,U+0055,U+0056,U+0054,U+0055,U+0056,U+0054,U+0055,U+0056,U+0054,U+0055,U+0056:[6=0+560|9=1+602|10=2+602|6=3+560|9=4+602|12=5+602|5=6+560|8=7+602|11=8+602|6=9+560|8=10+602|10=11+602]
commit 2de96e846844d21888af6893378b21a33fc19232
Author: David Corbett <corbett.dav at husky.neu.edu>
Date:   Sat Jan 27 19:48:38 2018 -0500

    Test 'rand'

diff --git a/test/shaping/data/in-house/Makefile.sources b/test/shaping/data/in-house/Makefile.sources
index ef16faed..1bb8604e 100644
--- a/test/shaping/data/in-house/Makefile.sources
+++ b/test/shaping/data/in-house/Makefile.sources
@@ -32,6 +32,7 @@ TESTS = \
 	tests/mongolian-variation-selector.tests \
 	tests/myanmar-syllable.tests \
 	tests/none-directional.tests \
+	tests/rand.tests \
 	tests/spaces.tests \
 	tests/simple.tests \
 	tests/sinhala.tests \
diff --git a/test/shaping/data/in-house/fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf b/test/shaping/data/in-house/fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf
new file mode 100644
index 00000000..588ce3b9
Binary files /dev/null and b/test/shaping/data/in-house/fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf differ
diff --git a/test/shaping/data/in-house/tests/rand.tests b/test/shaping/data/in-house/tests/rand.tests
new file mode 100644
index 00000000..f1023e82
--- /dev/null
+++ b/test/shaping/data/in-house/tests/rand.tests
@@ -0,0 +1,3 @@
+../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names --features=-rand:U+0054,U+0055,U+0056:[1=0+560|2=1+602|3=2+602]
+../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names --features=rand=2:U+0054,U+0055,U+0056:[5=0+560|8=1+602|11=2+602]
+../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names:U+0054,U+0055,U+0056,U+0054,U+0055,U+0056,U+0054,U+0055,U+0056,U+0054,U+0055,U+0056:[4=0+560|7=1+602|11=2+602|6=3+560|8=4+602|10=5+602|5=6+560|9=7+602|10=8+602|5=9+560|7=10+602|12=11+602]
commit f05df643b44d9bbfd742e93f02c235fc821190d0
Author: David Corbett <corbett.dav at husky.neu.edu>
Date:   Fri Jan 26 21:36:15 2018 -0500

    Allow requesting a specific glyph for 'rand'
    
    Randomization only happens by default. If the user specifies a value for
    'rand', that value is respected.

diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index fb320e29..8617f054 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -254,6 +254,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t  &m,
     map->stage[1] = info->stage[1];
     map->auto_zwnj = !(info->flags & F_MANUAL_ZWNJ);
     map->auto_zwj = !(info->flags & F_MANUAL_ZWJ);
+    map->random = !!(info->flags & F_RANDOM);
     if ((info->flags & F_GLOBAL) && info->max_value == 1) {
       /* Uses the global bit */
       map->shift = global_bit_shift;
@@ -304,7 +305,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t  &m,
 		       m.features[i].mask,
 		       m.features[i].auto_zwnj,
 		       m.features[i].auto_zwj,
-		       m.features[i].tag == HB_TAG ('r','a','n','d'));
+		       m.features[i].random);
 
       /* Sort lookups and merge duplicates */
       if (last_num_lookups < m.lookups[table_index].len)
diff --git a/src/hb-ot-map.hh b/src/hb-ot-map.hh
index 2518a492..091cb3b6 100644
--- a/src/hb-ot-map.hh
+++ b/src/hb-ot-map.hh
@@ -52,6 +52,7 @@ struct hb_ot_map_t
     unsigned int needs_fallback : 1;
     unsigned int auto_zwnj : 1;
     unsigned int auto_zwj : 1;
+    unsigned int random : 1;
 
     inline int cmp (const hb_tag_t *tag_) const
     { return *tag_ < tag ? -1 : *tag_ > tag ? 1 : 0; }
@@ -168,7 +169,8 @@ enum hb_ot_map_feature_flags_t {
   F_HAS_FALLBACK	= 0x0002u, /* Has fallback implementation, so include mask bit even if feature not found. */
   F_MANUAL_ZWNJ		= 0x0004u, /* Don't skip over ZWNJ when matching **context**. */
   F_MANUAL_ZWJ		= 0x0008u, /* Don't skip over ZWJ when matching **input**. */
-  F_GLOBAL_SEARCH	= 0x0010u  /* If feature not found in LangSys, look for it in global feature list and pick one. */
+  F_GLOBAL_SEARCH	= 0x0010u, /* If feature not found in LangSys, look for it in global feature list and pick one. */
+  F_RANDOM		= 0x0020u  /* Randomly select a glyph from an AlternateSubstFormat1 subtable. */
 };
 HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t);
 /* Macro version for where const is desired. */
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index f5aeb0df..0007e0ab 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -49,7 +49,6 @@ static hb_tag_t common_features[] = {
   HB_TAG('m','a','r','k'),
   HB_TAG('m','k','m','k'),
   HB_TAG('r','l','i','g'),
-  HB_TAG('r','a','n','d'),
 };
 
 
@@ -71,6 +70,7 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
 			      unsigned int                    num_user_features)
 {
   hb_ot_map_builder_t *map = &planner->map;
+  bool default_rand = true;
 
   map->add_global_bool_feature (HB_TAG('r','v','r','n'));
   map->add_gsub_pause (nullptr);
@@ -123,7 +123,12 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
     map->add_feature (feature->tag, feature->value,
 		      (feature->start == 0 && feature->end == (unsigned int) -1) ?
 		       F_GLOBAL : F_NONE);
+    if (feature->tag == HB_TAG ('r','a','n','d'))
+      default_rand = false;
   }
+
+  if (default_rand)
+    map->add_feature (HB_TAG ('r','a','n','d'), 1, F_GLOBAL | F_RANDOM);
 }
 
 
commit c2a75e07e54314f6c611dda0f050ed5f09909e43
Author: David Corbett <corbett.dav at husky.neu.edu>
Date:   Thu Jan 25 14:22:03 2018 -0500

    Implement 'rand'

diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 76a0ea6d..db24a284 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -534,16 +534,21 @@ struct AlternateSet
 
     if (unlikely (!count)) return_trace (false);
 
-    hb_mask_t glyph_mask = c->buffer->cur().mask;
-    hb_mask_t lookup_mask = c->lookup_mask;
+    if (c->random) {
+      c->random_state = (0x5DEECE66Dull * c->random_state + 11) & (((uint64_t) 1 << 48) - 1);
+      c->replace_glyph (alternates[(c->random_state >> 32) % count]);
+    } else {
+      hb_mask_t glyph_mask = c->buffer->cur().mask;
+      hb_mask_t lookup_mask = c->lookup_mask;
 
-    /* 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);
+      /* 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);
 
-    if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
+      if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
 
-    c->replace_glyph (alternates[alt_index - 1]);
+      c->replace_glyph (alternates[alt_index - 1]);
+    }
 
     return_trace (true);
   }
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index 719a5050..113433d9 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -480,6 +480,8 @@ struct hb_ot_apply_context_t :
 
   bool auto_zwnj;
   bool auto_zwj;
+  bool random;
+  uint64_t random_state;
   bool has_glyph_classes;
 
 
@@ -500,11 +502,17 @@ struct hb_ot_apply_context_t :
 			debug_depth (0),
 			auto_zwnj (true),
 			auto_zwj (true),
+			random (false),
+			random_state (0),
 			has_glyph_classes (gdef.has_glyph_classes ()) {}
 
   inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
   inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
   inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; }
+  inline void set_random_state (uint64_t random_state_) {
+    random = true;
+    random_state = random_state_;
+  }
   inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
   inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
   inline void set_lookup_props (unsigned int lookup_props_)
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index a1220f4d..b31dbbca 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -1268,6 +1268,14 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
       c.set_lookup_mask (lookups[table_index][i].mask);
       c.set_auto_zwj (lookups[table_index][i].auto_zwj);
       c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
+      if (lookups[table_index][i].random)
+      {
+	uint64_t random_state = 1;
+	for (unsigned int j = 0; j < buffer->len; j++)
+	  random_state = 31 * random_state + buffer->info[j].codepoint;
+	c.set_random_state (random_state);
+	buffer->unsafe_to_break_all ();
+      }
       apply_string<Proxy> (&c,
 			   proxy.table.get_lookup (lookup_index),
 			   proxy.accels[lookup_index]);
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index 29f52dcc..fb320e29 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -95,7 +95,8 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t  &m,
 				  unsigned int  variations_index,
 				  hb_mask_t     mask,
 				  bool          auto_zwnj,
-				  bool          auto_zwj)
+				  bool          auto_zwj,
+				  bool          random)
 {
   unsigned int lookup_indices[32];
   unsigned int offset, len;
@@ -122,6 +123,7 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t  &m,
       lookup->index = lookup_indices[i];
       lookup->auto_zwnj = auto_zwnj;
       lookup->auto_zwj = auto_zwj;
+      lookup->random = random;
     }
 
     offset += len;
@@ -301,7 +303,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t  &m,
 		       variations_index,
 		       m.features[i].mask,
 		       m.features[i].auto_zwnj,
-		       m.features[i].auto_zwj);
+		       m.features[i].auto_zwj,
+		       m.features[i].tag == HB_TAG ('r','a','n','d'));
 
       /* Sort lookups and merge duplicates */
       if (last_num_lookups < m.lookups[table_index].len)
diff --git a/src/hb-ot-map.hh b/src/hb-ot-map.hh
index 32a9e7e0..2518a492 100644
--- a/src/hb-ot-map.hh
+++ b/src/hb-ot-map.hh
@@ -61,6 +61,7 @@ struct hb_ot_map_t
     unsigned short index;
     unsigned short auto_zwnj : 1;
     unsigned short auto_zwj : 1;
+    unsigned short random : 1;
     hb_mask_t mask;
 
     static int cmp (const void *pa, const void *pb)
@@ -206,7 +207,8 @@ struct hb_ot_map_builder_t
 				unsigned int  variations_index,
 				hb_mask_t     mask,
 				bool          auto_zwnj = true,
-				bool          auto_zwj = true);
+				bool          auto_zwj = true,
+				bool          random = false);
 
   struct feature_info_t {
     hb_tag_t tag;
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 63102f6b..f5aeb0df 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -49,6 +49,7 @@ static hb_tag_t common_features[] = {
   HB_TAG('m','a','r','k'),
   HB_TAG('m','k','m','k'),
   HB_TAG('r','l','i','g'),
+  HB_TAG('r','a','n','d'),
 };
 
 


More information about the HarfBuzz mailing list