8206428: Upgrade JDK11 to harfbuzz 1.8.2
authorprr
Fri, 06 Jul 2018 10:37:47 -0700
changeset 51000 7c8841474f57
parent 50999 f8038b878d27
child 51001 deff20e15445
8206428: Upgrade JDK11 to harfbuzz 1.8.2 Reviewed-by: serb
src/java.desktop/share/legal/harfbuzz.md
src/java.desktop/share/native/libfontmanager/harfbuzz/hb-blob.cc
src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-file-private.hh
src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-type-private.hh
src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-common-private.hh
src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-gpos-table.hh
src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-indic.cc
src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-khmer.cc
src/java.desktop/share/native/libfontmanager/harfbuzz/hb-private.hh
src/java.desktop/share/native/libfontmanager/harfbuzz/hb-version.h
--- a/src/java.desktop/share/legal/harfbuzz.md	Fri Jul 06 13:38:56 2018 +0530
+++ b/src/java.desktop/share/legal/harfbuzz.md	Fri Jul 06 10:37:47 2018 -0700
@@ -1,4 +1,4 @@
-## Harfbuzz v1.8.1
+## Harfbuzz v1.8.2
 
 ### Harfbuzz License
 
--- a/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-blob.cc	Fri Jul 06 13:38:56 2018 +0530
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-blob.cc	Fri Jul 06 10:37:47 2018 -0700
@@ -489,10 +489,10 @@
 
 #if defined(_WIN32) || defined(__CYGWIN__)
 # include <windows.h>
-#endif
-
-#ifndef _O_BINARY
-# define _O_BINARY 0
+#else
+# ifndef _O_BINARY
+#  define _O_BINARY 0
+# endif
 #endif
 
 #ifndef MAP_NORESERVE
@@ -517,7 +517,7 @@
   UnmapViewOfFile (file->contents);
   CloseHandle (file->mapping);
 #else
-  free (file->contents);
+  assert (0); // If we don't have mmap we shouldn't reach here
 #endif
 
   free (file);
@@ -534,77 +534,103 @@
 hb_blob_t *
 hb_blob_create_from_file (const char *file_name)
 {
-  // Adopted from glib's gmappedfile.c with Matthias Clasen and
-  // Allison Lortie permission but changed a lot to suit our need.
-  bool writable = false;
-  hb_memory_mode_t mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
+  /* Adopted from glib's gmappedfile.c with Matthias Clasen and
+     Allison Lortie permission but changed a lot to suit our need. */
+#if defined(HAVE_MMAP) && !defined(HB_NO_MMAP)
   hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
   if (unlikely (!file)) return hb_blob_get_empty ();
 
-#ifdef HAVE_MMAP
-  int fd = open (file_name, (writable ? O_RDWR : O_RDONLY) | _O_BINARY, 0);
-# define CLOSE close
+  int fd = open (file_name, O_RDONLY | _O_BINARY, 0);
   if (unlikely (fd == -1)) goto fail_without_close;
 
   struct stat st;
   if (unlikely (fstat (fd, &st) == -1)) goto fail;
 
-  // See https://github.com/GNOME/glib/blob/f9faac7/glib/gmappedfile.c#L139-L142
-  if (unlikely (st.st_size == 0 && S_ISREG (st.st_mode))) goto fail;
-
   file->length = (unsigned long) st.st_size;
-  file->contents = (char *) mmap (nullptr, file->length,
-                                  writable ? PROT_READ|PROT_WRITE : PROT_READ,
+  file->contents = (char *) mmap (nullptr, file->length, PROT_READ,
                                   MAP_PRIVATE | MAP_NORESERVE, fd, 0);
 
   if (unlikely (file->contents == MAP_FAILED)) goto fail;
 
-#elif defined(_WIN32) || defined(__CYGWIN__)
-  HANDLE fd = CreateFile (file_name,
-                          writable ? GENERIC_READ|GENERIC_WRITE : GENERIC_READ,
-                          FILE_SHARE_READ, nullptr, OPEN_EXISTING,
-                          FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr);
-# define CLOSE CloseHandle
+  close (fd);
+
+  return hb_blob_create (file->contents, file->length,
+                         HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
+                         (hb_destroy_func_t) _hb_mapped_file_destroy);
+
+fail:
+  close (fd);
+fail_without_close:
+  free (file);
+
+#elif (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_MMAP)
+  hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
+  if (unlikely (!file)) return hb_blob_get_empty ();
+
+  HANDLE fd = CreateFile (file_name, GENERIC_READ, FILE_SHARE_READ, nullptr,
+                          OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
+                          nullptr);
 
   if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
 
   file->length = (unsigned long) GetFileSize (fd, nullptr);
-  file->mapping = CreateFileMapping (fd, nullptr,
-                                     writable ? PAGE_WRITECOPY : PAGE_READONLY,
-                                     0, 0, nullptr);
+  file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr);
   if (unlikely (file->mapping == nullptr)) goto fail;
 
-  file->contents = (char *) MapViewOfFile (file->mapping,
-                                           writable ? FILE_MAP_COPY : FILE_MAP_READ,
-                                           0, 0, 0);
+  file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0);
   if (unlikely (file->contents == nullptr)) goto fail;
 
-#else
-  mm = HB_MEMORY_MODE_WRITABLE;
-
-  FILE *fd = fopen (file_name, "rb");
-# define CLOSE fclose
-  if (unlikely (!fd)) goto fail_without_close;
+  CloseHandle (fd);
+  return hb_blob_create (file->contents, file->length,
+                         HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
+                         (hb_destroy_func_t) _hb_mapped_file_destroy);
 
-  fseek (fd, 0, SEEK_END);
-  file->length = ftell (fd);
-  rewind (fd);
-  file->contents = (char *) malloc (file->length);
-  if (unlikely (!file->contents)) goto fail;
-
-  if (unlikely (fread (file->contents, 1, file->length, fd) != file->length))
-    goto fail;
+fail:
+  CloseHandle (fd);
+fail_without_close:
+  free (file);
 
 #endif
 
-  CLOSE (fd);
-  return hb_blob_create (file->contents, file->length, mm, (void *) file,
-                         (hb_destroy_func_t) _hb_mapped_file_destroy);
+  /* The following tries to read a file without knowing its size beforehand
+     It's used as a fallback for systems without mmap or to read from pipes */
+  unsigned long len = 0, allocated = BUFSIZ * 16;
+  char *data = (char *) malloc (allocated);
+  if (unlikely (data == nullptr)) return hb_blob_get_empty ();
+
+  FILE *fp = fopen (file_name, "rb");
+  if (unlikely (fp == nullptr)) goto fread_fail_without_close;
 
-fail:
-  CLOSE (fd);
-#undef CLOSE
-fail_without_close:
-  free (file);
+  while (!feof (fp))
+  {
+    if (allocated - len < BUFSIZ)
+    {
+      allocated *= 2;
+      /* Don't allocate and go more than ~536MB, our mmap reader still
+         can cover files like that but lets limit our fallback reader */
+      if (unlikely (allocated > (2 << 28))) goto fread_fail;
+      char *new_data = (char *) realloc (data, allocated);
+      if (unlikely (new_data == nullptr)) goto fread_fail;
+      data = new_data;
+    }
+
+    unsigned long addition = fread (data + len, 1, allocated - len, fp);
+
+    int err = ferror (fp);
+#ifdef EINTR // armcc doesn't have it
+    if (unlikely (err == EINTR)) continue;
+#endif
+    if (unlikely (err)) goto fread_fail;
+
+    len += addition;
+  }
+
+  return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data,
+                         (hb_destroy_func_t) free);
+
+fread_fail:
+  fclose (fp);
+fread_fail_without_close:
+  free (data);
   return hb_blob_get_empty ();
 }
--- a/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-file-private.hh	Fri Jul 06 13:38:56 2018 +0530
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-file-private.hh	Fri Jul 06 10:37:47 2018 -0700
@@ -286,6 +286,197 @@
   } u;
 };
 
+/*
+ * Mac Resource Fork
+ */
+
+struct ResourceRefItem
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    // actual data sanitization is done on ResourceForkHeader sanitizer
+    return_trace (likely (c->check_struct (this)));
+  }
+
+  HBINT16       id;             /* Resource ID, is really should be signed? */
+  HBINT16       nameOffset;     /* Offset from beginning of resource name list
+                                 * to resource name, minus means there is no */
+  HBUINT8       attr;           /* Resource attributes */
+  HBUINT24      dataOffset;     /* Offset from beginning of resource data to
+                                 * data for this resource */
+  HBUINT32      reserved;       /* Reserved for handle to resource */
+  public:
+  DEFINE_SIZE_STATIC (12);
+};
+
+struct ResourceTypeItem
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    // RefList sanitization is done on ResourceMap sanitizer
+    return_trace (likely (c->check_struct (this)));
+  }
+
+  inline unsigned int get_resource_count () const
+  {
+    return numRes + 1;
+  }
+
+  inline bool is_sfnt () const
+  {
+    return type == HB_TAG ('s','f','n','t');
+  }
+
+  inline const ResourceRefItem& get_ref_item (const void *base,
+                                              unsigned int i) const
+  {
+    return (base+refList)[i];
+  }
+
+  protected:
+  Tag           type;           /* Resource type */
+  HBUINT16      numRes;         /* Number of resource this type in map minus 1 */
+  OffsetTo<UnsizedArrayOf<ResourceRefItem> >
+                refList;        /* Offset from beginning of resource type list
+                                 * to reference list for this type */
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+struct ResourceMap
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this)))
+      return_trace (false);
+    for (unsigned int i = 0; i < get_types_count (); ++i)
+    {
+      const ResourceTypeItem& type = get_type (i);
+      if (unlikely (!type.sanitize (c)))
+        return_trace (false);
+      for (unsigned int j = 0; j < type.get_resource_count (); ++j)
+        if (unlikely (!get_ref_item (type, j).sanitize (c)))
+          return_trace (false);
+    }
+    return_trace (true);
+  }
+
+  inline const ResourceTypeItem& get_type (unsigned int i) const
+  {
+    // Why offset from the second byte of the object? I'm not sure
+    return ((&reserved[2])+typeList)[i];
+  }
+
+  inline unsigned int get_types_count () const
+  {
+    return nTypes + 1;
+  }
+
+  inline const ResourceRefItem &get_ref_item (const ResourceTypeItem &type,
+                                              unsigned int i) const
+  {
+    return type.get_ref_item (&(this+typeList), i);
+  }
+
+  inline const PString& get_name (const ResourceRefItem &item,
+                                  unsigned int i) const
+  {
+    if (item.nameOffset == -1)
+      return Null (PString);
+
+    return StructAtOffset<PString> (this, nameList + item.nameOffset);
+  }
+
+  protected:
+  HBUINT8       reserved[16];   /* Reserved for copy of resource header */
+  LOffsetTo<ResourceMap>
+                reserved1;      /* Reserved for handle to next resource map */
+  HBUINT16      reserved2;      /* Reserved for file reference number */
+  HBUINT16      attr;           /* Resource fork attribute */
+  OffsetTo<UnsizedArrayOf<ResourceTypeItem> >
+                typeList;       /* Offset from beginning of map to
+                                 * resource type list */
+  HBUINT16      nameList;       /* Offset from beginning of map to
+                                 * resource name list */
+  HBUINT16      nTypes;         /* Number of types in the map minus 1 */
+  public:
+  DEFINE_SIZE_STATIC (30);
+};
+
+struct ResourceForkHeader
+{
+  inline unsigned int get_face_count () const
+  {
+    const ResourceMap &resource_map = this+map;
+    for (unsigned int i = 0; i < resource_map.get_types_count (); ++i)
+    {
+      const ResourceTypeItem& type = resource_map.get_type (i);
+      if (type.is_sfnt ())
+        return type.get_resource_count ();
+    }
+    return 0;
+  }
+
+  inline const LArrayOf<HBUINT8>& get_data (const ResourceTypeItem& type,
+                                            unsigned int idx) const
+  {
+    const ResourceMap &resource_map = this+map;
+    unsigned int offset = dataOffset;
+    offset += resource_map.get_ref_item (type, idx).dataOffset;
+    return StructAtOffset<LArrayOf<HBUINT8> > (this, offset);
+  }
+
+  inline const OpenTypeFontFace& get_face (unsigned int idx) const
+  {
+    const ResourceMap &resource_map = this+map;
+    for (unsigned int i = 0; i < resource_map.get_types_count (); ++i)
+    {
+      const ResourceTypeItem& type = resource_map.get_type (i);
+      if (type.is_sfnt () && idx < type.get_resource_count ())
+        return (OpenTypeFontFace&) get_data (type, idx).arrayZ;
+    }
+    return Null (OpenTypeFontFace);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this)))
+      return_trace (false);
+
+    const ResourceMap &resource_map = this+map;
+    if (unlikely (!resource_map.sanitize (c)))
+      return_trace (false);
+
+    for (unsigned int i = 0; i < resource_map.get_types_count (); ++i)
+    {
+      const ResourceTypeItem& type = resource_map.get_type (i);
+      for (unsigned int j = 0; j < type.get_resource_count (); ++j)
+      {
+        const LArrayOf<HBUINT8>& data = get_data (type, j);
+        if (unlikely (!(data.sanitize (c) &&
+                        ((OpenTypeFontFace&) data.arrayZ).sanitize (c))))
+          return_trace (false);
+      }
+    }
+
+    return_trace (true);
+  }
+
+  protected:
+  HBUINT32      dataOffset;     /* Offset from beginning of resource fork
+                                 * to resource data */
+  LOffsetTo<ResourceMap>
+                map;            /* Offset from beginning of resource fork
+                                 * to resource map */
+  HBUINT32      dataLen;        /* Length of resource data */
+  HBUINT32      mapLen;         /* Length of resource map */
+  public:
+  DEFINE_SIZE_STATIC (16);
+};
 
 /*
  * OpenType Font File
@@ -299,6 +490,7 @@
     CFFTag              = HB_TAG ('O','T','T','O'), /* OpenType with Postscript outlines */
     TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ), /* OpenType with TrueType outlines */
     TTCTag              = HB_TAG ('t','t','c','f'), /* TrueType Collection */
+    DFontTag            = HB_TAG ( 0 , 0 , 1 , 0 ), /* DFont Mac Resource Fork */
     TrueTag             = HB_TAG ('t','r','u','e'), /* Obsolete Apple TrueType */
     Typ1Tag             = HB_TAG ('t','y','p','1')  /* Obsolete Apple Type1 font in SFNT container */
   };
@@ -313,6 +505,7 @@
     case Typ1Tag:
     case TrueTypeTag:   return 1;
     case TTCTag:        return u.ttcHeader.get_face_count ();
+//    case DFontTag:    return u.rfHeader.get_face_count ();
     default:            return 0;
     }
   }
@@ -327,6 +520,7 @@
     case Typ1Tag:
     case TrueTypeTag:   return u.fontFace;
     case TTCTag:        return u.ttcHeader.get_face (i);
+//    case DFontTag:    return u.rfHeader.get_face (i);
     default:            return Null(OpenTypeFontFace);
     }
   }
@@ -353,6 +547,7 @@
     case Typ1Tag:
     case TrueTypeTag:   return_trace (u.fontFace.sanitize (c));
     case TTCTag:        return_trace (u.ttcHeader.sanitize (c));
+//    case DFontTag:    return_trace (u.rfHeader.sanitize (c));
     default:            return_trace (true);
     }
   }
@@ -362,6 +557,7 @@
   Tag                   tag;            /* 4-byte identifier. */
   OpenTypeFontFace      fontFace;
   TTCHeader             ttcHeader;
+  ResourceForkHeader    rfHeader;
   } u;
   public:
   DEFINE_SIZE_UNION (4, tag);
--- a/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-type-private.hh	Fri Jul 06 13:38:56 2018 +0530
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-type-private.hh	Fri Jul 06 10:37:47 2018 -0700
@@ -1033,6 +1033,7 @@
   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
 };
 template <typename Type> struct LArrayOf : ArrayOf<Type, HBUINT32> {};
+typedef ArrayOf<HBUINT8, HBUINT8> PString;
 
 /* Array of Offset's */
 template <typename Type, typename OffsetType=HBUINT16>
--- a/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-common-private.hh	Fri Jul 06 13:38:56 2018 +0530
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-common-private.hh	Fri Jul 06 10:37:47 2018 -0700
@@ -832,7 +832,12 @@
       c = &c_;
       coverage = 0;
       i = 0;
-      j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0;
+      j = c->rangeRecord.len ? c->rangeRecord[0].start : 0;
+      if (unlikely (c->rangeRecord[0].start > c->rangeRecord[0].end))
+      {
+        /* Broken table. Skip. */
+        i = c->rangeRecord.len;
+      }
     }
     inline bool more (void) { return i < c->rangeRecord.len; }
     inline void next (void)
@@ -842,7 +847,14 @@
         i++;
         if (more ())
         {
+          hb_codepoint_t old = j;
           j = c->rangeRecord[i].start;
+          if (unlikely (j <= old))
+          {
+            /* Broken table. Skip. Important to avoid DoS. */
+           i = c->rangeRecord.len;
+           return;
+          }
           coverage = c->rangeRecord[i].value;
         }
         return;
@@ -855,7 +867,8 @@
 
     private:
     const struct CoverageFormat2 *c;
-    unsigned int i, j, coverage;
+    unsigned int i, coverage;
+    hb_codepoint_t j;
   };
   private:
 
--- a/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-gpos-table.hh	Fri Jul 06 13:38:56 2018 +0530
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-gpos-table.hh	Fri Jul 06 10:37:47 2018 -0700
@@ -1074,10 +1074,13 @@
       if (!skippy_iter.prev ()) return_trace (false);
       /* We only want to attach to the first of a MultipleSubst sequence.
        * https://github.com/harfbuzz/harfbuzz/issues/740
-       * Reject others. */
+       * Reject others...
+       * ...but stop if we find a mark in the MultipleSubst sequence:
+       * https://github.com/harfbuzz/harfbuzz/issues/1020 */
       if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) ||
           0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) ||
           (skippy_iter.idx == 0 ||
+           _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) ||
            _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) !=
            _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) ||
            _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) !=
--- a/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-indic.cc	Fri Jul 06 13:38:56 2018 +0530
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-indic.cc	Fri Jul 06 10:37:47 2018 -0700
@@ -668,8 +668,9 @@
    *
    * 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.
+   * does it unconditionally in other scripts (eg. Malayalam, Bengali).  We
+   * don't currently know about other scripts, so we whitelist Malayalam and
+   * Bengali for now.
    *
    * Kannada test case:
    * U+0C9A,U+0CCD,U+0C9A,U+0CCD
@@ -679,10 +680,16 @@
    * Malayalam test case:
    * U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D
    * With lohit-ttf-20121122/Lohit-Malayalam.ttf
+   *
+   * Bengali test case
+   * U+0998,U+09CD,U+09AF,U+09CD
+   * With Windows XP vrinda.ttf
+   * https://github.com/harfbuzz/harfbuzz/issues/1073
    */
   if (indic_plan->is_old_spec)
   {
-    bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM;
+    bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM &&
+                                   buffer->props.script != HB_SCRIPT_BENGALI;
     for (unsigned int i = base + 1; i < end; i++)
       if (info[i].indic_category() == OT_H)
       {
--- a/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-khmer.cc	Fri Jul 06 13:38:56 2018 +0530
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-khmer.cc	Fri Jul 06 10:37:47 2018 -0700
@@ -372,22 +372,25 @@
         break;
       }
 
-    /* Note!  syllable() is a one-byte field. */
-    for (unsigned int i = base; i < end; i++)
-      if (info[i].syllable() != 255)
-      {
-        unsigned int max = i;
-        unsigned int j = start + info[i].syllable();
-        while (j != i)
+    if (unlikely (end - start >= 127))
+      buffer->merge_clusters (start, end);
+    else
+      /* Note!  syllable() is a one-byte field. */
+      for (unsigned int i = base; i < end; i++)
+        if (info[i].syllable() != 255)
         {
-          max = MAX (max, j);
-          unsigned int next = start + info[j].syllable();
-          info[j].syllable() = 255; /* So we don't process j later again. */
-          j = next;
+          unsigned int max = i;
+          unsigned int j = start + info[i].syllable();
+          while (j != i)
+          {
+            max = MAX (max, j);
+            unsigned int next = start + info[j].syllable();
+            info[j].syllable() = 255; /* So we don't process j later again. */
+            j = next;
+          }
+          if (i != max)
+            buffer->merge_clusters (i, max + 1);
         }
-        if (i != max)
-          buffer->merge_clusters (i, max + 1);
-      }
 
     /* Put syllable back in. */
     for (unsigned int i = start; i < end; i++)
--- a/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-private.hh	Fri Jul 06 13:38:56 2018 +0530
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-private.hh	Fri Jul 06 10:37:47 2018 -0700
@@ -1228,13 +1228,14 @@
 /* fallback for round() */
 #if !defined (HAVE_ROUND) && !defined (HAVE_DECL_ROUND)
 static inline double
-round (double x)
+_hb_round (double x)
 {
   if (x >= 0)
     return floor (x + 0.5);
   else
     return ceil (x - 0.5);
 }
+#define round(x) _hb_round(x)
 #endif
 
 
--- a/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-version.h	Fri Jul 06 13:38:56 2018 +0530
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-version.h	Fri Jul 06 10:37:47 2018 -0700
@@ -38,9 +38,9 @@
 
 #define HB_VERSION_MAJOR 1
 #define HB_VERSION_MINOR 8
-#define HB_VERSION_MICRO 1
+#define HB_VERSION_MICRO 2
 
-#define HB_VERSION_STRING "1.8.1"
+#define HB_VERSION_STRING "1.8.2"
 
 #define HB_VERSION_ATLEAST(major,minor,micro) \
         ((major)*10000+(minor)*100+(micro) <= \