Merge from lmp-dev-plus-aosp harfbuzz

Change-Id: Ibd9da468c26988c3e3e1236f5ca5f603be7761bf
diff --git a/NEWS b/NEWS
index f4fabc7..a838715 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,13 @@
+Overview of changes leading to 0.9.33
+Tuesday, July 22, 2014
+=====================================
+
+- Turn off ARabic 'cswh' feature that was accidentally turned on.
+- Add HB_TAG_MAX_SIGNED.
+- Make hb_face_make_immutable() really make face immutable!
+- Windows build fixes.
+
+
 Overview of changes leading to 0.9.32
 Thursday, July 17, 2014
 =====================================
diff --git a/configure.ac b/configure.ac
index f93ceac..78e3178 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
 AC_PREREQ([2.64])
 AC_INIT([HarfBuzz],
-        [0.9.32],
+        [0.9.33],
         [http://bugs.freedesktop.org/enter_bug.cgi?product=harfbuzz],
         [harfbuzz],
         [http://harfbuzz.org/])
diff --git a/src/Makefile.am b/src/Makefile.am
index 5832f75..acedaa0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -361,6 +361,7 @@
 INTROSPECTION_GIRS = HarfBuzz-$(HB_VERSION_MAJOR).0.gir # What does the 0 mean anyway?!
 INTROSPECTION_SCANNER_ARGS = -I$(srcdir) -n hb --identifier-prefix=hb_ --warn-all
 INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
+INTROSPECTION_SCANNER_ENV = CC="$(CC)"
 
 HarfBuzz-0.0.gir: libharfbuzz.la libharfbuzz-gobject.la
 HarfBuzz_0_0_gir_INCLUDES = GObject-2.0
diff --git a/src/hb-common.h b/src/hb-common.h
index 32a62e5..f5141b9 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -316,7 +316,7 @@
 hb_script_t
 hb_script_from_iso15924_tag (hb_tag_t tag);
 
-/* suger for tag_from_string() then script_from_iso15924_tag */
+/* sugar for tag_from_string() then script_from_iso15924_tag */
 /* len=-1 means s is NUL-terminated */
 hb_script_t
 hb_script_from_string (const char *s, int len);
diff --git a/src/hb-face.cc b/src/hb-face.cc
index 71cf49a..9348af7 100644
--- a/src/hb-face.cc
+++ b/src/hb-face.cc
@@ -298,7 +298,7 @@
 void
 hb_face_make_immutable (hb_face_t *face)
 {
-  if (hb_object_is_inert (face))
+  if (unlikely (hb_object_is_inert (face)))
     return;
 
   face->immutable = true;
@@ -368,7 +368,7 @@
 hb_face_set_index (hb_face_t    *face,
 		   unsigned int  index)
 {
-  if (hb_object_is_inert (face))
+  if (face->immutable)
     return;
 
   face->index = index;
@@ -403,7 +403,7 @@
 hb_face_set_upem (hb_face_t    *face,
 		  unsigned int  upem)
 {
-  if (hb_object_is_inert (face))
+  if (face->immutable)
     return;
 
   face->upem = upem;
@@ -447,7 +447,7 @@
 hb_face_set_glyph_count (hb_face_t    *face,
 			 unsigned int  glyph_count)
 {
-  if (hb_object_is_inert (face))
+  if (face->immutable)
     return;
 
   face->num_glyphs = glyph_count;
diff --git a/src/hb-font.cc b/src/hb-font.cc
index fc4c8eb..4364ca7 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -357,7 +357,7 @@
 void
 hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
 {
-  if (hb_object_is_inert (ffuncs))
+  if (unlikely (hb_object_is_inert (ffuncs)))
     return;
 
   ffuncs->immutable = true;
@@ -1034,7 +1034,7 @@
 void
 hb_font_make_immutable (hb_font_t *font)
 {
-  if (hb_object_is_inert (font))
+  if (unlikely (hb_object_is_inert (font)))
     return;
 
   font->immutable = true;
diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh
index 046df97..475187b 100644
--- a/src/hb-open-type-private.hh
+++ b/src/hb-open-type-private.hh
@@ -289,7 +289,7 @@
 struct Sanitizer
 {
   static hb_blob_t *sanitize (hb_blob_t *blob) {
-    hb_sanitize_context_t c[1] = {{0}};
+    hb_sanitize_context_t c[1] = {{0, NULL, NULL, false, 0, NULL}};
     bool sane;
 
     /* TODO is_sane() stuff */
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index 9b06300..d94ac50 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@ -127,7 +127,7 @@
   }
 
   template <typename TLookup>
-  inline void fini (const TLookup &lookup)
+  inline void fini (const TLookup &lookup HB_UNUSED)
   {
   }
 
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 33215a3..be5d574 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -921,14 +921,32 @@
     info[start].indic_position() = POS_RA_TO_BECOME_REPH;
 
   /* For old-style Indic script tags, move the first post-base Halant after
-   * last consonant.  Only do this if there is *not* a Halant after last
-   * consonant.  Otherwise it becomes messy. */
-  if (indic_plan->is_old_spec) {
+   * last consonant.
+   *
+   * Reports suggest that in some scripts Uniscribe does this only if there
+   * is *not* a Halant after last consonant already (eg. Kannada), while it
+   * does it unconditionally in other scripts (eg. Malayalam).  We don't
+   * currently know about other scripts, so we single out Malayalam for now.
+   *
+   * Kannada test case:
+   * U+0C9A,U+0CCD,U+0C9A,U+0CCD
+   * With some versions of Lohit Kannada.
+   * https://bugs.freedesktop.org/show_bug.cgi?id=59118
+   *
+   * Malayalam test case:
+   * U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D
+   * With lohit-ttf-20121122/Lohit-Malayalam.ttf
+   */
+  if (indic_plan->is_old_spec)
+  {
+    bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM;
     for (unsigned int i = base + 1; i < end; i++)
-      if (info[i].indic_category() == OT_H) {
+      if (info[i].indic_category() == OT_H)
+      {
         unsigned int j;
         for (j = end - 1; j > i; j--)
-	  if (is_consonant (info[j]) || info[j].indic_category() == OT_H)
+	  if (is_consonant (info[j]) ||
+	      (disallow_double_halants && info[j].indic_category() == OT_H))
 	    break;
 	if (info[j].indic_category() != OT_H && j > i) {
 	  /* Move Halant to after last consonant. */
diff --git a/src/hb-private.hh b/src/hb-private.hh
index 68223b3..5a4ca69 100644
--- a/src/hb-private.hh
+++ b/src/hb-private.hh
@@ -116,7 +116,7 @@
 #define HB_FUNC __func__
 #endif
 
-#ifdef _WIN32
+#if defined(_WIN32) || defined(__CYGWIN__)
    /* We need Windows Vista for both Uniscribe backend and for
     * MemoryBarrier.  We don't support compiling on Windows XP,
     * though we run on it fine. */
@@ -284,7 +284,7 @@
 /* arrays and maps */
 
 
-#define HB_PREALLOCED_ARRAY_INIT {0}
+#define HB_PREALLOCED_ARRAY_INIT {0, 0, NULL}
 template <typename Type, unsigned int StaticSize=16>
 struct hb_prealloced_array_t
 {
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index c1b7524..812cf59 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -34,15 +34,15 @@
 #include "hb-font-private.hh"
 
 
-static void
+static bool
 parse_space (const char **pp, const char *end)
 {
-  char c;
-  while (*pp < end && (c = **pp, ISSPACE (c)))
+  while (*pp < end && ISSPACE (**pp))
     (*pp)++;
+  return true;
 }
 
-static hb_bool_t
+static bool
 parse_char (const char **pp, const char *end, char c)
 {
   parse_space (pp, end);
@@ -54,7 +54,7 @@
   return true;
 }
 
-static hb_bool_t
+static bool
 parse_uint (const char **pp, const char *end, unsigned int *pv)
 {
   char buf[32];
@@ -78,7 +78,27 @@
   return true;
 }
 
-static hb_bool_t
+static bool
+parse_bool (const char **pp, const char *end, unsigned int *pv)
+{
+  parse_space (pp, end);
+
+  const char *p = *pp;
+  while (*pp < end && ISALPHA(**pp))
+    (*pp)++;
+
+  /* CSS allows on/off as aliases 1/0. */
+  if (*pp - p == 2 || 0 == strncmp (p, "on", 2))
+    *pv = 1;
+  else if (*pp - p == 3 || 0 == strncmp (p, "off", 2))
+    *pv = 0;
+  else
+    return false;
+
+  return true;
+}
+
+static bool
 parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
 {
   if (parse_char (pp, end, '-'))
@@ -91,32 +111,48 @@
   return true;
 }
 
-static hb_bool_t
+static bool
 parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
 {
-  const char *p = *pp;
-  char c;
-
   parse_space (pp, end);
 
-#define ISALNUM(c) (('a' <= (c) && (c) <= 'z') || ('A' <= (c) && (c) <= 'Z') || ('0' <= (c) && (c) <= '9'))
-  while (*pp < end && (c = **pp, ISALNUM(c)))
-    (*pp)++;
-#undef ISALNUM
+  char quote = 0;
 
-  if (p == *pp)
+  if (*pp < end && (**pp == '\'' || **pp == '"'))
+  {
+    quote = **pp;
+    (*pp)++;
+  }
+
+  const char *p = *pp;
+  while (*pp < end && ISALNUM(**pp))
+    (*pp)++;
+
+  if (p == *pp || *pp - p > 4)
     return false;
 
   feature->tag = hb_tag_from_string (p, *pp - p);
+
+  if (quote)
+  {
+    /* CSS expects exactly four bytes.  And we only allow quotations for
+     * CSS compatibility.  So, enforce the length. */
+     if (*pp - p != 4)
+       return false;
+    if (*pp == end || **pp != quote)
+      return false;
+    (*pp)++;
+  }
+
   return true;
 }
 
-static hb_bool_t
+static bool
 parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
 {
   parse_space (pp, end);
 
-  hb_bool_t has_start;
+  bool has_start;
 
   feature->start = 0;
   feature->end = (unsigned int) -1;
@@ -136,20 +172,27 @@
   return parse_char (pp, end, ']');
 }
 
-static hb_bool_t
+static bool
 parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
 {
-  return !parse_char (pp, end, '=') || parse_uint (pp, end, &feature->value);
+  bool had_equal = parse_char (pp, end, '=');
+  bool had_value = parse_uint (pp, end, &feature->value) ||
+                   parse_bool (pp, end, &feature->value);
+  /* CSS doesn't use equal-sign between tag and value.
+   * If there was an equal-sign, then there *must* be a value.
+   * A value without an eqaul-sign is ok, but not required. */
+  return !had_equal || had_value;
 }
 
 
-static hb_bool_t
+static bool
 parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
 {
   return parse_feature_value_prefix (pp, end, feature) &&
 	 parse_feature_tag (pp, end, feature) &&
 	 parse_feature_indices (pp, end, feature) &&
 	 parse_feature_value_postfix (pp, end, feature) &&
+	 parse_space (pp, end) &&
 	 *pp == end;
 }
 
@@ -157,7 +200,7 @@
  * hb_feature_from_string:
  * @str: (array length=len):
  * @len: 
- * @feature: (out):
+ * @feature: (out) (allow-none):
  *
  * 
  *
@@ -169,10 +212,21 @@
 hb_feature_from_string (const char *str, int len,
 			hb_feature_t *feature)
 {
+  hb_feature_t feat;
+
   if (len < 0)
     len = strlen (str);
 
-  return parse_one_feature (&str, str + len, feature);
+  if (likely (parse_one_feature (&str, str + len, &feat)))
+  {
+    if (feature)
+      *feature = feat;
+    return true;
+  }
+
+  if (feature)
+    memset (feature, 0, sizeof (*feature));
+  return false;
 }
 
 /**
@@ -203,18 +257,18 @@
   {
     s[len++] = '[';
     if (feature->start)
-      len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->start));
+      len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
     if (feature->end != feature->start + 1) {
       s[len++] = ':';
       if (feature->end != (unsigned int) -1)
-	len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->end));
+	len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
     }
     s[len++] = ']';
   }
   if (feature->value > 1)
   {
     s[len++] = '=';
-    len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->value));
+    len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
   }
   assert (len < ARRAY_LENGTH (s));
   len = MIN (len, size - 1);
diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc
index 84e5c06..d59dfb2 100644
--- a/src/hb-unicode.cc
+++ b/src/hb-unicode.cc
@@ -310,7 +310,7 @@
 void
 hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
 {
-  if (hb_object_is_inert (ufuncs))
+  if (unlikely (hb_object_is_inert (ufuncs)))
     return;
 
   ufuncs->immutable = true;
diff --git a/test/shaping/Makefile.am b/test/shaping/Makefile.am
index 3f43aec..c2c4db6 100644
--- a/test/shaping/Makefile.am
+++ b/test/shaping/Makefile.am
@@ -38,6 +38,7 @@
 TESTS = \
 	tests/arabic-feature-order.tests \
 	tests/context-matching.tests \
+	tests/indic-old-spec.tests \
 	tests/indic-pref-blocking.tests \
 	tests/mongolian-variation-selector.tests \
 	$(NULL)
@@ -48,7 +49,7 @@
 
 AM_TESTS_ENVIRONMENT = \
 	EXEEXT="$(EXEEXT)"; \
-	export EXEECT; \
+	export EXEEXT; \
 	srcdir="$(srcdir)"; \
 	export srcdir; \
 	builddir="$(builddir)"; \
diff --git a/test/shaping/fonts/sha1sum/270b89df543a7e48e206a2d830c0e10e5265c630.ttf b/test/shaping/fonts/sha1sum/270b89df543a7e48e206a2d830c0e10e5265c630.ttf
new file mode 100644
index 0000000..fc22649
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/270b89df543a7e48e206a2d830c0e10e5265c630.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf b/test/shaping/fonts/sha1sum/57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf
new file mode 100644
index 0000000..746fc60
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/MANIFEST b/test/shaping/fonts/sha1sum/MANIFEST
index cd2ede5..4aaa54d 100644
--- a/test/shaping/fonts/sha1sum/MANIFEST
+++ b/test/shaping/fonts/sha1sum/MANIFEST
@@ -1,6 +1,8 @@
 226bc2deab3846f1a682085f70c67d0421014144.ttf
+270b89df543a7e48e206a2d830c0e10e5265c630.ttf
 37033cc5cf37bb223d7355153016b6ccece93b28.ttf
 4cce528e99f600ed9c25a2b69e32eb94a03b4ae8.ttf
+57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf
 813c2f8e5512187fd982417a7fb4286728e6f4a8.ttf
 8a9fea2a7384f2116e5b84a9b31f83be7850ce21.ttf
 a919b33197965846f21074b24e30250d67277bce.ttf
diff --git a/test/shaping/tests/MANIFEST b/test/shaping/tests/MANIFEST
index 1b577c7..a792e91 100644
--- a/test/shaping/tests/MANIFEST
+++ b/test/shaping/tests/MANIFEST
@@ -1,4 +1,5 @@
 arabic-feature-order.tests
 context-matching.tests
+indic-old-spec.tests
 indic-pref-blocking.tests
 mongolian-variation-selector.tests
diff --git a/test/shaping/tests/indic-old-spec.tests b/test/shaping/tests/indic-old-spec.tests
new file mode 100644
index 0000000..96e8cdd
--- /dev/null
+++ b/test/shaping/tests/indic-old-spec.tests
@@ -0,0 +1,2 @@
+fonts/sha1sum/57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf:U+0C9A,U+0CCD,U+0C9A,U+0CCD:[U0C9A_U0CCD.haln=0+1066|U0C9A_0CCD.blwf=0+0]
+fonts/sha1sum/270b89df543a7e48e206a2d830c0e10e5265c630.ttf:U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D:[glyph201=0+1183|U0D4D=0+0]
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/misc.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/misc.txt
index c5144f0..2e732ae 100644
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/misc.txt
+++ b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/misc.txt
@@ -62,3 +62,4 @@
 ശിം‌
 കോം‌
 യ‍്യ
+സ്റ്റ്
diff --git a/util/options.cc b/util/options.cc
index 738fb7a..0adc179 100644
--- a/util/options.cc
+++ b/util/options.cc
@@ -304,7 +304,9 @@
   const gchar *features_help = "Comma-separated list of font features\n"
     "\n"
     "    Features can be enabled or disabled, either globally or limited to\n"
-    "    specific character ranges.\n"
+    "    specific character ranges.  The format for specifying feature settings\n"
+    "    follows.  All valid CSS font-feature-settings values other than 'normal'\n"
+    "    and 'inherited' are also accepted, though, not documented below.\n"
     "\n"
     "    The range indices refer to the positions between Unicode characters,\n"
     "    unless the --utf8-clusters is provided, in which case range indices\n"