changeset 13240:8c09472c3de2

8143177: Integrate harfbuzz opentype layout engine per JEP 258 Reviewed-by: srl, vadim, serb
author prr
date Mon, 23 Nov 2015 09:58:44 -0800
parents 184913381cb8
children 47095c5242d8
files make/lib/Awt2dLibraries.gmk make/mapfiles/libfontmanager/mapfile-vers make/mapfiles/libfontmanager/mapfile-vers.openjdk src/java.desktop/macosx/classes/sun/font/CFont.java src/java.desktop/share/classes/sun/font/Font2D.java src/java.desktop/share/classes/sun/font/GlyphLayout.java src/java.desktop/share/classes/sun/font/SunLayoutEngine.java src/java.desktop/share/classes/sun/font/TrueTypeFont.java src/java.desktop/share/native/libfontmanager/HBShaper.c src/java.desktop/share/native/libfontmanager/harfbuzz/hb-atomic-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-blob.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-blob.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-deserialize-json.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-deserialize-text.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-serialize.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-cache-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-common.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-common.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-coretext.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-coretext.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-deprecated.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-fallback-shape.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-font-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-font.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-font.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ft.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ft.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-mutex-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-object-private.hh 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-cmap-table.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-font.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-font.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-glyf-table.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-head-table.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-hhea-table.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-hmtx-table.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-common-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-gdef-table.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-gpos-table.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-gsub-table.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-gsubgpos-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-jstf-table.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-map-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-map.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-maxp-table.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-name-table.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-arabic-fallback.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-arabic-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-arabic-table.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-arabic-win1256.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-arabic.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-default.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-hangul.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-hebrew.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-indic-machine.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-indic-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-indic-table.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-indic.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-myanmar-machine.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-myanmar.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-thai.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-tibetan.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-use-machine.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-use-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-use-table.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-use.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-fallback-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-fallback.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-normalize-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-normalize.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-tag.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-tag.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-set-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-set.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-set.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shape-plan-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shape-plan.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shape-plan.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shape.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shape.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shaper-impl-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shaper-list.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shaper-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shaper.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ucdn.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ucdn/ucdn.c src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ucdn/ucdn.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ucdn/unicodedata_db.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-unicode-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-unicode.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb-unicode.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-utf-private.hh src/java.desktop/share/native/libfontmanager/harfbuzz/hb-version.h src/java.desktop/share/native/libfontmanager/harfbuzz/hb-warning.cc src/java.desktop/share/native/libfontmanager/harfbuzz/hb.h src/java.desktop/share/native/libfontmanager/hb-jdk-font.cc src/java.desktop/share/native/libfontmanager/hb-jdk.h src/java.desktop/share/native/libfontmanager/scriptMapping.c src/java.desktop/share/native/libfontmanager/scriptMapping.h test/java/awt/font/TextLayout/TestLayoutVsICU.java test/java/awt/font/TextLayout/TestLayoutVsICU_jdkbase.xml
diffstat 118 files changed, 52287 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/make/lib/Awt2dLibraries.gmk	Mon Nov 23 14:44:41 2015 +0300
+++ b/make/lib/Awt2dLibraries.gmk	Mon Nov 23 09:58:44 2015 -0800
@@ -602,6 +602,34 @@
     $(LIBJAVA_HEADER_FLAGS) \
     #
 
+#### Begin harfbuzz configuration
+
+HARFBUZZ_CFLAGS := -DHAVE_OT -DHAVE_FALLBACK -DHAVE_UCDN
+
+ifneq ($(OPENJDK_TARGET_OS), windows)
+  HARFBUZZ_CFLAGS += -DGETPAGESIZE -DHAVE_MPROTECT -DHAVE_PTHREAD \
+                      -DHAVE_SYSCONF -DHAVE_SYS_MMAN_H -DHAVE_UNISTD_H
+endif
+ifneq (, $(findstring $(OPENJDK_TARGET_OS), linux macosx))
+  HARFBUZZ_CFLAGS += -DHAVE_INTEL_ATOMIC_PRIMITIVES
+endif
+ifeq ($(OPENJDK_TARGET_OS), solaris)
+  HARFBUZZ_CFLAGS += -DHAVE_SOLARIS_ATOMIC_OPS
+endif
+ifeq ($(OPENJDK_TARGET_OS), macosx)
+  HARFBUZZ_CFLAGS += -DHAVE_CORETEXT
+endif
+ifneq ($(OPENJDK_TARGET_OS), macosx)
+  LIBFONTMANAGER_EXCLUDE_FILES += harfbuzz/hb-coretext.cc
+endif
+ifndef OPENJDK
+  LIBFONTMANAGER_EXCLUDE_FILES += harfbuzz/hb-ft.cc
+endif
+
+LIBFONTMANAGER_CFLAGS += $(HARFBUZZ_CFLAGS)
+
+#### End harfbuzz configuration
+
 ifndef OPENJDK
   LIBFONTMANAGER_CFLAGS += -I$(JDK_TOPDIR)/src/closed/java.desktop/share/native/libt2k
   BUILD_LIBFONTMANAGER_MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libfontmanager/mapfile-vers
@@ -648,11 +676,11 @@
     OPTIMIZATION := $(LIBFONTMANAGER_OPTIMIZATION), \
     CFLAGS_windows = -DCC_NOEX, \
     DISABLED_WARNINGS_gcc := sign-compare int-to-pointer-cast reorder \
-        delete-non-virtual-dtor type-limits, \
+        delete-non-virtual-dtor type-limits missing-field-initializers, \
     DISABLED_WARNINGS_clang := unused-value incompatible-pointer-types \
         tautological-constant-out-of-range-compare int-to-pointer-cast, \
     DISABLED_WARNINGS_solstudio := truncwarn, \
-    DISABLED_WARNINGS_microsoft := 4267 4244 4018 4090 4996 4146, \
+    DISABLED_WARNINGS_microsoft := 4267 4244 4018 4090 4996 4146 4334, \
     WARNINGS_AS_ERRORS_gcc := false, \
     WARNINGS_AS_ERRORS_solstudio := false, \
     MAPFILE := $(BUILD_LIBFONTMANAGER_MAPFILE), \
--- a/make/mapfiles/libfontmanager/mapfile-vers	Mon Nov 23 14:44:41 2015 +0300
+++ b/make/mapfiles/libfontmanager/mapfile-vers	Mon Nov 23 09:58:44 2015 -0800
@@ -41,6 +41,7 @@
                 Java_sun_font_StrikeCache_freeLongMemory;
                 Java_sun_font_SunLayoutEngine_initGVIDs;
                 Java_sun_font_SunLayoutEngine_nativeLayout;
+                Java_sun_font_SunLayoutEngine_shape;
                 Java_sun_font_X11TextRenderer_doDrawGlyphList;
 		Java_sun_java2d_loops_DrawGlyphListAA_DrawGlyphListAA;
 		Java_sun_java2d_loops_DrawGlyphListLCD_DrawGlyphListLCD;
--- a/make/mapfiles/libfontmanager/mapfile-vers.openjdk	Mon Nov 23 14:44:41 2015 +0300
+++ b/make/mapfiles/libfontmanager/mapfile-vers.openjdk	Mon Nov 23 09:58:44 2015 -0800
@@ -43,6 +43,7 @@
                 Java_sun_font_StrikeCache_freeLongMemory;
                 Java_sun_font_SunLayoutEngine_initGVIDs;
                 Java_sun_font_SunLayoutEngine_nativeLayout;
+                Java_sun_font_SunLayoutEngine_shape;
                 Java_sun_font_X11TextRenderer_doDrawGlyphList;
 		Java_sun_java2d_loops_DrawGlyphListAA_DrawGlyphListAA;
 		Java_sun_java2d_loops_DrawGlyphListLCD_DrawGlyphListLCD;
--- a/src/java.desktop/macosx/classes/sun/font/CFont.java	Mon Nov 23 14:44:41 2015 +0300
+++ b/src/java.desktop/macosx/classes/sun/font/CFont.java	Mon Nov 23 09:58:44 2015 -0800
@@ -198,6 +198,13 @@
         return nativeFontPtr;
     }
 
+    private native long getCGFontPtrNative(long ptr);
+
+    // This digs the CGFont out of the AWTFont.
+    protected synchronized long getPlatformNativeFontPtr() {
+        return getCGFontPtrNative(getNativeFontPtr());
+    }
+
     static native void getCascadeList(long nativeFontPtr, ArrayList<String> listOfString);
 
     private CompositeFont createCompositeFont() {
--- a/src/java.desktop/share/classes/sun/font/Font2D.java	Mon Nov 23 14:44:41 2015 +0300
+++ b/src/java.desktop/share/classes/sun/font/Font2D.java	Mon Nov 23 09:58:44 2015 -0800
@@ -472,6 +472,12 @@
         return 0L;
     }
 
+    /* Used only on OS X.
+     */
+    protected long getPlatformNativeFontPtr() {
+        return 0L;
+    }
+
     /* for layout code */
     protected long getUnitsPerEm() {
         return 2048;
--- a/src/java.desktop/share/classes/sun/font/GlyphLayout.java	Mon Nov 23 14:44:41 2015 +0300
+++ b/src/java.desktop/share/classes/sun/font/GlyphLayout.java	Mon Nov 23 09:58:44 2015 -0800
@@ -96,6 +96,7 @@
     private Point2D.Float _pt;
     private FontStrikeDesc _sd;
     private float[] _mat;
+    private float ptSize;
     private int _typo_flags;
     private int _offset;
 
@@ -172,7 +173,7 @@
          * If the GVData does not have room for the glyphs, throws an IndexOutOfBoundsException and
          * leave pt and the gvdata unchanged.
          */
-        public void layout(FontStrikeDesc sd, float[] mat, int gmask,
+        public void layout(FontStrikeDesc sd, float[] mat, float ptSize, int gmask,
                            int baseIndex, TextRecord text, int typo_flags, Point2D.Float pt, GVData data);
     }
 
@@ -386,6 +387,7 @@
         _mat[2] = (float)txinfo.gtx.getShearX();
         _mat[3] = (float)txinfo.gtx.getScaleY();
         _pt.setLocation(txinfo.delta);
+        ptSize = font.getSize2D();
 
         int lim = offset + count;
 
@@ -682,7 +684,7 @@
         void layout() {
             _textRecord.start = start;
             _textRecord.limit = limit;
-            engine.layout(_sd, _mat, gmask, start - _offset, _textRecord,
+            engine.layout(_sd, _mat, ptSize, gmask, start - _offset, _textRecord,
                           _typo_flags | eflags, _pt, _gvdata);
         }
     }
--- a/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java	Mon Nov 23 14:44:41 2015 +0300
+++ b/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java	Mon Nov 23 09:58:44 2015 -0800
@@ -103,9 +103,20 @@
  * */
 public final class SunLayoutEngine implements LayoutEngine, LayoutEngineFactory {
     private static native void initGVIDs();
+    private static final boolean useICU;
     static {
         FontManagerNativeLibrary.load();
         initGVIDs();
+        String le = java.security.AccessController.doPrivileged(
+            new sun.security.action.
+                GetPropertyAction("sun.font.layoutengine", ""));
+        useICU = le.equals("icu");
+        String verbose = java.security.AccessController.doPrivileged(
+            new sun.security.action.
+                GetPropertyAction("sun.font.layoutengine.verbose", ""));
+        if ("true".equalsIgnoreCase(verbose)) {
+            System.out.println("Using " + (useICU ? "icu." : "harfbuzz."));
+        }
     }
 
     private LayoutEngineKey key;
@@ -150,21 +161,57 @@
         this.key = key;
     }
 
-    public void layout(FontStrikeDesc desc, float[] mat, int gmask,
+    private boolean isAAT(Font2D font) {
+       if (font instanceof TrueTypeFont) {
+           TrueTypeFont ttf = (TrueTypeFont)font;
+           return ttf.getDirectoryEntry(TrueTypeFont.morxTag) != null ||
+                  ttf.getDirectoryEntry(TrueTypeFont.mortTag) != null;
+       } else if (font instanceof PhysicalFont) {
+           PhysicalFont pf = (PhysicalFont)font;
+           return pf.getTableBytes(TrueTypeFont.morxTag) != null ||
+                  pf.getTableBytes(TrueTypeFont.mortTag) != null;
+       }
+       return false;
+    }
+
+    public void layout(FontStrikeDesc desc, float[] mat, float ptSize, int gmask,
                        int baseIndex, TextRecord tr, int typo_flags,
                        Point2D.Float pt, GVData data) {
         Font2D font = key.font();
         FontStrike strike = font.getStrike(desc);
         long layoutTables = font.getLayoutTableCache();
+        if (useICU) {
         nativeLayout(font, strike, mat, gmask, baseIndex,
              tr.text, tr.start, tr.limit, tr.min, tr.max,
              key.script(), key.lang(), typo_flags, pt, data,
              font.getUnitsPerEm(), layoutTables);
+        } else {
+            long pNativeFont = font.getPlatformNativeFontPtr(); // used on OSX
+            // pScaler probably not needed long term.
+            long pScaler = 0L;
+            if (font instanceof FileFont) {
+                pScaler = ((FileFont)font).getScaler().nativeScaler;
+            }
+            shape(font, strike, ptSize, mat, pScaler, pNativeFont, isAAT(font),
+                  tr.text, data, key.script(),
+                  tr.start, tr.limit, baseIndex, pt,
+                  typo_flags, gmask);
+         }
     }
 
+    /* Native method to invoke ICU layout engine */
     private static native void
         nativeLayout(Font2D font, FontStrike strike, float[] mat, int gmask,
              int baseIndex, char[] chars, int offset, int limit,
              int min, int max, int script, int lang, int typo_flags,
              Point2D.Float pt, GVData data, long upem, long layoutTables);
+
+
+    /* Native method to invoke harfbuzz layout engine */
+    private static native boolean
+        shape(Font2D font, FontStrike strike, float ptSize, float[] mat,
+              long pscaler, long pNativeFont, boolean aat,
+              char[] chars, GVData data,
+              int script, int offset, int limit,
+              int baseIndex, Point2D.Float pt, int typo_flags, int slot);
 }
--- a/src/java.desktop/share/classes/sun/font/TrueTypeFont.java	Mon Nov 23 14:44:41 2015 +0300
+++ b/src/java.desktop/share/classes/sun/font/TrueTypeFont.java	Mon Nov 23 09:58:44 2015 -0800
@@ -83,6 +83,7 @@
     public static final int GPOSTag = 0x47504F53; // 'GPOS'
     public static final int GSUBTag = 0x47535542; // 'GSUB'
     public static final int mortTag = 0x6D6F7274; // 'mort'
+    public static final int morxTag = 0x6D6F7278; // 'morx'
 
     /* -- Tags for non-standard tables */
     public static final int fdscTag = 0x66647363; // 'fdsc' - gxFont descriptor
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/HBShaper.c	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <jni_util.h>
+#include <stdlib.h>
+#include "hb.h"
+#include "hb-jdk.h"
+#include "hb-ot.h"
+#ifdef MACOSX
+#include "hb-coretext.h"
+#endif
+#include "scriptMapping.h"
+
+static jclass gvdClass = 0;
+static const char* gvdClassName = "sun/font/GlyphLayout$GVData";
+static jfieldID gvdCountFID = 0;
+static jfieldID gvdFlagsFID = 0;
+static jfieldID gvdGlyphsFID = 0;
+static jfieldID gvdPositionsFID = 0;
+static jfieldID gvdIndicesFID = 0;
+static int jniInited = 0;
+
+static void getFloat(JNIEnv* env, jobject pt, jfloat *x, jfloat *y) {
+    *x = (*env)->GetFloatField(env, pt, sunFontIDs.xFID);
+    *y = (*env)->GetFloatField(env, pt, sunFontIDs.yFID);
+}
+
+static void putFloat(JNIEnv* env, jobject pt, jfloat x, jfloat y) {
+    (*env)->SetFloatField(env, pt, sunFontIDs.xFID, x);
+    (*env)->SetFloatField(env, pt, sunFontIDs.yFID, y);
+}
+
+static int init_JNI_IDs(JNIEnv *env) {
+    if (jniInited) {
+        return jniInited;
+    }
+    CHECK_NULL_RETURN(gvdClass = (*env)->FindClass(env, gvdClassName), 0);
+    CHECK_NULL_RETURN(gvdClass = (jclass)(*env)->NewGlobalRef(env, gvdClass), 0);
+    CHECK_NULL_RETURN(gvdCountFID = (*env)->GetFieldID(env, gvdClass, "_count", "I"), 0);
+    CHECK_NULL_RETURN(gvdFlagsFID = (*env)->GetFieldID(env, gvdClass, "_flags", "I"), 0);
+    CHECK_NULL_RETURN(gvdGlyphsFID = (*env)->GetFieldID(env, gvdClass, "_glyphs", "[I"), 0);
+    CHECK_NULL_RETURN(gvdPositionsFID = (*env)->GetFieldID(env, gvdClass, "_positions", "[F"), 0);
+    CHECK_NULL_RETURN(gvdIndicesFID = (*env)->GetFieldID(env, gvdClass, "_indices", "[I"), 0);
+    jniInited = 1;
+    return jniInited;
+}
+
+// gmask is the composite font slot mask
+// baseindex is to be added to the character (code point) index.
+int storeGVData(JNIEnv* env,
+               jobject gvdata, jint slot, jint baseIndex, jobject startPt,
+               int glyphCount, hb_glyph_info_t *glyphInfo,
+               hb_glyph_position_t *glyphPos, hb_direction_t direction) {
+
+    int i;
+    float x=0, y=0;
+    float startX, startY;
+    float scale = 1.0f/64.0f;
+    unsigned int* glyphs;
+    float* positions;
+
+    if (!init_JNI_IDs(env)) {
+        return 0;
+    }
+
+    int initialCount = (*env)->GetIntField(env, gvdata, gvdCountFID);
+    jarray glyphArray =
+       (jarray)(*env)->GetObjectField(env, gvdata, gvdGlyphsFID);
+    jarray posArray =
+        (jarray)(*env)->GetObjectField(env, gvdata, gvdPositionsFID);
+
+    if (glyphArray == NULL || posArray == NULL)
+    {
+        JNU_ThrowArrayIndexOutOfBoundsException(env, "");
+        return 0;
+    }
+
+    // The Java code catches the IIOBE and expands the storage
+    // and re-invokes layout. I suppose this is expected to be rare
+    // because at least in a single threaded case there should be
+    // re-use of the same container, but it is a little wasteful/distateful.
+    int glyphArrayLen = (*env)->GetArrayLength(env, glyphArray);
+    int posArrayLen = (*env)->GetArrayLength(env, posArray);
+    int maxGlyphs = glyphCount + initialCount;
+    if ((maxGlyphs >  glyphArrayLen) ||
+        (maxGlyphs * 2 + 2 >  posArrayLen))
+    {
+        JNU_ThrowArrayIndexOutOfBoundsException(env, "");
+        return 0;
+    }
+
+    getFloat(env, startPt, &startX, &startY);
+
+    glyphs =
+        (unsigned int*)(*env)->GetPrimitiveArrayCritical(env, glyphArray, NULL);
+    positions = (jfloat*)(*env)->GetPrimitiveArrayCritical(env, posArray, NULL);
+    for (i = 0; i < glyphCount; i++) {
+        int storei = i + initialCount;
+        int index = glyphInfo[i].codepoint | slot;
+        if (i<glyphCount)glyphs[storei] = (unsigned int)index;
+        positions[(storei*2)] = startX + x + glyphPos[i].x_offset * scale;
+        positions[(storei*2)+1] = startY + y - glyphPos[i].y_offset * scale;
+        x += glyphPos[i].x_advance * scale;
+        y += glyphPos[i].y_advance * scale;
+    }
+    int storeadv = initialCount+glyphCount;
+    // The final slot in the positions array is important
+    // because when the GlyphVector is created from this
+    // data it determines the overall advance of the glyphvector
+    // and this is used in positioning the next glyphvector
+    // during rendering where text is broken into runs.
+    // We also need to report it back into "pt", so layout can
+    // pass it back down for that next run in this code.
+    positions[(storeadv*2)] = startX + x;
+    positions[(storeadv*2)+1] = startY + y;
+    (*env)->ReleasePrimitiveArrayCritical(env, glyphArray, glyphs, 0);
+    (*env)->ReleasePrimitiveArrayCritical(env, posArray, positions, 0);
+    putFloat(env, startPt,positions[(storeadv*2)],positions[(storeadv*2)+1] );
+    jarray inxArray =
+        (jarray)(*env)->GetObjectField(env, gvdata, gvdIndicesFID);
+    unsigned int* indices =
+        (unsigned int*)(*env)->GetPrimitiveArrayCritical(env, inxArray, NULL);
+    int prevCluster = -1;
+    for (i = 0; i < glyphCount; i++) {
+        int cluster = glyphInfo[i].cluster;
+        if (direction == HB_DIRECTION_LTR) {
+            // I need to understand what hb does when processing a substring
+            // I expected the cluster index to be from the start of the text
+            // to process.
+            // Instead it appears to be from the start of the whole thing.
+            indices[i+initialCount] = cluster;
+        } else {
+            indices[i+initialCount] = baseIndex + glyphCount -1 -i;
+        }
+    }
+    (*env)->ReleasePrimitiveArrayCritical(env, inxArray, indices, 0);
+    (*env)->SetIntField(env, gvdata, gvdCountFID, initialCount+glyphCount);
+    return initialCount+glyphCount;
+}
+
+static float euclidianDistance(float a, float b)
+{
+    float root;
+    if (a < 0) {
+        a = -a;
+    }
+
+    if (b < 0) {
+        b = -b;
+    }
+
+    if (a == 0) {
+        return b;
+    }
+
+    if (b == 0) {
+        return a;
+    }
+
+    /* Do an initial approximation, in root */
+    root = a > b ? a + (b / 2) : b + (a / 2);
+
+    /* An unrolled Newton-Raphson iteration sequence */
+    root = (root + (a * (a / root)) + (b * (b / root)) + 1) / 2;
+    root = (root + (a * (a / root)) + (b * (b / root)) + 1) / 2;
+    root = (root + (a * (a / root)) + (b * (b / root)) + 1) / 2;
+
+    return root;
+}
+
+JDKFontInfo*
+     createJDKFontInfo(JNIEnv *env,
+                       jobject font2D,
+                       jobject fontStrike,
+                       jfloat ptSize,
+                       jlong pScaler,
+                       jlong pNativeFont,
+                       jfloatArray matrix,
+                       jboolean aat) {
+
+
+    JDKFontInfo *fi = (JDKFontInfo*)malloc(sizeof(JDKFontInfo));
+    if (!fi) {
+       return NULL;
+    }
+    fi->env = env; // this is valid only for the life of this JNI call.
+    fi->font2D = font2D;
+    fi->fontStrike = fontStrike;
+    fi->nativeFont = pNativeFont;
+    fi->aat = aat;
+    (*env)->GetFloatArrayRegion(env, matrix, 0, 4, fi->matrix);
+    fi->ptSize = ptSize;
+    fi->xPtSize = euclidianDistance(fi->matrix[0], fi->matrix[1]);
+    fi->yPtSize = euclidianDistance(fi->matrix[2], fi->matrix[3]);
+
+    return fi;
+}
+
+
+#define TYPO_RTL 0x80000000
+
+JNIEXPORT jboolean JNICALL Java_sun_font_SunLayoutEngine_shape
+    (JNIEnv *env, jclass cls,
+     jobject font2D,
+     jobject fontStrike,
+     jfloat ptSize,
+     jfloatArray matrix,
+     jlong pScaler,
+     jlong pNativeFont,
+     jboolean aat,
+     jcharArray text,
+     jobject gvdata,
+     jint script,
+     jint offset,
+     jint limit,
+     jint baseIndex,
+     jobject startPt,
+     jint flags,
+     jint slot) {
+
+     hb_buffer_t *buffer;
+     hb_font_t* hbfont;
+     jchar  *chars;
+     jsize len;
+     int glyphCount;
+     hb_glyph_info_t *glyphInfo;
+     hb_glyph_position_t *glyphPos;
+     hb_direction_t direction = HB_DIRECTION_LTR;
+     hb_feature_t *features =  NULL;
+     int featureCount = 0;
+
+     int i;
+     unsigned int buflen;
+
+     JDKFontInfo *jdkFontInfo =
+         createJDKFontInfo(env, font2D, fontStrike, ptSize,
+                           pScaler, pNativeFont, matrix, aat);
+     if (!jdkFontInfo) {
+        return JNI_FALSE;
+     }
+     jdkFontInfo->env = env; // this is valid only for the life of this JNI call.
+     jdkFontInfo->font2D = font2D;
+     jdkFontInfo->fontStrike = fontStrike;
+
+     hbfont = hb_jdk_font_create(jdkFontInfo, NULL);
+
+     buffer = hb_buffer_create();
+     hb_buffer_set_script(buffer, getHBScriptCode(script));
+     hb_buffer_set_language(buffer,
+                            hb_ot_tag_to_language(HB_OT_TAG_DEFAULT_LANGUAGE));
+     if ((flags & TYPO_RTL) != 0) {
+         direction = HB_DIRECTION_RTL;
+     }
+     hb_buffer_set_direction(buffer, direction);
+
+     chars = (*env)->GetCharArrayElements(env, text, NULL);
+     len = (*env)->GetArrayLength(env, text);
+
+     hb_buffer_add_utf16(buffer, chars, len, offset, limit-offset);
+
+     hb_shape_full(hbfont, buffer, features, featureCount, 0);
+     glyphCount = hb_buffer_get_length(buffer);
+     glyphInfo = hb_buffer_get_glyph_infos(buffer, 0);
+     glyphPos = hb_buffer_get_glyph_positions(buffer, &buflen);
+     for (i = 0; i < glyphCount; i++) {
+         int index = glyphInfo[i].codepoint;
+         int xadv = (glyphPos[i].x_advance);
+         int yadv = (glyphPos[i].y_advance);
+     }
+     // On "input" HB assigns a cluster index to each character in UTF-16.
+     // On output where a sequence of characters have been mapped to
+     // a glyph they are all mapped to the cluster index of the first character.
+     // The next cluster index will be that of the first character in the
+     // next cluster. So cluster indexes may 'skip' on output.
+     // This can also happen if there are supplementary code-points
+     // such that two UTF-16 characters are needed to make one codepoint.
+     // In RTL text you need to count down.
+     // So the following code tries to build the reverse map as expected
+     // by calling code.
+
+     storeGVData(env, gvdata, slot, baseIndex, startPt,
+                 glyphCount, glyphInfo, glyphPos, direction);
+
+     hb_buffer_destroy (buffer);
+     hb_font_destroy(hbfont);
+     free((void*)jdkFontInfo);
+     if (features != NULL) free(features);
+
+     return JNI_TRUE;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-atomic-private.hh	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,164 @@
+/*
+ * Copyright © 2007  Chris Wilson
+ * Copyright © 2009,2010  Red Hat, Inc.
+ * Copyright © 2011,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.
+ *
+ * Contributor(s):
+ *      Chris Wilson <chris@chris-wilson.co.uk>
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_ATOMIC_PRIVATE_HH
+#define HB_ATOMIC_PRIVATE_HH
+
+#include "hb-private.hh"
+
+
+/* atomic_int */
+
+/* We need external help for these */
+
+#if defined(hb_atomic_int_impl_add) \
+ && defined(hb_atomic_ptr_impl_get) \
+ && defined(hb_atomic_ptr_impl_cmpexch)
+
+/* Defined externally, i.e. in config.h; must have typedef'ed hb_atomic_int_impl_t as well. */
+
+
+#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
+
+#include <windows.h>
+
+/* MinGW has a convoluted history of supporting MemoryBarrier
+ * properly.  As such, define a function to wrap the whole
+ * thing. */
+static inline void _HBMemoryBarrier (void) {
+#if !defined(MemoryBarrier)
+  long dummy = 0;
+  InterlockedExchange (&dummy, 1);
+#else
+  MemoryBarrier ();
+#endif
+}
+
+typedef LONG hb_atomic_int_impl_t;
+#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
+#define hb_atomic_int_impl_add(AI, V)           InterlockedExchangeAdd (&(AI), (V))
+
+#define hb_atomic_ptr_impl_get(P)               (_HBMemoryBarrier (), (void *) *(P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)       (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
+
+
+#elif !defined(HB_NO_MT) && defined(__APPLE__)
+
+#include <libkern/OSAtomic.h>
+#ifdef __MAC_OS_X_MIN_REQUIRED
+#include <AvailabilityMacros.h>
+#elif defined(__IPHONE_OS_MIN_REQUIRED)
+#include <Availability.h>
+#endif
+
+
+typedef int32_t hb_atomic_int_impl_t;
+#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
+#define hb_atomic_int_impl_add(AI, V)           (OSAtomicAdd32Barrier ((V), &(AI)) - (V))
+
+#define hb_atomic_ptr_impl_get(P)               (OSMemoryBarrier (), (void *) *(P))
+#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)       OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
+#else
+#if __ppc64__ || __x86_64__ || __aarch64__
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)       OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
+#else
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)       OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))
+#endif
+#endif
+
+
+#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
+
+typedef int hb_atomic_int_impl_t;
+#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
+#define hb_atomic_int_impl_add(AI, V)           __sync_fetch_and_add (&(AI), (V))
+
+#define hb_atomic_ptr_impl_get(P)               (void *) (__sync_synchronize (), *(P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)       __sync_bool_compare_and_swap ((P), (O), (N))
+
+
+#elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS)
+
+#include <atomic.h>
+#include <mbarrier.h>
+
+typedef unsigned int hb_atomic_int_impl_t;
+#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
+#define hb_atomic_int_impl_add(AI, V)           ( ({__machine_rw_barrier ();}), atomic_add_int_nv (&(AI), (V)) - (V))
+
+#define hb_atomic_ptr_impl_get(P)               ( ({__machine_rw_barrier ();}), (void *) *(P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)       ( ({__machine_rw_barrier ();}), atomic_cas_ptr ((void **) (P), (void *) (O), (void *) (N)) == (void *) (O) ? true : false)
+
+
+#elif !defined(HB_NO_MT)
+
+#define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */
+
+typedef volatile int hb_atomic_int_impl_t;
+#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
+#define hb_atomic_int_impl_add(AI, V)           (((AI) += (V)) - (V))
+
+#define hb_atomic_ptr_impl_get(P)               ((void *) *(P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)       (* (void * volatile *) (P) == (void *) (O) ? (* (void * volatile *) (P) = (void *) (N), true) : false)
+
+
+#else /* HB_NO_MT */
+
+typedef int hb_atomic_int_impl_t;
+#define HB_ATOMIC_INT_IMPL_INIT(V)              (V)
+#define hb_atomic_int_impl_add(AI, V)           (((AI) += (V)) - (V))
+
+#define hb_atomic_ptr_impl_get(P)               ((void *) *(P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)       (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
+
+
+#endif
+
+
+#define HB_ATOMIC_INT_INIT(V)           {HB_ATOMIC_INT_IMPL_INIT(V)}
+
+struct hb_atomic_int_t
+{
+  hb_atomic_int_impl_t v;
+
+  inline void set_unsafe (int v_) { v = v_; }
+  inline int get_unsafe (void) const { return v; }
+  inline int inc (void) { return hb_atomic_int_impl_add (const_cast<hb_atomic_int_impl_t &> (v),  1); }
+  inline int dec (void) { return hb_atomic_int_impl_add (const_cast<hb_atomic_int_impl_t &> (v), -1); }
+};
+
+
+#define hb_atomic_ptr_get(P) hb_atomic_ptr_impl_get(P)
+#define hb_atomic_ptr_cmpexch(P,O,N) hb_atomic_ptr_impl_cmpexch((P),(O),(N))
+
+
+#endif /* HB_ATOMIC_PRIVATE_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-blob.cc	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,479 @@
+/*
+ * Copyright © 2009  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
+ */
+
+/* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 199309L
+#endif
+
+#include "hb-private.hh"
+
+#include "hb-object-private.hh"
+
+#ifdef HAVE_SYS_MMAN_H
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <sys/mman.h>
+#endif /* HAVE_SYS_MMAN_H */
+
+#include <stdio.h>
+#include <errno.h>
+
+
+
+#ifndef HB_DEBUG_BLOB
+#define HB_DEBUG_BLOB (HB_DEBUG+0)
+#endif
+
+
+struct hb_blob_t {
+  hb_object_header_t header;
+  ASSERT_POD ();
+
+  bool immutable;
+
+  const char *data;
+  unsigned int length;
+  hb_memory_mode_t mode;
+
+  void *user_data;
+  hb_destroy_func_t destroy;
+};
+
+
+static bool _try_writable (hb_blob_t *blob);
+
+static void
+_hb_blob_destroy_user_data (hb_blob_t *blob)
+{
+  if (blob->destroy) {
+    blob->destroy (blob->user_data);
+    blob->user_data = NULL;
+    blob->destroy = NULL;
+  }
+}
+
+/**
+ * hb_blob_create: (skip)
+ * @data: Pointer to blob data.
+ * @length: Length of @data in bytes.
+ * @mode: Memory mode for @data.
+ * @user_data: Data parameter to pass to @destroy.
+ * @destroy: Callback to call when @data is not needed anymore.
+ *
+ * Creates a new "blob" object wrapping @data.  The @mode parameter is used
+ * to negotiate ownership and lifecycle of @data.
+ *
+ * Return value: New blob, or the empty blob if something failed or if @length is
+ * zero.  Destroy with hb_blob_destroy().
+ *
+ * Since: 0.9.2
+ **/
+hb_blob_t *
+hb_blob_create (const char        *data,
+                unsigned int       length,
+                hb_memory_mode_t   mode,
+                void              *user_data,
+                hb_destroy_func_t  destroy)
+{
+  hb_blob_t *blob;
+
+  if (!length ||
+      length >= 1u << 31 ||
+      data + length < data /* overflows */ ||
+      !(blob = hb_object_create<hb_blob_t> ())) {
+    if (destroy)
+      destroy (user_data);
+    return hb_blob_get_empty ();
+  }
+
+  blob->data = data;
+  blob->length = length;
+  blob->mode = mode;
+
+  blob->user_data = user_data;
+  blob->destroy = destroy;
+
+  if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
+    blob->mode = HB_MEMORY_MODE_READONLY;
+    if (!_try_writable (blob)) {
+      hb_blob_destroy (blob);
+      return hb_blob_get_empty ();
+    }
+  }
+
+  return blob;
+}
+
+/**
+ * hb_blob_create_sub_blob:
+ * @parent: Parent blob.
+ * @offset: Start offset of sub-blob within @parent, in bytes.
+ * @length: Length of sub-blob.
+ *
+ * Returns a blob that represents a range of bytes in @parent.  The new
+ * blob is always created with %HB_MEMORY_MODE_READONLY, meaning that it
+ * will never modify data in the parent blob.  The parent data is not
+ * expected to be modified, and will result in undefined behavior if it
+ * is.
+ *
+ * Makes @parent immutable.
+ *
+ * Return value: New blob, or the empty blob if something failed or if
+ * @length is zero or @offset is beyond the end of @parent's data.  Destroy
+ * with hb_blob_destroy().
+ *
+ * Since: 0.9.2
+ **/
+hb_blob_t *
+hb_blob_create_sub_blob (hb_blob_t    *parent,
+                         unsigned int  offset,
+                         unsigned int  length)
+{
+  hb_blob_t *blob;
+
+  if (!length || offset >= parent->length)
+    return hb_blob_get_empty ();
+
+  hb_blob_make_immutable (parent);
+
+  blob = hb_blob_create (parent->data + offset,
+                         MIN (length, parent->length - offset),
+                         HB_MEMORY_MODE_READONLY,
+                         hb_blob_reference (parent),
+                         (hb_destroy_func_t) hb_blob_destroy);
+
+  return blob;
+}
+
+/**
+ * hb_blob_get_empty:
+ *
+ * Returns the singleton empty blob.
+ *
+ * See TODO:link object types for more information.
+ *
+ * Return value: (transfer full): the empty blob.
+ *
+ * Since: 0.9.2
+ **/
+hb_blob_t *
+hb_blob_get_empty (void)
+{
+  static const hb_blob_t _hb_blob_nil = {
+    HB_OBJECT_HEADER_STATIC,
+
+    true, /* immutable */
+
+    NULL, /* data */
+    0, /* length */
+    HB_MEMORY_MODE_READONLY, /* mode */
+
+    NULL, /* user_data */
+    NULL  /* destroy */
+  };
+
+  return const_cast<hb_blob_t *> (&_hb_blob_nil);
+}
+
+/**
+ * hb_blob_reference: (skip)
+ * @blob: a blob.
+ *
+ * Increases the reference count on @blob.
+ *
+ * See TODO:link object types for more information.
+ *
+ * Return value: @blob.
+ *
+ * Since: 0.9.2
+ **/
+hb_blob_t *
+hb_blob_reference (hb_blob_t *blob)
+{
+  return hb_object_reference (blob);
+}
+
+/**
+ * hb_blob_destroy: (skip)
+ * @blob: a blob.
+ *
+ * Descreases the reference count on @blob, and if it reaches zero, destroys
+ * @blob, freeing all memory, possibly calling the destroy-callback the blob
+ * was created for if it has not been called already.
+ *
+ * See TODO:link object types for more information.
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_blob_destroy (hb_blob_t *blob)
+{
+  if (!hb_object_destroy (blob)) return;
+
+  _hb_blob_destroy_user_data (blob);
+
+  free (blob);
+}
+
+/**
+ * hb_blob_set_user_data: (skip)
+ * @blob: a blob.
+ * @key: key for data to set.
+ * @data: data to set.
+ * @destroy: callback to call when @data is not needed anymore.
+ * @replace: whether to replace an existing data with the same key.
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_blob_set_user_data (hb_blob_t          *blob,
+                       hb_user_data_key_t *key,
+                       void *              data,
+                       hb_destroy_func_t   destroy,
+                       hb_bool_t           replace)
+{
+  return hb_object_set_user_data (blob, key, data, destroy, replace);
+}
+
+/**
+ * hb_blob_get_user_data: (skip)
+ * @blob: a blob.
+ * @key: key for data to get.
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.2
+ **/
+void *
+hb_blob_get_user_data (hb_blob_t          *blob,
+                       hb_user_data_key_t *key)
+{
+  return hb_object_get_user_data (blob, key);
+}
+
+
+/**
+ * hb_blob_make_immutable:
+ * @blob: a blob.
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_blob_make_immutable (hb_blob_t *blob)
+{
+  if (hb_object_is_inert (blob))
+    return;
+
+  blob->immutable = true;
+}
+
+/**
+ * hb_blob_is_immutable:
+ * @blob: a blob.
+ *
+ *
+ *
+ * Return value: TODO
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_blob_is_immutable (hb_blob_t *blob)
+{
+  return blob->immutable;
+}
+
+
+/**
+ * hb_blob_get_length:
+ * @blob: a blob.
+ *
+ *
+ *
+ * Return value: the length of blob data in bytes.
+ *
+ * Since: 0.9.2
+ **/
+unsigned int
+hb_blob_get_length (hb_blob_t *blob)
+{
+  return blob->length;
+}
+
+/**
+ * hb_blob_get_data:
+ * @blob: a blob.
+ * @length: (out):
+ *
+ *
+ *
+ * Returns: (transfer none) (array length=length):
+ *
+ * Since: 0.9.2
+ **/
+const char *
+hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
+{
+  if (length)
+    *length = blob->length;
+
+  return blob->data;
+}
+
+/**
+ * hb_blob_get_data_writable:
+ * @blob: a blob.
+ * @length: (out): output length of the writable data.
+ *
+ * Tries to make blob data writable (possibly copying it) and
+ * return pointer to data.
+ *
+ * Fails if blob has been made immutable, or if memory allocation
+ * fails.
+ *
+ * Returns: (transfer none) (array length=length): Writable blob data,
+ * or %NULL if failed.
+ *
+ * Since: 0.9.2
+ **/
+char *
+hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
+{
+  if (!_try_writable (blob)) {
+    if (length)
+      *length = 0;
+
+    return NULL;
+  }
+
+  if (length)
+    *length = blob->length;
+
+  return const_cast<char *> (blob->data);
+}
+
+
+static hb_bool_t
+_try_make_writable_inplace_unix (hb_blob_t *blob)
+{
+#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT)
+  uintptr_t pagesize = -1, mask, length;
+  const char *addr;
+
+#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
+  pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE);
+#elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
+  pagesize = (uintptr_t) sysconf (_SC_PAGESIZE);
+#elif defined(HAVE_GETPAGESIZE)
+  pagesize = (uintptr_t) getpagesize ();
+#endif
+
+  if ((uintptr_t) -1L == pagesize) {
+    DEBUG_MSG_FUNC (BLOB, blob, "failed to get pagesize: %s", strerror (errno));
+    return false;
+  }
+  DEBUG_MSG_FUNC (BLOB, blob, "pagesize is %lu", (unsigned long) pagesize);
+
+  mask = ~(pagesize-1);
+  addr = (const char *) (((uintptr_t) blob->data) & mask);
+  length = (const char *) (((uintptr_t) blob->data + blob->length + pagesize-1) & mask)  - addr;
+  DEBUG_MSG_FUNC (BLOB, blob,
+                  "calling mprotect on [%p..%p] (%lu bytes)",
+                  addr, addr+length, (unsigned long) length);
+  if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) {
+    DEBUG_MSG_FUNC (BLOB, blob, "mprotect failed: %s", strerror (errno));
+    return false;
+  }
+
+  blob->mode = HB_MEMORY_MODE_WRITABLE;
+
+  DEBUG_MSG_FUNC (BLOB, blob,
+                  "successfully made [%p..%p] (%lu bytes) writable\n",
+                  addr, addr+length, (unsigned long) length);
+  return true;
+#else
+  return false;
+#endif
+}
+
+static bool
+_try_writable_inplace (hb_blob_t *blob)
+{
+  DEBUG_MSG_FUNC (BLOB, blob, "making writable inplace\n");
+
+  if (_try_make_writable_inplace_unix (blob))
+    return true;
+
+  DEBUG_MSG_FUNC (BLOB, blob, "making writable -> FAILED\n");
+
+  /* Failed to make writable inplace, mark that */
+  blob->mode = HB_MEMORY_MODE_READONLY;
+  return false;
+}
+
+static bool
+_try_writable (hb_blob_t *blob)
+{
+  if (blob->immutable)
+    return false;
+
+  if (blob->mode == HB_MEMORY_MODE_WRITABLE)
+    return true;
+
+  if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE && _try_writable_inplace (blob))
+    return true;
+
+  if (blob->mode == HB_MEMORY_MODE_WRITABLE)
+    return true;
+
+
+  DEBUG_MSG_FUNC (BLOB, blob, "current data is -> %p\n", blob->data);
+
+  char *new_data;
+
+  new_data = (char *) malloc (blob->length);
+  if (unlikely (!new_data))
+    return false;
+
+  DEBUG_MSG_FUNC (BLOB, blob, "dupped successfully -> %p\n", blob->data);
+
+  memcpy (new_data, blob->data, blob->length);
+  _hb_blob_destroy_user_data (blob);
+  blob->mode = HB_MEMORY_MODE_WRITABLE;
+  blob->data = new_data;
+  blob->user_data = new_data;
+  blob->destroy = free;
+
+  return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-blob.h	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,126 @@
+/*
+ * Copyright © 2009  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_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_BLOB_H
+#define HB_BLOB_H
+
+#include "hb-common.h"
+
+HB_BEGIN_DECLS
+
+
+/*
+ * Note re various memory-modes:
+ *
+ * - In no case shall the HarfBuzz client modify memory
+ *   that is passed to HarfBuzz in a blob.  If there is
+ *   any such possibility, MODE_DUPLICATE should be used
+ *   such that HarfBuzz makes a copy immediately,
+ *
+ * - Use MODE_READONLY otherse, unless you really really
+ *   really know what you are doing,
+ *
+ * - MODE_WRITABLE is appropriate if you really made a
+ *   copy of data solely for the purpose of passing to
+ *   HarfBuzz and doing that just once (no reuse!),
+ *
+ * - If the font is mmap()ed, it's ok to use
+ *   READONLY_MAY_MAKE_WRITABLE, however, using that mode
+ *   correctly is very tricky.  Use MODE_READONLY instead.
+ */
+typedef enum {
+  HB_MEMORY_MODE_DUPLICATE,
+  HB_MEMORY_MODE_READONLY,
+  HB_MEMORY_MODE_WRITABLE,
+  HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE
+} hb_memory_mode_t;
+
+typedef struct hb_blob_t hb_blob_t;
+
+hb_blob_t *
+hb_blob_create (const char        *data,
+                unsigned int       length,
+                hb_memory_mode_t   mode,
+                void              *user_data,
+                hb_destroy_func_t  destroy);
+
+/* Always creates with MEMORY_MODE_READONLY.
+ * Even if the parent blob is writable, we don't
+ * want the user of the sub-blob to be able to
+ * modify the parent data as that data may be
+ * shared among multiple sub-blobs.
+ */
+hb_blob_t *
+hb_blob_create_sub_blob (hb_blob_t    *parent,
+                         unsigned int  offset,
+                         unsigned int  length);
+
+hb_blob_t *
+hb_blob_get_empty (void);
+
+hb_blob_t *
+hb_blob_reference (hb_blob_t *blob);
+
+void
+hb_blob_destroy (hb_blob_t *blob);
+
+hb_bool_t
+hb_blob_set_user_data (hb_blob_t          *blob,
+                       hb_user_data_key_t *key,
+                       void *              data,
+                       hb_destroy_func_t   destroy,
+                       hb_bool_t           replace);
+
+
+void *
+hb_blob_get_user_data (hb_blob_t          *blob,
+                       hb_user_data_key_t *key);
+
+
+void
+hb_blob_make_immutable (hb_blob_t *blob);
+
+hb_bool_t
+hb_blob_is_immutable (hb_blob_t *blob);
+
+
+unsigned int
+hb_blob_get_length (hb_blob_t *blob);
+
+const char *
+hb_blob_get_data (hb_blob_t *blob, unsigned int *length);
+
+char *
+hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length);
+
+
+HB_END_DECLS
+
+#endif /* HB_BLOB_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-deserialize-json.hh	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,643 @@
+
+#line 1 "hb-buffer-deserialize-json.rl"
+/*
+ * 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
+ */
+
+#ifndef HB_BUFFER_DESERIALIZE_JSON_HH
+#define HB_BUFFER_DESERIALIZE_JSON_HH
+
+#include "hb-private.hh"
+
+
+#line 36 "hb-buffer-deserialize-json.hh"
+static const unsigned char _deserialize_json_trans_keys[] = {
+        0u, 0u, 9u, 123u, 9u, 34u, 97u, 103u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u,
+        48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u,
+        9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u,
+        120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u,
+        9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u,
+        65u, 122u, 34u, 122u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 123u, 0u, 0u, 0
+};
+
+static const char _deserialize_json_key_spans[] = {
+        0, 115, 26, 7, 2, 1, 50, 49,
+        10, 117, 117, 117, 1, 50, 49, 10,
+        117, 117, 1, 1, 50, 49, 117, 117,
+        2, 1, 50, 49, 10, 117, 117, 1,
+        50, 49, 10, 117, 117, 1, 50, 49,
+        58, 89, 117, 117, 85, 115, 0
+};
+
+static const short _deserialize_json_index_offsets[] = {
+        0, 0, 116, 143, 151, 154, 156, 207,
+        257, 268, 386, 504, 622, 624, 675, 725,
+        736, 854, 972, 974, 976, 1027, 1077, 1195,
+        1313, 1316, 1318, 1369, 1419, 1430, 1548, 1666,
+        1668, 1719, 1769, 1780, 1898, 2016, 2018, 2069,
+        2119, 2178, 2268, 2386, 2504, 2590, 2706
+};
+
+static const char _deserialize_json_indicies[] = {
+        0, 0, 0, 0, 0, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        0, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 2, 1, 3, 3, 3,
+        3, 3, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 3, 1, 4, 1,
+        5, 1, 6, 7, 1, 1, 8, 1,
+        9, 10, 1, 11, 1, 11, 11, 11,
+        11, 11, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 11, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 12, 1,
+        12, 12, 12, 12, 12, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 12,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 13, 1, 1, 14,
+        15, 15, 15, 15, 15, 15, 15, 15,
+        15, 1, 16, 17, 17, 17, 17, 17,
+        17, 17, 17, 17, 1, 18, 18, 18,
+        18, 18, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 18, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        19, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 20, 1, 21, 21, 21, 21, 21,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 21, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 3, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 22,
+        1, 18, 18, 18, 18, 18, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        18, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 19, 1, 1, 1,
+        17, 17, 17, 17, 17, 17, 17, 17,
+        17, 17, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 20, 1, 23,
+        1, 23, 23, 23, 23, 23, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        23, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 24, 1, 24, 24, 24, 24,
+        24, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 24, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        25, 1, 1, 26, 27, 27, 27, 27,
+        27, 27, 27, 27, 27, 1, 28, 29,
+        29, 29, 29, 29, 29, 29, 29, 29,
+        1, 30, 30, 30, 30, 30, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        30, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 31, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 32, 1, 30,
+        30, 30, 30, 30, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 30, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 31, 1, 1, 1, 29, 29,
+        29, 29, 29, 29, 29, 29, 29, 29,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 32, 1, 33, 1, 34,
+        1, 34, 34, 34, 34, 34, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        34, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 35, 1, 35, 35, 35, 35,
+        35, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 35, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 36, 37, 37, 37, 37,
+        37, 37, 37, 37, 37, 1, 38, 38,
+        38, 38, 38, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 38, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 39, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 40, 1, 38, 38, 38, 38,
+        38, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 38, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 39,
+        1, 1, 1, 41, 41, 41, 41, 41,
+        41, 41, 41, 41, 41, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        40, 1, 42, 43, 1, 44, 1, 44,
+        44, 44, 44, 44, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 44, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        45, 1, 45, 45, 45, 45, 45, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 45, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 46, 1,
+        1, 47, 48, 48, 48, 48, 48, 48,
+        48, 48, 48, 1, 49, 50, 50, 50,
+        50, 50, 50, 50, 50, 50, 1, 51,
+        51, 51, 51, 51, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 51, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 52, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 53, 1, 51, 51, 51,
+        51, 51, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 51, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        52, 1, 1, 1, 50, 50, 50, 50,
+        50, 50, 50, 50, 50, 50, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 53, 1, 54, 1, 54, 54, 54,
+        54, 54, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 54, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 55, 1,
+        55, 55, 55, 55, 55, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 55,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 56, 1, 1, 57,
+        58, 58, 58, 58, 58, 58, 58, 58,
+        58, 1, 59, 60, 60, 60, 60, 60,
+        60, 60, 60, 60, 1, 61, 61, 61,
+        61, 61, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 61, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        62, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 63, 1, 61, 61, 61, 61, 61,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 61, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 62, 1,
+        1, 1, 60, 60, 60, 60, 60, 60,
+        60, 60, 60, 60, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 63,
+        1, 64, 1, 64, 64, 64, 64, 64,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 64, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 65, 1, 65, 65,
+        65, 65, 65, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 65, 1, 66,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 67, 68, 68,
+        68, 68, 68, 68, 68, 68, 68, 1,
+        69, 69, 69, 69, 69, 69, 69, 69,
+        69, 69, 69, 69, 69, 69, 69, 69,
+        69, 69, 69, 69, 69, 69, 69, 69,
+        69, 69, 1, 1, 1, 1, 1, 1,
+        69, 69, 69, 69, 69, 69, 69, 69,
+        69, 69, 69, 69, 69, 69, 69, 69,
+        69, 69, 69, 69, 69, 69, 69, 69,
+        69, 69, 1, 70, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 71, 71,
+        1, 71, 71, 71, 71, 71, 71, 71,
+        71, 71, 71, 1, 1, 1, 1, 1,
+        1, 1, 71, 71, 71, 71, 71, 71,
+        71, 71, 71, 71, 71, 71, 71, 71,
+        71, 71, 71, 71, 71, 71, 71, 71,
+        71, 71, 71, 71, 1, 1, 1, 1,
+        71, 1, 71, 71, 71, 71, 71, 71,
+        71, 71, 71, 71, 71, 71, 71, 71,
+        71, 71, 71, 71, 71, 71, 71, 71,
+        71, 71, 71, 71, 1, 72, 72, 72,
+        72, 72, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 72, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        73, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 74, 1, 72, 72, 72, 72, 72,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 72, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 73, 1,
+        1, 1, 75, 75, 75, 75, 75, 75,
+        75, 75, 75, 75, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 74,
+        1, 76, 76, 76, 76, 76, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        76, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 77, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 78, 1, 0,
+        0, 0, 0, 0, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 0, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 2, 1, 1, 0
+};
+
+static const char _deserialize_json_trans_targs[] = {
+        1, 0, 2, 2, 3, 4, 18, 24,
+        37, 5, 12, 6, 7, 8, 9, 11,
+        9, 11, 10, 2, 44, 10, 44, 13,
+        14, 15, 16, 17, 16, 17, 10, 2,
+        44, 19, 20, 21, 22, 23, 10, 2,
+        44, 23, 25, 31, 26, 27, 28, 29,
+        30, 29, 30, 10, 2, 44, 32, 33,
+        34, 35, 36, 35, 36, 10, 2, 44,
+        38, 39, 40, 42, 43, 41, 10, 41,
+        10, 2, 44, 43, 44, 45, 46
+};
+
+static const char _deserialize_json_trans_actions[] = {
+        0, 0, 1, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 2, 2, 2,
+        0, 0, 3, 3, 4, 0, 5, 0,
+        0, 2, 2, 2, 0, 0, 6, 6,
+        7, 0, 0, 0, 2, 2, 8, 8,
+        9, 0, 0, 0, 0, 0, 2, 2,
+        2, 0, 0, 10, 10, 11, 0, 0,
+        2, 2, 2, 0, 0, 12, 12, 13,
+        0, 0, 0, 2, 2, 2, 14, 0,
+        15, 15, 16, 0, 0, 0, 0
+};
+
+static const int deserialize_json_start = 1;
+static const int deserialize_json_first_final = 44;
+static const int deserialize_json_error = 0;
+
+static const int deserialize_json_en_main = 1;
+
+
+#line 97 "hb-buffer-deserialize-json.rl"
+
+
+static hb_bool_t
+_hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer,
+                                    const char *buf,
+                                    unsigned int buf_len,
+                                    const char **end_ptr,
+                                    hb_font_t *font)
+{
+  const char *p = buf, *pe = buf + buf_len;
+
+  /* Ensure we have positions. */
+  (void) hb_buffer_get_glyph_positions (buffer, NULL);
+
+  while (p < pe && ISSPACE (*p))
+    p++;
+  if (p < pe && *p == (buffer->len ? ',' : '['))
+  {
+    *end_ptr = ++p;
+  }
+
+  const char *tok = NULL;
+  int cs;
+  hb_glyph_info_t info = {0};
+  hb_glyph_position_t pos = {0};
+
+#line 466 "hb-buffer-deserialize-json.hh"
+        {
+        cs = deserialize_json_start;
+        }
+
+#line 471 "hb-buffer-deserialize-json.hh"
+        {
+        int _slen;
+        int _trans;
+        const unsigned char *_keys;
+        const char *_inds;
+        if ( p == pe )
+                goto _test_eof;
+        if ( cs == 0 )
+                goto _out;
+_resume:
+        _keys = _deserialize_json_trans_keys + (cs<<1);
+        _inds = _deserialize_json_indicies + _deserialize_json_index_offsets[cs];
+
+        _slen = _deserialize_json_key_spans[cs];
+        _trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
+                (*p) <= _keys[1] ?
+                (*p) - _keys[0] : _slen ];
+
+        cs = _deserialize_json_trans_targs[_trans];
+
+        if ( _deserialize_json_trans_actions[_trans] == 0 )
+                goto _again;
+
+        switch ( _deserialize_json_trans_actions[_trans] ) {
+        case 1:
+#line 38 "hb-buffer-deserialize-json.rl"
+        {
+        memset (&info, 0, sizeof (info));
+        memset (&pos , 0, sizeof (pos ));
+}
+        break;
+        case 5:
+#line 43 "hb-buffer-deserialize-json.rl"
+        {
+        buffer->add_info (info);
+        if (buffer->in_error)
+          return false;
+        buffer->pos[buffer->len - 1] = pos;
+        *end_ptr = p;
+}
+        break;
+        case 2:
+#line 51 "hb-buffer-deserialize-json.rl"
+        {
+        tok = p;
+}
+        break;
+        case 14:
+#line 55 "hb-buffer-deserialize-json.rl"
+        {
+        if (!hb_font_glyph_from_string (font,
+                                        tok, p - tok,
+                                        &info.codepoint))
+          return false;
+}
+        break;
+        case 15:
+#line 62 "hb-buffer-deserialize-json.rl"
+        { if (!parse_uint (tok, p, &info.codepoint)) return false; }
+        break;
+        case 8:
+#line 63 "hb-buffer-deserialize-json.rl"
+        { if (!parse_uint (tok, p, &info.cluster )) return false; }
+        break;
+        case 10:
+#line 64 "hb-buffer-deserialize-json.rl"
+        { if (!parse_int  (tok, p, &pos.x_offset )) return false; }
+        break;
+        case 12:
+#line 65 "hb-buffer-deserialize-json.rl"
+        { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+        break;
+        case 3:
+#line 66 "hb-buffer-deserialize-json.rl"
+        { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+        break;
+        case 6:
+#line 67 "hb-buffer-deserialize-json.rl"
+        { if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+        break;
+        case 16:
+#line 62 "hb-buffer-deserialize-json.rl"
+        { if (!parse_uint (tok, p, &info.codepoint)) return false; }
+#line 43 "hb-buffer-deserialize-json.rl"
+        {
+        buffer->add_info (info);
+        if (buffer->in_error)
+          return false;
+        buffer->pos[buffer->len - 1] = pos;
+        *end_ptr = p;
+}
+        break;
+        case 9:
+#line 63 "hb-buffer-deserialize-json.rl"
+        { if (!parse_uint (tok, p, &info.cluster )) return false; }
+#line 43 "hb-buffer-deserialize-json.rl"
+        {
+        buffer->add_info (info);
+        if (buffer->in_error)
+          return false;
+        buffer->pos[buffer->len - 1] = pos;
+        *end_ptr = p;
+}
+        break;
+        case 11:
+#line 64 "hb-buffer-deserialize-json.rl"
+        { if (!parse_int  (tok, p, &pos.x_offset )) return false; }
+#line 43 "hb-buffer-deserialize-json.rl"
+        {
+        buffer->add_info (info);
+        if (buffer->in_error)
+          return false;
+        buffer->pos[buffer->len - 1] = pos;
+        *end_ptr = p;
+}
+        break;
+        case 13:
+#line 65 "hb-buffer-deserialize-json.rl"
+        { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+#line 43 "hb-buffer-deserialize-json.rl"
+        {
+        buffer->add_info (info);
+        if (buffer->in_error)
+          return false;
+        buffer->pos[buffer->len - 1] = pos;
+        *end_ptr = p;
+}
+        break;
+        case 4:
+#line 66 "hb-buffer-deserialize-json.rl"
+        { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+#line 43 "hb-buffer-deserialize-json.rl"
+        {
+        buffer->add_info (info);
+        if (buffer->in_error)
+          return false;
+        buffer->pos[buffer->len - 1] = pos;
+        *end_ptr = p;
+}
+        break;
+        case 7:
+#line 67 "hb-buffer-deserialize-json.rl"
+        { if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+#line 43 "hb-buffer-deserialize-json.rl"
+        {
+        buffer->add_info (info);
+        if (buffer->in_error)
+          return false;
+        buffer->pos[buffer->len - 1] = pos;
+        *end_ptr = p;
+}
+        break;
+#line 624 "hb-buffer-deserialize-json.hh"
+        }
+
+_again:
+        if ( cs == 0 )
+                goto _out;
+        if ( ++p != pe )
+                goto _resume;
+        _test_eof: {}
+        _out: {}
+        }
+
+#line 125 "hb-buffer-deserialize-json.rl"
+
+
+  *end_ptr = p;
+
+  return p == pe && *(p-1) != ']';
+}
+
+#endif /* HB_BUFFER_DESERIALIZE_JSON_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-deserialize-text.hh	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,571 @@
+
+#line 1 "hb-buffer-deserialize-text.rl"
+/*
+ * 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
+ */
+
+#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH
+#define HB_BUFFER_DESERIALIZE_TEXT_HH
+
+#include "hb-private.hh"
+
+
+#line 36 "hb-buffer-deserialize-text.hh"
+static const unsigned char _deserialize_text_trans_keys[] = {
+        0u, 0u, 9u, 122u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u,
+        48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 9u, 124u, 9u, 124u, 0u, 0u,
+        9u, 122u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u,
+        9u, 124u, 9u, 124u, 9u, 124u, 0
+};
+
+static const char _deserialize_text_key_spans[] = {
+        0, 114, 13, 10, 13, 10, 10, 13,
+        10, 1, 13, 10, 14, 116, 116, 0,
+        114, 116, 116, 116, 116, 116, 116, 116,
+        116, 116, 116
+};
+
+static const short _deserialize_text_index_offsets[] = {
+        0, 0, 115, 129, 140, 154, 165, 176,
+        190, 201, 203, 217, 228, 243, 360, 477,
+        478, 593, 710, 827, 944, 1061, 1178, 1295,
+        1412, 1529, 1646
+};
+
+static const char _deserialize_text_indicies[] = {
+        0, 0, 0, 0, 0, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        0, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        2, 3, 3, 3, 3, 3, 3, 3,
+        3, 3, 1, 1, 1, 1, 1, 1,
+        1, 4, 4, 4, 4, 4, 4, 4,
+        4, 4, 4, 4, 4, 4, 4, 4,
+        4, 4, 4, 4, 4, 4, 4, 4,
+        4, 4, 4, 1, 1, 1, 1, 1,
+        1, 4, 4, 4, 4, 4, 4, 4,
+        4, 4, 4, 4, 4, 4, 4, 4,
+        4, 4, 4, 4, 4, 4, 4, 4,
+        4, 4, 4, 1, 5, 1, 1, 6,
+        7, 7, 7, 7, 7, 7, 7, 7,
+        7, 1, 8, 9, 9, 9, 9, 9,
+        9, 9, 9, 9, 1, 10, 1, 1,
+        11, 12, 12, 12, 12, 12, 12, 12,
+        12, 12, 1, 13, 14, 14, 14, 14,
+        14, 14, 14, 14, 14, 1, 15, 16,
+        16, 16, 16, 16, 16, 16, 16, 16,
+        1, 17, 1, 1, 18, 19, 19, 19,
+        19, 19, 19, 19, 19, 19, 1, 20,
+        21, 21, 21, 21, 21, 21, 21, 21,
+        21, 1, 22, 1, 23, 1, 1, 24,
+        25, 25, 25, 25, 25, 25, 25, 25,
+        25, 1, 26, 27, 27, 27, 27, 27,
+        27, 27, 27, 27, 1, 22, 1, 1,
+        1, 21, 21, 21, 21, 21, 21, 21,
+        21, 21, 21, 1, 28, 28, 28, 28,
+        28, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 28, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 29, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        30, 1, 1, 31, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        32, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 33,
+        1, 34, 34, 34, 34, 34, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        34, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 35, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 36, 1, 1, 0,
+        0, 0, 0, 0, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 0, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 2, 3,
+        3, 3, 3, 3, 3, 3, 3, 3,
+        1, 1, 1, 1, 1, 1, 1, 4,
+        4, 4, 4, 4, 4, 4, 4, 4,
+        4, 4, 4, 4, 4, 4, 4, 4,
+        4, 4, 4, 4, 4, 4, 4, 4,
+        4, 1, 1, 1, 1, 1, 1, 4,
+        4, 4, 4, 4, 4, 4, 4, 4,
+        4, 4, 4, 4, 4, 4, 4, 4,
+        4, 4, 4, 4, 4, 4, 4, 4,
+        4, 1, 28, 28, 28, 28, 28, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 28, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 29, 1, 1, 1,
+        1, 37, 37, 37, 37, 37, 37, 37,
+        37, 37, 37, 1, 1, 1, 30, 1,
+        1, 31, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 32, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 33, 1, 38,
+        38, 38, 38, 38, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 38, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 39, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 40, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 41, 1, 42, 42, 42, 42,
+        42, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 42, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        43, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 44,
+        1, 42, 42, 42, 42, 42, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        42, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        14, 14, 14, 14, 14, 14, 14, 14,
+        14, 14, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 43, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 44, 1, 38, 38,
+        38, 38, 38, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 38, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 39, 1, 1, 1, 9, 9, 9,
+        9, 9, 9, 9, 9, 9, 9, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 40, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 41, 1, 45, 45, 45, 45, 45,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 45, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 46, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 47, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 48,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 49, 1,
+        50, 50, 50, 50, 50, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 50,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 51, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 52, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 53, 1, 50, 50, 50,
+        50, 50, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 50, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 51,
+        1, 1, 1, 1, 27, 27, 27, 27,
+        27, 27, 27, 27, 27, 27, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 52, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        53, 1, 45, 45, 45, 45, 45, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 45, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 46, 1, 1, 1,
+        1, 54, 54, 54, 54, 54, 54, 54,
+        54, 54, 54, 1, 1, 1, 1, 1,
+        1, 47, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 48, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 49, 1, 28,
+        28, 28, 28, 28, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 28, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 29, 1, 55, 55, 1, 55, 55,
+        55, 55, 55, 55, 55, 55, 55, 55,
+        1, 1, 1, 30, 1, 1, 31, 55,
+        55, 55, 55, 55, 55, 55, 55, 55,
+        55, 55, 55, 55, 55, 55, 55, 55,
+        55, 55, 55, 55, 55, 55, 55, 55,
+        55, 1, 1, 32, 1, 55, 1, 55,
+        55, 55, 55, 55, 55, 55, 55, 55,
+        55, 55, 55, 55, 55, 55, 55, 55,
+        55, 55, 55, 55, 55, 55, 55, 55,
+        55, 1, 33, 1, 0
+};
+
+static const char _deserialize_text_trans_targs[] = {
+        1, 0, 13, 17, 26, 3, 18, 21,
+        18, 21, 5, 19, 20, 19, 20, 22,
+        25, 8, 9, 12, 9, 12, 10, 11,
+        23, 24, 23, 24, 14, 2, 6, 7,
+        15, 16, 14, 15, 16, 17, 14, 4,
+        15, 16, 14, 15, 16, 14, 2, 7,
+        15, 16, 14, 2, 15, 16, 25, 26
+};
+
+static const char _deserialize_text_trans_actions[] = {
+        0, 0, 1, 1, 1, 2, 2, 2,
+        0, 0, 2, 2, 2, 0, 0, 2,
+        2, 2, 2, 2, 0, 0, 3, 2,
+        2, 2, 0, 0, 4, 5, 5, 5,
+        4, 4, 0, 0, 0, 0, 6, 7,
+        6, 6, 8, 8, 8, 9, 10, 10,
+        9, 9, 11, 12, 11, 11, 0, 0
+};
+
+static const char _deserialize_text_eof_actions[] = {
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 4, 0, 0,
+        0, 4, 6, 8, 8, 6, 9, 11,
+        11, 9, 4
+};
+
+static const int deserialize_text_start = 1;
+static const int deserialize_text_first_final = 13;
+static const int deserialize_text_error = 0;
+
+static const int deserialize_text_en_main = 1;
+
+
+#line 91 "hb-buffer-deserialize-text.rl"
+
+
+static hb_bool_t
+_hb_buffer_deserialize_glyphs_text (hb_buffer_t *buffer,
+                                    const char *buf,
+                                    unsigned int buf_len,
+                                    const char **end_ptr,
+                                    hb_font_t *font)
+{
+  const char *p = buf, *pe = buf + buf_len;
+
+  /* Ensure we have positions. */
+  (void) hb_buffer_get_glyph_positions (buffer, NULL);
+
+  while (p < pe && ISSPACE (*p))
+    p++;
+  if (p < pe && *p == (buffer->len ? '|' : '['))
+  {
+    *end_ptr = ++p;
+  }
+
+  const char *eof = pe, *tok = NULL;
+  int cs;
+  hb_glyph_info_t info = {0};
+  hb_glyph_position_t pos = {0};
+
+#line 343 "hb-buffer-deserialize-text.hh"
+        {
+        cs = deserialize_text_start;
+        }
+
+#line 348 "hb-buffer-deserialize-text.hh"
+        {
+        int _slen;
+        int _trans;
+        const unsigned char *_keys;
+        const char *_inds;
+        if ( p == pe )
+                goto _test_eof;
+        if ( cs == 0 )
+                goto _out;
+_resume:
+        _keys = _deserialize_text_trans_keys + (cs<<1);
+        _inds = _deserialize_text_indicies + _deserialize_text_index_offsets[cs];
+
+        _slen = _deserialize_text_key_spans[cs];
+        _trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
+                (*p) <= _keys[1] ?
+                (*p) - _keys[0] : _slen ];
+
+        cs = _deserialize_text_trans_targs[_trans];
+
+        if ( _deserialize_text_trans_actions[_trans] == 0 )
+                goto _again;
+
+        switch ( _deserialize_text_trans_actions[_trans] ) {
+        case 2:
+#line 51 "hb-buffer-deserialize-text.rl"
+        {
+        tok = p;
+}
+        break;
+        case 5:
+#line 55 "hb-buffer-deserialize-text.rl"
+        {
+        if (!hb_font_glyph_from_string (font,
+                                        tok, p - tok,
+                                        &info.codepoint))
+          return false;
+}
+        break;
+        case 10:
+#line 62 "hb-buffer-deserialize-text.rl"
+        { if (!parse_uint (tok, p, &info.cluster )) return false; }
+        break;
+        case 3:
+#line 63 "hb-buffer-deserialize-text.rl"
+        { if (!parse_int  (tok, p, &pos.x_offset )) return false; }
+        break;
+        case 12:
+#line 64 "hb-buffer-deserialize-text.rl"
+        { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+        break;
+        case 7:
+#line 65 "hb-buffer-deserialize-text.rl"
+        { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+        break;
+        case 1:
+#line 38 "hb-buffer-deserialize-text.rl"
+        {
+        memset (&info, 0, sizeof (info));
+        memset (&pos , 0, sizeof (pos ));
+}
+#line 51 "hb-buffer-deserialize-text.rl"
+        {
+        tok = p;
+}
+        break;
+        case 4:
+#line 55 "hb-buffer-deserialize-text.rl"
+        {
+        if (!hb_font_glyph_from_string (font,
+                                        tok, p - tok,
+                                        &info.codepoint))
+          return false;
+}
+#line 43 "hb-buffer-deserialize-text.rl"
+        {
+        buffer->add_info (info);
+        if (buffer->in_error)
+          return false;
+        buffer->pos[buffer->len - 1] = pos;
+        *end_ptr = p;
+}
+        break;
+        case 9:
+#line 62 "hb-buffer-deserialize-text.rl"
+        { if (!parse_uint (tok, p, &info.cluster )) return false; }
+#line 43 "hb-buffer-deserialize-text.rl"
+        {
+        buffer->add_info (info);
+        if (buffer->in_error)
+          return false;
+        buffer->pos[buffer->len - 1] = pos;
+        *end_ptr = p;
+}
+        break;
+        case 11:
+#line 64 "hb-buffer-deserialize-text.rl"
+        { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+#line 43 "hb-buffer-deserialize-text.rl"
+        {
+        buffer->add_info (info);
+        if (buffer->in_error)
+          return false;
+        buffer->pos[buffer->len - 1] = pos;
+        *end_ptr = p;
+}
+        break;
+        case 6:
+#line 65 "hb-buffer-deserialize-text.rl"
+        { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+#line 43 "hb-buffer-deserialize-text.rl"
+        {
+        buffer->add_info (info);
+        if (buffer->in_error)
+          return false;
+        buffer->pos[buffer->len - 1] = pos;
+        *end_ptr = p;
+}
+        break;
+        case 8:
+#line 66 "hb-buffer-deserialize-text.rl"
+        { if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+#line 43 "hb-buffer-deserialize-text.rl"
+        {
+        buffer->add_info (info);
+        if (buffer->in_error)
+          return false;
+        buffer->pos[buffer->len - 1] = pos;
+        *end_ptr = p;
+}
+        break;
+#line 480 "hb-buffer-deserialize-text.hh"
+        }
+
+_again:
+        if ( cs == 0 )
+                goto _out;
+        if ( ++p != pe )
+                goto _resume;
+        _test_eof: {}
+        if ( p == eof )
+        {
+        switch ( _deserialize_text_eof_actions[cs] ) {
+        case 4:
+#line 55 "hb-buffer-deserialize-text.rl"
+        {
+        if (!hb_font_glyph_from_string (font,
+                                        tok, p - tok,
+                                        &info.codepoint))
+          return false;
+}
+#line 43 "hb-buffer-deserialize-text.rl"
+        {
+        buffer->add_info (info);
+        if (buffer->in_error)
+          return false;
+        buffer->pos[buffer->len - 1] = pos;
+        *end_ptr = p;
+}
+        break;
+        case 9:
+#line 62 "hb-buffer-deserialize-text.rl"
+        { if (!parse_uint (tok, p, &info.cluster )) return false; }
+#line 43 "hb-buffer-deserialize-text.rl"
+        {
+        buffer->add_info (info);
+        if (buffer->in_error)
+          return false;
+        buffer->pos[buffer->len - 1] = pos;
+        *end_ptr = p;
+}
+        break;
+        case 11:
+#line 64 "hb-buffer-deserialize-text.rl"
+        { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+#line 43 "hb-buffer-deserialize-text.rl"
+        {
+        buffer->add_info (info);
+        if (buffer->in_error)
+          return false;
+        buffer->pos[buffer->len - 1] = pos;
+        *end_ptr = p;
+}
+        break;
+        case 6:
+#line 65 "hb-buffer-deserialize-text.rl"
+        { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+#line 43 "hb-buffer-deserialize-text.rl"
+        {
+        buffer->add_info (info);
+        if (buffer->in_error)
+          return false;
+        buffer->pos[buffer->len - 1] = pos;
+        *end_ptr = p;
+}
+        break;
+        case 8:
+#line 66 "hb-buffer-deserialize-text.rl"
+        { if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+#line 43 "hb-buffer-deserialize-text.rl"
+        {
+        buffer->add_info (info);
+        if (buffer->in_error)
+          return false;
+        buffer->pos[buffer->len - 1] = pos;
+        *end_ptr = p;
+}
+        break;
+#line 557 "hb-buffer-deserialize-text.hh"
+        }
+        }
+
+        _out: {}
+        }
+
+#line 119 "hb-buffer-deserialize-text.rl"
+
+
+  *end_ptr = p;
+
+  return p == pe && *(p-1) != ']';
+}
+
+#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-private.hh	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,220 @@
+/*
+ * Copyright © 1998-2004  David Turner and Werner Lemberg
+ * Copyright © 2004,2007,2009,2010  Red Hat, Inc.
+ * Copyright © 2011,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.
+ *
+ * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_BUFFER_PRIVATE_HH
+#define HB_BUFFER_PRIVATE_HH
+
+#include "hb-private.hh"
+#include "hb-object-private.hh"
+#include "hb-unicode-private.hh"
+
+
+ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20);
+ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
+
+
+/*
+ * hb_buffer_t
+ */
+
+struct hb_buffer_t {
+  hb_object_header_t header;
+  ASSERT_POD ();
+
+  /* Information about how the text in the buffer should be treated */
+  hb_unicode_funcs_t *unicode; /* Unicode functions */
+  hb_buffer_flags_t flags; /* BOT / EOT / etc. */
+  hb_buffer_cluster_level_t cluster_level;
+  hb_codepoint_t replacement; /* U+FFFD or something else. */
+
+  /* Buffer contents */
+  hb_buffer_content_type_t content_type;
+  hb_segment_properties_t props; /* Script, language, direction */
+
+  bool in_error; /* Allocation failed */
+  bool have_output; /* Whether we have an output buffer going on */
+  bool have_positions; /* Whether we have positions */
+
+  unsigned int idx; /* Cursor into ->info and ->pos arrays */
+  unsigned int len; /* Length of ->info and ->pos arrays */
+  unsigned int out_len; /* Length of ->out array if have_output */
+
+  unsigned int allocated; /* Length of allocated arrays */
+  hb_glyph_info_t     *info;
+  hb_glyph_info_t     *out_info;
+  hb_glyph_position_t *pos;
+
+  inline hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
+  inline hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
+
+  inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
+  inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
+
+  inline hb_glyph_info_t &prev (void) { return out_info[out_len - 1]; }
+  inline hb_glyph_info_t prev (void) const { return info[out_len - 1]; }
+
+  inline bool has_separate_output (void) const { return info != out_info; }
+
+  unsigned int serial;
+
+  /* These reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
+  uint8_t allocated_var_bytes[8];
+  const char *allocated_var_owner[8];
+
+  /* Text before / after the main buffer contents.
+   * Always in Unicode, and ordered outward.
+   * Index 0 is for "pre-context", 1 for "post-context". */
+  static const unsigned int CONTEXT_LENGTH = 5;
+  hb_codepoint_t context[2][CONTEXT_LENGTH];
+  unsigned int context_len[2];
+
+
+  /* Methods */
+
+  HB_INTERNAL void reset (void);
+  HB_INTERNAL void clear (void);
+
+  inline unsigned int backtrack_len (void) const
+  { return have_output? out_len : idx; }
+  inline unsigned int lookahead_len (void) const
+  { return len - idx; }
+  inline unsigned int next_serial (void) { return serial++; }
+
+  HB_INTERNAL void allocate_var (unsigned int byte_i, unsigned int count, const char *owner);
+  HB_INTERNAL void deallocate_var (unsigned int byte_i, unsigned int count, const char *owner);
+  HB_INTERNAL void assert_var (unsigned int byte_i, unsigned int count, const char *owner);
+  HB_INTERNAL void deallocate_var_all (void);
+
+  HB_INTERNAL void add (hb_codepoint_t  codepoint,
+                        unsigned int    cluster);
+  HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info);
+
+  HB_INTERNAL void reverse_range (unsigned int start, unsigned int end);
+  HB_INTERNAL void reverse (void);
+  HB_INTERNAL void reverse_clusters (void);
+  HB_INTERNAL void guess_segment_properties (void);
+
+  HB_INTERNAL void swap_buffers (void);
+  HB_INTERNAL void remove_output (void);
+  HB_INTERNAL void clear_output (void);
+  HB_INTERNAL void clear_positions (void);
+
+  HB_INTERNAL void replace_glyphs (unsigned int num_in,
+                                   unsigned int num_out,
+                                   const hb_codepoint_t *glyph_data);
+
+  HB_INTERNAL void replace_glyph (hb_codepoint_t glyph_index);
+  /* Makes a copy of the glyph at idx to output and replace glyph_index */
+  HB_INTERNAL void output_glyph (hb_codepoint_t glyph_index);
+  HB_INTERNAL void output_info (const hb_glyph_info_t &glyph_info);
+  /* Copies glyph at idx to output but doesn't advance idx */
+  HB_INTERNAL void copy_glyph (void);
+  HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
+  /* Copies glyph at idx to output and advance idx.
+   * If there's no output, just advance idx. */
+  inline void
+  next_glyph (void)
+  {
+    if (have_output)
+    {
+      if (unlikely (out_info != info || out_len != idx)) {
+        if (unlikely (!make_room_for (1, 1))) return;
+        out_info[out_len] = info[idx];
+      }
+      out_len++;
+    }
+
+    idx++;
+  }
+
+  /* Advance idx without copying to output. */
+  inline void skip_glyph (void) { idx++; }
+
+  inline void reset_masks (hb_mask_t mask)
+  {
+    for (unsigned int j = 0; j < len; j++)
+      info[j].mask = mask;
+  }
+  inline void add_masks (hb_mask_t mask)
+  {
+    for (unsigned int j = 0; j < len; j++)
+      info[j].mask |= mask;
+  }
+  HB_INTERNAL void set_masks (hb_mask_t value,
+                              hb_mask_t mask,
+                              unsigned int cluster_start,
+                              unsigned int cluster_end);
+
+  HB_INTERNAL void merge_clusters (unsigned int start,
+                                   unsigned int end)
+  {
+    if (end - start < 2)
+      return;
+    merge_clusters_impl (start, end);
+  }
+  HB_INTERNAL void merge_clusters_impl (unsigned int start,
+                                        unsigned int end);
+  HB_INTERNAL void merge_out_clusters (unsigned int start,
+                                       unsigned int end);
+  /* Merge clusters for deleting current glyph, and skip it. */
+  HB_INTERNAL void delete_glyph (void);
+
+  /* Internal methods */
+  HB_INTERNAL bool enlarge (unsigned int size);
+
+  inline bool ensure (unsigned int size)
+  { return likely (!size || size < allocated) ? true : enlarge (size); }
+
+  inline bool ensure_inplace (unsigned int size)
+  { return likely (!size || size < allocated); }
+
+  HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
+  HB_INTERNAL bool shift_forward (unsigned int count);
+
+  typedef long scratch_buffer_t;
+  HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size);
+
+  inline void clear_context (unsigned int side) { context_len[side] = 0; }
+
+  HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *));
+};
+
+
+#define HB_BUFFER_XALLOCATE_VAR(b, func, var, owner) \
+  b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \
+           sizeof (b->info[0].var), owner)
+#define HB_BUFFER_ALLOCATE_VAR(b, var) \
+        HB_BUFFER_XALLOCATE_VAR (b, allocate_var, var (), #var)
+#define HB_BUFFER_DEALLOCATE_VAR(b, var) \
+        HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var (), #var)
+#define HB_BUFFER_ASSERT_VAR(b, var) \
+        HB_BUFFER_XALLOCATE_VAR (b, assert_var, var (), #var)
+
+
+#endif /* HB_BUFFER_PRIVATE_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-serialize.cc	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,418 @@
+/*
+ * Copyright © 2012,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-buffer-private.hh"
+
+
+static const char *serialize_formats[] = {
+  "text",
+  "json",
+  NULL
+};
+
+/**
+ * hb_buffer_serialize_list_formats:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.2
+ **/
+const char **
+hb_buffer_serialize_list_formats (void)
+{
+  return serialize_formats;
+}
+
+/**
+ * hb_buffer_serialize_format_from_string:
+ * @str:
+ * @len:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_buffer_serialize_format_t
+hb_buffer_serialize_format_from_string (const char *str, int len)
+{
+  /* Upper-case it. */
+  return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020u);
+}
+
+/**
+ * hb_buffer_serialize_format_to_string:
+ * @format:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+const char *
+hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
+{
+  switch (format)
+  {
+    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:       return serialize_formats[0];
+    case HB_BUFFER_SERIALIZE_FORMAT_JSON:       return serialize_formats[1];
+    default:
+    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:    return NULL;
+  }
+}
+
+static unsigned int
+_hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
+                                  unsigned int start,
+                                  unsigned int end,
+                                  char *buf,
+                                  unsigned int buf_size,
+                                  unsigned int *buf_consumed,
+                                  hb_font_t *font,
+                                  hb_buffer_serialize_flags_t flags)
+{
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
+  hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
+                             NULL : hb_buffer_get_glyph_positions (buffer, NULL);
+
+  *buf_consumed = 0;
+  for (unsigned int i = start; i < end; i++)
+  {
+    char b[1024];
+    char *p = b;
+
+    /* In the following code, we know b is large enough that no overflow can happen. */
+
+#define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END
+
+    if (i)
+      *p++ = ',';
+
+    *p++ = '{';
+
+    APPEND ("\"g\":");
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
+    {
+      char g[128];
+      hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g));
+      *p++ = '"';
+      for (char *q = g; *q; q++) {
+        if (*q == '"')
+          *p++ = '\\';
+        *p++ = *q;
+      }
+      *p++ = '"';
+    }
+    else
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
+
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
+    }
+
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
+    {
+      p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
+                     pos[i].x_offset, pos[i].y_offset);
+      p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
+                     pos[i].x_advance, pos[i].y_advance);
+    }
+
+    if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
+    {
+      hb_glyph_extents_t extents;
+      hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
+        extents.x_bearing, extents.y_bearing));
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
+        extents.width, extents.height));
+    }
+
+    *p++ = '}';
+
+    unsigned int l = p - b;
+    if (buf_size > l)
+    {
+      memcpy (buf, b, l);
+      buf += l;
+      buf_size -= l;
+      *buf_consumed += l;
+      *buf = '\0';
+    } else
+      return i - start;
+  }
+
+  return end - start;
+}
+
+static unsigned int
+_hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
+                                  unsigned int start,
+                                  unsigned int end,
+                                  char *buf,
+                                  unsigned int buf_size,
+                                  unsigned int *buf_consumed,
+                                  hb_font_t *font,
+                                  hb_buffer_serialize_flags_t flags)
+{
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
+  hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
+                             NULL : hb_buffer_get_glyph_positions (buffer, NULL);
+
+  *buf_consumed = 0;
+  for (unsigned int i = start; i < end; i++)
+  {
+    char b[1024];
+    char *p = b;
+
+    /* In the following code, we know b is large enough that no overflow can happen. */
+
+    if (i)
+      *p++ = '|';
+
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
+    {
+      hb_font_glyph_to_string (font, info[i].codepoint, p, 128);
+      p += strlen (p);
+    }
+    else
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
+
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
+    }
+
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
+    {
+      if (pos[i].x_offset || pos[i].y_offset)
+        p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset));
+
+      *p++ = '+';
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
+      if (pos[i].y_advance)
+        p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
+    }
+
+    if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
+    {
+      hb_glyph_extents_t extents;
+      hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
+    }
+
+    unsigned int l = p - b;
+    if (buf_size > l)
+    {
+      memcpy (buf, b, l);
+      buf += l;
+      buf_size -= l;
+      *buf_consumed += l;
+      *buf = '\0';
+    } else
+      return i - start;
+  }
+
+  return end - start;
+}
+
+/* Returns number of items, starting at start, that were serialized. */
+/**
+ * hb_buffer_serialize_glyphs:
+ * @buffer: a buffer.
+ * @start:
+ * @end:
+ * @buf: (array length=buf_size):
+ * @buf_size:
+ * @buf_consumed: (out):
+ * @font:
+ * @format:
+ * @flags:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+unsigned int
+hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
+                            unsigned int start,
+                            unsigned int end,
+                            char *buf,
+                            unsigned int buf_size,
+                            unsigned int *buf_consumed, /* May be NULL */
+                            hb_font_t *font, /* May be NULL */
+                            hb_buffer_serialize_format_t format,
+                            hb_buffer_serialize_flags_t flags)
+{
+  assert (start <= end && end <= buffer->len);
+
+  unsigned int sconsumed;
+  if (!buf_consumed)
+    buf_consumed = &sconsumed;
+  *buf_consumed = 0;
+
+  assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
+          buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+
+  if (unlikely (start == end))
+    return 0;
+
+  if (!font)
+    font = hb_font_get_empty ();
+
+  switch (format)
+  {
+    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
+      return _hb_buffer_serialize_glyphs_text (buffer, start, end,
+                                               buf, buf_size, buf_consumed,
+                                               font, flags);
+
+    case HB_BUFFER_SERIALIZE_FORMAT_JSON:
+      return _hb_buffer_serialize_glyphs_json (buffer, start, end,
+                                               buf, buf_size, buf_consumed,
+                                               font, flags);
+
+    default:
+    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
+      return 0;
+
+  }
+}
+
+
+static hb_bool_t
+parse_uint (const char *pp, const char *end, uint32_t *pv)
+{
+  char buf[32];
+  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
+  strncpy (buf, pp, len);
+  buf[len] = '\0';
+
+  char *p = buf;
+  char *pend = p;
+  uint32_t v;
+
+  errno = 0;
+  v = strtol (p, &pend, 10);
+  if (errno || p == pend || pend - p != end - pp)
+    return false;
+
+  *pv = v;
+  return true;
+}
+
+static hb_bool_t
+parse_int (const char *pp, const char *end, int32_t *pv)
+{
+  char buf[32];
+  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
+  strncpy (buf, pp, len);
+  buf[len] = '\0';
+
+  char *p = buf;
+  char *pend = p;
+  int32_t v;
+
+  errno = 0;
+  v = strtol (p, &pend, 10);
+  if (errno || p == pend || pend - p != end - pp)
+    return false;
+
+  *pv = v;
+  return true;
+}
+
+#include "hb-buffer-deserialize-json.hh"
+#include "hb-buffer-deserialize-text.hh"
+
+/**
+ * hb_buffer_deserialize_glyphs:
+ * @buffer: a buffer.
+ * @buf: (array length=buf_len):
+ * @buf_len:
+ * @end_ptr: (out):
+ * @font:
+ * @format:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
+                              const char *buf,
+                              int buf_len, /* -1 means nul-terminated */
+                              const char **end_ptr, /* May be NULL */
+                              hb_font_t *font, /* May be NULL */
+                              hb_buffer_serialize_format_t format)
+{
+  const char *end;
+  if (!end_ptr)
+    end_ptr = &end;
+  *end_ptr = buf;
+
+  assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
+          buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+
+  if (buf_len == -1)
+    buf_len = strlen (buf);
+
+  if (!buf_len)
+  {
+    *end_ptr = buf;
+    return false;
+  }
+
+  hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);
+
+  if (!font)
+    font = hb_font_get_empty ();
+
+  switch (format)
+  {
+    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
+      return _hb_buffer_deserialize_glyphs_text (buffer,
+                                                 buf, buf_len, end_ptr,
+                                                 font);
+
+    case HB_BUFFER_SERIALIZE_FORMAT_JSON:
+      return _hb_buffer_deserialize_glyphs_json (buffer,
+                                                 buf, buf_len, end_ptr,
+                                                 font);
+
+    default:
+    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
+      return false;
+
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer.cc	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,1701 @@
+/*
+ * Copyright © 1998-2004  David Turner and Werner Lemberg
+ * Copyright © 2004,2007,2009,2010  Red Hat, Inc.
+ * Copyright © 2011,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.
+ *
+ * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-buffer-private.hh"
+#include "hb-utf-private.hh"
+
+
+#ifndef HB_DEBUG_BUFFER
+#define HB_DEBUG_BUFFER (HB_DEBUG+0)
+#endif
+
+
+/**
+ * Since: 0.9.7
+ **/
+hb_bool_t
+hb_segment_properties_equal (const hb_segment_properties_t *a,
+                             const hb_segment_properties_t *b)
+{
+  return a->direction == b->direction &&
+         a->script    == b->script    &&
+         a->language  == b->language  &&
+         a->reserved1 == b->reserved1 &&
+         a->reserved2 == b->reserved2;
+
+}
+
+/**
+ * Since: 0.9.7
+ **/
+unsigned int
+hb_segment_properties_hash (const hb_segment_properties_t *p)
+{
+  return (unsigned int) p->direction ^
+         (unsigned int) p->script ^
+         (intptr_t) (p->language);
+}
+
+
+
+/* Here is how the buffer works internally:
+ *
+ * There are two info pointers: info and out_info.  They always have
+ * the same allocated size, but different lengths.
+ *
+ * As an optimization, both info and out_info may point to the
+ * same piece of memory, which is owned by info.  This remains the
+ * case as long as out_len doesn't exceed i at any time.
+ * In that case, swap_buffers() is no-op and the glyph operations operate
+ * mostly in-place.
+ *
+ * As soon as out_info gets longer than info, out_info is moved over
+ * to an alternate buffer (which we reuse the pos buffer for!), and its
+ * current contents (out_len entries) are copied to the new place.
+ * This should all remain transparent to the user.  swap_buffers() then
+ * switches info and out_info.
+ */
+
+
+
+/* Internal API */
+
+bool
+hb_buffer_t::enlarge (unsigned int size)
+{
+  if (unlikely (in_error))
+    return false;
+
+  unsigned int new_allocated = allocated;
+  hb_glyph_position_t *new_pos = NULL;
+  hb_glyph_info_t *new_info = NULL;
+  bool separate_out = out_info != info;
+
+  if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
+    goto done;
+
+  while (size >= new_allocated)
+    new_allocated += (new_allocated >> 1) + 32;
+
+  ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
+  if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
+    goto done;
+
+  new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
+  new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
+
+done:
+  if (unlikely (!new_pos || !new_info))
+    in_error = true;
+
+  if (likely (new_pos))
+    pos = new_pos;
+
+  if (likely (new_info))
+    info = new_info;
+
+  out_info = separate_out ? (hb_glyph_info_t *) pos : info;
+  if (likely (!in_error))
+    allocated = new_allocated;
+
+  return likely (!in_error);
+}
+
+bool
+hb_buffer_t::make_room_for (unsigned int num_in,
+                            unsigned int num_out)
+{
+  if (unlikely (!ensure (out_len + num_out))) return false;
+
+  if (out_info == info &&
+      out_len + num_out > idx + num_in)
+  {
+    assert (have_output);
+
+    out_info = (hb_glyph_info_t *) pos;
+    memcpy (out_info, info, out_len * sizeof (out_info[0]));
+  }
+
+  return true;
+}
+
+bool
+hb_buffer_t::shift_forward (unsigned int count)
+{
+  assert (have_output);
+  if (unlikely (!ensure (len + count))) return false;
+
+  memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));
+  len += count;
+  idx += count;
+
+  return true;
+}
+
+hb_buffer_t::scratch_buffer_t *
+hb_buffer_t::get_scratch_buffer (unsigned int *size)
+{
+  have_output = false;
+  have_positions = false;
+
+  out_len = 0;
+  out_info = info;
+
+  assert ((uintptr_t) pos % sizeof (scratch_buffer_t) == 0);
+  *size = allocated * sizeof (pos[0]) / sizeof (scratch_buffer_t);
+  return (scratch_buffer_t *) (void *) pos;
+}
+
+
+
+/* HarfBuzz-Internal API */
+
+void
+hb_buffer_t::reset (void)
+{
+  if (unlikely (hb_object_is_inert (this)))
+    return;
+
+  hb_unicode_funcs_destroy (unicode);
+  unicode = hb_unicode_funcs_get_default ();
+  flags = HB_BUFFER_FLAG_DEFAULT;
+  replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
+
+  clear ();
+}
+
+void
+hb_buffer_t::clear (void)
+{
+  if (unlikely (hb_object_is_inert (this)))
+    return;
+
+  hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
+  props = default_props;
+
+  content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
+  in_error = false;
+  have_output = false;
+  have_positions = false;
+
+  idx = 0;
+  len = 0;
+  out_len = 0;
+  out_info = info;
+
+  serial = 0;
+  memset (allocated_var_bytes, 0, sizeof allocated_var_bytes);
+  memset (allocated_var_owner, 0, sizeof allocated_var_owner);
+
+  memset (context, 0, sizeof context);
+  memset (context_len, 0, sizeof context_len);
+}
+
+void
+hb_buffer_t::add (hb_codepoint_t  codepoint,
+                  unsigned int    cluster)
+{
+  hb_glyph_info_t *glyph;
+
+  if (unlikely (!ensure (len + 1))) return;
+
+  glyph = &info[len];
+
+  memset (glyph, 0, sizeof (*glyph));
+  glyph->codepoint = codepoint;
+  glyph->mask = 1;
+  glyph->cluster = cluster;
+
+  len++;
+}
+
+void
+hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
+{
+  if (unlikely (!ensure (len + 1))) return;
+
+  info[len] = glyph_info;
+
+  len++;
+}
+
+
+void
+hb_buffer_t::remove_output (void)
+{
+  if (unlikely (hb_object_is_inert (this)))
+    return;
+
+  have_output = false;
+  have_positions = false;
+
+  out_len = 0;
+  out_info = info;
+}
+
+void
+hb_buffer_t::clear_output (void)
+{
+  if (unlikely (hb_object_is_inert (this)))
+    return;
+
+  have_output = true;
+  have_positions = false;
+
+  out_len = 0;
+  out_info = info;
+}
+
+void
+hb_buffer_t::clear_positions (void)
+{
+  if (unlikely (hb_object_is_inert (this)))
+    return;
+
+  have_output = false;
+  have_positions = true;
+
+  out_len = 0;
+  out_info = info;
+
+  memset (pos, 0, sizeof (pos[0]) * len);
+}
+
+void
+hb_buffer_t::swap_buffers (void)
+{
+  if (unlikely (in_error)) return;
+
+  assert (have_output);
+  have_output = false;
+
+  if (out_info != info)
+  {
+    hb_glyph_info_t *tmp_string;
+    tmp_string = info;
+    info = out_info;
+    out_info = tmp_string;
+    pos = (hb_glyph_position_t *) out_info;
+  }
+
+  unsigned int tmp;
+  tmp = len;
+  len = out_len;
+  out_len = tmp;
+
+  idx = 0;
+}
+
+
+void
+hb_buffer_t::replace_glyphs (unsigned int num_in,
+                             unsigned int num_out,
+                             const uint32_t *glyph_data)
+{
+  if (unlikely (!make_room_for (num_in, num_out))) return;
+
+  merge_clusters (idx, idx + num_in);
+
+  hb_glyph_info_t orig_info = info[idx];
+  hb_glyph_info_t *pinfo = &out_info[out_len];
+  for (unsigned int i = 0; i < num_out; i++)
+  {
+    *pinfo = orig_info;
+    pinfo->codepoint = glyph_data[i];
+    pinfo++;
+  }
+
+  idx  += num_in;
+  out_len += num_out;
+}
+
+void
+hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
+{
+  if (unlikely (!make_room_for (0, 1))) return;
+
+  out_info[out_len] = info[idx];
+  out_info[out_len].codepoint = glyph_index;
+
+  out_len++;
+}
+
+void
+hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info)
+{
+  if (unlikely (!make_room_for (0, 1))) return;
+
+  out_info[out_len] = glyph_info;
+
+  out_len++;
+}
+
+void
+hb_buffer_t::copy_glyph (void)
+{
+  if (unlikely (!make_room_for (0, 1))) return;
+
+  out_info[out_len] = info[idx];
+
+  out_len++;
+}
+
+bool
+hb_buffer_t::move_to (unsigned int i)
+{
+  if (!have_output)
+  {
+    assert (i <= len);
+    idx = i;
+    return true;
+  }
+
+  assert (i <= out_len + (len - idx));
+
+  if (out_len < i)
+  {
+    unsigned int count = i - out_len;
+    if (unlikely (!make_room_for (count, count))) return false;
+
+    memmove (out_info + out_len, info + idx, count * sizeof (out_info[0]));
+    idx += count;
+    out_len += count;
+  }
+  else if (out_len > i)
+  {
+    /* Tricky part: rewinding... */
+    unsigned int count = out_len - i;
+
+    if (unlikely (idx < count && !shift_forward (count + 32))) return false;
+
+    assert (idx >= count);
+
+    idx -= count;
+    out_len -= count;
+    memmove (info + idx, out_info + out_len, count * sizeof (out_info[0]));
+  }
+
+  return true;
+}
+
+void
+hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
+{
+  if (unlikely (out_info != info || out_len != idx)) {
+    if (unlikely (!make_room_for (1, 1))) return;
+    out_info[out_len] = info[idx];
+  }
+  out_info[out_len].codepoint = glyph_index;
+
+  idx++;
+  out_len++;
+}
+
+
+void
+hb_buffer_t::set_masks (hb_mask_t    value,
+                        hb_mask_t    mask,
+                        unsigned int cluster_start,
+                        unsigned int cluster_end)
+{
+  hb_mask_t not_mask = ~mask;
+  value &= mask;
+
+  if (!mask)
+    return;
+
+  if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
+    unsigned int count = len;
+    for (unsigned int i = 0; i < count; i++)
+      info[i].mask = (info[i].mask & not_mask) | value;
+    return;
+  }
+
+  unsigned int count = len;
+  for (unsigned int i = 0; i < count; i++)
+    if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
+      info[i].mask = (info[i].mask & not_mask) | value;
+}
+
+void
+hb_buffer_t::reverse_range (unsigned int start,
+                            unsigned int end)
+{
+  unsigned int i, j;
+
+  if (end - start < 2)
+    return;
+
+  for (i = start, j = end - 1; i < j; i++, j--) {
+    hb_glyph_info_t t;
+
+    t = info[i];
+    info[i] = info[j];
+    info[j] = t;
+  }
+
+  if (have_positions) {
+    for (i = start, j = end - 1; i < j; i++, j--) {
+      hb_glyph_position_t t;
+
+      t = pos[i];
+      pos[i] = pos[j];
+      pos[j] = t;
+    }
+  }
+}
+
+void
+hb_buffer_t::reverse (void)
+{
+  if (unlikely (!len))
+    return;
+
+  reverse_range (0, len);
+}
+
+void
+hb_buffer_t::reverse_clusters (void)
+{
+  unsigned int i, start, count, last_cluster;
+
+  if (unlikely (!len))
+    return;
+
+  reverse ();
+
+  count = len;
+  start = 0;
+  last_cluster = info[0].cluster;
+  for (i = 1; i < count; i++) {
+    if (last_cluster != info[i].cluster) {
+      reverse_range (start, i);
+      start = i;
+      last_cluster = info[i].cluster;
+    }
+  }
+  reverse_range (start, i);
+}
+
+void
+hb_buffer_t::merge_clusters_impl (unsigned int start,
+                                  unsigned int end)
+{
+  if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
+    return;
+
+  unsigned int cluster = info[start].cluster;
+
+  for (unsigned int i = start + 1; i < end; i++)
+    cluster = MIN (cluster, info[i].cluster);
+
+  /* Extend end */
+  while (end < len && info[end - 1].cluster == info[end].cluster)
+    end++;
+
+  /* Extend start */
+  while (idx < start && info[start - 1].cluster == info[start].cluster)
+    start--;
+
+  /* If we hit the start of buffer, continue in out-buffer. */
+  if (idx == start)
+    for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
+      out_info[i - 1].cluster = cluster;
+
+  for (unsigned int i = start; i < end; i++)
+    info[i].cluster = cluster;
+}
+void
+hb_buffer_t::merge_out_clusters (unsigned int start,
+                                 unsigned int end)
+{
+  if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
+    return;
+
+  if (unlikely (end - start < 2))
+    return;
+
+  unsigned int cluster = out_info[start].cluster;
+
+  for (unsigned int i = start + 1; i < end; i++)
+    cluster = MIN (cluster, out_info[i].cluster);
+
+  /* Extend start */
+  while (start && out_info[start - 1].cluster == out_info[start].cluster)
+    start--;
+
+  /* Extend end */
+  while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)
+    end++;
+
+  /* If we hit the end of out-buffer, continue in buffer. */
+  if (end == out_len)
+    for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
+      info[i].cluster = cluster;
+
+  for (unsigned int i = start; i < end; i++)
+    out_info[i].cluster = cluster;
+}
+void
+hb_buffer_t::delete_glyph ()
+{
+  unsigned int cluster = info[idx].cluster;
+  if (idx + 1 < len && cluster == info[idx + 1].cluster)
+  {
+    /* Cluster survives; do nothing. */
+    goto done;
+  }
+
+  if (out_len)
+  {
+    /* Merge cluster backward. */
+    if (cluster < out_info[out_len - 1].cluster)
+    {
+      unsigned int old_cluster = out_info[out_len - 1].cluster;
+      for (unsigned i = out_len; i && out_info[i - 1].cluster == old_cluster; i--)
+        out_info[i - 1].cluster = cluster;
+    }
+    goto done;
+  }
+
+  if (idx + 1 < len)
+  {
+    /* Merge cluster forward. */
+    merge_clusters (idx, idx + 2);
+    goto done;
+  }
+
+done:
+  skip_glyph ();
+}
+
+void
+hb_buffer_t::guess_segment_properties (void)
+{
+  assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
+          (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
+
+  /* If script is set to INVALID, guess from buffer contents */
+  if (props.script == HB_SCRIPT_INVALID) {
+    for (unsigned int i = 0; i < len; i++) {
+      hb_script_t script = unicode->script (info[i].codepoint);
+      if (likely (script != HB_SCRIPT_COMMON &&
+                  script != HB_SCRIPT_INHERITED &&
+                  script != HB_SCRIPT_UNKNOWN)) {
+        props.script = script;
+        break;
+      }
+    }
+  }
+
+  /* If direction is set to INVALID, guess from script */
+  if (props.direction == HB_DIRECTION_INVALID) {
+    props.direction = hb_script_get_horizontal_direction (props.script);
+  }
+
+  /* If language is not set, use default language from locale */
+  if (props.language == HB_LANGUAGE_INVALID) {
+    /* TODO get_default_for_script? using $LANGUAGE */
+    props.language = hb_language_get_default ();
+  }
+}
+
+
+static inline void
+dump_var_allocation (const hb_buffer_t *buffer)
+{
+  char buf[80];
+  for (unsigned int i = 0; i < 8; i++)
+    buf[i] = '0' + buffer->allocated_var_bytes[7 - i];
+  buf[8] = '\0';
+  DEBUG_MSG (BUFFER, buffer,
+             "Current var allocation: %s",
+             buf);
+}
+
+void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner)
+{
+  assert (byte_i < 8 && byte_i + count <= 8);
+
+  if (DEBUG_ENABLED (BUFFER))
+    dump_var_allocation (this);
+  DEBUG_MSG (BUFFER, this,
+             "Allocating var bytes %d..%d for %s",
+             byte_i, byte_i + count - 1, owner);
+
+  for (unsigned int i = byte_i; i < byte_i + count; i++) {
+    assert (!allocated_var_bytes[i]);
+    allocated_var_bytes[i]++;
+    allocated_var_owner[i] = owner;
+  }
+}
+
+void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner)
+{
+  if (DEBUG_ENABLED (BUFFER))
+    dump_var_allocation (this);
+
+  DEBUG_MSG (BUFFER, this,
+             "Deallocating var bytes %d..%d for %s",
+             byte_i, byte_i + count - 1, owner);
+
+  assert (byte_i < 8 && byte_i + count <= 8);
+  for (unsigned int i = byte_i; i < byte_i + count; i++) {
+    assert (allocated_var_bytes[i]);
+    assert (0 == strcmp (allocated_var_owner[i], owner));
+    allocated_var_bytes[i]--;
+  }
+}
+
+void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner)
+{
+  if (DEBUG_ENABLED (BUFFER))
+    dump_var_allocation (this);
+
+  DEBUG_MSG (BUFFER, this,
+             "Asserting var bytes %d..%d for %s",
+             byte_i, byte_i + count - 1, owner);
+
+  assert (byte_i < 8 && byte_i + count <= 8);
+  for (unsigned int i = byte_i; i < byte_i + count; i++) {
+    assert (allocated_var_bytes[i]);
+    assert (0 == strcmp (allocated_var_owner[i], owner));
+  }
+}
+
+void hb_buffer_t::deallocate_var_all (void)
+{
+  memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
+  memset (allocated_var_owner, 0, sizeof (allocated_var_owner));
+}
+
+/* Public API */
+
+/**
+ * hb_buffer_create: (Xconstructor)
+ *
+ *
+ *
+ * Return value: (transfer full)
+ *
+ * Since: 0.9.2
+ **/
+hb_buffer_t *
+hb_buffer_create (void)
+{
+  hb_buffer_t *buffer;
+
+  if (!(buffer = hb_object_create<hb_buffer_t> ()))
+    return hb_buffer_get_empty ();
+
+  buffer->reset ();
+
+  return buffer;
+}
+
+/**
+ * hb_buffer_get_empty:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.2
+ **/
+hb_buffer_t *
+hb_buffer_get_empty (void)
+{
+  static const hb_buffer_t _hb_buffer_nil = {
+    HB_OBJECT_HEADER_STATIC,
+
+    const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
+    HB_BUFFER_FLAG_DEFAULT,
+    HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
+    HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
+
+    HB_BUFFER_CONTENT_TYPE_INVALID,
+    HB_SEGMENT_PROPERTIES_DEFAULT,
+    true, /* in_error */
+    true, /* have_output */
+    true  /* have_positions */
+
+    /* Zero is good enough for everything else. */
+  };
+
+  return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
+}
+
+/**
+ * hb_buffer_reference: (skip)
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.2
+ **/
+hb_buffer_t *
+hb_buffer_reference (hb_buffer_t *buffer)
+{
+  return hb_object_reference (buffer);
+}
+
+/**
+ * hb_buffer_destroy: (skip)
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_buffer_destroy (hb_buffer_t *buffer)
+{
+  if (!hb_object_destroy (buffer)) return;
+
+  hb_unicode_funcs_destroy (buffer->unicode);
+
+  free (buffer->info);
+  free (buffer->pos);
+
+  free (buffer);
+}
+
+/**
+ * hb_buffer_set_user_data: (skip)
+ * @buffer: a buffer.
+ * @key:
+ * @data:
+ * @destroy:
+ * @replace:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_buffer_set_user_data (hb_buffer_t        *buffer,
+                         hb_user_data_key_t *key,
+                         void *              data,
+                         hb_destroy_func_t   destroy,
+                         hb_bool_t           replace)
+{
+  return hb_object_set_user_data (buffer, key, data, destroy, replace);
+}
+
+/**
+ * hb_buffer_get_user_data: (skip)
+ * @buffer: a buffer.
+ * @key:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+void *
+hb_buffer_get_user_data (hb_buffer_t        *buffer,
+                         hb_user_data_key_t *key)
+{
+  return hb_object_get_user_data (buffer, key);
+}
+
+
+/**
+ * hb_buffer_set_content_type:
+ * @buffer: a buffer.
+ * @content_type:
+ *
+ *
+ *
+ * Since: 0.9.5
+ **/
+void
+hb_buffer_set_content_type (hb_buffer_t              *buffer,
+                            hb_buffer_content_type_t  content_type)
+{
+  buffer->content_type = content_type;
+}
+
+/**
+ * hb_buffer_get_content_type:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.5
+ **/
+hb_buffer_content_type_t
+hb_buffer_get_content_type (hb_buffer_t *buffer)
+{
+  return buffer->content_type;
+}
+
+
+/**
+ * hb_buffer_set_unicode_funcs:
+ * @buffer: a buffer.
+ * @unicode_funcs:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
+                             hb_unicode_funcs_t *unicode_funcs)
+{
+  if (unlikely (hb_object_is_inert (buffer)))
+    return;
+
+  if (!unicode_funcs)
+    unicode_funcs = hb_unicode_funcs_get_default ();
+
+
+  hb_unicode_funcs_reference (unicode_funcs);
+  hb_unicode_funcs_destroy (buffer->unicode);
+  buffer->unicode = unicode_funcs;
+}
+
+/**
+ * hb_buffer_get_unicode_funcs:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_unicode_funcs_t *
+hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer)
+{
+  return buffer->unicode;
+}
+
+/**
+ * hb_buffer_set_direction:
+ * @buffer: a buffer.
+ * @direction:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_buffer_set_direction (hb_buffer_t    *buffer,
+                         hb_direction_t  direction)
+
+{
+  if (unlikely (hb_object_is_inert (buffer)))
+    return;
+
+  buffer->props.direction = direction;
+}
+
+/**
+ * hb_buffer_get_direction:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_direction_t
+hb_buffer_get_direction (hb_buffer_t    *buffer)
+{
+  return buffer->props.direction;
+}
+
+/**
+ * hb_buffer_set_script:
+ * @buffer: a buffer.
+ * @script:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_buffer_set_script (hb_buffer_t *buffer,
+                      hb_script_t  script)
+{
+  if (unlikely (hb_object_is_inert (buffer)))
+    return;
+
+  buffer->props.script = script;
+}
+
+/**
+ * hb_buffer_get_script:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_script_t
+hb_buffer_get_script (hb_buffer_t *buffer)
+{
+  return buffer->props.script;
+}
+
+/**
+ * hb_buffer_set_language:
+ * @buffer: a buffer.
+ * @language:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_buffer_set_language (hb_buffer_t   *buffer,
+                        hb_language_t  language)
+{
+  if (unlikely (hb_object_is_inert (buffer)))
+    return;
+
+  buffer->props.language = language;
+}
+
+/**
+ * hb_buffer_get_language:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.2
+ **/
+hb_language_t
+hb_buffer_get_language (hb_buffer_t *buffer)
+{
+  return buffer->props.language;
+}
+
+/**
+ * hb_buffer_set_segment_properties:
+ * @buffer: a buffer.
+ * @props:
+ *
+ *
+ *
+ * Since: 0.9.7
+ **/
+void
+hb_buffer_set_segment_properties (hb_buffer_t *buffer,
+                                  const hb_segment_properties_t *props)
+{
+  if (unlikely (hb_object_is_inert (buffer)))
+    return;
+
+  buffer->props = *props;
+}
+
+/**
+ * hb_buffer_get_segment_properties:
+ * @buffer: a buffer.
+ * @props: (out):
+ *
+ *
+ *
+ * Since: 0.9.7
+ **/
+void
+hb_buffer_get_segment_properties (hb_buffer_t *buffer,
+                                  hb_segment_properties_t *props)
+{
+  *props = buffer->props;
+}
+
+
+/**
+ * hb_buffer_set_flags:
+ * @buffer: a buffer.
+ * @flags:
+ *
+ *
+ *
+ * Since: 0.9.7
+ **/
+void
+hb_buffer_set_flags (hb_buffer_t       *buffer,
+                     hb_buffer_flags_t  flags)
+{
+  if (unlikely (hb_object_is_inert (buffer)))
+    return;
+
+  buffer->flags = flags;
+}
+
+/**
+ * hb_buffer_get_flags:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.7
+ **/
+hb_buffer_flags_t
+hb_buffer_get_flags (hb_buffer_t *buffer)
+{
+  return buffer->flags;
+}
+
+/**
+ * hb_buffer_set_cluster_level:
+ * @buffer: a buffer.
+ * @cluster_level:
+ *
+ *
+ *
+ * Since: 0.9.42
+ **/
+void
+hb_buffer_set_cluster_level (hb_buffer_t       *buffer,
+                     hb_buffer_cluster_level_t  cluster_level)
+{
+  if (unlikely (hb_object_is_inert (buffer)))
+    return;
+
+  buffer->cluster_level = cluster_level;
+}
+
+/**
+ * hb_buffer_get_cluster_level:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.42
+ **/
+hb_buffer_cluster_level_t
+hb_buffer_get_cluster_level (hb_buffer_t *buffer)
+{
+  return buffer->cluster_level;
+}
+
+
+/**
+ * hb_buffer_set_replacement_codepoint:
+ * @buffer: a buffer.
+ * @replacement:
+ *
+ *
+ *
+ * Since: 0.9.31
+ **/
+void
+hb_buffer_set_replacement_codepoint (hb_buffer_t    *buffer,
+                                     hb_codepoint_t  replacement)
+{
+  if (unlikely (hb_object_is_inert (buffer)))
+    return;
+
+  buffer->replacement = replacement;
+}
+
+/**
+ * hb_buffer_get_replacement_codepoint:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.31
+ **/
+hb_codepoint_t
+hb_buffer_get_replacement_codepoint (hb_buffer_t    *buffer)
+{
+  return buffer->replacement;
+}
+
+
+/**
+ * hb_buffer_reset:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_buffer_reset (hb_buffer_t *buffer)
+{
+  buffer->reset ();
+}
+
+/**
+ * hb_buffer_clear_contents:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Since: 0.9.11
+ **/
+void
+hb_buffer_clear_contents (hb_buffer_t *buffer)
+{
+  buffer->clear ();
+}
+
+/**
+ * hb_buffer_pre_allocate:
+ * @buffer: a buffer.
+ * @size:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
+{
+  return buffer->ensure (size);
+}
+
+/**
+ * hb_buffer_allocation_successful:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_buffer_allocation_successful (hb_buffer_t  *buffer)
+{
+  return !buffer->in_error;
+}
+
+/**
+ * hb_buffer_add:
+ * @buffer: a buffer.
+ * @codepoint:
+ * @cluster:
+ *
+ *
+ *
+ * Since: 0.9.7
+ **/
+void
+hb_buffer_add (hb_buffer_t    *buffer,
+               hb_codepoint_t  codepoint,
+               unsigned int    cluster)
+{
+  buffer->add (codepoint, cluster);
+  buffer->clear_context (1);
+}
+
+/**
+ * hb_buffer_set_length:
+ * @buffer: a buffer.
+ * @length:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_buffer_set_length (hb_buffer_t  *buffer,
+                      unsigned int  length)
+{
+  if (unlikely (hb_object_is_inert (buffer)))
+    return length == 0;
+
+  if (!buffer->ensure (length))
+    return false;
+
+  /* Wipe the new space */
+  if (length > buffer->len) {
+    memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
+    if (buffer->have_positions)
+      memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
+  }
+
+  buffer->len = length;
+
+  if (!length)
+  {
+    buffer->content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
+    buffer->clear_context (0);
+  }
+  buffer->clear_context (1);
+
+  return true;
+}
+
+/**
+ * hb_buffer_get_length:
+ * @buffer: a buffer.
+ *
+ * Returns the number of items in the buffer.
+ *
+ * Return value: buffer length.
+ *
+ * Since: 0.9.2
+ **/
+unsigned int
+hb_buffer_get_length (hb_buffer_t *buffer)
+{
+  return buffer->len;
+}
+
+/**
+ * hb_buffer_get_glyph_infos:
+ * @buffer: a buffer.
+ * @length: (out): output array length.
+ *
+ * Returns buffer glyph information array.  Returned pointer
+ * is valid as long as buffer contents are not modified.
+ *
+ * Return value: (transfer none) (array length=length): buffer glyph information array.
+ *
+ * Since: 0.9.2
+ **/
+hb_glyph_info_t *
+hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
+                           unsigned int *length)
+{
+  if (length)
+    *length = buffer->len;
+
+  return (hb_glyph_info_t *) buffer->info;
+}
+
+/**
+ * hb_buffer_get_glyph_positions:
+ * @buffer: a buffer.
+ * @length: (out): output length.
+ *
+ * Returns buffer glyph position array.  Returned pointer
+ * is valid as long as buffer contents are not modified.
+ *
+ * Return value: (transfer none) (array length=length): buffer glyph position array.
+ *
+ * Since: 0.9.2
+ **/
+hb_glyph_position_t *
+hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
+                               unsigned int *length)
+{
+  if (!buffer->have_positions)
+    buffer->clear_positions ();
+
+  if (length)
+    *length = buffer->len;
+
+  return (hb_glyph_position_t *) buffer->pos;
+}
+
+/**
+ * hb_buffer_reverse:
+ * @buffer: a buffer.
+ *
+ * Reverses buffer contents.
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_buffer_reverse (hb_buffer_t *buffer)
+{
+  buffer->reverse ();
+}
+
+/**
+ * hb_buffer_reverse_range:
+ * @buffer: a buffer.
+ * @start: start index.
+ * @end: end index.
+ *
+ * Reverses buffer contents between start to end.
+ *
+ * Since: 0.9.41
+ **/
+void
+hb_buffer_reverse_range (hb_buffer_t *buffer,
+                         unsigned int start, unsigned int end)
+{
+  buffer->reverse_range (start, end);
+}
+
+/**
+ * hb_buffer_reverse_clusters:
+ * @buffer: a buffer.
+ *
+ * Reverses buffer clusters.  That is, the buffer contents are
+ * reversed, then each cluster (consecutive items having the
+ * same cluster number) are reversed again.
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_buffer_reverse_clusters (hb_buffer_t *buffer)
+{
+  buffer->reverse_clusters ();
+}
+
+/**
+ * hb_buffer_guess_segment_properties:
+ * @buffer: a buffer.
+ *
+ * Sets unset buffer segment properties based on buffer Unicode
+ * contents.  If buffer is not empty, it must have content type
+ * %HB_BUFFER_CONTENT_TYPE_UNICODE.
+ *
+ * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
+ * will be set to the Unicode script of the first character in
+ * the buffer that has a script other than %HB_SCRIPT_COMMON,
+ * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN.
+ *
+ * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
+ * it will be set to the natural horizontal direction of the
+ * buffer script as returned by hb_script_get_horizontal_direction().
+ *
+ * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
+ * it will be set to the process's default language as returned by
+ * hb_language_get_default().  This may change in the future by
+ * taking buffer script into consideration when choosing a language.
+ *
+ * Since: 0.9.7
+ **/
+void
+hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
+{
+  buffer->guess_segment_properties ();
+}
+
+template <typename utf_t>
+static inline void
+hb_buffer_add_utf (hb_buffer_t  *buffer,
+                   const typename utf_t::codepoint_t *text,
+                   int           text_length,
+                   unsigned int  item_offset,
+                   int           item_length)
+{
+  typedef typename utf_t::codepoint_t T;
+  const hb_codepoint_t replacement = buffer->replacement;
+
+  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
+          (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
+
+  if (unlikely (hb_object_is_inert (buffer)))
+    return;
+
+  if (text_length == -1)
+    text_length = utf_t::strlen (text);
+
+  if (item_length == -1)
+    item_length = text_length - item_offset;
+
+  buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
+
+  /* If buffer is empty and pre-context provided, install it.
+   * This check is written this way, to make sure people can
+   * provide pre-context in one add_utf() call, then provide
+   * text in a follow-up call.  See:
+   *
+   * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
+   */
+  if (!buffer->len && item_offset > 0)
+  {
+    /* Add pre-context */
+    buffer->clear_context (0);
+    const T *prev = text + item_offset;
+    const T *start = text;
+    while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
+    {
+      hb_codepoint_t u;
+      prev = utf_t::prev (prev, start, &u, replacement);
+      buffer->context[0][buffer->context_len[0]++] = u;
+    }
+  }
+
+  const T *next = text + item_offset;
+  const T *end = next + item_length;
+  while (next < end)
+  {
+    hb_codepoint_t u;
+    const T *old_next = next;
+    next = utf_t::next (next, end, &u, replacement);
+    buffer->add (u, old_next - (const T *) text);
+  }
+
+  /* Add post-context */
+  buffer->clear_context (1);
+  end = text + text_length;
+  while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
+  {
+    hb_codepoint_t u;
+    next = utf_t::next (next, end, &u, replacement);
+    buffer->context[1][buffer->context_len[1]++] = u;
+  }
+
+  buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
+}
+
+/**
+ * hb_buffer_add_utf8:
+ * @buffer: a buffer.
+ * @text: (array length=text_length) (element-type uint8_t):
+ * @text_length:
+ * @item_offset:
+ * @item_length:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_buffer_add_utf8 (hb_buffer_t  *buffer,
+                    const char   *text,
+                    int           text_length,
+                    unsigned int  item_offset,
+                    int           item_length)
+{
+  hb_buffer_add_utf<hb_utf8_t> (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
+}
+
+/**
+ * hb_buffer_add_utf16:
+ * @buffer: a buffer.
+ * @text: (array length=text_length):
+ * @text_length:
+ * @item_offset:
+ * @item_length:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_buffer_add_utf16 (hb_buffer_t    *buffer,
+                     const uint16_t *text,
+                     int             text_length,
+                     unsigned int    item_offset,
+                     int             item_length)
+{
+  hb_buffer_add_utf<hb_utf16_t> (buffer, text, text_length, item_offset, item_length);
+}
+
+/**
+ * hb_buffer_add_utf32:
+ * @buffer: a buffer.
+ * @text: (array length=text_length):
+ * @text_length:
+ * @item_offset:
+ * @item_length:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_buffer_add_utf32 (hb_buffer_t    *buffer,
+                     const uint32_t *text,
+                     int             text_length,
+                     unsigned int    item_offset,
+                     int             item_length)
+{
+  hb_buffer_add_utf<hb_utf32_t<> > (buffer, text, text_length, item_offset, item_length);
+}
+
+/**
+ * hb_buffer_add_latin1:
+ * @buffer: a buffer.
+ * @text: (array length=text_length) (element-type uint8_t):
+ * @text_length:
+ * @item_offset:
+ * @item_length:
+ *
+ *
+ *
+ * Since: 0.9.39
+ **/
+void
+hb_buffer_add_latin1 (hb_buffer_t   *buffer,
+                      const uint8_t *text,
+                      int            text_length,
+                      unsigned int   item_offset,
+                      int            item_length)
+{
+  hb_buffer_add_utf<hb_latin1_t> (buffer, text, text_length, item_offset, item_length);
+}
+
+/**
+ * hb_buffer_add_codepoints:
+ * @buffer: a buffer.
+ * @text: (array length=text_length):
+ * @text_length:
+ * @item_offset:
+ * @item_length:
+ *
+ *
+ *
+ * Since: 0.9.31
+ **/
+void
+hb_buffer_add_codepoints (hb_buffer_t          *buffer,
+                          const hb_codepoint_t *text,
+                          int                   text_length,
+                          unsigned int          item_offset,
+                          int                   item_length)
+{
+  hb_buffer_add_utf<hb_utf32_t<false> > (buffer, text, text_length, item_offset, item_length);
+}
+
+
+static int
+compare_info_codepoint (const hb_glyph_info_t *pa,
+                        const hb_glyph_info_t *pb)
+{
+  return (int) pb->codepoint - (int) pa->codepoint;
+}
+
+static inline void
+normalize_glyphs_cluster (hb_buffer_t *buffer,
+                          unsigned int start,
+                          unsigned int end,
+                          bool backward)
+{
+  hb_glyph_position_t *pos = buffer->pos;
+
+  /* Total cluster advance */
+  hb_position_t total_x_advance = 0, total_y_advance = 0;
+  for (unsigned int i = start; i < end; i++)
+  {
+    total_x_advance += pos[i].x_advance;
+    total_y_advance += pos[i].y_advance;
+  }
+
+  hb_position_t x_advance = 0, y_advance = 0;
+  for (unsigned int i = start; i < end; i++)
+  {
+    pos[i].x_offset += x_advance;
+    pos[i].y_offset += y_advance;
+
+    x_advance += pos[i].x_advance;
+    y_advance += pos[i].y_advance;
+
+    pos[i].x_advance = 0;
+    pos[i].y_advance = 0;
+  }
+
+  if (backward)
+  {
+    /* Transfer all cluster advance to the last glyph. */
+    pos[end - 1].x_advance = total_x_advance;
+    pos[end - 1].y_advance = total_y_advance;
+
+    hb_stable_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
+  } else {
+    /* Transfer all cluster advance to the first glyph. */
+    pos[start].x_advance += total_x_advance;
+    pos[start].y_advance += total_y_advance;
+    for (unsigned int i = start + 1; i < end; i++) {
+      pos[i].x_offset -= total_x_advance;
+      pos[i].y_offset -= total_y_advance;
+    }
+    hb_stable_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
+  }
+}
+
+/**
+ * hb_buffer_normalize_glyphs:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
+{
+  assert (buffer->have_positions);
+  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+
+  bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
+
+  unsigned int count = buffer->len;
+  if (unlikely (!count)) return;
+  hb_glyph_info_t *info = buffer->info;
+
+  unsigned int start = 0;
+  unsigned int end;
+  for (end = start + 1; end < count; end++)
+    if (info[start].cluster != info[end].cluster) {
+      normalize_glyphs_cluster (buffer, start, end, backward);
+      start = end;
+    }
+  normalize_glyphs_cluster (buffer, start, end, backward);
+}
+
+void
+hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *))
+{
+  assert (!have_positions);
+  for (unsigned int i = start + 1; i < end; i++)
+  {
+    unsigned int j = i;
+    while (j > start && compar (&info[j - 1], &info[i]) > 0)
+      j--;
+    if (i == j)
+      continue;
+    /* Move item i to occupy place for item j, shift what's in between. */
+    merge_clusters (j, i + 1);
+    {
+      hb_glyph_info_t t = info[i];
+      memmove (&info[j + 1], &info[j], (i - j) * sizeof (hb_glyph_info_t));
+      info[j] = t;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer.h	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,378 @@
+/*
+ * Copyright © 1998-2004  David Turner and Werner Lemberg
+ * Copyright © 2004,2007,2009  Red Hat, Inc.
+ * Copyright © 2011,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.
+ *
+ * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_BUFFER_H
+#define HB_BUFFER_H
+
+#include "hb-common.h"
+#include "hb-unicode.h"
+#include "hb-font.h"
+
+HB_BEGIN_DECLS
+
+
+typedef struct hb_glyph_info_t {
+  hb_codepoint_t codepoint;
+  hb_mask_t      mask;
+  uint32_t       cluster;
+
+  /*< private >*/
+  hb_var_int_t   var1;
+  hb_var_int_t   var2;
+} hb_glyph_info_t;
+
+typedef struct hb_glyph_position_t {
+  hb_position_t  x_advance;
+  hb_position_t  y_advance;
+  hb_position_t  x_offset;
+  hb_position_t  y_offset;
+
+  /*< private >*/
+  hb_var_int_t   var;
+} hb_glyph_position_t;
+
+
+typedef struct hb_segment_properties_t {
+  hb_direction_t  direction;
+  hb_script_t     script;
+  hb_language_t   language;
+  /*< private >*/
+  void           *reserved1;
+  void           *reserved2;
+} hb_segment_properties_t;
+
+#define HB_SEGMENT_PROPERTIES_DEFAULT {HB_DIRECTION_INVALID, \
+                                       HB_SCRIPT_INVALID, \
+                                       HB_LANGUAGE_INVALID, \
+                                       NULL, \
+                                       NULL}
+
+hb_bool_t
+hb_segment_properties_equal (const hb_segment_properties_t *a,
+                             const hb_segment_properties_t *b);
+
+unsigned int
+hb_segment_properties_hash (const hb_segment_properties_t *p);
+
+
+
+/*
+ * hb_buffer_t
+ */
+
+typedef struct hb_buffer_t hb_buffer_t;
+
+hb_buffer_t *
+hb_buffer_create (void);
+
+hb_buffer_t *
+hb_buffer_get_empty (void);
+
+hb_buffer_t *
+hb_buffer_reference (hb_buffer_t *buffer);
+
+void
+hb_buffer_destroy (hb_buffer_t *buffer);
+
+hb_bool_t
+hb_buffer_set_user_data (hb_buffer_t        *buffer,
+                         hb_user_data_key_t *key,
+                         void *              data,
+                         hb_destroy_func_t   destroy,
+                         hb_bool_t           replace);
+
+void *
+hb_buffer_get_user_data (hb_buffer_t        *buffer,
+                         hb_user_data_key_t *key);
+
+
+typedef enum {
+  HB_BUFFER_CONTENT_TYPE_INVALID = 0,
+  HB_BUFFER_CONTENT_TYPE_UNICODE,
+  HB_BUFFER_CONTENT_TYPE_GLYPHS
+} hb_buffer_content_type_t;
+
+void
+hb_buffer_set_content_type (hb_buffer_t              *buffer,
+                            hb_buffer_content_type_t  content_type);
+
+hb_buffer_content_type_t
+hb_buffer_get_content_type (hb_buffer_t *buffer);
+
+
+void
+hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
+                             hb_unicode_funcs_t *unicode_funcs);
+
+hb_unicode_funcs_t *
+hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer);
+
+void
+hb_buffer_set_direction (hb_buffer_t    *buffer,
+                         hb_direction_t  direction);
+
+hb_direction_t
+hb_buffer_get_direction (hb_buffer_t *buffer);
+
+void
+hb_buffer_set_script (hb_buffer_t *buffer,
+                      hb_script_t  script);
+
+hb_script_t
+hb_buffer_get_script (hb_buffer_t *buffer);
+
+void
+hb_buffer_set_language (hb_buffer_t   *buffer,
+                        hb_language_t  language);
+
+
+hb_language_t
+hb_buffer_get_language (hb_buffer_t *buffer);
+
+void
+hb_buffer_set_segment_properties (hb_buffer_t *buffer,
+                                  const hb_segment_properties_t *props);
+
+void
+hb_buffer_get_segment_properties (hb_buffer_t *buffer,
+                                  hb_segment_properties_t *props);
+
+void
+hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
+
+
+/*
+ * Since: 0.9.20
+ */
+typedef enum { /*< flags >*/
+  HB_BUFFER_FLAG_DEFAULT                        = 0x00000000u,
+  HB_BUFFER_FLAG_BOT                            = 0x00000001u, /* Beginning-of-text */
+  HB_BUFFER_FLAG_EOT                            = 0x00000002u, /* End-of-text */
+  HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES    = 0x00000004u
+} hb_buffer_flags_t;
+
+void
+hb_buffer_set_flags (hb_buffer_t       *buffer,
+                     hb_buffer_flags_t  flags);
+
+hb_buffer_flags_t
+hb_buffer_get_flags (hb_buffer_t *buffer);
+
+/*
+ * Since: 0.9.42
+ */
+typedef enum {
+  HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES    = 0,
+  HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS   = 1,
+  HB_BUFFER_CLUSTER_LEVEL_CHARACTERS            = 2,
+  HB_BUFFER_CLUSTER_LEVEL_DEFAULT = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES
+} hb_buffer_cluster_level_t;
+
+void
+hb_buffer_set_cluster_level (hb_buffer_t               *buffer,
+                             hb_buffer_cluster_level_t  cluster_level);
+
+hb_buffer_cluster_level_t
+hb_buffer_get_cluster_level (hb_buffer_t *buffer);
+
+#define HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT 0xFFFDu
+
+/* Sets codepoint used to replace invalid UTF-8/16/32 entries.
+ * Default is 0xFFFDu. */
+void
+hb_buffer_set_replacement_codepoint (hb_buffer_t    *buffer,
+                                     hb_codepoint_t  replacement);
+
+hb_codepoint_t
+hb_buffer_get_replacement_codepoint (hb_buffer_t    *buffer);
+
+
+/* Resets the buffer.  Afterwards it's as if it was just created,
+ * except that it has a larger buffer allocated perhaps... */
+void
+hb_buffer_reset (hb_buffer_t *buffer);
+
+/* Like reset, but does NOT clear unicode_funcs and replacement_codepoint. */
+void
+hb_buffer_clear_contents (hb_buffer_t *buffer);
+
+/* Returns false if allocation failed */
+hb_bool_t
+hb_buffer_pre_allocate (hb_buffer_t  *buffer,
+                        unsigned int  size);
+
+
+/* Returns false if allocation has failed before */
+hb_bool_t
+hb_buffer_allocation_successful (hb_buffer_t  *buffer);
+
+void
+hb_buffer_reverse (hb_buffer_t *buffer);
+
+void
+hb_buffer_reverse_range (hb_buffer_t *buffer,
+                         unsigned int start, unsigned int end);
+
+void
+hb_buffer_reverse_clusters (hb_buffer_t *buffer);
+
+
+/* Filling the buffer in */
+
+void
+hb_buffer_add (hb_buffer_t    *buffer,
+               hb_codepoint_t  codepoint,
+               unsigned int    cluster);
+
+void
+hb_buffer_add_utf8 (hb_buffer_t  *buffer,
+                    const char   *text,
+                    int           text_length,
+                    unsigned int  item_offset,
+                    int           item_length);
+
+void
+hb_buffer_add_utf16 (hb_buffer_t    *buffer,
+                     const uint16_t *text,
+                     int             text_length,
+                     unsigned int    item_offset,
+                     int             item_length);
+
+void
+hb_buffer_add_utf32 (hb_buffer_t    *buffer,
+                     const uint32_t *text,
+                     int             text_length,
+                     unsigned int    item_offset,
+                     int             item_length);
+
+/* Allows only access to first 256 Unicode codepoints. */
+void
+hb_buffer_add_latin1 (hb_buffer_t   *buffer,
+                      const uint8_t *text,
+                      int            text_length,
+                      unsigned int   item_offset,
+                      int            item_length);
+
+/* Like add_utf32 but does NOT check for invalid Unicode codepoints. */
+void
+hb_buffer_add_codepoints (hb_buffer_t          *buffer,
+                          const hb_codepoint_t *text,
+                          int                   text_length,
+                          unsigned int          item_offset,
+                          int                   item_length);
+
+
+/* Clears any new items added at the end */
+hb_bool_t
+hb_buffer_set_length (hb_buffer_t  *buffer,
+                      unsigned int  length);
+
+/* Return value valid as long as buffer not modified */
+unsigned int
+hb_buffer_get_length (hb_buffer_t *buffer);
+
+/* Getting glyphs out of the buffer */
+
+/* Return value valid as long as buffer not modified */
+hb_glyph_info_t *
+hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
+                           unsigned int *length);
+
+/* Return value valid as long as buffer not modified */
+hb_glyph_position_t *
+hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
+                               unsigned int *length);
+
+
+/* Reorders a glyph buffer to have canonical in-cluster glyph order / position.
+ * The resulting clusters should behave identical to pre-reordering clusters.
+ * NOTE: This has nothing to do with Unicode normalization. */
+void
+hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
+
+
+/*
+ * Serialize
+ */
+
+/*
+ * Since: 0.9.20
+ */
+typedef enum { /*< flags >*/
+  HB_BUFFER_SERIALIZE_FLAG_DEFAULT              = 0x00000000u,
+  HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS          = 0x00000001u,
+  HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS         = 0x00000002u,
+  HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES       = 0x00000004u,
+  HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS        = 0x00000008u
+} hb_buffer_serialize_flags_t;
+
+typedef enum {
+  HB_BUFFER_SERIALIZE_FORMAT_TEXT       = HB_TAG('T','E','X','T'),
+  HB_BUFFER_SERIALIZE_FORMAT_JSON       = HB_TAG('J','S','O','N'),
+  HB_BUFFER_SERIALIZE_FORMAT_INVALID    = HB_TAG_NONE
+} hb_buffer_serialize_format_t;
+
+/* len=-1 means str is NUL-terminated. */
+hb_buffer_serialize_format_t
+hb_buffer_serialize_format_from_string (const char *str, int len);
+
+const char *
+hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format);
+
+const char **
+hb_buffer_serialize_list_formats (void);
+
+/* Returns number of items, starting at start, that were serialized. */
+unsigned int
+hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
+                            unsigned int start,
+                            unsigned int end,
+                            char *buf,
+                            unsigned int buf_size,
+                            unsigned int *buf_consumed, /* May be NULL */
+                            hb_font_t *font, /* May be NULL */
+                            hb_buffer_serialize_format_t format,
+                            hb_buffer_serialize_flags_t flags);
+
+hb_bool_t
+hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
+                              const char *buf,
+                              int buf_len, /* -1 means nul-terminated */
+                              const char **end_ptr, /* May be NULL */
+                              hb_font_t *font, /* May be NULL */
+                              hb_buffer_serialize_format_t format);
+
+
+HB_END_DECLS
+
+#endif /* HB_BUFFER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-cache-private.hh	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,74 @@
+/*
+ * Copyright © 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
+ */
+
+#ifndef HB_CACHE_PRIVATE_HH
+#define HB_CACHE_PRIVATE_HH
+
+#include "hb-private.hh"
+
+
+/* Implements a lock-free cache for int->int functions. */
+
+template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits>
+struct hb_cache_t
+{
+  ASSERT_STATIC (key_bits >= cache_bits);
+  ASSERT_STATIC (key_bits + value_bits - cache_bits < 8 * sizeof (unsigned int));
+
+  inline void clear (void)
+  {
+    memset (values, 255, sizeof (values));
+  }
+
+  inline bool get (unsigned int key, unsigned int *value)
+  {
+    unsigned int k = key & ((1<<cache_bits)-1);
+    unsigned int v = values[k];
+    if ((v >> value_bits) != (key >> cache_bits))
+      return false;
+    *value = v & ((1<<value_bits)-1);
+    return true;
+  }
+
+  inline bool set (unsigned int key, unsigned int value)
+  {
+    if (unlikely ((key >> key_bits) || (value >> value_bits)))
+      return false; /* Overflows */
+    unsigned int k = key & ((1<<cache_bits)-1);
+    unsigned int v = ((key>>cache_bits)<<value_bits) | value;
+    values[k] = v;
+    return true;
+  }
+
+  private:
+  unsigned int values[1<<cache_bits];
+};
+
+typedef hb_cache_t<21, 16, 8> hb_cmap_cache_t;
+typedef hb_cache_t<16, 24, 8> hb_advance_cache_t;
+
+
+#endif /* HB_CACHE_PRIVATE_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-common.cc	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,593 @@
+/*
+ * Copyright © 2009,2010  Red Hat, Inc.
+ * Copyright © 2011,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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-private.hh"
+
+#include "hb-mutex-private.hh"
+#include "hb-object-private.hh"
+
+#include <locale.h>
+
+
+/* hb_options_t */
+
+hb_options_union_t _hb_options;
+
+void
+_hb_options_init (void)
+{
+  hb_options_union_t u;
+  u.i = 0;
+  u.opts.initialized = 1;
+
+  char *c = getenv ("HB_OPTIONS");
+  u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible");
+
+  /* This is idempotent and threadsafe. */
+  _hb_options = u;
+}
+
+
+/* hb_tag_t */
+
+/**
+ * hb_tag_from_string:
+ * @str: (array length=len) (element-type uint8_t):
+ * @len:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_tag_t
+hb_tag_from_string (const char *str, int len)
+{
+  char tag[4];
+  unsigned int i;
+
+  if (!str || !len || !*str)
+    return HB_TAG_NONE;
+
+  if (len < 0 || len > 4)
+    len = 4;
+  for (i = 0; i < (unsigned) len && str[i]; i++)
+    tag[i] = str[i];
+  for (; i < 4; i++)
+    tag[i] = ' ';
+
+  return HB_TAG_CHAR4 (tag);
+}
+
+/**
+ * hb_tag_to_string:
+ * @tag:
+ * @buf: (array fixed-size=4):
+ *
+ *
+ *
+ * Since: 0.9.5
+ **/
+void
+hb_tag_to_string (hb_tag_t tag, char *buf)
+{
+  buf[0] = (char) (uint8_t) (tag >> 24);
+  buf[1] = (char) (uint8_t) (tag >> 16);
+  buf[2] = (char) (uint8_t) (tag >>  8);
+  buf[3] = (char) (uint8_t) (tag >>  0);
+}
+
+
+/* hb_direction_t */
+
+const char direction_strings[][4] = {
+  "ltr",
+  "rtl",
+  "ttb",
+  "btt"
+};
+
+/**
+ * hb_direction_from_string:
+ * @str: (array length=len) (element-type uint8_t):
+ * @len:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_direction_t
+hb_direction_from_string (const char *str, int len)
+{
+  if (unlikely (!str || !len || !*str))
+    return HB_DIRECTION_INVALID;
+
+  /* Lets match loosely: just match the first letter, such that
+   * all of "ltr", "left-to-right", etc work!
+   */
+  char c = TOLOWER (str[0]);
+  for (unsigned int i = 0; i < ARRAY_LENGTH (direction_strings); i++)
+    if (c == direction_strings[i][0])
+      return (hb_direction_t) (HB_DIRECTION_LTR + i);
+
+  return HB_DIRECTION_INVALID;
+}
+
+/**
+ * hb_direction_to_string:
+ * @direction:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.2
+ **/
+const char *
+hb_direction_to_string (hb_direction_t direction)
+{
+  if (likely ((unsigned int) (direction - HB_DIRECTION_LTR)
+              < ARRAY_LENGTH (direction_strings)))
+    return direction_strings[direction - HB_DIRECTION_LTR];
+
+  return "invalid";
+}
+
+
+/* hb_language_t */
+
+struct hb_language_impl_t {
+  const char s[1];
+};
+
+static const char canon_map[256] = {
+   0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,  '-',  0,   0,
+  '0', '1', '2', '3', '4', '5', '6', '7',  '8', '9',  0,   0,   0,   0,   0,   0,
+  '-', 'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+  'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,  '-',
+   0,  'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+  'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,   0
+};
+
+static bool
+lang_equal (hb_language_t  v1,
+            const void    *v2)
+{
+  const unsigned char *p1 = (const unsigned char *) v1;
+  const unsigned char *p2 = (const unsigned char *) v2;
+
+  while (*p1 && *p1 == canon_map[*p2])
+    p1++, p2++;
+
+  return *p1 == canon_map[*p2];
+}
+
+#if 0
+static unsigned int
+lang_hash (const void *key)
+{
+  const unsigned char *p = key;
+  unsigned int h = 0;
+  while (canon_map[*p])
+    {
+      h = (h << 5) - h + canon_map[*p];
+      p++;
+    }
+
+  return h;
+}
+#endif
+
+
+struct hb_language_item_t {
+
+  struct hb_language_item_t *next;
+  hb_language_t lang;
+
+  inline bool operator == (const char *s) const {
+    return lang_equal (lang, s);
+  }
+
+  inline hb_language_item_t & operator = (const char *s) {
+    lang = (hb_language_t) strdup (s);
+    for (unsigned char *p = (unsigned char *) lang; *p; p++)
+      *p = canon_map[*p];
+
+    return *this;
+  }
+
+  void finish (void) { free ((void *) lang); }
+};
+
+
+/* Thread-safe lock-free language list */
+
+static hb_language_item_t *langs;
+
+#ifdef HB_USE_ATEXIT
+static
+void free_langs (void)
+{
+  while (langs) {
+    hb_language_item_t *next = langs->next;
+    langs->finish ();
+    free (langs);
+    langs = next;
+  }
+}
+#endif
+
+static hb_language_item_t *
+lang_find_or_insert (const char *key)
+{
+retry:
+  hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs);
+
+  for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
+    if (*lang == key)
+      return lang;
+
+  /* Not found; allocate one. */
+  hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t));
+  if (unlikely (!lang))
+    return NULL;
+  lang->next = first_lang;
+  *lang = key;
+
+  if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {
+    lang->finish ();
+    free (lang);
+    goto retry;
+  }
+
+#ifdef HB_USE_ATEXIT
+  if (!first_lang)
+    atexit (free_langs); /* First person registers atexit() callback. */
+#endif
+
+  return lang;
+}
+
+
+/**
+ * hb_language_from_string:
+ * @str: (array length=len) (element-type uint8_t):
+ * @len:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.2
+ **/
+hb_language_t
+hb_language_from_string (const char *str, int len)
+{
+  if (!str || !len || !*str)
+    return HB_LANGUAGE_INVALID;
+
+  hb_language_item_t *item = NULL;
+  if (len >= 0)
+  {
+    /* NUL-terminate it. */
+    char strbuf[64];
+    len = MIN (len, (int) sizeof (strbuf) - 1);
+    memcpy (strbuf, str, len);
+    strbuf[len] = '\0';
+    item = lang_find_or_insert (strbuf);
+  }
+  else
+    item = lang_find_or_insert (str);
+
+  return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
+}
+
+/**
+ * hb_language_to_string:
+ * @language:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.2
+ **/
+const char *
+hb_language_to_string (hb_language_t language)
+{
+  /* This is actually NULL-safe! */
+  return language->s;
+}
+
+/**
+ * hb_language_get_default:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.2
+ **/
+hb_language_t
+hb_language_get_default (void)
+{
+  static hb_language_t default_language = HB_LANGUAGE_INVALID;
+
+  hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language);
+  if (unlikely (language == HB_LANGUAGE_INVALID)) {
+    language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1);
+    (void) hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language);
+  }
+
+  return default_language;
+}
+
+
+/* hb_script_t */
+
+/**
+ * hb_script_from_iso15924_tag:
+ * @tag:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_script_t
+hb_script_from_iso15924_tag (hb_tag_t tag)
+{
+  if (unlikely (tag == HB_TAG_NONE))
+    return HB_SCRIPT_INVALID;
+
+  /* Be lenient, adjust case (one capital letter followed by three small letters) */
+  tag = (tag & 0xDFDFDFDFu) | 0x00202020u;
+
+  switch (tag) {
+
+    /* These graduated from the 'Q' private-area codes, but
+     * the old code is still aliased by Unicode, and the Qaai
+     * one in use by ICU. */
+    case HB_TAG('Q','a','a','i'): return HB_SCRIPT_INHERITED;
+    case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC;
+
+    /* Script variants from http://unicode.org/iso15924/ */
+    case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC;
+    case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN;
+    case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN;
+    case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC;
+    case HB_TAG('S','y','r','j'): return HB_SCRIPT_SYRIAC;
+    case HB_TAG('S','y','r','n'): return HB_SCRIPT_SYRIAC;
+  }
+
+  /* If it looks right, just use the tag as a script */
+  if (((uint32_t) tag & 0xE0E0E0E0u) == 0x40606060u)
+    return (hb_script_t) tag;
+
+  /* Otherwise, return unknown */
+  return HB_SCRIPT_UNKNOWN;
+}
+
+/**
+ * hb_script_from_string:
+ * @s: (array length=len) (element-type uint8_t):
+ * @len:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_script_t
+hb_script_from_string (const char *s, int len)
+{
+  return hb_script_from_iso15924_tag (hb_tag_from_string (s, len));
+}
+
+/**
+ * hb_script_to_iso15924_tag:
+ * @script:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_tag_t
+hb_script_to_iso15924_tag (hb_script_t script)
+{
+  return (hb_tag_t) script;
+}
+
+/**
+ * hb_script_get_horizontal_direction:
+ * @script:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_direction_t
+hb_script_get_horizontal_direction (hb_script_t script)
+{
+  /* http://goo.gl/x9ilM */
+  switch ((hb_tag_t) script)
+  {
+    /* Unicode-1.1 additions */
+    case HB_SCRIPT_ARABIC:
+    case HB_SCRIPT_HEBREW:
+
+    /* Unicode-3.0 additions */
+    case HB_SCRIPT_SYRIAC:
+    case HB_SCRIPT_THAANA:
+
+    /* Unicode-4.0 additions */
+    case HB_SCRIPT_CYPRIOT:
+
+    /* Unicode-4.1 additions */
+    case HB_SCRIPT_KHAROSHTHI:
+
+    /* Unicode-5.0 additions */
+    case HB_SCRIPT_PHOENICIAN:
+    case HB_SCRIPT_NKO:
+
+    /* Unicode-5.1 additions */
+    case HB_SCRIPT_LYDIAN:
+
+    /* Unicode-5.2 additions */
+    case HB_SCRIPT_AVESTAN:
+    case HB_SCRIPT_IMPERIAL_ARAMAIC:
+    case HB_SCRIPT_INSCRIPTIONAL_PAHLAVI:
+    case HB_SCRIPT_INSCRIPTIONAL_PARTHIAN:
+    case HB_SCRIPT_OLD_SOUTH_ARABIAN:
+    case HB_SCRIPT_OLD_TURKIC:
+    case HB_SCRIPT_SAMARITAN:
+
+    /* Unicode-6.0 additions */
+    case HB_SCRIPT_MANDAIC:
+
+    /* Unicode-6.1 additions */
+    case HB_SCRIPT_MEROITIC_CURSIVE:
+    case HB_SCRIPT_MEROITIC_HIEROGLYPHS:
+
+    /* Unicode-7.0 additions */
+    case HB_SCRIPT_MANICHAEAN:
+    case HB_SCRIPT_MENDE_KIKAKUI:
+    case HB_SCRIPT_NABATAEAN:
+    case HB_SCRIPT_OLD_NORTH_ARABIAN:
+    case HB_SCRIPT_PALMYRENE:
+    case HB_SCRIPT_PSALTER_PAHLAVI:
+
+    /* Unicode-8.0 additions */
+    case HB_SCRIPT_OLD_HUNGARIAN:
+
+      return HB_DIRECTION_RTL;
+  }
+
+  return HB_DIRECTION_LTR;
+}
+
+
+/* hb_user_data_array_t */
+
+bool
+hb_user_data_array_t::set (hb_user_data_key_t *key,
+                           void *              data,
+                           hb_destroy_func_t   destroy,
+                           hb_bool_t           replace)
+{
+  if (!key)
+    return false;
+
+  if (replace) {
+    if (!data && !destroy) {
+      items.remove (key, lock);
+      return true;
+    }
+  }
+  hb_user_data_item_t item = {key, data, destroy};
+  bool ret = !!items.replace_or_insert (item, lock, replace);
+
+  return ret;
+}
+
+void *
+hb_user_data_array_t::get (hb_user_data_key_t *key)
+{
+  hb_user_data_item_t item = {NULL };
+
+  return items.find (key, &item, lock) ? item.data : NULL;
+}
+
+
+/* hb_version */
+
+/**
+ * hb_version:
+ * @major: (out): Library major version component.
+ * @minor: (out): Library minor version component.
+ * @micro: (out): Library micro version component.
+ *
+ * Returns library version as three integer components.
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_version (unsigned int *major,
+            unsigned int *minor,
+            unsigned int *micro)
+{
+  *major = HB_VERSION_MAJOR;
+  *minor = HB_VERSION_MINOR;
+  *micro = HB_VERSION_MICRO;
+}
+
+/**
+ * hb_version_string:
+ *
+ * Returns library version as a string with three components.
+ *
+ * Return value: library version string.
+ *
+ * Since: 0.9.2
+ **/
+const char *
+hb_version_string (void)
+{
+  return HB_VERSION_STRING;
+}
+
+/**
+ * hb_version_atleast:
+ * @major:
+ * @minor:
+ * @micro:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.30
+ **/
+hb_bool_t
+hb_version_atleast (unsigned int major,
+                    unsigned int minor,
+                    unsigned int micro)
+{
+  return HB_VERSION_ATLEAST (major, minor, micro);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-common.h	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,354 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * Copyright © 2011,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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_COMMON_H
+#define HB_COMMON_H
+
+#ifndef HB_BEGIN_DECLS
+# ifdef __cplusplus
+#  define HB_BEGIN_DECLS        extern "C" {
+#  define HB_END_DECLS          }
+# else /* !__cplusplus */
+#  define HB_BEGIN_DECLS
+#  define HB_END_DECLS
+# endif /* !__cplusplus */
+#endif
+
+#if !defined (HB_DONT_DEFINE_STDINT)
+
+#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \
+    defined (_sgi) || defined (__sun) || defined (sun) || \
+    defined (__digital__) || defined (__HP_cc)
+#  include <inttypes.h>
+#elif defined (_AIX)
+#  include <sys/inttypes.h>
+/* VS 2010 (_MSC_VER 1600) has stdint.h */
+#elif defined (_MSC_VER) && _MSC_VER < 1600
+typedef __int8 int8_t;
+typedef unsigned __int8 uint8_t;
+typedef __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+#  include <stdint.h>
+#endif
+
+#endif
+
+HB_BEGIN_DECLS
+
+
+typedef int hb_bool_t;
+
+typedef uint32_t hb_codepoint_t;
+typedef int32_t hb_position_t;
+typedef uint32_t hb_mask_t;
+
+typedef union _hb_var_int_t {
+  uint32_t u32;
+  int32_t i32;
+  uint16_t u16[2];
+  int16_t i16[2];
+  uint8_t u8[4];
+  int8_t i8[4];
+} hb_var_int_t;
+
+
+/* hb_tag_t */
+
+typedef uint32_t hb_tag_t;
+
+#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint8_t)(c1))<<24)|(((uint8_t)(c2))<<16)|(((uint8_t)(c3))<<8)|((uint8_t)(c4))))
+#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)
+#define HB_TAG_MAX_SIGNED HB_TAG(0x7f,0xff,0xff,0xff)
+
+/* len=-1 means str is NUL-terminated. */
+hb_tag_t
+hb_tag_from_string (const char *str, int len);
+
+/* buf should have 4 bytes. */
+void
+hb_tag_to_string (hb_tag_t tag, char *buf);
+
+
+/* hb_direction_t */
+
+typedef enum {
+  HB_DIRECTION_INVALID = 0,
+  HB_DIRECTION_LTR = 4,
+  HB_DIRECTION_RTL,
+  HB_DIRECTION_TTB,
+  HB_DIRECTION_BTT
+} hb_direction_t;
+
+/* len=-1 means str is NUL-terminated */
+hb_direction_t
+hb_direction_from_string (const char *str, int len);
+
+const char *
+hb_direction_to_string (hb_direction_t direction);
+
+#define HB_DIRECTION_IS_VALID(dir)      ((((unsigned int) (dir)) & ~3U) == 4)
+/* Direction must be valid for the following */
+#define HB_DIRECTION_IS_HORIZONTAL(dir) ((((unsigned int) (dir)) & ~1U) == 4)
+#define HB_DIRECTION_IS_VERTICAL(dir)   ((((unsigned int) (dir)) & ~1U) == 6)
+#define HB_DIRECTION_IS_FORWARD(dir)    ((((unsigned int) (dir)) & ~2U) == 4)
+#define HB_DIRECTION_IS_BACKWARD(dir)   ((((unsigned int) (dir)) & ~2U) == 5)
+#define HB_DIRECTION_REVERSE(dir)       ((hb_direction_t) (((unsigned int) (dir)) ^ 1))
+
+
+/* hb_language_t */
+
+typedef const struct hb_language_impl_t *hb_language_t;
+
+/* len=-1 means str is NUL-terminated */
+hb_language_t
+hb_language_from_string (const char *str, int len);
+
+const char *
+hb_language_to_string (hb_language_t language);
+
+#define HB_LANGUAGE_INVALID ((hb_language_t) NULL)
+
+hb_language_t
+hb_language_get_default (void);
+
+
+/* hb_script_t */
+
+/* http://unicode.org/iso15924/ */
+/* http://goo.gl/x9ilM */
+/* Unicode Character Database property: Script (sc) */
+typedef enum
+{
+  /*1.1*/ HB_SCRIPT_COMMON                      = HB_TAG ('Z','y','y','y'),
+  /*1.1*/ HB_SCRIPT_INHERITED                   = HB_TAG ('Z','i','n','h'),
+  /*5.0*/ HB_SCRIPT_UNKNOWN                     = HB_TAG ('Z','z','z','z'),
+
+  /*1.1*/ HB_SCRIPT_ARABIC                      = HB_TAG ('A','r','a','b'),
+  /*1.1*/ HB_SCRIPT_ARMENIAN                    = HB_TAG ('A','r','m','n'),
+  /*1.1*/ HB_SCRIPT_BENGALI                     = HB_TAG ('B','e','n','g'),
+  /*1.1*/ HB_SCRIPT_CYRILLIC                    = HB_TAG ('C','y','r','l'),
+  /*1.1*/ HB_SCRIPT_DEVANAGARI                  = HB_TAG ('D','e','v','a'),
+  /*1.1*/ HB_SCRIPT_GEORGIAN                    = HB_TAG ('G','e','o','r'),
+  /*1.1*/ HB_SCRIPT_GREEK                       = HB_TAG ('G','r','e','k'),
+  /*1.1*/ HB_SCRIPT_GUJARATI                    = HB_TAG ('G','u','j','r'),
+  /*1.1*/ HB_SCRIPT_GURMUKHI                    = HB_TAG ('G','u','r','u'),
+  /*1.1*/ HB_SCRIPT_HANGUL                      = HB_TAG ('H','a','n','g'),
+  /*1.1*/ HB_SCRIPT_HAN                         = HB_TAG ('H','a','n','i'),
+  /*1.1*/ HB_SCRIPT_HEBREW                      = HB_TAG ('H','e','b','r'),
+  /*1.1*/ HB_SCRIPT_HIRAGANA                    = HB_TAG ('H','i','r','a'),
+  /*1.1*/ HB_SCRIPT_KANNADA                     = HB_TAG ('K','n','d','a'),
+  /*1.1*/ HB_SCRIPT_KATAKANA                    = HB_TAG ('K','a','n','a'),
+  /*1.1*/ HB_SCRIPT_LAO                         = HB_TAG ('L','a','o','o'),
+  /*1.1*/ HB_SCRIPT_LATIN                       = HB_TAG ('L','a','t','n'),
+  /*1.1*/ HB_SCRIPT_MALAYALAM                   = HB_TAG ('M','l','y','m'),
+  /*1.1*/ HB_SCRIPT_ORIYA                       = HB_TAG ('O','r','y','a'),
+  /*1.1*/ HB_SCRIPT_TAMIL                       = HB_TAG ('T','a','m','l'),
+  /*1.1*/ HB_SCRIPT_TELUGU                      = HB_TAG ('T','e','l','u'),
+  /*1.1*/ HB_SCRIPT_THAI                        = HB_TAG ('T','h','a','i'),
+
+  /*2.0*/ HB_SCRIPT_TIBETAN                     = HB_TAG ('T','i','b','t'),
+
+  /*3.0*/ HB_SCRIPT_BOPOMOFO                    = HB_TAG ('B','o','p','o'),
+  /*3.0*/ HB_SCRIPT_BRAILLE                     = HB_TAG ('B','r','a','i'),
+  /*3.0*/ HB_SCRIPT_CANADIAN_SYLLABICS          = HB_TAG ('C','a','n','s'),
+  /*3.0*/ HB_SCRIPT_CHEROKEE                    = HB_TAG ('C','h','e','r'),
+  /*3.0*/ HB_SCRIPT_ETHIOPIC                    = HB_TAG ('E','t','h','i'),
+  /*3.0*/ HB_SCRIPT_KHMER                       = HB_TAG ('K','h','m','r'),
+  /*3.0*/ HB_SCRIPT_MONGOLIAN                   = HB_TAG ('M','o','n','g'),
+  /*3.0*/ HB_SCRIPT_MYANMAR                     = HB_TAG ('M','y','m','r'),
+  /*3.0*/ HB_SCRIPT_OGHAM                       = HB_TAG ('O','g','a','m'),
+  /*3.0*/ HB_SCRIPT_RUNIC                       = HB_TAG ('R','u','n','r'),
+  /*3.0*/ HB_SCRIPT_SINHALA                     = HB_TAG ('S','i','n','h'),
+  /*3.0*/ HB_SCRIPT_SYRIAC                      = HB_TAG ('S','y','r','c'),
+  /*3.0*/ HB_SCRIPT_THAANA                      = HB_TAG ('T','h','a','a'),
+  /*3.0*/ HB_SCRIPT_YI                          = HB_TAG ('Y','i','i','i'),
+
+  /*3.1*/ HB_SCRIPT_DESERET                     = HB_TAG ('D','s','r','t'),
+  /*3.1*/ HB_SCRIPT_GOTHIC                      = HB_TAG ('G','o','t','h'),
+  /*3.1*/ HB_SCRIPT_OLD_ITALIC                  = HB_TAG ('I','t','a','l'),
+
+  /*3.2*/ HB_SCRIPT_BUHID                       = HB_TAG ('B','u','h','d'),
+  /*3.2*/ HB_SCRIPT_HANUNOO                     = HB_TAG ('H','a','n','o'),
+  /*3.2*/ HB_SCRIPT_TAGALOG                     = HB_TAG ('T','g','l','g'),
+  /*3.2*/ HB_SCRIPT_TAGBANWA                    = HB_TAG ('T','a','g','b'),
+
+  /*4.0*/ HB_SCRIPT_CYPRIOT                     = HB_TAG ('C','p','r','t'),
+  /*4.0*/ HB_SCRIPT_LIMBU                       = HB_TAG ('L','i','m','b'),
+  /*4.0*/ HB_SCRIPT_LINEAR_B                    = HB_TAG ('L','i','n','b'),
+  /*4.0*/ HB_SCRIPT_OSMANYA                     = HB_TAG ('O','s','m','a'),
+  /*4.0*/ HB_SCRIPT_SHAVIAN                     = HB_TAG ('S','h','a','w'),
+  /*4.0*/ HB_SCRIPT_TAI_LE                      = HB_TAG ('T','a','l','e'),
+  /*4.0*/ HB_SCRIPT_UGARITIC                    = HB_TAG ('U','g','a','r'),
+
+  /*4.1*/ HB_SCRIPT_BUGINESE                    = HB_TAG ('B','u','g','i'),
+  /*4.1*/ HB_SCRIPT_COPTIC                      = HB_TAG ('C','o','p','t'),
+  /*4.1*/ HB_SCRIPT_GLAGOLITIC                  = HB_TAG ('G','l','a','g'),
+  /*4.1*/ HB_SCRIPT_KHAROSHTHI                  = HB_TAG ('K','h','a','r'),
+  /*4.1*/ HB_SCRIPT_NEW_TAI_LUE                 = HB_TAG ('T','a','l','u'),
+  /*4.1*/ HB_SCRIPT_OLD_PERSIAN                 = HB_TAG ('X','p','e','o'),
+  /*4.1*/ HB_SCRIPT_SYLOTI_NAGRI                = HB_TAG ('S','y','l','o'),
+  /*4.1*/ HB_SCRIPT_TIFINAGH                    = HB_TAG ('T','f','n','g'),
+
+  /*5.0*/ HB_SCRIPT_BALINESE                    = HB_TAG ('B','a','l','i'),
+  /*5.0*/ HB_SCRIPT_CUNEIFORM                   = HB_TAG ('X','s','u','x'),
+  /*5.0*/ HB_SCRIPT_NKO                         = HB_TAG ('N','k','o','o'),
+  /*5.0*/ HB_SCRIPT_PHAGS_PA                    = HB_TAG ('P','h','a','g'),
+  /*5.0*/ HB_SCRIPT_PHOENICIAN                  = HB_TAG ('P','h','n','x'),
+
+  /*5.1*/ HB_SCRIPT_CARIAN                      = HB_TAG ('C','a','r','i'),
+  /*5.1*/ HB_SCRIPT_CHAM                        = HB_TAG ('C','h','a','m'),
+  /*5.1*/ HB_SCRIPT_KAYAH_LI                    = HB_TAG ('K','a','l','i'),
+  /*5.1*/ HB_SCRIPT_LEPCHA                      = HB_TAG ('L','e','p','c'),
+  /*5.1*/ HB_SCRIPT_LYCIAN                      = HB_TAG ('L','y','c','i'),
+  /*5.1*/ HB_SCRIPT_LYDIAN                      = HB_TAG ('L','y','d','i'),
+  /*5.1*/ HB_SCRIPT_OL_CHIKI                    = HB_TAG ('O','l','c','k'),
+  /*5.1*/ HB_SCRIPT_REJANG                      = HB_TAG ('R','j','n','g'),
+  /*5.1*/ HB_SCRIPT_SAURASHTRA                  = HB_TAG ('S','a','u','r'),
+  /*5.1*/ HB_SCRIPT_SUNDANESE                   = HB_TAG ('S','u','n','d'),
+  /*5.1*/ HB_SCRIPT_VAI                         = HB_TAG ('V','a','i','i'),
+
+  /*5.2*/ HB_SCRIPT_AVESTAN                     = HB_TAG ('A','v','s','t'),
+  /*5.2*/ HB_SCRIPT_BAMUM                       = HB_TAG ('B','a','m','u'),
+  /*5.2*/ HB_SCRIPT_EGYPTIAN_HIEROGLYPHS        = HB_TAG ('E','g','y','p'),
+  /*5.2*/ HB_SCRIPT_IMPERIAL_ARAMAIC            = HB_TAG ('A','r','m','i'),
+  /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PAHLAVI       = HB_TAG ('P','h','l','i'),
+  /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PARTHIAN      = HB_TAG ('P','r','t','i'),
+  /*5.2*/ HB_SCRIPT_JAVANESE                    = HB_TAG ('J','a','v','a'),
+  /*5.2*/ HB_SCRIPT_KAITHI                      = HB_TAG ('K','t','h','i'),
+  /*5.2*/ HB_SCRIPT_LISU                        = HB_TAG ('L','i','s','u'),
+  /*5.2*/ HB_SCRIPT_MEETEI_MAYEK                = HB_TAG ('M','t','e','i'),
+  /*5.2*/ HB_SCRIPT_OLD_SOUTH_ARABIAN           = HB_TAG ('S','a','r','b'),
+  /*5.2*/ HB_SCRIPT_OLD_TURKIC                  = HB_TAG ('O','r','k','h'),
+  /*5.2*/ HB_SCRIPT_SAMARITAN                   = HB_TAG ('S','a','m','r'),
+  /*5.2*/ HB_SCRIPT_TAI_THAM                    = HB_TAG ('L','a','n','a'),
+  /*5.2*/ HB_SCRIPT_TAI_VIET                    = HB_TAG ('T','a','v','t'),
+
+  /*6.0*/ HB_SCRIPT_BATAK                       = HB_TAG ('B','a','t','k'),
+  /*6.0*/ HB_SCRIPT_BRAHMI                      = HB_TAG ('B','r','a','h'),
+  /*6.0*/ HB_SCRIPT_MANDAIC                     = HB_TAG ('M','a','n','d'),
+
+  /*6.1*/ HB_SCRIPT_CHAKMA                      = HB_TAG ('C','a','k','m'),
+  /*6.1*/ HB_SCRIPT_MEROITIC_CURSIVE            = HB_TAG ('M','e','r','c'),
+  /*6.1*/ HB_SCRIPT_MEROITIC_HIEROGLYPHS        = HB_TAG ('M','e','r','o'),
+  /*6.1*/ HB_SCRIPT_MIAO                        = HB_TAG ('P','l','r','d'),
+  /*6.1*/ HB_SCRIPT_SHARADA                     = HB_TAG ('S','h','r','d'),
+  /*6.1*/ HB_SCRIPT_SORA_SOMPENG                = HB_TAG ('S','o','r','a'),
+  /*6.1*/ HB_SCRIPT_TAKRI                       = HB_TAG ('T','a','k','r'),
+
+  /*
+   * Since: 0.9.30
+   */
+  /*7.0*/ HB_SCRIPT_BASSA_VAH                   = HB_TAG ('B','a','s','s'),
+  /*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN          = HB_TAG ('A','g','h','b'),
+  /*7.0*/ HB_SCRIPT_DUPLOYAN                    = HB_TAG ('D','u','p','l'),
+  /*7.0*/ HB_SCRIPT_ELBASAN                     = HB_TAG ('E','l','b','a'),
+  /*7.0*/ HB_SCRIPT_GRANTHA                     = HB_TAG ('G','r','a','n'),
+  /*7.0*/ HB_SCRIPT_KHOJKI                      = HB_TAG ('K','h','o','j'),
+  /*7.0*/ HB_SCRIPT_KHUDAWADI                   = HB_TAG ('S','i','n','d'),
+  /*7.0*/ HB_SCRIPT_LINEAR_A                    = HB_TAG ('L','i','n','a'),
+  /*7.0*/ HB_SCRIPT_MAHAJANI                    = HB_TAG ('M','a','h','j'),
+  /*7.0*/ HB_SCRIPT_MANICHAEAN                  = HB_TAG ('M','a','n','i'),
+  /*7.0*/ HB_SCRIPT_MENDE_KIKAKUI               = HB_TAG ('M','e','n','d'),
+  /*7.0*/ HB_SCRIPT_MODI                        = HB_TAG ('M','o','d','i'),
+  /*7.0*/ HB_SCRIPT_MRO                         = HB_TAG ('M','r','o','o'),
+  /*7.0*/ HB_SCRIPT_NABATAEAN                   = HB_TAG ('N','b','a','t'),
+  /*7.0*/ HB_SCRIPT_OLD_NORTH_ARABIAN           = HB_TAG ('N','a','r','b'),
+  /*7.0*/ HB_SCRIPT_OLD_PERMIC                  = HB_TAG ('P','e','r','m'),
+  /*7.0*/ HB_SCRIPT_PAHAWH_HMONG                = HB_TAG ('H','m','n','g'),
+  /*7.0*/ HB_SCRIPT_PALMYRENE                   = HB_TAG ('P','a','l','m'),
+  /*7.0*/ HB_SCRIPT_PAU_CIN_HAU                 = HB_TAG ('P','a','u','c'),
+  /*7.0*/ HB_SCRIPT_PSALTER_PAHLAVI             = HB_TAG ('P','h','l','p'),
+  /*7.0*/ HB_SCRIPT_SIDDHAM                     = HB_TAG ('S','i','d','d'),
+  /*7.0*/ HB_SCRIPT_TIRHUTA                     = HB_TAG ('T','i','r','h'),
+  /*7.0*/ HB_SCRIPT_WARANG_CITI                 = HB_TAG ('W','a','r','a'),
+
+  /*8.0*/ HB_SCRIPT_AHOM                        = HB_TAG ('A','h','o','m'),
+  /*8.0*/ HB_SCRIPT_ANATOLIAN_HIEROGLYPHS       = HB_TAG ('H','l','u','w'),
+  /*8.0*/ HB_SCRIPT_HATRAN                      = HB_TAG ('H','a','t','r'),
+  /*8.0*/ HB_SCRIPT_MULTANI                     = HB_TAG ('M','u','l','t'),
+  /*8.0*/ HB_SCRIPT_OLD_HUNGARIAN               = HB_TAG ('H','u','n','g'),
+  /*8.0*/ HB_SCRIPT_SIGNWRITING                 = HB_TAG ('S','g','n','w'),
+
+  /* No script set. */
+  HB_SCRIPT_INVALID                             = HB_TAG_NONE,
+
+  /* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t
+   * without risking undefined behavior.  Include both a signed and unsigned max,
+   * since technically enums are int, and indeed, hb_script_t ends up being signed.
+   * See this thread for technicalities:
+   *
+   *   http://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html
+   */
+  _HB_SCRIPT_MAX_VALUE                          = HB_TAG_MAX, /*< skip >*/
+  _HB_SCRIPT_MAX_VALUE_SIGNED                   = HB_TAG_MAX_SIGNED /*< skip >*/
+
+} hb_script_t;
+
+
+/* Script functions */
+
+hb_script_t
+hb_script_from_iso15924_tag (hb_tag_t 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);
+
+hb_tag_t
+hb_script_to_iso15924_tag (hb_script_t script);
+
+hb_direction_t
+hb_script_get_horizontal_direction (hb_script_t script);
+
+
+/* User data */
+
+typedef struct hb_user_data_key_t {
+  /*< private >*/
+  char unused;
+} hb_user_data_key_t;
+
+typedef void (*hb_destroy_func_t) (void *user_data);
+
+
+HB_END_DECLS
+
+#endif /* HB_COMMON_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-coretext.cc	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,1219 @@
+/*
+ * Copyright © 2012,2013  Mozilla Foundation.
+ * Copyright © 2012,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.
+ *
+ * Mozilla Author(s): Jonathan Kew
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#define HB_SHAPER coretext
+#define hb_coretext_shaper_face_data_t CGFont
+#include "hb-shaper-impl-private.hh"
+
+#include "hb-coretext.h"
+
+
+#ifndef HB_DEBUG_CORETEXT
+#define HB_DEBUG_CORETEXT (HB_DEBUG+0)
+#endif
+
+
+static void
+release_table_data (void *user_data)
+{
+  CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
+  CFRelease(cf_data);
+}
+
+static hb_blob_t *
+reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+{
+  CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
+  CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
+  if (unlikely (!cf_data))
+    return NULL;
+
+  const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
+  const size_t length = CFDataGetLength (cf_data);
+  if (!data || !length)
+    return NULL;
+
+  return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
+                         reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
+                         release_table_data);
+}
+
+hb_face_t *
+hb_coretext_face_create (CGFontRef cg_font)
+{
+  return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), (hb_destroy_func_t) CGFontRelease);
+}
+
+
+HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face)
+HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
+
+
+/*
+ * shaper face data
+ */
+
+static void
+release_data (void *info, const void *data, size_t size)
+{
+  assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
+          hb_blob_get_data ((hb_blob_t *) info, NULL) == data);
+
+  hb_blob_destroy ((hb_blob_t *) info);
+}
+
+hb_coretext_shaper_face_data_t *
+_hb_coretext_shaper_face_data_create (hb_face_t *face)
+{
+  hb_coretext_shaper_face_data_t *data = NULL;
+
+  if (face->destroy == (hb_destroy_func_t) CGFontRelease)
+  {
+    data = CGFontRetain ((CGFontRef) face->user_data);
+  }
+  else
+  {
+    hb_blob_t *blob = hb_face_reference_blob (face);
+    unsigned int blob_length;
+    const char *blob_data = hb_blob_get_data (blob, &blob_length);
+    if (unlikely (!blob_length))
+      DEBUG_MSG (CORETEXT, face, "Face has empty blob");
+
+    CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
+    if (likely (provider))
+    {
+      data = CGFontCreateWithDataProvider (provider);
+      CGDataProviderRelease (provider);
+    }
+  }
+
+  if (unlikely (!data)) {
+    DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
+  }
+
+  return data;
+}
+
+void
+_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
+{
+  CFRelease (data);
+}
+
+/*
+ * Since: 0.9.10
+ */
+CGFontRef
+hb_coretext_face_get_cg_font (hb_face_t *face)
+{
+  if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
+  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+  return face_data;
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_coretext_shaper_font_data_t {
+  CTFontRef ct_font;
+  CGFloat x_mult, y_mult; /* From CT space to HB space. */
+};
+
+hb_coretext_shaper_font_data_t *
+_hb_coretext_shaper_font_data_create (hb_font_t *font)
+{
+  if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL;
+
+  hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t));
+  if (unlikely (!data))
+    return NULL;
+
+  hb_face_t *face = font->face;
+  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+
+  /* Choose a CoreText font size and calculate multipliers to convert to HarfBuzz space. */
+  /* TODO: use upem instead of 36? */
+  CGFloat font_size = 36.; /* Default... */
+  /* No idea if the following is even a good idea. */
+  if (font->y_ppem)
+    font_size = font->y_ppem;
+
+  if (font_size < 0)
+    font_size = -font_size;
+  data->x_mult = (CGFloat) font->x_scale / font_size;
+  data->y_mult = (CGFloat) font->y_scale / font_size;
+  data->ct_font = CTFontCreateWithGraphicsFont (face_data, font_size, NULL, NULL);
+  if (unlikely (!data->ct_font)) {
+    DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
+    free (data);
+    return NULL;
+  }
+
+  return data;
+}
+
+void
+_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
+{
+  CFRelease (data->ct_font);
+  free (data);
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_coretext_shaper_shape_plan_data_t {};
+
+hb_coretext_shaper_shape_plan_data_t *
+_hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
+                                             const hb_feature_t *user_features HB_UNUSED,
+                                             unsigned int        num_user_features HB_UNUSED)
+{
+  return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED)
+{
+}
+
+CTFontRef
+hb_coretext_font_get_ct_font (hb_font_t *font)
+{
+  if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL;
+  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+  return font_data->ct_font;
+}
+
+
+/*
+ * shaper
+ */
+
+struct feature_record_t {
+  unsigned int feature;
+  unsigned int setting;
+};
+
+struct active_feature_t {
+  feature_record_t rec;
+  unsigned int order;
+
+  static int cmp (const active_feature_t *a, const active_feature_t *b) {
+    return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
+           a->order < b->order ? -1 : a->order > b->order ? 1 :
+           a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 :
+           0;
+  }
+  bool operator== (const active_feature_t *f) {
+    return cmp (this, f) == 0;
+  }
+};
+
+struct feature_event_t {
+  unsigned int index;
+  bool start;
+  active_feature_t feature;
+
+  static int cmp (const feature_event_t *a, const feature_event_t *b) {
+    return a->index < b->index ? -1 : a->index > b->index ? 1 :
+           a->start < b->start ? -1 : a->start > b->start ? 1 :
+           active_feature_t::cmp (&a->feature, &b->feature);
+  }
+};
+
+struct range_record_t {
+  CTFontRef font;
+  unsigned int index_first; /* == start */
+  unsigned int index_last;  /* == end - 1 */
+};
+
+
+/* The following enum members are added in OS X 10.8. */
+#define kAltHalfWidthTextSelector               6
+#define kAltProportionalTextSelector            5
+#define kAlternateHorizKanaOffSelector          1
+#define kAlternateHorizKanaOnSelector           0
+#define kAlternateKanaType                      34
+#define kAlternateVertKanaOffSelector           3
+#define kAlternateVertKanaOnSelector            2
+#define kCaseSensitiveLayoutOffSelector         1
+#define kCaseSensitiveLayoutOnSelector          0
+#define kCaseSensitiveLayoutType                33
+#define kCaseSensitiveSpacingOffSelector        3
+#define kCaseSensitiveSpacingOnSelector         2
+#define kContextualAlternatesOffSelector        1
+#define kContextualAlternatesOnSelector         0
+#define kContextualAlternatesType               36
+#define kContextualLigaturesOffSelector         19
+#define kContextualLigaturesOnSelector          18
+#define kContextualSwashAlternatesOffSelector   5
+#define kContextualSwashAlternatesOnSelector    4
+#define kDefaultLowerCaseSelector               0
+#define kDefaultUpperCaseSelector               0
+#define kHistoricalLigaturesOffSelector         21
+#define kHistoricalLigaturesOnSelector          20
+#define kHojoCharactersSelector                 12
+#define kJIS2004CharactersSelector              11
+#define kLowerCasePetiteCapsSelector            2
+#define kLowerCaseSmallCapsSelector             1
+#define kLowerCaseType                          37
+#define kMathematicalGreekOffSelector           11
+#define kMathematicalGreekOnSelector            10
+#define kNLCCharactersSelector                  13
+#define kQuarterWidthTextSelector               4
+#define kScientificInferiorsSelector            4
+#define kStylisticAltEightOffSelector           17
+#define kStylisticAltEightOnSelector            16
+#define kStylisticAltEighteenOffSelector        37
+#define kStylisticAltEighteenOnSelector         36
+#define kStylisticAltElevenOffSelector          23
+#define kStylisticAltElevenOnSelector           22
+#define kStylisticAltFifteenOffSelector         31
+#define kStylisticAltFifteenOnSelector          30
+#define kStylisticAltFiveOffSelector            11
+#define kStylisticAltFiveOnSelector             10
+#define kStylisticAltFourOffSelector            9
+#define kStylisticAltFourOnSelector             8
+#define kStylisticAltFourteenOffSelector        29
+#define kStylisticAltFourteenOnSelector         28
+#define kStylisticAltNineOffSelector            19
+#define kStylisticAltNineOnSelector             18
+#define kStylisticAltNineteenOffSelector        39
+#define kStylisticAltNineteenOnSelector         38
+#define kStylisticAltOneOffSelector             3
+#define kStylisticAltOneOnSelector              2
+#define kStylisticAltSevenOffSelector           15
+#define kStylisticAltSevenOnSelector            14
+#define kStylisticAltSeventeenOffSelector       35
+#define kStylisticAltSeventeenOnSelector        34
+#define kStylisticAltSixOffSelector             13
+#define kStylisticAltSixOnSelector              12
+#define kStylisticAltSixteenOffSelector         33
+#define kStylisticAltSixteenOnSelector          32
+#define kStylisticAltTenOffSelector             21
+#define kStylisticAltTenOnSelector              20
+#define kStylisticAltThirteenOffSelector        27
+#define kStylisticAltThirteenOnSelector         26
+#define kStylisticAltThreeOffSelector           7
+#define kStylisticAltThreeOnSelector            6
+#define kStylisticAltTwelveOffSelector          25
+#define kStylisticAltTwelveOnSelector           24
+#define kStylisticAltTwentyOffSelector          41
+#define kStylisticAltTwentyOnSelector           40
+#define kStylisticAltTwoOffSelector             5
+#define kStylisticAltTwoOnSelector              4
+#define kStylisticAlternativesType              35
+#define kSwashAlternatesOffSelector             3
+#define kSwashAlternatesOnSelector              2
+#define kThirdWidthTextSelector                 3
+#define kTraditionalNamesCharactersSelector     14
+#define kUpperCasePetiteCapsSelector            2
+#define kUpperCaseSmallCapsSelector             1
+#define kUpperCaseType                          38
+
+/* Table data courtesy of Apple. */
+static const struct feature_mapping_t {
+    FourCharCode otFeatureTag;
+    uint16_t aatFeatureType;
+    uint16_t selectorToEnable;
+    uint16_t selectorToDisable;
+} feature_mappings[] = {
+    { 'c2pc',   kUpperCaseType,             kUpperCasePetiteCapsSelector,           kDefaultUpperCaseSelector },
+    { 'c2sc',   kUpperCaseType,             kUpperCaseSmallCapsSelector,            kDefaultUpperCaseSelector },
+    { 'calt',   kContextualAlternatesType,  kContextualAlternatesOnSelector,        kContextualAlternatesOffSelector },
+    { 'case',   kCaseSensitiveLayoutType,   kCaseSensitiveLayoutOnSelector,         kCaseSensitiveLayoutOffSelector },
+    { 'clig',   kLigaturesType,             kContextualLigaturesOnSelector,         kContextualLigaturesOffSelector },
+    { 'cpsp',   kCaseSensitiveLayoutType,   kCaseSensitiveSpacingOnSelector,        kCaseSensitiveSpacingOffSelector },
+    { 'cswh',   kContextualAlternatesType,  kContextualSwashAlternatesOnSelector,   kContextualSwashAlternatesOffSelector },
+    { 'dlig',   kLigaturesType,             kRareLigaturesOnSelector,               kRareLigaturesOffSelector },
+    { 'expt',   kCharacterShapeType,        kExpertCharactersSelector,              16 },
+    { 'frac',   kFractionsType,             kDiagonalFractionsSelector,             kNoFractionsSelector },
+    { 'fwid',   kTextSpacingType,           kMonospacedTextSelector,                7 },
+    { 'halt',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
+    { 'hist',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
+    { 'hkna',   kAlternateKanaType,         kAlternateHorizKanaOnSelector,          kAlternateHorizKanaOffSelector, },
+    { 'hlig',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
+    { 'hngl',   kTransliterationType,       kHanjaToHangulSelector,                 kNoTransliterationSelector },
+    { 'hojo',   kCharacterShapeType,        kHojoCharactersSelector,                16 },
+    { 'hwid',   kTextSpacingType,           kHalfWidthTextSelector,                 7 },
+    { 'ital',   kItalicCJKRomanType,        kCJKItalicRomanOnSelector,              kCJKItalicRomanOffSelector },
+    { 'jp04',   kCharacterShapeType,        kJIS2004CharactersSelector,             16 },
+    { 'jp78',   kCharacterShapeType,        kJIS1978CharactersSelector,             16 },
+    { 'jp83',   kCharacterShapeType,        kJIS1983CharactersSelector,             16 },
+    { 'jp90',   kCharacterShapeType,        kJIS1990CharactersSelector,             16 },
+    { 'liga',   kLigaturesType,             kCommonLigaturesOnSelector,             kCommonLigaturesOffSelector },
+    { 'lnum',   kNumberCaseType,            kUpperCaseNumbersSelector,              2 },
+    { 'mgrk',   kMathematicalExtrasType,    kMathematicalGreekOnSelector,           kMathematicalGreekOffSelector },
+    { 'nlck',   kCharacterShapeType,        kNLCCharactersSelector,                 16 },
+    { 'onum',   kNumberCaseType,            kLowerCaseNumbersSelector,              2 },
+    { 'ordn',   kVerticalPositionType,      kOrdinalsSelector,                      kNormalPositionSelector },
+    { 'palt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
+    { 'pcap',   kLowerCaseType,             kLowerCasePetiteCapsSelector,           kDefaultLowerCaseSelector },
+    { 'pkna',   kTextSpacingType,           kProportionalTextSelector,              7 },
+    { 'pnum',   kNumberSpacingType,         kProportionalNumbersSelector,           4 },
+    { 'pwid',   kTextSpacingType,           kProportionalTextSelector,              7 },
+    { 'qwid',   kTextSpacingType,           kQuarterWidthTextSelector,              7 },
+    { 'ruby',   kRubyKanaType,              kRubyKanaOnSelector,                    kRubyKanaOffSelector },
+    { 'sinf',   kVerticalPositionType,      kScientificInferiorsSelector,           kNormalPositionSelector },
+    { 'smcp',   kLowerCaseType,             kLowerCaseSmallCapsSelector,            kDefaultLowerCaseSelector },
+    { 'smpl',   kCharacterShapeType,        kSimplifiedCharactersSelector,          16 },
+    { 'ss01',   kStylisticAlternativesType, kStylisticAltOneOnSelector,             kStylisticAltOneOffSelector },
+    { 'ss02',   kStylisticAlternativesType, kStylisticAltTwoOnSelector,             kStylisticAltTwoOffSelector },
+    { 'ss03',   kStylisticAlternativesType, kStylisticAltThreeOnSelector,           kStylisticAltThreeOffSelector },
+    { 'ss04',   kStylisticAlternativesType, kStylisticAltFourOnSelector,            kStylisticAltFourOffSelector },
+    { 'ss05',   kStylisticAlternativesType, kStylisticAltFiveOnSelector,            kStylisticAltFiveOffSelector },
+    { 'ss06',   kStylisticAlternativesType, kStylisticAltSixOnSelector,             kStylisticAltSixOffSelector },
+    { 'ss07',   kStylisticAlternativesType, kStylisticAltSevenOnSelector,           kStylisticAltSevenOffSelector },
+    { 'ss08',   kStylisticAlternativesType, kStylisticAltEightOnSelector,           kStylisticAltEightOffSelector },
+    { 'ss09',   kStylisticAlternativesType, kStylisticAltNineOnSelector,            kStylisticAltNineOffSelector },
+    { 'ss10',   kStylisticAlternativesType, kStylisticAltTenOnSelector,             kStylisticAltTenOffSelector },
+    { 'ss11',   kStylisticAlternativesType, kStylisticAltElevenOnSelector,          kStylisticAltElevenOffSelector },
+    { 'ss12',   kStylisticAlternativesType, kStylisticAltTwelveOnSelector,          kStylisticAltTwelveOffSelector },
+    { 'ss13',   kStylisticAlternativesType, kStylisticAltThirteenOnSelector,        kStylisticAltThirteenOffSelector },
+    { 'ss14',   kStylisticAlternativesType, kStylisticAltFourteenOnSelector,        kStylisticAltFourteenOffSelector },
+    { 'ss15',   kStylisticAlternativesType, kStylisticAltFifteenOnSelector,         kStylisticAltFifteenOffSelector },
+    { 'ss16',   kStylisticAlternativesType, kStylisticAltSixteenOnSelector,         kStylisticAltSixteenOffSelector },
+    { 'ss17',   kStylisticAlternativesType, kStylisticAltSeventeenOnSelector,       kStylisticAltSeventeenOffSelector },
+    { 'ss18',   kStylisticAlternativesType, kStylisticAltEighteenOnSelector,        kStylisticAltEighteenOffSelector },
+    { 'ss19',   kStylisticAlternativesType, kStylisticAltNineteenOnSelector,        kStylisticAltNineteenOffSelector },
+    { 'ss20',   kStylisticAlternativesType, kStylisticAltTwentyOnSelector,          kStylisticAltTwentyOffSelector },
+    { 'subs',   kVerticalPositionType,      kInferiorsSelector,                     kNormalPositionSelector },
+    { 'sups',   kVerticalPositionType,      kSuperiorsSelector,                     kNormalPositionSelector },
+    { 'swsh',   kContextualAlternatesType,  kSwashAlternatesOnSelector,             kSwashAlternatesOffSelector },
+    { 'titl',   kStyleOptionsType,          kTitlingCapsSelector,                   kNoStyleOptionsSelector },
+    { 'tnam',   kCharacterShapeType,        kTraditionalNamesCharactersSelector,    16 },
+    { 'tnum',   kNumberSpacingType,         kMonospacedNumbersSelector,             4 },
+    { 'trad',   kCharacterShapeType,        kTraditionalCharactersSelector,         16 },
+    { 'twid',   kTextSpacingType,           kThirdWidthTextSelector,                7 },
+    { 'unic',   kLetterCaseType,            14,                                     15 },
+    { 'valt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
+    { 'vert',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
+    { 'vhal',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
+    { 'vkna',   kAlternateKanaType,         kAlternateVertKanaOnSelector,           kAlternateVertKanaOffSelector },
+    { 'vpal',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
+    { 'vrt2',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
+    { 'zero',   kTypographicExtrasType,     kSlashedZeroOnSelector,                 kSlashedZeroOffSelector },
+};
+
+static int
+_hb_feature_mapping_cmp (const void *key_, const void *entry_)
+{
+  unsigned int key = * (unsigned int *) key_;
+  const feature_mapping_t * entry = (const feature_mapping_t *) entry_;
+  return key < entry->otFeatureTag ? -1 :
+         key > entry->otFeatureTag ? 1 :
+         0;
+}
+
+hb_bool_t
+_hb_coretext_shape (hb_shape_plan_t    *shape_plan,
+                    hb_font_t          *font,
+                    hb_buffer_t        *buffer,
+                    const hb_feature_t *features,
+                    unsigned int        num_features)
+{
+  hb_face_t *face = font->face;
+  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+
+  /* Attach marks to their bases, to match the 'ot' shaper.
+   * Adapted from hb-ot-shape:hb_form_clusters().
+   * Note that this only makes us be closer to the 'ot' shaper,
+   * but by no means the same.  For example, if there's
+   * B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
+   * continue pointing to B2 even though B2 was merged into B1's
+   * cluster... */
+  {
+    hb_unicode_funcs_t *unicode = buffer->unicode;
+    unsigned int count = buffer->len;
+    hb_glyph_info_t *info = buffer->info;
+    for (unsigned int i = 1; i < count; i++)
+      if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (info[i].codepoint)))
+        buffer->merge_clusters (i - 1, i + 1);
+  }
+
+  hb_auto_array_t<feature_record_t> feature_records;
+  hb_auto_array_t<range_record_t> range_records;
+
+  /*
+   * Set up features.
+   * (copied + modified from code from hb-uniscribe.cc)
+   */
+  if (num_features)
+  {
+    /* Sort features by start/end events. */
+    hb_auto_array_t<feature_event_t> feature_events;
+    for (unsigned int i = 0; i < num_features; i++)
+    {
+      const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag,
+                                                                               feature_mappings,
+                                                                               ARRAY_LENGTH (feature_mappings),
+                                                                               sizeof (feature_mappings[0]),
+                                                                               _hb_feature_mapping_cmp);
+      if (!mapping)
+        continue;
+
+      active_feature_t feature;
+      feature.rec.feature = mapping->aatFeatureType;
+      feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable;
+      feature.order = i;
+
+      feature_event_t *event;
+
+      event = feature_events.push ();
+      if (unlikely (!event))
+        goto fail_features;
+      event->index = features[i].start;
+      event->start = true;
+      event->feature = feature;
+
+      event = feature_events.push ();
+      if (unlikely (!event))
+        goto fail_features;
+      event->index = features[i].end;
+      event->start = false;
+      event->feature = feature;
+    }
+    feature_events.qsort ();
+    /* Add a strategic final event. */
+    {
+      active_feature_t feature;
+      feature.rec.feature = HB_TAG_NONE;
+      feature.rec.setting = 0;
+      feature.order = num_features + 1;
+
+      feature_event_t *event = feature_events.push ();
+      if (unlikely (!event))
+        goto fail_features;
+      event->index = 0; /* This value does magic. */
+      event->start = false;
+      event->feature = feature;
+    }
+
+    /* Scan events and save features for each range. */
+    hb_auto_array_t<active_feature_t> active_features;
+    unsigned int last_index = 0;
+    for (unsigned int i = 0; i < feature_events.len; i++)
+    {
+      feature_event_t *event = &feature_events[i];
+
+      if (event->index != last_index)
+      {
+        /* Save a snapshot of active features and the range. */
+        range_record_t *range = range_records.push ();
+        if (unlikely (!range))
+          goto fail_features;
+
+        if (active_features.len)
+        {
+          CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+
+          /* TODO sort and resolve conflicting features? */
+          /* active_features.qsort (); */
+          for (unsigned int j = 0; j < active_features.len; j++)
+          {
+            CFStringRef keys[2] = {
+              kCTFontFeatureTypeIdentifierKey,
+              kCTFontFeatureSelectorIdentifierKey
+            };
+            CFNumberRef values[2] = {
+              CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
+              CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
+            };
+            CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
+                                                       (const void **) keys,
+                                                       (const void **) values,
+                                                       2,
+                                                       &kCFTypeDictionaryKeyCallBacks,
+                                                       &kCFTypeDictionaryValueCallBacks);
+            CFRelease (values[0]);
+            CFRelease (values[1]);
+
+            CFArrayAppendValue (features_array, dict);
+            CFRelease (dict);
+
+          }
+
+          CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
+                                                           (const void **) &kCTFontFeatureSettingsAttribute,
+                                                           (const void **) &features_array,
+                                                           1,
+                                                           &kCFTypeDictionaryKeyCallBacks,
+                                                           &kCFTypeDictionaryValueCallBacks);
+          CFRelease (features_array);
+
+          CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
+          CFRelease (attributes);
+
+          range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc);
+          CFRelease (font_desc);
+        }
+        else
+        {
+          range->font = NULL;
+        }
+
+        range->index_first = last_index;
+        range->index_last  = event->index - 1;
+
+        last_index = event->index;
+      }
+
+      if (event->start) {
+        active_feature_t *feature = active_features.push ();
+        if (unlikely (!feature))
+          goto fail_features;
+        *feature = event->feature;
+      } else {
+        active_feature_t *feature = active_features.find (&event->feature);
+        if (feature)
+          active_features.remove (feature - active_features.array);
+      }
+    }
+
+    if (!range_records.len) /* No active feature found. */
+      goto fail_features;
+  }
+  else
+  {
+  fail_features:
+    num_features = 0;
+  }
+
+  unsigned int scratch_size;
+  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
+
+#define ALLOCATE_ARRAY(Type, name, len, on_no_room) \
+  Type *name = (Type *) scratch; \
+  { \
+    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
+    if (unlikely (_consumed > scratch_size)) \
+    { \
+      on_no_room; \
+      assert (0); \
+    } \
+    scratch += _consumed; \
+    scratch_size -= _consumed; \
+  }
+
+  ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/);
+  unsigned int chars_len = 0;
+  for (unsigned int i = 0; i < buffer->len; i++) {
+    hb_codepoint_t c = buffer->info[i].codepoint;
+    if (likely (c <= 0xFFFFu))
+      pchars[chars_len++] = c;
+    else if (unlikely (c > 0x10FFFFu))
+      pchars[chars_len++] = 0xFFFDu;
+    else {
+      pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
+      pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
+    }
+  }
+
+  ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, /*nothing*/);
+  chars_len = 0;
+  for (unsigned int i = 0; i < buffer->len; i++)
+  {
+    hb_codepoint_t c = buffer->info[i].codepoint;
+    unsigned int cluster = buffer->info[i].cluster;
+    log_clusters[chars_len++] = cluster;
+    if (hb_in_range (c, 0x10000u, 0x10FFFFu))
+      log_clusters[chars_len++] = cluster; /* Surrogates. */
+  }
+
+#define FAIL(...) \
+  HB_STMT_START { \
+    DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
+    ret = false; \
+    goto fail; \
+  } HB_STMT_END;
+
+  bool ret = true;
+  CFStringRef string_ref = NULL;
+  CTLineRef line = NULL;
+
+  if (0)
+  {
+resize_and_retry:
+    DEBUG_MSG (CORETEXT, buffer, "Buffer resize");
+    /* string_ref uses the scratch-buffer for backing store, and line references
+     * string_ref (via attr_string).  We must release those before resizing buffer. */
+    assert (string_ref);
+    assert (line);
+    CFRelease (string_ref);
+    CFRelease (line);
+    string_ref = NULL;
+    line = NULL;
+
+    /* Get previous start-of-scratch-area, that we use later for readjusting
+     * our existing scratch arrays. */
+    unsigned int old_scratch_used;
+    hb_buffer_t::scratch_buffer_t *old_scratch;
+    old_scratch = buffer->get_scratch_buffer (&old_scratch_used);
+    old_scratch_used = scratch - old_scratch;
+
+    if (unlikely (!buffer->ensure (buffer->allocated * 2)))
+      FAIL ("Buffer resize failed");
+
+    /* Adjust scratch, pchars, and log_cluster arrays.  This is ugly, but really the
+     * cleanest way to do without completely restructuring the rest of this shaper. */
+    scratch = buffer->get_scratch_buffer (&scratch_size);
+    pchars = reinterpret_cast<UniChar *> (((char *) scratch + ((char *) pchars - (char *) old_scratch)));
+    log_clusters = reinterpret_cast<unsigned int *> (((char *) scratch + ((char *) log_clusters - (char *) old_scratch)));
+    scratch += old_scratch_used;
+    scratch_size -= old_scratch_used;
+  }
+retry:
+  {
+    string_ref = CFStringCreateWithCharactersNoCopy (NULL,
+                                                     pchars, chars_len,
+                                                     kCFAllocatorNull);
+    if (unlikely (!string_ref))
+      FAIL ("CFStringCreateWithCharactersNoCopy failed");
+
+    /* Create an attributed string, populate it, and create a line from it, then release attributed string. */
+    {
+      CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (kCFAllocatorDefault,
+                                                                                  chars_len);
+      if (unlikely (!attr_string))
+        FAIL ("CFAttributedStringCreateMutable failed");
+      CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref);
+      if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
+      {
+        CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
+                                        kCTVerticalFormsAttributeName, kCFBooleanTrue);
+      }
+
+      if (buffer->props.language)
+      {
+/* What's the iOS equivalent of this check?
+ * The symbols was introduced in iOS 7.0.
+ * At any rate, our fallback is safe and works fine. */
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
+#  define kCTLanguageAttributeName CFSTR ("NSLanguage")
+#endif
+        CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault,
+                                                            hb_language_to_string (buffer->props.language),
+                                                            kCFStringEncodingUTF8,
+                                                            kCFAllocatorNull);
+        if (unlikely (!lang))
+          FAIL ("CFStringCreateWithCStringNoCopy failed");
+        CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
+                                        kCTLanguageAttributeName, lang);
+        CFRelease (lang);
+      }
+      CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
+                                      kCTFontAttributeName, font_data->ct_font);
+
+      if (num_features)
+      {
+        unsigned int start = 0;
+        range_record_t *last_range = &range_records[0];
+        for (unsigned int k = 0; k < chars_len; k++)
+        {
+          range_record_t *range = last_range;
+          while (log_clusters[k] < range->index_first)
+            range--;
+          while (log_clusters[k] > range->index_last)
+            range++;
+          if (range != last_range)
+          {
+            if (last_range->font)
+              CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start),
+                                              kCTFontAttributeName, last_range->font);
+
+            start = k;
+          }
+
+          last_range = range;
+        }
+        if (start != chars_len && last_range->font)
+          CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start),
+                                          kCTFontAttributeName, last_range->font);
+      }
+
+      int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
+      CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
+      CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault,
+                                                    (const void **) &kCTTypesetterOptionForcedEmbeddingLevel,
+                                                    (const void **) &level_number,
+                                                    1,
+                                                    &kCFTypeDictionaryKeyCallBacks,
+                                                    &kCFTypeDictionaryValueCallBacks);
+      if (unlikely (!options))
+        FAIL ("CFDictionaryCreate failed");
+
+      CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedStringAndOptions (attr_string, options);
+      CFRelease (options);
+      CFRelease (attr_string);
+      if (unlikely (!typesetter))
+        FAIL ("CTTypesetterCreateWithAttributedStringAndOptions failed");
+
+      line = CTTypesetterCreateLine (typesetter, CFRangeMake(0, 0));
+      CFRelease (typesetter);
+      if (unlikely (!line))
+        FAIL ("CTTypesetterCreateLine failed");
+    }
+
+    CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
+    unsigned int num_runs = CFArrayGetCount (glyph_runs);
+    DEBUG_MSG (CORETEXT, NULL, "Num runs: %d", num_runs);
+
+    buffer->len = 0;
+    uint32_t status_and = ~0, status_or = 0;
+    double advances_so_far = 0;
+    /* For right-to-left runs, CoreText returns the glyphs positioned such that
+     * any trailing whitespace is to the left of (0,0).  Adjust coordinate system
+     * to fix for that.  Test with any RTL string with trailing spaces.
+     * https://code.google.com/p/chromium/issues/detail?id=469028
+     */
+    if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+    {
+      advances_so_far -= CTLineGetTrailingWhitespaceWidth (line);
+      if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
+          advances_so_far = -advances_so_far;
+    }
+
+    const CFRange range_all = CFRangeMake (0, 0);
+
+    for (unsigned int i = 0; i < num_runs; i++)
+    {
+      CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i));
+      CTRunStatus run_status = CTRunGetStatus (run);
+      status_or  |= run_status;
+      status_and &= run_status;
+      DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
+      double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
+      if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
+          run_advance = -run_advance;
+      DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
+
+      /* CoreText does automatic font fallback (AKA "cascading") for  characters
+       * not supported by the requested font, and provides no way to turn it off,
+       * so we must detect if the returned run uses a font other than the requested
+       * one and fill in the buffer with .notdef glyphs instead of random glyph
+       * indices from a different font.
+       */
+      CFDictionaryRef attributes = CTRunGetAttributes (run);
+      CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
+      if (!CFEqual (run_ct_font, font_data->ct_font))
+      {
+        /* The run doesn't use our main font instance.  We have to figure out
+         * whether font fallback happened, or this is just CoreText giving us
+         * another CTFont using the same underlying CGFont.  CoreText seems
+         * to do that in a variety of situations, one of which being vertical
+         * text, but also perhaps for caching reasons.
+         *
+         * First, see if it uses any of our subfonts created to set font features...
+         *
+         * Next, compare the CGFont to the one we used to create our fonts.
+         * Even this doesn't work all the time.
+         *
+         * Finally, we compare PS names, which I don't think are unique...
+         *
+         * Looks like if we really want to be sure here we have to modify the
+         * font to change the name table, similar to what we do in the uniscribe
+         * backend.
+         *
+         * However, even that wouldn't work if we were passed in the CGFont to
+         * begin with.
+         *
+         * Webkit uses a slightly different approach: it installs LastResort
+         * as fallback chain, and then checks PS name of used font against
+         * LastResort.  That one is safe for any font except for LastResort,
+         * as opposed to ours, which can fail if we are using any uninstalled
+         * font that has the same name as an installed font.
+         *
+         * See: http://github.com/behdad/harfbuzz/pull/36
+         */
+        bool matched = false;
+        for (unsigned int i = 0; i < range_records.len; i++)
+          if (range_records[i].font && CFEqual (run_ct_font, range_records[i].font))
+          {
+            matched = true;
+            break;
+          }
+        if (!matched)
+        {
+          CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
+          if (run_cg_font)
+          {
+            matched = CFEqual (run_cg_font, face_data);
+            CFRelease (run_cg_font);
+          }
+        }
+        if (!matched)
+        {
+          CFStringRef font_ps_name = CTFontCopyName (font_data->ct_font, kCTFontPostScriptNameKey);
+          CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey);
+          CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0);
+          CFRelease (run_ps_name);
+          CFRelease (font_ps_name);
+          if (result == kCFCompareEqualTo)
+            matched = true;
+        }
+        if (!matched)
+        {
+          CFRange range = CTRunGetStringRange (run);
+          DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld",
+                     range.location, range.location + range.length);
+          if (!buffer->ensure_inplace (buffer->len + range.length))
+            goto resize_and_retry;
+          hb_glyph_info_t *info = buffer->info + buffer->len;
+
+          hb_codepoint_t notdef = 0;
+          hb_direction_t dir = buffer->props.direction;
+          hb_position_t x_advance, y_advance, x_offset, y_offset;
+          hb_font_get_glyph_advance_for_direction (font, notdef, dir, &x_advance, &y_advance);
+          hb_font_get_glyph_origin_for_direction (font, notdef, dir, &x_offset, &y_offset);
+          hb_position_t advance = x_advance + y_advance;
+          x_offset = -x_offset;
+          y_offset = -y_offset;
+
+          unsigned int old_len = buffer->len;
+          for (CFIndex j = range.location; j < range.location + range.length; j++)
+          {
+              UniChar ch = CFStringGetCharacterAtIndex (string_ref, j);
+              if (hb_in_range<UniChar> (ch, 0xDC00u, 0xDFFFu) && range.location < j)
+              {
+                ch = CFStringGetCharacterAtIndex (string_ref, j - 1);
+                if (hb_in_range<UniChar> (ch, 0xD800u, 0xDBFFu))
+                  /* This is the second of a surrogate pair.  Don't need .notdef
+                   * for this one. */
+                  continue;
+              }
+              if (buffer->unicode->is_default_ignorable (ch))
+                continue;
+
+              info->codepoint = notdef;
+              info->cluster = log_clusters[j];
+
+              info->mask = advance;
+              info->var1.i32 = x_offset;
+              info->var2.i32 = y_offset;
+
+              info++;
+              buffer->len++;
+          }
+          if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+            buffer->reverse_range (old_len, buffer->len);
+          advances_so_far += run_advance;
+          continue;
+        }
+      }
+
+      unsigned int num_glyphs = CTRunGetGlyphCount (run);
+      if (num_glyphs == 0)
+        continue;
+
+      if (!buffer->ensure_inplace (buffer->len + num_glyphs))
+        goto resize_and_retry;
+
+      hb_glyph_info_t *run_info = buffer->info + buffer->len;
+
+      /* Testing used to indicate that CTRunGetGlyphsPtr, etc (almost?) always
+       * succeed, and so copying data to our own buffer will be rare.  Reports
+       * have it that this changed in OS X 10.10 Yosemite, and NULL is returned
+       * frequently.  At any rate, we can test that codepath by setting USE_PTR
+       * to false. */
+
+#define USE_PTR true
+
+#define SCRATCH_SAVE() \
+  unsigned int scratch_size_saved = scratch_size; \
+  hb_buffer_t::scratch_buffer_t *scratch_saved = scratch
+
+#define SCRATCH_RESTORE() \
+  scratch_size = scratch_size_saved; \
+  scratch = scratch_saved;
+
+      { /* Setup glyphs */
+        SCRATCH_SAVE();
+        const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : NULL;
+        if (!glyphs) {
+          ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry);
+          CTRunGetGlyphs (run, range_all, glyph_buf);
+          glyphs = glyph_buf;
+        }
+        const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : NULL;
+        if (!string_indices) {
+          ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs, goto resize_and_retry);
+          CTRunGetStringIndices (run, range_all, index_buf);
+          string_indices = index_buf;
+        }
+        hb_glyph_info_t *info = run_info;
+        for (unsigned int j = 0; j < num_glyphs; j++)
+        {
+          info->codepoint = glyphs[j];
+          info->cluster = log_clusters[string_indices[j]];
+          info++;
+        }
+        SCRATCH_RESTORE();
+      }
+      {
+        /* Setup positions.
+         * Note that CoreText does not return advances for glyphs.  As such,
+         * for all but last glyph, we use the delta position to next glyph as
+         * advance (in the advance direction only), and for last glyph we set
+         * whatever is needed to make the whole run's advance add up. */
+        SCRATCH_SAVE();
+        const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL;
+        if (!positions) {
+          ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_retry);
+          CTRunGetPositions (run, range_all, position_buf);
+          positions = position_buf;
+        }
+        hb_glyph_info_t *info = run_info;
+        CGFloat x_mult = font_data->x_mult, y_mult = font_data->y_mult;
+        if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+        {
+          hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult;
+          for (unsigned int j = 0; j < num_glyphs; j++)
+          {
+            double advance;
+            if (likely (j + 1 < num_glyphs))
+              advance = positions[j + 1].x - positions[j].x;
+            else /* last glyph */
+              advance = run_advance - (positions[j].x - positions[0].x);
+            info->mask = advance * x_mult;
+            info->var1.i32 = x_offset;
+            info->var2.i32 = positions[j].y * y_mult;
+            info++;
+          }
+        }
+        else
+        {
+          hb_position_t y_offset = (positions[0].y - advances_so_far) * y_mult;
+          for (unsigned int j = 0; j < num_glyphs; j++)
+          {
+            double advance;
+            if (likely (j + 1 < num_glyphs))
+              advance = positions[j + 1].y - positions[j].y;
+            else /* last glyph */
+              advance = run_advance - (positions[j].y - positions[0].y);
+            info->mask = advance * y_mult;
+            info->var1.i32 = positions[j].x * x_mult;
+            info->var2.i32 = y_offset;
+            info++;
+          }
+        }
+        SCRATCH_RESTORE();
+        advances_so_far += run_advance;
+      }
+#undef SCRATCH_RESTORE
+#undef SCRATCH_SAVE
+#undef USE_PTR
+#undef ALLOCATE_ARRAY
+
+      buffer->len += num_glyphs;
+    }
+
+    /* Mac OS 10.6 doesn't have kCTTypesetterOptionForcedEmbeddingLevel,
+     * or if it does, it doesn't resepct it.  So we get runs with wrong
+     * directions.  As such, disable the assert...  It wouldn't crash, but
+     * cursoring will be off...
+     *
+     * http://crbug.com/419769
+     */
+    if (0)
+    {
+      /* Make sure all runs had the expected direction. */
+      bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
+      assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
+      assert (bool (status_or  & kCTRunStatusRightToLeft) == backward);
+    }
+
+    buffer->clear_positions ();
+
+    unsigned int count = buffer->len;
+    hb_glyph_info_t *info = buffer->info;
+    hb_glyph_position_t *pos = buffer->pos;
+    if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+      for (unsigned int i = 0; i < count; i++)
+      {
+        pos->x_advance = info->mask;
+        pos->x_offset = info->var1.i32;
+        pos->y_offset = info->var2.i32;
+        info++, pos++;
+      }
+    else
+      for (unsigned int i = 0; i < count; i++)
+      {
+        pos->y_advance = info->mask;
+        pos->x_offset = info->var1.i32;
+        pos->y_offset = info->var2.i32;
+        info++, pos++;
+      }
+
+    /* Fix up clusters so that we never return out-of-order indices;
+     * if core text has reordered glyphs, we'll merge them to the
+     * beginning of the reordered cluster.  CoreText is nice enough
+     * to tell us whenever it has produced nonmonotonic results...
+     * Note that we assume the input clusters were nonmonotonic to
+     * begin with.
+     *
+     * This does *not* mean we'll form the same clusters as Uniscribe
+     * or the native OT backend, only that the cluster indices will be
+     * monotonic in the output buffer. */
+    if (count > 1 && (status_or & kCTRunStatusNonMonotonic))
+    {
+      hb_glyph_info_t *info = buffer->info;
+      if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))
+      {
+        unsigned int cluster = info[count - 1].cluster;
+        for (unsigned int i = count - 1; i > 0; i--)
+        {
+          cluster = MIN (cluster, info[i - 1].cluster);
+          info[i - 1].cluster = cluster;
+        }
+      }
+      else
+      {
+        unsigned int cluster = info[0].cluster;
+        for (unsigned int i = 1; i < count; i++)
+        {
+          cluster = MIN (cluster, info[i].cluster);
+          info[i].cluster = cluster;
+        }
+      }
+    }
+  }
+
+#undef FAIL
+
+fail:
+  if (string_ref)
+    CFRelease (string_ref);
+  if (line)
+    CFRelease (line);
+
+  for (unsigned int i = 0; i < range_records.len; i++)
+    if (range_records[i].font)
+      CFRelease (range_records[i].font);
+
+  return ret;
+}
+
+
+/*
+ * AAT shaper
+ */
+
+HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face)
+HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font)
+
+
+/*
+ * shaper face data
+ */
+
+struct hb_coretext_aat_shaper_face_data_t {};
+
+hb_coretext_aat_shaper_face_data_t *
+_hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
+{
+  hb_blob_t *mort_blob = face->reference_table (HB_CORETEXT_TAG_MORT);
+  /* Umm, we just reference the table to check whether it exists.
+   * Maybe add better API for this? */
+  if (!hb_blob_get_length (mort_blob))
+  {
+    hb_blob_destroy (mort_blob);
+    mort_blob = face->reference_table (HB_CORETEXT_TAG_MORX);
+    if (!hb_blob_get_length (mort_blob))
+    {
+      hb_blob_destroy (mort_blob);
+      return NULL;
+    }
+  }
+  hb_blob_destroy (mort_blob);
+
+  return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
+}
+
+void
+_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_coretext_aat_shaper_font_data_t {};
+
+hb_coretext_aat_shaper_font_data_t *
+_hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
+{
+  return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
+}
+
+void
+_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_coretext_aat_shaper_shape_plan_data_t {};
+
+hb_coretext_aat_shaper_shape_plan_data_t *
+_hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
+                                             const hb_feature_t *user_features HB_UNUSED,
+                                             unsigned int        num_user_features HB_UNUSED)
+{
+  return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_plan_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper
+ */
+
+hb_bool_t
+_hb_coretext_aat_shape (hb_shape_plan_t    *shape_plan,
+                        hb_font_t          *font,
+                        hb_buffer_t        *buffer,
+                        const hb_feature_t *features,
+                        unsigned int        num_features)
+{
+  return _hb_coretext_shape (shape_plan, font, buffer, features, num_features);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-coretext.h	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 2012  Mozilla Foundation.
+ *
+ *  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.
+ *
+ * Mozilla Author(s): Jonathan Kew
+ */
+
+#ifndef HB_CORETEXT_H
+#define HB_CORETEXT_H
+
+#include "hb.h"
+
+#include <TargetConditionals.h>
+#if TARGET_OS_IPHONE
+#  include <CoreText/CoreText.h>
+#  include <CoreGraphics/CoreGraphics.h>
+#else
+#  include <ApplicationServices/ApplicationServices.h>
+#endif
+
+HB_BEGIN_DECLS
+
+
+#define HB_CORETEXT_TAG_MORT HB_TAG('m','o','r','t')
+#define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x')
+
+
+hb_face_t *
+hb_coretext_face_create (CGFontRef cg_font);
+
+
+CGFontRef
+hb_coretext_face_get_cg_font (hb_face_t *face);
+
+CTFontRef
+hb_coretext_font_get_ct_font (hb_font_t *font);
+
+
+HB_END_DECLS
+
+#endif /* HB_CORETEXT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-deprecated.h	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,51 @@
+/*
+ * 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
+ */
+
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_DEPRECATED_H
+#define HB_DEPRECATED_H
+
+#include "hb-common.h"
+#include "hb-unicode.h"
+#include "hb-font.h"
+
+HB_BEGIN_DECLS
+
+#ifndef HB_DISABLE_DEPRECATED
+
+#define HB_SCRIPT_CANADIAN_ABORIGINAL           HB_SCRIPT_CANADIAN_SYLLABICS
+
+#define HB_BUFFER_FLAGS_DEFAULT                 HB_BUFFER_FLAG_DEFAULT
+#define HB_BUFFER_SERIALIZE_FLAGS_DEFAULT       HB_BUFFER_SERIALIZE_FLAG_DEFAULT
+
+#endif
+
+HB_END_DECLS
+
+#endif /* HB_DEPRECATED_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face-private.hh	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,107 @@
+/*
+ * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2011  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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_FACE_PRIVATE_HH
+#define HB_FACE_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-object-private.hh"
+#include "hb-shaper-private.hh"
+#include "hb-shape-plan-private.hh"
+
+
+/*
+ * hb_face_t
+ */
+
+struct hb_face_t {
+  hb_object_header_t header;
+  ASSERT_POD ();
+
+  hb_bool_t immutable;
+
+  hb_reference_table_func_t  reference_table_func;
+  void                      *user_data;
+  hb_destroy_func_t          destroy;
+
+  unsigned int index;
+  mutable unsigned int upem;
+  mutable unsigned int num_glyphs;
+
+  struct hb_shaper_data_t shaper_data;
+
+  struct plan_node_t {
+    hb_shape_plan_t *shape_plan;
+    plan_node_t *next;
+  } *shape_plans;
+
+
+  inline hb_blob_t *reference_table (hb_tag_t tag) const
+  {
+    hb_blob_t *blob;
+
+    if (unlikely (!reference_table_func))
+      return hb_blob_get_empty ();
+
+    blob = reference_table_func (/*XXX*/const_cast<hb_face_t *> (this), tag, user_data);
+    if (unlikely (!blob))
+      return hb_blob_get_empty ();
+
+    return blob;
+  }
+
+  inline HB_PURE_FUNC unsigned int get_upem (void) const
+  {
+    if (unlikely (!upem))
+      load_upem ();
+    return upem;
+  }
+
+  inline unsigned int get_num_glyphs (void) const
+  {
+    if (unlikely (num_glyphs == (unsigned int) -1))
+      load_num_glyphs ();
+    return num_glyphs;
+  }
+
+  private:
+  HB_INTERNAL void load_upem (void) const;
+  HB_INTERNAL void load_num_glyphs (void) const;
+};
+
+extern HB_INTERNAL const hb_face_t _hb_face_nil;
+
+#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, face);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
+
+
+#endif /* HB_FACE_PRIVATE_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face.cc	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,481 @@
+/*
+ * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-private.hh"
+
+#include "hb-ot-layout-private.hh"
+
+#include "hb-font-private.hh"
+#include "hb-open-file-private.hh"
+#include "hb-ot-head-table.hh"
+#include "hb-ot-maxp-table.hh"
+
+#include "hb-cache-private.hh"
+
+#include <string.h>
+
+
+/*
+ * hb_face_t
+ */
+
+const hb_face_t _hb_face_nil = {
+  HB_OBJECT_HEADER_STATIC,
+
+  true, /* immutable */
+
+  NULL, /* reference_table_func */
+  NULL, /* user_data */
+  NULL, /* destroy */
+
+  0,    /* index */
+  1000, /* upem */
+  0,    /* num_glyphs */
+
+  {
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+  },
+
+  NULL, /* shape_plans */
+};
+
+
+/**
+ * hb_face_create_for_tables:
+ * @reference_table_func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Return value: (transfer full)
+ *
+ * Since: 0.9.2
+ **/
+hb_face_t *
+hb_face_create_for_tables (hb_reference_table_func_t  reference_table_func,
+                           void                      *user_data,
+                           hb_destroy_func_t          destroy)
+{
+  hb_face_t *face;
+
+  if (!reference_table_func || !(face = hb_object_create<hb_face_t> ())) {
+    if (destroy)
+      destroy (user_data);
+    return hb_face_get_empty ();
+  }
+
+  face->reference_table_func = reference_table_func;
+  face->user_data = user_data;
+  face->destroy = destroy;
+
+  face->upem = 0;
+  face->num_glyphs = (unsigned int) -1;
+
+  return face;
+}
+
+
+typedef struct hb_face_for_data_closure_t {
+  hb_blob_t *blob;
+  unsigned int  index;
+} hb_face_for_data_closure_t;
+
+static hb_face_for_data_closure_t *
+_hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
+{
+  hb_face_for_data_closure_t *closure;
+
+  closure = (hb_face_for_data_closure_t *) calloc (1, sizeof (hb_face_for_data_closure_t));
+  if (unlikely (!closure))
+    return NULL;
+
+  closure->blob = blob;
+  closure->index = index;
+
+  return closure;
+}
+
+static void
+_hb_face_for_data_closure_destroy (hb_face_for_data_closure_t *closure)
+{
+  hb_blob_destroy (closure->blob);
+  free (closure);
+}
+
+static hb_blob_t *
+_hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+{
+  hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
+
+  if (tag == HB_TAG_NONE)
+    return hb_blob_reference (data->blob);
+
+  const OT::OpenTypeFontFile &ot_file = *OT::Sanitizer<OT::OpenTypeFontFile>::lock_instance (data->blob);
+  const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
+
+  const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag);
+
+  hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length);
+
+  return blob;
+}
+
+/**
+ * hb_face_create: (Xconstructor)
+ * @blob:
+ * @index:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.2
+ **/
+hb_face_t *
+hb_face_create (hb_blob_t    *blob,
+                unsigned int  index)
+{
+  hb_face_t *face;
+
+  if (unlikely (!blob))
+    blob = hb_blob_get_empty ();
+
+  hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
+
+  if (unlikely (!closure))
+    return hb_face_get_empty ();
+
+  face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
+                                    closure,
+                                    (hb_destroy_func_t) _hb_face_for_data_closure_destroy);
+
+  hb_face_set_index (face, index);
+
+  return face;
+}
+
+/**
+ * hb_face_get_empty:
+ *
+ *
+ *
+ * Return value: (transfer full)
+ *
+ * Since: 0.9.2
+ **/
+hb_face_t *
+hb_face_get_empty (void)
+{
+  return const_cast<hb_face_t *> (&_hb_face_nil);
+}
+
+
+/**
+ * hb_face_reference: (skip)
+ * @face: a face.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_face_t *
+hb_face_reference (hb_face_t *face)
+{
+  return hb_object_reference (face);
+}
+
+/**
+ * hb_face_destroy: (skip)
+ * @face: a face.
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_face_destroy (hb_face_t *face)
+{
+  if (!hb_object_destroy (face)) return;
+
+  for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
+  {
+    hb_face_t::plan_node_t *next = node->next;
+    hb_shape_plan_destroy (node->shape_plan);
+    free (node);
+    node = next;
+  }
+
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, face);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+  if (face->destroy)
+    face->destroy (face->user_data);
+
+  free (face);
+}
+
+/**
+ * hb_face_set_user_data: (skip)
+ * @face: a face.
+ * @key:
+ * @data:
+ * @destroy:
+ * @replace:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_face_set_user_data (hb_face_t          *face,
+                       hb_user_data_key_t *key,
+                       void *              data,
+                       hb_destroy_func_t   destroy,
+                       hb_bool_t           replace)
+{
+  return hb_object_set_user_data (face, key, data, destroy, replace);
+}
+
+/**
+ * hb_face_get_user_data: (skip)
+ * @face: a face.
+ * @key:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.2
+ **/
+void *
+hb_face_get_user_data (hb_face_t          *face,
+                       hb_user_data_key_t *key)
+{
+  return hb_object_get_user_data (face, key);
+}
+
+/**
+ * hb_face_make_immutable:
+ * @face: a face.
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_face_make_immutable (hb_face_t *face)
+{
+  if (unlikely (hb_object_is_inert (face)))
+    return;
+
+  face->immutable = true;
+}
+
+/**
+ * hb_face_is_immutable:
+ * @face: a face.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_face_is_immutable (hb_face_t *face)
+{
+  return face->immutable;
+}
+
+
+/**
+ * hb_face_reference_table:
+ * @face: a face.
+ * @tag:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.2
+ **/
+hb_blob_t *
+hb_face_reference_table (hb_face_t *face,
+                         hb_tag_t   tag)
+{
+  return face->reference_table (tag);
+}
+
+/**
+ * hb_face_reference_blob:
+ * @face: a face.
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.2
+ **/
+hb_blob_t *
+hb_face_reference_blob (hb_face_t *face)
+{
+  return face->reference_table (HB_TAG_NONE);
+}
+
+/**
+ * hb_face_set_index:
+ * @face: a face.
+ * @index:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_face_set_index (hb_face_t    *face,
+                   unsigned int  index)
+{
+  if (face->immutable)
+    return;
+
+  face->index = index;
+}
+
+/**
+ * hb_face_get_index:
+ * @face: a face.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+unsigned int
+hb_face_get_index (hb_face_t    *face)
+{
+  return face->index;
+}
+
+/**
+ * hb_face_set_upem:
+ * @face: a face.
+ * @upem:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_face_set_upem (hb_face_t    *face,
+                  unsigned int  upem)
+{
+  if (face->immutable)
+    return;
+
+  face->upem = upem;
+}
+
+/**
+ * hb_face_get_upem:
+ * @face: a face.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+unsigned int
+hb_face_get_upem (hb_face_t *face)
+{
+  return face->get_upem ();
+}
+
+void
+hb_face_t::load_upem (void) const
+{
+  hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (reference_table (HB_OT_TAG_head));
+  const OT::head *head_table = OT::Sanitizer<OT::head>::lock_instance (head_blob);
+  upem = head_table->get_upem ();
+  hb_blob_destroy (head_blob);
+}
+
+/**
+ * hb_face_set_glyph_count:
+ * @face: a face.
+ * @glyph_count:
+ *
+ *
+ *
+ * Since: 0.9.7
+ **/
+void
+hb_face_set_glyph_count (hb_face_t    *face,
+                         unsigned int  glyph_count)
+{
+  if (face->immutable)
+    return;
+
+  face->num_glyphs = glyph_count;
+}
+
+/**
+ * hb_face_get_glyph_count:
+ * @face: a face.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.7
+ **/
+unsigned int
+hb_face_get_glyph_count (hb_face_t *face)
+{
+  return face->get_num_glyphs ();
+}
+
+void
+hb_face_t::load_num_glyphs (void) const
+{
+  hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>::sanitize (reference_table (HB_OT_TAG_maxp));
+  const OT::maxp *maxp_table = OT::Sanitizer<OT::maxp>::lock_instance (maxp_blob);
+  num_glyphs = maxp_table->get_num_glyphs ();
+  hb_blob_destroy (maxp_blob);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face.h	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,117 @@
+/*
+ * Copyright © 2009  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_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_FACE_H
+#define HB_FACE_H
+
+#include "hb-common.h"
+#include "hb-blob.h"
+
+HB_BEGIN_DECLS
+
+
+/*
+ * hb_face_t
+ */
+
+typedef struct hb_face_t hb_face_t;
+
+hb_face_t *
+hb_face_create (hb_blob_t    *blob,
+                unsigned int  index);
+
+typedef hb_blob_t * (*hb_reference_table_func_t)  (hb_face_t *face, hb_tag_t tag, void *user_data);
+
+/* calls destroy() when not needing user_data anymore */
+hb_face_t *
+hb_face_create_for_tables (hb_reference_table_func_t  reference_table_func,
+                           void                      *user_data,
+                           hb_destroy_func_t          destroy);
+
+hb_face_t *
+hb_face_get_empty (void);
+
+hb_face_t *
+hb_face_reference (hb_face_t *face);
+
+void
+hb_face_destroy (hb_face_t *face);
+
+hb_bool_t
+hb_face_set_user_data (hb_face_t          *face,
+                       hb_user_data_key_t *key,
+                       void *              data,
+                       hb_destroy_func_t   destroy,
+                       hb_bool_t           replace);
+
+
+void *
+hb_face_get_user_data (hb_face_t          *face,
+                       hb_user_data_key_t *key);
+
+void
+hb_face_make_immutable (hb_face_t *face);
+
+hb_bool_t
+hb_face_is_immutable (hb_face_t *face);
+
+
+hb_blob_t *
+hb_face_reference_table (hb_face_t *face,
+                         hb_tag_t   tag);
+
+hb_blob_t *
+hb_face_reference_blob (hb_face_t *face);
+
+void
+hb_face_set_index (hb_face_t    *face,
+                   unsigned int  index);
+
+unsigned int
+hb_face_get_index (hb_face_t    *face);
+
+void
+hb_face_set_upem (hb_face_t    *face,
+                  unsigned int  upem);
+
+unsigned int
+hb_face_get_upem (hb_face_t *face);
+
+void
+hb_face_set_glyph_count (hb_face_t    *face,
+                         unsigned int  glyph_count);
+
+unsigned int
+hb_face_get_glyph_count (hb_face_t *face);
+
+
+HB_END_DECLS
+
+#endif /* HB_FACE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-fallback-shape.cc	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,141 @@
+/*
+ * Copyright © 2011  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
+ */
+
+#define HB_SHAPER fallback
+#include "hb-shaper-impl-private.hh"
+
+
+/*
+ * shaper face data
+ */
+
+struct hb_fallback_shaper_face_data_t {};
+
+hb_fallback_shaper_face_data_t *
+_hb_fallback_shaper_face_data_create (hb_face_t *face HB_UNUSED)
+{
+  return (hb_fallback_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_fallback_shaper_face_data_destroy (hb_fallback_shaper_face_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_fallback_shaper_font_data_t {};
+
+hb_fallback_shaper_font_data_t *
+_hb_fallback_shaper_font_data_create (hb_font_t *font HB_UNUSED)
+{
+  return (hb_fallback_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_fallback_shaper_font_data_destroy (hb_fallback_shaper_font_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_fallback_shaper_shape_plan_data_t {};
+
+hb_fallback_shaper_shape_plan_data_t *
+_hb_fallback_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
+                                            const hb_feature_t *user_features HB_UNUSED,
+                                            unsigned int        num_user_features HB_UNUSED)
+{
+  return (hb_fallback_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_fallback_shaper_shape_plan_data_destroy (hb_fallback_shaper_shape_plan_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper
+ */
+
+hb_bool_t
+_hb_fallback_shape (hb_shape_plan_t    *shape_plan HB_UNUSED,
+                    hb_font_t          *font,
+                    hb_buffer_t        *buffer,
+                    const hb_feature_t *features HB_UNUSED,
+                    unsigned int        num_features HB_UNUSED)
+{
+  /* TODO
+   *
+   * - Apply fallback kern.
+   * - Handle Variation Selectors?
+   * - Apply normalization?
+   *
+   * This will make the fallback shaper into a dumb "TrueType"
+   * shaper which many people unfortunately still request.
+   */
+
+  hb_codepoint_t space;
+  bool has_space = font->get_glyph (' ', 0, &space);
+
+  buffer->clear_positions ();
+
+  hb_direction_t direction = buffer->props.direction;
+  hb_unicode_funcs_t *unicode = buffer->unicode;
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  hb_glyph_position_t *pos = buffer->pos;
+  for (unsigned int i = 0; i < count; i++)
+  {
+    if (has_space && unicode->is_default_ignorable (info[i].codepoint)) {
+      info[i].codepoint = space;
+      pos[i].x_advance = 0;
+      pos[i].y_advance = 0;
+      continue;
+    }
+    font->get_glyph (info[i].codepoint, 0, &info[i].codepoint);
+    font->get_glyph_advance_for_direction (info[i].codepoint,
+                                           direction,
+                                           &pos[i].x_advance,
+                                           &pos[i].y_advance);
+    font->subtract_glyph_origin_for_direction (info[i].codepoint,
+                                               direction,
+                                               &pos[i].x_offset,
+                                               &pos[i].y_offset);
+  }
+
+  if (HB_DIRECTION_IS_BACKWARD (direction))
+    hb_buffer_reverse (buffer);
+
+  return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-font-private.hh	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,415 @@
+/*
+ * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2011  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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_FONT_PRIVATE_HH
+#define HB_FONT_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-object-private.hh"
+#include "hb-face-private.hh"
+#include "hb-shaper-private.hh"
+
+
+
+/*
+ * hb_font_funcs_t
+ */
+
+#define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \
+  HB_FONT_FUNC_IMPLEMENT (glyph) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_extents) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_name) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \
+  /* ^--- Add new callbacks here */
+
+struct hb_font_funcs_t {
+  hb_object_header_t header;
+  ASSERT_POD ();
+
+  hb_bool_t immutable;
+
+  /* Don't access these directly.  Call hb_font_get_*() instead. */
+
+  struct {
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
+    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+  } get;
+
+  struct {
+#define HB_FONT_FUNC_IMPLEMENT(name) void *name;
+    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+  } user_data;
+
+  struct {
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
+    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+  } destroy;
+};
+
+
+
+/*
+ * hb_font_t
+ */
+
+struct hb_font_t {
+  hb_object_header_t header;
+  ASSERT_POD ();
+
+  hb_bool_t immutable;
+
+  hb_font_t *parent;
+  hb_face_t *face;
+
+  int x_scale;
+  int y_scale;
+
+  unsigned int x_ppem;
+  unsigned int y_ppem;
+
+  hb_font_funcs_t   *klass;
+  void              *user_data;
+  hb_destroy_func_t  destroy;
+
+  struct hb_shaper_data_t shaper_data;
+
+
+  /* Convert from font-space to user-space */
+  inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, this->x_scale); }
+  inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, this->y_scale); }
+
+  /* Convert from parent-font user-space to our user-space */
+  inline hb_position_t parent_scale_x_distance (hb_position_t v) {
+    if (unlikely (parent && parent->x_scale != x_scale))
+      return (hb_position_t) (v * (int64_t) this->x_scale / this->parent->x_scale);
+    return v;
+  }
+  inline hb_position_t parent_scale_y_distance (hb_position_t v) {
+    if (unlikely (parent && parent->y_scale != y_scale))
+      return (hb_position_t) (v * (int64_t) this->y_scale / this->parent->y_scale);
+    return v;
+  }
+  inline hb_position_t parent_scale_x_position (hb_position_t v) {
+    return parent_scale_x_distance (v);
+  }
+  inline hb_position_t parent_scale_y_position (hb_position_t v) {
+    return parent_scale_y_distance (v);
+  }
+
+  inline void parent_scale_distance (hb_position_t *x, hb_position_t *y) {
+    *x = parent_scale_x_distance (*x);
+    *y = parent_scale_y_distance (*y);
+  }
+  inline void parent_scale_position (hb_position_t *x, hb_position_t *y) {
+    *x = parent_scale_x_position (*x);
+    *y = parent_scale_y_position (*y);
+  }
+
+
+  /* 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)
+  {
+    *glyph = 0;
+    return klass->get.glyph (this, user_data,
+                             unicode, variation_selector, glyph,
+                             klass->user_data.glyph);
+  }
+
+  inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
+  {
+    return klass->get.glyph_h_advance (this, user_data,
+                                       glyph,
+                                       klass->user_data.glyph_h_advance);
+  }
+
+  inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
+  {
+    return klass->get.glyph_v_advance (this, user_data,
+                                       glyph,
+                                       klass->user_data.glyph_v_advance);
+  }
+
+  inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
+                                       hb_position_t *x, hb_position_t *y)
+  {
+    *x = *y = 0;
+    return klass->get.glyph_h_origin (this, user_data,
+                                      glyph, x, y,
+                                      klass->user_data.glyph_h_origin);
+  }
+
+  inline hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
+                                       hb_position_t *x, hb_position_t *y)
+  {
+    *x = *y = 0;
+    return klass->get.glyph_v_origin (this, user_data,
+                                      glyph, x, y,
+                                      klass->user_data.glyph_v_origin);
+  }
+
+  inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
+  {
+    return klass->get.glyph_h_kerning (this, user_data,
+                                       left_glyph, right_glyph,
+                                       klass->user_data.glyph_h_kerning);
+  }
+
+  inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
+  {
+    return klass->get.glyph_v_kerning (this, user_data,
+                                       top_glyph, bottom_glyph,
+                                       klass->user_data.glyph_v_kerning);
+  }
+
+  inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
+                                      hb_glyph_extents_t *extents)
+  {
+    memset (extents, 0, sizeof (*extents));
+    return klass->get.glyph_extents (this, user_data,
+                                     glyph,
+                                     extents,
+                                     klass->user_data.glyph_extents);
+  }
+
+  inline hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
+                                            hb_position_t *x, hb_position_t *y)
+  {
+    *x = *y = 0;
+    return klass->get.glyph_contour_point (this, user_data,
+                                           glyph, point_index,
+                                           x, y,
+                                           klass->user_data.glyph_contour_point);
+  }
+
+  inline hb_bool_t get_glyph_name (hb_codepoint_t glyph,
+                                   char *name, unsigned int size)
+  {
+    if (size) *name = '\0';
+    return klass->get.glyph_name (this, user_data,
+                                  glyph,
+                                  name, size,
+                                  klass->user_data.glyph_name);
+  }
+
+  inline hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
+                                        hb_codepoint_t *glyph)
+  {
+    *glyph = 0;
+    if (len == -1) len = strlen (name);
+    return klass->get.glyph_from_name (this, user_data,
+                                       name, len,
+                                       glyph,
+                                       klass->user_data.glyph_from_name);
+  }
+
+
+  /* A bit higher-level, and with fallback */
+
+  inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
+                                               hb_direction_t direction,
+                                               hb_position_t *x, hb_position_t *y)
+  {
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
+      *x = get_glyph_h_advance (glyph);
+      *y = 0;
+    } else {
+      *x = 0;
+      *y = get_glyph_v_advance (glyph);
+    }
+  }
+
+  /* Internal only */
+  inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
+                                             hb_position_t *x, hb_position_t *y)
+  {
+    *x = get_glyph_h_advance (glyph) / 2;
+
+    /* TODO use font_metrics.ascent */
+    *y = y_scale;
+  }
+
+  inline void get_glyph_origin_for_direction (hb_codepoint_t glyph,
+                                              hb_direction_t direction,
+                                              hb_position_t *x, hb_position_t *y)
+  {
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
+    {
+      if (!get_glyph_h_origin (glyph, x, y) &&
+           get_glyph_v_origin (glyph, x, y))
+      {
+        hb_position_t dx, dy;
+        guess_v_origin_minus_h_origin (glyph, &dx, &dy);
+        *x -= dx; *y -= dy;
+      }
+    }
+    else
+    {
+      if (!get_glyph_v_origin (glyph, x, y) &&
+           get_glyph_h_origin (glyph, x, y))
+      {
+        hb_position_t dx, dy;
+        guess_v_origin_minus_h_origin (glyph, &dx, &dy);
+        *x += dx; *y += dy;
+      }
+    }
+  }
+
+  inline void add_glyph_origin_for_direction (hb_codepoint_t glyph,
+                                              hb_direction_t direction,
+                                              hb_position_t *x, hb_position_t *y)
+  {
+    hb_position_t origin_x, origin_y;
+
+    get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
+
+    *x += origin_x;
+    *y += origin_y;
+  }
+
+  inline void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
+                                                   hb_direction_t direction,
+                                                   hb_position_t *x, hb_position_t *y)
+  {
+    hb_position_t origin_x, origin_y;
+
+    get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
+
+    *x -= origin_x;
+    *y -= origin_y;
+  }
+
+  inline void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
+                                               hb_direction_t direction,
+                                               hb_position_t *x, hb_position_t *y)
+  {
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
+      *x = get_glyph_h_kerning (first_glyph, second_glyph);
+      *y = 0;
+    } else {
+      *x = 0;
+      *y = get_glyph_v_kerning (first_glyph, second_glyph);
+    }
+  }
+
+  inline hb_bool_t get_glyph_extents_for_origin (hb_codepoint_t glyph,
+                                                 hb_direction_t direction,
+                                                 hb_glyph_extents_t *extents)
+  {
+    hb_bool_t ret = get_glyph_extents (glyph, extents);
+
+    if (ret)
+      subtract_glyph_origin_for_direction (glyph, direction, &extents->x_bearing, &extents->y_bearing);
+
+    return ret;
+  }
+
+  inline hb_bool_t get_glyph_contour_point_for_origin (hb_codepoint_t glyph, unsigned int point_index,
+                                                       hb_direction_t direction,
+                                                       hb_position_t *x, hb_position_t *y)
+  {
+    hb_bool_t ret = get_glyph_contour_point (glyph, point_index, x, y);
+
+    if (ret)
+      subtract_glyph_origin_for_direction (glyph, direction, x, y);
+
+    return ret;
+  }
+
+  /* Generates gidDDD if glyph has no name. */
+  inline void
+  glyph_to_string (hb_codepoint_t glyph,
+                   char *s, unsigned int size)
+  {
+    if (get_glyph_name (glyph, s, size)) return;
+
+    if (size && snprintf (s, size, "gid%u", glyph) < 0)
+      *s = '\0';
+  }
+
+  /* Parses gidDDD and uniUUUU strings automatically. */
+  inline hb_bool_t
+  glyph_from_string (const char *s, int len, /* -1 means nul-terminated */
+                     hb_codepoint_t *glyph)
+  {
+    if (get_glyph_from_name (s, len, glyph)) return true;
+
+    if (len == -1) len = strlen (s);
+
+    /* Straight glyph index. */
+    if (hb_codepoint_parse (s, len, 10, glyph))
+      return true;
+
+    if (len > 3)
+    {
+      /* gidDDD syntax for glyph indices. */
+      if (0 == strncmp (s, "gid", 3) &&
+          hb_codepoint_parse (s + 3, len - 3, 10, glyph))
+        return true;
+
+      /* uniUUUU and other Unicode character indices. */
+      hb_codepoint_t unichar;
+      if (0 == strncmp (s, "uni", 3) &&
+          hb_codepoint_parse (s + 3, len - 3, 16, &unichar) &&
+          get_glyph (unichar, 0, glyph))
+        return true;
+    }
+
+    return false;
+  }
+
+  private:
+  inline hb_position_t em_scale (int16_t v, int scale) { return (hb_position_t) (v * (int64_t) scale / face->get_upem ()); }
+};
+
+#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, font);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
+
+
+#endif /* HB_FONT_PRIVATE_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-font.cc	Mon Nov 23 09:58:44 2015 -0800
@@ -0,0 +1,1266 @@
+/*
+ * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-private.hh"
+
+#include "hb-ot-layout-private.hh"
+
+#include "hb-font-private.hh"
+#include "hb-open-file-private.hh"
+#include "hb-ot-head-table.hh"
+#include "hb-ot-maxp-table.hh"
+
+#include "hb-cache-private.hh"
+
+#include <string.h>
+
+
+/*
+ * hb_font_funcs_t
+ */
+
+static hb_bool_t
+hb_font_get_glyph_nil (hb_font_t *font,
+                       void *font_data HB_UNUSED,
+                       hb_codepoint_t unicode,
+                       hb_codepoint_t variation_selector,
+                       hb_codepoint_t *glyph,
+                       void *user_data HB_UNUSED)
+{
+  if (font->parent)
+    return font->parent->get_glyph (unicode, variation_selector, glyph);
+
+  *glyph = 0;
+  return false;
+}
+
+static hb_position_t
+hb_font_get_glyph_h_advance_nil (hb_font_t *font,
+                                 void *font_data HB_UNUSED,
+                                 hb_codepoint_t glyph,
+                                 void *user_data HB_UNUSED)
+{
+  if (font->parent)
+    return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
+
+  return font->x_scale;
+}
+
+static hb_position_t
+hb_font_get_glyph_v_advance_nil (hb_font_t *font,
+                                 void *font_data HB_UNUSED,
+                                 hb_codepoint_t glyph,
+                                 void *user_data HB_UNUSED)
+{
+  if (font->parent)
+    return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
+
+  return font->y_scale;
+}
+
+static hb_bool_t
+hb_font_get_glyph_h_origin_nil (hb_font_t *font,
+                                void *font_data HB_UNUSED,
+                                hb_codepoint_t glyph,
+                                hb_position_t *x,
+                                hb_position_t *y,
+                                void *user_data HB_UNUSED)
+{
+  if (font->parent) {
+    hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y);
+    if (ret)
+      font->parent_scale_position (x, y);
+    return ret;
+  }
+
+  *x = *y = 0;
+  return false;
+}
+
+static hb_bool_t
+hb_font_get_glyph_v_origin_nil (hb_font_t *font,
+                                void *font_data HB_UNUSED,
+                                hb_codepoint_t glyph,
+                                hb_position_t *x,
+                                hb_position_t *y,
+                                void *user_data HB_UNUSED)
+{
+  if (font->parent) {
+    hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y);
+    if (ret)
+      font->parent_scale_position (x, y);
+    return ret;
+  }
+
+  *x = *y = 0;
+  return false;
+}
+
+static hb_position_t
+hb_font_get_glyph_h_kerning_nil (hb_font_t *font,
+                                 void *font_data HB_UNUSED,
+                                 hb_codepoint_t left_glyph,
+                                 hb_codepoint_t right_glyph,
+                                 void *user_data HB_UNUSED)
+{
+  if (font->parent)
+    return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
+
+  return 0;
+}
+
+static hb_position_t
+hb_font_get_glyph_v_kerning_nil (hb_font_t *font,
+                                 void *font_data HB_UNUSED,
+                                 hb_codepoint_t top_glyph,
+                                 hb_codepoint_t bottom_glyph,
+                                 void *user_data HB_UNUSED)
+{
+  if (font->parent)
+    return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
+
+  return 0;
+}
+
+static hb_bool_t
+hb_font_get_glyph_extents_nil (hb_font_t *font,
+                               void *font_data HB_UNUSED,
+                               hb_codepoint_t glyph,
+                               hb_glyph_extents_t *extents,
+                               void *user_data HB_UNUSED)
+{
+  if (font->parent) {
+    hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents);
+    if (ret) {
+      font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
+      font->parent_scale_distance (&extents->width, &extents->height);
+    }
+    return ret;
+  }
+
+  memset (extents, 0, sizeof (*extents));
+  return false;
+}
+
+static hb_bool_t
+hb_font_get_glyph_contour_point_nil (hb_font_t *font,
+                                     void *font_data HB_UNUSED,
+                                     hb_codepoint_t glyph,
+                                     unsigned int point_index,
+                                     hb_position_t *x,
+                                     hb_position_t *y,
+                                     void *user_data HB_UNUSED)
+{
+  if (font->parent) {
+    hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y);
+    if (ret)
+      font->parent_scale_position (x, y);
+    return ret;
+  }
+
+  *x = *y = 0;
+  return false;
+}
+
+static hb_bool_t
+hb_font_get_glyph_name_nil (hb_font_t *font,
+                            void *font_data HB_UNUSED,
+                            hb_codepoint_t glyph,
+                            char *name, unsigned int size,
+                            void *user_data HB_UNUSED)
+{
+  if (font->parent)
+    return font->parent->get_glyph_name (glyph, name, size);
+
+  if (size) *name = '\0';
+  return false;
+}
+
+static hb_bool_t
+hb_font_get_glyph_from_name_nil (hb_font_t *font,
+                                 void *font_data HB_UNUSED,
+                                 const char *name, int len, /* -1 means nul-terminated */
+                                 hb_codepoint_t *glyph,
+                                 void *user_data HB_UNUSED)
+{
+  if (font->parent)
+    return font->parent->get_glyph_from_name (name, len, glyph);
+
+  *glyph = 0;
+  return false;
+}
+
+
+static const hb_font_funcs_t _hb_font_funcs_nil = {
+  HB_OBJECT_HEADER_STATIC,
+
+  true, /* immutable */
+
+  {
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
+    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+  }
+};
+
+
+/**
+ * hb_font_funcs_create: (Xconstructor)
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.2
+ **/
+hb_font_funcs_t *
+hb_font_funcs_create (void)
+{
+  hb_font_funcs_t *ffuncs;
+
+  if (!(ffuncs = hb_object_create<hb_font_funcs_t> ()))
+    return hb_font_funcs_get_empty ();
+
+  ffuncs->get = _hb_font_funcs_nil.get;
+
+  return ffuncs;
+}
+
+/**
+ * hb_font_funcs_get_empty:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.2
+ **/
+hb_font_funcs_t *
+hb_font_funcs_get_empty (void)
+{
+  return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil);
+}
+
+/**
+ * hb_font_funcs_reference: (skip)
+ * @ffuncs: font functions.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_font_funcs_t *
+hb_font_funcs_reference (hb_font_funcs_t *ffuncs)
+{
+  return hb_object_reference (ffuncs);
+}
+
+/**
+ * hb_font_funcs_destroy: (skip)
+ * @ffuncs: font functions.
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
+{
+  if (!hb_object_destroy (ffuncs)) return;
+
+#define HB_FONT_FUNC_IMPLEMENT(name) if (ffuncs->destroy.name) \
+  ffuncs->destroy.name (ffuncs->user_data.name);
+  HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+
+  free (ffuncs);
+}
+
+/**
+ * hb_font_funcs_set_user_data: (skip)
+ * @ffuncs: font functions.
+ * @key:
+ * @data:
+ * @destroy:
+ * @replace:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_font_funcs_set_user_data (hb_font_funcs_t    *ffuncs,
+                             hb_user_data_key_t *key,
+                             void *              data,
+                             hb_destroy_func_t   destroy,
+                             hb_bool_t           replace)
+{
+  return hb_object_set_user_data (ffuncs, key, data, destroy, replace);
+}
+
+/**
+ * hb_font_funcs_get_user_data: (skip)
+ * @ffuncs: font functions.
+ * @key:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.2
+ **/
+void *
+hb_font_funcs_get_user_data (hb_font_funcs_t    *ffuncs,
+                             hb_user_data_key_t *key)
+{
+  return hb_object_get_user_data (ffuncs, key);
+}
+
+
+/**
+ * hb_font_funcs_make_immutable:
+ * @ffuncs: font functions.
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
+{
+  if (unlikely (hb_object_is_inert (ffuncs)))
+    return;
+
+  ffuncs->immutable = true;
+}
+
+/**
+ * hb_font_funcs_is_immutable:
+ * @ffuncs: font functions.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs)
+{
+  return ffuncs->immutable;
+}
+
+
+#define HB_FONT_FUNC_IMPLEMENT(name) \
+                                                                         \
+void                                                                     \
+hb_font_funcs_set_##name##_func (hb_font_funcs_t             *ffuncs,    \
+                                 hb_font_get_##name##_func_t  func,      \
+                                 void                        *user_data, \
+                                 hb_destroy_func_t            destroy)   \
+{                                                                        \
+  if (ffuncs->immutable) {                                               \
+    if (destroy)                                                         \
+      destroy (user_data);                                               \
+    return;                                                              \
+  }                                                                      \
+                                                                         \
+  if (ffuncs->destroy.name)                                              \
+    ffuncs->destroy.name (ffuncs->user_data.name);                       \
+                                                                         \
+  if (func) {                                                            \
+    ffuncs->get.name = func;                                             \
+    ffuncs->user_data.name = user_data;                                  \
+    ffuncs->destroy.name = destroy;                                      \
+  } else {                                                               \
+    ffuncs->get.name = hb_font_get_##name##_nil;                         \
+    ffuncs->user_data.name = NULL;                                       \
+    ffuncs->destroy.name = NULL;                                         \
+  }                                                                      \
+}
+
+HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+
+
+/* Public getters */
+
+/**
+ * hb_font_get_glyph:
+ * @font: a font.
+ * @unicode:
+ * @variation_selector:
+ * @glyph: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_font_get_glyph (hb_font_t *font,
+                   hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+                   hb_codepoint_t *glyph)
+{
+  return font->get_glyph (unicode, variation_selector, glyph);
+}
+
+/**
+ * hb_font_get_glyph_h_advance:
+ * @font: a font.
+ * @glyph:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_position_t
+hb_font_get_glyph_h_advance (hb_font_t *font,
+                             hb_codepoint_t glyph)
+{
+  return font->get_glyph_h_advance (glyph);
+}
+
+/**
+ * hb_font_get_glyph_v_advance:
+ * @font: a font.
+ * @glyph:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_position_t
+hb_font_get_glyph_v_advance (hb_font_t *font,
+                             hb_codepoint_t glyph)
+{
+  return font->get_glyph_v_advance (glyph);
+}
+
+/**
+ * hb_font_get_glyph_h_origin:
+ * @font: a font.
+ * @glyph:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_font_get_glyph_h_origin (hb_font_t *font,
+                            hb_codepoint_t glyph,
+                            hb_position_t *x, hb_position_t *y)
+{
+  return font->get_glyph_h_origin (glyph, x, y);
+}
+
+/**
+ * hb_font_get_glyph_v_origin:
+ * @font: a font.
+ * @glyph:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_font_get_glyph_v_origin (hb_font_t *font,
+                            hb_codepoint_t glyph,
+                            hb_position_t *x, hb_position_t *y)
+{
+  return font->get_glyph_v_origin (glyph, x, y);
+}
+
+/**
+ * hb_font_get_glyph_h_kerning:
+ * @font: a font.
+ * @left_glyph:
+ * @right_glyph:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_position_t
+hb_font_get_glyph_h_kerning (hb_font_t *font,
+                             hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
+{
+  return font->get_glyph_h_kerning (left_glyph, right_glyph);
+}
+
+/**
+ * hb_font_get_glyph_v_kerning:
+ * @font: a font.
+ * @top_glyph:
+ * @bottom_glyph:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_position_t
+hb_font_get_glyph_v_kerning (hb_font_t *font,
+                             hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
+{
+  return font->get_glyph_v_kerning (top_glyph, bottom_glyph);
+}
+
+/**
+ * hb_font_get_glyph_extents:
+ * @font: a font.
+ * @glyph:
+ * @extents: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_font_get_glyph_extents (hb_font_t *font,
+                           hb_codepoint_t glyph,
+                           hb_glyph_extents_t *extents)
+{
+  return font->get_glyph_extents (glyph, extents);
+}
+
+/**
+ * hb_font_get_glyph_contour_point:
+ * @font: a font.
+ * @glyph:
+ * @point_index:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_font_get_glyph_contour_point (hb_font_t *font,
+                                 hb_codepoint_t glyph, unsigned int point_index,
+                                 hb_position_t *x, hb_position_t *y)
+{
+  return font->get_glyph_contour_point (glyph, point_index, x, y);
+}
+
+/**
+ * hb_font_get_glyph_name:
+ * @font: a font.
+ * @glyph:
+ * @name: (array length=size):
+ * @size:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_font_get_glyph_name (hb_font_t *font,
+                        hb_codepoint_t glyph,
+                        char *name, unsigned int size)
+{
+  return font->get_glyph_name (glyph, name, size);
+}
+
+/**
+ * hb_font_get_glyph_from_name:
+ * @font: a font.
+ * @name: (array length=len):
+ * @len:
+ * @glyph: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_font_get_glyph_from_name (hb_font_t *font,
+                             const char *name, int len, /* -1 means nul-terminated */
+                             hb_codepoint_t *glyph)
+{
+  return font->get_glyph_from_name (name, len, glyph);
+}
+
+
+/* A bit higher-level, and with fallback */
+
+/**
+ * hb_font_get_glyph_advance_for_direction:
+ * @font: a font.
+ * @glyph:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_font_get_glyph_advance_for_direction (hb_font_t *font,
+                                         hb_codepoint_t glyph,
+                                         hb_direction_t direction,
+                                         hb_position_t *x, hb_position_t *y)
+{
+  return font->get_glyph_advance_for_direction (glyph, direction, x, y);
+}
+
+/**
+ * hb_font_get_glyph_origin_for_direction:
+ * @font: a font.
+ * @glyph:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_font_get_glyph_origin_for_direction (hb_font_t *font,
+                                        hb_codepoint_t glyph,
+                                        hb_direction_t direction,
+                                        hb_position_t *x, hb_position_t *y)
+{
+  return font->get_glyph_origin_for_direction (glyph, direction, x, y);
+}
+
+/**
+ * hb_font_add_glyph_origin_for_direction:
+ * @font: a font.
+ * @glyph:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_font_add_glyph_origin_for_direction (hb_font_t *font,
+                                        hb_codepoint_t glyph,
+                                        hb_direction_t direction,
+                                        hb_position_t *x, hb_position_t *y)
+{
+  return font->add_glyph_origin_for_direction (glyph, direction, x, y);
+}
+
+/**
+ * hb_font_subtract_glyph_origin_for_direction:
+ * @font: a font.
+ * @glyph:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
+                                             hb_codepoint_t glyph,
+                                             hb_direction_t direction,
+                                             hb_position_t *x, hb_position_t *y)
+{
+  return font->subtract_glyph_origin_for_direction (glyph, direction, x, y);
+}
+
+/**
+ * hb_font_get_glyph_kerning_for_direction:
+ * @font: a font.
+ * @first_glyph:
+ * @second_glyph:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
+                                         hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
+                                         hb_direction_t direction,
+                                         hb_position_t *x, hb_position_t *y)
+{
+  return font->get_glyph_kerning_for_direction (first_glyph, second_glyph, direction, x, y);
+}
+
+/**
+ * hb_font_get_glyph_extents_for_origin:
+ * @font: a font.
+ * @glyph:
+ * @direction:
+ * @extents: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_font_get_glyph_extents_for_origin (hb_font_t *font,
+                                      hb_codepoint_t glyph,
+                                      hb_direction_t direction,
+                                      hb_glyph_extents_t *extents)
+{
+  return font->get_glyph_extents_for_origin (glyph, direction, extents);
+}
+
+/**
+ * hb_font_get_glyph_contour_point_for_origin:
+ * @font: a font.
+ * @glyph:
+ * @point_index:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
+                                            hb_codepoint_t glyph, unsigned int point_index,
+                                            hb_direction_t direction,
+                                            hb_position_t *x, hb_position_t *y)
+{
+  return font->get_glyph_contour_point_for_origin (glyph, point_index, direction, x, y);
+}
+
+/* Generates gidDDD if glyph has no name. */
+/**
+ * hb_font_glyph_to_string:
+ * @font: a font.
+ * @glyph:
+ * @s: (array length=size):
+ * @size:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_font_glyph_to_string (hb_font_t *font,
+                         hb_codepoint_t glyph,
+                         char *s, unsigned int size)
+{
+  font->glyph_to_string (glyph, s, size);
+}
+
+/* Parses gidDDD and uniUUUU strings automatically. */
+/**
+ * hb_font_glyph_from_string:
+ * @font: a font.
+ * @s: (array length=len) (element-type uint8_t):
+ * @len:
+ * @glyph: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_font_glyph_from_string (hb_font_t *font,
+                           const char *s, int len, /* -1 means nul-terminated */
+                           hb_codepoint_t *glyph)
+{
+  return font->glyph_from_string (s, len, glyph);
+}
+
+
+/*
+ * hb_font_t
+ */
+
+/**
+ * hb_font_create: (Xconstructor)
+ * @face: a face.
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.2
+ **/
+hb_font_t *
+hb_font_create (hb_face_t *face)
+{
+  hb_font_t *font;
+
+  if (unlikely (!face))
+    face = hb_face_get_empty ();
+  if (!(font = hb_object_create<hb_font_t> ()))
+    return hb_font_get_empty ();
+
+  hb_face_make_immutable (face);
+  font->face = hb_face_reference (face);
+  font->klass = hb_font_funcs_get_empty ();
+
+  font->x_scale = font->y_scale = hb_face_get_upem (face);
+
+  return font;
+}
+
+/**
+ * hb_font_create_sub_font:
+ * @parent: parent font.
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.2
+ **/
+hb_font_t *
+hb_font_create_sub_font (hb_font_t *parent)
+{
+  if (unlikely (!parent))
+    parent = hb_font_get_empty ();
+
+  hb_font_t *font = hb_font_create (parent->face);
+
+  if (unlikely (hb_object_is_inert (font)))
+    return font;
+
+  font->parent = hb_font_reference (parent);
+
+  font->x_scale = parent->x_scale;
+  font->y_scale = parent->y_scale;
+  font->x_ppem = parent->x_ppem;
+  font->y_ppem = parent->y_ppem;
+
+  return font;
+}
+
+/**
+ * hb_font_get_empty:
+ *
+ *
+ *
+ * Return value: (transfer full)
+ *
+ * Since: 0.9.2
+ **/
+hb_font_t *
+hb_font_get_empty (void)
+{
+  static const hb_font_t _hb_font_nil = {
+    HB_OBJECT_HEADER_STATIC,
+
+    true, /* immutable */
+
+    NULL, /* parent */
+    const_cast<hb_face_t *> (&_hb_face_nil),
+
+    0, /* x_scale */
+    0, /* y_scale */
+
+    0, /* x_ppem */
+    0, /* y_ppem */
+
+    const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil), /* klass */
+    NULL, /* user_data */
+    NULL, /* destroy */
+
+    {
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+    }
+  };
+
+  return const_cast<hb_font_t *> (&_hb_font_nil);
+}
+
+/**
+ * hb_font_reference: (skip)
+ * @font: a font.
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.2
+ **/
+hb_font_t *
+hb_font_reference (hb_font_t *font)
+{
+  return hb_object_reference (font);
+}
+
+/**
+ * hb_font_destroy: (skip)
+ * @font: a font.
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_font_destroy (hb_font_t *font)
+{
+  if (!hb_object_destroy (font)) return;
+
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, font);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+  if (font->destroy)
+    font->destroy (font->user_data);
+
+  hb_font_destroy (font->parent);
+  hb_face_destroy (font->face);
+  hb_font_funcs_destroy (font->klass);
+
+  free (font);
+}
+
+/**
+ * hb_font_set_user_data: (skip)
+ * @font: a font.
+ * @key:
+ * @data:
+ * @destroy:
+ * @replace:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_font_set_user_data (hb_font_t          *font,
+                       hb_user_data_key_t *key,
+                       void *              data,
+                       hb_destroy_func_t   destroy,
+                       hb_bool_t           replace)
+{
+  return hb_object_set_user_data (font, key, data, destroy, replace);
+}
+
+/**
+ * hb_font_get_user_data: (skip)
+ * @font: a font.
+ * @key:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.2
+ **/
+void *
+hb_font_get_user_data (hb_font_t          *font,
+                       hb_user_data_key_t *key)
+{
+  return hb_object_get_user_data (font, key);
+}
+
+/**
+ * hb_font_make_immutable:
+ * @font: a font.
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_font_make_immutable (hb_font_t *font)
+{
+  if (unlikely (hb_object_is_inert (font)))
+    return;
+
+  if (font->parent)
+    hb_font_make_immutable (font->parent);
+
+  font->immutable = true;
+}
+
+/**
+ * hb_font_is_immutable:
+ * @font: a font.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_font_is_immutable (hb_font_t *font)
+{
+  return font->immutable;
+}
+
+/**
+ * hb_font_set_parent:
+ * @font: a font.
+ * @parent: new parent.
+ *
+ * Sets parent font of @font.
+ *
+ * Since: 1.0.5
+ **/
+void
+hb_font_set_parent (hb_font_t *font,
+                    hb_font_t *parent)
+{
+  if (font->immutable)
+    return;
+
+  if (!parent)
+    parent = hb_font_get_empty ();
+
+  hb_font_t *old = font->parent;
+
+  font->parent = hb_font_reference (parent);
+
+  hb_font_destroy (old);
+}
+
+/**
+ * hb_font_get_parent:
+ * @font: a font.
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.2
+ **/
+hb_font_t *
+hb_font_get_parent (hb_font_t *font)
+{
+  return font->parent;
+}
+
+/**
+ * hb_font_get_face:
+ * @font: a font.
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.2
+ **/
+hb_face_t *
+hb_font_get_face (hb_font_t *font)
+{
+  return font->face;
+}
+
+
+/**
+ * hb_font_set_funcs:
+ * @font: a font.
+ * @klass: (closure font_data) (destroy destroy) (scope notified):
+ * @font_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_font_set_funcs (hb_font_t         *font,
+                   hb_font_funcs_t   *klass,
+                   void              *font_data,
+                   hb_destroy_func_t  destroy)
+{
+  if (font->immutable) {
+    if (destroy)
+      destroy (font_data);
+    return;
+  }
+
+  if (font->destroy)
+    font->destroy (font->user_data);
+
+  if (!klass)
+    klass = hb_font_funcs_get_empty ();
+
+  hb_font_funcs_reference (klass);
+  hb_font_funcs_destroy (font->klass);
+  font->klass = klass;
+  font->user_data = font_data;
+  font->destroy = destroy;
+}
+
+/**
+ * hb_font_set_funcs_data:
+ * @font: a font.
+ * @font_data: (destroy destroy) (scope notified):
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_font_set_funcs_data (hb_font_t         *font,
+                        void              *font_data,
+                        hb_destroy_func_t  destroy)
+{
+  /* Destroy user_data? */
+  if (font->immutable) {
+    if (destroy)
+      destroy (font_data);
+    return;
+  }
+
+  if (font->destroy)
+    font->destroy (font->user_data);
+
+  font->user_data = font_data;
+  font->destroy = destroy;
+}
+
+
+/**
+ * hb_font_set_scale:
+ * @font: a font.
+ * @x_scale:
+ * @y_scale:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_font_set_scale (hb_font_t *font,
+                   int x_scale,
+                   int y_scale)
+{
+  if (font->immutable)
+    return;
+
+  font->x_scale = x_scale;
+  font->y_scale = y_scale;
+}
+
+/**
+ * hb_font_get_scale:
+ * @font: a font.
+ * @x_scale: (out):
+ * @y_scale: (out):
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_font_get_scale (hb_font_t *font,
+                   int *x_scale,
+                   int *y_scale)
+{
+  if (x_scale) *x_scale = font->x_scale;
+  if (y_scale) *y_scale = font->y_scale;
+}
+
+/**
+ * hb_font_set_ppem:
+ * @font: a font.
+ * @x_ppem:
+ * @y_ppem:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_font_set_ppem (hb_font_t *font,
+                  unsigned int x_ppem,
+                  unsigned int y_ppem)
+{
+  if (font->immutable)