Merge with jdk8u152-b00

Conflicts:
	src/macosx/classes/sun/lwawt/LWWindowPeer.java
	src/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java
	src/macosx/classes/sun/lwawt/macosx/NSEvent.java
	src/macosx/native/sun/awt/AWTWindow.m
	src/macosx/native/sun/awt/JavaComponentAccessibility.m
	src/macosx/native/sun/awt/LWCToolkit.h
	src/macosx/native/sun/awt/LWCToolkit.m
	src/macosx/native/sun/font/AWTFont.m
	src/macosx/native/sun/osxapp/NSApplicationAWT.m
	src/share/back/debugLoop.c
	test/java/awt/Focus/ModalDialogActivationTest/ModalDialogActivationTest.java
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..814f170
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+JTwork
+JTreport
+*.class
+.idea/workspace.xml
+idea/java/.idea/workspace.xml
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="Git" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/idea/java/.idea/.name b/idea/java/.idea/.name
new file mode 100644
index 0000000..25feecc
--- /dev/null
+++ b/idea/java/.idea/.name
@@ -0,0 +1 @@
+jdk
\ No newline at end of file
diff --git a/idea/java/.idea/compiler.xml b/idea/java/.idea/compiler.xml
new file mode 100644
index 0000000..3e65032
--- /dev/null
+++ b/idea/java/.idea/compiler.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <option name="DEFAULT_COMPILER" value="Javac" />
+    <option name="BUILD_PROCESS_HEAP_SIZE" value="1500" />
+    <resourceExtensions />
+    <wildcardResourcePatterns>
+      <entry name="!?*.java" />
+      <entry name="!?*.form" />
+      <entry name="!?*.class" />
+      <entry name="!?*.groovy" />
+      <entry name="!?*.scala" />
+      <entry name="!?*.flex" />
+      <entry name="!?*.kt" />
+      <entry name="!?*.clj" />
+    </wildcardResourcePatterns>
+    <annotationProcessing>
+      <profile default="true" name="Default" enabled="false">
+        <processorPath useClasspath="true" />
+      </profile>
+    </annotationProcessing>
+  </component>
+</project>
\ No newline at end of file
diff --git a/idea/java/.idea/copyright/JetBrains.xml b/idea/java/.idea/copyright/JetBrains.xml
new file mode 100644
index 0000000..e0fbec0
--- /dev/null
+++ b/idea/java/.idea/copyright/JetBrains.xml
@@ -0,0 +1,9 @@
+<component name="CopyrightManager">
+  <copyright>
+    <option name="notice" value="Copyright 2000-&amp;#36;today.year JetBrains s.r.o.&#10;&#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10;http://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
+    <option name="keyword" value="Copyright" />
+    <option name="allowReplaceKeyword" value="JetBrains" />
+    <option name="myName" value="JetBrains" />
+    <option name="myLocal" value="true" />
+  </copyright>
+</component>
\ No newline at end of file
diff --git a/idea/java/.idea/copyright/profiles_settings.xml b/idea/java/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..4c0f48a
--- /dev/null
+++ b/idea/java/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,3 @@
+<component name="CopyrightManager">
+  <settings default="JetBrains" />
+</component>
\ No newline at end of file
diff --git a/idea/java/.idea/encodings.xml b/idea/java/.idea/encodings.xml
new file mode 100644
index 0000000..97626ba
--- /dev/null
+++ b/idea/java/.idea/encodings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding">
+    <file url="PROJECT" charset="UTF-8" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/idea/java/.idea/misc.xml b/idea/java/.idea/misc.xml
new file mode 100644
index 0000000..600bd87
--- /dev/null
+++ b/idea/java/.idea/misc.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="EntryPointsManager">
+    <entry_points version="2.0" />
+  </component>
+  <component name="ProjectLevelVcsManager" settingsEditedManually="false">
+    <OptionsSetting value="true" id="Add" />
+    <OptionsSetting value="true" id="Remove" />
+    <OptionsSetting value="true" id="Checkout" />
+    <OptionsSetting value="true" id="Update" />
+    <OptionsSetting value="true" id="Status" />
+    <OptionsSetting value="true" id="Edit" />
+    <ConfirmationsSetting value="0" id="Add" />
+    <ConfirmationsSetting value="0" id="Remove" />
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" assert-keyword="true" jdk-15="true" project-jdk-name="JBSDK" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/out" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/idea/java/.idea/modules.xml b/idea/java/.idea/modules.xml
new file mode 100644
index 0000000..78b4806
--- /dev/null
+++ b/idea/java/.idea/modules.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/osx/osx.iml" filepath="$PROJECT_DIR$/osx/osx.iml" />
+      <module fileurl="file://$PROJECT_DIR$/share/share.iml" filepath="$PROJECT_DIR$/share/share.iml" />
+      <module fileurl="file://$PROJECT_DIR$/solaris/solaris.iml" filepath="$PROJECT_DIR$/solaris/solaris.iml" />
+      <module fileurl="file://$PROJECT_DIR$/tests/tests.iml" filepath="$PROJECT_DIR$/tests/tests.iml" />
+      <module fileurl="file://$PROJECT_DIR$/windows/windows.iml" filepath="$PROJECT_DIR$/windows/windows.iml" />
+    </modules>
+  </component>
+</project>
\ No newline at end of file
diff --git a/idea/java/.idea/runConfigurations/AlphaSurfaceText.xml b/idea/java/.idea/runConfigurations/AlphaSurfaceText.xml
new file mode 100644
index 0000000..2ec7462
--- /dev/null
+++ b/idea/java/.idea/runConfigurations/AlphaSurfaceText.xml
@@ -0,0 +1,17 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="AlphaSurfaceText" type="Application" factoryName="Application" nameIsGenerated="true">
+    <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
+    <option name="MAIN_CLASS_NAME" value="AlphaSurfaceText" />
+    <option name="VM_PARAMETERS" value="-Xbootclasspath/p:$PROJECT_DIR$/out/production/osx:$PROJECT_DIR$/out/production/share" />
+    <option name="PROGRAM_PARAMETERS" value="" />
+    <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
+    <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
+    <option name="ALTERNATIVE_JRE_PATH" value="JBRE" />
+    <option name="ENABLE_SWING_INSPECTOR" value="false" />
+    <option name="ENV_VARIABLES" />
+    <option name="PASS_PARENT_ENVS" value="true" />
+    <module name="tests" />
+    <envs />
+    <method />
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/idea/java/.idea/vcs.xml b/idea/java/.idea/vcs.xml
new file mode 100644
index 0000000..b2bdec2
--- /dev/null
+++ b/idea/java/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/idea/java/jdk.iml b/idea/java/jdk.iml
new file mode 100644
index 0000000..c90834f
--- /dev/null
+++ b/idea/java/jdk.iml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/idea/java/osx/osx.iml b/idea/java/osx/osx.iml
new file mode 100644
index 0000000..bba2450
--- /dev/null
+++ b/idea/java/osx/osx.iml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$/../../../src/macosx/classes">
+      <sourceFolder url="file://$MODULE_DIR$/../../../src/macosx/classes" isTestSource="false" />
+    </content>
+    <orderEntry type="module" module-name="share" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="inheritedJdk" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/idea/java/share/share.iml b/idea/java/share/share.iml
new file mode 100644
index 0000000..b7c7736
--- /dev/null
+++ b/idea/java/share/share.iml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$/../../../src/share/classes">
+      <sourceFolder url="file://$MODULE_DIR$/../../../src/share/classes" isTestSource="false" />
+      <excludeFolder url="file://$MODULE_DIR$/../../../src/share/classes/com/sun/jmx" />
+      <excludeFolder url="file://$MODULE_DIR$/../../../src/share/classes/com/sun/management" />
+      <excludeFolder url="file://$MODULE_DIR$/../../../src/share/classes/javax/management" />
+      <excludeFolder url="file://$MODULE_DIR$/../../../src/share/classes/sun/dc" />
+      <excludeFolder url="file://$MODULE_DIR$/../../../src/share/classes/sun/management" />
+      <excludeFolder url="file://$MODULE_DIR$/../../../src/share/classes/sun/tools/jconsole" />
+    </content>
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="inheritedJdk" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/idea/java/solaris/solaris.iml b/idea/java/solaris/solaris.iml
new file mode 100644
index 0000000..42b80ca
--- /dev/null
+++ b/idea/java/solaris/solaris.iml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$/../../../src/solaris/classes">
+      <sourceFolder url="file://$MODULE_DIR$/../../../src/solaris/classes" isTestSource="false" />
+      <excludeFolder url="file://$MODULE_DIR$/../../../src/solaris/classes/sun/nio" />
+    </content>
+    <orderEntry type="module" module-name="share" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="inheritedJdk" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/idea/java/tests/lib/ant-junit4.jar b/idea/java/tests/lib/ant-junit4.jar
new file mode 100644
index 0000000..43a27e8
--- /dev/null
+++ b/idea/java/tests/lib/ant-junit4.jar
Binary files differ
diff --git a/idea/java/tests/lib/hamcrest-core-1.3.jar b/idea/java/tests/lib/hamcrest-core-1.3.jar
new file mode 100644
index 0000000..9d5fe16
--- /dev/null
+++ b/idea/java/tests/lib/hamcrest-core-1.3.jar
Binary files differ
diff --git a/idea/java/tests/lib/junit-4.12.jar b/idea/java/tests/lib/junit-4.12.jar
new file mode 100644
index 0000000..3a7fc26
--- /dev/null
+++ b/idea/java/tests/lib/junit-4.12.jar
Binary files differ
diff --git a/idea/java/tests/perf_tests.xml b/idea/java/tests/perf_tests.xml
new file mode 100644
index 0000000..8c547e8
--- /dev/null
+++ b/idea/java/tests/perf_tests.xml
@@ -0,0 +1,44 @@
+<project name="PerfTests" default="run" basedir=".">
+    <description>
+        JBRE Performance tests
+    </description>
+    <property name="src" location="src"/>
+    <property name="lib" location="lib"/>
+    <property name="build" location="build"/>
+    <property name="test_jvm" location="../../../jbsdk/jdk/Contents/Home/bin/java"/>
+
+    <target name="init">
+        <tstamp/>
+        <mkdir dir="${build}"/>
+    </target>
+
+    <target name="compile" depends="init"
+            description="compile the source">
+        <javac srcdir="${src}" destdir="${build}">
+            <classpath>
+                <pathelement location="${lib}/junit-4.12.jar" />
+            </classpath>
+        </javac>
+    </target>
+
+    <target name="run"  depends="compile">
+        <junit printsummary="on" haltonfailure="no" showoutput="on" fork="yes" jvm="${test_jvm}">
+            <classpath>
+                <pathelement location="${lib}/junit-4.12.jar" />
+                <pathelement location="${lib}/hamcrest-core-1.3.jar" />
+                <pathelement location="${build}"/>
+            </classpath>
+            <formatter type="plain" />
+
+            <test name="performance.text.LCDTextAreaScrollingTest"/>
+            <test name="performance.text.HugeLCDTextAreaScrollingTest"/>
+            <test name="performance.text.GreyscaleTextAreaScrollingTest"/>
+            <test name="performance.text.HugeGreyscaleTextAreaScrollingTest"/>
+        </junit>
+    </target>
+
+    <target name="clean"
+            description="clean up">
+        <delete dir="${build}"/>
+    </target>
+</project>
\ No newline at end of file
diff --git a/idea/java/tests/quality_tests.xml b/idea/java/tests/quality_tests.xml
new file mode 100644
index 0000000..d54d721
--- /dev/null
+++ b/idea/java/tests/quality_tests.xml
@@ -0,0 +1,70 @@
+<project name="QualityTests" default="run" basedir=".">
+<description>
+        JBRE Quality tests
+    </description>
+
+    <condition property="isWindows">
+        <os family="windows" />
+    </condition>
+
+    <condition property="isLinux">
+        <os family="unix" />
+    </condition>
+
+    <condition property="isMac">
+        <os family="mac" />
+    </condition>
+
+    <property name="src" location="src"/>
+    <property name="lib" location="lib"/>
+    <property name="testdata" location="testdata"/>
+    <property name="build" location="build"/>
+
+    <target name="set_test_jvm_mac" if="isMac">
+        <property name="test_jvm" location="../../../jbsdk/jdk/Contents/Home/bin/java"/>
+        <property name="test_javac" location="../../../jbsdk/jdk/Contents/Home/bin/javac"/>
+    </target>
+
+    <target name="set_test_jvm_linux" if="isLinux">
+        <property name="test_jvm" location="../../../jbsdk/bin/java"/>
+        <property name="test_javac" location="../../../jbsdk/bin/javac"/>
+    </target>
+
+    <target name="set_test_jvm_windows" if="isWindows">
+        <property name="test_jvm" location="../../../jbsdk/bin/java.exe"/>
+        <property name="test_javac" location="../../../jbsdk/bin/javac.exe"/>
+    </target>
+
+    <target name="init">
+        <tstamp/>
+        <mkdir dir="${build}"/>
+    </target>
+
+    <target name="compile" depends="init,set_test_jvm_mac, set_test_jvm_windows, set_test_jvm_linux"
+            description="compile the source">
+        <javac srcdir="${src}" destdir="${build}" executable="${test_javac}" fork="yes">
+            <classpath>
+                <pathelement location="${lib}/junit-4.12.jar" />
+            </classpath>
+        </javac>
+    </target>
+
+    <target name="run"  depends="compile">
+        <junit printsummary="on" haltonfailure="no" showoutput="on" fork="yes" jvm="${test_jvm}">
+            <classpath>
+                <pathelement location="${lib}/junit-4.12.jar" />
+                <pathelement location="${lib}/hamcrest-core-1.3.jar" />
+                <pathelement location="${build}"/>
+            </classpath>
+            <jvmarg value="-Dtestdata=${testdata}" />
+            <formatter type="plain" />
+
+            <test name="quality.text.DroidFontTest"/>
+        </junit>
+    </target>
+
+    <target name="clean"
+            description="clean up">
+        <delete dir="${build}"/>
+    </target>
+</project>
diff --git a/idea/java/tests/src/ScreenPaintingCaptor.java b/idea/java/tests/src/ScreenPaintingCaptor.java
new file mode 100644
index 0000000..26347a3
--- /dev/null
+++ b/idea/java/tests/src/ScreenPaintingCaptor.java
@@ -0,0 +1,47 @@
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.util.function.Consumer;
+import javax.swing.*;
+
+public class ScreenPaintingCaptor {
+    public static BufferedImage capture(int width, int height, Consumer<Graphics2D> painter) throws Exception {
+        JFrame[] f = new JFrame[1];
+        Point[] p = new Point[1];
+        SwingUtilities.invokeAndWait(() -> {
+            f[0] = new JFrame();
+            JComponent c = new MyComponent(painter);
+            f[0].add(c);
+            c.setSize(width + 2, height + 2);
+            f[0].setSize(width + 100, height + 100); // giving some space for frame border effects, e.g. rounded frame
+            c.setLocation(50, 50);
+            f[0].setVisible(true);
+            p[0]= c.getLocationOnScreen();
+        });
+        Robot r = new Robot();
+        while (!Color.black.equals(r.getPixelColor(p[0].x, p[0].y))) {
+            Thread.sleep(100);
+        }
+        BufferedImage i = r.createScreenCapture(new Rectangle(p[0].x + 1, p[0].y + 1, width, height));
+        SwingUtilities.invokeAndWait(f[0]::dispose);
+        return i;
+    }
+
+    private static class MyComponent extends JComponent {
+        private final Consumer<Graphics2D> painter;
+
+        private MyComponent(Consumer<Graphics2D> painter) {
+            this.painter = painter;
+        }
+
+        @Override
+        protected void paintComponent(Graphics g) {
+            g.translate(1, 1);
+            Shape savedClip = g.getClip();
+            g.clipRect(0, 0, getWidth() - 2, getHeight() - 2);
+            painter.accept((Graphics2D)g);
+            g.setClip(savedClip);
+            g.setColor(Color.black);
+            g.drawRect(-1, -1, getWidth() - 1, getHeight() - 1);
+        }
+    }
+}
diff --git a/idea/java/tests/src/performance/BaseScrollingPerformanceTest.java b/idea/java/tests/src/performance/BaseScrollingPerformanceTest.java
new file mode 100644
index 0000000..0f264da
--- /dev/null
+++ b/idea/java/tests/src/performance/BaseScrollingPerformanceTest.java
@@ -0,0 +1,1022 @@
+package performance;
+import sun.swing.SwingUtilities2;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.concurrent.Semaphore;
+
+public abstract class BaseScrollingPerformanceTest extends JFrame {
+
+    protected static SwingUtilities2.AATextInfo SUBPIXEL_HINT = new SwingUtilities2.AATextInfo(
+            RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB, 100);
+
+    protected static SwingUtilities2.AATextInfo GREYSCALE_HINT = new SwingUtilities2.AATextInfo(
+            RenderingHints.VALUE_TEXT_ANTIALIAS_ON, 100);
+
+    protected static String hugeText =
+            "sdfsdffffffffffffffffffffffsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfdsfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "dsfsdfsdfdfddddddddddddddddddddddddddddddddddddddddffsdfsegjoijogjoijodifjg" +
+            "sdfsdffffffffffffffffffffffsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfdsfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "fsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsfdfsdfsdfsdfsdfsdffdsfsdfsdfsdfsdfsdfsd" +
+            "dsfsdfsdfdfddddddddddddddddddddddddddddddddddddddddffsdfsegjoijogjoijodifjg";
+
+    @SuppressWarnings("FieldCanBeLocal")
+    private static int N0 = 200;
+    private static int N1 = 400;
+
+    private static volatile int count = 0;
+    private static volatile long overallTime = 0;
+    private static volatile long time = 0;
+
+    private static Semaphore s = new Semaphore(1);
+
+    private JComponent component;
+    private String message;
+
+    public BaseScrollingPerformanceTest(String message) {
+        this.message = message;
+        component = createComponent();
+
+        JScrollPane comp = new JScrollPane(component);
+        configureScrollPane(comp);
+        add(comp);
+        setPreferredSize(new Dimension(1000, 800));
+        pack();
+    }
+
+    private static volatile BaseScrollingPerformanceTest test;
+
+    public static void doInitCounts(int nWarmUp, int nMeasure) {
+        N0 = nWarmUp;
+        N1 = nMeasure;
+        count = 0;
+    }
+
+    public static void doBeginPaint() {
+        if (count >= N0) {
+            time = System.currentTimeMillis();
+        }
+    }
+
+    public static void doEndPaint() {
+        count++;
+        if (count > N0) {
+            overallTime += System.currentTimeMillis() - time;
+            if (count >= N1 + N0) {
+                System.err.println("value='" + (double) overallTime / N1 + "']");
+                System.out.println((double) overallTime / N1);
+                count = 0;
+                s.release();
+                overallTime = 0;
+            }
+        }
+
+    }
+
+    protected static void doTest(BaseScrollingPerformanceTest testCase, int n0, int n1) {
+        try {
+            s.acquire();
+        } catch (InterruptedException e) {
+            throw new RuntimeException("Cannot start test");
+        }
+
+        doInitCounts(n0, n1);
+        SwingUtilities.invokeLater(() -> {
+            test = testCase;
+            test.setVisible(true);
+            test.component.requestFocus();
+        });
+
+        doScroll(N0);
+
+        SwingUtilities.invokeLater(() -> {
+            System.err.print(test.getMessage());
+        });
+
+        doScroll(N1);
+
+        try {
+            s.acquire();
+            test.setVisible(false);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+            throw new RuntimeException(e.getMessage());
+        } finally {
+            s.release();
+        }
+    }
+
+    private static void doScroll(int n) {
+        for (int i = 0; i < n; i++) {
+            SwingUtilities.invokeLater(() -> {
+                try {
+                    test.component.requestFocus();
+                    Robot robot = new Robot();
+                    robot.mouseMove(test.getX() + 100, test.getY() + 100);
+                    robot.mouseWheel(100);
+
+
+                } catch (AWTException e) {
+                    e.printStackTrace();
+                }
+            });
+
+            SwingUtilities.invokeLater(() -> {
+                try {
+                    test.component.requestFocus();
+                    Robot robot = new Robot();
+                    robot.mouseMove(test.getX() + 100, test.getY() + 100);
+                    robot.mouseWheel(-100);
+
+                } catch (AWTException e) {
+                    e.printStackTrace();
+                }
+            });
+        }
+    }
+
+    protected abstract JComponent createComponent();
+    protected abstract void configureScrollPane(JScrollPane scrollPane);
+
+    public String getMessage() {
+        return message;
+    }
+
+    protected JComponent createTextArea() {
+        MyTextArea textArea = new MyTextArea();
+        textArea.setColumns(120);
+        textArea.setLineWrap(true);
+        textArea.setRows(80);
+        textArea.setWrapStyleWord(true);
+        textArea.setText(hugeText);
+        return textArea;
+    }
+
+    class MyTextArea extends JTextArea {
+        @Override
+        public void paint(Graphics g) {
+            doBeginPaint();
+            super.paint(g);
+            doEndPaint();
+        }
+    }
+}
diff --git a/idea/java/tests/src/performance/text/GreyscaleTextAreaScrollingTest.java b/idea/java/tests/src/performance/text/GreyscaleTextAreaScrollingTest.java
new file mode 100644
index 0000000..653293f
--- /dev/null
+++ b/idea/java/tests/src/performance/text/GreyscaleTextAreaScrollingTest.java
@@ -0,0 +1,29 @@
+package performance.text;
+
+import org.junit.Test;
+import performance.BaseScrollingPerformanceTest;
+import sun.swing.SwingUtilities2;
+
+import javax.swing.*;
+
+public class GreyscaleTextAreaScrollingTest extends BaseScrollingPerformanceTest {
+    public GreyscaleTextAreaScrollingTest() {
+        super("##teamcity[buildStatisticValue key='GreyscaleTextAreaScrolling' ");
+    }
+
+    @Test
+    public void testTextAreaScrolling() {
+        doTest(this, 200, 400);
+    }
+
+    protected JComponent createComponent() {
+        JComponent textArea = createTextArea();
+        textArea.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, GREYSCALE_HINT);
+        return textArea;
+    }
+
+    @Override
+    protected void configureScrollPane(JScrollPane scrollPane) {
+        scrollPane.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, GREYSCALE_HINT);
+    }
+}
diff --git a/idea/java/tests/src/performance/text/HugeGreyscaleTextAreaScrollingTest.java b/idea/java/tests/src/performance/text/HugeGreyscaleTextAreaScrollingTest.java
new file mode 100644
index 0000000..ebe8f2e
--- /dev/null
+++ b/idea/java/tests/src/performance/text/HugeGreyscaleTextAreaScrollingTest.java
@@ -0,0 +1,31 @@
+package performance.text;
+
+import org.junit.Test;
+import performance.BaseScrollingPerformanceTest;
+import sun.swing.SwingUtilities2;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class HugeGreyscaleTextAreaScrollingTest extends BaseScrollingPerformanceTest {
+    public HugeGreyscaleTextAreaScrollingTest() {
+        super("##teamcity[buildStatisticValue key='HugeGreyscaleTextAreaScrolling' ");
+    }
+
+    @Test
+    public void testTextAreaScrolling() {
+        doTest(this, 4, 8);
+    }
+
+    protected JComponent createComponent() {
+        JComponent textArea = createTextArea();
+        textArea.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, GREYSCALE_HINT);
+        textArea.setFont(new Font("Dialog", Font.PLAIN, 50));
+        return textArea;
+    }
+
+    @Override
+    protected void configureScrollPane(JScrollPane scrollPane) {
+        scrollPane.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, GREYSCALE_HINT);
+    }
+}
diff --git a/idea/java/tests/src/performance/text/HugeLCDTextAreaScrollingTest.java b/idea/java/tests/src/performance/text/HugeLCDTextAreaScrollingTest.java
new file mode 100644
index 0000000..c71b591
--- /dev/null
+++ b/idea/java/tests/src/performance/text/HugeLCDTextAreaScrollingTest.java
@@ -0,0 +1,31 @@
+package performance.text;
+
+import org.junit.Test;
+import performance.BaseScrollingPerformanceTest;
+import sun.swing.SwingUtilities2;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class HugeLCDTextAreaScrollingTest extends BaseScrollingPerformanceTest {
+    public HugeLCDTextAreaScrollingTest() {
+        super("##teamcity[buildStatisticValue key='HugeLCDTextAreaScrolling' ");
+    }
+
+    @Test
+    public void testTextAreaScrolling() {
+        doTest(this, 4, 8);
+    }
+
+    protected JComponent createComponent() {
+        JComponent textArea = createTextArea();
+        textArea.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, SUBPIXEL_HINT);
+        textArea.setFont(new Font("Dialog", Font.PLAIN, 50));
+        return textArea;
+    }
+
+    @Override
+    protected void configureScrollPane(JScrollPane scrollPane) {
+        scrollPane.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, SUBPIXEL_HINT);
+    }
+}
diff --git a/idea/java/tests/src/performance/text/LCDTextAreaScrollingTest.java b/idea/java/tests/src/performance/text/LCDTextAreaScrollingTest.java
new file mode 100644
index 0000000..1657db8
--- /dev/null
+++ b/idea/java/tests/src/performance/text/LCDTextAreaScrollingTest.java
@@ -0,0 +1,29 @@
+package performance.text;
+
+import org.junit.Test;
+import performance.BaseScrollingPerformanceTest;
+import sun.swing.SwingUtilities2;
+
+import javax.swing.*;
+
+public class LCDTextAreaScrollingTest extends BaseScrollingPerformanceTest {
+    public LCDTextAreaScrollingTest() {
+        super("##teamcity[buildStatisticValue key='LCDTextAreaScrolling' ");
+    }
+
+    @Test
+    public void testTextAreaScrolling() {
+        doTest(this, 200, 400);
+    }
+
+    protected JComponent createComponent() {
+        JComponent textArea = createTextArea();
+        textArea.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, SUBPIXEL_HINT);
+        return textArea;
+    }
+
+    @Override
+    protected void configureScrollPane(JScrollPane scrollPane) {
+        scrollPane.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, SUBPIXEL_HINT);
+    }
+}
diff --git a/idea/java/tests/src/performance/text/SimpleRealPaintingPerformanceTest.java b/idea/java/tests/src/performance/text/SimpleRealPaintingPerformanceTest.java
new file mode 100644
index 0000000..08cdcf0
--- /dev/null
+++ b/idea/java/tests/src/performance/text/SimpleRealPaintingPerformanceTest.java
@@ -0,0 +1,55 @@
+package performance.text;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.font.GlyphVector;
+import java.awt.image.BufferedImage;
+import java.util.concurrent.locks.LockSupport;
+
+public class SimpleRealPaintingPerformanceTest {
+    public static void main(String[] args) {
+        Graphics2D g2d = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB).createGraphics();
+        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
+        g2d.drawString("a", 10, 10);
+
+        SwingUtilities.invokeLater(() -> {
+            JFrame f = new JFrame() {
+                @Override
+                public void paint(Graphics g) {
+                    Graphics2D g2d = (Graphics2D) g;
+                    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
+                    g2d.drawString("a", 10, 10);
+                    super.paint(g);
+                }
+            };
+            f.add(new MyComponent());
+            f.setSize(1000, 1000);
+            f.setLocationRelativeTo(null);
+            f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+            f.setVisible(true);
+        });
+    }
+
+    private static class MyComponent extends JComponent {
+        Font font = new Font("Menlo", Font.PLAIN, 12);
+        String text = "abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi ";
+
+        @Override
+        protected void paintComponent(Graphics g1) {
+            Graphics2D g = (Graphics2D) g1;
+            g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
+
+            GlyphVector gv = font.layoutGlyphVector(g.getFontRenderContext(), text.toCharArray(), 0, text.length(), Font.LAYOUT_LEFT_TO_RIGHT);
+
+            while (true) {
+                long t = System.currentTimeMillis();
+                for (int i = 0; i < 10000; i++) {
+                    g.drawGlyphVector(gv, 100, 100);
+                }
+                System.out.println(System.currentTimeMillis() - t);
+
+                LockSupport.parkNanos(1_000_000_000L);
+            }
+        }
+    }
+}
diff --git a/idea/java/tests/src/quality/text/DroidFontTest.java b/idea/java/tests/src/quality/text/DroidFontTest.java
new file mode 100644
index 0000000..ef796af
--- /dev/null
+++ b/idea/java/tests/src/quality/text/DroidFontTest.java
@@ -0,0 +1,172 @@
+package quality.text;
+
+import org.junit.Test;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.Raster;
+import java.io.File;
+
+import static org.junit.Assert.*;
+
+public class DroidFontTest {
+    /* Tests for the following font names and styles:
+
+            "droid sans" : PLAIN, BOLD
+            "droid sans bold" : alias for "droid sans"
+
+            "droid sans mono" : PLAIN
+            "droid sans mono slashed" : PLAIN
+            "droid sans mono dotted" : PLAIN
+
+            "droid serif" : PLAIN, BOLD, ITALIC, BOLD | ITALIC
+
+            "droid serif bold" : alias for "droid serif" BOLD, BOLD | ITALIC
+    */
+
+    private static final String abc =
+            "the quick brown fox jumps over the lazy dog";
+
+    private static final String digits = "0123456789";
+
+    @SuppressWarnings("SameParameterValue")
+    private void doTestFont(String aliasName, String name, int style, int size)
+            throws Exception {
+
+        String[] testDataVariant = {
+                "osx_hardware_rendering", "osx_software_rendering", "linux_rendering"};
+
+        String testDataStr = System.getProperty("testdata");
+        assertNotNull("testdata property is not set", testDataStr);
+
+        File testData = new File(testDataStr, "quality" + File.separator +
+                "text");
+        assertTrue("Test data dir does not exist", testData.exists());
+
+        String testStr = abc.toUpperCase() + abc + digits;
+
+        BufferedImage image = new BufferedImage((size + 3)*testStr.length(),
+                size*3, BufferedImage.TYPE_INT_RGB);
+        Graphics2D g2d = image.createGraphics();
+
+        Font f = new Font(aliasName, style, size);
+
+        g2d.setFont(f);
+        g2d.setColor(Color.WHITE);
+        Rectangle2D bnd = f.getStringBounds(testStr,
+                g2d.getFontRenderContext());
+
+        g2d.drawString(testStr, 0, size + 3);
+
+
+        BufferedImage resultImage = image.getSubimage((int) bnd.getX(),
+                (int) (size + 3 + bnd.getY()),
+                (int) bnd.getWidth(), (int) bnd.getHeight());
+
+        String gfName = name.toLowerCase().replace(" ", "") +
+                Integer.toString(style) + "_" + Integer.toString(size) + ".png";
+
+        if (System.getProperty("gentestdata") == null) {
+            boolean failed = true;
+            String failureReason = "";
+            for (String variant : testDataVariant) {
+                File goldenFile = new File(testData, variant + File.separator +
+                        gfName);
+
+                BufferedImage goldenImage = ImageIO.read(goldenFile);
+                failed = true;
+                if (resultImage.getWidth() != goldenImage.getWidth() ||
+                    resultImage.getHeight() != resultImage.getHeight())
+                {
+                    failureReason += variant +
+                            " : Golden image and result have different sizes\n";
+                    continue;
+                }
+
+                Raster gRaster = goldenImage.getData();
+                Raster rRaster = resultImage.getData();
+                int[] gArr = new int[3];
+                int[] rArr = new int[3];
+                failed = false;
+                scan:
+                for (int i = 0; i < gRaster.getWidth(); i++) {
+                    for (int j = 0; j < gRaster.getHeight(); j++) {
+                        gRaster.getPixel(i, j, gArr);
+                        rRaster.getPixel(i, j, rArr);
+                        assertTrue(gArr.length == rArr.length);
+                        for (int k = 0; k < gArr.length; k++) {
+                            if (gArr[k] != rArr[k]) {
+                                failureReason += variant +
+                                        " : Different pixels found " +
+                                        "at (" + i + "," + j + ")";
+                                failed = true;
+                                break scan;
+                            }
+                        }
+                    }
+                }
+
+                if (!failed) break;
+            }
+
+            if (failed) throw new RuntimeException(failureReason);
+        }
+        else {
+            ImageIO.write(resultImage, "png", new File(testData, gfName));
+        }
+    }
+
+    private void doTestFont(String name, int style)
+            throws Exception {
+        doTestFont(name, name, style, 20);
+    }
+
+        @Test
+    public void testDroidSans() throws Exception {
+        doTestFont("Droid Sans", Font.PLAIN);
+    }
+
+    @Test
+    public void testDroidSansBold() throws Exception {
+        doTestFont("Droid Sans", Font.BOLD);
+        doTestFont("Droid Sans Bold", "Droid Sans", Font.BOLD, 20);
+    }
+
+    @Test
+    public void testDroidSansMono() throws Exception {
+        doTestFont("Droid Sans Mono", Font.PLAIN);
+    }
+
+    @Test
+    public void testDroidSansMonoSlashed() throws Exception {
+        doTestFont("Droid Sans Mono Slashed", Font.PLAIN);
+    }
+
+    @Test
+    public void testDroidSansMonoDotted() throws Exception {
+        doTestFont("Droid Sans Mono Dotted", Font.PLAIN);
+    }
+
+    @Test
+    public void testDroidSerif() throws Exception {
+        doTestFont("Droid Serif", Font.PLAIN);
+    }
+
+    @Test
+    public void testDroidSerifBold() throws Exception {
+        doTestFont("Droid Serif", Font.BOLD);
+        doTestFont("Droid Serif Bold", "Droid Serif",
+                Font.BOLD, 20);
+        doTestFont("Droid Serif Bold", "Droid Serif",
+                Font.BOLD | Font.ITALIC, 20);
+    }
+
+    @Test
+    public void testDroidSerifItalic() throws Exception {
+        doTestFont("Droid Serif", Font.ITALIC);
+        doTestFont("Droid Serif Italic", "Droid Serif",
+                Font.ITALIC, 20);
+    }
+}
diff --git a/idea/java/tests/testdata/quality/text/linux_rendering/droidsans0_20.png b/idea/java/tests/testdata/quality/text/linux_rendering/droidsans0_20.png
new file mode 100644
index 0000000..574c9a6
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/linux_rendering/droidsans0_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/linux_rendering/droidsans1_20.png b/idea/java/tests/testdata/quality/text/linux_rendering/droidsans1_20.png
new file mode 100644
index 0000000..4482b5f
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/linux_rendering/droidsans1_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/linux_rendering/droidsansmono0_20.png b/idea/java/tests/testdata/quality/text/linux_rendering/droidsansmono0_20.png
new file mode 100644
index 0000000..9a94772
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/linux_rendering/droidsansmono0_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/linux_rendering/droidsansmonodotted0_20.png b/idea/java/tests/testdata/quality/text/linux_rendering/droidsansmonodotted0_20.png
new file mode 100644
index 0000000..8b68a6d
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/linux_rendering/droidsansmonodotted0_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/linux_rendering/droidsansmonoslashed0_20.png b/idea/java/tests/testdata/quality/text/linux_rendering/droidsansmonoslashed0_20.png
new file mode 100644
index 0000000..bdb202b
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/linux_rendering/droidsansmonoslashed0_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/linux_rendering/droidserif0_20.png b/idea/java/tests/testdata/quality/text/linux_rendering/droidserif0_20.png
new file mode 100644
index 0000000..2b24d22
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/linux_rendering/droidserif0_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/linux_rendering/droidserif1_20.png b/idea/java/tests/testdata/quality/text/linux_rendering/droidserif1_20.png
new file mode 100644
index 0000000..307074f
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/linux_rendering/droidserif1_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/linux_rendering/droidserif2_20.png b/idea/java/tests/testdata/quality/text/linux_rendering/droidserif2_20.png
new file mode 100644
index 0000000..35c1171
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/linux_rendering/droidserif2_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/linux_rendering/droidserif3_20.png b/idea/java/tests/testdata/quality/text/linux_rendering/droidserif3_20.png
new file mode 100644
index 0000000..1fd8439
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/linux_rendering/droidserif3_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidsans0_20.png b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidsans0_20.png
new file mode 100644
index 0000000..70e6f56
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidsans0_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidsans1_20.png b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidsans1_20.png
new file mode 100644
index 0000000..b8386dc
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidsans1_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidsansmono0_20.png b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidsansmono0_20.png
new file mode 100644
index 0000000..cf1a89d
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidsansmono0_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidsansmonodotted0_20.png b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidsansmonodotted0_20.png
new file mode 100644
index 0000000..9f68c5b
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidsansmonodotted0_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidsansmonoslashed0_20.png b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidsansmonoslashed0_20.png
new file mode 100644
index 0000000..da76dda
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidsansmonoslashed0_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidserif0_20.png b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidserif0_20.png
new file mode 100644
index 0000000..8f7b89e
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidserif0_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidserif1_20.png b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidserif1_20.png
new file mode 100644
index 0000000..32d0dff
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidserif1_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidserif2_20.png b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidserif2_20.png
new file mode 100644
index 0000000..2e3b1b3
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidserif2_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidserif3_20.png b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidserif3_20.png
new file mode 100644
index 0000000..1fd8439
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_hardware_rendering/droidserif3_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_software_rendering/droidsans0_20.png b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidsans0_20.png
new file mode 100644
index 0000000..70e6f56
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidsans0_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_software_rendering/droidsans1_20.png b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidsans1_20.png
new file mode 100644
index 0000000..b8386dc
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidsans1_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_software_rendering/droidsansmono0_20.png b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidsansmono0_20.png
new file mode 100644
index 0000000..cf1a89d
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidsansmono0_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_software_rendering/droidsansmonodotted0_20.png b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidsansmonodotted0_20.png
new file mode 100644
index 0000000..9f68c5b
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidsansmonodotted0_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_software_rendering/droidsansmonoslashed0_20.png b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidsansmonoslashed0_20.png
new file mode 100644
index 0000000..da76dda
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidsansmonoslashed0_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_software_rendering/droidserif0_20.png b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidserif0_20.png
new file mode 100644
index 0000000..8f7b89e
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidserif0_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_software_rendering/droidserif1_20.png b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidserif1_20.png
new file mode 100644
index 0000000..32d0dff
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidserif1_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_software_rendering/droidserif2_20.png b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidserif2_20.png
new file mode 100644
index 0000000..2e3b1b3
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidserif2_20.png
Binary files differ
diff --git a/idea/java/tests/testdata/quality/text/osx_software_rendering/droidserif3_20.png b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidserif3_20.png
new file mode 100644
index 0000000..1fd8439
--- /dev/null
+++ b/idea/java/tests/testdata/quality/text/osx_software_rendering/droidserif3_20.png
Binary files differ
diff --git a/idea/java/tests/tests.iml b/idea/java/tests/tests.iml
new file mode 100644
index 0000000..0fa7fed
--- /dev/null
+++ b/idea/java/tests/tests.iml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+    </content>
+    <content url="file://$MODULE_DIR$/../../../test/java/awt/Graphics2D">
+      <sourceFolder url="file://$MODULE_DIR$/../../../test/java/awt/Graphics2D" isTestSource="false" />
+    </content>
+    <content url="file://$MODULE_DIR$/../../../test/sun/java2d">
+      <sourceFolder url="file://$MODULE_DIR$/../../../test/sun/java2d" isTestSource="false" />
+    </content>
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="file://$APPLICATION_HOME_DIR$/lib/junit-4.12.jar" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+        <jarDirectory url="file://$APPLICATION_HOME_DIR$/lib/junit-4.12.jar" recursive="false" />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="file://$APPLICATION_HOME_DIR$/lib/junit.jar" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+        <jarDirectory url="file://$APPLICATION_HOME_DIR$/lib/junit.jar" recursive="false" />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library name="JUnit4">
+        <CLASSES>
+          <root url="jar://$APPLICATION_HOME_DIR$/lib/junit-4.12.jar!/" />
+          <root url="jar://$APPLICATION_HOME_DIR$/lib/hamcrest-core-1.3.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+  </component>
+</module>
\ No newline at end of file
diff --git a/idea/java/windows/windows.iml b/idea/java/windows/windows.iml
new file mode 100644
index 0000000..97bdf50
--- /dev/null
+++ b/idea/java/windows/windows.iml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$/../../../src/windows/classes">
+      <sourceFolder url="file://$MODULE_DIR$/../../../src/windows/classes" isTestSource="false" />
+    </content>
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="share" />
+    <orderEntry type="inheritedJdk" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/idea/native/.idea/vcs.xml b/idea/native/.idea/vcs.xml
new file mode 100644
index 0000000..b2bdec2
--- /dev/null
+++ b/idea/native/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/idea/native/CMakeLists.txt b/idea/native/CMakeLists.txt
new file mode 100644
index 0000000..9437895
--- /dev/null
+++ b/idea/native/CMakeLists.txt
@@ -0,0 +1,1712 @@
+cmake_minimum_required(VERSION 3.4)
+project(jdk)
+
+include_directories(
+        ../../src/share/javavm/export
+        ../../src/share/native/common
+        ../../src/share/native/sun/font
+        ../../src/share/native/sun/java2d
+        ../../src/share/native/sun/java2d/loops)
+
+if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin" OR ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+    include_directories(
+            ../../src/solaris/native/common
+            ../../src/solaris/javavm/export)
+endif()
+
+if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+    include_directories(
+            ../../../build/macosx-x86_64-normal-server-release/jdk/gensrc_headers)
+elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+    include_directories(
+            ../../../build/linux-x86_64-normal-server-release/jdk/gensrc_headers)
+elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+    include_directories(
+            ../../src/windows/native/common
+            ../../src/windows/javavm/export
+            ../../../build/windows-x86_64-normal-server-release/jdk/gensrc_headers)
+endif()
+
+find_package(Freetype REQUIRED)
+include_directories(${FREETYPE_INCLUDE_DIRS})
+
+set(SOURCE_FILES
+    ../../src/share/javavm/export/classfile_constants.h
+    ../../src/share/javavm/export/jawt.h
+    ../../src/share/javavm/export/jdwpTransport.h
+    ../../src/share/javavm/export/jmm.h
+    ../../src/share/javavm/export/jni.h
+    ../../src/share/javavm/export/jvm.h
+    ../../src/share/javavm/export/jvmti.h
+    ../../src/share/javavm/export/jvmticmlr.h
+    ../../src/share/native/com/sun/java/util/jar/pack/bands.cpp
+    ../../src/share/native/com/sun/java/util/jar/pack/bands.h
+    ../../src/share/native/com/sun/java/util/jar/pack/bytes.cpp
+    ../../src/share/native/com/sun/java/util/jar/pack/bytes.h
+    ../../src/share/native/com/sun/java/util/jar/pack/coding.cpp
+    ../../src/share/native/com/sun/java/util/jar/pack/coding.h
+    ../../src/share/native/com/sun/java/util/jar/pack/constants.h
+    ../../src/share/native/com/sun/java/util/jar/pack/defines.h
+    ../../src/share/native/com/sun/java/util/jar/pack/jni.cpp
+    ../../src/share/native/com/sun/java/util/jar/pack/main.cpp
+    ../../src/share/native/com/sun/java/util/jar/pack/unpack.cpp
+    ../../src/share/native/com/sun/java/util/jar/pack/unpack.h
+    ../../src/share/native/com/sun/java/util/jar/pack/utils.cpp
+    ../../src/share/native/com/sun/java/util/jar/pack/utils.h
+    ../../src/share/native/com/sun/java/util/jar/pack/zip.cpp
+    ../../src/share/native/com/sun/java/util/jar/pack/zip.h
+    ../../src/share/native/com/sun/media/sound/Configure.h
+    ../../src/share/native/com/sun/media/sound/DirectAudio.h
+    ../../src/share/native/com/sun/media/sound/DirectAudioDevice.c
+    ../../src/share/native/com/sun/media/sound/DirectAudioDeviceProvider.c
+    ../../src/share/native/com/sun/media/sound/MidiInDevice.c
+    ../../src/share/native/com/sun/media/sound/MidiInDeviceProvider.c
+    ../../src/share/native/com/sun/media/sound/MidiOutDevice.c
+    ../../src/share/native/com/sun/media/sound/MidiOutDeviceProvider.c
+    ../../src/share/native/com/sun/media/sound/Platform.c
+    ../../src/share/native/com/sun/media/sound/PlatformMidi.c
+    ../../src/share/native/com/sun/media/sound/PlatformMidi.h
+    ../../src/share/native/com/sun/media/sound/PortMixer.c
+    ../../src/share/native/com/sun/media/sound/PortMixerProvider.c
+    ../../src/share/native/com/sun/media/sound/Ports.h
+    ../../src/share/native/com/sun/media/sound/SoundDefs.h
+    ../../src/share/native/com/sun/media/sound/Utilities.c
+    ../../src/share/native/com/sun/media/sound/Utilities.h
+    ../../src/share/native/com/sun/tools/jdi/SharedMemory.h
+    ../../src/share/native/com/sun/tools/jdi/SharedMemoryConnection.c
+    ../../src/share/native/com/sun/tools/jdi/SharedMemoryTransport.c
+    ../../src/share/native/common/check_code.c
+    ../../src/share/native/common/check_format.c
+    ../../src/share/native/common/check_version.c
+    ../../src/share/native/common/gdefs.h
+    ../../src/share/native/common/jdk_util.c
+    ../../src/share/native/common/jdk_util.h
+    ../../src/share/native/common/jio.c
+    ../../src/share/native/common/jlong.h
+    ../../src/share/native/common/jni_util.c
+    ../../src/share/native/common/jni_util.h
+    ../../src/share/native/common/sizecalc.h
+    ../../src/share/native/common/verify_stub.c
+    ../../src/share/native/java/io/FileInputStream.c
+    ../../src/share/native/java/io/io_util.c
+    ../../src/share/native/java/io/io_util.h
+    ../../src/share/native/java/io/ObjectInputStream.c
+    ../../src/share/native/java/io/ObjectOutputStream.c
+    ../../src/share/native/java/io/ObjectStreamClass.c
+    ../../src/share/native/java/io/RandomAccessFile.c
+    ../../src/share/native/java/lang/fdlibm/include/fdlibm.h
+    ../../src/share/native/java/lang/fdlibm/include/jfdlibm.h
+    ../../src/share/native/java/lang/fdlibm/src/e_acos.c
+    ../../src/share/native/java/lang/fdlibm/src/e_asin.c
+    ../../src/share/native/java/lang/fdlibm/src/e_atan2.c
+    ../../src/share/native/java/lang/fdlibm/src/e_atanh.c
+    ../../src/share/native/java/lang/fdlibm/src/e_cosh.c
+    ../../src/share/native/java/lang/fdlibm/src/e_exp.c
+    ../../src/share/native/java/lang/fdlibm/src/e_fmod.c
+    ../../src/share/native/java/lang/fdlibm/src/e_hypot.c
+    ../../src/share/native/java/lang/fdlibm/src/e_log.c
+    ../../src/share/native/java/lang/fdlibm/src/e_log10.c
+    ../../src/share/native/java/lang/fdlibm/src/e_pow.c
+    ../../src/share/native/java/lang/fdlibm/src/e_rem_pio2.c
+    ../../src/share/native/java/lang/fdlibm/src/e_remainder.c
+    ../../src/share/native/java/lang/fdlibm/src/e_scalb.c
+    ../../src/share/native/java/lang/fdlibm/src/e_sinh.c
+    ../../src/share/native/java/lang/fdlibm/src/e_sqrt.c
+    ../../src/share/native/java/lang/fdlibm/src/k_cos.c
+    ../../src/share/native/java/lang/fdlibm/src/k_rem_pio2.c
+    ../../src/share/native/java/lang/fdlibm/src/k_sin.c
+    ../../src/share/native/java/lang/fdlibm/src/k_standard.c
+    ../../src/share/native/java/lang/fdlibm/src/k_tan.c
+    ../../src/share/native/java/lang/fdlibm/src/s_atan.c
+    ../../src/share/native/java/lang/fdlibm/src/s_cbrt.c
+    ../../src/share/native/java/lang/fdlibm/src/s_ceil.c
+    ../../src/share/native/java/lang/fdlibm/src/s_copysign.c
+    ../../src/share/native/java/lang/fdlibm/src/s_cos.c
+    ../../src/share/native/java/lang/fdlibm/src/s_expm1.c
+    ../../src/share/native/java/lang/fdlibm/src/s_fabs.c
+    ../../src/share/native/java/lang/fdlibm/src/s_finite.c
+    ../../src/share/native/java/lang/fdlibm/src/s_floor.c
+    ../../src/share/native/java/lang/fdlibm/src/s_frexp.c
+    ../../src/share/native/java/lang/fdlibm/src/s_ilogb.c
+    ../../src/share/native/java/lang/fdlibm/src/s_isnan.c
+    ../../src/share/native/java/lang/fdlibm/src/s_ldexp.c
+    ../../src/share/native/java/lang/fdlibm/src/s_lib_version.c
+    ../../src/share/native/java/lang/fdlibm/src/s_log1p.c
+    ../../src/share/native/java/lang/fdlibm/src/s_logb.c
+    ../../src/share/native/java/lang/fdlibm/src/s_matherr.c
+    ../../src/share/native/java/lang/fdlibm/src/s_modf.c
+    ../../src/share/native/java/lang/fdlibm/src/s_nextafter.c
+    ../../src/share/native/java/lang/fdlibm/src/s_rint.c
+    ../../src/share/native/java/lang/fdlibm/src/s_scalbn.c
+    ../../src/share/native/java/lang/fdlibm/src/s_signgam.c
+    ../../src/share/native/java/lang/fdlibm/src/s_significand.c
+    ../../src/share/native/java/lang/fdlibm/src/s_sin.c
+    ../../src/share/native/java/lang/fdlibm/src/s_tan.c
+    ../../src/share/native/java/lang/fdlibm/src/s_tanh.c
+    ../../src/share/native/java/lang/fdlibm/src/w_acos.c
+    ../../src/share/native/java/lang/fdlibm/src/w_asin.c
+    ../../src/share/native/java/lang/fdlibm/src/w_atan2.c
+    ../../src/share/native/java/lang/fdlibm/src/w_atanh.c
+    ../../src/share/native/java/lang/fdlibm/src/w_cosh.c
+    ../../src/share/native/java/lang/fdlibm/src/w_exp.c
+    ../../src/share/native/java/lang/fdlibm/src/w_fmod.c
+    ../../src/share/native/java/lang/fdlibm/src/w_hypot.c
+    ../../src/share/native/java/lang/fdlibm/src/w_log.c
+    ../../src/share/native/java/lang/fdlibm/src/w_log10.c
+    ../../src/share/native/java/lang/fdlibm/src/w_pow.c
+    ../../src/share/native/java/lang/fdlibm/src/w_remainder.c
+    ../../src/share/native/java/lang/fdlibm/src/w_scalb.c
+    ../../src/share/native/java/lang/fdlibm/src/w_sinh.c
+    ../../src/share/native/java/lang/fdlibm/src/w_sqrt.c
+    ../../src/share/native/java/lang/reflect/Array.c
+    ../../src/share/native/java/lang/reflect/Executable.c
+    ../../src/share/native/java/lang/reflect/Field.c
+    ../../src/share/native/java/lang/reflect/Proxy.c
+    ../../src/share/native/java/lang/Class.c
+    ../../src/share/native/java/lang/ClassLoader.c
+    ../../src/share/native/java/lang/Compiler.c
+    ../../src/share/native/java/lang/Double.c
+    ../../src/share/native/java/lang/Float.c
+    ../../src/share/native/java/lang/java_props.h
+    ../../src/share/native/java/lang/Object.c
+    ../../src/share/native/java/lang/Package.c
+    ../../src/share/native/java/lang/Runtime.c
+    ../../src/share/native/java/lang/SecurityManager.c
+    ../../src/share/native/java/lang/Shutdown.c
+    ../../src/share/native/java/lang/StrictMath.c
+    ../../src/share/native/java/lang/String.c
+    ../../src/share/native/java/lang/System.c
+    ../../src/share/native/java/lang/Thread.c
+    ../../src/share/native/java/lang/Throwable.c
+    ../../src/share/native/java/net/DatagramPacket.c
+    ../../src/share/native/java/net/Inet4Address.c
+    ../../src/share/native/java/net/Inet6Address.c
+    ../../src/share/native/java/net/InetAddress.c
+    ../../src/share/native/java/net/net_util.c
+    ../../src/share/native/java/net/net_util.h
+    ../../src/share/native/java/nio/Bits.c
+    ../../src/share/native/java/security/AccessController.c
+    ../../src/share/native/java/util/concurrent/atomic/AtomicLong.c
+    ../../src/share/native/java/util/zip/zlib-1.2.8/compress.c
+    ../../src/share/native/java/util/zip/zlib-1.2.8/crc32.h
+    ../../src/share/native/java/util/zip/zlib-1.2.8/deflate.c
+    ../../src/share/native/java/util/zip/zlib-1.2.8/deflate.h
+    ../../src/share/native/java/util/zip/zlib-1.2.8/gzclose.c
+    ../../src/share/native/java/util/zip/zlib-1.2.8/gzguts.h
+    ../../src/share/native/java/util/zip/zlib-1.2.8/gzlib.c
+    ../../src/share/native/java/util/zip/zlib-1.2.8/gzread.c
+    ../../src/share/native/java/util/zip/zlib-1.2.8/gzwrite.c
+    ../../src/share/native/java/util/zip/zlib-1.2.8/infback.c
+    ../../src/share/native/java/util/zip/zlib-1.2.8/inffast.c
+    ../../src/share/native/java/util/zip/zlib-1.2.8/inffast.h
+    ../../src/share/native/java/util/zip/zlib-1.2.8/inffixed.h
+    ../../src/share/native/java/util/zip/zlib-1.2.8/inflate.c
+    ../../src/share/native/java/util/zip/zlib-1.2.8/inflate.h
+    ../../src/share/native/java/util/zip/zlib-1.2.8/inftrees.c
+    ../../src/share/native/java/util/zip/zlib-1.2.8/inftrees.h
+    ../../src/share/native/java/util/zip/zlib-1.2.8/trees.c
+    ../../src/share/native/java/util/zip/zlib-1.2.8/trees.h
+    ../../src/share/native/java/util/zip/zlib-1.2.8/uncompr.c
+    ../../src/share/native/java/util/zip/zlib-1.2.8/zadler32.c
+    ../../src/share/native/java/util/zip/zlib-1.2.8/zconf.h
+    ../../src/share/native/java/util/zip/zlib-1.2.8/zcrc32.c
+    ../../src/share/native/java/util/zip/zlib-1.2.8/zlib.h
+    ../../src/share/native/java/util/zip/zlib-1.2.8/zutil.c
+    ../../src/share/native/java/util/zip/zlib-1.2.8/zutil.h
+    ../../src/share/native/java/util/zip/Adler32.c
+    ../../src/share/native/java/util/zip/CRC32.c
+    ../../src/share/native/java/util/zip/Deflater.c
+    ../../src/share/native/java/util/zip/Inflater.c
+    ../../src/share/native/java/util/zip/zip_util.c
+    ../../src/share/native/java/util/zip/zip_util.h
+    ../../src/share/native/java/util/zip/ZipFile.c
+    ../../src/share/native/java/util/TimeZone.c
+    ../../src/share/native/sun/awt/debug/debug_assert.c
+    ../../src/share/native/sun/awt/debug/debug_assert.h
+    ../../src/share/native/sun/awt/debug/debug_mem.c
+    ../../src/share/native/sun/awt/debug/debug_mem.h
+    ../../src/share/native/sun/awt/debug/debug_trace.c
+    ../../src/share/native/sun/awt/debug/debug_trace.h
+    ../../src/share/native/sun/awt/debug/debug_util.c
+    ../../src/share/native/sun/awt/debug/debug_util.h
+    ../../src/share/native/sun/awt/giflib/dgif_lib.c
+    ../../src/share/native/sun/awt/giflib/gif_err.c
+    ../../src/share/native/sun/awt/giflib/gif_hash.h
+    ../../src/share/native/sun/awt/giflib/gif_lib.h
+    ../../src/share/native/sun/awt/giflib/gif_lib_private.h
+    ../../src/share/native/sun/awt/giflib/gifalloc.c
+    ../../src/share/native/sun/awt/image/cvutils/img_alpha.h
+    ../../src/share/native/sun/awt/image/cvutils/img_anycm.h
+    ../../src/share/native/sun/awt/image/cvutils/img_colors.c
+    ../../src/share/native/sun/awt/image/cvutils/img_colors.h
+    ../../src/share/native/sun/awt/image/cvutils/img_dcm.h
+    ../../src/share/native/sun/awt/image/cvutils/img_dcm8.h
+    ../../src/share/native/sun/awt/image/cvutils/img_dir8dither.h
+    ../../src/share/native/sun/awt/image/cvutils/img_dirdither.h
+    ../../src/share/native/sun/awt/image/cvutils/img_fscolor.h
+    ../../src/share/native/sun/awt/image/cvutils/img_fsdither.h
+    ../../src/share/native/sun/awt/image/cvutils/img_fsgray.h
+    ../../src/share/native/sun/awt/image/cvutils/img_fsutil.h
+    ../../src/share/native/sun/awt/image/cvutils/img_globals.c
+    ../../src/share/native/sun/awt/image/cvutils/img_globals.h
+    ../../src/share/native/sun/awt/image/cvutils/img_icm.h
+    ../../src/share/native/sun/awt/image/cvutils/img_input32.h
+    ../../src/share/native/sun/awt/image/cvutils/img_input8.h
+    ../../src/share/native/sun/awt/image/cvutils/img_input8_32.h
+    ../../src/share/native/sun/awt/image/cvutils/img_nodither.h
+    ../../src/share/native/sun/awt/image/cvutils/img_noscale.h
+    ../../src/share/native/sun/awt/image/cvutils/img_opaque.h
+    ../../src/share/native/sun/awt/image/cvutils/img_ordclrsgn.h
+    ../../src/share/native/sun/awt/image/cvutils/img_ordclruns.h
+    ../../src/share/native/sun/awt/image/cvutils/img_orddither.h
+    ../../src/share/native/sun/awt/image/cvutils/img_ordgray.h
+    ../../src/share/native/sun/awt/image/cvutils/img_output16.h
+    ../../src/share/native/sun/awt/image/cvutils/img_output16_32.h
+    ../../src/share/native/sun/awt/image/cvutils/img_output24.h
+    ../../src/share/native/sun/awt/image/cvutils/img_output32.h
+    ../../src/share/native/sun/awt/image/cvutils/img_output8.h
+    ../../src/share/native/sun/awt/image/cvutils/img_output8_16_24.h
+    ../../src/share/native/sun/awt/image/cvutils/img_output8_16_32.h
+    ../../src/share/native/sun/awt/image/cvutils/img_output8_32.h
+    ../../src/share/native/sun/awt/image/cvutils/img_replscale.h
+    ../../src/share/native/sun/awt/image/cvutils/img_scaleloop.h
+    ../../src/share/native/sun/awt/image/cvutils/img_util.h
+    ../../src/share/native/sun/awt/image/gif/gifdecoder.c
+    ../../src/share/native/sun/awt/image/jpeg/imageioJPEG.c
+    ../../src/share/native/sun/awt/image/jpeg/jcapimin.c
+    ../../src/share/native/sun/awt/image/jpeg/jcapistd.c
+    ../../src/share/native/sun/awt/image/jpeg/jccoefct.c
+    ../../src/share/native/sun/awt/image/jpeg/jccolor.c
+    ../../src/share/native/sun/awt/image/jpeg/jcdctmgr.c
+    ../../src/share/native/sun/awt/image/jpeg/jchuff.c
+    ../../src/share/native/sun/awt/image/jpeg/jchuff.h
+    ../../src/share/native/sun/awt/image/jpeg/jcinit.c
+    ../../src/share/native/sun/awt/image/jpeg/jcmainct.c
+    ../../src/share/native/sun/awt/image/jpeg/jcmarker.c
+    ../../src/share/native/sun/awt/image/jpeg/jcmaster.c
+    ../../src/share/native/sun/awt/image/jpeg/jcomapi.c
+    ../../src/share/native/sun/awt/image/jpeg/jconfig.h
+    ../../src/share/native/sun/awt/image/jpeg/jcparam.c
+    ../../src/share/native/sun/awt/image/jpeg/jcphuff.c
+    ../../src/share/native/sun/awt/image/jpeg/jcprepct.c
+    ../../src/share/native/sun/awt/image/jpeg/jcsample.c
+    ../../src/share/native/sun/awt/image/jpeg/jctrans.c
+    ../../src/share/native/sun/awt/image/jpeg/jdapimin.c
+    ../../src/share/native/sun/awt/image/jpeg/jdapistd.c
+    ../../src/share/native/sun/awt/image/jpeg/jdcoefct.c
+    ../../src/share/native/sun/awt/image/jpeg/jdcolor.c
+    ../../src/share/native/sun/awt/image/jpeg/jdct.h
+    ../../src/share/native/sun/awt/image/jpeg/jddctmgr.c
+    ../../src/share/native/sun/awt/image/jpeg/jdhuff.c
+    ../../src/share/native/sun/awt/image/jpeg/jdhuff.h
+    ../../src/share/native/sun/awt/image/jpeg/jdinput.c
+    ../../src/share/native/sun/awt/image/jpeg/jdmainct.c
+    ../../src/share/native/sun/awt/image/jpeg/jdmarker.c
+    ../../src/share/native/sun/awt/image/jpeg/jdmaster.c
+    ../../src/share/native/sun/awt/image/jpeg/jdmerge.c
+    ../../src/share/native/sun/awt/image/jpeg/jdphuff.c
+    ../../src/share/native/sun/awt/image/jpeg/jdpostct.c
+    ../../src/share/native/sun/awt/image/jpeg/jdsample.c
+    ../../src/share/native/sun/awt/image/jpeg/jdtrans.c
+    ../../src/share/native/sun/awt/image/jpeg/jerror.c
+    ../../src/share/native/sun/awt/image/jpeg/jerror.h
+    ../../src/share/native/sun/awt/image/jpeg/jfdctflt.c
+    ../../src/share/native/sun/awt/image/jpeg/jfdctfst.c
+    ../../src/share/native/sun/awt/image/jpeg/jfdctint.c
+    ../../src/share/native/sun/awt/image/jpeg/jidctflt.c
+    ../../src/share/native/sun/awt/image/jpeg/jidctfst.c
+    ../../src/share/native/sun/awt/image/jpeg/jidctint.c
+    ../../src/share/native/sun/awt/image/jpeg/jidctred.c
+    ../../src/share/native/sun/awt/image/jpeg/jinclude.h
+    ../../src/share/native/sun/awt/image/jpeg/jmemmgr.c
+    ../../src/share/native/sun/awt/image/jpeg/jmemnobs.c
+    ../../src/share/native/sun/awt/image/jpeg/jmemsys.h
+    ../../src/share/native/sun/awt/image/jpeg/jmorecfg.h
+    ../../src/share/native/sun/awt/image/jpeg/jpegdecoder.c
+    ../../src/share/native/sun/awt/image/jpeg/jpegint.h
+    ../../src/share/native/sun/awt/image/jpeg/jpeglib.h
+    ../../src/share/native/sun/awt/image/jpeg/jquant1.c
+    ../../src/share/native/sun/awt/image/jpeg/jquant2.c
+    ../../src/share/native/sun/awt/image/jpeg/jutils.c
+    ../../src/share/native/sun/awt/image/jpeg/jversion.h
+    ../../src/share/native/sun/awt/image/awt_ImageRep.c
+    ../../src/share/native/sun/awt/image/awt_parseImage.c
+    ../../src/share/native/sun/awt/image/awt_parseImage.h
+    ../../src/share/native/sun/awt/image/BufImgSurfaceData.c
+    ../../src/share/native/sun/awt/image/BufImgSurfaceData.h
+    ../../src/share/native/sun/awt/image/DataBufferNative.c
+    ../../src/share/native/sun/awt/image/dither.c
+    ../../src/share/native/sun/awt/image/dither.h
+    ../../src/share/native/sun/awt/image/imageInitIDs.c
+    ../../src/share/native/sun/awt/image/imageInitIDs.h
+    ../../src/share/native/sun/awt/libpng/png.c
+    ../../src/share/native/sun/awt/libpng/png.h
+    ../../src/share/native/sun/awt/libpng/pngconf.h
+    ../../src/share/native/sun/awt/libpng/pngdebug.h
+    ../../src/share/native/sun/awt/libpng/pngerror.c
+    ../../src/share/native/sun/awt/libpng/pngget.c
+    ../../src/share/native/sun/awt/libpng/pnginfo.h
+    ../../src/share/native/sun/awt/libpng/pnglibconf.h
+    ../../src/share/native/sun/awt/libpng/pngmem.c
+    ../../src/share/native/sun/awt/libpng/pngpread.c
+    ../../src/share/native/sun/awt/libpng/pngpriv.h
+    ../../src/share/native/sun/awt/libpng/pngread.c
+    ../../src/share/native/sun/awt/libpng/pngrio.c
+    ../../src/share/native/sun/awt/libpng/pngrtran.c
+    ../../src/share/native/sun/awt/libpng/pngrutil.c
+    ../../src/share/native/sun/awt/libpng/pngset.c
+    ../../src/share/native/sun/awt/libpng/pngstruct.h
+    ../../src/share/native/sun/awt/libpng/pngtest.c
+    ../../src/share/native/sun/awt/libpng/pngtrans.c
+    ../../src/share/native/sun/awt/libpng/pngwio.c
+    ../../src/share/native/sun/awt/libpng/pngwrite.c
+    ../../src/share/native/sun/awt/libpng/pngwtran.c
+    ../../src/share/native/sun/awt/libpng/pngwutil.c
+    ../../src/share/native/sun/awt/medialib/awt_ImagingLib.c
+    ../../src/share/native/sun/awt/medialib/awt_ImagingLib.h
+    ../../src/share/native/sun/awt/medialib/j2d_names.h
+    ../../src/share/native/sun/awt/medialib/mlib.h
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffine_BC.c
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffine_BC_S16.c
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffine_BC_U16.c
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffine_BL.c
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffine_BL_S16.c
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffine_BL_U16.c
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffine_NN.c
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffineIndex_BC.c
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffineIndex_BL.c
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageBlendTable.c
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageBlendTable.h
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageConv.h
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageConv_f.c
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageConvClearEdge.c
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageConvCopyEdge.c
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageConvVersion.c
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageCopy.c
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageLookUp.c
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageLookUp.h
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageLookUp_f.c
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageThresh1.h
+    ../../src/share/native/sun/awt/medialib/mlib_c_ImageThresh1_U8.c
+    ../../src/share/native/sun/awt/medialib/mlib_image.h
+    ../../src/share/native/sun/awt/medialib/mlib_image_blend_proto.h
+    ../../src/share/native/sun/awt/medialib/mlib_image_get.h
+    ../../src/share/native/sun/awt/medialib/mlib_image_proto.h
+    ../../src/share/native/sun/awt/medialib/mlib_image_types.h
+    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine.h
+    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine_BC_D64.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine_BC_F32.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine_BC_S32.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine_BL_D64.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine_BL_F32.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine_BL_S32.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine_NN.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine_NN_Bit.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageAffineEdge.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageCheck.h
+    ../../src/share/native/sun/awt/medialib/mlib_ImageClipping.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageClipping.h
+    ../../src/share/native/sun/awt/medialib/mlib_ImageColormap.h
+    ../../src/share/native/sun/awt/medialib/mlib_ImageColorTrue2Index.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConv.h
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConv2x2_f.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_16ext.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_16nw.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_32nw.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_8ext.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_8nw.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_D64nw.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_F32nw.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_u16ext.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_u16nw.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConvClearEdge_Bit.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConvClearEdge_Fp.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConvCopyEdge_Bit.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConvEdge.h
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConvKernelConvert.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConvMxN.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConvMxN_ext.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageConvMxN_Fp.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageCopy.h
+    ../../src/share/native/sun/awt/medialib/mlib_ImageCopy_Bit.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageCreate.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageCreate.h
+    ../../src/share/native/sun/awt/medialib/mlib_ImageDivTables.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageDivTables.h
+    ../../src/share/native/sun/awt/medialib/mlib_ImageFilters.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageFilters.h
+    ../../src/share/native/sun/awt/medialib/mlib_ImageLookUp.h
+    ../../src/share/native/sun/awt/medialib/mlib_ImageLookUp_64.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageLookUp_Bit.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageRowTable.h
+    ../../src/share/native/sun/awt/medialib/mlib_ImageScanPoly.c
+    ../../src/share/native/sun/awt/medialib/mlib_ImageUtils.c
+    ../../src/share/native/sun/awt/medialib/mlib_status.h
+    ../../src/share/native/sun/awt/medialib/mlib_sys.c
+    ../../src/share/native/sun/awt/medialib/mlib_sys.h
+    ../../src/share/native/sun/awt/medialib/mlib_sys_proto.h
+    ../../src/share/native/sun/awt/medialib/mlib_SysMath.h
+    ../../src/share/native/sun/awt/medialib/mlib_types.h
+    ../../src/share/native/sun/awt/medialib/safe_alloc.h
+    ../../src/share/native/sun/awt/medialib/safe_math.h
+    ../../src/share/native/sun/awt/splashscreen/java_awt_SplashScreen.c
+    ../../src/share/native/sun/awt/splashscreen/splashscreen_gfx.h
+    ../../src/share/native/sun/awt/splashscreen/splashscreen_gfx_impl.c
+    ../../src/share/native/sun/awt/splashscreen/splashscreen_gfx_impl.h
+    ../../src/share/native/sun/awt/splashscreen/splashscreen_gif.c
+    ../../src/share/native/sun/awt/splashscreen/splashscreen_impl.c
+    ../../src/share/native/sun/awt/splashscreen/splashscreen_impl.h
+    ../../src/share/native/sun/awt/splashscreen/splashscreen_jpeg.c
+    ../../src/share/native/sun/awt/splashscreen/splashscreen_png.c
+    ../../src/share/native/sun/awt/utility/rect.c
+    ../../src/share/native/sun/font/harfbuzz/hb-ucdn/ucdn.c
+    ../../src/share/native/sun/font/harfbuzz/hb-ucdn/ucdn.h
+    ../../src/share/native/sun/font/harfbuzz/hb-ucdn/unicodedata_db.h
+    ../../src/share/native/sun/font/harfbuzz/hb-atomic-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-blob.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-blob.h
+    ../../src/share/native/sun/font/harfbuzz/hb-buffer-deserialize-json.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-buffer-deserialize-text.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-buffer-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-buffer-serialize.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-buffer.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-buffer.h
+    ../../src/share/native/sun/font/harfbuzz/hb-cache-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-common.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-common.h
+    ../../src/share/native/sun/font/harfbuzz/hb-coretext.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-coretext.h
+    ../../src/share/native/sun/font/harfbuzz/hb-deprecated.h
+    ../../src/share/native/sun/font/harfbuzz/hb-face-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-face.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-face.h
+    ../../src/share/native/sun/font/harfbuzz/hb-fallback-shape.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-font-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-font.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-font.h
+    ../../src/share/native/sun/font/harfbuzz/hb-ft.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ft.h
+    ../../src/share/native/sun/font/harfbuzz/hb-mutex-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-object-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-open-file-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-open-type-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-cmap-table.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-font.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-font.h
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-glyf-table.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-head-table.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-hhea-table.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-hmtx-table.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout-common-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout-gdef-table.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout-gpos-table.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout-gsub-table.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout-gsubgpos-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout-jstf-table.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout.h
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-map-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-map.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-maxp-table.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-name-table.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-fallback.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-table.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-win1256.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-default.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-hangul.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-hebrew.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic-machine.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic-table.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-myanmar-machine.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-myanmar.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-thai.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-tibetan.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use-machine.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use-table.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-fallback-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-fallback.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-normalize-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-normalize.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape.h
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-tag.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ot-tag.h
+    ../../src/share/native/sun/font/harfbuzz/hb-ot.h
+    ../../src/share/native/sun/font/harfbuzz/hb-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-set-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-set.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-set.h
+    ../../src/share/native/sun/font/harfbuzz/hb-shape-plan-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-shape-plan.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-shape-plan.h
+    ../../src/share/native/sun/font/harfbuzz/hb-shape.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-shape.h
+    ../../src/share/native/sun/font/harfbuzz/hb-shaper-impl-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-shaper-list.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-shaper-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-shaper.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-ucdn.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-unicode-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-unicode.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb-unicode.h
+    ../../src/share/native/sun/font/harfbuzz/hb-utf-private.hh
+    ../../src/share/native/sun/font/harfbuzz/hb-version.h
+    ../../src/share/native/sun/font/harfbuzz/hb-warning.cpp
+    ../../src/share/native/sun/font/harfbuzz/hb.h
+    ../../src/share/native/sun/font/layout/AlternateSubstSubtables.cpp
+    ../../src/share/native/sun/font/layout/AlternateSubstSubtables.h
+    ../../src/share/native/sun/font/layout/AnchorTables.cpp
+    ../../src/share/native/sun/font/layout/AnchorTables.h
+    ../../src/share/native/sun/font/layout/ArabicLayoutEngine.cpp
+    ../../src/share/native/sun/font/layout/ArabicLayoutEngine.h
+    ../../src/share/native/sun/font/layout/ArabicShaping.cpp
+    ../../src/share/native/sun/font/layout/ArabicShaping.h
+    ../../src/share/native/sun/font/layout/AttachmentPosnSubtables.h
+    ../../src/share/native/sun/font/layout/CanonData.cpp
+    ../../src/share/native/sun/font/layout/CanonShaping.cpp
+    ../../src/share/native/sun/font/layout/CanonShaping.h
+    ../../src/share/native/sun/font/layout/CharSubstitutionFilter.h
+    ../../src/share/native/sun/font/layout/ClassDefinitionTables.cpp
+    ../../src/share/native/sun/font/layout/ClassDefinitionTables.h
+    ../../src/share/native/sun/font/layout/ContextualGlyphInsertion.h
+    ../../src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.cpp
+    ../../src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.h
+    ../../src/share/native/sun/font/layout/ContextualGlyphSubstitution.h
+    ../../src/share/native/sun/font/layout/ContextualGlyphSubstProc.cpp
+    ../../src/share/native/sun/font/layout/ContextualGlyphSubstProc.h
+    ../../src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp
+    ../../src/share/native/sun/font/layout/ContextualGlyphSubstProc2.h
+    ../../src/share/native/sun/font/layout/ContextualSubstSubtables.cpp
+    ../../src/share/native/sun/font/layout/ContextualSubstSubtables.h
+    ../../src/share/native/sun/font/layout/CoverageTables.cpp
+    ../../src/share/native/sun/font/layout/CoverageTables.h
+    ../../src/share/native/sun/font/layout/CursiveAttachmentSubtables.cpp
+    ../../src/share/native/sun/font/layout/CursiveAttachmentSubtables.h
+    ../../src/share/native/sun/font/layout/DefaultCharMapper.h
+    ../../src/share/native/sun/font/layout/DeviceTables.cpp
+    ../../src/share/native/sun/font/layout/DeviceTables.h
+    ../../src/share/native/sun/font/layout/ExtensionSubtables.cpp
+    ../../src/share/native/sun/font/layout/ExtensionSubtables.h
+    ../../src/share/native/sun/font/layout/Features.cpp
+    ../../src/share/native/sun/font/layout/GDEFMarkFilter.cpp
+    ../../src/share/native/sun/font/layout/GDEFMarkFilter.h
+    ../../src/share/native/sun/font/layout/GlyphDefinitionTables.cpp
+    ../../src/share/native/sun/font/layout/GlyphDefinitionTables.h
+    ../../src/share/native/sun/font/layout/GlyphIterator.cpp
+    ../../src/share/native/sun/font/layout/GlyphIterator.h
+    ../../src/share/native/sun/font/layout/GlyphLookupTables.cpp
+    ../../src/share/native/sun/font/layout/GlyphLookupTables.h
+    ../../src/share/native/sun/font/layout/GlyphPositionAdjustments.cpp
+    ../../src/share/native/sun/font/layout/GlyphPositionAdjustments.h
+    ../../src/share/native/sun/font/layout/GlyphPositioningTables.cpp
+    ../../src/share/native/sun/font/layout/GlyphPositioningTables.h
+    ../../src/share/native/sun/font/layout/GlyphPosnLookupProc.cpp
+    ../../src/share/native/sun/font/layout/GlyphPosnLookupProc.h
+    ../../src/share/native/sun/font/layout/GlyphSubstitutionTables.cpp
+    ../../src/share/native/sun/font/layout/GlyphSubstitutionTables.h
+    ../../src/share/native/sun/font/layout/GlyphSubstLookupProc.cpp
+    ../../src/share/native/sun/font/layout/GlyphSubstLookupProc.h
+    ../../src/share/native/sun/font/layout/GXLayoutEngine.cpp
+    ../../src/share/native/sun/font/layout/GXLayoutEngine.h
+    ../../src/share/native/sun/font/layout/GXLayoutEngine2.cpp
+    ../../src/share/native/sun/font/layout/GXLayoutEngine2.h
+    ../../src/share/native/sun/font/layout/HangulLayoutEngine.cpp
+    ../../src/share/native/sun/font/layout/HangulLayoutEngine.h
+    ../../src/share/native/sun/font/layout/HanLayoutEngine.cpp
+    ../../src/share/native/sun/font/layout/HanLayoutEngine.h
+    ../../src/share/native/sun/font/layout/ICUFeatures.h
+    ../../src/share/native/sun/font/layout/IndicClassTables.cpp
+    ../../src/share/native/sun/font/layout/IndicLayoutEngine.cpp
+    ../../src/share/native/sun/font/layout/IndicLayoutEngine.h
+    ../../src/share/native/sun/font/layout/IndicRearrangement.h
+    ../../src/share/native/sun/font/layout/IndicRearrangementProcessor.cpp
+    ../../src/share/native/sun/font/layout/IndicRearrangementProcessor.h
+    ../../src/share/native/sun/font/layout/IndicRearrangementProcessor2.cpp
+    ../../src/share/native/sun/font/layout/IndicRearrangementProcessor2.h
+    ../../src/share/native/sun/font/layout/IndicReordering.cpp
+    ../../src/share/native/sun/font/layout/IndicReordering.h
+    ../../src/share/native/sun/font/layout/KernTable.cpp
+    ../../src/share/native/sun/font/layout/KernTable.h
+    ../../src/share/native/sun/font/layout/KhmerLayoutEngine.cpp
+    ../../src/share/native/sun/font/layout/KhmerLayoutEngine.h
+    ../../src/share/native/sun/font/layout/KhmerReordering.cpp
+    ../../src/share/native/sun/font/layout/KhmerReordering.h
+    ../../src/share/native/sun/font/layout/LayoutEngine.cpp
+    ../../src/share/native/sun/font/layout/LayoutEngine.h
+    ../../src/share/native/sun/font/layout/LayoutTables.h
+    ../../src/share/native/sun/font/layout/LEFontInstance.cpp
+    ../../src/share/native/sun/font/layout/LEFontInstance.h
+    ../../src/share/native/sun/font/layout/LEGlyphFilter.h
+    ../../src/share/native/sun/font/layout/LEGlyphStorage.cpp
+    ../../src/share/native/sun/font/layout/LEGlyphStorage.h
+    ../../src/share/native/sun/font/layout/LEInsertionList.cpp
+    ../../src/share/native/sun/font/layout/LEInsertionList.h
+    ../../src/share/native/sun/font/layout/LELanguages.h
+    ../../src/share/native/sun/font/layout/LEScripts.h
+    ../../src/share/native/sun/font/layout/LEStandalone.h
+    ../../src/share/native/sun/font/layout/LESwaps.h
+    ../../src/share/native/sun/font/layout/LETableReference.h
+    ../../src/share/native/sun/font/layout/LETypes.h
+    ../../src/share/native/sun/font/layout/LigatureSubstitution.h
+    ../../src/share/native/sun/font/layout/LigatureSubstProc.cpp
+    ../../src/share/native/sun/font/layout/LigatureSubstProc.h
+    ../../src/share/native/sun/font/layout/LigatureSubstProc2.cpp
+    ../../src/share/native/sun/font/layout/LigatureSubstProc2.h
+    ../../src/share/native/sun/font/layout/LigatureSubstSubtables.cpp
+    ../../src/share/native/sun/font/layout/LigatureSubstSubtables.h
+    ../../src/share/native/sun/font/layout/LookupProcessor.cpp
+    ../../src/share/native/sun/font/layout/LookupProcessor.h
+    ../../src/share/native/sun/font/layout/Lookups.cpp
+    ../../src/share/native/sun/font/layout/Lookups.h
+    ../../src/share/native/sun/font/layout/LookupTables.cpp
+    ../../src/share/native/sun/font/layout/LookupTables.h
+    ../../src/share/native/sun/font/layout/MarkArrays.cpp
+    ../../src/share/native/sun/font/layout/MarkArrays.h
+    ../../src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp
+    ../../src/share/native/sun/font/layout/MarkToBasePosnSubtables.h
+    ../../src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.cpp
+    ../../src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.h
+    ../../src/share/native/sun/font/layout/MarkToMarkPosnSubtables.cpp
+    ../../src/share/native/sun/font/layout/MarkToMarkPosnSubtables.h
+    ../../src/share/native/sun/font/layout/MirroredCharData.cpp
+    ../../src/share/native/sun/font/layout/MorphStateTables.h
+    ../../src/share/native/sun/font/layout/MorphTables.cpp
+    ../../src/share/native/sun/font/layout/MorphTables.h
+    ../../src/share/native/sun/font/layout/MorphTables2.cpp
+    ../../src/share/native/sun/font/layout/MPreFixups.cpp
+    ../../src/share/native/sun/font/layout/MPreFixups.h
+    ../../src/share/native/sun/font/layout/MultipleSubstSubtables.cpp
+    ../../src/share/native/sun/font/layout/MultipleSubstSubtables.h
+    ../../src/share/native/sun/font/layout/NonContextualGlyphSubst.h
+    ../../src/share/native/sun/font/layout/NonContextualGlyphSubstProc.cpp
+    ../../src/share/native/sun/font/layout/NonContextualGlyphSubstProc.h
+    ../../src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.cpp
+    ../../src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.h
+    ../../src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp
+    ../../src/share/native/sun/font/layout/OpenTypeLayoutEngine.h
+    ../../src/share/native/sun/font/layout/OpenTypeTables.h
+    ../../src/share/native/sun/font/layout/OpenTypeUtilities.cpp
+    ../../src/share/native/sun/font/layout/OpenTypeUtilities.h
+    ../../src/share/native/sun/font/layout/PairPositioningSubtables.cpp
+    ../../src/share/native/sun/font/layout/PairPositioningSubtables.h
+    ../../src/share/native/sun/font/layout/ScriptAndLanguage.cpp
+    ../../src/share/native/sun/font/layout/ScriptAndLanguage.h
+    ../../src/share/native/sun/font/layout/ScriptAndLanguageTags.cpp
+    ../../src/share/native/sun/font/layout/ScriptAndLanguageTags.h
+    ../../src/share/native/sun/font/layout/SegmentArrayProcessor.cpp
+    ../../src/share/native/sun/font/layout/SegmentArrayProcessor.h
+    ../../src/share/native/sun/font/layout/SegmentArrayProcessor2.cpp
+    ../../src/share/native/sun/font/layout/SegmentArrayProcessor2.h
+    ../../src/share/native/sun/font/layout/SegmentSingleProcessor.cpp
+    ../../src/share/native/sun/font/layout/SegmentSingleProcessor.h
+    ../../src/share/native/sun/font/layout/SegmentSingleProcessor2.cpp
+    ../../src/share/native/sun/font/layout/SegmentSingleProcessor2.h
+    ../../src/share/native/sun/font/layout/ShapingTypeData.cpp
+    ../../src/share/native/sun/font/layout/SimpleArrayProcessor.cpp
+    ../../src/share/native/sun/font/layout/SimpleArrayProcessor.h
+    ../../src/share/native/sun/font/layout/SimpleArrayProcessor2.cpp
+    ../../src/share/native/sun/font/layout/SimpleArrayProcessor2.h
+    ../../src/share/native/sun/font/layout/SinglePositioningSubtables.cpp
+    ../../src/share/native/sun/font/layout/SinglePositioningSubtables.h
+    ../../src/share/native/sun/font/layout/SingleSubstitutionSubtables.cpp
+    ../../src/share/native/sun/font/layout/SingleSubstitutionSubtables.h
+    ../../src/share/native/sun/font/layout/SingleTableProcessor.cpp
+    ../../src/share/native/sun/font/layout/SingleTableProcessor.h
+    ../../src/share/native/sun/font/layout/SingleTableProcessor2.cpp
+    ../../src/share/native/sun/font/layout/SingleTableProcessor2.h
+    ../../src/share/native/sun/font/layout/StateTableProcessor.cpp
+    ../../src/share/native/sun/font/layout/StateTableProcessor.h
+    ../../src/share/native/sun/font/layout/StateTableProcessor2.cpp
+    ../../src/share/native/sun/font/layout/StateTableProcessor2.h
+    ../../src/share/native/sun/font/layout/StateTables.h
+    ../../src/share/native/sun/font/layout/SubstitutionLookups.cpp
+    ../../src/share/native/sun/font/layout/SubstitutionLookups.h
+    ../../src/share/native/sun/font/layout/SubtableProcessor.cpp
+    ../../src/share/native/sun/font/layout/SubtableProcessor.h
+    ../../src/share/native/sun/font/layout/SubtableProcessor2.cpp
+    ../../src/share/native/sun/font/layout/SubtableProcessor2.h
+    ../../src/share/native/sun/font/layout/SunLayoutEngine.cpp
+    ../../src/share/native/sun/font/layout/ThaiLayoutEngine.cpp
+    ../../src/share/native/sun/font/layout/ThaiLayoutEngine.h
+    ../../src/share/native/sun/font/layout/ThaiShaping.cpp
+    ../../src/share/native/sun/font/layout/ThaiShaping.h
+    ../../src/share/native/sun/font/layout/ThaiStateTables.cpp
+    ../../src/share/native/sun/font/layout/TibetanLayoutEngine.cpp
+    ../../src/share/native/sun/font/layout/TibetanLayoutEngine.h
+    ../../src/share/native/sun/font/layout/TibetanReordering.cpp
+    ../../src/share/native/sun/font/layout/TibetanReordering.h
+    ../../src/share/native/sun/font/layout/TrimmedArrayProcessor.cpp
+    ../../src/share/native/sun/font/layout/TrimmedArrayProcessor.h
+    ../../src/share/native/sun/font/layout/TrimmedArrayProcessor2.cpp
+    ../../src/share/native/sun/font/layout/TrimmedArrayProcessor2.h
+    ../../src/share/native/sun/font/layout/ValueRecords.cpp
+    ../../src/share/native/sun/font/layout/ValueRecords.h
+    ../../src/share/native/sun/font/AccelGlyphCache.c
+    ../../src/share/native/sun/font/AccelGlyphCache.h
+    ../../src/share/native/sun/font/DrawGlyphList.c
+    ../../src/share/native/sun/font/fontconfig.h
+    ../../src/share/native/sun/font/FontInstanceAdapter.cpp
+    ../../src/share/native/sun/font/FontInstanceAdapter.h
+    ../../src/share/native/sun/font/fontscaler.h
+    ../../src/share/native/sun/font/fontscalerdefs.h
+    ../../src/share/native/sun/font/freetypeScaler.c
+    ../../src/share/native/sun/font/glyphblitting.h
+    ../../src/share/native/sun/font/hb-jdk-font.cpp
+    ../../src/share/native/sun/font/hb-jdk.h
+    ../../src/share/native/sun/font/HBShaper.c
+    ../../src/share/native/sun/font/scriptMapping.c
+    ../../src/share/native/sun/font/scriptMapping.h
+    ../../src/share/native/sun/font/sunFont.c
+    ../../src/share/native/sun/font/sunfontids.h
+    ../../src/share/native/sun/java2d/cmm/lcms/cmscam02.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmscgats.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmserr.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmsgamma.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmsgmt.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmshalf.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmsintrp.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmsio0.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmsio1.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmslut.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmsmd5.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmsnamed.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmsopt.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmspack.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmspcs.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmsplugin.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmsps2.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmssamp.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmssm.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmstypes.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmsvirt.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c
+    ../../src/share/native/sun/java2d/cmm/lcms/cmsxform.c
+    ../../src/share/native/sun/java2d/cmm/lcms/LCMS.c
+    ../../src/share/native/sun/java2d/cmm/lcms/lcms2.h
+    ../../src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h
+    ../../src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h
+    ../../src/share/native/sun/java2d/loops/AlphaMacros.c
+    ../../src/share/native/sun/java2d/loops/AlphaMacros.h
+    ../../src/share/native/sun/java2d/loops/AlphaMath.c
+    ../../src/share/native/sun/java2d/loops/AlphaMath.h
+    ../../src/share/native/sun/java2d/loops/Any3Byte.c
+    ../../src/share/native/sun/java2d/loops/Any3Byte.h
+    ../../src/share/native/sun/java2d/loops/Any4Byte.c
+    ../../src/share/native/sun/java2d/loops/Any4Byte.h
+    ../../src/share/native/sun/java2d/loops/AnyByte.c
+    ../../src/share/native/sun/java2d/loops/AnyByte.h
+    ../../src/share/native/sun/java2d/loops/AnyByteBinary.h
+    ../../src/share/native/sun/java2d/loops/AnyInt.c
+    ../../src/share/native/sun/java2d/loops/AnyInt.h
+    ../../src/share/native/sun/java2d/loops/AnyShort.c
+    ../../src/share/native/sun/java2d/loops/AnyShort.h
+    ../../src/share/native/sun/java2d/loops/Blit.c
+    ../../src/share/native/sun/java2d/loops/BlitBg.c
+    ../../src/share/native/sun/java2d/loops/ByteBinary1Bit.c
+    ../../src/share/native/sun/java2d/loops/ByteBinary1Bit.h
+    ../../src/share/native/sun/java2d/loops/ByteBinary2Bit.c
+    ../../src/share/native/sun/java2d/loops/ByteBinary2Bit.h
+    ../../src/share/native/sun/java2d/loops/ByteBinary4Bit.c
+    ../../src/share/native/sun/java2d/loops/ByteBinary4Bit.h
+    ../../src/share/native/sun/java2d/loops/ByteGray.c
+    ../../src/share/native/sun/java2d/loops/ByteGray.h
+    ../../src/share/native/sun/java2d/loops/ByteIndexed.c
+    ../../src/share/native/sun/java2d/loops/ByteIndexed.h
+    ../../src/share/native/sun/java2d/loops/DrawLine.c
+    ../../src/share/native/sun/java2d/loops/DrawParallelogram.c
+    ../../src/share/native/sun/java2d/loops/DrawPath.c
+    ../../src/share/native/sun/java2d/loops/DrawPath.h
+    ../../src/share/native/sun/java2d/loops/DrawPolygons.c
+    ../../src/share/native/sun/java2d/loops/DrawRect.c
+    ../../src/share/native/sun/java2d/loops/FillParallelogram.c
+    ../../src/share/native/sun/java2d/loops/FillPath.c
+    ../../src/share/native/sun/java2d/loops/FillRect.c
+    ../../src/share/native/sun/java2d/loops/FillSpans.c
+    ../../src/share/native/sun/java2d/loops/FourByteAbgr.c
+    ../../src/share/native/sun/java2d/loops/FourByteAbgr.h
+    ../../src/share/native/sun/java2d/loops/FourByteAbgrPre.c
+    ../../src/share/native/sun/java2d/loops/FourByteAbgrPre.h
+    ../../src/share/native/sun/java2d/loops/GlyphImageRef.h
+    ../../src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.c
+    ../../src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h
+    ../../src/share/native/sun/java2d/loops/ImageData.h
+    ../../src/share/native/sun/java2d/loops/Index12Gray.c
+    ../../src/share/native/sun/java2d/loops/Index12Gray.h
+    ../../src/share/native/sun/java2d/loops/Index8Gray.c
+    ../../src/share/native/sun/java2d/loops/Index8Gray.h
+    ../../src/share/native/sun/java2d/loops/IntArgb.c
+    ../../src/share/native/sun/java2d/loops/IntArgb.h
+    ../../src/share/native/sun/java2d/loops/IntArgbBm.c
+    ../../src/share/native/sun/java2d/loops/IntArgbBm.h
+    ../../src/share/native/sun/java2d/loops/IntArgbPre.c
+    ../../src/share/native/sun/java2d/loops/IntArgbPre.h
+    ../../src/share/native/sun/java2d/loops/IntBgr.c
+    ../../src/share/native/sun/java2d/loops/IntBgr.h
+    ../../src/share/native/sun/java2d/loops/IntDcm.h
+    ../../src/share/native/sun/java2d/loops/IntRgb.c
+    ../../src/share/native/sun/java2d/loops/IntRgb.h
+    ../../src/share/native/sun/java2d/loops/IntRgbx.c
+    ../../src/share/native/sun/java2d/loops/IntRgbx.h
+    ../../src/share/native/sun/java2d/loops/LineUtils.h
+    ../../src/share/native/sun/java2d/loops/LoopMacros.h
+    ../../src/share/native/sun/java2d/loops/MapAccelFunc.c
+    ../../src/share/native/sun/java2d/loops/MaskBlit.c
+    ../../src/share/native/sun/java2d/loops/MaskFill.c
+    ../../src/share/native/sun/java2d/loops/ParallelogramUtils.h
+    ../../src/share/native/sun/java2d/loops/ProcessPath.c
+    ../../src/share/native/sun/java2d/loops/ProcessPath.h
+    ../../src/share/native/sun/java2d/loops/ScaledBlit.c
+    ../../src/share/native/sun/java2d/loops/ThreeByteBgr.c
+    ../../src/share/native/sun/java2d/loops/ThreeByteBgr.h
+    ../../src/share/native/sun/java2d/loops/TransformHelper.c
+    ../../src/share/native/sun/java2d/loops/Ushort4444Argb.c
+    ../../src/share/native/sun/java2d/loops/Ushort4444Argb.h
+    ../../src/share/native/sun/java2d/loops/Ushort555Rgb.c
+    ../../src/share/native/sun/java2d/loops/Ushort555Rgb.h
+    ../../src/share/native/sun/java2d/loops/Ushort555Rgbx.c
+    ../../src/share/native/sun/java2d/loops/Ushort555Rgbx.h
+    ../../src/share/native/sun/java2d/loops/Ushort565Rgb.c
+    ../../src/share/native/sun/java2d/loops/Ushort565Rgb.h
+    ../../src/share/native/sun/java2d/loops/UshortGray.c
+    ../../src/share/native/sun/java2d/loops/UshortGray.h
+    ../../src/share/native/sun/java2d/loops/UshortIndexed.c
+    ../../src/share/native/sun/java2d/loops/UshortIndexed.h
+    ../../src/share/native/sun/java2d/opengl/J2D_GL/gl.h
+    ../../src/share/native/sun/java2d/opengl/J2D_GL/glext.h
+    ../../src/share/native/sun/java2d/opengl/OGLBlitLoops.c
+    ../../src/share/native/sun/java2d/opengl/OGLBlitLoops.h
+    ../../src/share/native/sun/java2d/opengl/OGLBufImgOps.c
+    ../../src/share/native/sun/java2d/opengl/OGLBufImgOps.h
+    ../../src/share/native/sun/java2d/opengl/OGLContext.c
+    ../../src/share/native/sun/java2d/opengl/OGLContext.h
+    ../../src/share/native/sun/java2d/opengl/OGLFuncMacros.h
+    ../../src/share/native/sun/java2d/opengl/OGLFuncs.c
+    ../../src/share/native/sun/java2d/opengl/OGLFuncs.h
+    ../../src/share/native/sun/java2d/opengl/OGLMaskBlit.c
+    ../../src/share/native/sun/java2d/opengl/OGLMaskBlit.h
+    ../../src/share/native/sun/java2d/opengl/OGLMaskFill.c
+    ../../src/share/native/sun/java2d/opengl/OGLMaskFill.h
+    ../../src/share/native/sun/java2d/opengl/OGLPaints.c
+    ../../src/share/native/sun/java2d/opengl/OGLPaints.h
+    ../../src/share/native/sun/java2d/opengl/OGLRenderer.c
+    ../../src/share/native/sun/java2d/opengl/OGLRenderer.h
+    ../../src/share/native/sun/java2d/opengl/OGLRenderQueue.c
+    ../../src/share/native/sun/java2d/opengl/OGLRenderQueue.h
+    ../../src/share/native/sun/java2d/opengl/OGLSurfaceData.c
+    ../../src/share/native/sun/java2d/opengl/OGLSurfaceData.h
+    ../../src/share/native/sun/java2d/opengl/OGLTextRenderer.c
+    ../../src/share/native/sun/java2d/opengl/OGLTextRenderer.h
+    ../../src/share/native/sun/java2d/opengl/OGLVertexCache.c
+    ../../src/share/native/sun/java2d/opengl/OGLVertexCache.h
+    ../../src/share/native/sun/java2d/pipe/BufferedMaskBlit.c
+    ../../src/share/native/sun/java2d/pipe/BufferedRenderPipe.c
+    ../../src/share/native/sun/java2d/pipe/PathConsumer2D.h
+    ../../src/share/native/sun/java2d/pipe/Region.c
+    ../../src/share/native/sun/java2d/pipe/Region.h
+    ../../src/share/native/sun/java2d/pipe/ShapeSpanIterator.c
+    ../../src/share/native/sun/java2d/pipe/SpanClipRenderer.c
+    ../../src/share/native/sun/java2d/pipe/SpanIterator.h
+    ../../src/share/native/sun/java2d/Disposer.c
+    ../../src/share/native/sun/java2d/Disposer.h
+    ../../src/share/native/sun/java2d/ShaderList.c
+    ../../src/share/native/sun/java2d/ShaderList.h
+    ../../src/share/native/sun/java2d/SurfaceData.c
+    ../../src/share/native/sun/java2d/SurfaceData.h
+    ../../src/share/native/sun/java2d/Trace.c
+    ../../src/share/native/sun/java2d/Trace.h
+    ../../src/share/native/sun/management/ClassLoadingImpl.c
+    ../../src/share/native/sun/management/DiagnosticCommandImpl.c
+    ../../src/share/native/sun/management/Flag.c
+    ../../src/share/native/sun/management/GarbageCollectorImpl.c
+    ../../src/share/native/sun/management/GcInfoBuilder.c
+    ../../src/share/native/sun/management/HotSpotDiagnostic.c
+    ../../src/share/native/sun/management/HotspotThread.c
+    ../../src/share/native/sun/management/management.c
+    ../../src/share/native/sun/management/management.h
+    ../../src/share/native/sun/management/MemoryImpl.c
+    ../../src/share/native/sun/management/MemoryManagerImpl.c
+    ../../src/share/native/sun/management/MemoryPoolImpl.c
+    ../../src/share/native/sun/management/ThreadImpl.c
+    ../../src/share/native/sun/management/VMManagementImpl.c
+    ../../src/share/native/sun/misc/GC.c
+    ../../src/share/native/sun/misc/MessageUtils.c
+    ../../src/share/native/sun/misc/NativeSignalHandler.c
+    ../../src/share/native/sun/misc/Signal.c
+    ../../src/share/native/sun/misc/URLClassPath.c
+    ../../src/share/native/sun/misc/Version.c
+    ../../src/share/native/sun/misc/VM.c
+    ../../src/share/native/sun/misc/VMSupport.c
+    ../../src/share/native/sun/nio/ch/nio.h
+    ../../src/share/native/sun/reflect/ConstantPool.c
+    ../../src/share/native/sun/reflect/NativeAccessors.c
+    ../../src/share/native/sun/reflect/Reflection.c
+    ../../src/share/native/sun/security/ec/impl/ec.c
+    ../../src/share/native/sun/security/ec/impl/ec.h
+    ../../src/share/native/sun/security/ec/impl/ec2.h
+    ../../src/share/native/sun/security/ec/impl/ec2_163.c
+    ../../src/share/native/sun/security/ec/impl/ec2_193.c
+    ../../src/share/native/sun/security/ec/impl/ec2_233.c
+    ../../src/share/native/sun/security/ec/impl/ec2_aff.c
+    ../../src/share/native/sun/security/ec/impl/ec2_mont.c
+    ../../src/share/native/sun/security/ec/impl/ec_naf.c
+    ../../src/share/native/sun/security/ec/impl/ecc_impl.h
+    ../../src/share/native/sun/security/ec/impl/ecdecode.c
+    ../../src/share/native/sun/security/ec/impl/ecl-curve.h
+    ../../src/share/native/sun/security/ec/impl/ecl-exp.h
+    ../../src/share/native/sun/security/ec/impl/ecl-priv.h
+    ../../src/share/native/sun/security/ec/impl/ecl.c
+    ../../src/share/native/sun/security/ec/impl/ecl.h
+    ../../src/share/native/sun/security/ec/impl/ecl_curve.c
+    ../../src/share/native/sun/security/ec/impl/ecl_gf.c
+    ../../src/share/native/sun/security/ec/impl/ecl_mult.c
+    ../../src/share/native/sun/security/ec/impl/ecp.h
+    ../../src/share/native/sun/security/ec/impl/ecp_192.c
+    ../../src/share/native/sun/security/ec/impl/ecp_224.c
+    ../../src/share/native/sun/security/ec/impl/ecp_256.c
+    ../../src/share/native/sun/security/ec/impl/ecp_384.c
+    ../../src/share/native/sun/security/ec/impl/ecp_521.c
+    ../../src/share/native/sun/security/ec/impl/ecp_aff.c
+    ../../src/share/native/sun/security/ec/impl/ecp_jac.c
+    ../../src/share/native/sun/security/ec/impl/ecp_jm.c
+    ../../src/share/native/sun/security/ec/impl/ecp_mont.c
+    ../../src/share/native/sun/security/ec/impl/logtab.h
+    ../../src/share/native/sun/security/ec/impl/mp_gf2m-priv.h
+    ../../src/share/native/sun/security/ec/impl/mp_gf2m.c
+    ../../src/share/native/sun/security/ec/impl/mp_gf2m.h
+    ../../src/share/native/sun/security/ec/impl/mpi-config.h
+    ../../src/share/native/sun/security/ec/impl/mpi-priv.h
+    ../../src/share/native/sun/security/ec/impl/mpi.c
+    ../../src/share/native/sun/security/ec/impl/mpi.h
+    ../../src/share/native/sun/security/ec/impl/mplogic.c
+    ../../src/share/native/sun/security/ec/impl/mplogic.h
+    ../../src/share/native/sun/security/ec/impl/mpmontg.c
+    ../../src/share/native/sun/security/ec/impl/mpprime.h
+    ../../src/share/native/sun/security/ec/impl/oid.c
+    ../../src/share/native/sun/security/ec/impl/secitem.c
+    ../../src/share/native/sun/security/ec/impl/secoidt.h
+    ../../src/share/native/sun/security/ec/ECC_JNI.cpp
+    ../../src/share/native/sun/security/jgss/wrapper/gssapi.h
+    ../../src/share/native/sun/security/jgss/wrapper/GSSLibStub.c
+    ../../src/share/native/sun/security/jgss/wrapper/NativeUtil.c
+    ../../src/share/native/sun/security/jgss/wrapper/NativeUtil.h
+    ../../src/share/native/sun/security/krb5/nativeccache.c
+    ../../src/share/native/sun/security/pkcs11/wrapper/p11_convert.c
+    ../../src/share/native/sun/security/pkcs11/wrapper/p11_crypt.c
+    ../../src/share/native/sun/security/pkcs11/wrapper/p11_digest.c
+    ../../src/share/native/sun/security/pkcs11/wrapper/p11_dual.c
+    ../../src/share/native/sun/security/pkcs11/wrapper/p11_general.c
+    ../../src/share/native/sun/security/pkcs11/wrapper/p11_keymgmt.c
+    ../../src/share/native/sun/security/pkcs11/wrapper/p11_mutex.c
+    ../../src/share/native/sun/security/pkcs11/wrapper/p11_objmgmt.c
+    ../../src/share/native/sun/security/pkcs11/wrapper/p11_sessmgmt.c
+    ../../src/share/native/sun/security/pkcs11/wrapper/p11_sign.c
+    ../../src/share/native/sun/security/pkcs11/wrapper/p11_util.c
+    ../../src/share/native/sun/security/pkcs11/wrapper/pkcs-11v2-20a3.h
+    ../../src/share/native/sun/security/pkcs11/wrapper/pkcs11.h
+    ../../src/share/native/sun/security/pkcs11/wrapper/pkcs11f.h
+    ../../src/share/native/sun/security/pkcs11/wrapper/pkcs11t.h
+    ../../src/share/native/sun/security/pkcs11/wrapper/pkcs11wrapper.h
+    ../../src/share/native/sun/security/pkcs11/j2secmod.c
+    ../../src/share/native/sun/security/pkcs11/j2secmod.h
+    ../../src/share/native/sun/security/smartcardio/pcsc.c
+    ../../src/share/native/sun/tracing/dtrace/JVM.c
+    ../../src/share/native/sun/tracing/dtrace/jvm_symbols.h)
+
+if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+    set(SOURCE_FILES
+            ${SOURCE_FILES}
+            ../../src/solaris/native/sun/xawt/awt_Desktop.c
+            ../../src/solaris/native/sun/xawt/gnome_interface.c
+            ../../src/solaris/native/sun/xawt/gnome_interface.h
+            ../../src/solaris/native/sun/xawt/XlibWrapper.c
+            ../../src/solaris/native/sun/xawt/XToolkit.c
+            ../../src/solaris/native/sun/xawt/XWindow.c)
+endif()
+
+if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin" OR ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+    set(SOURCE_FILES
+            ${SOURCE_FILES}
+            ../../src/solaris/javavm/export/jawt_md.h
+            ../../src/solaris/javavm/export/jni_md.h
+            ../../src/solaris/javavm/export/jvm_md.h
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_CommonUtils.c
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_CommonUtils.h
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_MidiIn.c
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_MidiOut.c
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_MidiUtils.c
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_MidiUtils.h
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_PCM.c
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_PCMUtils.c
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_PCMUtils.h
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_Ports.c
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.h
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiIn.c
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiOut.c
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.h
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCM.c
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.c
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_Ports.c
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_PCM.c
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_Ports.c
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_Utils.c
+            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_Utils.h
+            ../../src/solaris/native/com/sun/security/auth/module/Solaris.c
+            ../../src/solaris/native/com/sun/security/auth/module/Unix.c
+            ../../src/solaris/native/common/gdefs_md.h
+            ../../src/solaris/native/common/jdk_util_md.c
+            ../../src/solaris/native/common/jdk_util_md.h
+            ../../src/solaris/native/common/jlong_md.h
+            ../../src/solaris/native/common/jni_util_md.c
+            ../../src/solaris/native/java/io/canonicalize_md.c
+            ../../src/solaris/native/java/io/Console_md.c
+            ../../src/solaris/native/java/io/FileDescriptor_md.c
+            ../../src/solaris/native/java/io/FileInputStream_md.c
+            ../../src/solaris/native/java/io/FileOutputStream_md.c
+            ../../src/solaris/native/java/io/io_util_md.c
+            ../../src/solaris/native/java/io/io_util_md.h
+            ../../src/solaris/native/java/io/RandomAccessFile_md.c
+            ../../src/solaris/native/java/io/UnixFileSystem_md.c
+            ../../src/solaris/native/java/lang/childproc.c
+            ../../src/solaris/native/java/lang/childproc.h
+            ../../src/solaris/native/java/lang/java_props_macosx.c
+            ../../src/solaris/native/java/lang/java_props_macosx.h
+            ../../src/solaris/native/java/lang/java_props_md.c
+            ../../src/solaris/native/java/lang/jspawnhelper.c
+            ../../src/solaris/native/java/lang/locale_str.h
+            ../../src/solaris/native/java/lang/ProcessEnvironment_md.c
+            ../../src/solaris/native/java/lang/UNIXProcess_md.c
+            ../../src/solaris/native/java/net/bsd_close.c
+            ../../src/solaris/native/java/net/ExtendedOptionsImpl.c
+            ../../src/solaris/native/java/net/Inet4AddressImpl.c
+            ../../src/solaris/native/java/net/Inet6AddressImpl.c
+            ../../src/solaris/native/java/net/InetAddressImplFactory.c
+            ../../src/solaris/native/java/net/linux_close.c
+            ../../src/solaris/native/java/net/net_util_md.c
+            ../../src/solaris/native/java/net/net_util_md.h
+            ../../src/solaris/native/java/net/NetworkInterface.c
+            ../../src/solaris/native/java/net/PlainDatagramSocketImpl.c
+            ../../src/solaris/native/java/net/PlainSocketImpl.c
+            ../../src/solaris/native/java/net/SocketInputStream.c
+            ../../src/solaris/native/java/net/SocketOutputStream.c
+            ../../src/solaris/native/java/nio/MappedByteBuffer.c
+            ../../src/solaris/native/java/util/FileSystemPreferences.c
+            ../../src/solaris/native/java/util/logging.c
+            ../../src/solaris/native/java/util/TimeZone_md.c
+            ../../src/solaris/native/java/util/TimeZone_md.h
+            ../../src/solaris/native/sun/awt/medialib/mlib_ImageConvCopyEdge_Fp.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffine_BC.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffine_BC_S16.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffine_BC_U16.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffine_BL.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffine_BL_S16.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffine_BL_S16.h
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffine_BL_U16.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffine_NN.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffineIndex_BC.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelExtract.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelExtract.h
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelExtract_1.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelExtract_43.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelExtract_f.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelInsert.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelInsert.h
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelInsert_1.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelInsert_34.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConv.h
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConv_8nw.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConvClearEdge.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConvCopyEdge.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConvIndex3_8_16nw.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConvIndex3_8_8nw.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConvMxN_8.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConvMxN_8ext.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConvVersion.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageCopy.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageCopy_f.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageCopy_f.h
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageFilters.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageFilters.h
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUp.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpFunc.h
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpS16S16Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpS16S32Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpS16U16Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpS16U8Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpS32S16Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpS32S32Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpS32U16Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpS32U8Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIS16S16Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIS16S32Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIS16U16Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIS16U8Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIS32S16Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIS32S32Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIS32U16Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIS32U8Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIU16S16Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIU16S32Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIU16U16Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIU16U8Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIU8S16Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIU8S32Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIU8U16Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIU8U8Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpU16S16Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpU16S32Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpU16U16Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpU16U8Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpU8S16Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpU8S32Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpU8U16Func.c
+            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpU8U8Func.c
+            ../../src/solaris/native/sun/awt/medialib/vis_asi.h
+            ../../src/solaris/native/sun/awt/medialib/vis_proto.h
+            ../../src/solaris/native/sun/awt/splashscreen/splashscreen_config.h
+            ../../src/solaris/native/sun/awt/splashscreen/splashscreen_sys.c
+            ../../src/solaris/native/sun/awt/utility/rect.h
+            ../../src/solaris/native/sun/awt/awt.h
+            ../../src/solaris/native/sun/awt/awt_AWTEvent.c
+            ../../src/solaris/native/sun/awt/awt_AWTEvent.h
+            ../../src/solaris/native/sun/awt/awt_Component.h
+            ../../src/solaris/native/sun/awt/awt_DrawingSurface.c
+            ../../src/solaris/native/sun/awt/awt_DrawingSurface.h
+            ../../src/solaris/native/sun/awt/awt_Event.c
+            ../../src/solaris/native/sun/awt/awt_Event.h
+            ../../src/solaris/native/sun/awt/awt_Font.c
+            ../../src/solaris/native/sun/awt/awt_Font.h
+            ../../src/solaris/native/sun/awt/awt_GraphicsEnv.c
+            ../../src/solaris/native/sun/awt/awt_GraphicsEnv.h
+            ../../src/solaris/native/sun/awt/awt_InputMethod.c
+            ../../src/solaris/native/sun/awt/awt_Insets.c
+            ../../src/solaris/native/sun/awt/awt_Insets.h
+            ../../src/solaris/native/sun/awt/awt_LoadLibrary.c
+            ../../src/solaris/native/sun/awt/awt_MenuComponent.h
+            ../../src/solaris/native/sun/awt/awt_Mlib.c
+            ../../src/solaris/native/sun/awt/awt_Mlib.h
+            ../../src/solaris/native/sun/awt/awt_p.h
+            ../../src/solaris/native/sun/awt/awt_Robot.c
+            ../../src/solaris/native/sun/awt/awt_UNIXToolkit.c
+            ../../src/solaris/native/sun/awt/awt_util.c
+            ../../src/solaris/native/sun/awt/awt_util.h
+            ../../src/solaris/native/sun/awt/canvas.h
+            ../../src/solaris/native/sun/awt/color.h
+            ../../src/solaris/native/sun/awt/colordata.h
+            ../../src/solaris/native/sun/awt/CUPSfuncs.c
+            ../../src/solaris/native/sun/awt/extutil.h
+            ../../src/solaris/native/sun/awt/fontconfig.h
+            ../../src/solaris/native/sun/awt/fontpath.c
+            ../../src/solaris/native/sun/awt/gtk2_interface.c
+            ../../src/solaris/native/sun/awt/gtk2_interface.h
+            ../../src/solaris/native/sun/awt/HeadlessToolkit.c
+            ../../src/solaris/native/sun/awt/HPkeysym.h
+            ../../src/solaris/native/sun/awt/img_util_md.h
+            ../../src/solaris/native/sun/awt/initIDs.c
+            ../../src/solaris/native/sun/awt/jawt.c
+            ../../src/solaris/native/sun/awt/list.c
+            ../../src/solaris/native/sun/awt/list.h
+            ../../src/solaris/native/sun/awt/multi_font.c
+            ../../src/solaris/native/sun/awt/multi_font.h
+            ../../src/solaris/native/sun/awt/multiVis.c
+            ../../src/solaris/native/sun/awt/multiVis.h
+            ../../src/solaris/native/sun/awt/randr.h
+            ../../src/solaris/native/sun/awt/robot_common.c
+            ../../src/solaris/native/sun/awt/robot_common.h
+            ../../src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.c
+            ../../src/solaris/native/sun/awt/swing_GTKEngine.c
+            ../../src/solaris/native/sun/awt/swing_GTKStyle.c
+            ../../src/solaris/native/sun/awt/VDrawingArea.c
+            ../../src/solaris/native/sun/awt/VDrawingArea.h
+            ../../src/solaris/native/sun/awt/VDrawingAreaP.h
+            ../../src/solaris/native/sun/awt/wsutils.h
+            ../../src/solaris/native/sun/awt/X11Color.c
+            ../../src/solaris/native/sun/awt/Xrandr.h
+            ../../src/solaris/native/sun/font/X11FontScaler.c
+            ../../src/solaris/native/sun/font/X11FontScaler.h
+            ../../src/solaris/native/sun/font/X11TextRenderer.c
+            ../../src/solaris/native/sun/java2d/loops/java2d_Mlib.c
+            ../../src/solaris/native/sun/java2d/loops/java2d_Mlib.h
+            ../../src/solaris/native/sun/java2d/loops/mlib_ImageCopy.h
+            ../../src/solaris/native/sun/java2d/loops/mlib_ImageLogic_proto.h
+            ../../src/solaris/native/sun/java2d/loops/mlib_ImageZoom.h
+            ../../src/solaris/native/sun/java2d/loops/mlib_ImageZoom_NN.c
+            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageClear.c
+            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageClear_f.c
+            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageClear_f.h
+            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageConstLogic.h
+            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageConstXor.c
+            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageLogic.h
+            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageLogic_proto.h
+            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageXor.c
+            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageZoom_NN_f.c
+            ../../src/solaris/native/sun/java2d/loops/vis_AlphaMacros.c
+            ../../src/solaris/native/sun/java2d/loops/vis_AlphaMacros.h
+            ../../src/solaris/native/sun/java2d/loops/vis_AlphaMaskBlit.c
+            ../../src/solaris/native/sun/java2d/loops/vis_AlphaMaskFill.c
+            ../../src/solaris/native/sun/java2d/loops/vis_ByteGray.c
+            ../../src/solaris/native/sun/java2d/loops/vis_ByteGray_FromRgb.c
+            ../../src/solaris/native/sun/java2d/loops/vis_ByteGray_Mask.c
+            ../../src/solaris/native/sun/java2d/loops/vis_ByteIndexed.c
+            ../../src/solaris/native/sun/java2d/loops/vis_DrawLine.c
+            ../../src/solaris/native/sun/java2d/loops/vis_FourByteAbgr.c
+            ../../src/solaris/native/sun/java2d/loops/vis_FourByteAbgrPre.c
+            ../../src/solaris/native/sun/java2d/loops/vis_FuncArray.c
+            ../../src/solaris/native/sun/java2d/loops/vis_GlyphList.c
+            ../../src/solaris/native/sun/java2d/loops/vis_GlyphListXor.c
+            ../../src/solaris/native/sun/java2d/loops/vis_IntArgb.c
+            ../../src/solaris/native/sun/java2d/loops/vis_IntArgbBm.c
+            ../../src/solaris/native/sun/java2d/loops/vis_IntArgbPre.c
+            ../../src/solaris/native/sun/java2d/loops/vis_IntArgbPre_Mask.c
+            ../../src/solaris/native/sun/java2d/loops/vis_IntBgr.c
+            ../../src/solaris/native/sun/java2d/loops/vis_Interp.c
+            ../../src/solaris/native/sun/java2d/loops/vis_IntRgb.c
+            ../../src/solaris/native/sun/java2d/loops/vis_IntRgbx.c
+            ../../src/solaris/native/sun/java2d/loops/vis_SrcMaskFill.c
+            ../../src/solaris/native/sun/java2d/loops/vis_SrcOverMaskBlit.c
+            ../../src/solaris/native/sun/java2d/loops/vis_SrcOverMaskFill.c
+            ../../src/solaris/native/sun/java2d/loops/vis_ThreeByteBgr.c
+            ../../src/solaris/native/sun/java2d/loops/vis_UshortGray.c
+            ../../src/solaris/native/sun/java2d/loops/vis_UshortGray_FromRgb.c
+            ../../src/solaris/native/sun/java2d/loops/vis_XorBlit.c
+            ../../src/solaris/native/sun/java2d/opengl/J2D_GL/glx.h
+            ../../src/solaris/native/sun/java2d/opengl/J2D_GL/glxext.h
+            ../../src/solaris/native/sun/java2d/opengl/GLXGraphicsConfig.c
+            ../../src/solaris/native/sun/java2d/opengl/GLXGraphicsConfig.h
+            ../../src/solaris/native/sun/java2d/opengl/GLXSurfaceData.c
+            ../../src/solaris/native/sun/java2d/opengl/GLXSurfaceData.h
+            ../../src/solaris/native/sun/java2d/opengl/OGLFuncs_md.h
+            ../../src/solaris/native/sun/java2d/x11/X11FontScaler_md.c
+            ../../src/solaris/native/sun/java2d/x11/X11PMBlitLoops.c
+            ../../src/solaris/native/sun/java2d/x11/X11Renderer.c
+            ../../src/solaris/native/sun/java2d/x11/X11SurfaceData.c
+            ../../src/solaris/native/sun/java2d/x11/X11SurfaceData.h
+            ../../src/solaris/native/sun/java2d/x11/X11TextRenderer_md.c
+            ../../src/solaris/native/sun/java2d/x11/XRBackendNative.c
+            ../../src/solaris/native/sun/java2d/x11/XRSurfaceData.c
+            ../../src/solaris/native/sun/java2d/j2d_md.h
+            ../../src/solaris/native/sun/jdga/dgalock.c
+            ../../src/solaris/native/sun/jdga/jdga.h
+            ../../src/solaris/native/sun/jdga/jdgadevice.h
+            ../../src/solaris/native/sun/management/FileSystemImpl.c
+            ../../src/solaris/native/sun/management/LinuxOperatingSystem.c
+            ../../src/solaris/native/sun/management/MacosxOperatingSystem.c
+            ../../src/solaris/native/sun/management/OperatingSystemImpl.c
+            ../../src/solaris/native/sun/management/SolarisOperatingSystem.c
+            ../../src/solaris/native/sun/net/dns/ResolverConfigurationImpl.c
+            ../../src/solaris/native/sun/net/sdp/SdpSupport.c
+            ../../src/solaris/native/sun/net/spi/DefaultProxySelector.c
+            ../../src/solaris/native/sun/net/portconfig.c
+            ../../src/solaris/native/sun/nio/ch/sctp/Sctp.h
+            ../../src/solaris/native/sun/nio/ch/sctp/SctpChannelImpl.c
+            ../../src/solaris/native/sun/nio/ch/sctp/SctpNet.c
+            ../../src/solaris/native/sun/nio/ch/sctp/SctpServerChannelImpl.c
+            ../../src/solaris/native/sun/nio/ch/DatagramChannelImpl.c
+            ../../src/solaris/native/sun/nio/ch/DatagramDispatcher.c
+            ../../src/solaris/native/sun/nio/ch/DevPollArrayWrapper.c
+            ../../src/solaris/native/sun/nio/ch/EPoll.c
+            ../../src/solaris/native/sun/nio/ch/EPollArrayWrapper.c
+            ../../src/solaris/native/sun/nio/ch/EPollPort.c
+            ../../src/solaris/native/sun/nio/ch/FileChannelImpl.c
+            ../../src/solaris/native/sun/nio/ch/FileDispatcherImpl.c
+            ../../src/solaris/native/sun/nio/ch/FileKey.c
+            ../../src/solaris/native/sun/nio/ch/InheritedChannel.c
+            ../../src/solaris/native/sun/nio/ch/IOUtil.c
+            ../../src/solaris/native/sun/nio/ch/KQueue.c
+            ../../src/solaris/native/sun/nio/ch/KQueuePort.c
+            ../../src/solaris/native/sun/nio/ch/NativeThread.c
+            ../../src/solaris/native/sun/nio/ch/Net.c
+            ../../src/solaris/native/sun/nio/ch/nio_util.h
+            ../../src/solaris/native/sun/nio/ch/PollArrayWrapper.c
+            ../../src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c
+            ../../src/solaris/native/sun/nio/ch/SocketChannelImpl.c
+            ../../src/solaris/native/sun/nio/ch/SocketDispatcher.c
+            ../../src/solaris/native/sun/nio/ch/SolarisEventPort.c
+            ../../src/solaris/native/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.c
+            ../../src/solaris/native/sun/nio/ch/UnixAsynchronousSocketChannelImpl.c
+            ../../src/solaris/native/sun/nio/fs/BsdNativeDispatcher.c
+            ../../src/solaris/native/sun/nio/fs/GnomeFileTypeDetector.c
+            ../../src/solaris/native/sun/nio/fs/LinuxNativeDispatcher.c
+            ../../src/solaris/native/sun/nio/fs/LinuxWatchService.c
+            ../../src/solaris/native/sun/nio/fs/MacOSXNativeDispatcher.c
+            ../../src/solaris/native/sun/nio/fs/MagicFileTypeDetector.c
+            ../../src/solaris/native/sun/nio/fs/SolarisNativeDispatcher.c
+            ../../src/solaris/native/sun/nio/fs/SolarisWatchService.c
+            ../../src/solaris/native/sun/nio/fs/UnixCopyFile.c
+            ../../src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c
+            ../../src/solaris/native/sun/security/jgss/wrapper/NativeFunc.c
+            ../../src/solaris/native/sun/security/jgss/wrapper/NativeFunc.h
+            ../../src/solaris/native/sun/security/pkcs11/wrapper/p11_md.c
+            ../../src/solaris/native/sun/security/pkcs11/wrapper/p11_md.h
+            ../../src/solaris/native/sun/security/pkcs11/j2secmod_md.c
+            ../../src/solaris/native/sun/security/pkcs11/j2secmod_md.h
+            ../../src/solaris/native/sun/security/smartcardio/MUSCLE/pcsclite.h
+            ../../src/solaris/native/sun/security/smartcardio/MUSCLE/winscard.h
+            ../../src/solaris/native/sun/security/smartcardio/pcsc_md.c
+            ../../src/solaris/native/sun/security/smartcardio/pcsc_md.h
+            ../../src/solaris/native/sun/tools/attach/BsdVirtualMachine.c
+            ../../src/solaris/native/sun/tools/attach/LinuxVirtualMachine.c
+            ../../src/solaris/native/sun/tools/attach/SolarisVirtualMachine.c
+            ../../src/solaris/native/sun/tracing/dtrace/jvm_symbols_md.c)
+
+elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+    set(SOURCE_FILES
+            ${SOURCE_FILES}
+            ../../src/windows/native/com/sun/media/sound/PLATFORM_API_WinOS_DirectSound.cpp
+            ../../src/windows/native/com/sun/media/sound/PLATFORM_API_WinOS_MidiIn.cpp
+            ../../src/windows/native/com/sun/media/sound/PLATFORM_API_WinOS_MidiOut.c
+            ../../src/windows/native/com/sun/media/sound/PLATFORM_API_WinOS_Ports.c
+            ../../src/windows/native/com/sun/media/sound/PLATFORM_API_WinOS_Util.c
+            ../../src/windows/native/com/sun/media/sound/PLATFORM_API_WinOS_Util.h
+            ../../src/windows/native/com/sun/security/auth/module/nt.c
+            ../../src/windows/native/common/gdefs_md.h
+            ../../src/windows/native/common/java_main_md.h
+            ../../src/windows/native/common/jdk_util_md.c
+            ../../src/windows/native/common/jdk_util_md.h
+            ../../src/windows/native/common/jlong_md.h
+            ../../src/windows/native/common/jni_util_md.c
+            ../../src/windows/native/common/locale_str.h
+            ../../src/windows/native/java/io/canonicalize_md.c
+            ../../src/windows/native/java/io/Console_md.c
+            ../../src/windows/native/java/io/dirent_md.c
+            ../../src/windows/native/java/io/dirent_md.h
+            ../../src/windows/native/java/io/FileDescriptor_md.c
+            ../../src/windows/native/java/io/FileInputStream_md.c
+            ../../src/windows/native/java/io/FileOutputStream_md.c
+            ../../src/windows/native/java/io/io_util_md.c
+            ../../src/windows/native/java/io/io_util_md.h
+            ../../src/windows/native/java/io/RandomAccessFile_md.c
+            ../../src/windows/native/java/io/WinNTFileSystem_md.c
+            ../../src/windows/native/java/lang/java_props_md.c
+            ../../src/windows/native/java/lang/ProcessEnvironment_md.c
+            ../../src/windows/native/java/lang/ProcessImpl_md.c
+            ../../src/windows/native/java/net/DualStackPlainDatagramSocketImpl.c
+            ../../src/windows/native/java/net/DualStackPlainSocketImpl.c
+            ../../src/windows/native/java/net/ExtendedOptionsImpl.c
+            ../../src/windows/native/java/net/icmp.h
+            ../../src/windows/native/java/net/Inet4AddressImpl.c
+            ../../src/windows/native/java/net/Inet6AddressImpl.c
+            ../../src/windows/native/java/net/InetAddressImplFactory.c
+            ../../src/windows/native/java/net/NetworkInterface.c
+            ../../src/windows/native/java/net/NetworkInterface.h
+            ../../src/windows/native/java/net/NetworkInterface_winXP.c
+            ../../src/windows/native/java/net/net_util_md.c
+            ../../src/windows/native/java/net/net_util_md.h
+            ../../src/windows/native/java/net/SocketInputStream.c
+            ../../src/windows/native/java/net/SocketOutputStream.c
+            ../../src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c
+            ../../src/windows/native/java/net/TwoStacksPlainSocketImpl.c
+            ../../src/windows/native/java/nio/MappedByteBuffer.c
+            ../../src/windows/native/java/util/logging.c
+            ../../src/windows/native/java/util/TimeZone_md.c
+            ../../src/windows/native/java/util/TimeZone_md.h
+            ../../src/windows/native/java/util/WindowsPreferences.c
+            ../../src/windows/native/sun/awt/splashscreen/splashscreen_config.h
+            ../../src/windows/native/sun/awt/splashscreen/splashscreen_sys.c
+            ../../src/windows/native/sun/awt/utility/rect.h
+            ../../src/windows/native/sun/awt_common/awt_makecube.cpp
+            ../../src/windows/native/sun/bridge/AccessBridgeATInstance.cpp
+            ../../src/windows/native/sun/bridge/AccessBridgeATInstance.h
+            ../../src/windows/native/sun/bridge/AccessBridgeCallbacks.h
+            ../../src/windows/native/sun/bridge/AccessBridgeCalls.c
+            ../../src/windows/native/sun/bridge/AccessBridgeCalls.h
+            ../../src/windows/native/sun/bridge/AccessBridgeDebug.cpp
+            ../../src/windows/native/sun/bridge/AccessBridgeDebug.h
+            ../../src/windows/native/sun/bridge/AccessBridgeEventHandler.cpp
+            ../../src/windows/native/sun/bridge/AccessBridgeEventHandler.h
+            ../../src/windows/native/sun/bridge/AccessBridgeJavaEntryPoints.cpp
+            ../../src/windows/native/sun/bridge/AccessBridgeJavaEntryPoints.h
+            ../../src/windows/native/sun/bridge/AccessBridgeJavaVMInstance.cpp
+            ../../src/windows/native/sun/bridge/AccessBridgeJavaVMInstance.h
+            ../../src/windows/native/sun/bridge/AccessBridgeMessageQueue.cpp
+            ../../src/windows/native/sun/bridge/AccessBridgeMessageQueue.h
+            ../../src/windows/native/sun/bridge/AccessBridgeMessages.cpp
+            ../../src/windows/native/sun/bridge/AccessBridgeMessages.h
+            ../../src/windows/native/sun/bridge/AccessBridgePackages.h
+            ../../src/windows/native/sun/bridge/accessBridgeResource.h
+            ../../src/windows/native/sun/bridge/AccessBridgeStatusWindow.RC
+            ../../src/windows/native/sun/bridge/AccessBridgeWindowsEntryPoints.cpp
+            ../../src/windows/native/sun/bridge/AccessBridgeWindowsEntryPoints.h
+            ../../src/windows/native/sun/bridge/accessibility.properties
+            ../../src/windows/native/sun/bridge/jabswitch.cpp
+            ../../src/windows/native/sun/bridge/jabswitch.manifest
+            ../../src/windows/native/sun/bridge/jabswitch_manifest.rc
+            ../../src/windows/native/sun/bridge/JavaAccessBridge.cpp
+            ../../src/windows/native/sun/bridge/JavaAccessBridge.h
+            ../../src/windows/native/sun/bridge/JAWTAccessBridge.cpp
+            ../../src/windows/native/sun/bridge/JAWTAccessBridge.h
+            ../../src/windows/native/sun/bridge/resource.h
+            ../../src/windows/native/sun/bridge/WinAccessBridge.cpp
+            ../../src/windows/native/sun/bridge/WinAccessBridge.DEF
+            ../../src/windows/native/sun/bridge/WinAccessBridge.h
+            ../../src/windows/native/sun/font/fontpath.c
+            ../../src/windows/native/sun/font/lcdglyph.c
+            ../../src/windows/native/sun/font/lcdglyphDW.cpp
+            ../../src/windows/native/sun/io/Win32ErrorMode.c
+            ../../src/windows/native/sun/java2d/d3d/D3DBadHardware.h
+            ../../src/windows/native/sun/java2d/d3d/D3DBlitLoops.cpp
+            ../../src/windows/native/sun/java2d/d3d/D3DBlitLoops.h
+            ../../src/windows/native/sun/java2d/d3d/D3DBufImgOps.cpp
+            ../../src/windows/native/sun/java2d/d3d/D3DBufImgOps.h
+            ../../src/windows/native/sun/java2d/d3d/D3DContext.cpp
+            ../../src/windows/native/sun/java2d/d3d/D3DContext.h
+            ../../src/windows/native/sun/java2d/d3d/D3DGlyphCache.cpp
+            ../../src/windows/native/sun/java2d/d3d/D3DGlyphCache.h
+            ../../src/windows/native/sun/java2d/d3d/D3DGraphicsDevice.cpp
+            ../../src/windows/native/sun/java2d/d3d/D3DGraphicsDevice.h
+            ../../src/windows/native/sun/java2d/d3d/D3DMaskBlit.cpp
+            ../../src/windows/native/sun/java2d/d3d/D3DMaskBlit.h
+            ../../src/windows/native/sun/java2d/d3d/D3DMaskCache.cpp
+            ../../src/windows/native/sun/java2d/d3d/D3DMaskCache.h
+            ../../src/windows/native/sun/java2d/d3d/D3DMaskFill.cpp
+            ../../src/windows/native/sun/java2d/d3d/D3DMaskFill.h
+            ../../src/windows/native/sun/java2d/d3d/D3DPaints.cpp
+            ../../src/windows/native/sun/java2d/d3d/D3DPaints.h
+            ../../src/windows/native/sun/java2d/d3d/D3DPipeline.cpp
+            ../../src/windows/native/sun/java2d/d3d/D3DPipeline.h
+            ../../src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp
+            ../../src/windows/native/sun/java2d/d3d/D3DPipelineManager.h
+            ../../src/windows/native/sun/java2d/d3d/D3DRenderer.cpp
+            ../../src/windows/native/sun/java2d/d3d/D3DRenderer.h
+            ../../src/windows/native/sun/java2d/d3d/D3DRenderQueue.cpp
+            ../../src/windows/native/sun/java2d/d3d/D3DRenderQueue.h
+            ../../src/windows/native/sun/java2d/d3d/D3DResourceManager.cpp
+            ../../src/windows/native/sun/java2d/d3d/D3DResourceManager.h
+            ../../src/windows/native/sun/java2d/d3d/D3DShaderGen.c
+            ../../src/windows/native/sun/java2d/d3d/D3DShaders.h
+            ../../src/windows/native/sun/java2d/d3d/D3DSurfaceData.cpp
+            ../../src/windows/native/sun/java2d/d3d/D3DSurfaceData.h
+            ../../src/windows/native/sun/java2d/d3d/D3DTextRenderer.cpp
+            ../../src/windows/native/sun/java2d/d3d/D3DTextRenderer.h
+            ../../src/windows/native/sun/java2d/d3d/D3DVertexCacher.cpp
+            ../../src/windows/native/sun/java2d/d3d/D3DVertexCacher.h
+            ../../src/windows/native/sun/java2d/j2d_md.h
+            ../../src/windows/native/sun/java2d/opengl/J2D_GL/wglext.h
+            ../../src/windows/native/sun/java2d/opengl/OGLFuncs_md.h
+            ../../src/windows/native/sun/java2d/opengl/WGLGraphicsConfig.c
+            ../../src/windows/native/sun/java2d/opengl/WGLGraphicsConfig.h
+            ../../src/windows/native/sun/java2d/opengl/WGLSurfaceData.c
+            ../../src/windows/native/sun/java2d/opengl/WGLSurfaceData.h
+            ../../src/windows/native/sun/java2d/windows/GDIBlitLoops.cpp
+            ../../src/windows/native/sun/java2d/windows/GDIRenderer.cpp
+            ../../src/windows/native/sun/java2d/windows/GDIWindowSurfaceData.cpp
+            ../../src/windows/native/sun/java2d/windows/GDIWindowSurfaceData.h
+            ../../src/windows/native/sun/java2d/windows/WindowsFlags.cpp
+            ../../src/windows/native/sun/java2d/windows/WindowsFlags.h
+            ../../src/windows/native/sun/management/FileSystemImpl.c
+            ../../src/windows/native/sun/management/OperatingSystemImpl.c
+            ../../src/windows/native/sun/net/dns/ResolverConfigurationImpl.c
+            ../../src/windows/native/sun/net/portconfig.c
+            ../../src/windows/native/sun/net/spi/DefaultProxySelector.c
+            ../../src/windows/native/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.c
+            ../../src/windows/native/sun/nio/ch/DatagramChannelImpl.c
+            ../../src/windows/native/sun/nio/ch/DatagramDispatcher.c
+            ../../src/windows/native/sun/nio/ch/FileChannelImpl.c
+            ../../src/windows/native/sun/nio/ch/FileDispatcherImpl.c
+            ../../src/windows/native/sun/nio/ch/FileKey.c
+            ../../src/windows/native/sun/nio/ch/Iocp.c
+            ../../src/windows/native/sun/nio/ch/IOUtil.c
+            ../../src/windows/native/sun/nio/ch/Net.c
+            ../../src/windows/native/sun/nio/ch/nio_util.h
+            ../../src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c
+            ../../src/windows/native/sun/nio/ch/SocketChannelImpl.c
+            ../../src/windows/native/sun/nio/ch/SocketDispatcher.c
+            ../../src/windows/native/sun/nio/ch/WindowsAsynchronousFileChannelImpl.c
+            ../../src/windows/native/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.c
+            ../../src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c
+            ../../src/windows/native/sun/nio/ch/WindowsSelectorImpl.c
+            ../../src/windows/native/sun/nio/fs/RegistryFileTypeDetector.c
+            ../../src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c
+            ../../src/windows/native/sun/security/krb5/NativeCreds.c
+            ../../src/windows/native/sun/security/krb5/WindowsDirectory.c
+            ../../src/windows/native/sun/security/mscapi/security.cpp
+            ../../src/windows/native/sun/security/pkcs11/j2secmod_md.c
+            ../../src/windows/native/sun/security/pkcs11/j2secmod_md.h
+            ../../src/windows/native/sun/security/pkcs11/wrapper/p11_md.c
+            ../../src/windows/native/sun/security/pkcs11/wrapper/p11_md.h
+            ../../src/windows/native/sun/security/provider/WinCAPISeedGenerator.c
+            ../../src/windows/native/sun/security/smartcardio/pcsc_md.c
+            ../../src/windows/native/sun/security/smartcardio/pcsc_md.h
+            ../../src/windows/native/sun/tools/attach/WindowsAttachProvider.c
+            ../../src/windows/native/sun/tools/attach/WindowsVirtualMachine.c
+            ../../src/windows/native/sun/tracing/dtrace/jvm_symbols_md.c
+            ../../src/windows/native/sun/util/locale/provider/HostLocaleProviderAdapter_md.c
+            ../../src/windows/native/sun/windows/alloc.h
+            ../../src/windows/native/sun/windows/awt.h
+            ../../src/windows/native/sun/windows/awt.rc
+            ../../src/windows/native/sun/windows/awtmsg.h
+            ../../src/windows/native/sun/windows/awt_AWTEvent.cpp
+            ../../src/windows/native/sun/windows/awt_AWTEvent.h
+            ../../src/windows/native/sun/windows/awt_BitmapUtil.cpp
+            ../../src/windows/native/sun/windows/awt_BitmapUtil.h
+            ../../src/windows/native/sun/windows/awt_Brush.cpp
+            ../../src/windows/native/sun/windows/awt_Brush.h
+            ../../src/windows/native/sun/windows/awt_Button.cpp
+            ../../src/windows/native/sun/windows/awt_Button.h
+            ../../src/windows/native/sun/windows/awt_Canvas.cpp
+            ../../src/windows/native/sun/windows/awt_Canvas.h
+            ../../src/windows/native/sun/windows/awt_Checkbox.cpp
+            ../../src/windows/native/sun/windows/awt_Checkbox.h
+            ../../src/windows/native/sun/windows/awt_Choice.cpp
+            ../../src/windows/native/sun/windows/awt_Choice.h
+            ../../src/windows/native/sun/windows/awt_Clipboard.cpp
+            ../../src/windows/native/sun/windows/awt_Clipboard.h
+            ../../src/windows/native/sun/windows/awt_Color.cpp
+            ../../src/windows/native/sun/windows/awt_Color.h
+            ../../src/windows/native/sun/windows/awt_Component.cpp
+            ../../src/windows/native/sun/windows/awt_Component.h
+            ../../src/windows/native/sun/windows/awt_Container.cpp
+            ../../src/windows/native/sun/windows/awt_Container.h
+            ../../src/windows/native/sun/windows/awt_Cursor.cpp
+            ../../src/windows/native/sun/windows/awt_Cursor.h
+            ../../src/windows/native/sun/windows/awt_CustomPaletteDef.h
+            ../../src/windows/native/sun/windows/awt_DataTransferer.cpp
+            ../../src/windows/native/sun/windows/awt_DataTransferer.h
+            ../../src/windows/native/sun/windows/awt_DCHolder.cpp
+            ../../src/windows/native/sun/windows/awt_DCHolder.h
+            ../../src/windows/native/sun/windows/awt_Debug.cpp
+            ../../src/windows/native/sun/windows/awt_Debug.h
+            ../../src/windows/native/sun/windows/awt_Desktop.cpp
+            ../../src/windows/native/sun/windows/awt_DesktopProperties.cpp
+            ../../src/windows/native/sun/windows/awt_DesktopProperties.h
+            ../../src/windows/native/sun/windows/awt_Dialog.cpp
+            ../../src/windows/native/sun/windows/awt_Dialog.h
+            ../../src/windows/native/sun/windows/awt_Dimension.cpp
+            ../../src/windows/native/sun/windows/awt_Dimension.h
+            ../../src/windows/native/sun/windows/awt_DnDDS.cpp
+            ../../src/windows/native/sun/windows/awt_DnDDS.h
+            ../../src/windows/native/sun/windows/awt_DnDDT.cpp
+            ../../src/windows/native/sun/windows/awt_DnDDT.h
+            ../../src/windows/native/sun/windows/awt_DrawingSurface.cpp
+            ../../src/windows/native/sun/windows/awt_DrawingSurface.h
+            ../../src/windows/native/sun/windows/awt_Event.cpp
+            ../../src/windows/native/sun/windows/awt_Event.h
+            ../../src/windows/native/sun/windows/awt_FileDialog.cpp
+            ../../src/windows/native/sun/windows/awt_FileDialog.h
+            ../../src/windows/native/sun/windows/awt_Font.cpp
+            ../../src/windows/native/sun/windows/awt_Font.h
+            ../../src/windows/native/sun/windows/awt_Frame.cpp
+            ../../src/windows/native/sun/windows/awt_Frame.h
+            ../../src/windows/native/sun/windows/awt_GDIObject.cpp
+            ../../src/windows/native/sun/windows/awt_GDIObject.h
+            ../../src/windows/native/sun/windows/awt_IconCursor.cpp
+            ../../src/windows/native/sun/windows/awt_IconCursor.h
+            ../../src/windows/native/sun/windows/awt_InputEvent.cpp
+            ../../src/windows/native/sun/windows/awt_InputEvent.h
+            ../../src/windows/native/sun/windows/awt_InputMethod.cpp
+            ../../src/windows/native/sun/windows/awt_InputTextInfor.cpp
+            ../../src/windows/native/sun/windows/awt_InputTextInfor.h
+            ../../src/windows/native/sun/windows/awt_Insets.cpp
+            ../../src/windows/native/sun/windows/awt_Insets.h
+            ../../src/windows/native/sun/windows/awt_KeyboardFocusManager.cpp
+            ../../src/windows/native/sun/windows/awt_KeyEvent.cpp
+            ../../src/windows/native/sun/windows/awt_KeyEvent.h
+            ../../src/windows/native/sun/windows/awt_Label.cpp
+            ../../src/windows/native/sun/windows/awt_Label.h
+            ../../src/windows/native/sun/windows/awt_List.cpp
+            ../../src/windows/native/sun/windows/awt_List.h
+            ../../src/windows/native/sun/windows/awt_Menu.cpp
+            ../../src/windows/native/sun/windows/awt_Menu.h
+            ../../src/windows/native/sun/windows/awt_MenuBar.cpp
+            ../../src/windows/native/sun/windows/awt_MenuBar.h
+            ../../src/windows/native/sun/windows/awt_MenuItem.cpp
+            ../../src/windows/native/sun/windows/awt_MenuItem.h
+            ../../src/windows/native/sun/windows/awt_Mlib.cpp
+            ../../src/windows/native/sun/windows/awt_Mlib.h
+            ../../src/windows/native/sun/windows/awt_MouseEvent.cpp
+            ../../src/windows/native/sun/windows/awt_MouseEvent.h
+            ../../src/windows/native/sun/windows/awt_new.cpp
+            ../../src/windows/native/sun/windows/awt_new.h
+            ../../src/windows/native/sun/windows/awt_Object.cpp
+            ../../src/windows/native/sun/windows/awt_Object.h
+            ../../src/windows/native/sun/windows/awt_ole.cpp
+            ../../src/windows/native/sun/windows/awt_ole.h
+            ../../src/windows/native/sun/windows/awt_Palette.cpp
+            ../../src/windows/native/sun/windows/awt_Palette.h
+            ../../src/windows/native/sun/windows/awt_Panel.cpp
+            ../../src/windows/native/sun/windows/awt_Panel.h
+            ../../src/windows/native/sun/windows/awt_Pen.cpp
+            ../../src/windows/native/sun/windows/awt_Pen.h
+            ../../src/windows/native/sun/windows/awt_PopupMenu.cpp
+            ../../src/windows/native/sun/windows/awt_PopupMenu.h
+            ../../src/windows/native/sun/windows/awt_PrintControl.cpp
+            ../../src/windows/native/sun/windows/awt_PrintControl.h
+            ../../src/windows/native/sun/windows/awt_PrintDialog.cpp
+            ../../src/windows/native/sun/windows/awt_PrintDialog.h
+            ../../src/windows/native/sun/windows/awt_PrintJob.cpp
+            ../../src/windows/native/sun/windows/awt_Rectangle.cpp
+            ../../src/windows/native/sun/windows/awt_Rectangle.h
+            ../../src/windows/native/sun/windows/awt_Robot.cpp
+            ../../src/windows/native/sun/windows/awt_Robot.h
+            ../../src/windows/native/sun/windows/awt_Scrollbar.cpp
+            ../../src/windows/native/sun/windows/awt_Scrollbar.h
+            ../../src/windows/native/sun/windows/awt_ScrollPane.cpp
+            ../../src/windows/native/sun/windows/awt_ScrollPane.h
+            ../../src/windows/native/sun/windows/awt_TextArea.cpp
+            ../../src/windows/native/sun/windows/awt_TextArea.h
+            ../../src/windows/native/sun/windows/awt_TextComponent.cpp
+            ../../src/windows/native/sun/windows/awt_TextComponent.h
+            ../../src/windows/native/sun/windows/awt_TextField.cpp
+            ../../src/windows/native/sun/windows/awt_TextField.h
+            ../../src/windows/native/sun/windows/awt_Toolkit.cpp
+            ../../src/windows/native/sun/windows/awt_Toolkit.h
+            ../../src/windows/native/sun/windows/awt_TrayIcon.cpp
+            ../../src/windows/native/sun/windows/awt_TrayIcon.h
+            ../../src/windows/native/sun/windows/awt_Win32GraphicsConfig.cpp
+            ../../src/windows/native/sun/windows/awt_Win32GraphicsConfig.h
+            ../../src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp
+            ../../src/windows/native/sun/windows/awt_Win32GraphicsDevice.h
+            ../../src/windows/native/sun/windows/awt_Win32GraphicsEnv.cpp
+            ../../src/windows/native/sun/windows/awt_Window.cpp
+            ../../src/windows/native/sun/windows/awt_Window.h
+            ../../src/windows/native/sun/windows/check.bmp
+            ../../src/windows/native/sun/windows/CmdIDList.cpp
+            ../../src/windows/native/sun/windows/CmdIDList.h
+            ../../src/windows/native/sun/windows/colordata.h
+            ../../src/windows/native/sun/windows/ComCtl32Util.cpp
+            ../../src/windows/native/sun/windows/ComCtl32Util.h
+            ../../src/windows/native/sun/windows/Devices.cpp
+            ../../src/windows/native/sun/windows/Devices.h
+            ../../src/windows/native/sun/windows/DllUtil.cpp
+            ../../src/windows/native/sun/windows/DllUtil.h
+            ../../src/windows/native/sun/windows/GDIHashtable.cpp
+            ../../src/windows/native/sun/windows/GDIHashtable.h
+            ../../src/windows/native/sun/windows/hand.cur
+            ../../src/windows/native/sun/windows/Hashtable.cpp
+            ../../src/windows/native/sun/windows/Hashtable.h
+            ../../src/windows/native/sun/windows/img_util_md.h
+            ../../src/windows/native/sun/windows/initIDs.cpp
+            ../../src/windows/native/sun/windows/jawt.cpp
+            ../../src/windows/native/sun/windows/mlib_types_md.h
+            ../../src/windows/native/sun/windows/MouseInfo.cpp
+            ../../src/windows/native/sun/windows/ObjectList.cpp
+            ../../src/windows/native/sun/windows/ObjectList.h
+            ../../src/windows/native/sun/windows/README.JNI
+            ../../src/windows/native/sun/windows/security_warning.ico
+            ../../src/windows/native/sun/windows/security_warning_bw.ico
+            ../../src/windows/native/sun/windows/security_warning_int.ico
+            ../../src/windows/native/sun/windows/ShellFolder2.cpp
+            ../../src/windows/native/sun/windows/stdhdrs.h
+            ../../src/windows/native/sun/windows/ThemeReader.cpp
+            ../../src/windows/native/sun/windows/WBufferStrategy.cpp
+            ../../src/windows/native/sun/windows/WPrinterJob.cpp)
+endif()
+
+add_custom_target(make_java /usr/bin/make -C ${CMAKE_SOURCE_DIR}/../../../
+        DEPENDS ${SOURCE_FILES})
+
+add_executable(java ${SOURCE_FILES})
diff --git a/make/CopyFiles.gmk b/make/CopyFiles.gmk
index bc070f0..debf8f2 100644
--- a/make/CopyFiles.gmk
+++ b/make/CopyFiles.gmk
@@ -487,6 +487,42 @@
     COPY_FILES += $(OBL_FONTS_DST) $(OBL_FONTS_DST_DIR)/fonts.dir
 
   endif # linux
+else #OPENJDK
+  SHARED_FONTS_SRC_DIR := $(JDK_TOPDIR)/src/share/lib/fonts
+  SHARED_FONTS_DST_DIR := $(JDK_OUTPUTDIR)/lib/fonts
+
+  SHARED_FONTS_FILES := \
+      DroidSans-Bold.ttf \
+      DroidSerif-Regular.ttf \
+      DroidSans.ttf \
+      DroidSerif-Bold.ttf \
+      DroidSansMono.ttf \
+      DroidSansMonoDotted.ttf \
+      DroidSansMonoSlashed.ttf \
+      DroidSerif-BoldItalic.ttf \
+      DroidSerif-Italic.ttf
+
+
+  SHARED_FONTS_SRC := $(foreach F, $(SHARED_FONTS_FILES), $(SHARED_FONTS_SRC_DIR)/$(F))
+  SHARED_FONTS_DST := $(foreach F, $(SHARED_FONTS_FILES), $(SHARED_FONTS_DST_DIR)/$(F))
+
+  $(SHARED_FONTS_DST_DIR)/%.ttf: $(SHARED_FONTS_SRC_DIR)/%.ttf
+	$(call install-file)
+
+  $(SHARED_FONTS_DST_DIR)/fonts.dir: $(JDK_TOPDIR)/src/share/lib/fonts/fonts.dir
+	$(call install-file)
+
+  $(SHARED_FONTS_DST_DIR)/LICENSE.txt: $(JDK_TOPDIR)/src/share/lib/fonts/LICENSE.txt
+	$(call install-file)
+
+  COPY_FILES += $(SHARED_FONTS_DST)
+
+  ifneq ($(OPENJDK_TARGET_OS), windows)
+    COPY_FILES += $(SHARED_FONTS_DST_DIR)/fonts.dir
+  endif
+
+  COPY_FILES += $(SHARED_FONTS_DST_DIR)/LICENSE.txt
+
 endif # OPENJDK
 
 ##########################################################################################
diff --git a/make/gendata/GendataFontConfig.gmk b/make/gendata/GendataFontConfig.gmk
index 35b502d..5ac2425 100644
--- a/make/gendata/GendataFontConfig.gmk
+++ b/make/gendata/GendataFontConfig.gmk
@@ -38,7 +38,8 @@
         $(JDK_TOPDIR)/src/solaris/classes/sun/awt/fontconfigs
     # This is placeholder for possible fonconfig files which may
     # useful for some highly specialized Linux distributions
-    GENDATA_FONT_CONFIG_SRC_FILES :=
+    GENDATA_FONT_CONFIG_SRC_FILES := fontconfig.properties
+    GENDATA_FONT_CONFIG_SRC_PREFIX := linux.
   else
     GENDATA_FONT_CONFIG_SRC_DIR := \
         $(JDK_TOPDIR)/src/closed/solaris/classes/sun/awt/fontconfigs
diff --git a/make/lib/Awt2dLibraries.gmk b/make/lib/Awt2dLibraries.gmk
index 2c843f5..a3c66c5 100644
--- a/make/lib/Awt2dLibraries.gmk
+++ b/make/lib/Awt2dLibraries.gmk
@@ -859,6 +859,33 @@
 
 ##########################################################################################
 
+#### Begin harfbuzz configuration
+
+HARFBUZZ_CFLAGS := -I$(JDK_TOPDIR)/src/share/native/sun/font/harfbuzz \
+    -I$(JDK_TOPDIR)/src/share/native/sun/font/harfbuzz/hb-ucdn \
+    -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.cpp
+endif
+# hb-ft.cc is not presently needed, and requires freetype 2.4.2 or later.
+LIBFONTMANAGER_EXCLUDE_FILES += harfbuzz/hb-ft.cpp
+
+#### End harfbuzz configuration
+
 ifndef OPENJDK
   FONT_HEADERS := -I$(JDK_TOPDIR)/src/closed/share/native/sun/font/t2k
   BUILD_LIBFONTMANAGER_MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libfontmanager/mapfile-vers
@@ -879,10 +906,12 @@
   LIBFONTMANAGER_EXCLUDE_FILES += X11FontScaler.c \
       X11TextRenderer.c \
       fontpath.c \
-      lcdglyph.c
+      lcdglyph.c \
+      lcdglyphDW.cpp
 else
   LIBFONTMANAGER_EXCLUDE_FILES += fontpath.c \
-      lcdglyph.c
+      lcdglyph.c \
+      lcdglyphDW.cpp
 endif
 
 BUILD_LIBFONTMANAGER_CFLAGS_COMMON := \
@@ -897,7 +926,8 @@
     -I$(JDK_TOPDIR)/src/share/native/sun/java2d/loops \
     -I$(JDK_TOPDIR)/src/share/native/sun/java2d/pipe \
     -I$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/java2d \
-    -I$(JDK_TOPDIR)/src/share/native/sun/java2d
+    -I$(JDK_TOPDIR)/src/share/native/sun/java2d \
+    $(HARFBUZZ_CFLAGS)
 
 # Turn off aliasing with GCC for ExtensionSubtables.cpp
 ifeq ($(OPENJDK_TARGET_OS), linux)
diff --git a/make/mapfiles/libfontmanager/mapfile-vers b/make/mapfiles/libfontmanager/mapfile-vers
index 2a83f29..3c6716f 100644
--- a/make/mapfiles/libfontmanager/mapfile-vers
+++ b/make/mapfiles/libfontmanager/mapfile-vers
@@ -31,6 +31,8 @@
                 newLayoutTableCache;
                 freeLayoutTableCache;
                 isNullScalerContext;
+                Java_sun_font_Font2D_createHarfbuzzFace;
+                Java_sun_font_Font2D_disposeHarfbuzzFace;
                 Java_sun_font_NullFontScaler_getNullScalerContext;
                 Java_sun_font_NullFontScaler_getGlyphImage;
                 Java_sun_font_SunFontManager_initIDs;
@@ -41,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;
diff --git a/make/mapfiles/libfontmanager/mapfile-vers.openjdk b/make/mapfiles/libfontmanager/mapfile-vers.openjdk
index b20344e..058c9c5 100644
--- a/make/mapfiles/libfontmanager/mapfile-vers.openjdk
+++ b/make/mapfiles/libfontmanager/mapfile-vers.openjdk
@@ -33,6 +33,8 @@
                 newLayoutTableCache;
                 freeLayoutTableCache;
                 isNullScalerContext;
+                Java_sun_font_Font2D_createHarfbuzzFace;
+                Java_sun_font_Font2D_disposeHarfbuzzFace;
                 Java_sun_font_NullFontScaler_getNullScalerContext;
                 Java_sun_font_NullFontScaler_getGlyphImage;
                 Java_sun_font_SunFontManager_initIDs;
@@ -43,6 +45,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;
diff --git a/src/macosx/classes/com/apple/eawt/event/GestureHandler.java b/src/macosx/classes/com/apple/eawt/event/GestureHandler.java
index 4514da9..e3813cf 100644
--- a/src/macosx/classes/com/apple/eawt/event/GestureHandler.java
+++ b/src/macosx/classes/com/apple/eawt/event/GestureHandler.java
@@ -43,6 +43,7 @@
     @Native static final int ROTATE = 2;
     @Native static final int MAGNIFY = 3;
     @Native static final int SWIPE = 4;
+    @Native static final int PRESSURE = 5;
 
     // installs a private instance of GestureHandler, if necessary
     static void addGestureListenerTo(final JComponent component, final GestureListener listener) {
@@ -97,6 +98,9 @@
                     case SWIPE:
                         firstNotifier.recursivelyHandleSwipe(a, b, new SwipeEvent());
                         return;
+                    case PRESSURE:
+                        firstNotifier.recursivelyHandlePressure(new PressureEvent(a,b));
+                        return;
                 }
             }
         });
@@ -107,6 +111,7 @@
     final List<RotationListener> rotaters = new LinkedList<RotationListener>();
     final List<MagnificationListener> magnifiers = new LinkedList<MagnificationListener>();
     final List<SwipeListener> swipers = new LinkedList<SwipeListener>();
+    final List<PressureListener> pressures = new LinkedList<PressureListener>();
 
     GestureHandler() { }
 
@@ -115,6 +120,7 @@
         if (listener instanceof RotationListener) rotaters.add((RotationListener)listener);
         if (listener instanceof MagnificationListener) magnifiers.add((MagnificationListener)listener);
         if (listener instanceof SwipeListener) swipers.add((SwipeListener)listener);
+        if (listener instanceof PressureListener) pressures.add((PressureListener)listener);
     }
 
     void removeListener(final GestureListener listener) {
@@ -169,6 +175,16 @@
             if (next != null) next.recursivelyHandleMagnify(e);
         }
 
+        void recursivelyHandlePressure(final PressureEvent e) {
+            for (final PressureListener listener : handler.pressures) {
+                listener.pressure(e);
+                if (e.isConsumed()) return;
+            }
+
+            final PerComponentNotifier next = getNextNotifierForComponent(component.getParent());
+            if (next != null) next.recursivelyHandlePressure(e);
+        }
+
         void recursivelyHandleSwipe(final double x, final double y, final SwipeEvent e) {
             for (final SwipeListener listener : handler.swipers) {
                 if (x < 0) listener.swipedLeft(e);
diff --git a/src/macosx/classes/com/apple/eawt/event/PressureEvent.java b/src/macosx/classes/com/apple/eawt/event/PressureEvent.java
new file mode 100644
index 0000000..f3140cc
--- /dev/null
+++ b/src/macosx/classes/com/apple/eawt/event/PressureEvent.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2011, 2012, 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.
+ */
+
+package com.apple.eawt.event;
+
+/**
+ * Event indicating a swipe was performed by the user.
+ *
+ * @see PressureListener
+ *
+ * @since Java for Mac OS X 10.10 Update 3, JDK 8
+ */
+public class PressureEvent extends GestureEvent {
+
+    public double getPressure() {
+        return pressure;
+    }
+
+    public double getStage() {
+        return stage;
+    }
+
+    private double pressure;
+    private double stage;
+
+    PressureEvent(double pressure, double stage) {
+        this.pressure = pressure;
+        this.stage = stage;
+    }
+}
diff --git a/src/macosx/classes/com/apple/eawt/event/PressureListener.java b/src/macosx/classes/com/apple/eawt/event/PressureListener.java
new file mode 100644
index 0000000..de6a646
--- /dev/null
+++ b/src/macosx/classes/com/apple/eawt/event/PressureListener.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2011, 2012, 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.
+ */
+
+package com.apple.eawt.event;
+
+/**
+ * Listener interface for receiving pressure events.
+ *
+ * @see PressureEvent
+ * @see GestureUtilities
+ *
+ * @since Java for Mac OS X 10.5 Update 7, Java for Mac OS X 10.6 Update 2
+ */
+public interface PressureListener extends GestureListener {
+    public void pressure(final PressureEvent e);
+}
diff --git a/src/macosx/classes/com/apple/laf/AquaImageFactory.java b/src/macosx/classes/com/apple/laf/AquaImageFactory.java
index 28977cb..be09c9b 100644
--- a/src/macosx/classes/com/apple/laf/AquaImageFactory.java
+++ b/src/macosx/classes/com/apple/laf/AquaImageFactory.java
@@ -46,7 +46,7 @@
 import com.apple.laf.AquaIcon.SystemIcon;
 import com.apple.laf.AquaUtils.RecyclableObject;
 import com.apple.laf.AquaUtils.RecyclableSingleton;
-import sun.awt.image.MultiResolutionImage;
+import java.awt.image.MultiResolutionImage;
 import sun.awt.image.MultiResolutionCachedImage;
 
 public class AquaImageFactory {
diff --git a/src/macosx/classes/com/apple/laf/AquaScrollPaneUI.java b/src/macosx/classes/com/apple/laf/AquaScrollPaneUI.java
index 0729321..3241ab1 100644
--- a/src/macosx/classes/com/apple/laf/AquaScrollPaneUI.java
+++ b/src/macosx/classes/com/apple/laf/AquaScrollPaneUI.java
@@ -29,7 +29,6 @@
 
 import javax.swing.*;
 import javax.swing.plaf.ComponentUI;
-import javax.swing.plaf.basic.BasicScrollPaneUI;
 
 public class AquaScrollPaneUI extends javax.swing.plaf.basic.BasicScrollPaneUI {
     public static ComponentUI createUI(final JComponent x) {
@@ -40,9 +39,28 @@
         return new XYMouseWheelHandler();
     }
 
-    protected class XYMouseWheelHandler extends BasicScrollPaneUI.MouseWheelHandler {
+    // This is a grody hack to trick BasicScrollPaneUI into scrolling horizontally
+    // when we notice that the shift key is down. This should be removed when AWT/Swing
+    // becomes aware of of multi-axis scroll wheels.
+    protected class XYMouseWheelHandler extends javax.swing.plaf.basic.BasicScrollPaneUI.MouseWheelHandler {
         public void mouseWheelMoved(final MouseWheelEvent e) {
+            JScrollBar vScrollBar = null;
+            boolean wasVisible = false;
+
+            if (e.isShiftDown()) {
+                vScrollBar = scrollpane.getVerticalScrollBar();
+                if (vScrollBar != null) {
+                    wasVisible = vScrollBar.isVisible();
+                    vScrollBar.setVisible(false);
+                }
+            }
+
             super.mouseWheelMoved(e);
+
+            if (wasVisible) {
+                vScrollBar.setVisible(true);
+            }
+
             // Consume the event even when the scrollBar is invisible
             // see #7124320
             e.consume();
diff --git a/src/macosx/classes/sun/awt/CGraphicsConfig.java b/src/macosx/classes/sun/awt/CGraphicsConfig.java
index bfc464c..2757c36 100644
--- a/src/macosx/classes/sun/awt/CGraphicsConfig.java
+++ b/src/macosx/classes/sun/awt/CGraphicsConfig.java
@@ -72,7 +72,8 @@
 
     @Override
     public AffineTransform getDefaultTransform() {
-        return new AffineTransform();
+        double scaleFactor = device.getScaleFactor();
+        return AffineTransform.getScaleInstance(scaleFactor, scaleFactor);
     }
 
     @Override
diff --git a/src/macosx/classes/sun/font/CCharToGlyphMapper.java b/src/macosx/classes/sun/font/CCharToGlyphMapper.java
index d2f9a54..5a2cf76 100644
--- a/src/macosx/classes/sun/font/CCharToGlyphMapper.java
+++ b/src/macosx/classes/sun/font/CCharToGlyphMapper.java
@@ -75,37 +75,9 @@
                 }
             }
 
-            if (code < 0x0590) {
+            if (code < FontUtilities.MIN_LAYOUT_CHARCODE) {
                 continue;
-            } else if (code <= 0x05ff) {
-                // Hebrew 0x0590->0x05ff
-                return true;
-            } else if (code >= 0x0600 && code <= 0x06ff) {
-                // Arabic
-                return true;
-            } else if (code >= 0x0900 && code <= 0x0d7f) {
-                // if Indic, assume shaping for conjuncts, reordering:
-                // 0900 - 097F Devanagari
-                // 0980 - 09FF Bengali
-                // 0A00 - 0A7F Gurmukhi
-                // 0A80 - 0AFF Gujarati
-                // 0B00 - 0B7F Oriya
-                // 0B80 - 0BFF Tamil
-                // 0C00 - 0C7F Telugu
-                // 0C80 - 0CFF Kannada
-                // 0D00 - 0D7F Malayalam
-                return true;
-            } else if (code >= 0x0e00 && code <= 0x0e7f) {
-                // if Thai, assume shaping for vowel, tone marks
-                return true;
-            } else if (code >= 0x200c && code <= 0x200d) {
-                // zwj or zwnj
-                return true;
-            } else if (code >= 0x202a && code <= 0x202e) {
-                // directional control
-                return true;
-            } else if (code >= 0x206a && code <= 0x206f) {
-                // directional control
+            } else if (FontUtilities.isComplexCharCode(code)) {
                 return true;
             } else if (code >= 0x10000) {
                 i += 1; // Empty glyph slot after surrogate
diff --git a/src/macosx/classes/sun/font/CCompositeFont.java b/src/macosx/classes/sun/font/CCompositeFont.java
new file mode 100644
index 0000000..846e1c7
--- /dev/null
+++ b/src/macosx/classes/sun/font/CCompositeFont.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2016 JetBrains s.r.o.
+ * 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.
+ *
+ * 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.
+ *
+ */
+package sun.font;
+
+import java.lang.ref.SoftReference;
+import java.util.ArrayList;
+import java.util.List;
+
+public final class CCompositeFont extends CompositeFont {
+    private final List<CFont> fallbackFonts = new ArrayList<>();
+
+    public CCompositeFont(CFont font) {
+        super(new PhysicalFont[]{font});
+        mapper = new CCompositeGlyphMapper(this);
+    }
+
+    @Override
+    public synchronized int getNumSlots() {
+        return super.getNumSlots();
+    }
+
+    @Override
+    public CFont getSlotFont(int slot) {
+        if (slot == 0) return (CFont) super.getSlotFont(0);
+        synchronized (this) {
+            return fallbackFonts.get(slot - 1);
+        }
+    }
+
+    @Override
+    synchronized FontStrike getStrike(FontStrikeDesc desc, boolean copy) {
+        return super.getStrike(desc, copy);
+    }
+
+    @Override
+    synchronized void removeFromCache(FontStrikeDesc desc) {
+        super.removeFromCache(desc);
+    }
+
+    @Override
+    protected synchronized int getValidatedGlyphCode(int glyphCode) {
+        return super.getValidatedGlyphCode(glyphCode);
+    }
+
+    @Override
+    public boolean hasSupplementaryChars() {
+        return false;
+    }
+
+    @Override
+    public boolean useAAForPtSize(int ptsize) {
+        return true;
+    }
+
+    public synchronized int findSlot(String fontName) {
+        for (int slot = 0; slot < numSlots; slot++) {
+            CFont slotFont = getSlotFont(slot);
+            if (fontName.equals(slotFont.getNativeFontName())) {
+                return slot;
+            }
+        }
+        return -1;
+    }
+
+    public synchronized int addSlot(CFont font) {
+        int slot = findSlot(font.getNativeFontName());
+        if (slot >= 0) return slot;
+        fallbackFonts.add(font);
+        lastFontStrike = new SoftReference<>(null);
+        strikeCache.clear();
+        return numSlots++;
+    }
+}
diff --git a/src/macosx/classes/sun/font/CCompositeGlyphMapper.java b/src/macosx/classes/sun/font/CCompositeGlyphMapper.java
new file mode 100644
index 0000000..11ee071
--- /dev/null
+++ b/src/macosx/classes/sun/font/CCompositeGlyphMapper.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+package sun.font;
+
+import java.awt.*;
+
+public final class CCompositeGlyphMapper extends CompositeGlyphMapper {
+    public CCompositeGlyphMapper(CCompositeFont compFont) {
+        super(compFont);
+    }
+
+    @Override
+    protected int convertToGlyph(int unicode) {
+        CCompositeFont compositeFont = (CCompositeFont) font;
+        CFont mainFont = (CFont) font.getSlotFont(0);
+        String[] fallbackFontInfo = new String[2];
+        int glyphCode = nativeCodePointToGlyph(mainFont.getNativeFontPtr(), unicode, fallbackFontInfo);
+        if (glyphCode == missingGlyph) {
+            return missingGlyph;
+        }
+        String fallbackFontName = fallbackFontInfo[0];
+        String fallbackFontFamilyName = fallbackFontInfo[1];
+        if (fallbackFontName == null || fallbackFontFamilyName == null) {
+            return missingGlyph;
+        }
+
+        int slot = compositeFont.findSlot(fallbackFontName);
+
+        if (slot < 0) {
+            Font2D fallbackFont = FontManagerFactory.getInstance().findFont2D(fallbackFontName,
+                    Font.PLAIN, FontManager.NO_FALLBACK);
+            if (!(fallbackFont instanceof CFont) ||
+                    !fallbackFontName.equals(((CFont) fallbackFont).getNativeFontName())) {
+                // Native font fallback mechanism can return "hidden" fonts - their names start with dot,
+                // and they are not returned in a list of fonts available in system, but they can still be used
+                // if requested explicitly.
+                fallbackFont = new CFont(fallbackFontName, fallbackFontFamilyName);
+            }
+
+            if (mainFont.isFakeItalic()) fallbackFont = ((CFont)fallbackFont).createItalicVariant(false);
+
+            slot = compositeFont.addSlot((CFont) fallbackFont);
+        }
+
+        return compositeGlyphCode(slot, glyphCode);
+    }
+
+    // This invokes native font fallback mechanism, returning information about font (its Postscript and family names)
+    // able to display a given character, and corresponding glyph code
+    private static native int nativeCodePointToGlyph(long nativeFontPtr, int codePoint, String[] result);
+}
\ No newline at end of file
diff --git a/src/macosx/classes/sun/font/CFont.java b/src/macosx/classes/sun/font/CFont.java
index c88e53c..5d169eb 100644
--- a/src/macosx/classes/sun/font/CFont.java
+++ b/src/macosx/classes/sun/font/CFont.java
@@ -25,18 +25,26 @@
 
 package sun.font;
 
-import java.awt.Font;
+import java.awt.*;
 import java.awt.font.FontRenderContext;
 import java.awt.geom.AffineTransform;
-import java.awt.geom.GeneralPath;;
+import java.awt.geom.GeneralPath;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 
 // Right now this class is final to avoid a problem with native code.
 // For some reason the JNI IsInstanceOf was not working correctly
 // so we are checking the class specifically. If we subclass this
 // we need to modify the native code in CFontWrapper.m
-public final class CFont extends PhysicalFont {
+public final class CFont extends PhysicalFont implements FontSubstitution {
+    private static final boolean useCoreTextLayout;
+
+    static {
+        useCoreTextLayout = AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
+                Boolean.getBoolean("sun.font.use.coretext.layout"));
+    }
 
     /* CFontStrike doesn't call these methods so they are unimplemented.
      * They are here to meet the requirements of PhysicalFont, needed
@@ -76,6 +84,20 @@
        throw new InternalError("Not implemented");
     }
 
+    @Override
+    protected long getLayoutTableCache() {
+        return getLayoutTableCacheNative(getNativeFontPtr());
+    }
+
+    @Override
+    protected byte[] getTableBytes(int tag) {
+        return getTableBytesNative(getNativeFontPtr(), tag);
+    }
+
+    private native synchronized long getLayoutTableCacheNative(long nativeFontPtr);
+
+    private native byte[] getTableBytesNative(long nativeFontPtr, int tag);
+
     private static native long createNativeFont(final String nativeFontName,
                                                 final int style);
     private static native void disposeNativeFont(final long nativeFontPtr);
@@ -166,12 +188,14 @@
         isFakeItalic = other.isFakeItalic;
     }
 
-    public CFont createItalicVariant() {
+    public CFont createItalicVariant(boolean updateStyle) {
         CFont font = new CFont(this, familyName);
         font.nativeFontName = fullName;
         font.fullName =
             fullName + (style == Font.BOLD ? "" : "-") + "Italic-Derived";
-        font.style |= Font.ITALIC;
+        if (updateStyle) {
+            font.style |= Font.ITALIC;
+        }
         font.isFakeItalic = true;
         return font;
     }
@@ -179,10 +203,26 @@
     protected synchronized long getNativeFontPtr() {
         if (nativeFontPtr == 0L) {
             nativeFontPtr = createNativeFont(nativeFontName, style);
-}
+        }
         return nativeFontPtr;
     }
 
+    private native long getCGFontPtrNative(long ptr);
+
+    // This digs the CGFont out of the AWTFont.
+    protected synchronized long getPlatformNativeFontPtr() {
+        return getCGFontPtrNative(getNativeFontPtr());
+    }
+
+    private CompositeFont compFont;
+
+    public CompositeFont getCompositeFont2D() {
+        if (compFont == null) {
+           compFont = new CCompositeFont(this);
+        }
+        return compFont;
+    }
+
     protected synchronized void finalize() {
         if (nativeFontPtr != 0) {
             disposeNativeFont(nativeFontPtr);
@@ -205,6 +245,21 @@
         return new CStrike(this, desc);
     }
 
+    boolean isFakeItalic() {
+        return isFakeItalic;
+    }
+
+    String getNativeFontName() {
+        return nativeFontName;
+    }
+
+    @Override
+    protected boolean isAAT() {
+        // CoreText layout code ignores fractional metrics font attribute
+        // also, using CoreText layout in Harfbuzz code leads to wrong advances for emoji glyphs
+        return useCoreTextLayout && !"AppleColorEmoji".equals(nativeFontName) && super.isAAT();
+    }
+
     // <rdar://problem/5321707> sun.font.Font2D caches the last used strike,
     // but does not check if the properties of the strike match the properties
     // of the incoming java.awt.Font object (size, style, etc).
@@ -215,6 +270,18 @@
         return getStrike(font, DEFAULT_FRC);
     }
 
+    public boolean equals(Object o) {
+        if (!super.equals(o)) {
+            return false;
+        }
+
+        return ((Font2D)o).getStyle() == this.getStyle();
+    }
+
+    public int hashCode() {
+        return super.hashCode() ^ this.getStyle();
+    }
+
     public String toString() {
         return "CFont { fullName: " + fullName +
             ",  familyName: " + familyName + ", style: " + style +
diff --git a/src/macosx/classes/sun/font/CFontManager.java b/src/macosx/classes/sun/font/CFontManager.java
index d05f549..6280b65 100644
--- a/src/macosx/classes/sun/font/CFontManager.java
+++ b/src/macosx/classes/sun/font/CFontManager.java
@@ -25,23 +25,17 @@
 
 package sun.font;
 
+import sun.awt.FontConfiguration;
+import sun.awt.HeadlessToolkit;
+import sun.lwawt.macosx.LWCToolkit;
+import sun.misc.ThreadGroupUtils;
+
+import javax.swing.plaf.FontUIResource;
 import java.awt.*;
 import java.io.File;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Locale;
-import java.util.TreeMap;
-import java.util.Vector;
-
-import javax.swing.plaf.FontUIResource;
-
-import sun.awt.FontConfiguration;
-import sun.awt.HeadlessToolkit;
-import sun.misc.ThreadGroupUtils;
-import sun.lwawt.macosx.*;
+import java.util.*;
 
 public final class CFontManager extends SunFontManager {
     private FontConfigManager fcManager = null;
@@ -277,10 +271,10 @@
             if (plain == null && bold == null) continue;
             if (italic != null && boldItalic != null) continue;
             if (plain != null && italic == null) {
-               registerGenericFont(plain.createItalicVariant(), true);
+               registerGenericFont(plain.createItalicVariant(true), true);
             }
             if (bold != null && boldItalic == null) {
-               registerGenericFont(bold.createItalicVariant(), true);
+               registerGenericFont(bold.createItalicVariant(true), true);
             }
         }
     }
@@ -395,4 +389,9 @@
     @Override
     protected void populateFontFileNameMap(HashMap<String, String> fontToFileMap, HashMap<String, String> fontToFamilyNameMap,
             HashMap<String, ArrayList<String>> familyToFontListMap, Locale locale) {}
+
+    @Override
+    public boolean areColorGlyphsSupported() {
+        return true;
+    }
 }
diff --git a/src/macosx/classes/sun/font/CStrike.java b/src/macosx/classes/sun/font/CStrike.java
index af4f875..5af84a8 100644
--- a/src/macosx/classes/sun/font/CStrike.java
+++ b/src/macosx/classes/sun/font/CStrike.java
@@ -25,13 +25,14 @@
 
 package sun.font;
 
+import com.apple.concurrent.Dispatch;
+
 import java.awt.Rectangle;
 import java.awt.geom.*;
-import java.util.*;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
 
-import sun.awt.SunHints;
-
-public final class CStrike extends FontStrike {
+public final class CStrike extends PhysicalStrike {
 
     // Creates the native strike
     private static native long createNativeStrikePtr(long nativeFontPtr,
@@ -356,7 +357,7 @@
         private static final int SECOND_LAYER_SIZE = 16384; // 16384 = 128x128
 
         // rdar://problem/5204197
-        private boolean disposed = false;
+        private final AtomicBoolean disposed = new AtomicBoolean(false);
 
         private final long[] firstLayerCache;
         private SparseBitShiftingTwoLayerArray secondLayerCache;
@@ -419,43 +420,56 @@
         }
 
         public synchronized void dispose() {
-            // rdar://problem/5204197
-            // Note that sun.font.Font2D.getStrike() actively disposes
-            // cleared strikeRef.  We need to check the disposed flag to
-            // prevent double frees of native resources.
-            if (disposed) {
-                return;
-            }
+            final Runnable command = () -> {
+                // rdar://problem/5204197
+                // Note that sun.font.Font2D.getStrike() actively disposes
+                // cleared strikeRef.  We need to check the disposed flag to
+                // prevent double frees of native resources.
+                if (disposed.compareAndSet(false, true)) {
 
-            super.dispose();
+                    super.dispose();
 
-            // clean out the first array
-            disposeLongArray(firstLayerCache);
+                    // clean out the first array
+                    disposeLongArray(firstLayerCache);
 
-            // clean out the two layer arrays
-            if (secondLayerCache != null) {
-                final long[][] secondLayerLongArrayArray = secondLayerCache.cache;
-                for (int i = 0; i < secondLayerLongArrayArray.length; i++) {
-                    final long[] longArray = secondLayerLongArrayArray[i];
-                    if (longArray != null) disposeLongArray(longArray);
-                }
-            }
+                    // clean out the two layer arrays
+                    if (secondLayerCache != null) {
+                        final long[][] secondLayerLongArrayArray = secondLayerCache.cache;
+                        for (final long[] longArray : secondLayerLongArrayArray) {
+                            if (longArray != null) disposeLongArray(longArray);
+                        }
+                    }
 
-            // clean up everyone else
-            if (generalCache != null) {
-                final Iterator<Long> i = generalCache.values().iterator();
-                while (i.hasNext()) {
-                    final long longValue = i.next().longValue();
-                    if (longValue != -1 && longValue != 0) {
-                        removeGlyphInfoFromCache(longValue);
-                        StrikeCache.freeLongPointer(longValue);
+                    // clean up everyone else
+                    if (generalCache != null) {
+                        for (Long aLong : generalCache.values()) {
+                            final long longValue = aLong;
+                            if (longValue != -1 && longValue != 0) {
+                                removeGlyphInfoFromCache(longValue);
+                                StrikeCache.freeLongPointer(longValue);
+                            }
+                        }
                     }
                 }
-            }
+            };
 
-            // rdar://problem/5204197
-            // Finally, set the flag.
-            disposed = true;
+            // Move disposal code to AppKit thread in order to avoid the
+            // following deadlock:
+            // 1) CGLGraphicsConfig.getCGLConfigInfo (called from Java2D
+            //    disposal thread) takes RenderQueue.lock
+            // 2) CGLLayer.drawInCGLContext is invoked on AppKit thread and
+            //    blocked on RenderQueue.lock
+            // 1) invokes native block on AppKit and wait
+            //
+            // If dispatch instance is not available, run the code on
+            // disposal thread as before
+
+            final Dispatch dispatch = Dispatch.getInstance();
+
+            if (dispatch != null)
+                dispatch.getNonBlockingMainQueueExecutor().execute(command);
+            else
+                command.run();
         }
 
         private static void disposeLongArray(final long[] longArray) {
diff --git a/src/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java b/src/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java
index b5ae3b8..e98b4da 100644
--- a/src/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java
+++ b/src/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java
@@ -41,6 +41,7 @@
 import java.awt.image.DirectColorModel;
 import java.awt.image.VolatileImage;
 import java.awt.image.WritableRaster;
+import java.util.HashMap;
 
 import sun.awt.CGraphicsConfig;
 import sun.awt.CGraphicsDevice;
@@ -84,6 +85,8 @@
                                                 int swapInterval);
     private static native int getOGLCapabilities(long configInfo);
 
+    private static final HashMap<Long, Integer> pGCRefCounts = new HashMap<>();
+
     /**
      * Returns GL_MAX_TEXTURE_SIZE from the shared opengl context. Must be
      * called under OGLRQ lock, because this method change current context.
@@ -106,7 +109,7 @@
         this.oglCaps = oglCaps;
         this.maxTextureSize = maxTextureSize;
         context = new OGLContext(OGLRenderQueue.getInstance(), this);
-
+        refPConfigInfo(pConfigInfo);
         // add a record to the Disposer so that we destroy the native
         // CGLGraphicsConfigInfo data when this object goes away
         Disposer.addRecord(disposerReferent,
@@ -169,6 +172,33 @@
         return new CGLGraphicsConfig(device, pixfmt, cfginfo, textureSize, caps);
     }
 
+    static void refPConfigInfo(long pConfigInfo) {
+        synchronized (pGCRefCounts) {
+            Integer count = pGCRefCounts.get(pConfigInfo);
+            if (count == null) {
+                count = 1;
+            }
+            else {
+                count++;
+            }
+            pGCRefCounts.put(pConfigInfo, count);
+        }
+    }
+
+    static void deRefPConfigInfo(long pConfigInfo) {
+        synchronized (pGCRefCounts) {
+            Integer count = pGCRefCounts.get(pConfigInfo);
+            if (count != null) {
+                count--;
+                pGCRefCounts.put(pConfigInfo, count);
+                if (count == 0) {
+                    OGLRenderQueue.disposeGraphicsConfig(pConfigInfo);
+                    pGCRefCounts.remove(pConfigInfo);
+                }
+            }
+        }
+    }
+
     public static boolean isCGLAvailable() {
         return cglAvailable;
     }
@@ -236,7 +266,7 @@
         }
         public void dispose() {
             if (pCfgInfo != 0) {
-                OGLRenderQueue.disposeGraphicsConfig(pCfgInfo);
+                deRefPConfigInfo(pCfgInfo);
                 pCfgInfo = 0;
             }
         }
diff --git a/src/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java b/src/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java
index 754e8f2..81e322c 100644
--- a/src/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java
+++ b/src/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java
@@ -77,6 +77,7 @@
             pPeerData = pView.getAWTView();
             isOpaque = pView.isOpaque();
         }
+        CGLGraphicsConfig.refPConfigInfo(pConfigInfo);
         initOps(pConfigInfo, pPeerData, 0, 0, 0, isOpaque);
     }
 
@@ -93,6 +94,7 @@
             layerPtr = layer.getPointer();
             isOpaque = layer.isOpaque();
         }
+        CGLGraphicsConfig.refPConfigInfo(pConfigInfo);
         initOps(pConfigInfo, 0, layerPtr, 0, 0, isOpaque);
     }
 
@@ -169,7 +171,12 @@
     }
 
     @Override
-    public int getDefaultScale() {
+    public double getDefaultScaleX() {
+        return scale;
+    }
+
+    @Override
+    public double getDefaultScaleY() {
         return scale;
     }
 
@@ -403,4 +410,9 @@
             destroyCGLContext(ctx);
         }
     }
+
+    static void dispose(long pData, long pConfigInfo) {
+        OGLSurfaceData.dispose(pData, pConfigInfo);
+        CGLGraphicsConfig.deRefPConfigInfo(pConfigInfo);
+    }
 }
diff --git a/src/macosx/classes/sun/lwawt/LWLightweightFramePeer.java b/src/macosx/classes/sun/lwawt/LWLightweightFramePeer.java
index 4491b7c..f17f209 100644
--- a/src/macosx/classes/sun/lwawt/LWLightweightFramePeer.java
+++ b/src/macosx/classes/sun/lwawt/LWLightweightFramePeer.java
@@ -64,9 +64,9 @@
         if (!focusAllowedFor()) {
             return false;
         }
-        if (getPlatformWindow().rejectFocusRequest(cause)) {
+        /*if (getPlatformWindow().rejectFocusRequest(cause)) {
             return false;
-        }
+        }*/
 
         Window opposite = LWKeyboardFocusManagerPeer.getInstance().
             getCurrentFocusedWindow();
diff --git a/src/macosx/classes/sun/lwawt/LWWindowPeer.java b/src/macosx/classes/sun/lwawt/LWWindowPeer.java
index db5a4f5..e89a5d3 100644
--- a/src/macosx/classes/sun/lwawt/LWWindowPeer.java
+++ b/src/macosx/classes/sun/lwawt/LWWindowPeer.java
@@ -708,7 +708,7 @@
      * point of the client area is (insets.top, insets.left).
      */
     @Override
-    public void notifyMouseEvent(int id, long when, int button,
+    public void notifyMouseEvent(PlatformWindow eventPlatformWindow, int id, long when, int button,
                                  int x, int y, int screenX, int screenY,
                                  int modifiers, int clickCount, boolean popupTrigger,
                                  byte[] bdata)
@@ -750,10 +750,9 @@
                 lastMouseEventPeer = targetPeer;
             }
         } else {
-            PlatformWindow topmostPlatformWindow = LWToolkit.getLWToolkit().getPlatformWindowUnderMouse();
 
             LWWindowPeer topmostWindowPeer =
-                    topmostPlatformWindow != null ? topmostPlatformWindow.getPeer() : null;
+                    eventPlatformWindow != null ? eventPlatformWindow.getPeer() : null;
 
             // topmostWindowPeer == null condition is added for the backward
             // compatibility with applets. It can be removed when the
@@ -1109,7 +1108,9 @@
             && !(dst instanceof NullSurfaceData)
             && !(src instanceof NullSurfaceData)
             && src.getSurfaceType().equals(dst.getSurfaceType())
-            && src.getDefaultScale() == dst.getDefaultScale()) {
+            && src.getDefaultScaleX() == dst.getDefaultScaleX()
+            && src.getDefaultScaleY() == dst.getDefaultScaleY())
+        {
             final Rectangle size = src.getBounds();
             final Blit blit = Blit.locate(src.getSurfaceType(),
                                           CompositeType.Src,
@@ -1160,9 +1161,9 @@
             return false;
         }
 
-        if (platformWindow.rejectFocusRequest(cause)) {
-            return false;
-        }
+        //if (platformWindow.rejectFocusRequest(cause)) {
+        //    return false;
+        //}
 
         AppContext targetAppContext = AWTAccessor.getComponentAccessor().getAppContext(getTarget());
         KeyboardFocusManager kfm = AWTAccessor.getKeyboardFocusManagerAccessor()
@@ -1175,6 +1176,7 @@
 
         // Make the owner active window.
         if (isSimpleWindow()) {
+	    focusLog.fine("This is a Simple Window.");
             LWWindowPeer owner = getOwnerFrameDialog(this);
 
             // If owner is not natively active, request native
@@ -1201,6 +1203,7 @@
 
             // DKFM will synthesize all the focus/activation events correctly.
             changeFocusedWindow(true, opposite);
+	    focusLog.fine("DKFM will synthesize all the focus/activation events correctly");
             return true;
 
         // In case the toplevel is active but not focused, change focus directly,
@@ -1208,16 +1211,26 @@
         } else if (getTarget() == currentActive && !getTarget().hasFocus()) {
 
             changeFocusedWindow(true, opposite);
+	    focusLog.fine("toplevel is active but not focused, change focus directly");
             return true;
         }
 
+       focusLog.fine("platformWindow.requestWindowFocus()");
         return platformWindow.requestWindowFocus();
     }
 
     protected boolean focusAllowedFor() {
         Window window = getTarget();
         // TODO: check if modal blocked
-        return window.isVisible() && window.isEnabled() && isFocusableWindow();
+
+        boolean allowed = (getBlocker() == null) && window.isVisible() && window.isEnabled() && isFocusableWindow() ;
+
+        focusLog.fine("Checking whether the focus is allowed [" + allowed + "] for " + window.getName() + "; blocker: "
+                + ((getBlocker() == null) ? "null" : getBlocker().getClass().getName()) + "; window.isVisible: " + window.isVisible() +
+                "; window.isEnabled: " + window.isEnabled() + "; isFocusableWindow: " + isFocusableWindow());
+
+
+        return allowed;
     }
 
     private boolean isFocusableWindow() {
@@ -1294,12 +1307,6 @@
         }
 
         KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();
-
-        if (!becomesFocused && kfmPeer.getCurrentFocusedWindow() != getTarget()) {
-            // late window focus lost event - ingoring
-            return;
-        }
-
         kfmPeer.setCurrentFocusedWindow(becomesFocused ? getTarget() : null);
 
         int eventID = becomesFocused ? WindowEvent.WINDOW_GAINED_FOCUS : WindowEvent.WINDOW_LOST_FOCUS;
diff --git a/src/macosx/classes/sun/lwawt/PlatformEventNotifier.java b/src/macosx/classes/sun/lwawt/PlatformEventNotifier.java
index 5bb3368..25df2fa 100644
--- a/src/macosx/classes/sun/lwawt/PlatformEventNotifier.java
+++ b/src/macosx/classes/sun/lwawt/PlatformEventNotifier.java
@@ -48,7 +48,8 @@
      * coordinates are relative to non-client window are, i.e. the top-left
      * point of the client area is (insets.top, insets.left).
      */
-    void notifyMouseEvent(int id, long when, int button,
+    void notifyMouseEvent(PlatformWindow eventPlatformWindow,
+                          int id, long when, int button,
                           int x, int y, int screenX, int screenY,
                           int modifiers, int clickCount, boolean popupTrigger,
                           byte[] bdata);
diff --git a/src/macosx/classes/sun/lwawt/macosx/CAccessible.java b/src/macosx/classes/sun/lwawt/macosx/CAccessible.java
index 6ac0a07..ed3db1a 100644
--- a/src/macosx/classes/sun/lwawt/macosx/CAccessible.java
+++ b/src/macosx/classes/sun/lwawt/macosx/CAccessible.java
@@ -101,7 +101,7 @@
 
     @Override
     public AccessibleContext getAccessibleContext() {
-        return accessible.getAccessibleContext();
+        return accessible != null ? accessible.getAccessibleContext() : null;
     }
 
     public void addNotificationListeners(Component c) {
diff --git a/src/macosx/classes/sun/lwawt/macosx/CCursorManager.java b/src/macosx/classes/sun/lwawt/macosx/CCursorManager.java
index e4abc5f..b22bf77 100644
--- a/src/macosx/classes/sun/lwawt/macosx/CCursorManager.java
+++ b/src/macosx/classes/sun/lwawt/macosx/CCursorManager.java
@@ -45,7 +45,7 @@
         return theInstance;
     }
 
-    private volatile Cursor currentCursor;
+    //private volatile Cursor currentCursor;
 
     private CCursorManager() { }
 
@@ -57,10 +57,10 @@
 
     @Override
     protected void setCursor(final Cursor cursor) {
-        if (cursor == currentCursor) {
-            return;
-        }
-        currentCursor = cursor;
+        //if (cursor == currentCursor) {
+        //    return;
+        //}
+        //currentCursor = cursor;
 
         if (cursor == null) {
             nativeSetBuiltInCursor(Cursor.DEFAULT_CURSOR, null);
diff --git a/src/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java b/src/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java
index 11f05b5..4fcac1b 100644
--- a/src/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java
+++ b/src/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java
@@ -32,6 +32,7 @@
 
 import sun.awt.EmbeddedFrame;
 import sun.lwawt.LWWindowPeer;
+import sun.lwawt.PlatformWindow;
 
 public class CEmbeddedFrame extends EmbeddedFrame {
 
@@ -68,7 +69,7 @@
     //                          SYNTHETIC EVENT DELIVERY
     // -----------------------------------------------------------------------
 
-    public void handleMouseEvent(int eventType, int modifierFlags, double pluginX,
+    public void handleMouseEvent(PlatformWindow platformWindow, int eventType, int modifierFlags, double pluginX,
                                  double pluginY, int buttonNumber, int clickCount) {
         int x = (int)pluginX;
         int y = (int)pluginY;
@@ -82,7 +83,7 @@
             CCursorManager.nativeSetAllowsCursorSetInBackground(false);
         }
 
-        responder.handleMouseEvent(eventType, modifierFlags, buttonNumber,
+        responder.handleMouseEvent(platformWindow, eventType, modifierFlags, buttonNumber,
                                    clickCount, x, y, screenX, screenY);
     }
 
@@ -94,11 +95,8 @@
         responder.handleScrollEvent(x, y, modifierFlags, deltaX, deltaY, NSEvent.SCROLL_PHASE_UNSUPPORTED);
     }
 
-    public void handleKeyEvent(int eventType, int modifierFlags, String characters,
-                               String charsIgnoringMods, boolean isRepeat, short keyCode,
-                               boolean needsKeyTyped) {
-        responder.handleKeyEvent(eventType, modifierFlags, characters, charsIgnoringMods,
-                keyCode, needsKeyTyped, isRepeat);
+    public void handleKeyEvent(NSEvent nsEvent) {
+        responder.handleKeyEvent(nsEvent);
     }
 
     public void handleInputEvent(String text) {
@@ -161,7 +159,7 @@
         }
         // ignore focus "lost" native request as it may mistakenly
         // deactivate active window (see 8001161)
-        if (globalFocusedWindow == this) {
+        if (globalFocusedWindow == this && parentWindowActive) {
             responder.handleWindowFocusEvent(parentWindowActive, null);
         }
     }
diff --git a/src/macosx/classes/sun/lwawt/macosx/CFileDialog.java b/src/macosx/classes/sun/lwawt/macosx/CFileDialog.java
index cc31b53..40dae8a 100644
--- a/src/macosx/classes/sun/lwawt/macosx/CFileDialog.java
+++ b/src/macosx/classes/sun/lwawt/macosx/CFileDialog.java
@@ -33,14 +33,20 @@
 import java.security.AccessController;
 import java.util.List;
 import java.io.*;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import sun.awt.CausedFocusEvent.Cause;
 import sun.awt.AWTAccessor;
 import sun.java2d.pipe.Region;
+import sun.lwawt.LWWindowPeer;
 import sun.security.action.GetBooleanAction;
+import sun.util.logging.PlatformLogger;
 
 class CFileDialog implements FileDialogPeer {
 
+    private static final PlatformLogger log = PlatformLogger.getLogger("sun.lwawt.macosx.CFileDialog");
+
     private class Task implements Runnable {
 
         @Override
@@ -57,7 +63,13 @@
                     title = " ";
                 }
 
-                String[] userFileNames = nativeRunFileDialog(title,
+                Window owner = target.getOwner();
+
+                long ownerPtr = owner == null ? 0L :((CPlatformWindow) (((LWWindowPeer)owner.getPeer())).getPlatformWindow()).getNSWindowPtr();
+
+                String[] userFileNames = nativeRunFileDialog(
+                        ownerPtr,
+                        title,
                         dialogMode,
                         target.isMultipleMode(),
                         navigateApps,
@@ -70,7 +82,7 @@
                 String file = null;
                 File[] files = null;
 
-                if (userFileNames != null) {
+                if (userFileNames != null && userFileNames.length > 0) {
                     // the dialog wasn't cancelled
                     int filesNumber = userFileNames.length;
                     files = new File[filesNumber];
@@ -131,7 +143,7 @@
      * If the dialog doesn't have a file filter return true.
      */
     private boolean queryFilenameFilter(final String inFilename) {
-        boolean ret = false;
+        AtomicBoolean ret = new AtomicBoolean(false);
 
         final FilenameFilter ff = target.getFilenameFilter();
         File fileObj = new File(inFilename);
@@ -140,12 +152,29 @@
         if (!fileObj.isDirectory()) {
             File directoryObj = new File(fileObj.getParent());
             String nameOnly = fileObj.getName();
-            ret = ff.accept(directoryObj, nameOnly);
+            final Semaphore filesFilterSemaphore = new Semaphore(0);
+
+            new Thread("File filtering thread") {
+                @Override
+                public void run() {
+                    ret.set(ff.accept(directoryObj, nameOnly));
+                    filesFilterSemaphore.release();
+                }
+            }.start();
+
+            try {
+                filesFilterSemaphore.acquire();
+            } catch (InterruptedException e) {
+                if (log.isLoggable(PlatformLogger.Level.FINE)) {
+                    log.fine("Concurrency issues during files filtering: ", e);
+                }
+            }
+
         }
-        return ret;
+        return ret.get();
     }
 
-    private native String[] nativeRunFileDialog(String title, int mode,
+    private native String[] nativeRunFileDialog(long ownerPtr, String title, int mode,
             boolean multipleMode, boolean shouldNavigateApps,
             boolean canChooseDirectories, boolean hasFilenameFilter,
             String directory, String file);
@@ -164,6 +193,13 @@
 
     @Override
     public void blockWindows(List<Window> windows) {
+        for (Window w : windows) {
+            WindowPeer wp =
+                    (WindowPeer) AWTAccessor.getComponentAccessor().getPeer(w);
+            if (wp != null) {
+                wp.setModalBlocked(target, true);
+            }
+        }
     }
 
     @Override
@@ -336,7 +372,7 @@
 
     @Override
     public boolean isFocusable() {
-        return false;
+        return true;
     }
 
     @Override
diff --git a/src/macosx/classes/sun/lwawt/macosx/CImage.java b/src/macosx/classes/sun/lwawt/macosx/CImage.java
index 5f468df..29dcaf9 100644
--- a/src/macosx/classes/sun/lwawt/macosx/CImage.java
+++ b/src/macosx/classes/sun/lwawt/macosx/CImage.java
@@ -31,7 +31,7 @@
 
 import java.util.Arrays;
 import java.util.List;
-import sun.awt.image.MultiResolutionImage;
+import java.awt.image.MultiResolutionImage;
 import sun.awt.image.MultiResolutionCachedImage;
 
 import sun.awt.image.SunWritableRaster;
@@ -238,18 +238,32 @@
         if (ptr == 0) return null;
 
         final Dimension2D size = nativeGetNSImageSize(ptr);
-        final int w = (int)size.getWidth();
-        final int h = (int)size.getHeight();
+        final int baseWidth = (int)size.getWidth();
+        final int baseHeight = (int)size.getHeight();
 
-        Dimension2D[] sizes
-                = nativeGetNSImageRepresentationSizes(ptr,
-                        size.getWidth(), size.getHeight());
+        Dimension2D[] sizes = nativeGetNSImageRepresentationSizes(ptr, size.getWidth(), size.getHeight());
+
+        int dstW = baseWidth;
+        int dstH = baseHeight;
+
+        // The image may be represented in the only size which differs from the base one.
+        // For instance, the app's dock icon is represented in a Retina-scaled size on Retina.
+        // Check if a single represenation has a bigger size and in that case use it as the dest size.
+        if (sizes != null && sizes.length == 1 &&
+            (sizes[0].getWidth() > baseWidth && sizes[0].getHeight() > baseHeight))
+        {
+            dstW = (int)sizes[0].getWidth();
+            dstH = (int)sizes[0].getHeight();
+        }
+        final int dstWidth  = dstW;
+        final int dstHeight = dstH;
+
 
         return sizes == null || sizes.length < 2 ?
-                new MultiResolutionCachedImage(w, h, (width, height)
-                        -> toImage(w, h, width, height))
-                : new MultiResolutionCachedImage(w, h, sizes, (width, height)
-                        -> toImage(w, h, width, height));
+                new MultiResolutionCachedImage(baseWidth, baseHeight, (width, height)
+                        -> toImage(baseWidth, baseHeight, dstWidth, dstHeight))
+                : new MultiResolutionCachedImage(baseWidth, baseHeight, sizes, (width, height)
+                        -> toImage(baseWidth, baseHeight, width, height));
     }
 
     private BufferedImage toImage(int srcWidth, int srcHeight, int dstWidth, int dstHeight) {
diff --git a/src/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java b/src/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java
index 15c377f..bcf9307 100644
--- a/src/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java
+++ b/src/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java
@@ -28,6 +28,8 @@
 import sun.awt.SunToolkit;
 import sun.lwawt.LWWindowPeer;
 import sun.lwawt.PlatformEventNotifier;
+import sun.lwawt.PlatformWindow;
+import sun.util.logging.PlatformLogger;
 
 import java.awt.Toolkit;
 import java.awt.event.MouseEvent;
@@ -41,11 +43,21 @@
  */
 final class CPlatformResponder {
 
+    private static final PlatformLogger keyboardLog = PlatformLogger.getLogger("sun.lwawt.macosx.CPlatformResponder");
+
     private final PlatformEventNotifier eventNotifier;
     private final boolean isNpapiCallback;
     private int lastKeyPressCode = KeyEvent.VK_UNDEFINED;
     private final DeltaAccumulator deltaAccumulatorX = new DeltaAccumulator();
     private final DeltaAccumulator deltaAccumulatorY = new DeltaAccumulator();
+    private boolean momentumStarted;
+    private int momentumX;
+    private int momentumY;
+    private int momentumModifiers;
+    private int lastDraggedAbsoluteX;
+    private int lastDraggedAbsoluteY;
+    private int lastDraggedRelativeX;
+    private int lastDraggedRelativeY;
 
     CPlatformResponder(final PlatformEventNotifier eventNotifier,
                        final boolean isNpapiCallback) {
@@ -56,7 +68,7 @@
     /**
      * Handles mouse events.
      */
-    void handleMouseEvent(int eventType, int modifierFlags, int buttonNumber,
+    void handleMouseEvent(PlatformWindow platformWindow, int eventType, int modifierFlags, int buttonNumber,
                           int clickCount, int x, int y, int absoluteX,
                           int absoluteY) {
         final SunToolkit tk = (SunToolkit)Toolkit.getDefaultToolkit();
@@ -68,6 +80,18 @@
         int jeventType = isNpapiCallback ? NSEvent.npToJavaEventType(eventType) :
                                            NSEvent.nsToJavaEventType(eventType);
 
+        boolean dragged = jeventType == MouseEvent.MOUSE_DRAGGED;
+        if (dragged  // ignore dragged event that does not change any location
+                && lastDraggedAbsoluteX == absoluteX && lastDraggedRelativeX == x
+                && lastDraggedAbsoluteY == absoluteY && lastDraggedRelativeY == y) return;
+
+        if (dragged || jeventType == MouseEvent.MOUSE_PRESSED) {
+            lastDraggedAbsoluteX = absoluteX;
+            lastDraggedAbsoluteY = absoluteY;
+            lastDraggedRelativeX = x;
+            lastDraggedRelativeY = y;
+        }
+
         int jbuttonNumber = MouseEvent.NOBUTTON;
         int jclickCount = 0;
 
@@ -83,7 +107,7 @@
                                                         modifierFlags);
         boolean jpopupTrigger = NSEvent.isPopupTrigger(jmodifiers);
 
-        eventNotifier.notifyMouseEvent(jeventType, System.currentTimeMillis(), jbuttonNumber,
+        eventNotifier.notifyMouseEvent(platformWindow, jeventType, System.currentTimeMillis(), jbuttonNumber,
                 x, y, absoluteX, absoluteY, jmodifiers, jclickCount,
                 jpopupTrigger, null);
     }
@@ -91,12 +115,26 @@
     /**
      * Handles scroll events.
      */
-    void handleScrollEvent(final int x, final int y, final int modifierFlags,
+    void handleScrollEvent(int x, int y, final int modifierFlags,
                            final double deltaX, final double deltaY,
                            final int scrollPhase) {
         final int buttonNumber = CocoaConstants.kCGMouseButtonCenter;
         int jmodifiers = NSEvent.nsToJavaMouseModifiers(buttonNumber,
                                                         modifierFlags);
+        if (scrollPhase > NSEvent.SCROLL_PHASE_UNSUPPORTED) {
+            if (scrollPhase == NSEvent.SCROLL_PHASE_BEGAN) {
+                momentumStarted = false;
+            } else if (scrollPhase == NSEvent.SCROLL_PHASE_MOMENTUM_BEGAN) {
+                momentumStarted = true;
+                momentumX = x;
+                momentumY = y;
+                momentumModifiers = jmodifiers;
+            } else if (momentumStarted) {
+                x = momentumX;
+                y = momentumY;
+                jmodifiers = momentumModifiers;
+            }
+        }
         final boolean isShift = (jmodifiers & InputEvent.SHIFT_DOWN_MASK) != 0;
 
         int roundDeltaX = deltaAccumulatorX.getRoundedDelta(deltaX, scrollPhase);
@@ -126,79 +164,15 @@
                 scrollAmount, -roundDelta, -delta, null);
     }
 
-    /**
-     * Handles key events.
-     */
-    void handleKeyEvent(int eventType, int modifierFlags, String chars, String charsIgnoringModifiers,
-                        short keyCode, boolean needsKeyTyped, boolean needsKeyReleased) {
-        boolean isFlagsChangedEvent =
-            isNpapiCallback ? (eventType == CocoaConstants.NPCocoaEventFlagsChanged) :
-                              (eventType == CocoaConstants.NSFlagsChanged);
+    private void handleFlagChangedEvent(int modifierFlags, short keyCode) {
+        int[] in = new int[] {modifierFlags, keyCode};
+        int[] out = new int[3]; // [jkeyCode, jkeyLocation, jkeyType]
 
-        int jeventType = KeyEvent.KEY_PRESSED;
-        int jkeyCode = KeyEvent.VK_UNDEFINED;
-        int jkeyLocation = KeyEvent.KEY_LOCATION_UNKNOWN;
-        boolean postsTyped = false;
+        NSEvent.nsKeyModifiersToJavaKeyInfo(in, out);
 
-        char testChar = KeyEvent.CHAR_UNDEFINED;
-        boolean isDeadChar = (chars!= null && chars.length() == 0);
-
-        if (isFlagsChangedEvent) {
-            int[] in = new int[] {modifierFlags, keyCode};
-            int[] out = new int[3]; // [jkeyCode, jkeyLocation, jkeyType]
-
-            NSEvent.nsKeyModifiersToJavaKeyInfo(in, out);
-
-            jkeyCode = out[0];
-            jkeyLocation = out[1];
-            jeventType = out[2];
-        } else {
-            if (chars != null && chars.length() > 0) {
-                testChar = chars.charAt(0);
-            }
-
-            char testCharIgnoringModifiers = charsIgnoringModifiers != null && charsIgnoringModifiers.length() > 0 ?
-                    charsIgnoringModifiers.charAt(0) : KeyEvent.CHAR_UNDEFINED;
-
-            int[] in = new int[] {testCharIgnoringModifiers, isDeadChar ? 1 : 0, modifierFlags, keyCode};
-            int[] out = new int[3]; // [jkeyCode, jkeyLocation, deadChar]
-
-            postsTyped = NSEvent.nsToJavaKeyInfo(in, out);
-            if (!postsTyped) {
-                testChar = KeyEvent.CHAR_UNDEFINED;
-            }
-
-            if(isDeadChar){
-                testChar = (char) out[2];
-                if(testChar == 0){
-                    return;
-                }
-            }
-
-            // If Pinyin Simplified input method is selected, CAPS_LOCK key is supposed to switch
-            // input to latin letters.
-            // It is necessary to use testCharIgnoringModifiers instead of testChar for event
-            // generation in such case to avoid uppercase letters in text components.
-            LWCToolkit lwcToolkit = (LWCToolkit)Toolkit.getDefaultToolkit();
-            if (lwcToolkit.getLockingKeyState(KeyEvent.VK_CAPS_LOCK) &&
-                    Locale.SIMPLIFIED_CHINESE.equals(lwcToolkit.getDefaultKeyboardLocale())) {
-                testChar = testCharIgnoringModifiers;
-            }
-
-            jkeyCode = out[0];
-            jkeyLocation = out[1];
-            jeventType = isNpapiCallback ? NSEvent.npToJavaEventType(eventType) :
-                                           NSEvent.nsToJavaEventType(eventType);
-        }
-
-        char javaChar = NSEvent.nsToJavaChar(testChar, modifierFlags);
-        // Some keys may generate a KEY_TYPED, but we can't determine
-        // what that character is. That's likely a bug, but for now we
-        // just check for CHAR_UNDEFINED.
-        if (javaChar == KeyEvent.CHAR_UNDEFINED) {
-            postsTyped = false;
-        }
-
+        int jkeyCode = out[0];
+        int jkeyLocation = out[1];
+        int jeventType = out[2];
 
         int jmodifiers = NSEvent.nsToJavaKeyModifiers(modifierFlags);
         long when = System.currentTimeMillis();
@@ -207,11 +181,158 @@
             lastKeyPressCode = jkeyCode;
         }
         eventNotifier.notifyKeyEvent(jeventType, when, jmodifiers,
-                jkeyCode, javaChar, jkeyLocation);
+                jkeyCode, KeyEvent.CHAR_UNDEFINED, jkeyLocation);
+    }
+
+    private static char mapNsCharsToCompatibleWithJava (char ch) {
+        switch (ch) {
+            case 0x0003:          // NSEnterCharacter
+            case 0x000d:          // NSCarriageReturnCharacter
+                return 0x000a;    // NSNewlineCharacter
+//            case  0x007f:         // NSDeleteCharacter
+//                return 0x0008;    // NSBackspaceCharacter
+            case  0xF728:         // NSDeleteFunctionKey
+                return 0x0008;    // NSDeleteCharacter
+            case  0x0019:         // NSBackTabCharacter
+                return 0x0009;    // NSTabCharacter
+        }
+        return ch;
+    }
+
+    /**
+     * Handles key events.
+     */
+    void handleKeyEvent(NSEvent nsEvent)
+    {
+        boolean isFlagsChangedEvent =
+                isNpapiCallback ? (nsEvent.getType() == CocoaConstants.NPCocoaEventFlagsChanged) :
+                        (nsEvent.getType() == CocoaConstants.NSFlagsChanged);
+
+        int jeventType = KeyEvent.KEY_PRESSED;
+        int jkeyCode = KeyEvent.VK_UNDEFINED;
+        int jkeyLocation = KeyEvent.KEY_LOCATION_UNKNOWN;
+        boolean postsTyped = false;
+
+
+        if (isFlagsChangedEvent) {
+            handleFlagChangedEvent(nsEvent.getModifierFlags(), nsEvent.getKeyCode());
+            return;
+        }
+
+        int jmodifiers = NSEvent.nsToJavaKeyModifiers(nsEvent.getModifierFlags());
+
+        boolean metaAltCtrlAreNotPressed = (jmodifiers &
+                (InputEvent.META_DOWN_MASK
+                | InputEvent.ALT_DOWN_MASK
+                | InputEvent.CTRL_DOWN_MASK)
+        ) == 0;
+
+        boolean shiftIsPressed = (jmodifiers & InputEvent.SHIFT_DOWN_MASK) != 0;
+
+        boolean useShiftedCharacters = metaAltCtrlAreNotPressed && shiftIsPressed;
+
+        boolean shiftAltDownAreNotPressed = (jmodifiers &
+                (InputEvent.META_DOWN_MASK
+                | InputEvent.ALT_DOWN_MASK
+                | InputEvent.SHIFT_DOWN_MASK)
+        ) == 0;
+
+        boolean ctrlIsPressed = (jmodifiers & InputEvent.CTRL_DOWN_MASK) != 0;
+
+        boolean isISOControl = false;
+
+        char checkedChar = (nsEvent.getCharacters() == null
+                || nsEvent.getCharacters().isEmpty()) ? KeyEvent.CHAR_UNDEFINED : nsEvent.getCharacters().charAt(0);
+
+        if (shiftAltDownAreNotPressed && ctrlIsPressed) {
+            if (Character.isISOControl(checkedChar)) {
+                isISOControl = true;
+            }
+        }
+
+        char characterToGetKeyCode = KeyEvent.CHAR_UNDEFINED;
+
+        boolean charactersIgnoringModifiersIsValid  = (nsEvent.getCharactersIgnoringModifiers() != null && nsEvent.getCharactersIgnoringModifiers().length() > 0);
+        boolean charactersIsValid  = (nsEvent.getCharacters() != null && nsEvent.getCharacters().length() > 0);
+
+        // We use this char to find a character that is printed depending on pressing modifiers
+        characterToGetKeyCode = charactersIgnoringModifiersIsValid
+            ? nsEvent.getCharactersIgnoringModifiers().charAt(0)
+            : charactersIsValid ? nsEvent.getCharacters().charAt(0) : KeyEvent.CHAR_UNDEFINED;
+
+        // We use char candidate if modifiers are not used
+        // otherwise, we use char ignoring modifiers
+        int[] in = new int[] {
+                characterToGetKeyCode,
+                nsEvent.getModifierFlags(),
+                nsEvent.isHasDeadKey() ? 1 : 0,
+                nsEvent.getKeyCode()
+        };
+
+        int[] out = new int[3]; // [jkeyCode, jkeyLocation, deadChar]
+
+        postsTyped = NSEvent.nsToJavaKeyInfo(in, out);
+
+        char characterToSendWithTheEvent = KeyEvent.CHAR_UNDEFINED;
+
+        if(nsEvent.isHasDeadKey()){
+            characterToSendWithTheEvent = (char) out[2];
+            jkeyCode = nsEvent.getDeadKeyCode();
+            if(characterToSendWithTheEvent == 0){
+                return;
+            }
+        }
+
+        // If Pinyin Simplified input method is selected, CAPS_LOCK key is supposed to switch
+        // input to la tin letters.
+        // It is necessary to use charIgnoringModifiers instead of charCandidate for event
+        // generation in such case to avoid uppercase letters in text components.
+        LWCToolkit lwcToolkit = (LWCToolkit)Toolkit.getDefaultToolkit();
+        if (lwcToolkit.getLockingKeyState(KeyEvent.VK_CAPS_LOCK) &&
+                Locale.SIMPLIFIED_CHINESE.equals(lwcToolkit.getDefaultKeyboardLocale())) {
+            characterToSendWithTheEvent = characterToGetKeyCode;
+        }
+
+        jkeyCode = out[0];
+
+        jkeyLocation = out[1];
+        jeventType = isNpapiCallback ? NSEvent.npToJavaEventType(nsEvent.getType()) :
+                NSEvent.nsToJavaEventType(nsEvent.getType());
+
+
+        if (isISOControl) {
+            characterToSendWithTheEvent = checkedChar;
+        } else  if (useShiftedCharacters && nsEvent.getCharactersIgnoringModifiers() != null && !nsEvent.getCharactersIgnoringModifiers().isEmpty()) {
+            characterToSendWithTheEvent = nsEvent.getCharactersIgnoringModifiers().charAt(0);
+        } else  if (nsEvent.getCharactersIgnoringModifiersAndShift() != null && !nsEvent.getCharactersIgnoringModifiersAndShift().isEmpty()) {
+            characterToSendWithTheEvent = nsEvent.getCharactersIgnoringModifiersAndShift().charAt(0);
+        } else if (nsEvent.getCharacters() != null && !nsEvent.getCharacters().isEmpty() && metaAltCtrlAreNotPressed && shiftIsPressed) {
+            characterToSendWithTheEvent = checkedChar;
+        }
+
+        characterToSendWithTheEvent = mapNsCharsToCompatibleWithJava(characterToSendWithTheEvent);
+
+        if (jmodifiers != 0 && nsEvent.getCharactersIgnoringModifiersAndShift() != null && !nsEvent.getCharactersIgnoringModifiersAndShift().isEmpty()) {
+            String stringWithChar = NSEvent.nsToJavaChar(characterToSendWithTheEvent, nsEvent.getModifierFlags());
+            characterToSendWithTheEvent = stringWithChar == null ? KeyEvent.CHAR_UNDEFINED : stringWithChar.charAt(0);
+        } else {
+            String stringWithChar = NSEvent.nsToJavaChar(characterToSendWithTheEvent, nsEvent.getModifierFlags());
+            characterToSendWithTheEvent = stringWithChar == null ? KeyEvent.CHAR_UNDEFINED : stringWithChar.charAt(0);
+        }
+
+
+        long when = System.currentTimeMillis();
+
+        if (jeventType == KeyEvent.KEY_PRESSED) {
+            lastKeyPressCode = jkeyCode;
+        }
+
+        eventNotifier.notifyKeyEvent(jeventType, when, jmodifiers,
+                jkeyCode, characterToSendWithTheEvent, jkeyLocation);
 
         // Current browser may be sending input events, so don't
         // post the KEY_TYPED here.
-        postsTyped &= needsKeyTyped;
+        postsTyped &= true;
 
         // That's the reaction on the PRESSED (not RELEASED) event as it comes to
         // appear in MacOSX.
@@ -220,18 +341,22 @@
         // for clipboard related shortcuts like Meta + [CVX]
         if (jeventType == KeyEvent.KEY_PRESSED && postsTyped &&
                 (jmodifiers & KeyEvent.META_DOWN_MASK) == 0) {
-            // Enter and Space keys finish the input method processing,
-            // KEY_TYPED and KEY_RELEASED events for them are synthesized in handleInputEvent.
-            if (needsKeyReleased && (jkeyCode == KeyEvent.VK_ENTER || jkeyCode == KeyEvent.VK_SPACE)) {
-                return;
+
+            char characterToSendWithTypedEvent = KeyEvent.CHAR_UNDEFINED;
+
+            if (nsEvent.getCharacters()!= null ) {
+                characterToSendWithTypedEvent = mapNsCharsToCompatibleWithJava(checkedChar);
+                String stringWithChar = NSEvent.nsToJavaChar(characterToSendWithTypedEvent, nsEvent.getModifierFlags());
+                characterToSendWithTypedEvent = stringWithChar == null ? KeyEvent.CHAR_UNDEFINED :  stringWithChar.charAt(0);
             }
-            eventNotifier.notifyKeyEvent(KeyEvent.KEY_TYPED, when, jmodifiers,
-                    KeyEvent.VK_UNDEFINED, javaChar,
-                    KeyEvent.KEY_LOCATION_UNKNOWN);
-            //If events come from Firefox, released events should also be generated.
-            if (needsKeyReleased) {
-                eventNotifier.notifyKeyEvent(KeyEvent.KEY_RELEASED, when, jmodifiers,
-                        jkeyCode, javaChar,
+
+            boolean nonInputMethodsModifiersAreNotPressed = (jmodifiers &
+                    (InputEvent.META_DOWN_MASK | InputEvent.CTRL_DOWN_MASK)
+            ) == 0;
+
+            if (nonInputMethodsModifiersAreNotPressed) {
+                eventNotifier.notifyKeyEvent(KeyEvent.KEY_TYPED, when, jmodifiers,
+                        jkeyCode, characterToSendWithTypedEvent,
                         KeyEvent.KEY_LOCATION_UNKNOWN);
             }
         }
@@ -262,9 +387,8 @@
 
     static class DeltaAccumulator {
 
-        static final double MIN_THRESHOLD = 0.1;
-        static final double MAX_THRESHOLD = 0.5;
         double accumulatedDelta;
+        boolean accumulate;
 
         int getRoundedDelta(double delta, int scrollPhase) {
 
@@ -275,25 +399,23 @@
                     roundDelta = delta > 0 ? 1 : -1;
                 }
             } else { // trackpad
-                boolean begin = scrollPhase == NSEvent.SCROLL_PHASE_BEGAN;
-                boolean end = scrollPhase == NSEvent.SCROLL_MASK_PHASE_ENDED
-                        || scrollPhase == NSEvent.SCROLL_MASK_PHASE_CANCELLED;
-
-                if (begin) {
+                if (scrollPhase == NSEvent.SCROLL_PHASE_BEGAN) {
                     accumulatedDelta = 0;
+                    accumulate = true;
                 }
+                else if (scrollPhase == NSEvent.SCROLL_PHASE_MOMENTUM_BEGAN) {
+                    accumulate = true;
+                }
+                if (accumulate) {
 
-                accumulatedDelta += delta;
+                    accumulatedDelta += delta;
 
-                double absAccumulatedDelta = Math.abs(accumulatedDelta);
-                if (absAccumulatedDelta > MAX_THRESHOLD) {
                     roundDelta = (int) Math.round(accumulatedDelta);
-                    accumulatedDelta -= roundDelta;
-                }
 
-                if (end) {
-                    if (roundDelta == 0 && absAccumulatedDelta > MIN_THRESHOLD) {
-                        roundDelta = accumulatedDelta > 0 ? 1 : -1;
+                    accumulatedDelta -= roundDelta;
+
+                    if (scrollPhase == NSEvent.SCROLL_PHASE_ENDED) {
+                        accumulate = false;
                     }
                 }
             }
diff --git a/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java b/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java
index 9d1acaf..43f6495 100644
--- a/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java
+++ b/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java
@@ -35,6 +35,7 @@
 import sun.java2d.SurfaceData;
 import sun.java2d.opengl.CGLLayer;
 import sun.java2d.opengl.CGLSurfaceData;
+import sun.lwawt.PlatformWindow;
 
 public class CPlatformView extends CFRetainedResource {
     private native long nativeCreateView(int x, int y, int width, int height, long windowLayerPtr);
@@ -186,7 +187,7 @@
     }
 
 
-    private void deliverMouseEvent(NSEvent event) {
+    private void deliverMouseEvent(NSEvent event, CPlatformWindow platformWindow) {
         int x = event.getX();
         int y = getBounds().height - event.getY();
 
@@ -195,14 +196,13 @@
                                         event.getScrollDeltaX(), event.getScrollDeltaY(),
                                         event.getScrollPhase());
         } else {
-            responder.handleMouseEvent(event.getType(), event.getModifierFlags(), event.getButtonNumber(),
+            responder.handleMouseEvent(platformWindow, event.getType(), event.getModifierFlags(), event.getButtonNumber(),
                                        event.getClickCount(), x, y, event.getAbsX(), event.getAbsY());
         }
     }
 
-    private void deliverKeyEvent(NSEvent event) {
-        responder.handleKeyEvent(event.getType(), event.getModifierFlags(), event.getCharacters(),
-                                 event.getCharactersIgnoringModifiers(), event.getKeyCode(), true, false);
+    private void deliverKeyEvent(NSEvent nsEvent) {
+        responder.handleKeyEvent(nsEvent);
     }
 
     /**
diff --git a/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java b/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java
index f34f676..40e34ed 100644
--- a/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java
+++ b/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java
@@ -337,7 +337,7 @@
             javax.swing.JRootPane rootpane = ((javax.swing.RootPaneContainer)target).getRootPane();
             Object prop = null;
 
-            prop = rootpane.getClientProperty(WINDOW_BRUSH_METAL_LOOK);
+            prop = (rootpane == null) ? null : rootpane.getClientProperty(WINDOW_BRUSH_METAL_LOOK);
             if (prop != null) {
                 styleBits = SET(styleBits, TEXTURED, Boolean.parseBoolean(prop.toString()));
             }
@@ -349,7 +349,7 @@
                 }
             }
 
-            prop = rootpane.getClientProperty(WINDOW_STYLE);
+            prop = (rootpane == null) ? null : rootpane.getClientProperty(WINDOW_STYLE);
             if (prop != null) {
                 if ("small".equals(prop))  {
                     styleBits = SET(styleBits, UTILITY, true);
@@ -362,39 +362,41 @@
                 if ("hud".equals(prop)) styleBits = SET(styleBits, HUD, true);
             }
 
-            prop = rootpane.getClientProperty(WINDOW_HIDES_ON_DEACTIVATE);
-            if (prop != null) {
-                styleBits = SET(styleBits, HIDES_ON_DEACTIVATE, Boolean.parseBoolean(prop.toString()));
-            }
+            if (rootpane != null) {
+                prop = rootpane.getClientProperty(WINDOW_HIDES_ON_DEACTIVATE);
+                if (prop != null) {
+                    styleBits = SET(styleBits, HIDES_ON_DEACTIVATE, Boolean.parseBoolean(prop.toString()));
+                }
 
-            prop = rootpane.getClientProperty(WINDOW_CLOSEABLE);
-            if (prop != null) {
-                styleBits = SET(styleBits, CLOSEABLE, Boolean.parseBoolean(prop.toString()));
-            }
+                prop = rootpane.getClientProperty(WINDOW_CLOSEABLE);
+                if (prop != null) {
+                    styleBits = SET(styleBits, CLOSEABLE, Boolean.parseBoolean(prop.toString()));
+                }
 
-            prop = rootpane.getClientProperty(WINDOW_MINIMIZABLE);
-            if (prop != null) {
-                styleBits = SET(styleBits, MINIMIZABLE, Boolean.parseBoolean(prop.toString()));
-            }
+                prop = rootpane.getClientProperty(WINDOW_MINIMIZABLE);
+                if (prop != null) {
+                    styleBits = SET(styleBits, MINIMIZABLE, Boolean.parseBoolean(prop.toString()));
+                }
 
-            prop = rootpane.getClientProperty(WINDOW_ZOOMABLE);
-            if (prop != null) {
-                styleBits = SET(styleBits, ZOOMABLE, Boolean.parseBoolean(prop.toString()));
-            }
+                prop = rootpane.getClientProperty(WINDOW_ZOOMABLE);
+                if (prop != null) {
+                    styleBits = SET(styleBits, ZOOMABLE, Boolean.parseBoolean(prop.toString()));
+                }
 
-            prop = rootpane.getClientProperty(WINDOW_FULLSCREENABLE);
-            if (prop != null) {
-                styleBits = SET(styleBits, FULLSCREENABLE, Boolean.parseBoolean(prop.toString()));
-            }
+                prop = rootpane.getClientProperty(WINDOW_FULLSCREENABLE);
+                if (prop != null) {
+                    styleBits = SET(styleBits, FULLSCREENABLE, Boolean.parseBoolean(prop.toString()));
+                }
 
-            prop = rootpane.getClientProperty(WINDOW_SHADOW);
-            if (prop != null) {
-                styleBits = SET(styleBits, HAS_SHADOW, Boolean.parseBoolean(prop.toString()));
-            }
+                prop = rootpane.getClientProperty(WINDOW_SHADOW);
+                if (prop != null) {
+                    styleBits = SET(styleBits, HAS_SHADOW, Boolean.parseBoolean(prop.toString()));
+                }
 
-            prop = rootpane.getClientProperty(WINDOW_DRAGGABLE_BACKGROUND);
-            if (prop != null) {
-                styleBits = SET(styleBits, DRAGGABLE_BACKGROUND, Boolean.parseBoolean(prop.toString()));
+                prop = rootpane.getClientProperty(WINDOW_DRAGGABLE_BACKGROUND);
+                if (prop != null) {
+                    styleBits = SET(styleBits, DRAGGABLE_BACKGROUND, Boolean.parseBoolean(prop.toString()));
+                }
             }
         }
 
@@ -536,36 +538,6 @@
 
         boolean wasMaximized = isMaximized();
 
-        // Actually show or hide the window
-        LWWindowPeer blocker = (peer == null)? null : peer.getBlocker();
-        if (blocker == null || !visible) {
-            // If it ain't blocked, or is being hidden, go regular way
-            if (visible) {
-                CWrapper.NSWindow.makeFirstResponder(nsWindowPtr, contentView.getAWTView());
-
-                boolean isPopup = (target.getType() == Window.Type.POPUP);
-                if (isPopup) {
-                    // Popups in applets don't activate applet's process
-                    CWrapper.NSWindow.orderFrontRegardless(nsWindowPtr);
-                } else {
-                    CWrapper.NSWindow.orderFront(nsWindowPtr);
-                }
-
-                boolean isKeyWindow = CWrapper.NSWindow.isKeyWindow(nsWindowPtr);
-                if (!isKeyWindow) {
-                    CWrapper.NSWindow.makeKeyWindow(nsWindowPtr);
-                }
-            } else {
-                // immediately hide the window
-                CWrapper.NSWindow.orderOut(nsWindowPtr);
-                // process the close
-                CWrapper.NSWindow.close(nsWindowPtr);
-            }
-        } else {
-            // otherwise, put it in a proper z-order
-            CWrapper.NSWindow.orderWindow(nsWindowPtr, CWrapper.NSWindow.NSWindowBelow,
-                    ((CPlatformWindow)blocker.getPlatformWindow()).getNSWindowPtr());
-        }
         this.visible = visible;
 
         // Manage the extended state when showing
@@ -608,20 +580,43 @@
                 CWrapper.NSWindow.orderWindow(nsWindowPtr, CWrapper.NSWindow.NSWindowAbove, owner.getNSWindowPtr());
                 applyWindowLevel(target);
             }
-
-            // Order my own children above myself
-            for (Window w : target.getOwnedWindows()) {
-                WindowPeer p = (WindowPeer)w.getPeer();
-                if (p instanceof LWWindowPeer) {
-                    CPlatformWindow pw = (CPlatformWindow)((LWWindowPeer)p).getPlatformWindow();
-                    if (pw != null && pw.isVisible()) {
-                        CWrapper.NSWindow.orderWindow(pw.getNSWindowPtr(), CWrapper.NSWindow.NSWindowAbove, nsWindowPtr);
-                        pw.applyWindowLevel(w);
-                    }
-                }
-            }
         }
 
+
+        // Actually show or hide the window
+        LWWindowPeer blocker = (peer == null)? null : peer.getBlocker();
+        if (blocker == null || !visible) {
+
+            // If it ain't blocked, or is being hidden, go regular way
+            if (visible) {
+
+                CWrapper.NSWindow.makeFirstResponder(nsWindowPtr, contentView.getAWTView());
+
+                boolean isPopup = (target.getType() == Window.Type.POPUP);
+                if (isPopup) {
+                    // Popups in applets don't activate applet's process
+                    CWrapper.NSWindow.orderFrontRegardless(nsWindowPtr);
+                } else {
+                    CWrapper.NSWindow.orderFront(nsWindowPtr);
+                }
+
+                boolean isKeyWindow = CWrapper.NSWindow.isKeyWindow(nsWindowPtr);
+                if (!isKeyWindow) {
+                    CWrapper.NSWindow.makeKeyWindow(nsWindowPtr);
+                }
+            } else {
+                // immediately hide the window
+                CWrapper.NSWindow.orderOut(nsWindowPtr);
+                // process the close
+                CWrapper.NSWindow.close(nsWindowPtr);
+            }
+        } else {
+            // otherwise, put it in a proper z-order
+            CWrapper.NSWindow.orderWindow(nsWindowPtr, CWrapper.NSWindow.NSWindowBelow,
+                    ((CPlatformWindow)blocker.getPlatformWindow()).getNSWindowPtr());
+        }
+
+            // Order my own children above myself
         // Deal with the blocker of the window being shown
         if (blocker != null && visible) {
             // Make sure the blocker is above its siblings
@@ -669,7 +664,7 @@
         Window w = DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow();
         if( w != null && w.getPeer() != null
                 && ((LWWindowPeer)w.getPeer()).getPeerType() == LWWindowPeer.PeerType.EMBEDDED_FRAME
-                && !lwcToolkit.isApplicationActive()) {
+                /*&& !lwcToolkit.isApplicationActive()*/) {
             lwcToolkit.activateApplicationIgnoringOtherApps();
         }
         updateFocusabilityForAutoRequestFocus(false);
@@ -689,14 +684,15 @@
 
     @Override
     public boolean rejectFocusRequest(CausedFocusEvent.Cause cause) {
+        return true;
         // Cross-app activation requests are not allowed.
-        if (cause != CausedFocusEvent.Cause.MOUSE_EVENT &&
-            !((LWCToolkit)Toolkit.getDefaultToolkit()).isApplicationActive())
-        {
-            focusLogger.fine("the app is inactive, so the request is rejected");
-            return true;
-        }
-        return false;
+        //if (cause != CausedFocusEvent.Cause.MOUSE_EVENT &&
+        //    !((LWCToolkit)Toolkit.getDefaultToolkit()).isApplicationActive())
+        //{
+        //    focusLogger.fine("the app is inactive, so the request is rejected");
+        //    return true;
+        //}
+        //return false;
     }
 
     @Override
@@ -925,10 +921,10 @@
      *************************************************************/
     private void deliverWindowFocusEvent(boolean gained, CPlatformWindow opposite){
         // Fix for 7150349: ingore "gained" notifications when the app is inactive.
-        if (gained && !((LWCToolkit)Toolkit.getDefaultToolkit()).isApplicationActive()) {
-            focusLogger.fine("the app is inactive, so the notification is ignored");
-            return;
-        }
+        //if (gained && !((LWCToolkit)Toolkit.getDefaultToolkit()).isApplicationActive()) {
+        //     focusLogger.fine("the app is inactive, so the notification is ignored");
+        //     return;
+        //}
 
         LWWindowPeer oppositePeer = (opposite == null)? null : opposite.getPeer();
         responder.handleWindowFocusEvent(gained, oppositePeer);
diff --git a/src/macosx/classes/sun/lwawt/macosx/CWarningWindow.java b/src/macosx/classes/sun/lwawt/macosx/CWarningWindow.java
index 5962b7f..d488a45 100644
--- a/src/macosx/classes/sun/lwawt/macosx/CWarningWindow.java
+++ b/src/macosx/classes/sun/lwawt/macosx/CWarningWindow.java
@@ -33,6 +33,7 @@
 import sun.java2d.opengl.CGLLayer;
 import sun.lwawt.LWWindowPeer;
 import sun.lwawt.PlatformEventNotifier;
+import sun.lwawt.PlatformWindow;
 import sun.lwawt.SecurityWarningWindow;
 
 import java.awt.*;
@@ -187,7 +188,7 @@
     }
 
     @Override
-    public void notifyMouseEvent(int id, long when, int button, int x, int y,
+    public void notifyMouseEvent(PlatformWindow platformWindow, int id, long when, int button, int x, int y,
                                  int screenX, int screenY, int modifiers,
                                  int clickCount, boolean popupTrigger,
                                  byte[] bdata) {
diff --git a/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java b/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java
index 9b17d8b..042bcec 100644
--- a/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java
+++ b/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java
@@ -41,6 +41,9 @@
 import java.util.*;
 import java.util.concurrent.Callable;
 import java.net.MalformedURLException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
 
 import sun.awt.*;
 import sun.awt.datatransfer.DataTransferer;
@@ -48,7 +51,6 @@
 import sun.lwawt.*;
 import sun.lwawt.LWWindowPeer.PeerType;
 import sun.security.action.GetBooleanAction;
-import sun.awt.image.MultiResolutionImage;
 
 import sun.util.CoreResourceBundleControl;
 
@@ -135,6 +137,7 @@
     };
 
     private native void loadNativeColors(final int[] systemColors, final int[] appleColors);
+    private static native void printNativeCallStack();
 
     @Override
     protected void loadSystemColors(final int[] systemColors) {
@@ -606,6 +609,30 @@
         }
     }
 
+    private static final AtomicInteger blockingRunLoopCounter = new AtomicInteger(0);
+    private static final AtomicBoolean priorityInvocationPending = new AtomicBoolean(false);
+
+    @Override
+    public void unsafeNonblockingExecute(Runnable runnable) {
+        if (!EventQueue.isDispatchThread()) {
+            throw new Error("the method must be called on the Event Dispatching thread");
+        }
+        if (runnable == null) return;
+
+        synchronized (priorityInvocationPending) {
+            priorityInvocationPending.set(true);
+        }
+        AWTAccessor.getEventQueueAccessor().createSecondaryLoop(
+            getSystemEventQueue(),
+            () -> blockingRunLoopCounter.get() > 0).enter();
+
+        try {
+            runnable.run();
+        } finally {
+            priorityInvocationPending.set(false);
+        }
+    }
+
     /**
      * Kicks an event over to the appropriate eventqueue and waits for it to
      * finish To avoid deadlocking, we manually run the NSRunLoop while waiting
@@ -615,7 +642,15 @@
      * runloop Does not dispatch native events while in the loop
      */
     public static void invokeAndWait(Runnable runnable, Component component)
-            throws InvocationTargetException {
+            throws InvocationTargetException
+    {
+        boolean nonBlockingRunLoop;
+
+        synchronized (priorityInvocationPending) {
+            nonBlockingRunLoop = priorityInvocationPending.get();
+            if (!nonBlockingRunLoop) blockingRunLoopCounter.incrementAndGet();
+        }
+
         final long mediator = createAWTRunLoopMediator();
 
         InvocationEvent invocationEvent =
@@ -639,7 +674,8 @@
             ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
         }
 
-        doAWTRunLoop(mediator, false);
+        doAWTRunLoop(mediator, nonBlockingRunLoop);
+        if (!nonBlockingRunLoop) blockingRunLoopCounter.decrementAndGet();
 
         Throwable eventException = invocationEvent.getException();
         if (eventException != null) {
@@ -791,7 +827,8 @@
     /*
      * Returns true if the application (one of its windows) owns keyboard focus.
      */
-    native boolean isApplicationActive();
+    //native boolean isApplicationActive();
+    boolean isApplicationActive () { return true; }
 
     /**
      * Returns true if AWT toolkit is embedded, false otherwise.
diff --git a/src/macosx/classes/sun/lwawt/macosx/NSEvent.java b/src/macosx/classes/sun/lwawt/macosx/NSEvent.java
index eccc257..a19ebca 100644
--- a/src/macosx/classes/sun/lwawt/macosx/NSEvent.java
+++ b/src/macosx/classes/sun/lwawt/macosx/NSEvent.java
@@ -36,8 +36,11 @@
     static final int SCROLL_PHASE_UNSUPPORTED = 1;
     static final int SCROLL_PHASE_BEGAN = 2;
     static final int SCROLL_PHASE_CONTINUED = 3;
-    static final int SCROLL_MASK_PHASE_CANCELLED = 4;
-    static final int SCROLL_MASK_PHASE_ENDED = 5;
+    static final int SCROLL_PHASE_MOMENTUM_BEGAN = 4;
+    static final int SCROLL_PHASE_ENDED = 5;
+
+    private boolean hasDeadKey;
+    private int deadKeyCode;
 
     private int type;
     private int modifierFlags;
@@ -57,14 +60,28 @@
     private short keyCode;
     private String characters;
     private String charactersIgnoringModifiers;
+    private String charactersIgnoringModifiersAndShift;
+
+    public boolean isHasDeadKey() {
+        return hasDeadKey;
+    }
+
+    public int getDeadKeyCode() {
+        return deadKeyCode;
+    }
 
     // Called from native
-    NSEvent(int type, int modifierFlags, short keyCode, String characters, String charactersIgnoringModifiers) {
+    NSEvent(int type, int modifierFlags, short keyCode, String characters, String charactersIgnoringModifiers,
+            String charactersIgnoringModifiersAndShift, boolean hasDeadKey, int deadKeyCode) {
         this.type = type;
         this.modifierFlags = modifierFlags;
+
         this.keyCode = keyCode;
         this.characters = characters;
         this.charactersIgnoringModifiers = charactersIgnoringModifiers;
+        this.charactersIgnoringModifiersAndShift = charactersIgnoringModifiersAndShift;
+        this.hasDeadKey = hasDeadKey;
+        this.deadKeyCode = deadKeyCode;
     }
 
     // Called from native
@@ -136,6 +153,8 @@
         return charactersIgnoringModifiers;
     }
 
+    String getCharactersIgnoringModifiersAndShift() {return charactersIgnoringModifiersAndShift;}
+
     String getCharacters() {
         return characters;
     }
@@ -145,7 +164,7 @@
         return "NSEvent[" + getType() + " ," + getModifierFlags() + " ,"
                 + getClickCount() + " ," + getButtonNumber() + " ," + getX() + " ,"
                 + getY() + " ," + getAbsX() + " ," + getAbsY()+ " ," + getKeyCode() + " ,"
-                + getCharacters() + " ," + getCharactersIgnoringModifiers() + "]";
+                + getCharacters() + " ," + getCharactersIgnoringModifiers() + " ," + getCharactersIgnoringModifiersAndShift() + "]";
     }
 
     /*
@@ -269,7 +288,7 @@
      * There is a small number of NS characters that need to be converted
      * into other characters before we pass them to AWT.
      */
-    static native char nsToJavaChar(char nsChar, int modifierFlags);
+    static native String nsToJavaChar(char nsChar, int modifierFlags);
 
     static boolean isPopupTrigger(int jmodifiers) {
         final boolean isRightButtonDown = ((jmodifiers & InputEvent.BUTTON3_DOWN_MASK) != 0);
diff --git a/src/macosx/native/sun/awt/AWTEvent.h b/src/macosx/native/sun/awt/AWTEvent.h
index 7769f3d..c8301a3 100644
--- a/src/macosx/native/sun/awt/AWTEvent.h
+++ b/src/macosx/native/sun/awt/AWTEvent.h
@@ -28,6 +28,10 @@
 
 #import "LWCToolkit.h"
 
+@interface NSEvent (NSEventExtension)
+- (NSString *)charactersIgnoringModifiersAndShift;
+@end
+
 jlong UTC(NSEvent *event);
 void DeliverJavaKeyEvent(JNIEnv *env, NSEvent *event, jobject peer);
 void DeliverJavaMouseEvent(JNIEnv *env, NSEvent *event, jobject peer);
diff --git a/src/macosx/native/sun/awt/AWTEvent.m b/src/macosx/native/sun/awt/AWTEvent.m
index 7062476..087b738 100644
--- a/src/macosx/native/sun/awt/AWTEvent.m
+++ b/src/macosx/native/sun/awt/AWTEvent.m
@@ -26,7 +26,6 @@
 #import <JavaNativeFoundation/JavaNativeFoundation.h>
 #import <JavaRuntimeSupport/JavaRuntimeSupport.h>
 #import <sys/time.h>
-#include <Carbon/Carbon.h>
 
 #import "jni_util.h" 
 #import "LWCToolkit.h"
@@ -313,72 +312,6 @@
     {0, 0, 0, 0, 0, 0}
 };
 
-/*
- * Almost all unicode characters just go from NS to Java with no translation.
- *  For the few exceptions, we handle it here with this small table.
- */
-#define ALL_NS_KEY_MODIFIERS_MASK \
-    (NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask)
-
-static struct _char {
-    NSUInteger modifier;
-    unichar nsChar;
-    unichar javaChar;
-}
-const charTable[] = {
-    // map enter on keypad to same as return key
-    {0,                         NSEnterCharacter,          NSNewlineCharacter},
-
-    // [3134616] return newline instead of carriage return
-    {0,                         NSCarriageReturnCharacter, NSNewlineCharacter},
-
-    // "delete" means backspace in Java
-    {ALL_NS_KEY_MODIFIERS_MASK, NSDeleteCharacter,         NSBackspaceCharacter},
-    {ALL_NS_KEY_MODIFIERS_MASK, NSDeleteFunctionKey,       NSDeleteCharacter},
-
-    // back-tab is only differentiated from tab by Shift flag
-    {NSShiftKeyMask,            NSBackTabCharacter,        NSTabCharacter},
-
-    {0, 0, 0}
-};
-
-unichar NsCharToJavaChar(unichar nsChar, NSUInteger modifiers)
-{
-    const struct _char *cur;
-    // Mask off just the keyboard modifiers from the event modifier mask.
-    NSUInteger testableFlags = (modifiers & ALL_NS_KEY_MODIFIERS_MASK);
-
-    // walk through table & find the match
-    for (cur = charTable; cur->nsChar != 0 ; cur++) {
-        // <rdar://Problem/3476426> Need to determine if we are looking at
-        // a plain keypress or a modified keypress.  Don't adjust the
-        // character of a keypress with a modifier.
-        if (cur->nsChar == nsChar) {
-            if (cur->modifier == 0 && testableFlags == 0) {
-                // If the modifier field is 0, that means to transform
-                // this character if no additional keyboard modifiers are set.
-                // This lets ctrl-C be reported as ctrl-C and not transformed
-                // into Newline.
-                return cur->javaChar;
-            } else if (cur->modifier != 0 &&
-                       (testableFlags & cur->modifier) == testableFlags)
-            {
-                // Likewise, if the modifier field is nonzero, that means
-                // transform this character if only these modifiers are
-                // set in the testable flags.
-                return cur->javaChar;
-            }
-        }
-    }
-
-    if (nsChar >= NSUpArrowFunctionKey && nsChar <= NSModeSwitchFunctionKey) {
-        return java_awt_event_KeyEvent_CHAR_UNDEFINED;
-    }
-
-    // otherwise return character unchanged
-    return nsChar;
-}
-
 static unichar NsGetDeadKeyChar(unsigned short keyCode)
 {
     TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
@@ -419,7 +352,99 @@
     return 0;
 }
 
-/*
+static NSDictionary* getDiacriticUnicharToVkCodeDictionary() {
+
+    static NSDictionary* diacriticUnicharToVkCodeDictionary = nil;
+    static dispatch_once_t onceToken;
+
+    dispatch_once(&onceToken, ^{
+         diacriticUnicharToVkCodeDictionary =
+             [NSDictionary dictionaryWithObjectsAndKeys:
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_A_WITH_GRAVE], @"à",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_A_WITH_ACUTE], @"á",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_A_WITH_CIRCUMFLEX], @"â",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_A_WITH_TILDE], @"ã",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_A_WITH_DIAERESIS], @"ä",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_A_WITH_RING_ABOVE], @"å",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_AE], @"æ",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_C_WITH_CEDILLA], @"ç",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_E_WITH_GRAVE], @"è",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_E_WITH_ACUTE], @"é",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_E_WITH_CIRCUMFLEX], @"ê",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_E_WITH_DIAERESIS], @"ë",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_I_WITH_GRAVE], @"ì",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_I_WITH_ACUTE], @"í",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_I_WITH_CIRCUMFLEX], @"î",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_I_WITH_DIAERESIS], @"ï",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_ETH], @"ð",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_N_WITH_TILDE], @"ñ",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_O_WITH_GRAVE], @"ò",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_O_WITH_ACUTE], @"ó",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_O_WITH_CIRCUMFLEX], @"ô",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_O_WITH_TILDE], @"õ",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_O_WITH_DIAERESIS], @"ö",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_DIVISION_SIGN], @"÷",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_O_WITH_SLASH], @"ø",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_U_WITH_GRAVE], @"ù",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_U_WITH_ACUTE], @"ú",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_U_WITH_CIRCUMFLEX], @"û",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_U_WITH_DIAERESIS], @"ü",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_Y_WITH_ACUTE], @"ý",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_THORN], @"þ",
+                  [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_Y_WITH_DIAERESIS], @"ÿ",
+                  nil
+             ];
+             // This is ok to retain a singleton object
+             [diacriticUnicharToVkCodeDictionary retain];
+    });
+    return diacriticUnicharToVkCodeDictionary;
+}
+
+static NSDictionary* getUnicharToVkCodeDictionary() {
+
+    static NSDictionary* unicharToVkCodeDictionary = nil;
+    static dispatch_once_t onceToken;
+
+    dispatch_once(&onceToken, ^{
+         unicharToVkCodeDictionary =
+             [NSDictionary dictionaryWithObjectsAndKeys:
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_BACK_QUOTE], @"`",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_1], @"1",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_2], @"2",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_3], @"3",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_4], @"4",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_5], @"5",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_6], @"6",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_7], @"7",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_8], @"8",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_9], @"9",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_0], @"0",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_EQUALS], @"=",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_MINUS], @"-",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_CLOSE_BRACKET], @"]",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_OPEN_BRACKET], @"[",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_QUOTE], @"\'",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_SEMICOLON], @";",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_COLON], @":",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_BACK_SLASH], @"\\",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_COMMA], @",",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_SLASH], @"/",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_PERIOD], @".",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_MULTIPLY], @"*",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_ADD], @"+",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_EQUALS], @"=",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_COMMA], @",",
+                 [NSNumber numberWithInt:java_awt_event_KeyEvent_VK_NUMBER_SIGN], @"#",
+                 nil
+             ];
+             // This is ok to retain a singleton object
+             [unicharToVkCodeDictionary retain];
+    });
+
+    return unicharToVkCodeDictionary;
+}
+
+/*§
  * This is the function that uses the table above to take incoming
  * NSEvent keyCodes and translate to the Java virtual key code.
  */
@@ -432,6 +457,7 @@
     NSInteger offset;
 
     if (isDeadChar) {
+        //NSLog(@"This is a dead char");
         unichar testDeadChar = NsGetDeadKeyChar(key);
         const struct CharToVKEntry *map;
         for (map = charToDeadVKTable; map->c != 0; ++map) {
@@ -447,17 +473,22 @@
         // If we got here, we keep looking for a normal key.
     }
 
+
+
     if ([[NSCharacterSet letterCharacterSet] characterIsMember:ch]) {
         // key is an alphabetic character
         unichar lower;
         lower = tolower(ch);
         offset = lower - 'a';
+        //NSLog(@"letter offset: %d", offset);
         if (offset >= 0 && offset <= 25) {
             // some chars in letter set are NOT actually A-Z characters?!
             // skip them...
             *postsTyped = YES;
             // do quick conversion
             *keyCode = java_awt_event_KeyEvent_VK_A + offset;
+            //NSLog(@"A code is  %d", java_awt_event_KeyEvent_VK_A);
+            //NSLog(@"so key code is: %d", *keyCode);
             *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_STANDARD;
             return;
         }
@@ -467,6 +498,7 @@
         // key is a digit
         offset = ch - '0';
         // make sure in range for decimal digits
+        //NSLog(@"This is a decimal digit");
         if (offset >= 0 && offset <= 9)    {
             jboolean numpad = (flags & NSNumericPadKeyMask) != 0;
             *postsTyped = YES;
@@ -481,17 +513,34 @@
         }
     }
 
-    if (key < size) {
-        *postsTyped = keyTable[key].postsTyped;
-        *keyCode = keyTable[key].javaKeyCode;
-        *keyLocation = keyTable[key].javaKeyLocation;
-    } else {
-        // Should we report this? This means we've got a keyboard
-        // we don't know about...
-        *postsTyped = NO;
-        *keyCode = java_awt_event_KeyEvent_VK_UNDEFINED;
-        *keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;
+    NSDictionary* unicharToVkCodeDictionary = getUnicharToVkCodeDictionary();
+    if ([[NSCharacterSet punctuationCharacterSet] characterIsMember:ch] ||
+         [[NSCharacterSet symbolCharacterSet] characterIsMember:ch])
+    {
+         //NSLog(@"This is a punctuation char");
+         *keyCode = [[unicharToVkCodeDictionary objectForKey:[NSString stringWithFormat:@"%C",ch]] intValue];
+         //NSLog(@"key code %d for char %@", *keyCode,[NSString stringWithFormat:@"%C",ch]);
+         // we cannot find key location from a char, so let's use key code
+         *postsTyped = YES;
+         *keyLocation = keyTable[key].javaKeyLocation;
+         return;
     }
+
+    NSDictionary* diacriticUnicharToVkCodeDictionary = getDiacriticUnicharToVkCodeDictionary();
+    NSNumber * jkc = [diacriticUnicharToVkCodeDictionary objectForKey:[NSString stringWithFormat:@"%C",ch]];
+    if (jkc != nil) {
+        //NSLog(@"This is a Diacritic Unichar");
+        *keyCode = [jkc intValue];
+        // we cannot find key location from a char, so let's use key code
+        *postsTyped = YES;
+        *keyLocation = keyTable[key].javaKeyLocation;
+        return;
+    }
+
+    *postsTyped = keyTable[key].postsTyped;
+    *keyCode = keyTable[key].javaKeyCode;
+    *keyLocation = keyTable[key].javaKeyLocation;
+
 }
 
 /*
@@ -758,19 +807,21 @@
 /*
  * Class:     sun_lwawt_macosx_NSEvent
  * Method:    nsToJavaChar
- * Signature: (CI)C
+ * Signature: (CI)Ljava/lang/String
  */
-JNIEXPORT jint JNICALL
+JNIEXPORT jstring JNICALL
 Java_sun_lwawt_macosx_NSEvent_nsToJavaChar
 (JNIEnv *env, jclass cls, jchar nsChar, jint modifierFlags)
 {
-    jchar javaChar = 0;
+    jstring charAsString = NULL;
 
 JNF_COCOA_ENTER(env);
 
-    javaChar = NsCharToJavaChar(nsChar, modifierFlags);
+    NSString * nsStr = [NSString stringWithFormat: @"%C", nsChar];
+    charAsString = JNFNSToJavaString(env,  nsStr);
+
 
 JNF_COCOA_EXIT(env);
 
-    return javaChar;
+    return charAsString;
 }
diff --git a/src/macosx/native/sun/awt/AWTView.m b/src/macosx/native/sun/awt/AWTView.m
index 0808580..f5aad8c 100644
--- a/src/macosx/native/sun/awt/AWTView.m
+++ b/src/macosx/native/sun/awt/AWTView.m
@@ -28,6 +28,7 @@
 #import <JavaNativeFoundation/JavaNativeFoundation.h>
 #import <JavaRuntimeSupport/JavaRuntimeSupport.h>
 
+
 #import "ThreadUtilities.h"
 #import "AWTView.h"
 #import "AWTEvent.h"
@@ -39,6 +40,7 @@
 #import "GeomUtilities.h"
 #import "OSVersion.h"
 #import "CGLLayer.h"
+#import "java_awt_event_KeyEvent.h"
 
 @interface AWTView()
 @property (retain) CDropTarget *_dropTarget;
@@ -281,6 +283,10 @@
     fProcessingKeystroke = YES;
     fKeyEventsNeeded = YES;
 
+    if ([event keyCode] == 24 && (([event modifierFlags] & (NSControlKeyMask | NSCommandKeyMask)) != 0)) {
+        return;
+    }
+
     // Allow TSM to look at the event and potentially send back NSTextInputClient messages.
     [self interpretKeyEvents:[NSArray arrayWithObject:event]];
 
@@ -308,29 +314,71 @@
 }
 
 - (void) flagsChanged: (NSEvent *)event {
-    [self deliverJavaKeyEventHelper: event];
+    if (/*([event keyCode] == 65535) && */[event modifierFlags] == 2148532232 || [event modifierFlags] == 2147483648
+	|| [event modifierFlags] == 2147614722 || [event modifierFlags] == 2147483648) {
+	return;
+    }
+
+    NSEvent* newEvent = event;
+
+    unsigned short newKeyCode = 0;
+
+    if( NSAlphaShiftKeyMask & [NSEvent modifierFlags] ){
+	newKeyCode = 0x39;
+    }
+
+    if( NSShiftKeyMask & [NSEvent modifierFlags] ){
+	newKeyCode = 0x38;
+    }
+
+    if( NSControlKeyMask & [NSEvent modifierFlags] ){
+	newKeyCode = 0x3B;
+    }
+
+   // if( NSAlternateKeyMask & [NSEvent modifierFlags] ){
+//
+  //  }
+
+
+    if( NSCommandKeyMask & [NSEvent modifierFlags] ){
+	newKeyCode = 0x37;
+    }
+//    if( NSNumericPadKeyMask & [NSEvent modifierFlags] ){
+//	newKeyCode =
+//    }
+
+//    if( NSHelpKeyMask & [NSEvent modifierFlags] ){
+//	newKeyCode =
+//    }
+
+//    if( NSFunctionKeyMask & [NSEvent modifierFlags] ){
+//	newKeyCode =
+//    }
+
+    if (newKeyCode != 0) {
+      newEvent = [NSEvent keyEventWithType:NSFlagsChanged location:event.locationInWindow modifierFlags:event.modifierFlags timestamp:event.timestamp windowNumber:event.windowNumber context:event.context characters:@"" charactersIgnoringModifiers:@"" isARepeat:NO keyCode:newKeyCode];
+    }
+
+    [self deliverJavaKeyEventHelper: newEvent];
 }
 
 - (BOOL) performKeyEquivalent: (NSEvent *) event {
-    // if IM is active key events should be ignored 
-    if (![self hasMarkedText] && !fInPressAndHold) {
-        [self deliverJavaKeyEventHelper: event];
+
+    if ([event keyCode] == 0) return NO;
+
+    if ([event keyCode] == 24 && [[event characters] isEqual:@"+"]) {
+        return 0;
     }
 
-    // Workaround for 8020209: special case for "Cmd =" and "Cmd ." 
-    // because Cocoa calls performKeyEquivalent twice for these keystrokes  
-    NSUInteger modFlags = [event modifierFlags] & 
-        (NSCommandKeyMask | NSAlternateKeyMask | NSShiftKeyMask | NSControlKeyMask);
-    if (modFlags == NSCommandKeyMask) {
-        NSString *eventChars = [event charactersIgnoringModifiers];
-        if ([eventChars length] == 1) {
-            unichar ch = [eventChars characterAtIndex:0];
-            if (ch == '=' || ch == '.') {
-                [[NSApp mainMenu] performKeyEquivalent: event];
-                return YES;
-            }
-        }
+    if ([AWTToolkit latestPerformKeyEquivalentEvent] != NULL) {
+        [[AWTToolkit latestPerformKeyEquivalentEvent] release];
+    }
+    AWTToolkit.latestPerformKeyEquivalentEvent = event;
+    [event retain];
 
+    // if IM is active key events should be ignored
+    if (![self hasMarkedText] && !fInPressAndHold) {
+        [self deliverJavaKeyEventHelper: event];
     }
 
     return NO;
@@ -402,13 +450,37 @@
         return;
     }
 
-    static JNF_CLASS_CACHE(jc_PlatformView, "sun/lwawt/macosx/CPlatformView");
-    static JNF_MEMBER_CACHE(jm_deliverMouseEvent, jc_PlatformView, "deliverMouseEvent", "(Lsun/lwawt/macosx/NSEvent;)V");
+    AWTWindow *awtWindow = (AWTWindow*)[event window];
 
-    jobject jlocal = (*env)->NewLocalRef(env, m_cPlatformView);
-    if (!(*env)->IsSameObject(env, jlocal, NULL)) {
-        JNFCallVoidMethod(env, jlocal, jm_deliverMouseEvent, jEvent);
-        (*env)->DeleteLocalRef(env, jlocal);
+    if (![AWTWindow isAWTWindow: awtWindow]) {
+        NSLog(@"awt Window is not an AWTWindow instance");
+        return;
+    }
+
+    AWTWindow* aDelegate = (AWTWindow*)[awtWindow delegate];
+
+    jobject platformWindow = [aDelegate.javaPlatformWindow jObjectWithEnv:env];
+
+    if (platformWindow == nil) {
+        NSLog(@"Platform window is nil");
+        return;
+    }
+
+    static JNF_CLASS_CACHE(jc_PlatformWindow, "sun/lwawt/macosx/CPlatformWindow");
+
+    if (!JNFIsInstanceOf(env, platformWindow, &jc_PlatformWindow)) {
+        NSLog(@"Platform window is not an instance of CPlatformWindow");
+    }
+
+    static JNF_CLASS_CACHE(jc_PlatformView, "sun/lwawt/macosx/CPlatformView");
+    static JNF_MEMBER_CACHE(jm_deliverMouseEvent, jc_PlatformView, "deliverMouseEvent", "(Lsun/lwawt/macosx/NSEvent;Lsun/lwawt/macosx/CPlatformWindow;)V");
+
+    jobject platformViewLocalRef = (*env)->NewLocalRef(env, m_cPlatformView);
+    if (!(*env)->IsSameObject(env, platformViewLocalRef, NULL)) {
+        JNFCallVoidMethod(env, platformViewLocalRef, jm_deliverMouseEvent, jEvent, platformWindow);
+        (*env)->DeleteLocalRef(env, platformViewLocalRef);
+    } else {
+        NSLog(@"m_cPlatformView is null");
     }
 }
 
@@ -445,27 +517,143 @@
         // The event is repeatedly delivered by keyDown: after performKeyEquivalent:
         return;
     }
+
     [sLastKeyEvent release];
     sLastKeyEvent = [event retain];
 
     [AWTToolkit eventCountPlusPlus];
     JNIEnv *env = [ThreadUtilities getJNIEnv];
 
+    TISInputSourceRef sourceRef = TISCopyCurrentKeyboardLayoutInputSource();
+    CFDataRef keyLayoutPtr = (CFDataRef)TISGetInputSourceProperty(
+    sourceRef, kTISPropertyUnicodeKeyLayoutData);
+    CFRelease( sourceRef);
+
+    const UCKeyboardLayout *keyboardLayout =  (UCKeyboardLayout*)CFDataGetBytePtr(keyLayoutPtr);
+
+    UInt32 isDeadKeyPressed;
+    UInt32 lengthOfBuffer = 4;
+    UniChar stringWithChars[lengthOfBuffer];
+    UniCharCount actualLength;
+
+    OSStatus status =  UCKeyTranslate(
+                   keyboardLayout,
+                   [event keyCode],
+                   kUCKeyActionDown,
+                   0,
+                   LMGetKbdType(),
+                   0,
+                   // ignore for now
+                   &isDeadKeyPressed,
+                   lengthOfBuffer,
+                   &actualLength,
+                   stringWithChars);
+
+    NSString*  charactersIgnoringModifiersAndShiftAsNsString = [NSString stringWithCharacters:stringWithChars length:actualLength];
+
     jstring characters = NULL;
     jstring charactersIgnoringModifiers = NULL;
+    jstring charactersIgnoringModifiersAndShift = NULL;
+
     if ([event type] != NSFlagsChanged) {
         characters = JNFNSToJavaString(env, [event characters]);
         charactersIgnoringModifiers = JNFNSToJavaString(env, [event charactersIgnoringModifiers]);
+        charactersIgnoringModifiersAndShift = JNFNSToJavaString(env, charactersIgnoringModifiersAndShiftAsNsString);
+    }
+
+    jint javaDeadKeyCode = 0;
+
+    if (status == noErr && isDeadKeyPressed != 0) {
+
+        if (event.type != 11 /*NSEventTypeKeyUp*/) {
+            // We send only key release for dead keys
+            return;
+        }
+
+        status = UCKeyTranslate(
+                    keyboardLayout,
+                    kVK_Space,
+                    kUCKeyActionDown,
+                    0,
+                    LMGetKbdType(),
+                    0,
+                    &isDeadKeyPressed,
+                    lengthOfBuffer,
+                    &actualLength,
+                    stringWithChars);
+
+        charactersIgnoringModifiersAndShift = JNFNSToJavaString(env, [NSString stringWithCharacters:stringWithChars length:actualLength]);
+
+        switch ([event keyCode]) {
+            case 0x0060:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_GRAVE;
+               break;
+            case 0x00B4:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_ACUTE;
+               break;
+            case 0x0384:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_ACUTE;
+               break;
+            case 0x005E:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_CIRCUMFLEX;
+               break;
+            case 0x007E:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_TILDE;
+               break;
+            case 0x02DC:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_TILDE;
+               break;
+            case 0x00AF:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_MACRON;
+               break;
+            case 0x02D8:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_BREVE;
+               break;
+            case 0x02D9:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_ABOVEDOT;
+               break;
+            case 0x00A8:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_DIAERESIS;
+               break;
+            case 0x02DA:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_ABOVERING;
+               break;
+            case 0x02DD:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_DOUBLEACUTE;
+               break;
+            case 0x02C7:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_CARON;
+               break;
+            case 0x00B8:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_CEDILLA;
+               break;
+            case 0x02DB:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_OGONEK;
+               break;
+            case 0x037A:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_IOTA;
+               break;
+            case 0x309B:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_VOICED_SOUND;
+               break;
+            case 0x309C:
+               javaDeadKeyCode = java_awt_event_KeyEvent_VK_DEAD_SEMIVOICED_SOUND;
+                break;
+        }
     }
 
     static JNF_CLASS_CACHE(jc_NSEvent, "sun/lwawt/macosx/NSEvent");
-    static JNF_CTOR_CACHE(jctor_NSEvent, jc_NSEvent, "(IISLjava/lang/String;Ljava/lang/String;)V");
+    static JNF_CTOR_CACHE(jctor_NSEvent, jc_NSEvent, "(IISLjava/lang/String;Ljava/lang/String;Ljava/lang/String;ZI)V");
     jobject jevent = JNFNewObject(env, jctor_NSEvent,
                                   [event type],
                                   [event modifierFlags],
                                   [event keyCode],
                                   characters,
-                                  charactersIgnoringModifiers);
+                                  charactersIgnoringModifiers,
+                                  charactersIgnoringModifiersAndShift,
+                                  isDeadKeyPressed,
+                                  javaDeadKeyCode
+                                  );
 
     static JNF_CLASS_CACHE(jc_PlatformView, "sun/lwawt/macosx/CPlatformView");
     static JNF_MEMBER_CACHE(jm_deliverKeyEvent, jc_PlatformView,
diff --git a/src/macosx/native/sun/awt/AWTWindow.m b/src/macosx/native/sun/awt/AWTWindow.m
index 9f6de82..d2689e5 100644
--- a/src/macosx/native/sun/awt/AWTWindow.m
+++ b/src/macosx/native/sun/awt/AWTWindow.m
@@ -165,6 +165,18 @@
                     b:[event deltaY]];
 }
 
+- (void)pressureChangeWithEvent:(NSEvent *)event {
+
+    float pressure = event.pressure;
+
+    [self postGesture:event
+                       as:com_apple_eawt_event_GestureHandler_PRESSURE
+                        a:pressure
+                        b:(([event respondsToSelector:@selector(stage)]) ? ((NSInteger)[event stage]) : -1)
+    ];
+
+}
+
 @end
 @implementation AWTWindow_Panel
 AWT_NS_WINDOW_IMPLEMENTATION
@@ -466,7 +478,7 @@
 // Tests whether window is blocked by modal dialog/window
 - (BOOL) isBlocked {
     BOOL isBlocked = NO;
-    
+
     JNIEnv *env = [ThreadUtilities getJNIEnv];
     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
     if (platformWindow != NULL) {
@@ -474,7 +486,7 @@
         isBlocked = JNFCallBooleanMethod(env, platformWindow, jm_isBlocked) == JNI_TRUE ? YES : NO;
         (*env)->DeleteLocalRef(env, platformWindow);
     }
-    
+
     return isBlocked;
 }
 
@@ -883,7 +895,8 @@
                 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
                 if (platformWindow != NULL) {
                     // Currently, no need to deliver the whole NSEvent.
-                    static JNF_MEMBER_CACHE(jm_deliverNCMouseDown, jc_CPlatformWindow, "deliverNCMouseDown", "()V");
+                    static JNF_MEMBER_CACHE(jm_deliverNCMouseDown, jc_CPlatformWindow,
+                    "deliverNCMouseDown", "()V");
                     JNFCallVoidMethod(env, platformWindow, jm_deliverNCMouseDown);
                     (*env)->DeleteLocalRef(env, platformWindow);
                 }
@@ -929,11 +942,6 @@
     if (IS(self.styleBits, ZOOMABLE)) {
         [[self.nsWindow standardWindowButton:NSWindowZoomButton] setEnabled: flag];
     }
-
-    if (IS(self.styleBits, RESIZABLE)) {
-        [self updateMinMaxSize:flag];
-        [self.nsWindow setShowsResizeIndicator:flag];
-    }
 }
 
 + (void) setLastKeyWindow:(AWTWindow *)window {
@@ -1370,7 +1378,7 @@
     } else {
         [JNFException raise:env as:kIllegalArgumentException reason:"unknown event type"];
     }
-    
+
 JNF_COCOA_EXIT(env);
 }
 
diff --git a/src/macosx/native/sun/awt/ApplicationDelegate.m b/src/macosx/native/sun/awt/ApplicationDelegate.m
index 8195575..f4b7c2a 100644
--- a/src/macosx/native/sun/awt/ApplicationDelegate.m
+++ b/src/macosx/native/sun/awt/ApplicationDelegate.m
@@ -464,42 +464,16 @@
         return;
     }
 
-    // setup an image view for the dock tile
-    NSRect frame = NSMakeRect(0, 0, dockTile.size.width, dockTile.size.height);
-    NSImageView *dockImageView = [[NSImageView alloc] initWithFrame: frame];
-    [dockImageView setImageScaling:NSImageScaleProportionallyUpOrDown];
-    [dockImageView setImage:image];
-
-    // add it to the NSDockTile
-    [dockTile setContentView: dockImageView];
-    [dockTile display];
-
-    [dockImageView release];
+    // Set the app's icon instead to meet Retina.
+    [NSApp setApplicationIconImage:image];
 }
 
 // Obtains the image of the Dock icon, either manually set, a drawn copy, or the default NSApplicationIcon
 + (NSImage *)_dockIconImage {
 AWT_ASSERT_APPKIT_THREAD;
 
-    NSDockTile *dockTile = [NSApp dockTile];
-    NSView *view = [dockTile contentView];
-
-    if ([view isKindOfClass:[NSImageView class]]) {
-        NSImage *img = [((NSImageView *)view) image];
-        if (img) return img;
-    }
-
-    if (view == nil) {
-        return [NSImage imageNamed:@"NSApplicationIcon"];
-    }
-
-    NSRect frame = [view frame];
-    NSImage *image = [[NSImage alloc] initWithSize:frame.size];
-    [image lockFocus];
-    [view drawRect:frame];
-    [image unlockFocus];
-    [image autorelease];
-    return image;
+    // The app's dock icon defaults to the app's icon (see the spec) which is Retina-aware unlike the dock icon.
+    return [NSApp applicationIconImage];
 }
 
 @end
diff --git a/src/macosx/native/sun/awt/CFileDialog.h b/src/macosx/native/sun/awt/CFileDialog.h
index ba43511..1843c41 100644
--- a/src/macosx/native/sun/awt/CFileDialog.h
+++ b/src/macosx/native/sun/awt/CFileDialog.h
@@ -27,6 +27,8 @@
 #import <JavaNativeFoundation/JavaNativeFoundation.h>
 
 @interface CFileDialog : NSObject <NSOpenSavePanelDelegate> {
+    NSWindow* fOwner;
+
     // Should we query back to Java for a file filter?
     jboolean fHasFileFilter;
 
@@ -60,7 +62,8 @@
 }
 
 // Allocator
-- (id) initWithFilter:(jboolean)inHasFilter
+- (id) initWithOwner:(NSWindow*) owner
+           filter:(jboolean)inHasFilter
            fileDialog:(jobject)inDialog
                 title:(NSString *)inTitle
             directory:(NSString *)inPath
diff --git a/src/macosx/native/sun/awt/CFileDialog.m b/src/macosx/native/sun/awt/CFileDialog.m
index 7dc8202..93a94c6 100644
--- a/src/macosx/native/sun/awt/CFileDialog.m
+++ b/src/macosx/native/sun/awt/CFileDialog.m
@@ -28,14 +28,17 @@
 #import <JavaNativeFoundation/JavaNativeFoundation.h>
 
 #import "CFileDialog.h"
+#import "AWTWindow.h"
 #import "ThreadUtilities.h"
+#import "ApplicationDelegate.h"
 
 #import "java_awt_FileDialog.h"
 #import "sun_lwawt_macosx_CFileDialog.h"
 
 @implementation CFileDialog
 
-- (id)initWithFilter:(jboolean)inHasFilter
+- (id)initWithOwner:(NSWindow*)owner
+              filter:(jboolean)inHasFilter
           fileDialog:(jobject)inDialog
                title:(NSString *)inTitle
            directory:(NSString *)inPath
@@ -47,6 +50,8 @@
              withEnv:(JNIEnv*)env;
 {
     if (self == [super init]) {
+        fOwner = owner;
+        [fOwner retain];
         fHasFileFilter = inHasFilter;
         fFileDialog = JNFNewGlobalRef(env, inDialog);
         fDirectory = inPath;
@@ -86,6 +91,9 @@
     [fURLs release];
     fURLs = nil;
 
+    [fOwner release];
+    fOwner = nil;
+
     [super dealloc];
 }
 //- (void)finalize { [super finalize]; }
@@ -117,25 +125,86 @@
 
         if (fMode == java_awt_FileDialog_LOAD) {
             NSOpenPanel *openPanel = (NSOpenPanel *)thePanel;
+            [openPanel setResolvesAliases:NO];
             [openPanel setAllowsMultipleSelection:fMultipleMode];
-            [openPanel setCanChooseFiles:!fChooseDirectories];
-            [openPanel setCanChooseDirectories:fChooseDirectories];
+            [openPanel setCanChooseFiles:YES];
+            [openPanel setCanChooseDirectories:YES];
             [openPanel setCanCreateDirectories:YES];
         }
 
         [thePanel setDelegate:self];
-        fPanelResult = [thePanel runModalForDirectory:fDirectory file:fFile];
-        [thePanel setDelegate:nil];
 
-        if ([self userClickedOK]) {
-            if (fMode == java_awt_FileDialog_LOAD) {
-                NSOpenPanel *openPanel = (NSOpenPanel *)thePanel;
-                fURLs = [openPanel URLs];
-            } else {
-                fURLs = [NSArray arrayWithObject:[thePanel URL]];
+        if (fOwner != nil) {
+
+            //[thePanel setLevel:CGShieldingWindowLevel()];
+
+            if (fDirectory != nil) {
+                 [thePanel setDirectoryURL:[NSURL fileURLWithPath:[fDirectory stringByExpandingTildeInPath]]];
             }
-            [fURLs retain];
+
+            if (fFile != nil) {
+                 [thePanel setNameFieldStringValue:fFile];
+            }
+
+            if (fOwner != nil) {
+
+                // Finds appropriate menubar in our hierarchy,
+                AWTWindow *awtWindow = (AWTWindow *)fOwner.delegate;
+                while (awtWindow.ownerWindow != nil) {
+                    awtWindow = awtWindow.ownerWindow;
+                }
+
+                CMenuBar *menuBar = nil;
+                BOOL isDisabled = NO;
+                if ([awtWindow.nsWindow isVisible]){
+                    menuBar = awtWindow.javaMenuBar;
+                    isDisabled = !awtWindow.isEnabled;
+                }
+
+                if (menuBar == nil) {
+                    menuBar = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
+                    isDisabled = NO;
+                }
+
+                [CMenuBar activate:menuBar modallyDisabled:isDisabled];
+            }
+
+            [thePanel beginSheetModalForWindow:fOwner completionHandler:^(NSInteger result) {
+
+                if (result == NSFileHandlingPanelOKButton) {
+                    NSOpenPanel *openPanel = (NSOpenPanel *)thePanel;
+                    fURLs = (fMode == java_awt_FileDialog_LOAD)
+                         ? [openPanel URLs]
+                         : [NSArray arrayWithObject:[openPanel URL]];
+
+                    fPanelResult = NSFileHandlingPanelOKButton;
+
+                    } else {
+                        fURLs = [NSArray array];
+                    }
+                    [fURLs retain];
+                    [NSApp stopModal];
+                }
+            ];
+
+            [NSApp runModalForWindow:thePanel];
         }
+        else
+        {
+            fPanelResult = [thePanel runModalForDirectory:fDirectory file:fFile];
+
+            if ([self userClickedOK]) {
+                if (fMode == java_awt_FileDialog_LOAD) {
+                    NSOpenPanel *openPanel = (NSOpenPanel *)thePanel;
+                    fURLs = [openPanel URLs];
+                } else {
+                    fURLs = [NSArray arrayWithObject:[thePanel URL]];
+                }
+                [fURLs retain];
+            }
+        }
+
+        [thePanel setDelegate:nil];
     }
 
     [self disposer];
@@ -175,7 +244,7 @@
 }
 
 - (BOOL) userClickedOK {
-    return fPanelResult == NSOKButton;
+    return fPanelResult == NSFileHandlingPanelOKButton;
 }
 
 - (NSArray *)URLs {
@@ -191,7 +260,7 @@
  */
 JNIEXPORT jobjectArray JNICALL
 Java_sun_lwawt_macosx_CFileDialog_nativeRunFileDialog
-(JNIEnv *env, jobject peer, jstring title, jint mode, jboolean multipleMode,
+(JNIEnv *env, jobject peer, jlong ownerPtr, jstring title, jint mode, jboolean multipleMode,
  jboolean navigateApps, jboolean chooseDirectories, jboolean hasFilter,
  jstring directory, jstring file)
 {
@@ -203,7 +272,8 @@
         dialogTitle = @" ";
     }
 
-    CFileDialog *dialogDelegate = [[CFileDialog alloc] initWithFilter:hasFilter
+    CFileDialog *dialogDelegate = [[CFileDialog alloc] initWithOwner:(NSWindow *)jlong_to_ptr(ownerPtr)
+                                                               filter:hasFilter
                                                            fileDialog:peer
                                                                 title:dialogTitle
                                                             directory:JNFJavaToNSString(env, directory)
diff --git a/src/macosx/native/sun/awt/CGraphicsDevice.m b/src/macosx/native/sun/awt/CGraphicsDevice.m
index c04a6a3..8d315ed 100644
--- a/src/macosx/native/sun/awt/CGraphicsDevice.m
+++ b/src/macosx/native/sun/awt/CGraphicsDevice.m
@@ -328,7 +328,7 @@
 Java_sun_awt_CGraphicsDevice_nativeGetScaleFactor
 (JNIEnv *env, jclass class, jint displayID)
 {
-    __block jdouble ret = 1.0f;
+    __block jdouble ret = 2.0f;
 
 JNF_COCOA_ENTER(env);
 
diff --git a/src/macosx/native/sun/awt/CMenuItem.m b/src/macosx/native/sun/awt/CMenuItem.m
index 219cc5b..bf98677 100644
--- a/src/macosx/native/sun/awt/CMenuItem.m
+++ b/src/macosx/native/sun/awt/CMenuItem.m
@@ -70,37 +70,13 @@
     JNIEnv *env = [ThreadUtilities getJNIEnv];
 JNF_COCOA_ENTER(env);
 
-    // If we are called as a result of user pressing a shortcut, do nothing,
-    // because AVTView has already sent corresponding key event to the Java
-    // layer from performKeyEquivalent.
-    // There is an exception from the rule above, though: if a window with
-    // a menu gets minimized by user and there are no other windows to take
-    // focus, the window's menu won't be removed from the global menu bar.
-    // However, the Java layer won't handle invocation by a shortcut coming
-    // from this "frameless" menu, because there are no active windows. This
-    // means we have to handle it here.
     NSEvent *currEvent = [[NSApplication sharedApplication] currentEvent];
-    if ([currEvent type] == NSKeyDown) {
-        NSString *menuKey = [sender keyEquivalent];
-        NSString *eventKey = [currEvent charactersIgnoringModifiers];
 
-        // Apple uses characters from private Unicode range for some of the
-        // keys, so we need to do the same translation here that we do
-        // for the regular key down events
-        if ([eventKey length] == 1) {
-            unichar origChar = [eventKey characterAtIndex:0];
-            unichar newChar =  NsCharToJavaChar(origChar, 0);
-            if (newChar == java_awt_event_KeyEvent_CHAR_UNDEFINED) {
-                newChar = origChar;
-            }
-
-            eventKey = [NSString stringWithCharacters: &newChar length: 1];
-        }
-
-        NSWindow *keyWindow = [NSApp keyWindow];
-        if ([menuKey isEqualToString:eventKey] && keyWindow != nil) {
-            return;
-        }
+    NSEvent* latestPerformKeyEquivalentEvent = [AWTToolkit latestPerformKeyEquivalentEvent];
+    if (latestPerformKeyEquivalentEvent != NULL && [currEvent isEqual:latestPerformKeyEquivalentEvent]) {
+        [latestPerformKeyEquivalentEvent release];
+        [AWTToolkit setLatestPerformKeyEquivalentEvent:NULL];
+        return;
     }
 
     if (fIsCheckbox) {
diff --git a/src/macosx/native/sun/awt/CTrayIcon.m b/src/macosx/native/sun/awt/CTrayIcon.m
index b3967df..600379f 100644
--- a/src/macosx/native/sun/awt/CTrayIcon.m
+++ b/src/macosx/native/sun/awt/CTrayIcon.m
@@ -30,6 +30,7 @@
 #import "ThreadUtilities.h"
 #include "GeomUtilities.h"
 #import "LWCToolkit.h"
+#import "AWTWindow.h"
 
 #define kImageInset 4.0
 
diff --git a/src/macosx/native/sun/awt/JavaComponentAccessibility.m b/src/macosx/native/sun/awt/JavaComponentAccessibility.m
index 4b40590..6bfbcc8 100644
--- a/src/macosx/native/sun/awt/JavaComponentAccessibility.m
+++ b/src/macosx/native/sun/awt/JavaComponentAccessibility.m
@@ -341,8 +341,8 @@
     jobject jcomponent = [(AWTView *)view awtComponent:env];
     jint index = JNFCallStaticIntMethod(env, sjm_getAccessibleIndexInParent, jaccessible, jcomponent);
     if (index >= 0) {
-      NSString *javaRole = getJavaRole(env, jaccessible, jcomponent);
-      ret = [self createWithAccessible:jaccessible role:javaRole index:index withEnv:env withView:view];
+        NSString *javaRole = getJavaRole(env, jaccessible, jcomponent);
+        ret = [self createWithAccessible:jaccessible role:javaRole index:index withEnv:env withView:view];
     }
     (*env)->DeleteLocalRef(env, jcomponent);
     return ret;
@@ -1032,7 +1032,7 @@
                                     sjc_CAccessibility,
                                     "requestSelection",
                                     "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)V" );
-    
+
     if ([(NSNumber*)value boolValue]) {
         JNIEnv* env = [ThreadUtilities getJNIEnv];
         JNFCallStaticVoidMethod(env, jm_requestSelection, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
diff --git a/src/macosx/native/sun/awt/LWCToolkit.h b/src/macosx/native/sun/awt/LWCToolkit.h
index 0a57501..3c860e4 100644
--- a/src/macosx/native/sun/awt/LWCToolkit.h
+++ b/src/macosx/native/sun/awt/LWCToolkit.h
@@ -28,6 +28,7 @@
 
 #import <Cocoa/Cocoa.h>
 #import <JavaNativeFoundation/JavaNativeFoundation.h>
+#import <Carbon/Carbon.h>
 
 #define DEBUG 1
 
@@ -41,6 +42,8 @@
 + (long) getEventCount;
 + (void) eventCountPlusPlus;
 + (jint) scrollStateWithEvent: (NSEvent*) event;
++ (NSEvent*) latestPerformKeyEquivalentEvent;
++ (void) setLatestPerformKeyEquivalentEvent:(NSEvent *)val;
 @end
 
 /*
diff --git a/src/macosx/native/sun/awt/LWCToolkit.m b/src/macosx/native/sun/awt/LWCToolkit.m
index 8f0a290..de0c80e 100644
--- a/src/macosx/native/sun/awt/LWCToolkit.m
+++ b/src/macosx/native/sun/awt/LWCToolkit.m
@@ -43,7 +43,7 @@
 #define SCROLL_PHASE_UNSUPPORTED 1
 #define SCROLL_PHASE_BEGAN 2
 #define SCROLL_PHASE_CONTINUED 3
-#define SCROLL_PHASE_CANCELLED 4
+#define SCROLL_PHASE_MOMENTUM_BEGAN 4
 #define SCROLL_PHASE_ENDED 5
 
 int gNumberOfButtons;
@@ -51,6 +51,12 @@
 
 @implementation AWTToolkit
 
+static NSEvent* latestPerformKeyEquivalentEvent;
++ (NSEvent*) latestPerformKeyEquivalentEvent
+{ @synchronized(self) { return latestPerformKeyEquivalentEvent; } }
++ (void) setLatestPerformKeyEquivalentEvent:(NSEvent*) e
+{ @synchronized(self) { latestPerformKeyEquivalentEvent = e; } }
+
 static long eventCount;
 
 + (long) getEventCount{
@@ -66,17 +72,26 @@
     if ([event type] != NSScrollWheel) {
         return 0;
     }
-
-    NSEventPhase phase = [event phase];
-    NSEventPhase momentumPhase = [event momentumPhase];
-
-    if (!phase && !momentumPhase) return SCROLL_PHASE_UNSUPPORTED;
-    switch (phase) {
-        case NSEventPhaseBegan: return SCROLL_PHASE_BEGAN;
-        case NSEventPhaseCancelled: return SCROLL_PHASE_CANCELLED;
-        case NSEventPhaseEnded: return SCROLL_PHASE_ENDED;
+    if ([event phase]) {
+        // process a phase of manual scrolling
+        switch ([event phase]) {
+            case NSEventPhaseBegan: return SCROLL_PHASE_BEGAN;
+            case NSEventPhaseCancelled: return SCROLL_PHASE_ENDED;
+            case NSEventPhaseEnded: return SCROLL_PHASE_ENDED;
+            default: return SCROLL_PHASE_CONTINUED;
+        }
     }
-    return SCROLL_PHASE_CONTINUED;
+    if ([event momentumPhase]) {
+        // process a phase of automatic scrolling
+        switch ([event momentumPhase]) {
+            case NSEventPhaseBegan: return SCROLL_PHASE_MOMENTUM_BEGAN;
+            case NSEventPhaseCancelled: return SCROLL_PHASE_ENDED;
+            case NSEventPhaseEnded: return SCROLL_PHASE_ENDED;
+            default: return SCROLL_PHASE_CONTINUED;
+        }
+    }
+    // phase and momentum phase both are not set
+    return SCROLL_PHASE_UNSUPPORTED;
 }
 @end
 
@@ -420,6 +435,16 @@
     dlclose(hSplashLib);
 }
 
+/*
+ * Class:     sun_lwawt_macosx_LWCToolkit
+ * Method:    printNativeCallStack
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+JNICALL Java_sun_lwawt_macosx_LWCToolkit_printNativeCallStack(JNIEnv *env, jclass cls)
+{
+    NSLog(@"Cocoa AWT: %@", [NSThread callStackSymbols]);
+}
 
 // TODO: definitely doesn't belong here (copied from fontpath.c in the
 // solaris tree)...
diff --git a/src/macosx/native/sun/awt/OSVersion.h b/src/macosx/native/sun/awt/OSVersion.h
index 65d2f2c..94bc9bc 100644
--- a/src/macosx/native/sun/awt/OSVersion.h
+++ b/src/macosx/native/sun/awt/OSVersion.h
Binary files differ
diff --git a/src/macosx/native/sun/awt/OSVersion.m b/src/macosx/native/sun/awt/OSVersion.m
index d3eafbb..cd03ac0 100644
--- a/src/macosx/native/sun/awt/OSVersion.m
+++ b/src/macosx/native/sun/awt/OSVersion.m
Binary files differ
diff --git a/src/macosx/native/sun/font/AWTFont.h b/src/macosx/native/sun/font/AWTFont.h
index 0268099..a86f5c3 100644
--- a/src/macosx/native/sun/font/AWTFont.h
+++ b/src/macosx/native/sun/font/AWTFont.h
@@ -26,6 +26,8 @@
 #import <Cocoa/Cocoa.h>
 #import <JavaRuntimeSupport/JavaRuntimeSupport.h>
 
+#import "fontscalerdefs.h"
+
 #define MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE 256
 
 @interface AWTFont : NSObject {
@@ -33,6 +35,7 @@
     NSFont    *fFont;
     CGFontRef  fNativeCGFont;
     BOOL       fIsFakeItalic;
+    TTLayoutTableCache* layoutTableCache;
 }
 
 + (AWTFont *) awtFontForName:(NSString *)name
diff --git a/src/macosx/native/sun/font/AWTFont.m b/src/macosx/native/sun/font/AWTFont.m
index 6458f17..37b26d2 100644
--- a/src/macosx/native/sun/font/AWTFont.m
+++ b/src/macosx/native/sun/font/AWTFont.m
@@ -31,6 +31,7 @@
 #import "sun_font_CFont.h"
 #import "sun_font_CFontManager.h"
 
+#import "OSVersion.h"
 #import "AWTFont.h"
 #import "AWTStrike.h"
 #import "CoreTextSupport.h"
@@ -42,10 +43,33 @@
     if (self) {
         fFont = [font retain];
         fNativeCGFont = CTFontCopyGraphicsFont((CTFontRef)font, NULL);
+        layoutTableCache = NULL;
     }
     return self;
 }
 
+static TTLayoutTableCache* newCFontLayoutTableCache() {
+  TTLayoutTableCache* ltc = calloc(1, sizeof(TTLayoutTableCache));
+  if (ltc) {
+    int i;
+    for(i=0;i<LAYOUTCACHE_ENTRIES;i++) {
+      ltc->entries[i].len = -1;
+    }
+  }
+  return ltc;
+}
+
+static void freeCFontLayoutTableCache(TTLayoutTableCache* ltc) {
+  if (ltc) {
+    int i;
+    for(i=0;i<LAYOUTCACHE_ENTRIES;i++) {
+      if(ltc->entries[i].ptr) free (ltc->entries[i].ptr);
+    }
+    if (ltc->kernPairs) free(ltc->kernPairs);
+    free(ltc);
+  }
+}
+
 - (void) dealloc {
     [fFont release];
     fFont = nil;
@@ -53,6 +77,10 @@
     if (fNativeCGFont) {
         CGFontRelease(fNativeCGFont);
     fNativeCGFont = NULL;
+    if (layoutTableCache != NULL) {
+        freeCFontLayoutTableCache(layoutTableCache);
+        layoutTableCache = NULL;
+    }
     }
 
     [super dealloc];
@@ -63,6 +91,10 @@
         CGFontRelease(fNativeCGFont);
     fNativeCGFont = NULL;
     }
+    if (layoutTableCache != NULL) {
+        freeCFontLayoutTableCache(layoutTableCache);
+        layoutTableCache = NULL;
+    }
     [super finalize];
 }
 
@@ -162,7 +194,7 @@
     return [sFontFamilyTable objectForKey:fontname];
 }
 
-static void addFont(CTFontUIFontType uiType, 
+static void addFont(CTFontUIFontType uiType,
                     NSMutableArray *allFonts,
                     NSMutableDictionary* fontFamilyTable) {
 
@@ -199,7 +231,7 @@
         CFRelease(desc);
         CFRelease(font);
 }
- 
+
 static NSArray*
 GetFilteredFonts()
 {
@@ -233,6 +265,51 @@
                 }
             }
         }
+        if (isElCapitanOrGreater()) {
+            const NSArray *sanFranciscoFonts = [NSArray arrayWithObjects: @".SFNSDisplay-Regular",
+                                            @".SFNSDisplay-Black",
+                                            @".SFNSDisplay-Bold",
+                                            @".SFNSDisplay-Heavy",
+                                            @".SFNSDisplay-Light",
+                                            @".SFNSDisplay-Medium",
+                                            @".SFNSDisplay-Semibold",
+                                            @".SFNSDisplay-Thin",
+                                            @".SFNSDisplay-Ultralight",
+                                            @".SFNSText-Regular",
+                                            @".SFNSText-RegularG1",
+                                            @".SFNSText-RegularG2",
+                                            @".SFNSText-RegularG3",
+                                            @".SFNSText-RegularItalic",
+                                            @".SFNSText-RegularItalicG1",
+                                            @".SFNSText-RegularItalicG2",
+                                            @".SFNSText-RegularItalicG3",
+                                            @".SFNSText-Light",
+                                            @".SFNSText-LightItalic",
+                                            @".SFNSText-Medium",
+                                            @".SFNSText-MediumItalic",
+                                            @".SFNSText-Semibold",
+                                            @".SFNSText-SemiboldItalic",
+                                            @".SFNSText-Bold",
+                                            @".SFNSText-BoldG1",
+                                            @".SFNSText-BoldG2",
+                                            @".SFNSText-BoldG3",
+                                            @".SFNSText-BoldItalic",
+                                            @".SFNSText-BoldItalicG1",
+                                            @".SFNSText-BoldItalicG2",
+                                            @".SFNSText-BoldItalicG3",
+                                            @".SFNSText-Heavy",
+                                            @".SFNSText-HeavyItalic",
+                                            nil];
+
+            for (NSString *item in sanFranciscoFonts) {
+                NSFont* font = [NSFont fontWithName:item size:1.0];
+                if(font && font.familyName) {
+                    [allFonts addObject:item];
+                    [fontFamilyTable setObject:font.familyName forKey:item];
+                }
+            }
+        }
+
 
         /*
          * JavaFX registers these fonts and so JDK needs to do so as well.
@@ -391,6 +468,95 @@
 
 /*
  * Class:     sun_font_CFont
+ * Method:    getPlatformFontPtrNative
+ * Signature: (JI)[B
+ */
+JNIEXPORT jlong JNICALL
+Java_sun_font_CFont_getCGFontPtrNative
+    (JNIEnv *env, jclass clazz,
+     jlong awtFontPtr)
+{
+    AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
+    return (jlong)(awtFont->fNativeCGFont);
+}
+
+/*
+ * Class:     sun_font_CFont
+ * Method:    getLayoutTableCacheNative
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL
+Java_sun_font_CFont_getLayoutTableCacheNative
+    (JNIEnv *env, jclass clazz,
+     jlong awtFontPtr)
+{
+    AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
+    if (awtFont->layoutTableCache == NULL) {
+        awtFont->layoutTableCache = newCFontLayoutTableCache();
+    }
+    return (jlong)(awtFont->layoutTableCache);
+}
+
+/*
+ * Class:     sun_font_CFont
+ * Method:    getTableBytesNative
+ * Signature: (JI)[B
+ */
+JNIEXPORT jbyteArray JNICALL
+Java_sun_font_CFont_getTableBytesNative
+    (JNIEnv *env, jclass clazz,
+     jlong awtFontPtr, jint jtag)
+{
+    jbyteArray jbytes = NULL;
+JNF_COCOA_ENTER(env);
+
+    CTFontTableTag tag = (CTFontTableTag)jtag;
+    int i, found = 0;
+    AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
+    NSFont* nsFont = awtFont->fFont;
+    CTFontRef ctfont = (CTFontRef)nsFont;
+    CFArrayRef tagsArray =
+        CTFontCopyAvailableTables(ctfont, kCTFontTableOptionNoOptions);
+    CFIndex numTags = CFArrayGetCount(tagsArray);
+    for (i=0; i<numTags; i++) {
+        if (tag ==
+            (CTFontTableTag)(uintptr_t)CFArrayGetValueAtIndex(tagsArray, i)) {
+            found = 1;
+            break;
+        }
+    }
+    CFRelease(tagsArray);
+    if (!found) {
+        return NULL;
+    }
+    CFDataRef table = CTFontCopyTable(ctfont, tag, kCTFontTableOptionNoOptions);
+    if (table == NULL) {
+        return NULL;
+    }
+
+    char *tableBytes = (char*)(CFDataGetBytePtr(table));
+    size_t tableLength = CFDataGetLength(table);
+    if (tableBytes == NULL || tableLength == 0) {
+        CFRelease(table);
+        return NULL;
+    }
+
+    jbytes = (*env)->NewByteArray(env, (jsize)tableLength);
+    if (jbytes == NULL) {
+        return NULL;
+    }
+    (*env)->SetByteArrayRegion(env, jbytes, 0,
+                               (jsize)tableLength,
+                               (jbyte*)tableBytes);
+    CFRelease(table);
+
+JNF_COCOA_EXIT(env);
+
+    return jbytes;
+}
+
+/*
+ * Class:     sun_font_CFont
  * Method:    initNativeFont
  * Signature: (Ljava/lang/String;I)J
  */
diff --git a/src/macosx/native/sun/font/AWTStrike.m b/src/macosx/native/sun/font/AWTStrike.m
index e55a267..b58fe69 100644
--- a/src/macosx/native/sun/font/AWTStrike.m
+++ b/src/macosx/native/sun/font/AWTStrike.m
@@ -156,7 +156,19 @@
     // to indicate we should use CoreText to substitute the character
     CGGlyph glyph;
     const CTFontRef fallback = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtFont, glyphCode, &glyph);
-    CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &advance, 1);
+    const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
+    if (CGGI_IsColorFont(cgFallback)) {
+        CGAffineTransform matrix = awtStrike->fAltTx;
+        CGFloat fontSize = sqrt(fabs(matrix.a * matrix.d - matrix.b * matrix.c));
+        CTFontRef font = CTFontCreateWithGraphicsFont(cgFallback, fontSize, NULL, NULL);
+        CTFontGetAdvancesForGlyphs(font, kCTFontDefaultOrientation, &glyph, &advance, 1);
+        CFRelease(font);
+        advance.width /= fontSize;
+        advance.height /= fontSize;
+    } else {
+        CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &advance, 1);
+    }
+    CFRelease(cgFallback);
     CFRelease(fallback);
     advance = CGSizeApplyAffineTransform(advance, awtStrike->fFontTx);
     if (!JRSFontStyleUsesFractionalMetrics(awtStrike->fStyle)) {
diff --git a/src/macosx/native/sun/font/CCharToGlyphMapper.m b/src/macosx/native/sun/font/CCharToGlyphMapper.m
index 81fb69d..a36a213 100644
--- a/src/macosx/native/sun/font/CCharToGlyphMapper.m
+++ b/src/macosx/native/sun/font/CCharToGlyphMapper.m
@@ -27,6 +27,7 @@
 #import "CoreTextSupport.h"
 
 #import "sun_font_CCharToGlyphMapper.h"
+#import "sun_font_CCompositeGlyphMapper.h"
 
 /*
  * Class:     sun_font_CCharToGlyphMapper
@@ -111,3 +112,28 @@
 
 JNF_COCOA_EXIT(env);
 }
+
+/*
+ * Class:     sun_font_CCompositeGlyphMapper
+ * Method:    nativeCodePointToGlyph
+ * Signature: (JI[Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL
+Java_sun_font_CCompositeGlyphMapper_nativeCodePointToGlyph
+(JNIEnv *env, jclass clazz, jlong awtFontPtr, jint codePoint, jobjectArray resultArray)
+{
+JNF_COCOA_ENTER(env);
+    AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
+    CFStringRef fontNames[2];
+    CGGlyph glyph = CTS_CopyGlyphAndFontNamesForCodePoint(awtFont, (UnicodeScalarValue)codePoint, fontNames);
+    if (glyph > 0) {
+        jstring fontName = (jstring)JNFNSToJavaString(env, (NSString *)fontNames[0]);
+        if (fontNames[0]) CFRelease(fontNames[0]);
+        (*env)->SetObjectArrayElement(env, resultArray, 0, fontName);
+        jstring fontFamilyName = (jstring)JNFNSToJavaString(env, (NSString *)fontNames[1]);
+        if (fontNames[1]) CFRelease(fontNames[1]);
+        (*env)->SetObjectArrayElement(env, resultArray, 1, fontFamilyName);
+    }
+    return glyph;
+JNF_COCOA_EXIT(env);
+}
diff --git a/src/macosx/native/sun/font/CGGlyphImages.h b/src/macosx/native/sun/font/CGGlyphImages.h
index 73cb604..f457095 100644
--- a/src/macosx/native/sun/font/CGGlyphImages.h
+++ b/src/macosx/native/sun/font/CGGlyphImages.h
@@ -34,4 +34,6 @@
                                 const AWTStrike *strike,
                                 jint rawGlyphCodes[], const CFIndex len);
 
+bool CGGI_IsColorFont(CGFontRef font);
+
 #endif /* __CGGLYPHIMAGES_H */
diff --git a/src/macosx/native/sun/font/CGGlyphImages.m b/src/macosx/native/sun/font/CGGlyphImages.m
index c762fac..499661b 100644
--- a/src/macosx/native/sun/font/CGGlyphImages.m
+++ b/src/macosx/native/sun/font/CGGlyphImages.m
@@ -309,6 +309,39 @@
     }
 }
 
+static void
+CGGI_CopyImageFromCanvasToARGBInfo(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
+{
+    CGBitmapInfo bitmapInfo = CGBitmapContextGetBitmapInfo(canvas->context);
+    bool littleEndian = (bitmapInfo & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Little;
+    UInt32 *src = (UInt32 *)canvas->image->data;
+    size_t srcRowWidth = canvas->image->width;
+
+    UInt8 *dest = (UInt8 *)info->image;
+    size_t destRowWidth = info->width;
+
+    size_t height = info->height;
+
+    size_t y;
+
+    for (y = 0; y < height; y++) {
+        size_t srcRow = y * srcRowWidth;
+        if (littleEndian) {
+            UInt16 destRowBytes = info->rowBytes;
+            memcpy(dest, src + srcRow, destRowBytes);
+            dest += destRowBytes;
+        } else {
+            size_t x;
+            for (x = 0; x < destRowWidth; x++) {
+                UInt32 p = src[srcRow + x];
+                *dest++ = (p >> 24  & 0xFF); // blue  (alpha-premultiplied)
+                *dest++ = (p >> 16 & 0xFF); // green (alpha-premultiplied)
+                *dest++ = (p >> 8   & 0xFF); // red   (alpha-premultiplied)
+                *dest++ = (p & 0xFF); // alpha
+            }
+        }
+    }
+}
 
 #pragma mark --- Pixel Size, Modes, and Canvas Shaping Helper Functions ---
 
@@ -326,6 +359,25 @@
     { 1, &CGGI_CopyImageFromCanvasToAlphaInfo };
 static CGGI_GlyphInfoDescriptor rgb =
     { 3, &CGGI_CopyImageFromCanvasToRGBInfo };
+static CGGI_GlyphInfoDescriptor argb =
+    { 4, &CGGI_CopyImageFromCanvasToARGBInfo };
+
+static CFStringRef EMOJI_FONT_NAME = CFSTR("Apple Color Emoji");
+
+bool CGGI_IsColorFont(CGFontRef font)
+{
+    CFStringRef name = CGFontCopyFullName(font);
+    bool isFixedColor = CFStringCompare(name, EMOJI_FONT_NAME, 0) == kCFCompareEqualTo;
+    CFRelease(name);
+    return isFixedColor;
+}
+
+static inline CGGI_GlyphInfoDescriptor*
+CGGI_GetGlyphInfoDescriptor(const CGGI_RenderingMode *mode, CGFontRef font)
+{
+    bool isFixedColor = CGGI_IsColorFont(font);
+    return isFixedColor ? &argb : mode->glyphDescriptor;
+}
 
 static inline CGGI_RenderingMode
 CGGI_GetRenderingMode(const AWTStrike *strike)
@@ -459,11 +511,11 @@
 }
 
 /*
- * Clear the canvas by blitting white only into the region of interest
+ * Clear the canvas by blitting white (or transparent background for color glyphs) only into the region of interest
  * (the rect which we will copy out of once the glyph is struck).
  */
 static inline void
-CGGI_ClearCanvas(CGGI_GlyphCanvas *canvas, GlyphInfo *info)
+CGGI_ClearCanvas(CGGI_GlyphCanvas *canvas, GlyphInfo *info, bool transparent)
 {
     vImage_Buffer canvasRectToClear;
     canvasRectToClear.data = canvas->image->data;
@@ -474,18 +526,31 @@
 
     // clean the canvas
 #ifdef CGGI_DEBUG
-    Pixel_8888 opaqueWhite = { 0xE0, 0xE0, 0xE0, 0xE0 };
+    Pixel_8888 background = { 0xE0, 0xE0, 0xE0, 0xE0 };
 #else
-    Pixel_8888 opaqueWhite = { 0xFF, 0xFF, 0xFF, 0xFF };
+    Pixel_8888 background = { transparent ? 0 : 0xFF,
+                               transparent ? 0 : 0xFF,
+                               transparent ? 0 : 0xFF,
+                               transparent ? 0 : 0xFF };
 #endif
 
-    // clear canvas background and set foreground color
-    vImageBufferFill_ARGB8888(&canvasRectToClear, opaqueWhite, kvImageNoFlags);
+    // clear canvas background
+    vImageBufferFill_ARGB8888(&canvasRectToClear, background, kvImageNoFlags);
 }
 
 
 #pragma mark --- GlyphInfo Creation & Copy Functions ---
 
+static inline CGSize CGGI_ScaleAdvance(CGSize advance, const AWTStrike *strike) {
+    advance = CGSizeApplyAffineTransform(advance, strike->fFontTx);
+    if (!JRSFontStyleUsesFractionalMetrics(strike->fStyle)) {
+        advance.width = round(advance.width);
+        advance.height = round(advance.height);
+    }
+    advance = CGSizeApplyAffineTransform(advance, strike->fDevTx);
+    return advance;
+}
+
 /*
  * Creates a GlyphInfo with exactly the correct size image and measurements.
  */
@@ -493,9 +558,9 @@
 static inline GlyphInfo *
 CGGI_CreateNewGlyphInfoFrom(CGSize advance, CGRect bbox,
                             const AWTStrike *strike,
-                            const CGGI_RenderingMode *mode)
+                            const CGGI_GlyphInfoDescriptor *glyphDescriptor)
 {
-    size_t pixelSize = mode->glyphDescriptor->pixelSize;
+    size_t pixelSize = glyphDescriptor->pixelSize;
 
     // adjust the bounding box to be 1px bigger on each side than what
     // CGFont-whatever suggests - because it gives a bounding box that
@@ -515,12 +580,7 @@
         width = 1;
         height = 1;
     }
-    advance = CGSizeApplyAffineTransform(advance, strike->fFontTx);
-    if (!JRSFontStyleUsesFractionalMetrics(strike->fStyle)) {
-        advance.width = round(advance.width);
-        advance.height = round(advance.height);
-    }
-    advance = CGSizeApplyAffineTransform(advance, strike->fDevTx);
+    advance = CGGI_ScaleAdvance(advance, strike);
 
 #ifdef USE_IMAGE_ALIGNED_MEMORY
     // create separate memory
@@ -559,20 +619,52 @@
  */
 static inline void
 CGGI_CreateImageForGlyph
-    (CGGI_GlyphCanvas *canvas, const CGGlyph glyph,
-     GlyphInfo *info, const CGGI_RenderingMode *mode)
+    (CGFontRef cgFont, CGGI_GlyphCanvas *canvas, const CGGlyph glyph,
+     GlyphInfo *info, const CGGI_GlyphInfoDescriptor *glyphDescriptor, const AWTStrike *strike)
 {
     // clean the canvas
-    CGGI_ClearCanvas(canvas, info);
+    CGGI_ClearCanvas(canvas, info, glyphDescriptor == &argb);
 
     // strike the glyph in the upper right corner
-    CGContextShowGlyphsAtPoint(canvas->context,
-                               -info->topLeftX,
-                               canvas->image->height + info->topLeftY,
-                               &glyph, 1);
+    CGFloat x = -info->topLeftX;
+    CGFloat y = canvas->image->height + info->topLeftY;
+
+    if (glyphDescriptor == &argb) {
+        CGAffineTransform matrix = CGContextGetTextMatrix(canvas->context);
+        CGFloat fontSize = sqrt(fabs(matrix.a * matrix.d - matrix.b * matrix.c));
+        CTFontRef font = CTFontCreateWithGraphicsFont(cgFont, fontSize, NULL, NULL);
+
+        CGFloat normFactor = 1.0 / fontSize;
+        CGAffineTransform normMatrix = CGAffineTransformScale(matrix, normFactor, normFactor);
+        CGContextSetTextMatrix(canvas->context, normMatrix);
+
+        CGPoint userPoint = CGPointMake(x, y);
+        CGAffineTransform invNormMatrix = CGAffineTransformInvert(normMatrix);
+        CGPoint textPoint = CGPointApplyAffineTransform(userPoint, invNormMatrix);
+
+        CTFontDrawGlyphs(font, &glyph, &textPoint, 1, canvas->context);
+
+        // CTFontGetAdvancesForGlyphs returns rounded advance for emoji font, so it can be calculated only here
+        // where CTFont instance with actual size is available
+        CGSize advance;
+        CTFontGetAdvancesForGlyphs(font, kCTFontDefaultOrientation, &glyph, &advance, 1);
+        advance.width *= normFactor;
+        advance.height *= normFactor;
+        advance = CGGI_ScaleAdvance(advance, strike);
+        info->advanceX = advance.width;
+        info->advanceY = advance.height;
+
+        CFRelease(font);
+        // restore context's original state
+        CGContextSetTextMatrix(canvas->context, matrix);
+        CGContextSetFontSize(canvas->context, 1);
+    } else {
+        // old procedure is faster, so we use it by default
+        CGContextShowGlyphsAtPoint(canvas->context, x, y, &glyph, 1);
+    }
 
     // copy the glyph from the canvas into the info
-    (*mode->glyphDescriptor->copyFxnPtr)(canvas, info);
+    (*glyphDescriptor->copyFxnPtr)(canvas, info);
 }
 
 /*
@@ -581,7 +673,7 @@
 static inline GlyphInfo *
 CGGI_CreateImageForUnicode
     (CGGI_GlyphCanvas *canvas, const AWTStrike *strike,
-     const CGGI_RenderingMode *mode, const UniChar uniChar)
+     const CGGI_RenderingMode *mode, const UnicodeScalarValue uniChar)
 {
     // save the state of the world
     CGContextSaveGState(canvas->context);
@@ -610,8 +702,11 @@
     CGSize advance;
     CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &advance, 1);
 
+    const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
+    CGGI_GlyphInfoDescriptor *glyphDescriptor = CGGI_GetGlyphInfoDescriptor(mode, cgFallback);
+
     // create the Sun2D GlyphInfo we are going to strike into
-    GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode);
+    GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, glyphDescriptor);
 
     // fix the context size, just in case the substituted character is unexpectedly large
     CGGI_SizeCanvas(canvas, info->width, info->height, mode);
@@ -619,12 +714,11 @@
     // align the transform for the real CoreText strike
     CGContextSetTextMatrix(canvas->context, strike->fAltTx);
 
-    const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
     CGContextSetFont(canvas->context, cgFallback);
     CFRelease(cgFallback);
 
     // clean the canvas - align, strike, and copy the glyph from the canvas into the info
-    CGGI_CreateImageForGlyph(canvas, glyph, info, mode);
+    CGGI_CreateImageForGlyph(cgFallback, canvas, glyph, info, glyphDescriptor, strike);
 
     // restore the state of the world
     CGContextRestoreGState(canvas->context);
@@ -658,7 +752,7 @@
                                         const AWTStrike *strike,
                                         const CGGI_RenderingMode *mode,
                                         jlong glyphInfos[],
-                                        const UniChar uniChars[],
+                                        const UnicodeScalarValue uniChars[],
                                         const CGGlyph glyphs[],
                                         const CFIndex len)
 {
@@ -667,11 +761,14 @@
     CGContextSetFont(canvas->context, strike->fAWTFont->fNativeCGFont);
     JRSFontSetRenderingStyleOnContext(canvas->context, strike->fStyle);
 
+    CGGI_GlyphInfoDescriptor* mainFontDescriptor = CGGI_GetGlyphInfoDescriptor(mode, strike->fAWTFont->fNativeCGFont);
+
     CFIndex i;
     for (i = 0; i < len; i++) {
         GlyphInfo *info = (GlyphInfo *)jlong_to_ptr(glyphInfos[i]);
         if (info != NULL) {
-            CGGI_CreateImageForGlyph(canvas, glyphs[i], info, mode);
+            CGGI_CreateImageForGlyph(strike->fAWTFont->fNativeCGFont,
+                                     canvas, glyphs[i], info, mainFontDescriptor, strike);
         } else {
             info = CGGI_CreateImageForUnicode(canvas, strike, mode, uniChars[i]);
             glyphInfos[i] = ptr_to_jlong(info);
@@ -710,7 +807,7 @@
 static inline void
 CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
                          const CGGI_RenderingMode *mode,
-                         const UniChar uniChars[], const CGGlyph glyphs[],
+                         const UnicodeScalarValue uniChars[], const CGGlyph glyphs[],
                          const size_t maxWidth, const size_t maxHeight,
                          const CFIndex len)
 {
@@ -732,7 +829,7 @@
 
     NSString* theKey = (mode->glyphDescriptor == &rgb) ?
         threadLocalLCDCanvasKey : threadLocalAACanvasKey;
-    
+
     CGGI_GlyphCanvas *canvas = [threadDict objectForKey:theKey];
     if (canvas == nil) {
         canvas = [[CGGI_GlyphCanvas alloc] init];
@@ -757,7 +854,7 @@
 static inline void
 CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
                       const CGGI_RenderingMode *mode,
-                      const UniChar uniChars[], const CGGlyph glyphs[],
+                      const UnicodeScalarValue uniChars[], const CGGlyph glyphs[],
                       CGSize advances[], CGRect bboxes[], const CFIndex len)
 {
     AWTFont *font = strike->fAWTFont;
@@ -770,6 +867,8 @@
     size_t maxWidth = 1;
     size_t maxHeight = 1;
 
+    CGGI_GlyphInfoDescriptor* mainFontDescriptor = CGGI_GetGlyphInfoDescriptor(mode, strike->fAWTFont->fNativeCGFont);
+
     CFIndex i;
     for (i = 0; i < len; i++)
     {
@@ -782,7 +881,7 @@
         CGSize advance = advances[i];
         CGRect bbox = bboxes[i];
 
-        GlyphInfo *glyphInfo = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode);
+        GlyphInfo *glyphInfo = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mainFontDescriptor);
 
         if (maxWidth < glyphInfo->width)   maxWidth = glyphInfo->width;
         if (maxHeight < glyphInfo->height) maxHeight = glyphInfo->height;
@@ -807,7 +906,7 @@
                                         const AWTStrike *strike,
                                         const CGGI_RenderingMode *mode,
                                         jint rawGlyphCodes[],
-                                        UniChar uniChars[], CGGlyph glyphs[],
+                                        UnicodeScalarValue uniChars[], CGGlyph glyphs[],
                                         CGSize advances[], CGRect bboxes[],
                                         const CFIndex len)
 {
@@ -850,7 +949,7 @@
         CGRect bboxes[len];
         CGSize advances[len];
         CGGlyph glyphs[len];
-        UniChar uniChars[len];
+        UnicodeScalarValue uniChars[len];
 
         CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
                                                 rawGlyphCodes, uniChars, glyphs,
@@ -861,7 +960,7 @@
 
     // just do one malloc, and carve it up for all the buffers
     void *buffer = malloc(sizeof(CGRect) * sizeof(CGSize) *
-                          sizeof(CGGlyph) * sizeof(UniChar) * len);
+                          sizeof(CGGlyph) * sizeof(UnicodeScalarValue) * len);
     if (buffer == NULL) {
         [[NSException exceptionWithName:NSMallocException
             reason:@"Failed to allocate memory for the temporary glyph strike and measurement buffers." userInfo:nil] raise];
@@ -870,7 +969,7 @@
     CGRect *bboxes = (CGRect *)(buffer);
     CGSize *advances = (CGSize *)(bboxes + sizeof(CGRect) * len);
     CGGlyph *glyphs = (CGGlyph *)(advances + sizeof(CGGlyph) * len);
-    UniChar *uniChars = (UniChar *)(glyphs + sizeof(UniChar) * len);
+    UnicodeScalarValue *uniChars = (UnicodeScalarValue *)(glyphs + sizeof(UnicodeScalarValue) * len);
 
     CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
                                             rawGlyphCodes, uniChars, glyphs,
diff --git a/src/macosx/native/sun/font/CoreTextSupport.h b/src/macosx/native/sun/font/CoreTextSupport.h
index a0ede94..66ca1b1 100644
--- a/src/macosx/native/sun/font/CoreTextSupport.h
+++ b/src/macosx/native/sun/font/CoreTextSupport.h
@@ -32,7 +32,9 @@
 #pragma mark --- CoreText Support ---
 
 #define HI_SURROGATE_START 0xD800
+#define HI_SURROGATE_END   0xDBFF
 #define LO_SURROGATE_START 0xDC00
+#define LO_SURROGATE_END   0xDFFF
 
 /*
  *    Transform Unicode characters into glyphs.
@@ -52,6 +54,9 @@
 // Returns the substituted font, and places the appropriate glyph into "glyphRef"
 CTFontRef CTS_CopyCTFallbackFontAndGlyphForUnicode(const AWTFont *font, const UTF16Char *charRef, CGGlyph *glyphRef, int count);
 
+// Transform a single Unicode character into glyphs. Names of the relevant font (original or substituted one) are also returned
+CGGlyph CTS_CopyGlyphAndFontNamesForCodePoint(const AWTFont *font, const UnicodeScalarValue codePoint, CFStringRef fontNames[]);
+
 // Breakup a 32 bit unicode value into the component surrogate pairs
 void CTS_BreakupUnicodeIntoSurrogatePairs(int uniChar, UTF16Char charRef[]);
 
diff --git a/src/macosx/native/sun/font/CoreTextSupport.m b/src/macosx/native/sun/font/CoreTextSupport.m
index 1bcd9f5..5bd6663 100644
--- a/src/macosx/native/sun/font/CoreTextSupport.m
+++ b/src/macosx/native/sun/font/CoreTextSupport.m
@@ -88,6 +88,47 @@
     CFRelease(ctStateDict); // GC
 }
 
+void GetFontsAndGlyphsForCharacters(CTFontRef font, const UniChar unicodes[], CGGlyph glyphs[], jint glyphsAsInts[],
+                                    CTFontRef actualFonts[], const size_t count)
+{
+    CTFontGetGlyphsForCharacters(font, unicodes, glyphs, count);
+
+    size_t i;
+    for (i = 0; i < count; i++) {
+        UniChar unicode = unicodes[i];
+        UniChar nextUnicode = (i+1) < count ? unicodes[i+1] : 0;
+        bool surrogatePair = unicode >= HI_SURROGATE_START && unicode <= HI_SURROGATE_END
+                             && nextUnicode >= LO_SURROGATE_START && nextUnicode <= LO_SURROGATE_END;
+
+        CGGlyph glyph = glyphs[i];
+        if (glyph > 0) {
+            glyphsAsInts[i] = glyph;
+            if (surrogatePair) i++;
+            continue;
+        }
+
+        const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters(font, &unicodes[i], surrogatePair ? 2 : 1);
+        if (fallback) {
+            CTFontGetGlyphsForCharacters(fallback, &unicodes[i], &glyphs[i], surrogatePair ? 2 : 1);
+            glyph = glyphs[i];
+            if (actualFonts && glyph > 0) {
+                actualFonts[i] = fallback;
+            } else {
+                CFRelease(fallback);
+            }
+        }
+
+        if (glyph > 0) {
+            int codePoint = surrogatePair ? (((int)(unicode - HI_SURROGATE_START)) << 10)
+                                            + nextUnicode - LO_SURROGATE_START + 0x10000 : unicode;
+            glyphsAsInts[i] = -codePoint; // set the glyph code to the negative unicode value
+        } else {
+            glyphsAsInts[i] = 0; // CoreText couldn't find a glyph for this character either
+        }
+        if (surrogatePair) i++;
+    }
+}
+
 /*
  *    Transform Unicode characters into glyphs.
  *
@@ -99,29 +140,41 @@
 void CTS_GetGlyphsAsIntsForCharacters
 (const AWTFont *font, const UniChar unicodes[], CGGlyph glyphs[], jint glyphsAsInts[], const size_t count)
 {
-    CTFontGetGlyphsForCharacters((CTFontRef)font->fFont, unicodes, glyphs, count);
+    GetFontsAndGlyphsForCharacters((CTFontRef)font->fFont, unicodes, glyphs, glyphsAsInts, NULL, count);
+}
 
-    size_t i;
-    for (i = 0; i < count; i++) {
-        CGGlyph glyph = glyphs[i];
-        if (glyph > 0) {
-            glyphsAsInts[i] = glyph;
-            continue;
-        }
-
-        UniChar unicode = unicodes[i];
-        const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, &unicode, 1);
-        if (fallback) {
-            CTFontGetGlyphsForCharacters(fallback, &unicode, &glyph, 1);
-            CFRelease(fallback);
-        }
-
-        if (glyph > 0) {
-            glyphsAsInts[i] = -unicode; // set the glyph code to the negative unicode value
-        } else {
-            glyphsAsInts[i] = 0; // CoreText couldn't find a glyph for this character either
-        }
+/*
+ *   Returns glyph code for a given Unicode character. Names of the relevant font (original or substituted one)
+ *   are also returned.
+ */
+CGGlyph CTS_CopyGlyphAndFontNamesForCodePoint
+(const AWTFont *font, const UnicodeScalarValue codePoint, CFStringRef fontNames[])
+{
+    CTFontRef fontRef = (CTFontRef)font->fFont;
+    int count = codePoint >= 0x10000 ? 2 : 1;
+    UTF16Char unicodes[count];
+    if (count == 1) {
+        unicodes[0] = (UTF16Char)codePoint;
+    } else {
+        CTS_BreakupUnicodeIntoSurrogatePairs(codePoint, unicodes);
     }
+    CGGlyph glyphs[count];
+    jint glyphsAsInts[count];
+    CTFontRef actualFonts[count];
+    GetFontsAndGlyphsForCharacters(fontRef, unicodes, glyphs, glyphsAsInts, actualFonts, count);
+    CGGlyph glyph = glyphs[0];
+    if (glyph > 0) {
+        bool substitutionHappened = glyphsAsInts[0] < 0;
+        CTFontRef actualFont = substitutionHappened ? actualFonts[0] : fontRef;
+        CFStringRef fontName = CTFontCopyPostScriptName(actualFont);
+        CFStringRef familyName = CTFontCopyFamilyName(actualFont);
+        if (substitutionHappened) {
+            CFRelease(actualFont);
+        }
+        fontNames[0] = fontName;
+        fontNames[1] = familyName;
+    }
+    return glyph;
 }
 
 /*
@@ -158,8 +211,18 @@
         return (CTFontRef)font->fFont;
     }
 
-    UTF16Char character = -glyphCode;
-    return CTS_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);
+    int codePoint = -glyphCode;
+    if (codePoint >= 0x10000) {
+        UTF16Char chars[2];
+        CGGlyph glyphs[2];
+        CTS_BreakupUnicodeIntoSurrogatePairs(codePoint, chars);
+        CTFontRef result = CTS_CopyCTFallbackFontAndGlyphForUnicode(font, chars, glyphs, 2);
+        *glyphRef = glyphs[0];
+        return result;
+    } else {
+        UTF16Char character = codePoint;
+        return CTS_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);
+    }
 }
 
 // Breakup a 32 bit unicode value into the component surrogate pairs
diff --git a/src/macosx/native/sun/java2d/opengl/CGLSurfaceData.m b/src/macosx/native/sun/java2d/opengl/CGLSurfaceData.m
index e4dccab..d4c1d71 100644
--- a/src/macosx/native/sun/java2d/opengl/CGLSurfaceData.m
+++ b/src/macosx/native/sun/java2d/opengl/CGLSurfaceData.m
@@ -409,6 +409,18 @@
 extern UnlockFunc      OGLSD_Unlock;
 extern DisposeFunc     OGLSD_Dispose;
 
+
+void
+CGLSD_Dispose(JNIEnv *env, SurfaceDataOps *ops)
+{
+    OGLSDOps *oglsdo = (OGLSDOps *)ops;
+    jlong pConfigInfo = OGLSD_GetNativeConfigInfo(oglsdo);
+    JNU_CallStaticMethodByName(env, NULL, "sun/java2d/opengl/CGLSurfaceData",
+                               "dispose", "(JJ)V",
+                               ptr_to_jlong(ops), pConfigInfo);
+}
+
+
 JNIEXPORT void JNICALL
 Java_sun_java2d_opengl_CGLSurfaceData_initOps
     (JNIEnv *env, jobject cglsd,
@@ -432,7 +444,7 @@
     oglsdo->sdOps.Lock               = OGLSD_Lock;
     oglsdo->sdOps.GetRasInfo         = OGLSD_GetRasInfo;
     oglsdo->sdOps.Unlock             = OGLSD_Unlock;
-    oglsdo->sdOps.Dispose            = OGLSD_Dispose;
+    oglsdo->sdOps.Dispose            = CGLSD_Dispose;
 
     oglsdo->drawableType = OGLSD_UNDEFINED;
     oglsdo->activeBuffer = GL_FRONT;
diff --git a/src/macosx/native/sun/osxapp/NSApplicationAWT.h b/src/macosx/native/sun/osxapp/NSApplicationAWT.h
index 99c7d63..9269295 100644
--- a/src/macosx/native/sun/osxapp/NSApplicationAWT.h
+++ b/src/macosx/native/sun/osxapp/NSApplicationAWT.h
@@ -37,7 +37,6 @@
 - (void) registerWithProcessManager;
 - (void) setDockIconWithEnv:(JNIEnv *)env;
 - (void) postDummyEvent;
-- (void) postRunnableEvent:(void (^)())block;
 - (void) waitForDummyEvent;
 
 + (void) runAWTLoopWithApp:(NSApplication*)app;
diff --git a/src/macosx/native/sun/osxapp/NSApplicationAWT.m b/src/macosx/native/sun/osxapp/NSApplicationAWT.m
index d22983a..a531aac 100644
--- a/src/macosx/native/sun/osxapp/NSApplicationAWT.m
+++ b/src/macosx/native/sun/osxapp/NSApplicationAWT.m
@@ -338,13 +338,9 @@
 
 - (void)sendEvent:(NSEvent *)event
 {
-    if ([event type] == NSApplicationDefined && TS_EQUAL([event timestamp], dummyEventTimestamp) && [event subtype] == 0) {
+    if ([event type] == NSApplicationDefined && TS_EQUAL([event timestamp], dummyEventTimestamp)) {
         [seenDummyEventLock lockWhenCondition:NO];
         [seenDummyEventLock unlockWithCondition:YES];
-    } else if ([event type] == NSApplicationDefined && [event subtype] == 777) {
-        void (^block)() = (void (^)()) [event data1];
-        block();
-        [block release];
     } else if ([event type] == NSKeyUp && ([event modifierFlags] & NSCommandKeyMask)) {
         // Cocoa won't send us key up event when releasing a key while Cmd is down,
         // so we have to do it ourselves.
@@ -363,7 +359,7 @@
 {
     void (^copy)() = [block copy];
     NSInteger encode = (NSInteger) copy;
-    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];    
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
     NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined
                                         location: NSMakePoint(0,0)
                                    modifierFlags: 0
diff --git a/src/share/back/debugLoop.c b/src/share/back/debugLoop.c
index eaec870..18389e2 100644
--- a/src/share/back/debugLoop.c
+++ b/src/share/back/debugLoop.c
@@ -45,7 +45,7 @@
 
 static volatile struct PacketList *cmdQueue;
 static jrawMonitorID cmdQueueLock;
-static jrawMonitorID resumeLock;
+static jrawMonitorID vmDeathLock;
 static jboolean transportError;
 
 static jboolean
@@ -60,28 +60,17 @@
     }
 }
 
-static jboolean
-resumeCommand(jdwpCmdPacket *cmd)
-{
-    if ( (cmd->cmdSet == JDWP_COMMAND_SET(VirtualMachine)) &&
-         (cmd->cmd == JDWP_COMMAND(VirtualMachine, Resume)) ) {
-        return JNI_TRUE;
-    } else {
-        return JNI_FALSE;
-    }
-}
-
 void
 debugLoop_initialize(void)
 {
-    resumeLock = debugMonitorCreate("JDWP Resume Lock");
+    vmDeathLock = debugMonitorCreate("JDWP VM_DEATH Lock");
 }
 
 void
 debugLoop_sync(void)
 {
-    debugMonitorEnter(resumeLock);
-    debugMonitorExit(resumeLock);
+    debugMonitorEnter(vmDeathLock);
+    debugMonitorExit(vmDeathLock);
 }
 
 /*
@@ -136,14 +125,14 @@
             jboolean replyToSender = JNI_TRUE;
 
             /*
-             * For VirtualMachine.Resume commands we hold the resumeLock
+             * For VirtualMachine commands we hold the vmDeathLock
              * while executing and replying to the command. This ensures
-             * that a Resume after VM_DEATH will be allowed to complete
+             * that a VM command after VM_DEATH will be allowed to complete
              * before the thread posting the VM_DEATH continues VM
              * termination.
              */
-            if (resumeCommand(cmd)) {
-                debugMonitorEnter(resumeLock);
+            if (cmd->cmdSet == JDWP_COMMAND_SET(VirtualMachine)){
+                debugMonitorEnter(vmDeathLock);
             }
 
             /* Initialize the input and output streams */
@@ -181,10 +170,10 @@
             }
 
             /*
-             * Release the resumeLock as the reply has been posted.
+             * Release the vmDeathLock as the reply has been posted.
              */
-            if (resumeCommand(cmd)) {
-                debugMonitorExit(resumeLock);
+            if (cmd->cmdSet == JDWP_COMMAND_SET(VirtualMachine)){
+               debugMonitorExit(vmDeathLock);
             }
 
             inStream_destroy(&in);
diff --git a/src/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java b/src/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java
index 30b0831..0f427fb 100644
--- a/src/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java
+++ b/src/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java
@@ -93,7 +93,8 @@
      */
     static enum Settings {
         GTK_FONT_NAME,
-        GTK_ICON_SIZES
+        GTK_ICON_SIZES,
+        GTK_XFT_DPI
     }
 
     /* Custom regions are needed for representing regions that don't exist
diff --git a/src/share/classes/com/sun/java/swing/plaf/gtk/PangoFonts.java b/src/share/classes/com/sun/java/swing/plaf/gtk/PangoFonts.java
index 4794d83..5dc661e 100644
--- a/src/share/classes/com/sun/java/swing/plaf/gtk/PangoFonts.java
+++ b/src/share/classes/com/sun/java/swing/plaf/gtk/PangoFonts.java
@@ -163,6 +163,10 @@
         int dpi = 96;
         Object value =
             Toolkit.getDefaultToolkit().getDesktopProperty("gnome.Xft/DPI");
+
+        if (!(value instanceof Integer)) {
+            value = GTKEngine.INSTANCE.getSetting(GTKEngine.Settings.GTK_XFT_DPI);
+        }
         if (value instanceof Integer) {
             dpi = ((Integer)value).intValue() / 1024;
             if (dpi == -1) {
diff --git a/src/share/classes/com/sun/java/swing/plaf/windows/icons/JavaCup32.png b/src/share/classes/com/sun/java/swing/plaf/windows/icons/JavaCup32.png
index 0c41d65..b0b036c 100644
--- a/src/share/classes/com/sun/java/swing/plaf/windows/icons/JavaCup32.png
+++ b/src/share/classes/com/sun/java/swing/plaf/windows/icons/JavaCup32.png
Binary files differ
diff --git a/src/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java b/src/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java
index be98d5e..51c4478 100644
--- a/src/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java
+++ b/src/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java
@@ -975,32 +975,39 @@
         return minorVersion;
     }
 
-    private void getConstantPoolInfo() {
+    private byte[] getConstantPoolInfo() {
         JDWP.ReferenceType.ConstantPool jdwpCPool;
         if (!vm.canGetConstantPool()) {
             throw new UnsupportedOperationException();
         }
         if (constantPoolInfoGotten) {
-            return;
-        } else {
-            try {
-                jdwpCPool = JDWP.ReferenceType.ConstantPool.process(vm, this);
-            } catch (JDWPException exc) {
-                if (exc.errorCode() == JDWP.Error.ABSENT_INFORMATION) {
-                    constanPoolCount = 0;
-                    constantPoolBytesRef = null;
-                    constantPoolInfoGotten = true;
-                    return;
-                } else {
-                    throw exc.toJDIException();
-                }
+            if (constantPoolBytesRef == null) {
+                return null;
             }
-            byte[] cpbytes;
-            constanPoolCount = jdwpCPool.count;
-            cpbytes = jdwpCPool.bytes;
-            constantPoolBytesRef = new SoftReference<byte[]>(cpbytes);
-            constantPoolInfoGotten = true;
+            byte[] cpbytes = constantPoolBytesRef.get();
+            if (cpbytes != null) {
+                return cpbytes;
+            }
         }
+
+        try {
+            jdwpCPool = JDWP.ReferenceType.ConstantPool.process(vm, this);
+        } catch (JDWPException exc) {
+            if (exc.errorCode() == JDWP.Error.ABSENT_INFORMATION) {
+                constanPoolCount = 0;
+                constantPoolBytesRef = null;
+                constantPoolInfoGotten = true;
+                return null;
+            } else {
+                throw exc.toJDIException();
+            }
+        }
+        byte[] cpbytes;
+        constanPoolCount = jdwpCPool.count;
+        cpbytes = jdwpCPool.bytes;
+        constantPoolBytesRef = new SoftReference<byte[]>(cpbytes);
+        constantPoolInfoGotten = true;
+        return cpbytes;
     }
 
     public int constantPoolCount() {
@@ -1013,13 +1020,13 @@
     }
 
     public byte[] constantPool() {
+        byte[] cpbytes;
         try {
-            getConstantPoolInfo();
+            cpbytes = getConstantPoolInfo();
         } catch (RuntimeException exc) {
             throw exc;
         }
-        if (constantPoolBytesRef != null) {
-            byte[] cpbytes = constantPoolBytesRef.get();
+        if (cpbytes != null) {
             /*
              * Arrays are always modifiable, so it is a little unsafe
              * to return the cached bytecodes directly; instead, we
diff --git a/src/share/classes/com/sun/tools/jdi/TargetVM.java b/src/share/classes/com/sun/tools/jdi/TargetVM.java
index a94eb43..191e69e 100644
--- a/src/share/classes/com/sun/tools/jdi/TargetVM.java
+++ b/src/share/classes/com/sun/tools/jdi/TargetVM.java
@@ -321,15 +321,16 @@
         try {
             connection.close();
         } catch (IOException ioe) { }
+        if (eventController != null) {
+            eventController.release();
+        }
     }
 
-    static private class EventController extends Thread {
-        VirtualMachineImpl vm;
+    private class EventController extends Thread {
         int controlRequest = 0;
 
         EventController(VirtualMachineImpl vm) {
             super(vm.threadGroupForJDI(), "JDI Event Control Thread");
-            this.vm = vm;
             setDaemon(true);
             setPriority((MAX_PRIORITY + NORM_PRIORITY)/2);
             super.start();
@@ -351,6 +352,7 @@
                 synchronized(this) {
                     while (controlRequest == 0) {
                         try {wait();} catch (InterruptedException e) {}
+                        if (!shouldListen) return;
                     }
                     currentRequest = controlRequest;
                     controlRequest = 0;
diff --git a/src/share/classes/java/awt/EventQueue.java b/src/share/classes/java/awt/EventQueue.java
index f050900..8953a3b 100644
--- a/src/share/classes/java/awt/EventQueue.java
+++ b/src/share/classes/java/awt/EventQueue.java
@@ -46,6 +46,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 import java.security.AccessControlContext;
+import java.util.function.BooleanSupplier;
 
 import sun.misc.SharedSecrets;
 import sun.misc.JavaSecurityAccess;
@@ -226,6 +227,11 @@
                 public long getMostRecentEventTime(EventQueue eventQueue) {
                     return eventQueue.getMostRecentEventTimeImpl();
                 }
+
+                @Override
+                public SecondaryLoop createSecondaryLoop(EventQueue eventQueue, BooleanSupplier cond) {
+                    return eventQueue.createSecondaryLoop(cond::getAsBoolean, null, 0);
+                }
             });
     }
 
diff --git a/src/share/classes/java/awt/Font.java b/src/share/classes/java/awt/Font.java
index 3293932..6a77fdd 100644
--- a/src/share/classes/java/awt/Font.java
+++ b/src/share/classes/java/awt/Font.java
@@ -2664,6 +2664,12 @@
      */
     public static final int LAYOUT_NO_LIMIT_CONTEXT = 4;
 
+    /**
+     * A flag to layoutGlyphVector requesting to disable detection of paired characters
+     * when splitting text into scripts.
+     */
+    public static final int LAYOUT_NO_PAIRED_CHARS_AT_SCRIPT_SPLIT = 8;
+
 
     private static void applyTransform(AffineTransform trans, AttributeValues values) {
         if (trans == null) {
diff --git a/src/share/classes/java/awt/RenderingHints.java b/src/share/classes/java/awt/RenderingHints.java
index 2cc161a..65aed6c 100644
--- a/src/share/classes/java/awt/RenderingHints.java
+++ b/src/share/classes/java/awt/RenderingHints.java
@@ -955,6 +955,64 @@
         SunHints.VALUE_STROKE_PURE;
 
     /**
+     * Image resolution variant hint key.
+     * The {@code RESOLUTION_VARIANT} hint controls which image resolution
+     * variant should be chosen for image drawing.
+     *
+     * <ul>
+     * <li>{@link #VALUE_RESOLUTION_VARIANT_DEFAULT}
+     * <li>{@link #VALUE_RESOLUTION_VARIANT_BASE}
+     * <li>{@link #VALUE_RESOLUTION_VARIANT_SIZE_FIT}
+     * <li>{@link #VALUE_RESOLUTION_VARIANT_DPI_FIT}
+     * </ul>
+     * @since 1.9
+     */
+    public static final Key KEY_RESOLUTION_VARIANT =
+        SunHints.KEY_RESOLUTION_VARIANT;
+
+    /**
+     * Image resolution variant hint value -- an image resolution variant is
+     * chosen based on a default heuristic which may depend on the policies
+     * of the platform
+     *
+     * @see #KEY_RESOLUTION_VARIANT
+     * @since 1.9
+     */
+    public static final Object VALUE_RESOLUTION_VARIANT_DEFAULT =
+        SunHints.VALUE_RESOLUTION_VARIANT_DEFAULT;
+
+    /**
+     * Image resolution variant hint value -- the standard resolution of an image
+     * is always used.
+     *
+     * @see #KEY_RESOLUTION_VARIANT
+     * @since 1.9
+     */
+    public static final Object VALUE_RESOLUTION_VARIANT_BASE =
+        SunHints.VALUE_RESOLUTION_VARIANT_BASE;
+
+    /**
+     * Image resolution variant hint value -- an image resolution variant is
+     * chosen based on the DPI of the screen and the transform in the Graphics2D
+     * context.
+     *
+     * @see #KEY_RESOLUTION_VARIANT
+     * @since 1.9
+     */
+    public static final Object VALUE_RESOLUTION_VARIANT_SIZE_FIT =
+        SunHints.VALUE_RESOLUTION_VARIANT_SIZE_FIT;
+
+    /**
+     * Image resolution variant hint value -- an image resolution variant is
+     * chosen based only on the DPI of the screen.
+     *
+     * @see #KEY_RESOLUTION_VARIANT
+     * @since 1.9
+     */
+    public static final Object VALUE_RESOLUTION_VARIANT_DPI_FIT =
+        SunHints.VALUE_RESOLUTION_VARIANT_DPI_FIT;
+
+    /**
      * Constructs a new object with keys and values initialized
      * from the specified Map object which may be null.
      * @param init a map of key/value pairs to initialize the hints
diff --git a/src/share/classes/java/awt/event/KeyEvent.java b/src/share/classes/java/awt/event/KeyEvent.java
index 47bf7a5..002d536 100644
--- a/src/share/classes/java/awt/event/KeyEvent.java
+++ b/src/share/classes/java/awt/event/KeyEvent.java
@@ -30,6 +30,8 @@
 import java.awt.Toolkit;
 import java.io.IOException;
 import java.io.ObjectInputStream;
+import java.util.HashMap;
+
 import sun.awt.AWTAccessor;
 
 /**
@@ -306,6 +308,41 @@
     public static final int VK_Y              = 0x59;
     public static final int VK_Z              = 0x5A;
 
+    public static final int START_OF_LATIN_DIACRITIC_LETTERS = 0x0300;
+
+    public static final int VK_A_WITH_GRAVE = START_OF_LATIN_DIACRITIC_LETTERS + 0xE0;
+    public static final int VK_A_WITH_ACUTE = START_OF_LATIN_DIACRITIC_LETTERS + 0xE1;
+    public static final int VK_A_WITH_CIRCUMFLEX = START_OF_LATIN_DIACRITIC_LETTERS + 0xE2;
+    public static final int VK_A_WITH_TILDE = START_OF_LATIN_DIACRITIC_LETTERS + 0xE3;
+    public static final int VK_A_WITH_DIAERESIS = START_OF_LATIN_DIACRITIC_LETTERS + 0xE4;
+    public static final int VK_A_WITH_RING_ABOVE = START_OF_LATIN_DIACRITIC_LETTERS + 0xE5;
+    public static final int VK_AE = START_OF_LATIN_DIACRITIC_LETTERS + 0xE6;
+    public static final int VK_C_WITH_CEDILLA = START_OF_LATIN_DIACRITIC_LETTERS + 0xE7;
+    public static final int VK_E_WITH_GRAVE = START_OF_LATIN_DIACRITIC_LETTERS + 0xE8;
+    public static final int VK_E_WITH_ACUTE = START_OF_LATIN_DIACRITIC_LETTERS + 0xE9;
+    public static final int VK_E_WITH_CIRCUMFLEX = START_OF_LATIN_DIACRITIC_LETTERS + 0xEA;
+    public static final int VK_E_WITH_DIAERESIS = START_OF_LATIN_DIACRITIC_LETTERS + 0xEB;
+    public static final int VK_I_WITH_GRAVE = START_OF_LATIN_DIACRITIC_LETTERS + 0xEC;
+    public static final int VK_I_WITH_ACUTE = START_OF_LATIN_DIACRITIC_LETTERS + 0xED;
+    public static final int VK_I_WITH_CIRCUMFLEX = START_OF_LATIN_DIACRITIC_LETTERS + 0xEE;
+    public static final int VK_I_WITH_DIAERESIS = START_OF_LATIN_DIACRITIC_LETTERS + 0xEF;
+    public static final int VK_ETH = START_OF_LATIN_DIACRITIC_LETTERS + 0xF0;
+    public static final int VK_N_WITH_TILDE = START_OF_LATIN_DIACRITIC_LETTERS + 0xF1;
+    public static final int VK_O_WITH_GRAVE = START_OF_LATIN_DIACRITIC_LETTERS + 0xF2;
+    public static final int VK_O_WITH_ACUTE = START_OF_LATIN_DIACRITIC_LETTERS + 0xF3;
+    public static final int VK_O_WITH_CIRCUMFLEX = START_OF_LATIN_DIACRITIC_LETTERS + 0xF4;
+    public static final int VK_O_WITH_TILDE = START_OF_LATIN_DIACRITIC_LETTERS + 0xF5;
+    public static final int VK_O_WITH_DIAERESIS = START_OF_LATIN_DIACRITIC_LETTERS + 0xF6;
+    public static final int VK_DIVISION_SIGN = START_OF_LATIN_DIACRITIC_LETTERS + 0xF7;
+    public static final int VK_O_WITH_SLASH = START_OF_LATIN_DIACRITIC_LETTERS + 0xF8;
+    public static final int VK_U_WITH_GRAVE = START_OF_LATIN_DIACRITIC_LETTERS + 0xF9;
+    public static final int VK_U_WITH_ACUTE = START_OF_LATIN_DIACRITIC_LETTERS + 0xFA;
+    public static final int VK_U_WITH_CIRCUMFLEX = START_OF_LATIN_DIACRITIC_LETTERS + 0xFB;
+    public static final int VK_U_WITH_DIAERESIS = START_OF_LATIN_DIACRITIC_LETTERS + 0xFC;
+    public static final int VK_Y_WITH_ACUTE = START_OF_LATIN_DIACRITIC_LETTERS + 0xFD;
+    public static final int VK_THORN = START_OF_LATIN_DIACRITIC_LETTERS + 0xFE;
+    public static final int VK_Y_WITH_DIAERESIS = START_OF_LATIN_DIACRITIC_LETTERS + 0xFF;
+
     /**
      * Constant for the open bracket key, "["
      */
@@ -1010,17 +1047,7 @@
     public KeyEvent(Component source, int id, long when, int modifiers,
                     int keyCode, char keyChar, int keyLocation) {
         super(source, id, when, modifiers);
-        if (id == KEY_TYPED) {
-            if (keyChar == CHAR_UNDEFINED) {
-                throw new IllegalArgumentException("invalid keyChar");
-            }
-            if (keyCode != VK_UNDEFINED) {
-                throw new IllegalArgumentException("invalid keyCode");
-            }
-            if (keyLocation != KEY_LOCATION_UNKNOWN) {
-                throw new IllegalArgumentException("invalid keyLocation");
-            }
-        }
+
 
         this.keyCode = keyCode;
         this.keyChar = keyChar;
@@ -1180,6 +1207,43 @@
         return keyLocation;
     }
 
+    private static final HashMap<Integer, String> asciiCodeToString = new HashMap<Integer, String>() {
+        {
+            put(VK_A_WITH_GRAVE, "\u00e0");
+            put(VK_A_WITH_ACUTE, "\u00e1");
+            put(VK_A_WITH_CIRCUMFLEX, "\u00e2");
+            put(VK_A_WITH_TILDE, "\u00e3");
+            put(VK_A_WITH_DIAERESIS, "\u00e4");
+            put(VK_A_WITH_RING_ABOVE, "\u00e5");
+            put(VK_AE, "\u00e6");
+            put(VK_C_WITH_CEDILLA, "\u00e7");
+            put(VK_E_WITH_GRAVE, "\u00e8");
+            put(VK_E_WITH_ACUTE, "\u00e9");
+            put(VK_E_WITH_CIRCUMFLEX, "\u00ea");
+            put(VK_E_WITH_DIAERESIS, "\u00eb");
+            put(VK_I_WITH_GRAVE, "\u00ec");
+            put(VK_I_WITH_ACUTE, "\u00ed");
+            put(VK_I_WITH_CIRCUMFLEX, "\u00ee");
+            put(VK_I_WITH_DIAERESIS, "\u00ef");
+            put(VK_ETH, "\u00f0");
+            put(VK_N_WITH_TILDE, "\u00f1");
+            put(VK_O_WITH_GRAVE, "\u00f2");
+            put(VK_O_WITH_ACUTE, "\u00f3");
+            put(VK_O_WITH_CIRCUMFLEX, "\u00f4");
+            put(VK_O_WITH_TILDE, "\u00f5");
+            put(VK_O_WITH_DIAERESIS, "\u00f6");
+            put(VK_DIVISION_SIGN, "\u00f7");
+            put(VK_O_WITH_SLASH, "\u00f8");
+            put(VK_U_WITH_GRAVE, "\u00f9");
+            put(VK_U_WITH_ACUTE, "\u00fa");
+            put(VK_U_WITH_CIRCUMFLEX, "\u00fb");
+            put(VK_U_WITH_DIAERESIS, "\u00fc");
+            put(VK_Y_WITH_ACUTE, "\u00fd");
+            put(VK_THORN, "\u00fe");
+            put(VK_Y_WITH_DIAERESIS, "\u00ff");
+        }
+    };
+
     /**
      * Returns a String describing the keyCode, such as "HOME", "F1" or "A".
      * These strings can be localized by changing the awt.properties file.
@@ -1193,6 +1257,11 @@
             return String.valueOf((char)keyCode);
         }
 
+        if (keyCode > 0x0300 && keyCode < 0x0400) {
+            String asciiCodeStringRepresentation = asciiCodeToString.get(keyCode);
+            if (asciiCodeStringRepresentation != null) return asciiCodeStringRepresentation;
+        }
+
         switch(keyCode) {
           case VK_ENTER: return Toolkit.getProperty("AWT.enter", "Enter");
           case VK_BACK_SPACE: return Toolkit.getProperty("AWT.backSpace", "Backspace");
diff --git a/src/share/classes/java/awt/font/StyledFontLayoutTest.java b/src/share/classes/java/awt/font/StyledFontLayoutTest.java
new file mode 100644
index 0000000..df88ff9
--- /dev/null
+++ b/src/share/classes/java/awt/font/StyledFontLayoutTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test 
+ * @bug 8139176
+ * @summary Test layout uses correct styled font.
+ * @run main StyledFontLayoutTest
+ */
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import javax.swing.WindowConstants;
+
+public class StyledFontLayoutTest extends JPanel {
+
+    static final int W=600, H=400;
+    static boolean interactive;
+    static BufferedImage im;
+    public static void main(String[] args) {
+
+        interactive = args.length > 0;
+
+        runTest();
+
+        if (!interactive) {
+            return;
+        }
+        SwingUtilities.invokeLater(() -> {
+            JFrame frame = new JFrame("Styled Font Layout Test");
+            frame.add(new StyledFontLayoutTest());
+            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+            frame.setSize(W, H);
+            frame.setLocationRelativeTo(null);
+            frame.setVisible(true);
+        });
+    }
+
+    @Override
+    protected void paintComponent(Graphics g) {
+        g.drawImage(im, 0, 0, null);
+    }
+
+    private static void runTest() {
+        im = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB);
+        Graphics2D g2d = im.createGraphics();
+        g2d.setColor(Color.white);
+        g2d.fillRect(0, 0, W, H);
+        g2d.setColor(Color.black);
+        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+        char[] chs = "Sample Text.".toCharArray();
+        int len = chs.length;
+
+        int x = 50, y = 100;
+
+        FontRenderContext frc = g2d.getFontRenderContext();
+        Font plain = new Font("Serif", Font.PLAIN, 48);
+        GlyphVector pgv = plain.layoutGlyphVector(frc, chs, 0, len, 0);
+        g2d.setFont(plain);
+        g2d.drawChars(chs, 0, len, x, y); y +=50;
+
+        g2d.drawGlyphVector(pgv, x, y); y += 50;
+        Rectangle2D plainStrBounds = plain.getStringBounds(chs, 0, len, frc);
+        Rectangle2D plainGVBounds = pgv.getLogicalBounds();
+        Font bold = new Font("Serif", Font.BOLD, 48);
+        GlyphVector bgv = bold.layoutGlyphVector(frc, chs, 0, len, 0);
+        Rectangle2D boldStrBounds = bold.getStringBounds(chs, 0, len, frc);
+        Rectangle2D boldGVBounds = bgv.getLogicalBounds();
+        g2d.setFont(bold);
+        g2d.drawChars(chs, 0, len, x, y); y +=50;
+        g2d.drawGlyphVector(bgv, x, y);
+        System.out.println("Plain String Bounds = " + plainStrBounds);
+        System.out.println("Bold String Bounds = " + boldStrBounds);
+        System.out.println("Plain GlyphVector Bounds = " + plainGVBounds);
+        System.out.println("Bold GlyphVector Bounds = " + boldGVBounds);
+        if (!plainStrBounds.equals(boldStrBounds) &&
+                plainGVBounds.equals(boldGVBounds))
+        {
+            System.out.println("Test failed: Plain GV bounds same as Bold");
+            if (!interactive) {
+                throw new RuntimeException("Plain GV bounds same as Bold");
+            }
+        }
+
+    };
+}
\ No newline at end of file
diff --git a/src/share/classes/sun/awt/image/AbstractMultiResolutionImage.java b/src/share/classes/java/awt/image/AbstractMultiResolutionImage.java
similarity index 60%
rename from src/share/classes/sun/awt/image/AbstractMultiResolutionImage.java
rename to src/share/classes/java/awt/image/AbstractMultiResolutionImage.java
index 94c0709..606661b 100644
--- a/src/share/classes/sun/awt/image/AbstractMultiResolutionImage.java
+++ b/src/share/classes/java/awt/image/AbstractMultiResolutionImage.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -22,101 +22,81 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package sun.awt.image;
+package java.awt.image;
 
 import java.awt.Graphics;
 import java.awt.Image;
-import java.awt.image.*;
 
 /**
- * This class provides default implementations for the
- * <code>MultiResolutionImage</code> interface. The developer needs only
- * to subclass this abstract class and define the <code>getResolutionVariant</code>,
- * <code>getResolutionVariants</code>, and <code>getBaseImage</code> methods.
- *
+ * This class provides default implementations of several {@code Image} methods
+ * for classes that want to implement the {@MultiResolutionImage} interface.
  *
  * For example,
- * {@code
+ * <pre> {@code
  * public class CustomMultiResolutionImage extends AbstractMultiResolutionImage {
  *
- *     int baseImageIndex;
- *     Image[] resolutionVariants;
+ *     final Image[] resolutionVariants;
  *
- *     public CustomMultiResolutionImage(int baseImageIndex,
- *             Image... resolutionVariants) {
- *          this.baseImageIndex = baseImageIndex;
+ *     public CustomMultiResolutionImage(Image... resolutionVariants) {
  *          this.resolutionVariants = resolutionVariants;
  *     }
  *
- *     @Override
- *     public Image getResolutionVariant(float logicalDPIX, float logicalDPIY,
- *             float baseImageWidth, float baseImageHeight,
- *             float destImageWidth, float destImageHeight) {
- *         // return a resolution variant based on the given logical DPI,
- *         // base image size, or destination image size
+ *     public Image getResolutionVariant(
+ *             double destImageWidth, double destImageHeight) {
+ *         // return a resolution variant based on the given destination image size
  *     }
  *
- *     @Override
  *     public List<Image> getResolutionVariants() {
- *         return Arrays.asList(resolutionVariants);
+ *         return Collections.unmodifiableList(Arrays.asList(resolutionVariants));
  *     }
  *
  *     protected Image getBaseImage() {
- *         return resolutionVariants[baseImageIndex];
+ *         return resolutionVariants[0];
  *     }
  * }
- * }
+ * } </pre>
  *
  * @see java.awt.Image
  * @see java.awt.image.MultiResolutionImage
  *
+ * @since 1.9
  */
 public abstract class AbstractMultiResolutionImage extends java.awt.Image
         implements MultiResolutionImage {
 
-    /**
-     * @inheritDoc
-     */
     @Override
     public int getWidth(ImageObserver observer) {
-        return getBaseImage().getWidth(null);
+        return getBaseImage().getWidth(observer);
     }
 
-    /**
-     * @inheritDoc
-     */
     @Override
     public int getHeight(ImageObserver observer) {
-        return getBaseImage().getHeight(null);
+        return getBaseImage().getHeight(observer);
     }
 
-    /**
-     * @inheritDoc
-     */
     @Override
     public ImageProducer getSource() {
         return getBaseImage().getSource();
     }
 
-    /**
-     * @inheritDoc
-     */
     @Override
     public Graphics getGraphics() {
-        return getBaseImage().getGraphics();
-
+        throw new UnsupportedOperationException("getGraphics() not supported"
+                + " on Multi-Resolution Images");
     }
 
-    /**
-     * @inheritDoc
-     */
     @Override
     public Object getProperty(String name, ImageObserver observer) {
         return getBaseImage().getProperty(name, observer);
     }
 
     /**
-     * @return base image
+     * Return the base image representing the best version of the image for
+     * rendering at the default width and height.
+     *
+     * @return the base image of the set of multi-resolution images
+     *
+     * @since 1.9
      */
     protected abstract Image getBaseImage();
-}
+}
\ No newline at end of file
diff --git a/src/share/classes/java/awt/image/BaseMultiResolutionImage.java b/src/share/classes/java/awt/image/BaseMultiResolutionImage.java
new file mode 100644
index 0000000..6530576
--- /dev/null
+++ b/src/share/classes/java/awt/image/BaseMultiResolutionImage.java
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+package java.awt.image;
+
+import java.awt.Image;
+import java.util.List;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Objects;
+
+/**
+ * This class is an array-based implementation of
+ * the {@code AbstractMultiResolutionImage} class.
+ *
+ * This class will implement the
+ * {@code getResolutionVariant(double destImageWidth, double destImageHeight)}
+ * method using a simple algorithm which will return the first image variant
+ * in the array that is large enough to satisfy the rendering request. The
+ * last image in the array will be returned if no suitable image is found
+ * that is as large as the rendering request.
+ * <p>
+ * For best effect the array of images should be sorted with each image being
+ * both wider and taller than the previous image.  The base image need not be
+ * the first image in the array. No exception will be thrown if the images
+ * are not sorted as suggested.
+ *
+ * @see java.awt.Image
+ * @see java.awt.image.MultiResolutionImage
+ * @see java.awt.image.AbstractMultiResolutionImage
+ *
+ * @since 1.9
+ */
+public class BaseMultiResolutionImage extends AbstractMultiResolutionImage {
+
+    private final int baseImageIndex;
+    private final Image[] resolutionVariants;
+
+    /**
+     * Creates a multi-resolution image with the given resolution variants.
+     * The first resolution variant is used as the base image.
+     *
+     * @param resolutionVariants array of resolution variants sorted by image size
+     * @throws IllegalArgumentException if null or zero-length array is passed
+     * @throws NullPointerException if the specified {@code resolutionVariants}
+     *          contains one or more null elements
+     *
+     * @since 1.9
+     */
+    public BaseMultiResolutionImage(Image... resolutionVariants) {
+        this(0, resolutionVariants);
+    }
+
+    /**
+     * Creates a multi-resolution image with the given base image index and
+     * resolution variants.
+     *
+     * @param baseImageIndex the index of base image in the resolution variants
+     *        array
+     * @param resolutionVariants array of resolution variants sorted by image size
+     * @throws IllegalArgumentException if null or zero-length array is passed
+     * @throws NullPointerException if the specified {@code resolutionVariants}
+     *          contains one or more null elements
+     * @throws IndexOutOfBoundsException if {@code baseImageIndex} is
+     *          negative or greater than or equal to {@code resolutionVariants}
+     *          length.
+     *
+     * @since 1.9
+     */
+    public BaseMultiResolutionImage(int baseImageIndex,
+                                    Image... resolutionVariants) {
+
+        if (resolutionVariants == null || resolutionVariants.length == 0) {
+            throw new IllegalArgumentException(
+                    "Null or zero-length array is passed");
+        }
+
+        if (baseImageIndex < 0 || baseImageIndex >= resolutionVariants.length) {
+            throw new IndexOutOfBoundsException("Invalid base image index: "
+                    + baseImageIndex);
+        }
+
+        this.baseImageIndex = baseImageIndex;
+        this.resolutionVariants = Arrays.copyOf(resolutionVariants,
+                                                resolutionVariants.length);
+
+        for (Image resolutionVariant : this.resolutionVariants) {
+            Objects.requireNonNull(resolutionVariant,
+                                   "Resolution variant can't be null");
+        }
+    }
+
+    @Override
+    public Image getResolutionVariant(double destImageWidth,
+                                      double destImageHeight) {
+
+        checkSize(destImageWidth, destImageHeight);
+
+        for (Image rvImage : resolutionVariants) {
+            if (destImageWidth <= rvImage.getWidth(null)
+                    && destImageHeight <= rvImage.getHeight(null)) {
+                return rvImage;
+            }
+        }
+        return resolutionVariants[resolutionVariants.length - 1];
+    }
+
+    private static void checkSize(double width, double height) {
+        if (width <= 0 || height <= 0) {
+            throw new IllegalArgumentException(String.format(
+                    "Width (%s) or height (%s) cannot be <= 0", width, height));
+        }
+
+        if (!Double.isFinite(width) || !Double.isFinite(height)) {
+            throw new IllegalArgumentException(String.format(
+                    "Width (%s) or height (%s) is not finite", width, height));
+        }
+    }
+
+    @Override
+    public List<Image> getResolutionVariants() {
+        return Collections.unmodifiableList(Arrays.asList(resolutionVariants));
+    }
+
+    @Override
+    protected Image getBaseImage() {
+        return resolutionVariants[baseImageIndex];
+    }
+}
\ No newline at end of file
diff --git a/src/share/classes/java/awt/image/MultiResolutionImage.java b/src/share/classes/java/awt/image/MultiResolutionImage.java
new file mode 100644
index 0000000..26b4b53
--- /dev/null
+++ b/src/share/classes/java/awt/image/MultiResolutionImage.java
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+package java.awt.image;
+
+import java.awt.Image;
+import java.util.List;
+
+/**
+ * This interface is designed to be an optional additional API supported by
+ * some implementations of {@link java.awt.Image} to allow them to provide
+ * alternate images for various rendering resolutions. The various
+ * {@code Graphics.drawImage(...)} variant methods will consult the methods
+ * of this interface if it is implemented on the argument {@code Image} object
+ * in order to choose the best representation to use for each rendering operation.
+ * <p>
+ * The {@code MultiResolutionImage} interface should be implemented by any
+ * subclass of {@code java.awt.Image} whose instances are intended to provide
+ * image resolution variants according to the given image width and height.
+ * For convenience, toolkit images obtained from
+ * {@code Toolkit.getImage(String name)} and {@code Toolkit.getImage(URL url)}
+ * will implement this interface on platforms that support naming conventions
+ * for resolution variants of stored image media and the
+ * {@code AbstractMultiResolutionImage} and {@code BaseMultiResolutionImage}
+ * classes are provided to facilitate easy construction of custom multi-resolution
+ * images from a list of related images.
+ *
+ * @see java.awt.Image
+ * @see java.awt.image.AbstractMultiResolutionImage
+ * @see java.awt.image.BaseMultiResolutionImage
+ * @see java.awt.Toolkit#getImage(java.lang.String filename)
+ * @see java.awt.Toolkit#getImage(java.net.URL url)
+ *
+ * @since 1.9
+ */
+public interface MultiResolutionImage {
+
+    /**
+     * Gets a specific image that is the best variant to represent
+     * this logical image at the indicated size.
+     *
+     * @param destImageWidth the width of the destination image, in pixels.
+     * @param destImageHeight the height of the destination image, in pixels.
+     * @return image resolution variant.
+     * @throws IllegalArgumentException if {@code destImageWidth} or
+     *         {@code destImageHeight} is less than or equal to zero, infinity,
+     *         or NaN.
+     *
+     * @since 1.9
+     */
+    Image getResolutionVariant(double destImageWidth, double destImageHeight);
+
+    /**
+     * Gets a readable list of all resolution variants.
+     * The list must be nonempty and contain at least one resolution variant.
+     * <p>
+     * Note that many implementations might return an unmodifiable list.
+     * <p>
+     * @return list of resolution variants.
+     * @since 1.9
+     */
+    public List<Image> getResolutionVariants();
+}
\ No newline at end of file
diff --git a/src/share/classes/javax/swing/plaf/basic/icons/JavaCup16.png b/src/share/classes/javax/swing/plaf/basic/icons/JavaCup16.png
index 910dac1..47d75b7 100644
--- a/src/share/classes/javax/swing/plaf/basic/icons/JavaCup16.png
+++ b/src/share/classes/javax/swing/plaf/basic/icons/JavaCup16.png
Binary files differ
diff --git a/src/share/classes/javax/swing/text/PlainView.java b/src/share/classes/javax/swing/text/PlainView.java
index 3d91d86..4d300c8 100644
--- a/src/share/classes/javax/swing/text/PlainView.java
+++ b/src/share/classes/javax/swing/text/PlainView.java
@@ -27,6 +27,7 @@
 import java.util.Vector;
 import java.util.Properties;
 import java.awt.*;
+import java.util.Objects;
 import javax.swing.event.*;
 
 /**
@@ -203,7 +204,8 @@
     protected void updateMetrics() {
         Component host = getContainer();
         Font f = host.getFont();
-        if (font != f) {
+        FontMetrics fm = (font == null) ? null : host.getFontMetrics(font);
+        if (font != f || !Objects.equals(metrics, fm)) {
             // The font changed, we need to recalculate the
             // longest line.
             calculateLongestLine();
diff --git a/src/share/classes/sun/awt/AWTAccessor.java b/src/share/classes/sun/awt/AWTAccessor.java
index 0470dad..b0cd8fe 100644
--- a/src/share/classes/sun/awt/AWTAccessor.java
+++ b/src/share/classes/sun/awt/AWTAccessor.java
@@ -43,6 +43,7 @@
 import java.io.File;
 import java.util.ResourceBundle;
 import java.util.Vector;
+import java.util.function.BooleanSupplier;
 
 /**
  * The AWTAccessor utility class.
@@ -516,6 +517,11 @@
          * Gets most recent event time in the EventQueue
          */
         long getMostRecentEventTime(EventQueue eventQueue);
+
+        /**
+         * Creates a secondary loop with the provided condition.
+         */
+        SecondaryLoop createSecondaryLoop(EventQueue eventQueue, BooleanSupplier cond);
     }
 
     /*
diff --git a/src/share/classes/sun/awt/ExtendedKeyCodes.java b/src/share/classes/sun/awt/ExtendedKeyCodes.java
index fc004ba..76d2579 100644
--- a/src/share/classes/sun/awt/ExtendedKeyCodes.java
+++ b/src/share/classes/sun/awt/ExtendedKeyCodes.java
@@ -139,6 +139,50 @@
          regularKeyCodesMap.put(0x7F, KeyEvent.VK_DELETE);
          regularKeyCodesMap.put(0xA1, KeyEvent.VK_INVERTED_EXCLAMATION_MARK);
 
+
+         regularKeyCodesMap.put(0xF701, KeyEvent.VK_DOWN);    // NSDownArrowFunctionKey
+         regularKeyCodesMap.put(0xF702, KeyEvent.VK_LEFT);    // NSLeftArrowFunctionKey
+         regularKeyCodesMap.put(0xF703, KeyEvent.VK_RIGHT);   // NSRightArrowFunctionKey
+         regularKeyCodesMap.put(0xF704, KeyEvent.VK_F1);      // NSF1FunctionKey
+         regularKeyCodesMap.put(0xF705, KeyEvent.VK_F2);      // NSF2FunctionKey
+         regularKeyCodesMap.put(0xF706, KeyEvent.VK_F3);      // NSF3FunctionKey
+         regularKeyCodesMap.put(0xF707, KeyEvent.VK_F4);      // NSF4FunctionKey
+         regularKeyCodesMap.put(0xF708, KeyEvent.VK_F5);      // NSF5FunctionKey
+         regularKeyCodesMap.put(0xF709, KeyEvent.VK_F6);      // NSF6FunctionKey
+         regularKeyCodesMap.put(0xF70A, KeyEvent.VK_F7);      // NSF7FunctionKey
+         regularKeyCodesMap.put(0xF70B, KeyEvent.VK_F8);      // NSF8FunctionKey
+         regularKeyCodesMap.put(0xF70C, KeyEvent.VK_F9);      // NSF9FunctionKey
+         regularKeyCodesMap.put(0xF70D, KeyEvent.VK_F10);     // NSF10FunctionKey
+         regularKeyCodesMap.put(0xF70E, KeyEvent.VK_F11);     // NSF11FunctionKey
+         regularKeyCodesMap.put(0xF70F, KeyEvent.VK_F12);     // NSF12FunctionKey
+         regularKeyCodesMap.put(0xF710, KeyEvent.VK_F13);     // NSF13FunctionKey
+         regularKeyCodesMap.put(0xF711, KeyEvent.VK_F14);     // NSF14FunctionKey
+         regularKeyCodesMap.put(0xF712, KeyEvent.VK_F15);     // NSF15FunctionKey
+         regularKeyCodesMap.put(0xF713, KeyEvent.VK_F16);     // NSF16FunctionKey
+         regularKeyCodesMap.put(0xF714, KeyEvent.VK_F17);     // NSF17FunctionKey
+         regularKeyCodesMap.put(0xF715, KeyEvent.VK_F18);     // NSF18FunctionKey
+         regularKeyCodesMap.put(0xF716, KeyEvent.VK_F19);     // NSF19FunctionKey
+         regularKeyCodesMap.put(0xF717, KeyEvent.VK_F20);     // NSF20FunctionKey
+         regularKeyCodesMap.put(0xF718, KeyEvent.VK_F21);     // NSF21FunctionKey
+         regularKeyCodesMap.put(0xF719, KeyEvent.VK_F22);     // NSF22FunctionKey
+         regularKeyCodesMap.put(0xF71A, KeyEvent.VK_F23);     // NSF23FunctionKey
+         regularKeyCodesMap.put(0xF71B, KeyEvent.VK_F24);     // NSF24FunctionKey
+         regularKeyCodesMap.put(0xF727, KeyEvent.VK_INSERT);    // NSInsertFunctionKey
+         regularKeyCodesMap.put(0xF728, KeyEvent.VK_DELETE);    // NSDeleteFunctionKey
+         regularKeyCodesMap.put(0xF729, KeyEvent.VK_HOME);    // NSHomeFunctionKey
+         regularKeyCodesMap.put(0xF72A, KeyEvent.VK_BEGIN);    // NSBeginFunctionKey
+         regularKeyCodesMap.put(0xF72B, KeyEvent.VK_END);    // NSEndFunctionKey
+         regularKeyCodesMap.put(0xF72C, KeyEvent.VK_PAGE_UP);    // NSPageUpFunctionKey
+         regularKeyCodesMap.put(0xF72D, KeyEvent.VK_PAGE_DOWN);    // NSPageDownFunctionKey
+         regularKeyCodesMap.put(0xF72E, KeyEvent.VK_PRINTSCREEN);    // NSPrintScreenFunctionKey
+         regularKeyCodesMap.put(0xF72F, KeyEvent.VK_SCROLL_LOCK);    // NSScrollLockFunctionKey
+         regularKeyCodesMap.put(0xF730, KeyEvent.VK_PAUSE);    // NSPauseFunctionKey
+         regularKeyCodesMap.put(0xF734, KeyEvent.VK_STOP);    // NSStopFunctionKey
+         regularKeyCodesMap.put(0xF735, KeyEvent.VK_CONTEXT_MENU);    // NSMenuFunctionKey
+         regularKeyCodesMap.put(0xF738, KeyEvent.VK_PRINTSCREEN);    // NSPrintFunctionKey
+         regularKeyCodesMap.put(0xF739, KeyEvent.VK_CLEAR);    // NSClearLineFunctionKey
+         regularKeyCodesMap.put(0xF746, KeyEvent.VK_HELP);    // NSHelpFunctionKey
+
          extendedKeyCodesSet.add(0x01000000+0x0060);
          extendedKeyCodesSet.add(0x01000000+0x007C);
          extendedKeyCodesSet.add(0x01000000+0x007E);
diff --git a/src/share/classes/sun/awt/SunHints.java b/src/share/classes/sun/awt/SunHints.java
index 15c7e54..b82e056 100644
--- a/src/share/classes/sun/awt/SunHints.java
+++ b/src/share/classes/sun/awt/SunHints.java
@@ -257,8 +257,10 @@
      */
     @Native public static final int INTKEY_RESOLUTION_VARIANT = 9;
     @Native public static final int INTVAL_RESOLUTION_VARIANT_DEFAULT = 0;
-    @Native public static final int INTVAL_RESOLUTION_VARIANT_OFF = 1;
-    @Native public static final int INTVAL_RESOLUTION_VARIANT_ON = 2;
+    @Native public static final int INTVAL_RESOLUTION_VARIANT_BASE = 1;
+    @Native public static final int INTVAL_RESOLUTION_VARIANT_SIZE_FIT = 2;
+    @Native public static final int INTVAL_RESOLUTION_VARIANT_DPI_FIT = 3;
+
     /**
      * LCD text contrast control hint key.
      * Value is "100" to make discontiguous with the others which
@@ -466,15 +468,23 @@
     public static final Object VALUE_RESOLUTION_VARIANT_DEFAULT =
         new SunHints.Value(KEY_RESOLUTION_VARIANT,
                            SunHints.INTVAL_RESOLUTION_VARIANT_DEFAULT,
-                           "Choose image resolutions based on a default heuristic");
-    public static final Object VALUE_RESOLUTION_VARIANT_OFF =
+                           "Choose image resolutions based on a default"
+                                   + "heuristic");
+    public static final Object VALUE_RESOLUTION_VARIANT_BASE =
         new SunHints.Value(KEY_RESOLUTION_VARIANT,
-                           SunHints.INTVAL_RESOLUTION_VARIANT_OFF,
+                           SunHints.INTVAL_RESOLUTION_VARIANT_BASE,
                            "Use only the standard resolution of an image");
-    public static final Object VALUE_RESOLUTION_VARIANT_ON =
+    public static final Object VALUE_RESOLUTION_VARIANT_SIZE_FIT =
         new SunHints.Value(KEY_RESOLUTION_VARIANT,
-                           SunHints.INTVAL_RESOLUTION_VARIANT_ON,
-                           "Always use resolution-specific variants of images");
+                           SunHints.INTVAL_RESOLUTION_VARIANT_SIZE_FIT,
+                           "Choose image resolutions based on the DPI"
+                                   + "of the screen and transform"
+                                   + "in the Graphics2D context");
+    public static final Object VALUE_RESOLUTION_VARIANT_DPI_FIT =
+        new SunHints.Value(KEY_RESOLUTION_VARIANT,
+                           SunHints.INTVAL_RESOLUTION_VARIANT_DPI_FIT,
+                           "Choose image resolutions based only on the DPI"
+                                   + " of the screen");
 
     public static class LCDContrastKey extends Key {
 
diff --git a/src/share/classes/sun/awt/SunToolkit.java b/src/share/classes/sun/awt/SunToolkit.java
index 6269645..e88201e 100644
--- a/src/share/classes/sun/awt/SunToolkit.java
+++ b/src/share/classes/sun/awt/SunToolkit.java
@@ -52,6 +52,7 @@
 import sun.misc.SoftCache;
 import sun.font.FontDesignMetrics;
 import sun.awt.im.InputContext;
+import java.awt.image.MultiResolutionImage;
 import sun.awt.image.*;
 import sun.net.util.URLUtil;
 import sun.security.action.GetPropertyAction;
@@ -624,6 +625,25 @@
         }
     }
 
+    /**
+     * Must be called on the Event Dispatching thread.
+     * <p>
+     * Executes the runnable so that it can perform a non-blocking invocation on the toolkit thread.
+     * By default executes the runnable in place. Toolkits which can not rely on the default behavior
+     * provide platform-specific implementation to ensure the non-blocking invocation.
+     * <p>
+     * The method may be unsafe and is only used (externally) in critical deadlock-prone cases.
+     *
+     * @param runnable the runnable to execute
+     * @throws Error when called on not Event Dispatching thread
+     */
+    public void unsafeNonblockingExecute(Runnable runnable) {
+        if (!EventQueue.isDispatchThread()) {
+            throw new Error("the method must be called on the Event Dispatching thread");
+        }
+        if (runnable != null) runnable.run();
+    }
+
     /*
      * Returns true if the calling thread is the event dispatch thread
      * contained within AppContext which associated with the given target.
diff --git a/src/share/classes/sun/awt/datatransfer/DataTransferer.java b/src/share/classes/sun/awt/datatransfer/DataTransferer.java
index a5bd0f5..d990b70 100644
--- a/src/share/classes/sun/awt/datatransfer/DataTransferer.java
+++ b/src/share/classes/sun/awt/datatransfer/DataTransferer.java
@@ -25,95 +25,36 @@
 
 package sun.awt.datatransfer;
 
-import java.awt.EventQueue;
-import java.awt.Graphics;
-import java.awt.Image;
-import java.awt.Toolkit;
+import sun.awt.AppContext;
+import sun.awt.ComponentFactory;
+import sun.awt.SunToolkit;
+import sun.awt.image.ImageRepresentation;
+import sun.awt.image.ToolkitImage;
+import sun.util.logging.PlatformLogger;
 
-import java.awt.datatransfer.DataFlavor;
-import java.awt.datatransfer.FlavorMap;
-import java.awt.datatransfer.FlavorTable;
-import java.awt.datatransfer.Transferable;
-import java.awt.datatransfer.UnsupportedFlavorException;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Reader;
-import java.io.SequenceInputStream;
-import java.io.StringReader;
-
+import javax.imageio.*;
+import javax.imageio.spi.ImageWriterSpi;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.ImageOutputStream;
+import java.awt.*;
+import java.awt.datatransfer.*;
+import java.awt.image.*;
+import java.io.*;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.net.URI;
 import java.net.URISyntaxException;
-
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetEncoder;
 import java.nio.charset.IllegalCharsetNameException;
 import java.nio.charset.UnsupportedCharsetException;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
-import java.security.ProtectionDomain;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
+import java.security.*;
+import java.util.*;
 import java.util.List;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.SortedSet;
-import java.util.Set;
-import java.util.Stack;
-import java.util.TreeMap;
-import java.util.TreeSet;
-
-import sun.awt.ComponentFactory;
-import sun.util.logging.PlatformLogger;
-
-import sun.awt.AppContext;
-import sun.awt.SunToolkit;
-
-import java.awt.image.BufferedImage;
-import java.awt.image.ImageObserver;
-import java.awt.image.RenderedImage;
-import java.awt.image.WritableRaster;
-import java.awt.image.ColorModel;
-
-import javax.imageio.ImageIO;
-import javax.imageio.ImageReader;
-import javax.imageio.ImageReadParam;
-import javax.imageio.ImageWriter;
-import javax.imageio.ImageTypeSpecifier;
-
-import javax.imageio.spi.ImageWriterSpi;
-
-import javax.imageio.stream.ImageInputStream;
-import javax.imageio.stream.ImageOutputStream;
-
-import sun.awt.image.ImageRepresentation;
-import sun.awt.image.ToolkitImage;
-
-import java.io.FilePermission;
 
 
 /**
diff --git a/src/share/classes/sun/awt/image/BufImgSurfaceData.java b/src/share/classes/sun/awt/image/BufImgSurfaceData.java
index efc4bc9..9ccc484 100644
--- a/src/share/classes/sun/awt/image/BufImgSurfaceData.java
+++ b/src/share/classes/sun/awt/image/BufImgSurfaceData.java
@@ -50,6 +50,8 @@
     BufferedImage bufImg;
     private BufferedImageGraphicsConfig graphicsConfig;
     RenderLoops solidloops;
+    private final double scaleX;
+    private final double scaleY;
 
     private static native void initIDs(Class ICM, Class ICMColorData);
 
@@ -73,6 +75,12 @@
     }
 
     public static SurfaceData createData(BufferedImage bufImg) {
+        return createData(bufImg, 1, 1);
+    }
+
+    public static SurfaceData createData(BufferedImage bufImg,
+                                         double scaleX, double scaleY)
+    {
         if (bufImg == null) {
             throw new NullPointerException("BufferedImage cannot be null");
         }
@@ -82,31 +90,36 @@
         // REMIND: Check the image type and pick an appropriate subclass
         switch (type) {
         case BufferedImage.TYPE_INT_BGR:
-            sData = createDataIC(bufImg, SurfaceType.IntBgr);
+            sData = createDataIC(bufImg, SurfaceType.IntBgr, scaleX, scaleY);
             break;
         case BufferedImage.TYPE_INT_RGB:
-            sData = createDataIC(bufImg, SurfaceType.IntRgb);
+            sData = createDataIC(bufImg, SurfaceType.IntRgb, scaleX, scaleY);
             break;
         case BufferedImage.TYPE_INT_ARGB:
-            sData = createDataIC(bufImg, SurfaceType.IntArgb);
+            sData = createDataIC(bufImg, SurfaceType.IntArgb, scaleX, scaleY);
             break;
         case BufferedImage.TYPE_INT_ARGB_PRE:
-            sData = createDataIC(bufImg, SurfaceType.IntArgbPre);
+            sData = createDataIC(bufImg, SurfaceType.IntArgbPre, scaleX, scaleY);
             break;
         case BufferedImage.TYPE_3BYTE_BGR:
-            sData = createDataBC(bufImg, SurfaceType.ThreeByteBgr, 2);
+            sData = createDataBC(bufImg, SurfaceType.ThreeByteBgr, 2,
+                                 scaleX, scaleY);
             break;
         case BufferedImage.TYPE_4BYTE_ABGR:
-            sData = createDataBC(bufImg, SurfaceType.FourByteAbgr, 3);
+            sData = createDataBC(bufImg, SurfaceType.FourByteAbgr, 3,
+                                 scaleX, scaleY);
             break;
         case BufferedImage.TYPE_4BYTE_ABGR_PRE:
-            sData = createDataBC(bufImg, SurfaceType.FourByteAbgrPre, 3);
+            sData = createDataBC(bufImg, SurfaceType.FourByteAbgrPre, 3,
+                                 scaleX, scaleY);
             break;
         case BufferedImage.TYPE_USHORT_565_RGB:
-            sData = createDataSC(bufImg, SurfaceType.Ushort565Rgb, null);
+            sData = createDataSC(bufImg, SurfaceType.Ushort565Rgb, null,
+                                 scaleX, scaleY);
             break;
         case BufferedImage.TYPE_USHORT_555_RGB:
-            sData = createDataSC(bufImg, SurfaceType.Ushort555Rgb, null);
+            sData = createDataSC(bufImg, SurfaceType.Ushort555Rgb, null,
+                                 scaleX, scaleY);
             break;
         case BufferedImage.TYPE_BYTE_INDEXED:
             {
@@ -128,14 +141,16 @@
                 default:
                     throw new InternalError("Unrecognized transparency");
                 }
-                sData = createDataBC(bufImg, sType, 0);
+                sData = createDataBC(bufImg, sType, 0, scaleX, scaleY);
             }
             break;
         case BufferedImage.TYPE_BYTE_GRAY:
-            sData = createDataBC(bufImg, SurfaceType.ByteGray, 0);
+            sData = createDataBC(bufImg, SurfaceType.ByteGray, 0,
+                                 scaleX, scaleY);
             break;
         case BufferedImage.TYPE_USHORT_GRAY:
-            sData = createDataSC(bufImg, SurfaceType.UshortGray, null);
+            sData = createDataSC(bufImg, SurfaceType.UshortGray, null,
+                                 scaleX, scaleY);
             break;
         case BufferedImage.TYPE_BYTE_BINARY:
             {
@@ -154,7 +169,7 @@
                 default:
                     throw new InternalError("Unrecognized pixel size");
                 }
-                sData = createDataBP(bufImg, sType);
+                sData = createDataBP(bufImg, sType, scaleX, scaleY);
             }
             break;
         case BufferedImage.TYPE_CUSTOM:
@@ -191,7 +206,7 @@
                             sType = SurfaceType.AnyDcm;
                         }
                     }
-                    sData = createDataIC(bufImg, sType);
+                    sData = createDataIC(bufImg, sType, scaleX, scaleY);
                     break;
                 } else if (raster instanceof ShortComponentRaster &&
                            raster.getNumDataElements() == 1 &&
@@ -233,11 +248,12 @@
                             icm = null;
                         }
                     }
-                    sData = createDataSC(bufImg, sType, icm);
+                    sData = createDataSC(bufImg, sType, icm, scaleX, scaleY);
                     break;
                 }
-                sData = new BufImgSurfaceData(raster.getDataBuffer(),
-                                              bufImg, SurfaceType.Custom);
+                sData = new BufImgSurfaceData(raster.getDataBuffer(), bufImg,
+                                              SurfaceType.Custom,
+                                              scaleX, scaleY);
             }
             break;
         }
@@ -250,11 +266,15 @@
     }
 
     public static SurfaceData createDataIC(BufferedImage bImg,
-                                           SurfaceType sType) {
+                                           SurfaceType sType,
+                                           double scaleX,
+                                           double scaleY)
+    {
         IntegerComponentRaster icRaster =
             (IntegerComponentRaster)bImg.getRaster();
         BufImgSurfaceData bisd =
-            new BufImgSurfaceData(icRaster.getDataBuffer(), bImg, sType);
+            new BufImgSurfaceData(icRaster.getDataBuffer(), bImg, sType,
+                                  scaleX, scaleY);
         bisd.initRaster(icRaster.getDataStorage(),
                         icRaster.getDataOffset(0) * 4, 0,
                         icRaster.getWidth(),
@@ -267,11 +287,14 @@
 
     public static SurfaceData createDataSC(BufferedImage bImg,
                                            SurfaceType sType,
-                                           IndexColorModel icm) {
+                                           IndexColorModel icm,
+                                           double scaleX, double scaleY)
+    {
         ShortComponentRaster scRaster =
             (ShortComponentRaster)bImg.getRaster();
         BufImgSurfaceData bisd =
-            new BufImgSurfaceData(scRaster.getDataBuffer(), bImg, sType);
+            new BufImgSurfaceData(scRaster.getDataBuffer(), bImg, sType,
+                                  scaleX, scaleY);
         bisd.initRaster(scRaster.getDataStorage(),
                         scRaster.getDataOffset(0) * 2, 0,
                         scRaster.getWidth(),
@@ -284,11 +307,14 @@
 
     public static SurfaceData createDataBC(BufferedImage bImg,
                                            SurfaceType sType,
-                                           int primaryBank) {
+                                           int primaryBank,
+                                           double scaleX, double scaleY)
+    {
         ByteComponentRaster bcRaster =
             (ByteComponentRaster)bImg.getRaster();
         BufImgSurfaceData bisd =
-            new BufImgSurfaceData(bcRaster.getDataBuffer(), bImg, sType);
+            new BufImgSurfaceData(bcRaster.getDataBuffer(), bImg, sType,
+                                  scaleX, scaleY);
         ColorModel cm = bImg.getColorModel();
         IndexColorModel icm = ((cm instanceof IndexColorModel)
                                ? (IndexColorModel) cm
@@ -304,11 +330,14 @@
     }
 
     public static SurfaceData createDataBP(BufferedImage bImg,
-                                           SurfaceType sType) {
+                                           SurfaceType sType,
+                                           double scaleX, double scaleY)
+    {
         BytePackedRaster bpRaster =
             (BytePackedRaster)bImg.getRaster();
         BufImgSurfaceData bisd =
-            new BufImgSurfaceData(bpRaster.getDataBuffer(), bImg, sType);
+            new BufImgSurfaceData(bpRaster.getDataBuffer(), bImg, sType,
+                                  scaleX, scaleY);
         ColorModel cm = bImg.getColorModel();
         IndexColorModel icm = ((cm instanceof IndexColorModel)
                                ? (IndexColorModel) cm
@@ -350,15 +379,22 @@
                                      IndexColorModel icm);
 
     public BufImgSurfaceData(DataBuffer db,
-                             BufferedImage bufImg, SurfaceType sType)
+                             BufferedImage bufImg,
+                             SurfaceType sType,
+                             double scaleX,
+                             double scaleY)
     {
         super(SunWritableRaster.stealTrackable(db),
               sType, bufImg.getColorModel());
         this.bufImg = bufImg;
+        this.scaleX = scaleX;
+        this.scaleY = scaleY;
     }
 
     protected BufImgSurfaceData(SurfaceType surfaceType, ColorModel cm) {
         super(surfaceType, cm);
+        this.scaleX = 1;
+        this.scaleY = 1;
     }
 
     public void initSolidLoops() {
@@ -395,7 +431,8 @@
 
     public synchronized GraphicsConfiguration getDeviceConfiguration() {
         if (graphicsConfig == null) {
-            graphicsConfig = BufferedImageGraphicsConfig.getConfig(bufImg);
+            graphicsConfig = BufferedImageGraphicsConfig
+                    .getConfig(bufImg, scaleX, scaleY);
         }
         return graphicsConfig;
     }
@@ -418,6 +455,16 @@
         return bufImg;
     }
 
+    @Override
+    public double getDefaultScaleX() {
+        return scaleX;
+    }
+
+    @Override
+    public double getDefaultScaleY() {
+        return scaleY;
+    }
+
     public static final class ICMColorData {
         private long pData = 0L;
 
diff --git a/src/share/classes/sun/awt/image/BufferedImageGraphicsConfig.java b/src/share/classes/sun/awt/image/BufferedImageGraphicsConfig.java
index dd831a6..6a04f76 100644
--- a/src/share/classes/sun/awt/image/BufferedImageGraphicsConfig.java
+++ b/src/share/classes/sun/awt/image/BufferedImageGraphicsConfig.java
@@ -45,19 +45,32 @@
     extends GraphicsConfiguration
 {
     private static final int numconfigs = BufferedImage.TYPE_BYTE_BINARY;
-    private static BufferedImageGraphicsConfig configs[] =
+    private static BufferedImageGraphicsConfig standardConfigs[] =
+        new BufferedImageGraphicsConfig[numconfigs];
+    private static BufferedImageGraphicsConfig scaledConfigs[] =
         new BufferedImageGraphicsConfig[numconfigs];
 
     public static BufferedImageGraphicsConfig getConfig(BufferedImage bImg) {
+        return getConfig(bImg, 1, 1);
+    }
+
+    public static BufferedImageGraphicsConfig getConfig(BufferedImage bImg,
+                                                        double scaleX,
+                                                        double scaleY)
+    {
         BufferedImageGraphicsConfig ret;
         int type = bImg.getType();
+
+        BufferedImageGraphicsConfig[] configs = (scaleX == 1 && scaleY == 1)
+                ? standardConfigs : scaledConfigs;
+
         if (type > 0 && type < numconfigs) {
             ret = configs[type];
-            if (ret != null) {
+            if (ret != null && ret.scaleX == scaleX && ret.scaleY == scaleY) {
                 return ret;
             }
         }
-        ret = new BufferedImageGraphicsConfig(bImg, null);
+        ret = new BufferedImageGraphicsConfig(bImg, null, scaleX, scaleY);
         if (type > 0 && type < numconfigs) {
             configs[type] = ret;
         }
@@ -67,9 +80,17 @@
     GraphicsDevice gd;
     ColorModel model;
     Raster raster;
-    int width, height;
+    int width, height; /* tav todo: remove */
+    private final double scaleX;
+    private final double scaleY;
 
     public BufferedImageGraphicsConfig(BufferedImage bufImg, Component comp) {
+        this(bufImg, comp, 1, 1);
+    }
+
+    public BufferedImageGraphicsConfig(BufferedImage bufImg, Component comp,
+                                       double scaleX, double scaleY)
+    {
         if (comp == null) {
             this.gd = new BufferedImageDevice(this);
         } else {
@@ -80,6 +101,8 @@
         this.raster = bufImg.getRaster().createCompatibleWritableRaster(1, 1);
         this.width = bufImg.getWidth();
         this.height = bufImg.getHeight();
+        this.scaleX = scaleX;
+        this.scaleY = scaleY;
     }
 
     /**
@@ -141,7 +164,7 @@
      * For image buffers, this Transform will be the Identity transform.
      */
     public AffineTransform getDefaultTransform() {
-        return new AffineTransform();
+        return AffineTransform.getScaleInstance(scaleX, scaleY);
     }
 
     /**
diff --git a/src/share/classes/sun/awt/image/MultiResolutionCachedImage.java b/src/share/classes/sun/awt/image/MultiResolutionCachedImage.java
index b1c6dae..72a3293 100644
--- a/src/share/classes/sun/awt/image/MultiResolutionCachedImage.java
+++ b/src/share/classes/sun/awt/image/MultiResolutionCachedImage.java
@@ -33,6 +33,7 @@
 import java.util.function.Function;
 import java.util.function.BiFunction;
 import java.util.stream.Collectors;
+import java.awt.image.AbstractMultiResolutionImage;
 
 public class MultiResolutionCachedImage extends AbstractMultiResolutionImage {
 
@@ -58,7 +59,10 @@
     }
 
     @Override
-    public Image getResolutionVariant(int width, int height) {
+    public Image getResolutionVariant(double destWidth, double destHeight) {
+        checkSize(destWidth, destHeight);
+        int width = (int) Math.ceil(destWidth);
+        int height = (int) Math.ceil(destHeight);
         ImageCache cache = ImageCache.getInstance();
         ImageCacheKey key = new ImageCacheKey(this, width, height);
         Image resolutionVariant = cache.getImage(key);
@@ -70,11 +74,23 @@
         return resolutionVariant;
     }
 
+    private static void checkSize(double width, double height) {
+        if (width <= 0 || height <= 0) {
+            throw new IllegalArgumentException(String.format(
+                    "Width (%s) or height (%s) cannot be <= 0", width, height));
+        }
+
+        if (!Double.isFinite(width) || !Double.isFinite(height)) {
+            throw new IllegalArgumentException(String.format(
+                    "Width (%s) or height (%s) is not finite", width, height));
+        }
+    }
+
     @Override
     public List<Image> getResolutionVariants() {
         return Arrays.stream(sizes).map((Function<Dimension2D, Image>) size
-                -> getResolutionVariant((int) size.getWidth(),
-                        (int) size.getHeight())).collect(Collectors.toList());
+                -> getResolutionVariant(size.getWidth(), size.getHeight()))
+                .collect(Collectors.toList());
     }
 
     public MultiResolutionCachedImage map(Function<Image, Image> mapper) {
diff --git a/src/share/classes/sun/awt/image/MultiResolutionImage.java b/src/share/classes/sun/awt/image/MultiResolutionImage.java
deleted file mode 100644
index 40be02e..0000000
--- a/src/share/classes/sun/awt/image/MultiResolutionImage.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (c) 2013, 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.
- */
-package sun.awt.image;
-
-import java.awt.Image;
-import java.util.List;
-
-/**
- * This interface is designed to provide a set of images at various resolutions.
- *
- * The <code>MultiResolutionImage</code> interface should be implemented by any
- * class whose instances are intended to provide image resolution variants
- * according to the given image width and height.
- *
- * For example,
- * <pre>
- * {@code
- *  public class ScaledImage extends BufferedImage
- *         implements MultiResolutionImage {
- *
- *    @Override
- *    public Image getResolutionVariant(int width, int height) {
- *      return ((width <= getWidth() && height <= getHeight()))
- *             ? this : highResolutionImage;
- *    }
- *
- *    @Override
- *    public List<Image> getResolutionVariants() {
- *        return Arrays.asList(this, highResolutionImage);
- *    }
- *  }
- * }</pre>
- *
- * It is recommended to cache image variants for performance reasons.
- *
- * <b>WARNING</b>: This class is an implementation detail. This API may change
- * between update release, and it may even be removed or be moved in some other
- * package(s)/class(es).
- */
-public interface MultiResolutionImage {
-
-    /**
-     * Provides an image with necessary resolution which best fits to the given
-     * image width and height.
-     *
-     * @param width the desired image resolution width.
-     * @param height the desired image resolution height.
-     * @return image resolution variant.
-     *
-     * @since JDK1.8
-     */
-    public Image getResolutionVariant(int width, int height);
-
-    /**
-     * Gets list of all resolution variants including the base image
-     *
-     * @return list of resolution variants.
-     * @since JDK1.8
-     */
-    public List<Image> getResolutionVariants();
-}
diff --git a/src/share/classes/sun/awt/image/MultiResolutionToolkitImage.java b/src/share/classes/sun/awt/image/MultiResolutionToolkitImage.java
index 46ef09f..21d5aa5 100644
--- a/src/share/classes/sun/awt/image/MultiResolutionToolkitImage.java
+++ b/src/share/classes/sun/awt/image/MultiResolutionToolkitImage.java
@@ -26,6 +26,7 @@
 
 import java.awt.Image;
 import java.awt.image.ImageObserver;
+import java.awt.image.MultiResolutionImage;
 import java.util.Arrays;
 import java.util.List;
 import sun.misc.SoftCache;
@@ -40,11 +41,24 @@
     }
 
     @Override
-    public Image getResolutionVariant(int width, int height) {
-        return ((width <= getWidth() && height <= getHeight()))
+    public Image getResolutionVariant(double destWidth, double destHeight) {
+        checkSize(destWidth, destHeight);
+        return ((destWidth <= getWidth() && destHeight <= getHeight()))
                 ? this : resolutionVariant;
     }
 
+    private static void checkSize(double width, double height) {
+        if (width <= 0 || height <= 0) {
+            throw new IllegalArgumentException(String.format(
+                    "Width (%s) or height (%s) cannot be <= 0", width, height));
+        }
+
+        if (!Double.isFinite(width) || !Double.isFinite(height)) {
+            throw new IllegalArgumentException(String.format(
+                    "Width (%s) or height (%s) is not finite", width, height));
+        }
+    }
+
     public Image getResolutionVariant() {
         return resolutionVariant;
     }
diff --git a/src/share/classes/sun/awt/image/SunVolatileImage.java b/src/share/classes/sun/awt/image/SunVolatileImage.java
index e5e8ca9..1ee5c40 100644
--- a/src/share/classes/sun/awt/image/SunVolatileImage.java
+++ b/src/share/classes/sun/awt/image/SunVolatileImage.java
@@ -237,8 +237,17 @@
      * or a backup surface.
      */
     public BufferedImage getBackupImage() {
-        return graphicsConfig.createCompatibleImage(getWidth(), getHeight(),
-                                                    getTransparency());
+        return getBackupImage(1, 1);
+    }
+
+    /**
+     * This method creates a BufferedImage intended for use as a "snapshot"
+     * or a backup surface with the given horizontal and vertical scale factors.
+     */
+    public BufferedImage getBackupImage(double scaleX, double scaleY) {
+        int w = (int) Math.ceil(getWidth() * scaleX);
+        int h = (int) Math.ceil(getHeight() * scaleY);
+        return graphicsConfig.createCompatibleImage(w, h, getTransparency());
     }
 
     public BufferedImage getSnapshot() {
diff --git a/src/share/classes/sun/awt/image/SurfaceManager.java b/src/share/classes/sun/awt/image/SurfaceManager.java
index 887ad5a..384bf5a 100644
--- a/src/share/classes/sun/awt/image/SurfaceManager.java
+++ b/src/share/classes/sun/awt/image/SurfaceManager.java
@@ -290,16 +290,30 @@
     }
 
     /**
-     * Returns a scale factor of the image. This is utility method, which
-     * fetches information from the SurfaceData of the image.
+     * Returns a horizontal scale factor of the image. This is utility method,
+     * which fetches information from the SurfaceData of the image.
      *
-     * @see SurfaceData#getDefaultScale
+     * @see SurfaceData#getDefaultScaleX
      */
-    public static int getImageScale(final Image img) {
+    public static double getImageScaleX(final Image img) {
         if (!(img instanceof VolatileImage)) {
             return 1;
         }
         final SurfaceManager sm = getManager(img);
-        return sm.getPrimarySurfaceData().getDefaultScale();
+        return sm.getPrimarySurfaceData().getDefaultScaleX();
+    }
+
+    /**
+     * Returns a vertical scale factor of the image. This is utility method,
+     * which fetches information from the SurfaceData of the image.
+     *
+     * @see SurfaceData#getDefaultScaleY
+     */
+    public static double getImageScaleY(final Image img) {
+        if (!(img instanceof VolatileImage)) {
+            return 1;
+        }
+        final SurfaceManager sm = getManager(img);
+        return sm.getPrimarySurfaceData().getDefaultScaleY();
     }
 }
diff --git a/src/share/classes/sun/awt/image/VolatileSurfaceManager.java b/src/share/classes/sun/awt/image/VolatileSurfaceManager.java
index b20f203..6d6b62b 100644
--- a/src/share/classes/sun/awt/image/VolatileSurfaceManager.java
+++ b/src/share/classes/sun/awt/image/VolatileSurfaceManager.java
@@ -25,18 +25,16 @@
 
 package sun.awt.image;
 
-import java.awt.Color;
 import java.awt.Graphics;
 import java.awt.GraphicsConfiguration;
 import java.awt.GraphicsEnvironment;
 import java.awt.ImageCapabilities;
+import java.awt.geom.AffineTransform;
 import java.awt.image.BufferedImage;
 import java.awt.image.VolatileImage;
 import sun.awt.DisplayChangedListener;
-import sun.awt.image.SunVolatileImage;
 import sun.java2d.SunGraphicsEnvironment;
 import sun.java2d.SurfaceData;
-import sun.java2d.loops.CompositeType;
 import static sun.java2d.pipe.hw.AccelSurface.*;
 
 /**
@@ -260,12 +258,16 @@
      */
     protected SurfaceData getBackupSurface() {
         if (sdBackup == null) {
-            BufferedImage bImg = vImg.getBackupImage();
+            GraphicsConfiguration gc = vImg.getGraphicsConfig();
+            AffineTransform tx = gc.getDefaultTransform();
+            double scaleX = tx.getScaleX();
+            double scaleY = tx.getScaleY();
+            BufferedImage bImg = vImg.getBackupImage(scaleX, scaleY);
             // Sabotage the acceleration capabilities of the BufImg surface
             SunWritableRaster.stealTrackable(bImg
                                              .getRaster()
                                              .getDataBuffer()).setUntrackable();
-            sdBackup = BufImgSurfaceData.createData(bImg);
+            sdBackup = BufImgSurfaceData.createData(bImg, scaleX, scaleY);
         }
         return sdBackup;
     }
diff --git a/src/share/classes/sun/font/ColorGlyphSurfaceData.java b/src/share/classes/sun/font/ColorGlyphSurfaceData.java
new file mode 100644
index 0000000..e188882
--- /dev/null
+++ b/src/share/classes/sun/font/ColorGlyphSurfaceData.java
@@ -0,0 +1,43 @@
+package sun.font;
+
+import sun.java2d.SurfaceData;
+
+import java.awt.GraphicsConfiguration;
+import java.awt.Rectangle;
+import java.awt.image.Raster;
+
+class ColorGlyphSurfaceData extends SurfaceData {
+    ColorGlyphSurfaceData() {
+        super(State.UNTRACKABLE);
+        initOps();
+    }
+
+    private native void initOps();
+
+    native void setCurrentGlyph(long imgPtr);
+
+    @Override
+    public SurfaceData getReplacement() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public GraphicsConfiguration getDeviceConfiguration() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Raster getRaster(int x, int y, int w, int h) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Rectangle getBounds() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Object getDestination() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/src/share/classes/sun/font/CompositeFont.java b/src/share/classes/sun/font/CompositeFont.java
index a7df046..00da86a 100644
--- a/src/share/classes/sun/font/CompositeFont.java
+++ b/src/share/classes/sun/font/CompositeFont.java
@@ -38,7 +38,7 @@
  * But its probably OK to include it so long as only composites include
  * fallbacks. If physicals do then it would be really confusing ..
  */
-public final class CompositeFont extends Font2D {
+public class CompositeFont extends Font2D {
 
     private boolean[] deferredInitialisation;
     String[] componentFileNames;
@@ -149,6 +149,25 @@
         }
     }
 
+    /*
+     * Build a composite from a set of individual slot fonts.
+     */
+    CompositeFont(PhysicalFont[] slotFonts) {
+
+        isStdComposite = false;
+        handle = new Font2DHandle(this);
+        fullName = slotFonts[0].fullName;
+        familyName = slotFonts[0].familyName;
+        style = slotFonts[0].style;
+
+        numMetricsSlots = 1; /* Only the physical Font */
+        numSlots = slotFonts.length;
+
+        components = new PhysicalFont[numSlots];
+        System.arraycopy(slotFonts, 0, components, 0, numSlots);
+        deferredInitialisation = new boolean[numSlots]; // all false.
+    }
+
     /* This method is currently intended to be called only from
      * FontManager.getCompositeFontUIResource(Font)
      * It creates a new CompositeFont with the contents of the Physical
diff --git a/src/share/classes/sun/font/CompositeGlyphMapper.java b/src/share/classes/sun/font/CompositeGlyphMapper.java
index b8d2b78..d5c4668 100644
--- a/src/share/classes/sun/font/CompositeGlyphMapper.java
+++ b/src/share/classes/sun/font/CompositeGlyphMapper.java
@@ -42,7 +42,7 @@
  * this appears to cause problems.
  */
 
-public final class CompositeGlyphMapper extends CharToGlyphMapper {
+public class CompositeGlyphMapper extends CharToGlyphMapper {
 
     public static final int SLOTMASK =  0xff000000;
     public static final int GLYPHMASK = 0x00ffffff;
@@ -117,7 +117,7 @@
         return mapper;
     }
 
-    private final int convertToGlyph(int unicode) {
+    protected int convertToGlyph(int unicode) {
 
         for (int slot = 0; slot < font.numSlots; slot++) {
             if (!hasExcludes || !font.isExcludedChar(slot, unicode)) {
diff --git a/src/share/classes/sun/font/ExtendedTextSourceLabel.java b/src/share/classes/sun/font/ExtendedTextSourceLabel.java
index 433170b..9dbdff4 100644
--- a/src/share/classes/sun/font/ExtendedTextSourceLabel.java
+++ b/src/share/classes/sun/font/ExtendedTextSourceLabel.java
@@ -550,13 +550,16 @@
     return charinfo;
   }
 
+  private static final boolean DEBUG = FontUtilities.debugFonts();
 /*
 * This takes the glyph info record obtained from the glyph vector and converts it into a similar record
 * adjusted to represent character data instead.  For economy we don't use glyph info records in this processing.
 *
 * Here are some constraints:
 * - there can be more glyphs than characters (glyph insertion, perhaps based on normalization, has taken place)
-* - there can not be fewer glyphs than characters (0xffff glyphs are inserted for characters ligaturized away)
+* - there can be fewer glyphs than characters
+*   Some layout engines may insert 0xffff glyphs for characters ligaturized away, but
+*   not all do, and it cannot be relied upon.
 * - each glyph maps to a single character, when multiple glyphs exist for a character they all map to it, but
 *   no two characters map to the same glyph
 * - multiple glyphs mapping to the same character need not be in sequence (thai, tamil have split characters)
@@ -578,7 +581,8 @@
 *
 * The algorithm works in the following way:
 * 1) we scan the glyphs ltr or rtl based on the bidi run direction
-* 2) we can work in place, since we always consume a glyph for each char we write
+* 2) Since the may be fewer glyphs than chars we cannot work in place.
+*    A new array is allocated for output.
 *    a) if the line is ltr, we start writing at position 0 until we finish, there may be leftver space
 *    b) if the line is rtl and 1-1, we start writing at position numChars/glyphs - 1 until we finish at 0
 *    c) otherwise if we don't finish at 0, we have to copy the data down
@@ -594,7 +598,7 @@
 *       iii) the x advance is the distance to the maximum x + adv of all glyphs whose advance is not zero
 *       iv) the y advance is the baseline
 *       v) vis x,y,w,h tightly encloses the vis x,y,w,h of all the glyphs with nonzero w and h
-* 4) we can make some simple optimizations if we know some things:
+* 4) In the future, we can make some simple optimizations to avoid copying if we know some things:
 *    a) if the mapping is 1-1, unidirectional, and there are no zero-adv glyphs, we just return the glyphinfo
 *    b) if the mapping is 1-1, unidirectional, we just adjust the remaining glyphs to originate at right/left of the base
 *    c) if the mapping is 1-1, we compute the base position and advance as we go, then go back to adjust the remaining glyphs
@@ -625,23 +629,20 @@
         System.out.println(source);
     }
 
-    /*
-    if ((gv.getDescriptionFlags() & 0x7) == 0) {
-        return glyphinfo;
-    }
-    */
-
     int numGlyphs = gv.getNumGlyphs();
     if (numGlyphs == 0) {
         return glyphinfo;
     }
     int[] indices = gv.getGlyphCharIndices(0, numGlyphs, null);
+    float[] charInfo = new float[source.getLength() * numvals];
 
-    boolean DEBUG = false;
     if (DEBUG) {
       System.err.println("number of glyphs: " + numGlyphs);
+      System.err.println("glyphinfo.len: " + glyphinfo.length);
+      System.err.println("indices.len: " + indices.length);
       for (int i = 0; i < numGlyphs; ++i) {
         System.err.println("g: " + i +
+            "  v: " + gv.getGlyphCode(i) +
             ", x: " + glyphinfo[i*numvals+posx] +
             ", a: " + glyphinfo[i*numvals+advx] +
             ", n: " + indices[i]);
@@ -650,22 +651,19 @@
 
     int minIndex = indices[0];  // smallest index seen this cluster
     int maxIndex = minIndex;    // largest index seen this cluster
-    int nextMin = 0;            // expected smallest index for this cluster
     int cp = 0;                 // character position
-    int cx = 0;                 // character index (logical)
+    int cc = 0;
     int gp = 0;                 // glyph position
     int gx = 0;                 // glyph index (visual)
     int gxlimit = numGlyphs;    // limit of gx, when we reach this we're done
     int pdelta = numvals;       // delta for incrementing positions
     int xdelta = 1;             // delta for incrementing indices
 
-    boolean ltr = (source.getLayoutFlags() & 0x1) == 0;
-    if (!ltr) {
+    boolean rtl = (source.getLayoutFlags() & 0x1) == 1;
+    if (rtl) {
         minIndex = indices[numGlyphs - 1];
         maxIndex = minIndex;
-        nextMin  = 0; // still logical
-        cp = glyphinfo.length - numvals;
-        cx = 0; // still logical
+        cp = charInfo.length - numvals;
         gp = glyphinfo.length - numvals;
         gx = numGlyphs - 1;
         gxlimit = -1;
@@ -693,47 +691,36 @@
     float cposl = 0, cposr = 0, cvisl = 0, cvist = 0, cvisr = 0, cvisb = 0;
     float baseline = 0;
 
-    // record if we have to copy data even when no cluster
-    boolean mustCopy = false;
-
     while (gx != gxlimit) {
         // start of new cluster
-        boolean haveCopy = false;
         int clusterExtraGlyphs = 0;
 
         minIndex = indices[gx];
         maxIndex = minIndex;
 
+        cposl = glyphinfo[gp + posx];
+        cposr = cposl + glyphinfo[gp + advx];
+        cvisl = glyphinfo[gp + visx];
+        cvist = glyphinfo[gp + visy];
+        cvisr = cvisl + glyphinfo[gp + visw];
+        cvisb = cvist + glyphinfo[gp + vish];
+
         // advance to next glyph
         gx += xdelta;
         gp += pdelta;
 
- /*
-        while (gx != gxlimit && (glyphinfo[gp + advx] == 0 ||
-                           minIndex != nextMin || indices[gx] <= maxIndex)) {
-  */
         while (gx != gxlimit &&
                ((glyphinfo[gp + advx] == 0) ||
-               (minIndex != nextMin) ||
                (indices[gx] <= maxIndex) ||
                (maxIndex - minIndex > clusterExtraGlyphs))) {
-            // initialize base data first time through, using base glyph
-            if (!haveCopy) {
-                int gps = gp - pdelta;
 
-                cposl = glyphinfo[gps + posx];
-                cposr = cposl + glyphinfo[gps + advx];
-                cvisl = glyphinfo[gps + visx];
-                cvist = glyphinfo[gps + visy];
-                cvisr = cvisl + glyphinfo[gps + visw];
-                cvisb = cvist + glyphinfo[gps + vish];
-
-                haveCopy = true;
+            ++clusterExtraGlyphs; // have an extra glyph in this cluster
+            if (DEBUG) {
+                System.err.println("gp=" +gp +" adv=" + glyphinfo[gp + advx] +
+                                   " gx="+ gx+ " i[gx]="+indices[gx] +
+                                   " clusterExtraGlyphs="+clusterExtraGlyphs);
             }
 
-            // have an extra glyph in this cluster
-            ++clusterExtraGlyphs;
-
             // adjust advance only if new glyph has non-zero advance
             float radvx = glyphinfo[gp + advx];
             if (radvx != 0) {
@@ -764,110 +751,84 @@
         // done with cluster, gx and gp are set for next glyph
 
         if (DEBUG) {
-            System.out.println("minIndex = " + minIndex + ", maxIndex = " + maxIndex);
+            System.err.println("minIndex = " + minIndex + ", maxIndex = " + maxIndex);
         }
 
-        nextMin = maxIndex + 1;
+        // save adjustments to the base character and do common adjustments.
+        charInfo[cp + posx] = cposl;
+        charInfo[cp + posy] = baseline;
+        charInfo[cp + advx] = cposr - cposl;
+        charInfo[cp + advy] = 0;
+        charInfo[cp + visx] = cvisl;
+        charInfo[cp + visy] = cvist;
+        charInfo[cp + visw] = cvisr - cvisl;
+        charInfo[cp + vish] = cvisb - cvist;
+        cc++;
 
-        // do common character adjustments
-        glyphinfo[cp + posy] = baseline;
-        glyphinfo[cp + advy] = 0;
-
-        if (haveCopy) {
-            // save adjustments to the base character
-            glyphinfo[cp + posx] = cposl;
-            glyphinfo[cp + advx] = cposr - cposl;
-            glyphinfo[cp + visx] = cvisl;
-            glyphinfo[cp + visy] = cvist;
-            glyphinfo[cp + visw] = cvisr - cvisl;
-            glyphinfo[cp + vish] = cvisb - cvist;
-
-            // compare number of chars read with number of glyphs read.
-            // if more glyphs than chars, set mustCopy to true, as we'll always have
-            // to copy the data from here on out.
-            if (maxIndex - minIndex < clusterExtraGlyphs) {
-                mustCopy = true;
-            }
-
-            // Fix the characters that follow the base character.
-            // New values are all the same.  Note we fix the number of characters
-            // we saw, not the number of glyphs we saw.
-            if (minIndex < maxIndex) {
-                if (!ltr) {
-                    // if rtl, characters to left of base, else to right.  reuse cposr.
-                    cposr = cposl;
-                }
-                cvisr -= cvisl; // reuse, convert to deltas.
-                cvisb -= cvist;
-
-                int iMinIndex = minIndex, icp = cp / 8;
-
-                while (minIndex < maxIndex) {
-                    ++minIndex;
-                    cx += xdelta;
-                    cp += pdelta;
-
-                    if (cp < 0 || cp >= glyphinfo.length) {
-                        if (DEBUG) System.out.println("minIndex = " + iMinIndex + ", maxIndex = " + maxIndex + ", cp = " + icp);
-                    }
-
-                    glyphinfo[cp + posx] = cposr;
-                    glyphinfo[cp + posy] = baseline;
-                    glyphinfo[cp + advx] = 0;
-                    glyphinfo[cp + advy] = 0;
-                    glyphinfo[cp + visx] = cvisl;
-                    glyphinfo[cp + visy] = cvist;
-                    glyphinfo[cp + visw] = cvisr;
-                    glyphinfo[cp + vish] = cvisb;
-                }
-            }
-
-            // no longer using this copy
-            haveCopy = false;
-        } else if (mustCopy) {
-            // out of synch, so we have to copy all the time now
-            int gpr = gp - pdelta;
-
-            glyphinfo[cp + posx] = glyphinfo[gpr + posx];
-            glyphinfo[cp + advx] = glyphinfo[gpr + advx];
-            glyphinfo[cp + visx] = glyphinfo[gpr + visx];
-            glyphinfo[cp + visy] = glyphinfo[gpr + visy];
-            glyphinfo[cp + visw] = glyphinfo[gpr + visw];
-            glyphinfo[cp + vish] = glyphinfo[gpr + vish];
+        int tgt;
+        if (gx == gxlimit) {
+           tgt = charInfo.length / numvals;
+        } else {
+           tgt = indices[gx];
         }
-        // else glyphinfo is already at the correct character position, and is unchanged, so just leave it
+        if (DEBUG) {
+           System.err.println("gx=" + gx + " gxlimit=" + gxlimit +
+                              " charInfo.len=" + charInfo.length +
+                              " tgt=" + tgt + " cc=" + cc + " cp=" + cp);
+        }
+        while (cc < tgt) {
+            if (rtl) {
+                // if rtl, characters to left of base, else to right.  reuse cposr.
+                cposr = cposl;
+            }
+            cvisr -= cvisl; // reuse, convert to deltas.
+            cvisb -= cvist;
 
-        // reset for new cluster
-        cp += pdelta;
-        cx += xdelta;
-    }
+            cp += pdelta;
 
-    if (mustCopy && !ltr) {
-        // data written to wrong end of array, need to shift down
+            if (cp < 0 || cp >= charInfo.length) {
+                if (DEBUG)  {
+                    System.err.println("Error : cp=" + cp +
+                                       " charInfo.length=" + charInfo.length);
+                }
+                break;
+            }
 
-        cp -= pdelta; // undo last increment, get start of valid character data in array
-        System.arraycopy(glyphinfo, cp, glyphinfo, 0, glyphinfo.length - cp);
+            if (DEBUG) {
+                System.err.println("Insert charIndex " + cc + " at pos="+cp);
+            }
+            charInfo[cp + posx] = cposr;
+            charInfo[cp + posy] = baseline;
+            charInfo[cp + advx] = 0;
+            charInfo[cp + advy] = 0;
+            charInfo[cp + visx] = cvisl;
+            charInfo[cp + visy] = cvist;
+            charInfo[cp + visw] = cvisr;
+            charInfo[cp + vish] = cvisb;
+            cc++;
+        }
+        cp += pdelta; // reset for new cluster
     }
 
     if (DEBUG) {
-      char[] chars = source.getChars();
-      int start = source.getStart();
-      int length = source.getLength();
-      System.out.println("char info for " + length + " characters");
-      for(int i = 0; i < length * numvals;) {
-        System.out.println(" ch: " + Integer.toHexString(chars[start + v2l(i / numvals)]) +
-                           " x: " + glyphinfo[i++] +
-                           " y: " + glyphinfo[i++] +
-                           " xa: " + glyphinfo[i++] +
-                           " ya: " + glyphinfo[i++] +
-                           " l: " + glyphinfo[i++] +
-                           " t: " + glyphinfo[i++] +
-                           " w: " + glyphinfo[i++] +
-                           " h: " + glyphinfo[i++]);
+        char[] chars = source.getChars();
+        int start = source.getStart();
+        int length = source.getLength();
+        System.err.println("char info for " + length + " characters");
+
+        for (int i = 0; i < length * numvals;) {
+            System.err.println(" ch: " + Integer.toHexString(chars[start + v2l(i / numvals)]) +
+                               " x: " + charInfo[i++] +
+                               " y: " + charInfo[i++] +
+                               " xa: " + charInfo[i++] +
+                               " ya: " + charInfo[i++] +
+                               " l: " + charInfo[i++] +
+                               " t: " + charInfo[i++] +
+                               " w: " + charInfo[i++] +
+                               " h: " + charInfo[i++]);
       }
     }
-
-    return glyphinfo;
+    return charInfo;
   }
 
   /**
diff --git a/src/share/classes/sun/font/FileFontStrike.java b/src/share/classes/sun/font/FileFontStrike.java
index c66bcaf..e4ae914 100644
--- a/src/share/classes/sun/font/FileFontStrike.java
+++ b/src/share/classes/sun/font/FileFontStrike.java
@@ -35,6 +35,8 @@
 import java.awt.geom.NoninvertibleTransformException;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.concurrent.ConcurrentHashMap;
 import static sun.awt.SunHints.*;
 
@@ -110,13 +112,77 @@
     /* Used only for communication to native layer */
     private int intPtSize;
 
+    // -1 - undefined, 0 - horizontal (normal direction), 1 - 90 degrees CCW, 2 - 180 degrees, 3 - 90 degrees CW
+    private int rotation = -1;
+
     /* Perform global initialisation needed for Windows native rasterizer */
     private static native boolean initNative();
+    private static native boolean isDirectWriteAvailable();
     private static boolean isXPorLater = false;
+
+    private static boolean useNativesForRotatedText;
+
+    private static boolean useDirectWrite;
+
+    // DirectWrite rendering options' values can be found in MSDN documentation
+    // for IDWriteBitmapRenderTarget::DrawGlyphRun method and its parameters
+    // (https://msdn.microsoft.com/en-us/library/windows/desktop/dd368167(v=vs.85).aspx)
+
+    // Measuring mode doesn't seem to impact glyph rendering directly,
+    // but values other that 0 ('natural' measuring mode) seem to limit possible other options' values.
+    private static int dwMeasuringMode = 0;
+    // Only 'natural' and 'natural symmetric' rendering modes seem to use requested gamma value,
+    // so only they can be used to produce valid glyph images.
+    // 'Natural' mode is said to look better for smaller font sizes.
+    private static int dwRenderingMode = 4;
+    // 'Full' ClearType
+    private static float dwClearTypeLevel = 1;
+    // Disabling enhanced contrast - it doesn't seem to be doing anything for white-on-black glyphs being generated.
+    private static float dwEnhancedContrast = 0;
+    // gamma correction will be applied when glyph image is blitted onto target surface, so for a cached glyph image
+    // we don't need any gamma correction
+    private static float dwGamma = 1;
+    // use monitor-default pixel geometry
+    private static int dwPixelGeometry = -1;
+
     static {
         if (FontUtilities.isWindows && !FontUtilities.useT2K &&
             !GraphicsEnvironment.isHeadless()) {
             isXPorLater = initNative();
+            if (isXPorLater) {
+                AccessController.doPrivileged(new PrivilegedAction() {
+                    public Object run() {
+                        String rotatedProperty = System.getProperty("rotated.text.native.rendering");
+                        useNativesForRotatedText = rotatedProperty == null || Boolean.parseBoolean(rotatedProperty);
+                        useDirectWrite = Boolean.getBoolean("directwrite.font.rendering") && isDirectWriteAvailable();
+                        if (useDirectWrite) {
+                            String options = System.getProperty("directwrite.font.rendering.options");
+                            if (options != null) {
+                                String[] parts = options.split(":");
+                                if (parts.length > 0 && parts[0].length() > 0) {
+                                    try { dwMeasuringMode = Integer.parseInt(parts[0]); } catch (NumberFormatException ignored) { }
+                                }
+                                if (parts.length > 1 && parts[1].length() > 0) {
+                                    try { dwRenderingMode = Integer.parseInt(parts[1]); } catch (NumberFormatException ignored) { }
+                                }
+                                if (parts.length > 2 && parts[2].length() > 0) {
+                                    try { dwClearTypeLevel = Float.parseFloat(parts[2]); } catch (NumberFormatException ignored) { }
+                                }
+                                if (parts.length > 3 && parts[3].length() > 0) {
+                                    try { dwEnhancedContrast = Float.parseFloat(parts[3]); } catch (NumberFormatException ignored) { }
+                                }
+                                if (parts.length > 4 && parts[4].length() > 0) {
+                                    try { dwGamma = Float.parseFloat(parts[4]); } catch (NumberFormatException ignored) { }
+                                }
+                                if (parts.length > 5 && parts[5].length() > 0) {
+                                    try { dwPixelGeometry = Integer.parseInt(parts[5]); } catch (NumberFormatException ignored) { }
+                                }
+                            }
+                        }
+                        return null;
+                    }
+                });
+            }
         }
     }
 
@@ -232,12 +298,18 @@
             !GraphicsEnvironment.isHeadless() &&
             !fileFont.useJavaRasterizer &&
             (desc.aaHint == INTVAL_TEXT_ANTIALIAS_LCD_HRGB ||
-             desc.aaHint == INTVAL_TEXT_ANTIALIAS_LCD_HBGR) &&
-            (matrix[1] == 0.0 && matrix[2] == 0.0 &&
-             matrix[0] == matrix[3] &&
-             matrix[0] >= 3.0 && matrix[0] <= 100.0) &&
-            !((TrueTypeFont)fileFont).useEmbeddedBitmapsForSize(intPtSize)) {
-            useNatives = true;
+             desc.aaHint == INTVAL_TEXT_ANTIALIAS_LCD_HBGR)) {
+            double pts = 0;
+            if (matrix[1] == 0.0 && matrix[2] == 0.0 && matrix[0] == matrix[3]) {
+                rotation = matrix[0] > 0 ? 0 : 2;
+                pts = Math.abs(matrix[0]);
+            } else if (matrix[0] == 0.0 && matrix[3] == 0.0 && matrix[1] == -matrix[2]) {
+                rotation = matrix[1] > 0 ? 3 : 1;
+                pts = Math.abs(matrix[1]);
+            }
+            intPtSize = (int) pts;
+            useNatives = (rotation == 0 || rotation > 0 && useNativesForRotatedText) && pts >= 3.0 && pts <= 100.0 &&
+                    !((TrueTypeFont)fileFont).useEmbeddedBitmapsForSize(intPtSize);
         }
         else if (fileFont.checkUseNatives() && desc.aaHint==0 && !algoStyle) {
             /* Check its a simple scale of a pt size in the range
@@ -328,31 +400,54 @@
                                                   int style,
                                                   int size,
                                                   int glyphCode,
-                                                  boolean fracMetrics);
+                                                  boolean fracMetrics,
+                                                  int rotation);
+
+    private native long _getGlyphImageFromWindowsUsingDirectWrite(String family,
+                                                                  int style,
+                                                                  int size,
+                                                                  int glyphCode,
+                                                                  int rotation,
+                                                                  int measuringMode,
+                                                                  int renderingMode,
+                                                                  float clearTypeLevel,
+                                                                  float enhancedContrast,
+                                                                  float gamma,
+                                                                  int pixelGeometry);
 
     long getGlyphImageFromWindows(int glyphCode) {
         String family = fileFont.getFamilyName(null);
         int style = desc.style & Font.BOLD | desc.style & Font.ITALIC
             | fileFont.getStyle();
         int size = intPtSize;
-        long ptr = _getGlyphImageFromWindows
-            (family, style, size, glyphCode,
-             desc.fmHint == INTVAL_FRACTIONALMETRICS_ON);
-        if (ptr != 0) {
-            /* Get the advance from the JDK rasterizer. This is mostly
-             * necessary for the fractional metrics case, but there are
-             * also some very small number (<0.25%) of marginal cases where
-             * there is some rounding difference between windows and JDK.
-             * After these are resolved, we can restrict this extra
-             * work to the FM case.
-             */
-            float advance = getGlyphAdvance(glyphCode, false);
-            StrikeCache.unsafe.putFloat(ptr + StrikeCache.xAdvanceOffset,
-                                        advance);
-            return ptr;
-        } else {
-            return fileFont.getGlyphImage(pScalerContext, glyphCode);
+        long ptr = 0;
+        if (useDirectWrite) {
+            ptr = _getGlyphImageFromWindowsUsingDirectWrite(family, style, size, glyphCode, rotation,
+                    dwMeasuringMode, dwRenderingMode, dwClearTypeLevel, dwEnhancedContrast, dwGamma, dwPixelGeometry);
+            if (ptr == 0 && FontUtilities.isLogging()) {
+                FontUtilities.getLogger().warning("Failed to render glyph via DirectWrite: code=" + glyphCode
+                        + ", fontFamily=" + family + ", style=" + style + ", size=" + size + ", rotation=" + rotation);
+            }
         }
+        if (ptr == 0) {
+            ptr = _getGlyphImageFromWindows(family, style, size, glyphCode,
+                    desc.fmHint == INTVAL_FRACTIONALMETRICS_ON, rotation);
+            if (ptr != 0 && (rotation == 0 || rotation == 2)) {
+                /* Get the advance from the JDK rasterizer. This is mostly
+                 * necessary for the fractional metrics case, but there are
+                 * also some very small number (<0.25%) of marginal cases where
+                 * there is some rounding difference between windows and JDK.
+                 * After these are resolved, we can restrict this extra
+                 * work to the FM case.
+                 */
+                float advance = getGlyphAdvance(glyphCode, false);
+                StrikeCache.unsafe.putFloat(ptr + StrikeCache.xAdvanceOffset, advance);
+            }
+        }
+        if (ptr == 0) {
+            ptr = fileFont.getGlyphImage(pScalerContext, glyphCode);
+        }
+        return ptr;
     }
 
     /* Try the native strikes first, then try the fileFont strike */
diff --git a/src/share/classes/sun/font/Font2D.java b/src/share/classes/sun/font/Font2D.java
index ae67a30..678c2a4 100644
--- a/src/share/classes/sun/font/Font2D.java
+++ b/src/share/classes/sun/font/Font2D.java
@@ -25,6 +25,9 @@
 
 package sun.font;
 
+import sun.java2d.Disposer;
+import sun.java2d.DisposerRecord;
+
 import java.awt.Font;
 import java.awt.font.FontRenderContext;
 import java.awt.geom.AffineTransform;
@@ -68,12 +71,16 @@
     private static final FontRenderContext DEFAULT_FRC =
         new FontRenderContext(null, false, false);
 
+    static final boolean fontSubstitutionEnabled = !Boolean.getBoolean("disable.font.substitution");
+
     public Font2DHandle handle;
     protected String familyName;           /* Family font name (english) */
     protected String fullName;             /* Full font name (english)   */
     protected int style = Font.PLAIN;
     protected FontFamily family;
     protected int fontRank = DEFAULT_RANK;
+    
+    private HarfbuzzFaceRef harfbuzzFaceRef; 
 
     /*
      * A mapper can be independent of the strike.
@@ -308,7 +315,7 @@
         return getStrike(desc, true);
     }
 
-    private FontStrike getStrike(FontStrikeDesc desc, boolean copy) {
+    FontStrike getStrike(FontStrikeDesc desc, boolean copy) {
         /* Before looking in the map, see if the descriptor matches the
          * last strike returned from this Font2D. This should often be a win
          * since its common for the same font, in the same size to be
@@ -461,10 +468,40 @@
      * to check the font class before attempting to run, rather than needing
      * to promote this method up from TrueTypeFont
      */
-    byte[] getTableBytes(int tag) {
+    protected byte[] getTableBytes(int tag) {
         return null;
     }
 
+    /* implemented for fonts backed by an sfnt that has
+     * OpenType or AAT layout tables.
+     */
+    protected long getLayoutTableCache() {
+        return 0L;
+    }
+
+    /* Used only on OS X.
+     */
+    protected long getPlatformNativeFontPtr() {
+        return 0L;
+    }
+    
+    protected boolean isAAT() {
+        return false;
+    }
+    
+    synchronized long getHarfbuzzFacePtr() {
+        if (harfbuzzFaceRef == null) {
+            long harfbuzzFaceNativePtr = createHarfbuzzFace(isAAT(), getPlatformNativeFontPtr());
+            if (harfbuzzFaceNativePtr == 0) return 0;
+            harfbuzzFaceRef = new HarfbuzzFaceRef(harfbuzzFaceNativePtr);
+            Disposer.addObjectRecord(this, harfbuzzFaceRef);
+        }
+        return harfbuzzFaceRef.harfbuzzFaceNativePtr;
+    }
+
+    private native long createHarfbuzzFace(boolean aat, long platformNativeFontPtr);
+    private static native void disposeHarfbuzzFace(long harfbuzzFaceNativePtr);    
+
     /* for layout code */
     protected long getUnitsPerEm() {
         return 2048;
@@ -546,4 +583,16 @@
         }
     }
 
+    private static class HarfbuzzFaceRef implements DisposerRecord {
+        private final long harfbuzzFaceNativePtr;
+
+        private HarfbuzzFaceRef(long harfbuzzFaceNativePtr) {
+            this.harfbuzzFaceNativePtr = harfbuzzFaceNativePtr;
+        }
+
+        @Override
+        public void dispose() {
+            disposeHarfbuzzFace(harfbuzzFaceNativePtr);
+        }
+    }
 }
diff --git a/src/share/classes/sun/font/FontFamily.java b/src/share/classes/sun/font/FontFamily.java
index e319886..a0d8032 100644
--- a/src/share/classes/sun/font/FontFamily.java
+++ b/src/share/classes/sun/font/FontFamily.java
@@ -27,6 +27,7 @@
 
 import java.io.File;
 import java.awt.Font;
+import java.io.IOException;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.concurrent.ConcurrentHashMap;
@@ -132,6 +133,16 @@
 
         FileFont newFont = (FileFont)font;
         File newDir = (new File(newFont.platName)).getParentFile();
+        if (existDir != null) {
+            try {
+                existDir = existDir.getCanonicalFile();
+            } catch (IOException ignored) {}
+        }
+        if (newDir != null) {
+            try {
+                newDir = newDir.getCanonicalFile();
+            } catch (IOException ignored) {}
+        }
         return java.util.Objects.equals(newDir, existDir);
     }
 
diff --git a/src/share/classes/sun/font/FontSubstitution.java b/src/share/classes/sun/font/FontSubstitution.java
new file mode 100644
index 0000000..47dfc6f
--- /dev/null
+++ b/src/share/classes/sun/font/FontSubstitution.java
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+package sun.font;
+
+
+
+/**
+ * Interface that indicates a Font2D that is not a Composite but has the
+ * property that it internally behaves like one, substituting glyphs
+ * from another font at render time.
+ * In this case the Font must provide a way to behave like a regular
+ * composite when that behaviour is not wanted.
+ */
+public interface FontSubstitution {
+    public CompositeFont getCompositeFont2D();
+}
diff --git a/src/share/classes/sun/font/FontUtilities.java b/src/share/classes/sun/font/FontUtilities.java
index 04a4f9f..b6fc413 100644
--- a/src/share/classes/sun/font/FontUtilities.java
+++ b/src/share/classes/sun/font/FontUtilities.java
@@ -64,6 +64,8 @@
 
     static final String LUCIDA_FILE_NAME = "LucidaSansRegular.ttf";
 
+    static final String DROID_FILE_NAME = "DroidSans.ttf";
+
     private static boolean debugFonts = false;
     private static PlatformLogger logger = null;
     private static boolean logging;
diff --git a/src/share/classes/sun/font/FreetypeFontScaler.java b/src/share/classes/sun/font/FreetypeFontScaler.java
index 50b69e5..9a3d595 100644
--- a/src/share/classes/sun/font/FreetypeFontScaler.java
+++ b/src/share/classes/sun/font/FreetypeFontScaler.java
@@ -25,6 +25,7 @@
 
 package sun.font;
 
+import java.awt.*;
 import java.awt.geom.GeneralPath;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
@@ -47,10 +48,10 @@
         /* At the moment fontmanager library depends on freetype library
            and therefore no need to load it explicitly here */
         FontManagerNativeLibrary.load();
-        initIDs(FreetypeFontScaler.class);
+        initIDs(FreetypeFontScaler.class, Toolkit.class, PhysicalFont.class);
     }
 
-    private static native void initIDs(Class FFS);
+    private static native void initIDs(Class FFS, Class toolkitClass, Class pfClass);
 
     private void invalidateScaler() throws FontScalerException {
         nativeScaler = 0;
diff --git a/src/share/classes/sun/font/GlyphLayout.java b/src/share/classes/sun/font/GlyphLayout.java
index 749a1c7..1360c7c 100644
--- a/src/share/classes/sun/font/GlyphLayout.java
+++ b/src/share/classes/sun/font/GlyphLayout.java
@@ -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);
     }
 
@@ -368,6 +369,8 @@
 
         init(count);
 
+        boolean handlePairedChars = (flags & Font.LAYOUT_NO_PAIRED_CHARS_AT_SCRIPT_SPLIT) == 0;
+
         // need to set after init
         // go through the back door for this
         if (font.hasLayoutAttributes()) {
@@ -386,6 +389,7 @@
         _mat[2] = (float)txinfo.gtx.getShearX();
         _mat[3] = (float)txinfo.gtx.getScaleY();
         _pt.setLocation(txinfo.delta);
+        ptSize = font.getSize2D();
 
         int lim = offset + count;
 
@@ -408,11 +412,14 @@
         int lang = -1; // default for now
 
         Font2D font2D = FontUtilities.getFont2D(font);
+        if (Font2D.fontSubstitutionEnabled && font2D instanceof FontSubstitution) {
+            font2D = ((FontSubstitution)font2D).getCompositeFont2D();
+        }
 
         _textRecord.init(text, offset, lim, min, max);
         int start = offset;
         if (font2D instanceof CompositeFont) {
-            _scriptRuns.init(text, offset, count); // ??? how to handle 'common' chars
+            _scriptRuns.init(text, offset, count, handlePairedChars); // ??? how to handle 'common' chars
             _fontRuns.init((CompositeFont)font2D, text, offset, lim);
             while (_scriptRuns.next()) {
                 int limit = _scriptRuns.getScriptLimit();
@@ -435,7 +442,7 @@
                 }
             }
         } else {
-            _scriptRuns.init(text, offset, count); // ??? don't worry about 'common' chars
+            _scriptRuns.init(text, offset, count, handlePairedChars); // ??? don't worry about 'common' chars
             while (_scriptRuns.next()) {
                 int limit = _scriptRuns.getScriptLimit();
                 int script = _scriptRuns.getScriptCode();
@@ -679,7 +686,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);
         }
     }
diff --git a/src/share/classes/sun/font/GlyphList.java b/src/share/classes/sun/font/GlyphList.java
index ef7dc56..ad61f3d 100644
--- a/src/share/classes/sun/font/GlyphList.java
+++ b/src/share/classes/sun/font/GlyphList.java
@@ -25,9 +25,9 @@
 
 package sun.font;
 
-import java.awt.Font;
 import java.awt.font.GlyphVector;
-import java.awt.font.FontRenderContext;
+
+import sun.java2d.SurfaceData;
 import sun.java2d.loops.FontInfo;
 
 /*
@@ -83,6 +83,7 @@
 
     int glyphindex;
     int metrics[];
+    int bounds[];
     byte graybits[];
 
     /* A reference to the strike is needed for the case when the GlyphList
@@ -154,6 +155,7 @@
     private static GlyphList reusableGL = new GlyphList();
     private static boolean inUse;
 
+    private ColorGlyphSurfaceData glyphSurfaceData;
 
     void ensureCapacity(int len) {
       /* Note len must not be -ve! only setFromChars should be capable
@@ -271,6 +273,7 @@
         }
         info.fontStrike.getGlyphImagePtrs(glyphData, images, len);
         glyphindex = -1;
+        resetBounds();
         return true;
     }
 
@@ -294,16 +297,20 @@
                                           usePositions ? positions : null,
                                           info.devTx);
         glyphindex = -1;
+        resetBounds();
     }
 
     public int[] getBounds() {
-        /* We co-opt the 5 element array that holds per glyph metrics in order
-         * to return the bounds. So a caller must copy the data out of the
-         * array before calling any other methods on this GlyphList
-         */
-        if (glyphindex >= 0) {
-            throw new InternalError("calling getBounds after setGlyphIndex");
+        if (!areBoundsPopulated()) {
+            if (bounds == null) {
+                bounds = new int[4];
+            }
+            fillBounds(bounds);
         }
+        return bounds;
+    }
+
+    public void startGlyphIteration() {
         if (metrics == null) {
             metrics = new int[5];
         }
@@ -311,8 +318,6 @@
          * Add 0.5f for consistent rounding to pixel position. */
         gposx = x + 0.5f;
         gposy = y + 0.5f;
-        fillBounds(metrics);
-        return metrics;
     }
 
     /* This method now assumes "state", so must be called 0->len
@@ -442,6 +447,17 @@
         return len;
     }
 
+    private void resetBounds() {
+        if (bounds != null) {
+            bounds[0] = 1;
+            bounds[2] = 0;
+        }
+    }
+
+    private boolean areBoundsPopulated() {
+        return bounds != null && bounds[0] <= bounds[2];
+    }
+
     /* We re-do all this work as we iterate through the glyphs
      * but it seems unavoidable without re-working the Java TextRenderers.
      */
@@ -497,4 +513,18 @@
         bounds[2] = (int)Math.floor(bx1);
         bounds[3] = (int)Math.floor(by1);
     }
+
+    public boolean isColorGlyph(int glyphIndex) {
+        int width = StrikeCache.unsafe.getChar(images[glyphIndex] + StrikeCache.widthOffset);
+        int rowBytes = StrikeCache.unsafe.getChar(images[glyphIndex] + StrikeCache.rowBytesOffset);
+        return rowBytes == width * 4;
+    }
+
+    public SurfaceData getColorGlyphData() {
+        if (glyphSurfaceData == null) {
+            glyphSurfaceData = new ColorGlyphSurfaceData();
+        }
+        glyphSurfaceData.setCurrentGlyph(images[glyphindex]);
+        return glyphSurfaceData;
+    }
 }
diff --git a/src/share/classes/sun/font/PhysicalFont.java b/src/share/classes/sun/font/PhysicalFont.java
index a3c7378..5d9737c 100644
--- a/src/share/classes/sun/font/PhysicalFont.java
+++ b/src/share/classes/sun/font/PhysicalFont.java
@@ -79,6 +79,12 @@
         return new Point2D.Float();
     }
 
+    @Override
+    protected boolean isAAT() {
+        return getTableBytes(TrueTypeFont.morxTag) != null ||
+               getTableBytes(TrueTypeFont.mortTag) != null;
+    }
+
     /* These 3 metrics methods should be implemented to return
      * values in user space.
      */
diff --git a/src/share/classes/sun/font/ScriptRun.java b/src/share/classes/sun/font/ScriptRun.java
index e719fc3..e7da669 100644
--- a/src/share/classes/sun/font/ScriptRun.java
+++ b/src/share/classes/sun/font/ScriptRun.java
@@ -43,7 +43,7 @@
  * COMMON and INHERITED characters are first, they will be assigned to
  * the same script as the following characters.
  *
- * The iterator will try to match paired punctuation. If it sees an
+ * The iterator will try (optionally) to match paired punctuation. If it sees an
  * opening punctuation character, it will remember the script that
  * was assigned to that character, and assign the same script to the
  * matching closing punctuation.
@@ -83,6 +83,8 @@
     private int stack[];         // stack used to handle paired punctuation if encountered
     private int parenSP;
 
+    private boolean handlePairedChars;
+
     public ScriptRun() {
         // must call init later or we die.
     }
@@ -100,7 +102,11 @@
         init(chars, start, count);
     }
 
-    public void init(char[] chars, int start, int count)
+    public void init(char[] chars, int start, int count) {
+        init(chars, start, count, true);
+    }
+
+    public void init(char[] chars, int start, int count, boolean pairedChars)
     {
         if (chars == null || start < 0 || count < 0 || count > chars.length - start) {
             throw new IllegalArgumentException();
@@ -114,6 +120,7 @@
         scriptLimit = textStart;
         scriptCode = Script.INVALID_CODE;
         parenSP = 0;
+        handlePairedChars = pairedChars;
     }
 
     /**
@@ -165,7 +172,7 @@
 
         while ((ch = nextCodePoint()) != DONE) {
             int sc = ScriptRunData.getScript(ch);
-            int pairIndex = sc == Script.COMMON ? getPairIndex(ch) : -1;
+            int pairIndex = handlePairedChars && sc == Script.COMMON ? getPairIndex(ch) : -1;
 
             // Paired character handling:
             //
diff --git a/src/share/classes/sun/font/StandardGlyphVector.java b/src/share/classes/sun/font/StandardGlyphVector.java
index 0736c25..eae9aa2 100644
--- a/src/share/classes/sun/font/StandardGlyphVector.java
+++ b/src/share/classes/sun/font/StandardGlyphVector.java
@@ -26,7 +26,6 @@
 package sun.font;
 
 import java.awt.Font;
-import java.awt.Graphics2D;
 import java.awt.Point;
 import java.awt.Rectangle;
 import static java.awt.RenderingHints.*;
@@ -36,7 +35,6 @@
 import java.awt.font.GlyphJustificationInfo;
 import java.awt.font.GlyphVector;
 import java.awt.font.LineMetrics;
-import java.awt.font.TextAttribute;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.GeneralPath;
 import java.awt.geom.NoninvertibleTransformException;
@@ -1124,6 +1122,9 @@
 
     private void initFontData() {
         font2D = FontUtilities.getFont2D(font);
+        if (Font2D.fontSubstitutionEnabled && font2D instanceof FontSubstitution) {
+           font2D = ((FontSubstitution)font2D).getCompositeFont2D();
+        }
         float s = font.getSize2D();
         if (font.isTransformed()) {
             ftx = font.getTransform();
@@ -1742,7 +1743,12 @@
                                                      aa, fm);
             // Get the strike via the handle. Shouldn't matter
             // if we've invalidated the font but its an extra precaution.
-            FontStrike strike = sgv.font2D.handle.font2D.getStrike(desc);  // !!! getStrike(desc, false)
+        // do we want the CompFont from CFont here ?
+        Font2D f2d = sgv.font2D;
+        if (Font2D.fontSubstitutionEnabled && f2d instanceof FontSubstitution) {
+           f2d = ((FontSubstitution)f2d).getCompositeFont2D();
+        }
+            FontStrike strike = f2d.handle.font2D.getStrike(desc);  // !!! getStrike(desc, false)
 
             return new GlyphStrike(sgv, strike, dx, dy);
         }
diff --git a/src/share/classes/sun/font/SunFontManager.java b/src/share/classes/sun/font/SunFontManager.java
index ec6b4d8..232f44a 100644
--- a/src/share/classes/sun/font/SunFontManager.java
+++ b/src/share/classes/sun/font/SunFontManager.java
@@ -188,11 +188,12 @@
     boolean loadedAllFonts = false;
     boolean loadedAllFontFiles = false;
     HashMap<String,String> jreFontMap;
-    HashSet<String> jreLucidaFontFiles;
+    HashSet<String> jreBundledFontFiles;
     String[] jreOtherFontFiles;
     boolean noOtherJREFontFiles = false; // initial assumption.
 
     public static final String lucidaFontName = "Lucida Sans Regular";
+    public static final String droidFontName = "Droid Sans";
     public static String jreLibDirName;
     public static String jreFontDirName;
     private static HashSet<String> missingFontFiles = null;
@@ -278,55 +279,76 @@
          * no evidence they are useful in practice.
          */
         jreFontMap = new HashMap<String,String>();
-        jreLucidaFontFiles = new HashSet<String>();
+        jreBundledFontFiles = new HashSet<String>();
         if (isOpenJDK()) {
-            return;
+
+            /* Droid Sans Mono Family */
+            jreFontMap.put("droid sans0",   "DroidSans.ttf");
+            jreFontMap.put("droid sans1",   "DroidSans-Bold.ttf");
+            jreFontMap.put("droid sans bold1", "DroidSans-Bold.ttf");
+
+            /* Droid Sans Mono Family */
+            jreFontMap.put("droid sans mono0", "DroidSansMono.ttf");
+            jreFontMap.put("droid sans mono slashed0",
+                           "DroidSansMonoSlashed.ttf");
+            jreFontMap.put("droid sans mono dotted0",
+                           "DroidSansMonoDotted.ttf");
+
+            /* Droid Serif Family */
+            jreFontMap.put("droid serif0", "DroidSerif-Regular.ttf");
+            jreFontMap.put("droid serif1", "DroidSerif-Bold.ttf");
+            jreFontMap.put("droid serif2", "DroidSerif-Italic.ttf");
+            jreFontMap.put("droid serif3", "DroidSerif-BoldItalic.ttf");
+            jreFontMap.put("droid serif bold1", "DroidSerif-Bold.ttf");
+            jreFontMap.put("droid serif bold italic3", "DroidSerif-BoldItalic.ttf");
         }
+        else {
         /* Lucida Sans Family */
-        jreFontMap.put("lucida sans0",   "LucidaSansRegular.ttf");
-        jreFontMap.put("lucida sans1",   "LucidaSansDemiBold.ttf");
+            jreFontMap.put("lucida sans0", "LucidaSansRegular.ttf");
+            jreFontMap.put("lucida sans1", "LucidaSansDemiBold.ttf");
         /* Lucida Sans full names (map Bold and DemiBold to same file) */
-        jreFontMap.put("lucida sans regular0", "LucidaSansRegular.ttf");
-        jreFontMap.put("lucida sans regular1", "LucidaSansDemiBold.ttf");
-        jreFontMap.put("lucida sans bold1", "LucidaSansDemiBold.ttf");
-        jreFontMap.put("lucida sans demibold1", "LucidaSansDemiBold.ttf");
+            jreFontMap.put("lucida sans regular0", "LucidaSansRegular.ttf");
+            jreFontMap.put("lucida sans regular1", "LucidaSansDemiBold.ttf");
+            jreFontMap.put("lucida sans bold1", "LucidaSansDemiBold.ttf");
+            jreFontMap.put("lucida sans demibold1", "LucidaSansDemiBold.ttf");
 
         /* Lucida Sans Typewriter Family */
-        jreFontMap.put("lucida sans typewriter0",
-                       "LucidaTypewriterRegular.ttf");
-        jreFontMap.put("lucida sans typewriter1", "LucidaTypewriterBold.ttf");
+            jreFontMap.put("lucida sans typewriter0",
+                    "LucidaTypewriterRegular.ttf");
+            jreFontMap.put("lucida sans typewriter1", "LucidaTypewriterBold.ttf");
         /* Typewriter full names (map Bold and DemiBold to same file) */
-        jreFontMap.put("lucida sans typewriter regular0",
-                       "LucidaTypewriter.ttf");
-        jreFontMap.put("lucida sans typewriter regular1",
-                       "LucidaTypewriterBold.ttf");
-        jreFontMap.put("lucida sans typewriter bold1",
-                       "LucidaTypewriterBold.ttf");
-        jreFontMap.put("lucida sans typewriter demibold1",
-                       "LucidaTypewriterBold.ttf");
+            jreFontMap.put("lucida sans typewriter regular0",
+                    "LucidaTypewriter.ttf");
+            jreFontMap.put("lucida sans typewriter regular1",
+                    "LucidaTypewriterBold.ttf");
+            jreFontMap.put("lucida sans typewriter bold1",
+                    "LucidaTypewriterBold.ttf");
+            jreFontMap.put("lucida sans typewriter demibold1",
+                    "LucidaTypewriterBold.ttf");
 
         /* Lucida Bright Family */
-        jreFontMap.put("lucida bright0", "LucidaBrightRegular.ttf");
-        jreFontMap.put("lucida bright1", "LucidaBrightDemiBold.ttf");
-        jreFontMap.put("lucida bright2", "LucidaBrightItalic.ttf");
-        jreFontMap.put("lucida bright3", "LucidaBrightDemiItalic.ttf");
+            jreFontMap.put("lucida bright0", "LucidaBrightRegular.ttf");
+            jreFontMap.put("lucida bright1", "LucidaBrightDemiBold.ttf");
+            jreFontMap.put("lucida bright2", "LucidaBrightItalic.ttf");
+            jreFontMap.put("lucida bright3", "LucidaBrightDemiItalic.ttf");
         /* Lucida Bright full names (map Bold and DemiBold to same file) */
-        jreFontMap.put("lucida bright regular0", "LucidaBrightRegular.ttf");
-        jreFontMap.put("lucida bright regular1", "LucidaBrightDemiBold.ttf");
-        jreFontMap.put("lucida bright regular2", "LucidaBrightItalic.ttf");
-        jreFontMap.put("lucida bright regular3", "LucidaBrightDemiItalic.ttf");
-        jreFontMap.put("lucida bright bold1", "LucidaBrightDemiBold.ttf");
-        jreFontMap.put("lucida bright bold3", "LucidaBrightDemiItalic.ttf");
-        jreFontMap.put("lucida bright demibold1", "LucidaBrightDemiBold.ttf");
-        jreFontMap.put("lucida bright demibold3","LucidaBrightDemiItalic.ttf");
-        jreFontMap.put("lucida bright italic2", "LucidaBrightItalic.ttf");
-        jreFontMap.put("lucida bright italic3", "LucidaBrightDemiItalic.ttf");
-        jreFontMap.put("lucida bright bold italic3",
-                       "LucidaBrightDemiItalic.ttf");
-        jreFontMap.put("lucida bright demibold italic3",
-                       "LucidaBrightDemiItalic.ttf");
+            jreFontMap.put("lucida bright regular0", "LucidaBrightRegular.ttf");
+            jreFontMap.put("lucida bright regular1", "LucidaBrightDemiBold.ttf");
+            jreFontMap.put("lucida bright regular2", "LucidaBrightItalic.ttf");
+            jreFontMap.put("lucida bright regular3", "LucidaBrightDemiItalic.ttf");
+            jreFontMap.put("lucida bright bold1", "LucidaBrightDemiBold.ttf");
+            jreFontMap.put("lucida bright bold3", "LucidaBrightDemiItalic.ttf");
+            jreFontMap.put("lucida bright demibold1", "LucidaBrightDemiBold.ttf");
+            jreFontMap.put("lucida bright demibold3", "LucidaBrightDemiItalic.ttf");
+            jreFontMap.put("lucida bright italic2", "LucidaBrightItalic.ttf");
+            jreFontMap.put("lucida bright italic3", "LucidaBrightDemiItalic.ttf");
+            jreFontMap.put("lucida bright bold italic3",
+                    "LucidaBrightDemiItalic.ttf");
+            jreFontMap.put("lucida bright demibold italic3",
+                    "LucidaBrightDemiItalic.ttf");
+        }
         for (String ffile : jreFontMap.values()) {
-            jreLucidaFontFiles.add(ffile);
+            jreBundledFontFiles.add(ffile);
         }
     }
 
@@ -353,8 +375,6 @@
                jreLibDirName =
                    System.getProperty("java.home","") + File.separator + "lib";
                jreFontDirName = jreLibDirName + File.separator + "fonts";
-               File lucidaFile =
-                   new File(jreFontDirName + File.separator + FontUtilities.LUCIDA_FILE_NAME);
 
                return null;
            }
@@ -429,11 +449,6 @@
                          * that might be specified.
                          */
                         fontConfig = createFontConfiguration();
-                        if (isOpenJDK()) {
-                            String[] fontInfo = getDefaultPlatformFont();
-                            defaultFontName = fontInfo[0];
-                            defaultFontFileName = fontInfo[1];
-                        }
 
                         String extraFontPath = fontConfig.getExtraFontPath();
 
@@ -981,7 +996,7 @@
         if (noOtherJREFontFiles) {
             return null;
         }
-        synchronized (jreLucidaFontFiles) {
+        synchronized (jreBundledFontFiles) {
             if (jreOtherFontFiles == null) {
                 HashSet<String> otherFontFiles = new HashSet<String>();
                 for (String deferredFile : deferredFontFiles.keySet()) {
@@ -993,7 +1008,7 @@
                      */
                     if (dir == null ||
                         !dir.equals(jreFontDirName) ||
-                        jreLucidaFontFiles.contains(fname)) {
+                        jreBundledFontFiles.contains(fname)) {
                         continue;
                     }
                     otherFontFiles.add(deferredFile);
@@ -1031,7 +1046,7 @@
             String fname = file.getName();
             if (dir != null &&
                 dir.equals(jreFontDirName) &&
-                jreLucidaFontFiles.contains(fname)) {
+                jreBundledFontFiles.contains(fname)) {
                 continue;
             }
             PhysicalFont physicalFont = initialiseDeferredFont(fileName);
@@ -3394,6 +3409,15 @@
                 defaultFontFileName = FontUtilities.LUCIDA_FILE_NAME;
             }
         }
+        else {
+            defaultFontName = droidFontName;
+            if (useAbsoluteFontFileNames()) {
+                defaultFontFileName =
+                        jreFontDirName + File.separator + FontUtilities.DROID_FILE_NAME;
+            } else {
+                defaultFontFileName = FontUtilities.DROID_FILE_NAME;
+            }
+        }
     }
 
     /**
@@ -3919,4 +3943,8 @@
     {
         return new FontUIResource(family, style, size);
     }
+
+    public boolean areColorGlyphsSupported() {
+        return false;
+    }
 }
diff --git a/src/share/classes/sun/font/SunLayoutEngine.java b/src/share/classes/sun/font/SunLayoutEngine.java
index eb763cd..6c44850 100644
--- a/src/share/classes/sun/font/SunLayoutEngine.java
+++ b/src/share/classes/sun/font/SunLayoutEngine.java
@@ -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;
@@ -149,24 +160,39 @@
         this.key = key;
     }
 
-    public void layout(FontStrikeDesc desc, float[] mat, int gmask,
+    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 = 0;
-        if (font instanceof TrueTypeFont) {
-            layoutTables = ((TrueTypeFont) font).getLayoutTableCache();
-        }
+        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 {
+            shape(font, strike, ptSize, mat, 
+                    font.getHarfbuzzFacePtr(), font.getPlatformNativeFontPtr(), font.isAAT(),
+                    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 pFace, long pNativeFont, boolean aat,
+          char[] chars, GVData data,
+          int script, int offset, int limit,
+          int baseIndex, Point2D.Float pt, int typo_flags, int slot);
 }
diff --git a/src/share/classes/sun/font/TrueTypeFont.java b/src/share/classes/sun/font/TrueTypeFont.java
index 7fade58..49ab993 100644
--- a/src/share/classes/sun/font/TrueTypeFont.java
+++ b/src/share/classes/sun/font/TrueTypeFont.java
@@ -79,6 +79,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
@@ -887,8 +888,8 @@
         }
     }
 
-    /* NB: is it better to move declaration to Font2D? */
-    long getLayoutTableCache() {
+    @Override
+    protected long getLayoutTableCache() {
         try {
           return getScaler().getLayoutTableCache();
         } catch(FontScalerException fe) {
@@ -897,7 +898,7 @@
     }
 
     @Override
-    byte[] getTableBytes(int tag) {
+    protected byte[] getTableBytes(int tag) {
         ByteBuffer buffer = getTableBuffer(tag);
         if (buffer == null) {
             return null;
@@ -988,6 +989,12 @@
        return (fontWeight > 0) ? fontWeight : super.getWeight();
     }
 
+    @Override
+    protected boolean isAAT() {
+        return getDirectoryEntry(TrueTypeFont.morxTag) != null ||
+               getDirectoryEntry(TrueTypeFont.mortTag) != null;
+    }
+
     /* TrueTypeFont can use the fsSelection fields of OS/2 table
      * to determine the style. In the unlikely case that doesn't exist,
      * can use macStyle in the 'head' table but simpler to
diff --git a/src/share/classes/sun/java2d/ReentrantContext.java b/src/share/classes/sun/java2d/ReentrantContext.java
new file mode 100644
index 0000000..fc067b0
--- /dev/null
+++ b/src/share/classes/sun/java2d/ReentrantContext.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+package sun.java2d;
+
+import java.lang.ref.Reference;
+
+/**
+ * ReentrantContext is a base class to hold thread-local data supporting
+ * reentrancy in either a ThreadLocal or a ConcurrentLinkedQueue
+ *
+ * @see ReentrantContextProvider
+ */
+public class ReentrantContext {
+    // usage stored as a byte
+    byte usage = ReentrantContextProvider.USAGE_TL_INACTIVE;
+    /*
+     * Reference to this instance (hard, soft or weak).
+     * @see ReentrantContextProvider#refType
+     */
+    Reference<? extends ReentrantContext> reference = null;
+}
diff --git a/src/share/classes/sun/java2d/ReentrantContextProvider.java b/src/share/classes/sun/java2d/ReentrantContextProvider.java
new file mode 100644
index 0000000..92132aa
--- /dev/null
+++ b/src/share/classes/sun/java2d/ReentrantContextProvider.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+package sun.java2d;
+
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+
+/**
+ * This abstract ReentrantContextProvider helper class manages the creation,
+ * storage, and retrieval of concrete ReentrantContext instances which can be
+ * subclassed to hold cached contextual data.
+ *
+ * It supports reentrancy as every call to acquire() provides a new unique context
+ * instance that must later be returned for reuse by a call to release(ctx)
+ * (typically in a try/finally block).
+ *
+ * It has a couple of abstract implementations which store references in a queue
+ * and/or thread-local storage.
+ * The Providers can be configured to hold ReentrantContext instances in memory
+ * using hard, soft or weak references.
+ *
+ * The acquire() and release() methods are used to retrieve and return the contexts.
+ *
+ * The {@code newContext()} method remains abstract in all implementations and
+ * must be provided by the module to create a new subclass of ReentrantContext
+ * with the appropriate contextual data in it.
+ *
+ * Sample Usage:
+ * - create a subclass ReentrantContextImpl to hold the thread state:
+ *
+ * static final class ReentrantContextImpl extends ReentrantContext {
+ *     // specific cached data
+ * }
+ *
+ * - create the appropriate ReentrantContextProvider:
+ *
+ * private static final ReentrantContextProvider<ReentrantContextImpl> contextProvider =
+ *     new ReentrantContextProviderTL<ReentrantContextImpl>(ReentrantContextProvider.REF_WEAK)
+ *     {
+ *         @Override
+ *         protected ReentrantContextImpl newContext() {
+ *             return new ReentrantContextImpl();
+ *         }
+ *     };
+ * ...
+ * void someMethod() {
+ *     ReentrantContextImpl ctx = contextProvider.acquire();
+ *     try {
+ *         // use the context
+ *     } finally {
+ *         contextProvider.release(ctx);
+ *     }
+ * }
+ *
+ * @param <K> ReentrantContext subclass
+ *
+ * @see ReentrantContext
+ */
+public abstract class ReentrantContextProvider<K extends ReentrantContext>
+{
+    // thread-local storage: inactive
+    static final byte USAGE_TL_INACTIVE = 0;
+    // thread-local storage: in use
+    static final byte USAGE_TL_IN_USE = 1;
+    // CLQ storage
+    static final byte USAGE_CLQ = 2;
+
+    // hard reference
+    public static final int REF_HARD = 0;
+    // soft reference
+    public static final int REF_SOFT = 1;
+    // weak reference
+    public static final int REF_WEAK = 2;
+
+    /* members */
+    // internal reference type
+    private final int refType;
+
+    /**
+     * Create a new ReentrantContext provider using the given reference type
+     * among hard, soft or weak
+     *
+     * @param refType reference type
+     */
+    protected ReentrantContextProvider(final int refType) {
+        this.refType = refType;
+    }
+
+    /**
+     * Create a new ReentrantContext instance
+     *
+     * @return new ReentrantContext instance
+     */
+    protected abstract K newContext();
+
+    /**
+     * Give a ReentrantContext instance for the current thread
+     *
+     * @return ReentrantContext instance
+     */
+    public abstract K acquire();
+
+    /**
+     * Restore the given ReentrantContext instance for reuse
+     *
+     * @param ctx ReentrantContext instance
+     */
+    public abstract void release(K ctx);
+
+    @SuppressWarnings("unchecked")
+    protected final Reference<K> getOrCreateReference(final K ctx) {
+        if (ctx.reference == null) {
+            // Create the reference:
+            switch (refType) {
+                case REF_HARD:
+                    ctx.reference = new HardReference<K>(ctx);
+                    break;
+                case REF_SOFT:
+                    ctx.reference = new SoftReference<K>(ctx);
+                    break;
+                default:
+                case REF_WEAK:
+                    ctx.reference = new WeakReference<K>(ctx);
+                    break;
+            }
+        }
+        return (Reference<K>) ctx.reference;
+    }
+
+    /* Missing HardReference implementation */
+    static final class HardReference<V> extends WeakReference<V> {
+        // kept strong reference:
+        private final V strongRef;
+
+        HardReference(final V referent) {
+            // no referent needed for the parent WeakReference:
+            super(null);
+            this.strongRef = referent;
+        }
+
+        @Override
+        public V get() {
+            return strongRef;
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/ReentrantContextProviderCLQ.java b/src/share/classes/sun/java2d/ReentrantContextProviderCLQ.java
new file mode 100644
index 0000000..22978ce
--- /dev/null
+++ b/src/share/classes/sun/java2d/ReentrantContextProviderCLQ.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+package sun.java2d;
+
+import java.lang.ref.Reference;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/**
+ * This ReentrantContextProvider implementation uses one ConcurrentLinkedQueue
+ * to store all ReentrantContext instances (thread and its child contexts)
+ *
+ * Note: this implementation keeps less contexts in memory depending on the
+ * concurrent active threads in contrary to a ThreadLocal provider. However,
+ * it is slower in highly concurrent workloads.
+ *
+ * @param <K> ReentrantContext subclass
+ */
+public abstract class ReentrantContextProviderCLQ<K extends ReentrantContext>
+    extends ReentrantContextProvider<K>
+{
+    // ReentrantContext queue to store all contexts
+    private final ConcurrentLinkedQueue<Reference<K>> ctxQueue
+        = new ConcurrentLinkedQueue<Reference<K>>();
+
+    /**
+     * Create a new ReentrantContext provider using the given reference type
+     * among hard, soft or weak based using a ConcurrentLinkedQueue storage
+     *
+     * @param refType reference type
+     */
+    public ReentrantContextProviderCLQ(final int refType) {
+        super(refType);
+    }
+
+    /**
+     * Give a ReentrantContext instance for the current thread
+     *
+     * @return ReentrantContext instance
+     */
+    @Override
+    public final K acquire() {
+        K ctx = null;
+        // Drain queue if all referent are null:
+        Reference<K> ref = null;
+        while ((ctx == null) && ((ref = ctxQueue.poll()) != null)) {
+            ctx = ref.get();
+        }
+        if (ctx == null) {
+            // create a new ReentrantContext if none is available
+            ctx = newContext();
+            ctx.usage = USAGE_CLQ;
+        }
+        return ctx;
+    }
+
+    /**
+     * Restore the given ReentrantContext instance for reuse
+     *
+     * @param ctx ReentrantContext instance
+     */
+    @Override
+    public final void release(final K ctx) {
+        if (ctx.usage == USAGE_CLQ) {
+            ctxQueue.offer(getOrCreateReference(ctx));
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/ReentrantContextProviderTL.java b/src/share/classes/sun/java2d/ReentrantContextProviderTL.java
new file mode 100644
index 0000000..14dcb84
--- /dev/null
+++ b/src/share/classes/sun/java2d/ReentrantContextProviderTL.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+package sun.java2d;
+
+import java.lang.ref.Reference;
+
+/**
+* This ReentrantContextProvider implementation uses a ThreadLocal to hold
+ * the first ReentrantContext per thread and a ReentrantContextProviderCLQ to
+ * store child ReentrantContext instances needed during recursion.
+ *
+ * Note: this implementation may keep up to one context in memory per thread.
+ * Child contexts for recursive uses are stored in the queue using a WEAK
+ * reference by default unless specified in the 2 argument constructor.
+ *
+ * @param <K> ReentrantContext subclass
+ */
+public abstract class ReentrantContextProviderTL<K extends ReentrantContext>
+    extends ReentrantContextProvider<K>
+{
+    // Thread-local storage:
+    private final ThreadLocal<Reference<K>> ctxTL
+        = new ThreadLocal<Reference<K>>();
+
+    // ReentrantContext CLQ provider for child contexts:
+    private final ReentrantContextProviderCLQ<K> ctxProviderCLQ;
+
+    /**
+     * Create a new ReentrantContext provider using the given reference type
+     * among hard, soft or weak.
+     * It uses weak reference for the child contexts.
+     *
+     * @param refType reference type
+     */
+    public ReentrantContextProviderTL(final int refType) {
+        this(refType, REF_WEAK);
+    }
+
+    /**
+     * Create a new ReentrantContext provider using the given reference types
+     * among hard, soft or weak
+     *
+     * @param refTypeTL reference type used by ThreadLocal
+     * @param refTypeCLQ reference type used by ReentrantContextProviderCLQ
+     */
+    public ReentrantContextProviderTL(final int refTypeTL, final int refTypeCLQ)
+    {
+        super(refTypeTL);
+
+        final ReentrantContextProviderTL<K> parent = this;
+
+        this.ctxProviderCLQ = new ReentrantContextProviderCLQ<K>(refTypeCLQ) {
+            @Override
+            protected K newContext() {
+                return parent.newContext();
+            }
+        };
+    }
+
+    /**
+     * Give a ReentrantContext instance for the current thread
+     *
+     * @return ReentrantContext instance
+     */
+    @Override
+    public final K acquire() {
+        K ctx = null;
+        final Reference<K> ref = ctxTL.get();
+        if (ref != null) {
+            ctx = ref.get();
+        }
+        if (ctx == null) {
+            // create a new ReentrantContext if none is available
+            ctx = newContext();
+            // update thread local reference:
+            ctxTL.set(getOrCreateReference(ctx));
+        }
+        // Check reentrance:
+        if (ctx.usage == USAGE_TL_INACTIVE) {
+           ctx.usage = USAGE_TL_IN_USE;
+        } else {
+            // get or create another ReentrantContext from CLQ provider:
+            ctx = ctxProviderCLQ.acquire();
+        }
+        return ctx;
+    }
+
+    /**
+     * Restore the given ReentrantContext instance for reuse
+     *
+     * @param ctx ReentrantContext instance
+     */
+    @Override
+    public final void release(final K ctx) {
+        if (ctx.usage == USAGE_TL_IN_USE) {
+           ctx.usage = USAGE_TL_INACTIVE;
+        } else {
+            ctxProviderCLQ.release(ctx);
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/SunGraphics2D.java b/src/share/classes/sun/java2d/SunGraphics2D.java
index 0ad5e16..23ea0af 100644
--- a/src/share/classes/sun/java2d/SunGraphics2D.java
+++ b/src/share/classes/sun/java2d/SunGraphics2D.java
@@ -61,7 +61,6 @@
 import java.awt.Rectangle;
 import java.text.AttributedCharacterIterator;
 import java.awt.Font;
-import java.awt.Point;
 import java.awt.image.ImageObserver;
 import java.awt.Transparency;
 import java.awt.font.GlyphVector;
@@ -94,11 +93,12 @@
 import sun.misc.PerformanceLogger;
 
 import java.lang.annotation.Native;
-import sun.awt.image.MultiResolutionImage;
+import java.awt.image.MultiResolutionImage;
 
 import static java.awt.geom.AffineTransform.TYPE_FLIP;
 import static java.awt.geom.AffineTransform.TYPE_MASK_SCALE;
 import static java.awt.geom.AffineTransform.TYPE_TRANSLATION;
+import java.awt.image.VolatileImage;
 import sun.awt.image.MultiResolutionToolkitImage;
 import sun.awt.image.ToolkitImage;
 
@@ -244,7 +244,6 @@
     public Shape usrClip;
     protected Region devClip;           // Actual physical drawable in pixels
 
-    private final int devScale;         // Actual physical scale factor
     private int resolutionVariantHint;
 
     // cached state for text rendering
@@ -268,8 +267,6 @@
         surfaceData = sd;
         foregroundColor = fg;
         backgroundColor = bg;
-
-        transform = new AffineTransform();
         stroke = defaultStroke;
         composite = defaultComposite;
         paint = foregroundColor;
@@ -287,14 +284,13 @@
 
         interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
 
-        validateColor();
-
-        devScale = sd.getDefaultScale();
-        if (devScale != 1) {
-            transform.setToScale(devScale, devScale);
+        transform = getDefaultTransform();
+        if (!transform.isIdentity()) {
             invalidateTransform();
         }
 
+        validateColor();
+
         font = f;
         if (font == null) {
             font = defaultFont;
@@ -304,6 +300,11 @@
         invalidatePipe();
     }
 
+    private AffineTransform getDefaultTransform() {
+        GraphicsConfiguration gc = getDeviceConfiguration();
+        return (gc == null) ? new AffineTransform() : gc.getDefaultTransform();
+    }
+
     protected Object clone() {
         try {
             SunGraphics2D g = (SunGraphics2D) super.clone();
@@ -1607,11 +1608,10 @@
      */
     @Override
     public void setTransform(AffineTransform Tx) {
-        if ((constrainX | constrainY) == 0 && devScale == 1) {
+        if ((constrainX | constrainY) == 0) {
             transform.setTransform(Tx);
         } else {
-            transform.setTransform(devScale, 0, 0, devScale, constrainX,
-                                   constrainY);
+            transform.setToTranslation(constrainX, constrainY);
             transform.concatenate(Tx);
         }
         invalidateTransform();
@@ -1671,13 +1671,11 @@
      */
     @Override
     public AffineTransform getTransform() {
-        if ((constrainX | constrainY) == 0 && devScale == 1) {
+        if ((constrainX | constrainY) == 0) {
             return new AffineTransform(transform);
         }
-        final double invScale = 1.0 / devScale;
-        AffineTransform tx = new AffineTransform(invScale, 0, 0, invScale,
-                                                 -constrainX * invScale,
-                                                 -constrainY * invScale);
+        AffineTransform tx
+                = AffineTransform.getTranslateInstance(-constrainX, -constrainY);
         tx.concatenate(transform);
         return tx;
     }
@@ -3086,31 +3084,50 @@
     }
 // end of text rendering methods
 
-    private boolean isHiDPIImage(final Image img) {
-        return (SurfaceManager.getImageScale(img) != 1) ||
-               (resolutionVariantHint != SunHints.INTVAL_RESOLUTION_VARIANT_OFF
-                    && img instanceof MultiResolutionImage);
-    }
+    private Boolean drawHiDPIImage(Image img,
+                                   int dx1, int dy1, int dx2, int dy2,
+                                   int sx1, int sy1, int sx2, int sy2,
+                                   Color bgcolor, ImageObserver observer,
+                                   AffineTransform xform) {
 
-    private boolean drawHiDPIImage(Image img, int dx1, int dy1, int dx2,
-                                   int dy2, int sx1, int sy1, int sx2, int sy2,
-                                   Color bgcolor, ImageObserver observer) {
+        if (img instanceof VolatileImage) {
+            final SurfaceData sd = SurfaceManager.getManager(img)
+                    .getPrimarySurfaceData();
+            final double scaleX = sd.getDefaultScaleX();
+            final double scaleY = sd.getDefaultScaleY();
+            if (scaleX == 1 && scaleY == 1) {
+                return null;
+            }
+            sx1 = Region.clipScale(sx1, scaleX);
+            sx2 = Region.clipScale(sx2, scaleX);
+            sy1 = Region.clipScale(sy1, scaleY);
+            sy2 = Region.clipScale(sy2, scaleY);
 
-        if (SurfaceManager.getImageScale(img) != 1) {  // Volatile Image
-            final int scale = SurfaceManager.getImageScale(img);
-            sx1 = Region.clipScale(sx1, scale);
-            sx2 = Region.clipScale(sx2, scale);
-            sy1 = Region.clipScale(sy1, scale);
-            sy2 = Region.clipScale(sy2, scale);
-        } else if (img instanceof MultiResolutionImage) {
+            AffineTransform tx = null;
+            if (xform != null) {
+                tx = new AffineTransform(transform);
+                transform(xform);
+            }
+            boolean result = scaleImage(img, dx1, dy1, dx2, dy2,
+                                        sx1, sy1, sx2, sy2,
+                                        bgcolor, observer);
+            if (tx != null) {
+                transform.setTransform(tx);
+                invalidateTransform();
+            }
+            return result;
+        } else if (resolutionVariantHint != SunHints.INTVAL_RESOLUTION_VARIANT_BASE
+                && (img instanceof MultiResolutionImage)) {
             // get scaled destination image size
 
             int width = img.getWidth(observer);
             int height = img.getHeight(observer);
 
-            Image resolutionVariant = getResolutionVariant(
-                    (MultiResolutionImage) img, width, height,
-                    dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2);
+            MultiResolutionImage mrImage = (MultiResolutionImage) img;
+            Image resolutionVariant = getResolutionVariant(mrImage, width, height,
+                                                           dx1, dy1, dx2, dy2,
+                                                           sx1, sy1, sx2, sy2,
+                                                           xform);
 
             if (resolutionVariant != img && resolutionVariant != null) {
                 // recalculate source region for the resolution variant
@@ -3124,8 +3141,8 @@
 
                 if (0 < width && 0 < height && 0 < rvWidth && 0 < rvHeight) {
 
-                    float widthScale = ((float) rvWidth) / width;
-                    float heightScale = ((float) rvHeight) / height;
+                    double widthScale = ((double) rvWidth) / width;
+                    double heightScale = ((double) rvHeight) / height;
 
                     sx1 = Region.clipScale(sx1, widthScale);
                     sy1 = Region.clipScale(sy1, heightScale);
@@ -3134,10 +3151,29 @@
 
                     observer = rvObserver;
                     img = resolutionVariant;
+
+                    if (xform != null) {
+                        assert dx1 == 0 && dy1 == 0;
+                        assert dx2 == img.getWidth(observer);
+                        assert dy2 == img.getHeight(observer);
+                        AffineTransform renderTX = new AffineTransform(xform);
+                        renderTX.scale(1 / widthScale, 1 / heightScale);
+                        return transformImage(img, renderTX, observer);
+                    }
+
+                    return scaleImage(img, dx1, dy1, dx2, dy2,
+                                      sx1, sy1, sx2, sy2,
+                                      bgcolor, observer);
                 }
             }
         }
+        return null;
+    }
 
+    private boolean scaleImage(Image img, int dx1, int dy1, int dx2, int dy2,
+                               int sx1, int sy1, int sx2, int sy2,
+                               Color bgcolor, ImageObserver observer)
+    {
         try {
             return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, sx1, sy1,
                                         sx2, sy2, bgcolor, observer);
@@ -3157,9 +3193,30 @@
         }
     }
 
+    private boolean transformImage(Image img,
+                                   AffineTransform xform,
+                                   ImageObserver observer)
+    {
+        try {
+            return imagepipe.transformImage(this, img, xform, observer);
+        } catch (InvalidPipeException e) {
+            try {
+                revalidateAll();
+                return imagepipe.transformImage(this, img, xform, observer);
+            } catch (InvalidPipeException e2) {
+                // Still catching the exception; we are not yet ready to
+                // validate the surfaceData correctly.  Fail for now and
+                // try again next time around.
+                return false;
+            }
+        } finally {
+            surfaceData.markDirty();
+        }
+    }
+
     private Image getResolutionVariant(MultiResolutionImage img,
             int srcWidth, int srcHeight, int dx1, int dy1, int dx2, int dy2,
-            int sx1, int sy1, int sx2, int sy2) {
+            int sx1, int sy1, int sx2, int sy2, AffineTransform xform) {
 
         if (srcWidth <= 0 || srcHeight <= 0) {
             return null;
@@ -3172,27 +3229,53 @@
             return null;
         }
 
-        int type = transform.getType();
-        int dw = dx2 - dx1;
-        int dh = dy2 - dy1;
-        double destRegionWidth;
-        double destRegionHeight;
+        AffineTransform tx;
 
-        if ((type & ~(TYPE_TRANSLATION | TYPE_FLIP)) == 0) {
-            destRegionWidth = dw;
-            destRegionHeight = dh;
-        } else if ((type & ~(TYPE_TRANSLATION | TYPE_FLIP | TYPE_MASK_SCALE)) == 0) {
-            destRegionWidth = dw * transform.getScaleX();
-            destRegionHeight = dh * transform.getScaleY();
+        if (xform == null) {
+            tx = transform;
         } else {
-            destRegionWidth = dw * Math.hypot(
-                    transform.getScaleX(), transform.getShearY());
-            destRegionHeight = dh * Math.hypot(
-                    transform.getShearX(), transform.getScaleY());
+            tx = new AffineTransform(transform);
+            tx.concatenate(xform);
         }
 
-        int destImageWidth = (int) Math.abs(srcWidth * destRegionWidth / sw);
-        int destImageHeight = (int) Math.abs(srcHeight * destRegionHeight / sh);
+        int type = tx.getType();
+        int dw = dx2 - dx1;
+        int dh = dy2 - dy1;
+
+        double destImageWidth;
+        double destImageHeight;
+
+        if (resolutionVariantHint == SunHints.INTVAL_RESOLUTION_VARIANT_BASE) {
+            destImageWidth = srcWidth;
+            destImageHeight = srcHeight;
+        } else if (resolutionVariantHint == SunHints.INTVAL_RESOLUTION_VARIANT_DPI_FIT) {
+            AffineTransform configTransform = getDefaultTransform();
+            if (configTransform.isIdentity()) {
+                destImageWidth = srcWidth;
+                destImageHeight = srcHeight;
+            } else {
+                destImageWidth = srcWidth * configTransform.getScaleX();
+                destImageHeight = srcHeight * configTransform.getScaleY();
+            }
+        } else {
+            double destRegionWidth;
+            double destRegionHeight;
+
+            if ((type & ~(TYPE_TRANSLATION | TYPE_FLIP)) == 0) {
+                destRegionWidth = dw;
+                destRegionHeight = dh;
+            } else if ((type & ~(TYPE_TRANSLATION | TYPE_FLIP | TYPE_MASK_SCALE)) == 0) {
+                destRegionWidth = dw * transform.getScaleX();
+                destRegionHeight = dh * transform.getScaleY();
+            } else {
+                destRegionWidth = dw * Math.hypot(
+                        transform.getScaleX(), transform.getShearY());
+                destRegionHeight = dh * Math.hypot(
+                        transform.getShearX(), transform.getScaleY());
+            }
+            destImageWidth = Math.abs(srcWidth * destRegionWidth / sw);
+            destImageHeight = Math.abs(srcHeight * destRegionHeight / sh);
+        }
 
         Image resolutionVariant
                 = img.getResolutionVariant(destImageWidth, destImageHeight);
@@ -3261,9 +3344,11 @@
 
         final int imgW = img.getWidth(null);
         final int imgH = img.getHeight(null);
-        if (isHiDPIImage(img)) {
-            return drawHiDPIImage(img, x, y, x + width, y + height, 0, 0, imgW,
-                                  imgH, bg, observer);
+        Boolean hidpiImageDrawn = drawHiDPIImage(img, x, y, x + width, y + height,
+                                                 0, 0, imgW, imgH, bg, observer,
+                                                 null);
+        if (hidpiImageDrawn != null) {
+            return hidpiImageDrawn;
         }
 
         if (width == imgW && height == imgH) {
@@ -3307,11 +3392,13 @@
             return true;
         }
 
-        if (isHiDPIImage(img)) {
-            final int imgW = img.getWidth(null);
-            final int imgH = img.getHeight(null);
-            return drawHiDPIImage(img, x, y, x + imgW, y + imgH, 0, 0, imgW,
-                                  imgH, bg, observer);
+        final int imgW = img.getWidth(null);
+        final int imgH = img.getHeight(null);
+        Boolean hidpiImageDrawn = drawHiDPIImage(img, x, y, x + imgW, y + imgH,
+                                                 0, 0, imgW, imgH, bg, observer,
+                                                 null);
+        if (hidpiImageDrawn != null) {
+            return hidpiImageDrawn;
         }
 
         try {
@@ -3362,9 +3449,12 @@
             return true;
         }
 
-        if (isHiDPIImage(img)) {
-            return drawHiDPIImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2,
-                                  bgcolor, observer);
+        Boolean hidpiImageDrawn = drawHiDPIImage(img, dx1, dy1, dx2, dy2,
+                                                 sx1, sy1, sx2, sy2,
+                                                 bgcolor, observer, null);
+
+        if (hidpiImageDrawn != null) {
+            return hidpiImageDrawn;
         }
 
         if (((sx2 - sx1) == (dx2 - dx1)) &&
@@ -3445,33 +3535,16 @@
             return drawImage(img, 0, 0, null, observer);
         }
 
-        if (isHiDPIImage(img)) {
-            final int w = img.getWidth(null);
-            final int h = img.getHeight(null);
-            final AffineTransform tx = new AffineTransform(transform);
-            transform(xform);
-            boolean result = drawHiDPIImage(img, 0, 0, w, h, 0, 0, w, h, null,
-                                            observer);
-            transform.setTransform(tx);
-            invalidateTransform();
-            return result;
+        final int w = img.getWidth(null);
+        final int h = img.getHeight(null);
+        Boolean hidpiImageDrawn = drawHiDPIImage(img, 0, 0, w, h, 0, 0, w, h,
+                                                 null, observer, xform);
+
+        if (hidpiImageDrawn != null) {
+            return hidpiImageDrawn;
         }
 
-        try {
-            return imagepipe.transformImage(this, img, xform, observer);
-        } catch (InvalidPipeException e) {
-            try {
-                revalidateAll();
-                return imagepipe.transformImage(this, img, xform, observer);
-            } catch (InvalidPipeException e2) {
-                // Still catching the exception; we are not yet ready to
-                // validate the surfaceData correctly.  Fail for now and
-                // try again next time around.
-                return false;
-            }
-        } finally {
-            surfaceData.markDirty();
-        }
+        return transformImage(img, xform, observer);
     }
 
     public void drawImage(BufferedImage bImg,
diff --git a/src/share/classes/sun/java2d/SunGraphicsEnvironment.java b/src/share/classes/sun/java2d/SunGraphicsEnvironment.java
index b43a071..1d59f38 100644
--- a/src/share/classes/sun/java2d/SunGraphicsEnvironment.java
+++ b/src/share/classes/sun/java2d/SunGraphicsEnvironment.java
@@ -66,6 +66,8 @@
 import sun.font.FontManagerFactory;
 import sun.font.FontManagerForSGE;
 import sun.font.NativeFont;
+import java.security.AccessController;
+import sun.security.action.GetPropertyAction;
 
 /**
  * This is an implementation of a GraphicsEnvironment object for the
@@ -80,6 +82,15 @@
     public static boolean isOpenSolaris;
     private static Font defaultFont;
 
+    private static final boolean uiScaleEnabled;
+    private static final double debugScale;
+
+    static {
+        uiScaleEnabled = "true".equals(AccessController.doPrivileged(
+                new GetPropertyAction("sun.java2d.uiScale.enabled", "false")));
+        debugScale = uiScaleEnabled ? getScaleFactor("sun.java2d.uiScale") : -1;
+    }
+
     public SunGraphicsEnvironment() {
         java.security.AccessController.doPrivileged(
                                     new java.security.PrivilegedAction() {
@@ -339,4 +350,56 @@
     public boolean isFlipStrategyPreferred(ComponentPeer peer) {
         return false;
     }
+
+    public static boolean isUIScaleEnabled() {
+        return uiScaleEnabled;
+    }
+
+    /**
+     * [tav] todo: Temp, until fractional scale is supported well enough.
+     *             Called via reflection from the client code.
+     */
+    protected boolean isUIScaleOn() {
+        // [tav] check if native JDK scaled up any of the displays
+        for (GraphicsDevice d : getScreenDevices()) {
+            if (d.getDefaultConfiguration().getDefaultTransform().getScaleX() > 1 ||
+                d.getDefaultConfiguration().getDefaultTransform().getScaleY() > 1) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static double getDebugScale() {
+        return debugScale;
+    }
+
+    public static double getScaleFactor(String propertyName) {
+
+        String scaleFactor = AccessController.doPrivileged(
+                new GetPropertyAction(propertyName, "-1"));
+
+        if (scaleFactor == null || scaleFactor.equals("-1")) {
+            return -1;
+        }
+
+        try {
+            double units = 1.0;
+
+            if (scaleFactor.endsWith("x")) {
+                scaleFactor = scaleFactor.substring(0, scaleFactor.length() - 1);
+            } else if (scaleFactor.endsWith("dpi")) {
+                units = 96;
+                scaleFactor = scaleFactor.substring(0, scaleFactor.length() - 3);
+            } else if (scaleFactor.endsWith("%")) {
+                units = 100;
+                scaleFactor = scaleFactor.substring(0, scaleFactor.length() - 1);
+            }
+
+            double scale = Double.parseDouble(scaleFactor);
+            return scale <= 0 ? -1 : scale / units;
+        } catch (NumberFormatException ignored) {
+            return -1;
+        }
+    }
 }
diff --git a/src/share/classes/sun/java2d/SurfaceData.java b/src/share/classes/sun/java2d/SurfaceData.java
index c1b8bf7..c60cf55 100644
--- a/src/share/classes/sun/java2d/SurfaceData.java
+++ b/src/share/classes/sun/java2d/SurfaceData.java
@@ -52,6 +52,7 @@
 import sun.java2d.loops.DrawGlyphList;
 import sun.java2d.loops.DrawGlyphListAA;
 import sun.java2d.loops.DrawGlyphListLCD;
+import sun.java2d.loops.DrawGlyphListColor;
 import sun.java2d.pipe.LoopPipe;
 import sun.java2d.pipe.ShapeDrawPipe;
 import sun.java2d.pipe.ParallelogramPipe;
@@ -887,6 +888,7 @@
         loops.drawGlyphListLoop = DrawGlyphList.locate(src, comp, dst);
         loops.drawGlyphListAALoop = DrawGlyphListAA.locate(src, comp, dst);
         loops.drawGlyphListLCDLoop = DrawGlyphListLCD.locate(src, comp, dst);
+        loops.drawGlyphListColorLoop = DrawGlyphListColor.locate(src, comp, dst);
         /*
         System.out.println("drawLine: "+loops.drawLineLoop);
         System.out.println("fillRect: "+loops.fillRectLoop);
@@ -1059,12 +1061,32 @@
     public abstract Object getDestination();
 
     /**
-     * Returns default scale factor of the destination surface. Scale factor
-     * describes the mapping between virtual and physical coordinates of the
+     * Returns default scale factor of the destination surface.
+     *
+     * @deprecated use {@link #getDefaultScaleX()} {@link #getDefaultScaleY()}
+     */
+    @Deprecated
+    public int getDefaultScale() {
+        return (int)getDefaultScaleX();
+    }
+
+    /**
+     * Returns default horizontal scale factor of the destination surface. Scale
+     * factor describes the mapping between virtual and physical coordinates of the
      * SurfaceData. If the scale is 2 then virtual pixel coordinates need to be
      * doubled for physical pixels.
      */
-    public int getDefaultScale() {
+    public double getDefaultScaleX() {
+        return 1;
+    }
+
+    /**
+     * Returns default vertical scale factor of the destination surface. Scale
+     * factor describes the mapping between virtual and physical coordinates of the
+     * SurfaceData. If the scale is 2 then virtual pixel coordinates need to be
+     * doubled for physical pixels.
+     */
+    public double getDefaultScaleY() {
         return 1;
     }
 }
diff --git a/src/share/classes/sun/java2d/loops/DrawGlyphList.java b/src/share/classes/sun/java2d/loops/DrawGlyphList.java
index 0928408..421e322 100644
--- a/src/share/classes/sun/java2d/loops/DrawGlyphList.java
+++ b/src/share/classes/sun/java2d/loops/DrawGlyphList.java
@@ -69,7 +69,7 @@
 
 
     public native void DrawGlyphList(SunGraphics2D sg2d, SurfaceData dest,
-                                     GlyphList srcData);
+                                     GlyphList srcData, int fromGlyph, int toGlyph);
 
     // This instance is used only for lookup.
     static {
@@ -95,16 +95,14 @@
         }
 
         public void DrawGlyphList(SunGraphics2D sg2d, SurfaceData dest,
-                                  GlyphList gl) {
+                                  GlyphList gl, int fromGlyph, int toGlyph) {
 
-            int strbounds[] = gl.getBounds(); // Don't delete, bug 4895493
-            int num = gl.getNumGlyphs();
             Region clip = sg2d.getCompClip();
             int cx1 = clip.getLoX();
             int cy1 = clip.getLoY();
             int cx2 = clip.getHiX();
             int cy2 = clip.getHiY();
-            for (int i = 0; i < num; i++) {
+            for (int i = fromGlyph; i < toGlyph; i++) {
                 gl.setGlyphIndex(i);
                 int metrics[] = gl.getMetrics();
                 int gx1 = metrics[0];
@@ -152,10 +150,10 @@
         }
 
         public void DrawGlyphList(SunGraphics2D sg2d, SurfaceData dest,
-                                  GlyphList glyphs)
+                                  GlyphList glyphs, int fromGlyph, int toGlyph)
         {
             tracePrimitive(target);
-            target.DrawGlyphList(sg2d, dest, glyphs);
+            target.DrawGlyphList(sg2d, dest, glyphs, fromGlyph, toGlyph);
         }
     }
 }
diff --git a/src/share/classes/sun/java2d/loops/DrawGlyphListAA.java b/src/share/classes/sun/java2d/loops/DrawGlyphListAA.java
index 83aee55..2200db1 100644
--- a/src/share/classes/sun/java2d/loops/DrawGlyphListAA.java
+++ b/src/share/classes/sun/java2d/loops/DrawGlyphListAA.java
@@ -68,7 +68,7 @@
     }
 
     public native void DrawGlyphListAA(SunGraphics2D sg2d, SurfaceData dest,
-                                       GlyphList srcData);
+                                       GlyphList srcData, int fromGlyph, int toGlyph);
 
     static {
         GraphicsPrimitiveMgr.registerGeneral(
@@ -93,16 +93,14 @@
         }
 
         public void DrawGlyphListAA(SunGraphics2D sg2d, SurfaceData dest,
-                                    GlyphList gl)
+                                    GlyphList gl, int fromGlyph, int toGlyph)
         {
-            gl.getBounds(); // Don't delete, bug 4895493
-            int num = gl.getNumGlyphs();
             Region clip = sg2d.getCompClip();
             int cx1 = clip.getLoX();
             int cy1 = clip.getLoY();
             int cx2 = clip.getHiX();
             int cy2 = clip.getHiY();
-            for (int i = 0; i < num; i++) {
+            for (int i = fromGlyph; i < toGlyph; i++) {
                 gl.setGlyphIndex(i);
                 int metrics[] = gl.getMetrics();
                 int gx1 = metrics[0];
@@ -150,10 +148,10 @@
         }
 
         public void DrawGlyphListAA(SunGraphics2D sg2d, SurfaceData dest,
-                                    GlyphList glyphs)
+                                    GlyphList glyphs, int fromGlyph, int toGlyph)
         {
             tracePrimitive(target);
-            target.DrawGlyphListAA(sg2d, dest, glyphs);
+            target.DrawGlyphListAA(sg2d, dest, glyphs, fromGlyph, toGlyph);
         }
     }
 }
diff --git a/src/share/classes/sun/java2d/loops/DrawGlyphListColor.java b/src/share/classes/sun/java2d/loops/DrawGlyphListColor.java
new file mode 100644
index 0000000..3e1ba87
--- /dev/null
+++ b/src/share/classes/sun/java2d/loops/DrawGlyphListColor.java
@@ -0,0 +1,117 @@
+package sun.java2d.loops;
+
+import sun.font.GlyphList;
+import sun.java2d.SunGraphics2D;
+import sun.java2d.SurfaceData;
+import sun.java2d.pipe.Region;
+
+import java.awt.*;
+
+public class DrawGlyphListColor extends GraphicsPrimitive {
+
+    public final static String methodSignature = "DrawGlyphListColor(...)".toString();
+
+    public final static int primTypeID = makePrimTypeID();
+
+    public static DrawGlyphListColor locate(SurfaceType srctype,
+                                            CompositeType comptype,
+                                            SurfaceType dsttype)
+    {
+        return (DrawGlyphListColor)
+            GraphicsPrimitiveMgr.locate(primTypeID,
+                                        srctype, comptype, dsttype);
+    }
+
+    protected DrawGlyphListColor(SurfaceType srctype,
+                                 CompositeType comptype,
+                                 SurfaceType dsttype)
+    {
+        super(methodSignature, primTypeID, srctype, comptype, dsttype);
+    }
+
+
+    public void DrawGlyphListColor(SunGraphics2D sg2d, SurfaceData dest,
+                                     GlyphList srcData, int fromGlyph, int toGlyph) {
+        // actual implementation is in the subclass
+    }
+
+    // This instance is used only for lookup.
+    static {
+        GraphicsPrimitiveMgr.registerGeneral(
+                                new DrawGlyphListColor(null, null, null));
+    }
+
+    public GraphicsPrimitive makePrimitive(SurfaceType srctype,
+                                           CompositeType comptype,
+                                           SurfaceType dsttype) {
+        return new General(srctype, comptype, dsttype);
+    }
+
+    private static class General extends DrawGlyphListColor {
+        private final Blit blit;
+
+        public General(SurfaceType srctype,
+                       CompositeType comptype,
+                       SurfaceType dsttype)
+        {
+            super(srctype, comptype, dsttype);
+            blit = Blit.locate(SurfaceType.IntArgbPre, CompositeType.SrcOverNoEa, dsttype);
+        }
+
+        public void DrawGlyphListColor(SunGraphics2D sg2d, SurfaceData dest,
+                                  GlyphList gl, int fromGlyph, int toGlyph) {
+
+            Region clip = sg2d.getCompClip();
+            int cx1 = clip.getLoX();
+            int cy1 = clip.getLoY();
+            int cx2 = clip.getHiX();
+            int cy2 = clip.getHiY();
+            for (int i = fromGlyph; i < toGlyph; i++) {
+                gl.setGlyphIndex(i);
+                int metrics[] = gl.getMetrics();
+                int x = metrics[0];
+                int y = metrics[1];
+                int w = metrics[2];
+                int h = metrics[3];
+                int gx1 = x;
+                int gy1 = y;
+                int gx2 = x + w;
+                int gy2 = y + h;
+                if (gx1 < cx1) gx1 = cx1;
+                if (gy1 < cy1) gy1 = cy1;
+                if (gx2 > cx2) gx2 = cx2;
+                if (gy2 > cy2) gy2 = cy2;
+                if (gx2 > gx1 && gy2 > gy1) {
+                    blit.Blit(gl.getColorGlyphData(), dest, AlphaComposite.SrcOver, clip,
+                            gx1 - x, gy1 - y, gx1, gy1, gx2 - gx1, gy2 - gy1);
+                }
+            }
+        }
+    }
+
+    public GraphicsPrimitive traceWrap() {
+        return new TraceDrawGlyphListColor(this);
+    }
+
+    private static class TraceDrawGlyphListColor extends DrawGlyphListColor {
+        DrawGlyphListColor target;
+
+        public TraceDrawGlyphListColor(DrawGlyphListColor target) {
+            super(target.getSourceType(),
+                  target.getCompositeType(),
+                  target.getDestType());
+            this.target = target;
+        }
+
+        public GraphicsPrimitive traceWrap() {
+            return this;
+        }
+
+        public void DrawGlyphListColor(SunGraphics2D sg2d, SurfaceData dest,
+                                  GlyphList glyphs, int fromGlyph, int toGlyph)
+        {
+            tracePrimitive(target);
+            target.DrawGlyphListColor(sg2d, dest, glyphs, fromGlyph, toGlyph);
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/loops/DrawGlyphListLCD.java b/src/share/classes/sun/java2d/loops/DrawGlyphListLCD.java
index 892dc64..3d3637d 100644
--- a/src/share/classes/sun/java2d/loops/DrawGlyphListLCD.java
+++ b/src/share/classes/sun/java2d/loops/DrawGlyphListLCD.java
@@ -70,7 +70,7 @@
     }
 
     public native void DrawGlyphListLCD(SunGraphics2D sg2d, SurfaceData dest,
-                                         GlyphList srcData);
+                                         GlyphList srcData, int fromGlyph, int toGlyph);
 
     static {
         GraphicsPrimitiveMgr.registerGeneral(
@@ -108,10 +108,10 @@
         }
 
         public void DrawGlyphListLCD(SunGraphics2D sg2d, SurfaceData dest,
-                                      GlyphList glyphs)
+                                      GlyphList glyphs, int fromGlyph, int toGlyph)
         {
             tracePrimitive(target);
-            target.DrawGlyphListLCD(sg2d, dest, glyphs);
+            target.DrawGlyphListLCD(sg2d, dest, glyphs, fromGlyph, toGlyph);
         }
     }
 }
diff --git a/src/share/classes/sun/java2d/loops/GeneralRenderer.java b/src/share/classes/sun/java2d/loops/GeneralRenderer.java
index ac01d53..2204435 100644
--- a/src/share/classes/sun/java2d/loops/GeneralRenderer.java
+++ b/src/share/classes/sun/java2d/loops/GeneralRenderer.java
@@ -367,7 +367,7 @@
      * reset the glyphs to non-AA after construction.
      */
     static void doDrawGlyphList(SurfaceData sData, PixelWriter pw,
-                                GlyphList gl, Region clip)
+                                GlyphList gl, int fromGlyph, int toGlyph, Region clip)
     {
         int[] bounds = gl.getBounds();
         clip.clipBoxToBounds(bounds);
@@ -380,8 +380,8 @@
             (WritableRaster) sData.getRaster(cx1, cy1, cx2 - cx1, cy2 - cy1);
         pw.setRaster(dstRast);
 
-        int num = gl.getNumGlyphs();
-        for (int i = 0; i < num; i++) {
+        gl.startGlyphIteration();
+        for (int i = fromGlyph; i < toGlyph; i++) {
             gl.setGlyphIndex(i);
             int metrics[] = gl.getMetrics();
             int gx1 = metrics[0];
@@ -973,10 +973,10 @@
     }
 
     public void DrawGlyphList(SunGraphics2D sg2d, SurfaceData sData,
-                              GlyphList gl)
+                              GlyphList gl, int fromGlyph, int toGlyph)
     {
         PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData);
-        GeneralRenderer.doDrawGlyphList(sData, pw, gl, sg2d.getCompClip());
+        GeneralRenderer.doDrawGlyphList(sData, pw, gl, fromGlyph, toGlyph, sg2d.getCompClip());
     }
 }
 
@@ -988,10 +988,10 @@
     }
 
     public void DrawGlyphListAA(SunGraphics2D sg2d, SurfaceData sData,
-                                GlyphList gl)
+                                GlyphList gl, int fromGlyph, int toGlyph)
     {
         PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData);
-        GeneralRenderer.doDrawGlyphList(sData, pw, gl, sg2d.getCompClip());
+        GeneralRenderer.doDrawGlyphList(sData, pw, gl, fromGlyph, toGlyph, sg2d.getCompClip());
     }
 }
 
diff --git a/src/share/classes/sun/java2d/loops/RenderLoops.java b/src/share/classes/sun/java2d/loops/RenderLoops.java
index 3b5a2a6..54b022c 100644
--- a/src/share/classes/sun/java2d/loops/RenderLoops.java
+++ b/src/share/classes/sun/java2d/loops/RenderLoops.java
@@ -52,4 +52,5 @@
     public DrawGlyphList        drawGlyphListLoop;
     public DrawGlyphListAA      drawGlyphListAALoop;
     public DrawGlyphListLCD     drawGlyphListLCDLoop;
+    public DrawGlyphListColor   drawGlyphListColorLoop;
 }
diff --git a/src/share/classes/sun/java2d/marlin/ArrayCache.java b/src/share/classes/sun/java2d/marlin/ArrayCache.java
new file mode 100644
index 0000000..5f36e0d
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/ArrayCache.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+import java.util.Arrays;
+import static sun.java2d.marlin.MarlinUtils.logInfo;
+
+public final class ArrayCache implements MarlinConst {
+
+    static final int BUCKETS = 4;
+    static final int MIN_ARRAY_SIZE = 4096;
+    static final int MAX_ARRAY_SIZE;
+    static final int MASK_CLR_1 = ~1;
+    // threshold to grow arrays only by (3/2) instead of 2
+    static final int THRESHOLD_ARRAY_SIZE;
+    static final int[] ARRAY_SIZES = new int[BUCKETS];
+    // dirty byte array sizes
+    static final int MIN_DIRTY_BYTE_ARRAY_SIZE = 32 * 2048; // 32px x 2048px
+    static final int MAX_DIRTY_BYTE_ARRAY_SIZE;
+    static final int[] DIRTY_BYTE_ARRAY_SIZES = new int[BUCKETS];
+    // large array thresholds:
+    static final long THRESHOLD_LARGE_ARRAY_SIZE;
+    static final long THRESHOLD_HUGE_ARRAY_SIZE;
+    // stats
+    private static int resizeInt = 0;
+    private static int resizeDirtyInt = 0;
+    private static int resizeDirtyFloat = 0;
+    private static int resizeDirtyByte = 0;
+    private static int oversize = 0;
+
+    static {
+        // initialize buckets for int/float arrays
+        int arraySize = MIN_ARRAY_SIZE;
+
+        for (int i = 0; i < BUCKETS; i++, arraySize <<= 2) {
+            ARRAY_SIZES[i] = arraySize;
+
+            if (DO_TRACE) {
+                logInfo("arraySize[" + i + "]: " + arraySize);
+            }
+        }
+        MAX_ARRAY_SIZE = arraySize >> 2;
+
+        /* initialize buckets for dirty byte arrays
+         (large AA chunk = 32 x 2048 pixels) */
+        arraySize = MIN_DIRTY_BYTE_ARRAY_SIZE;
+
+        for (int i = 0; i < BUCKETS; i++, arraySize <<= 1) {
+            DIRTY_BYTE_ARRAY_SIZES[i] = arraySize;
+
+            if (DO_TRACE) {
+                logInfo("dirty arraySize[" + i + "]: " + arraySize);
+            }
+        }
+        MAX_DIRTY_BYTE_ARRAY_SIZE = arraySize >> 1;
+
+        // threshold to grow arrays only by (3/2) instead of 2
+        THRESHOLD_ARRAY_SIZE = Math.max(2 * 1024 * 1024, MAX_ARRAY_SIZE); // 2M
+
+        THRESHOLD_LARGE_ARRAY_SIZE = 8L * THRESHOLD_ARRAY_SIZE; // 16M
+        THRESHOLD_HUGE_ARRAY_SIZE  = 8L * THRESHOLD_LARGE_ARRAY_SIZE; // 128M
+
+        if (DO_STATS || DO_MONITORS) {
+            logInfo("ArrayCache.BUCKETS        = " + BUCKETS);
+            logInfo("ArrayCache.MIN_ARRAY_SIZE = " + MIN_ARRAY_SIZE);
+            logInfo("ArrayCache.MAX_ARRAY_SIZE = " + MAX_ARRAY_SIZE);
+            logInfo("ArrayCache.ARRAY_SIZES = "
+                    + Arrays.toString(ARRAY_SIZES));
+            logInfo("ArrayCache.MIN_DIRTY_BYTE_ARRAY_SIZE = "
+                    + MIN_DIRTY_BYTE_ARRAY_SIZE);
+            logInfo("ArrayCache.MAX_DIRTY_BYTE_ARRAY_SIZE = "
+                    + MAX_DIRTY_BYTE_ARRAY_SIZE);
+            logInfo("ArrayCache.ARRAY_SIZES = "
+                    + Arrays.toString(DIRTY_BYTE_ARRAY_SIZES));
+            logInfo("ArrayCache.THRESHOLD_ARRAY_SIZE = "
+                    + THRESHOLD_ARRAY_SIZE);
+            logInfo("ArrayCache.THRESHOLD_LARGE_ARRAY_SIZE = "
+                    + THRESHOLD_LARGE_ARRAY_SIZE);
+            logInfo("ArrayCache.THRESHOLD_HUGE_ARRAY_SIZE = "
+                    + THRESHOLD_HUGE_ARRAY_SIZE);
+        }
+    }
+
+    private ArrayCache() {
+        // Utility class
+    }
+
+    static synchronized void incResizeInt() {
+        resizeInt++;
+    }
+
+    static synchronized void incResizeDirtyInt() {
+        resizeDirtyInt++;
+    }
+
+    static synchronized void incResizeDirtyFloat() {
+        resizeDirtyFloat++;
+    }
+
+    static synchronized void incResizeDirtyByte() {
+        resizeDirtyByte++;
+    }
+
+    static synchronized void incOversize() {
+        oversize++;
+    }
+
+    static void dumpStats() {
+        if (resizeInt != 0 || resizeDirtyInt != 0 || resizeDirtyFloat != 0
+                || resizeDirtyByte != 0 || oversize != 0) {
+            logInfo("ArrayCache: int resize: " + resizeInt
+                    + " - dirty int resize: " + resizeDirtyInt
+                    + " - dirty float resize: " + resizeDirtyFloat
+                    + " - dirty byte resize: " + resizeDirtyByte
+                    + " - oversize: " + oversize);
+        }
+    }
+
+    // small methods used a lot (to be inlined / optimized by hotspot)
+
+    static int getBucket(final int length) {
+        for (int i = 0; i < ARRAY_SIZES.length; i++) {
+            if (length <= ARRAY_SIZES[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    static int getBucketDirtyBytes(final int length) {
+        for (int i = 0; i < DIRTY_BYTE_ARRAY_SIZES.length; i++) {
+            if (length <= DIRTY_BYTE_ARRAY_SIZES[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Return the new array size (~ x2)
+     * @param curSize current used size
+     * @param needSize needed size
+     * @return new array size
+     */
+    public static int getNewSize(final int curSize, final int needSize) {
+        // check if needSize is negative or integer overflow:
+        if (needSize < 0) {
+            // hard overflow failure - we can't even accommodate
+            // new items without overflowing
+            throw new ArrayIndexOutOfBoundsException(
+                          "array exceeds maximum capacity !");
+        }
+        assert curSize >= 0;
+        final int initial = (curSize & MASK_CLR_1);
+        int size;
+        if (initial > THRESHOLD_ARRAY_SIZE) {
+            size = initial + (initial >> 1); // x(3/2)
+        } else {
+            size = (initial << 1); // x2
+        }
+        // ensure the new size is >= needed size:
+        if (size < needSize) {
+            // align to 4096 (may overflow):
+            size = ((needSize >> 12) + 1) << 12;
+        }
+        // check integer overflow:
+        if (size < 0) {
+            // resize to maximum capacity:
+            size = Integer.MAX_VALUE;
+        }
+        return size;
+    }
+
+    /**
+     * Return the new array size (~ x2)
+     * @param curSize current used size
+     * @param needSize needed size
+     * @return new array size
+     */
+    public static long getNewLargeSize(final long curSize, final long needSize) {
+        // check if needSize is negative or integer overflow:
+        if ((needSize >> 31L) != 0L) {
+            // hard overflow failure - we can't even accommodate
+            // new items without overflowing
+            throw new ArrayIndexOutOfBoundsException(
+                          "array exceeds maximum capacity !");
+        }
+        assert curSize >= 0L;
+        long size;
+        if (curSize > THRESHOLD_HUGE_ARRAY_SIZE) {
+            size = curSize + (curSize >> 2L); // x(5/4)
+        } else  if (curSize > THRESHOLD_LARGE_ARRAY_SIZE) {
+            size = curSize + (curSize >> 1L); // x(3/2)
+        } else {
+            size = (curSize << 1L); // x2
+        }
+        // ensure the new size is >= needed size:
+        if (size < needSize) {
+            // align to 4096:
+            size = ((needSize >> 12L) + 1L) << 12L;
+        }
+        // check integer overflow:
+        if (size > Integer.MAX_VALUE) {
+            // resize to maximum capacity:
+            size = Integer.MAX_VALUE;
+        }
+        return size;
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/ByteArrayCache.java b/src/share/classes/sun/java2d/marlin/ByteArrayCache.java
new file mode 100644
index 0000000..7854795
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/ByteArrayCache.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import static sun.java2d.marlin.MarlinUtils.logException;
+import static sun.java2d.marlin.MarlinUtils.logInfo;
+
+final class ByteArrayCache implements MarlinConst {
+
+    private final int arraySize;
+    private final ArrayDeque<byte[]> byteArrays;
+    // stats
+    private int getOp = 0;
+    private int createOp = 0;
+    private int returnOp = 0;
+
+    void dumpStats() {
+        if (getOp > 0) {
+            logInfo("ByteArrayCache[" + arraySize + "]: get: " + getOp
+                    + " created: " + createOp + " - returned: " + returnOp
+                    + " :: cache size: " + byteArrays.size());
+        }
+    }
+
+    ByteArrayCache(final int arraySize) {
+        this.arraySize = arraySize;
+        // small but enough: almost 1 cache line
+        this.byteArrays = new ArrayDeque<byte[]>(6);
+    }
+
+    byte[] getArray() {
+        if (DO_STATS) {
+            getOp++;
+        }
+
+        // use cache:
+        final byte[] array = byteArrays.pollLast();
+        if (array != null) {
+            return array;
+        }
+
+        if (DO_STATS) {
+            createOp++;
+        }
+
+        return new byte[arraySize];
+    }
+
+    void putDirtyArray(final byte[] array, final int length) {
+        if (length != arraySize) {
+            if (DO_CHECKS) {
+                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
+            }
+            return;
+        }
+        if (DO_STATS) {
+            returnOp++;
+        }
+
+        // NO clean-up of array data = DIRTY ARRAY
+
+        if (DO_CLEAN_DIRTY) {
+            // Force zero-fill dirty arrays:
+            Arrays.fill(array, 0, array.length, BYTE_0);
+        }
+
+        // fill cache:
+        byteArrays.addLast(array);
+    }
+
+    void putArray(final byte[] array, final int length,
+                  final int fromIndex, final int toIndex)
+    {
+        if (length != arraySize) {
+            if (DO_CHECKS) {
+                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
+            }
+            return;
+        }
+        if (DO_STATS) {
+            returnOp++;
+        }
+
+        // clean-up array of dirty part[fromIndex; toIndex[
+        fill(array, fromIndex, toIndex, BYTE_0);
+
+        // fill cache:
+        byteArrays.addLast(array);
+    }
+
+    static void fill(final byte[] array, final int fromIndex,
+                     final int toIndex, final byte value)
+    {
+        // clear array data:
+        /*
+         * Arrays.fill is faster than System.arraycopy(empty array)
+         * or Unsafe.setMemory(byte 0)
+         */
+        if (toIndex != 0) {
+            Arrays.fill(array, fromIndex, toIndex, value);
+        }
+
+        if (DO_CHECKS) {
+            check(array, fromIndex, toIndex, value);
+        }
+    }
+
+    static void check(final byte[] array, final int fromIndex,
+                      final int toIndex, final byte value)
+    {
+        if (DO_CHECKS) {
+            // check zero on full array:
+            for (int i = 0; i < array.length; i++) {
+                if (array[i] != value) {
+                    logException("Invalid value at: " + i + " = " + array[i]
+                            + " from: " + fromIndex + " to: " + toIndex + "\n"
+                            + Arrays.toString(array), new Throwable());
+
+                    // ensure array is correctly filled:
+                    Arrays.fill(array, value);
+
+                    return;
+                }
+            }
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/CollinearSimplifier.java b/src/share/classes/sun/java2d/marlin/CollinearSimplifier.java
new file mode 100644
index 0000000..dbe9c2c
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/CollinearSimplifier.java
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ */
+
+package sun.java2d.marlin;
+
+import sun.awt.geom.PathConsumer2D;
+
+final class CollinearSimplifier implements PathConsumer2D {
+
+    enum SimplifierState {
+
+        Empty, PreviousPoint, PreviousLine
+    };
+    // slope precision threshold
+    static final float EPS = 1e-4f; // aaime proposed 1e-3f
+
+    PathConsumer2D delegate;
+    SimplifierState state;
+    float px1, py1, px2, py2;
+    float pslope;
+
+    CollinearSimplifier() {
+    }
+
+    public CollinearSimplifier init(PathConsumer2D delegate) {
+        this.delegate = delegate;
+        this.state = SimplifierState.Empty;
+
+        return this; // fluent API
+    }
+
+    @Override
+    public void pathDone() {
+        emitStashedLine();
+        state = SimplifierState.Empty;
+        delegate.pathDone();
+    }
+
+    @Override
+    public void closePath() {
+        emitStashedLine();
+        state = SimplifierState.Empty;
+        delegate.closePath();
+    }
+
+    @Override
+    public long getNativeConsumer() {
+        return 0;
+    }
+
+    @Override
+    public void quadTo(float x1, float y1, float x2, float y2) {
+        emitStashedLine();
+        delegate.quadTo(x1, y1, x2, y2);
+        // final end point:
+        state = SimplifierState.PreviousPoint;
+        px1 = x2;
+        py1 = y2;
+    }
+
+    @Override
+    public void curveTo(float x1, float y1, float x2, float y2,
+                        float x3, float y3) {
+        emitStashedLine();
+        delegate.curveTo(x1, y1, x2, y2, x3, y3);
+        // final end point:
+        state = SimplifierState.PreviousPoint;
+        px1 = x3;
+        py1 = y3;
+    }
+
+    @Override
+    public void moveTo(float x, float y) {
+        emitStashedLine();
+        delegate.moveTo(x, y);
+        state = SimplifierState.PreviousPoint;
+        px1 = x;
+        py1 = y;
+    }
+
+    @Override
+    public void lineTo(final float x, final float y) {
+        switch (state) {
+            case Empty:
+                delegate.lineTo(x, y);
+                state = SimplifierState.PreviousPoint;
+                px1 = x;
+                py1 = y;
+                return;
+
+            case PreviousPoint:
+                state = SimplifierState.PreviousLine;
+                px2 = x;
+                py2 = y;
+                pslope = getSlope(px1, py1, x, y);
+                return;
+
+            case PreviousLine:
+                final float slope = getSlope(px2, py2, x, y);
+                // test for collinearity
+                if ((slope == pslope) || (Math.abs(pslope - slope) < EPS)) {
+                    // merge segments
+                    px2 = x;
+                    py2 = y;
+                    return;
+                }
+                // emit previous segment
+                delegate.lineTo(px2, py2);
+                px1 = px2;
+                py1 = py2;
+                px2 = x;
+                py2 = y;
+                pslope = slope;
+                return;
+            default:
+        }
+    }
+
+    private void emitStashedLine() {
+        if (state == SimplifierState.PreviousLine) {
+            delegate.lineTo(px2, py2);
+        }
+    }
+
+    private static float getSlope(float x1, float y1, float x2, float y2) {
+        float dy = y2 - y1;
+        if (dy == 0f) {
+            return (x2 > x1) ? Float.POSITIVE_INFINITY
+                   : Float.NEGATIVE_INFINITY;
+        }
+        return (x2 - x1) / dy;
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/Curve.java b/src/share/classes/sun/java2d/marlin/Curve.java
new file mode 100644
index 0000000..092a38e
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/Curve.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2007, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+final class Curve {
+
+    float ax, ay, bx, by, cx, cy, dx, dy;
+    float dax, day, dbx, dby;
+    // shared iterator instance
+    private final BreakPtrIterator iterator = new BreakPtrIterator();
+
+    Curve() {
+    }
+
+    void set(float[] points, int type) {
+        switch(type) {
+        case 8:
+            set(points[0], points[1],
+                points[2], points[3],
+                points[4], points[5],
+                points[6], points[7]);
+            return;
+        case 6:
+            set(points[0], points[1],
+                points[2], points[3],
+                points[4], points[5]);
+            return;
+        default:
+            throw new InternalError("Curves can only be cubic or quadratic");
+        }
+    }
+
+    void set(float x1, float y1,
+             float x2, float y2,
+             float x3, float y3,
+             float x4, float y4)
+    {
+        ax = 3f * (x2 - x3) + x4 - x1;
+        ay = 3f * (y2 - y3) + y4 - y1;
+        bx = 3f * (x1 - 2f * x2 + x3);
+        by = 3f * (y1 - 2f * y2 + y3);
+        cx = 3f * (x2 - x1);
+        cy = 3f * (y2 - y1);
+        dx = x1;
+        dy = y1;
+        dax = 3f * ax; day = 3f * ay;
+        dbx = 2f * bx; dby = 2f * by;
+    }
+
+    void set(float x1, float y1,
+             float x2, float y2,
+             float x3, float y3)
+    {
+        ax = 0f; ay = 0f;
+        bx = x1 - 2f * x2 + x3;
+        by = y1 - 2f * y2 + y3;
+        cx = 2f * (x2 - x1);
+        cy = 2f * (y2 - y1);
+        dx = x1;
+        dy = y1;
+        dax = 0f; day = 0f;
+        dbx = 2f * bx; dby = 2f * by;
+    }
+
+    float xat(float t) {
+        return t * (t * (t * ax + bx) + cx) + dx;
+    }
+    float yat(float t) {
+        return t * (t * (t * ay + by) + cy) + dy;
+    }
+
+    float dxat(float t) {
+        return t * (t * dax + dbx) + cx;
+    }
+
+    float dyat(float t) {
+        return t * (t * day + dby) + cy;
+    }
+
+    int dxRoots(float[] roots, int off) {
+        return Helpers.quadraticRoots(dax, dbx, cx, roots, off);
+    }
+
+    int dyRoots(float[] roots, int off) {
+        return Helpers.quadraticRoots(day, dby, cy, roots, off);
+    }
+
+    int infPoints(float[] pts, int off) {
+        // inflection point at t if -f'(t)x*f''(t)y + f'(t)y*f''(t)x == 0
+        // Fortunately, this turns out to be quadratic, so there are at
+        // most 2 inflection points.
+        final float a = dax * dby - dbx * day;
+        final float b = 2f * (cy * dax - day * cx);
+        final float c = cy * dbx - cx * dby;
+
+        return Helpers.quadraticRoots(a, b, c, pts, off);
+    }
+
+    // finds points where the first and second derivative are
+    // perpendicular. This happens when g(t) = f'(t)*f''(t) == 0 (where
+    // * is a dot product). Unfortunately, we have to solve a cubic.
+    private int perpendiculardfddf(float[] pts, int off) {
+        assert pts.length >= off + 4;
+
+        // these are the coefficients of some multiple of g(t) (not g(t),
+        // because the roots of a polynomial are not changed after multiplication
+        // by a constant, and this way we save a few multiplications).
+        final float a = 2f * (dax*dax + day*day);
+        final float b = 3f * (dax*dbx + day*dby);
+        final float c = 2f * (dax*cx + day*cy) + dbx*dbx + dby*dby;
+        final float d = dbx*cx + dby*cy;
+        return Helpers.cubicRootsInAB(a, b, c, d, pts, off, 0f, 1f);
+    }
+
+    // Tries to find the roots of the function ROC(t)-w in [0, 1). It uses
+    // a variant of the false position algorithm to find the roots. False
+    // position requires that 2 initial values x0,x1 be given, and that the
+    // function must have opposite signs at those values. To find such
+    // values, we need the local extrema of the ROC function, for which we
+    // need the roots of its derivative; however, it's harder to find the
+    // roots of the derivative in this case than it is to find the roots
+    // of the original function. So, we find all points where this curve's
+    // first and second derivative are perpendicular, and we pretend these
+    // are our local extrema. There are at most 3 of these, so we will check
+    // at most 4 sub-intervals of (0,1). ROC has asymptotes at inflection
+    // points, so roc-w can have at least 6 roots. This shouldn't be a
+    // problem for what we're trying to do (draw a nice looking curve).
+    int rootsOfROCMinusW(float[] roots, int off, final float w, final float err) {
+        // no OOB exception, because by now off<=6, and roots.length >= 10
+        assert off <= 6 && roots.length >= 10;
+        int ret = off;
+        int numPerpdfddf = perpendiculardfddf(roots, off);
+        float t0 = 0, ft0 = ROCsq(t0) - w*w;
+        roots[off + numPerpdfddf] = 1f; // always check interval end points
+        numPerpdfddf++;
+        for (int i = off; i < off + numPerpdfddf; i++) {
+            float t1 = roots[i], ft1 = ROCsq(t1) - w*w;
+            if (ft0 == 0f) {
+                roots[ret++] = t0;
+            } else if (ft1 * ft0 < 0f) { // have opposite signs
+                // (ROC(t)^2 == w^2) == (ROC(t) == w) is true because
+                // ROC(t) >= 0 for all t.
+                roots[ret++] = falsePositionROCsqMinusX(t0, t1, w*w, err);
+            }
+            t0 = t1;
+            ft0 = ft1;
+        }
+
+        return ret - off;
+    }
+
+    private static float eliminateInf(float x) {
+        return (x == Float.POSITIVE_INFINITY ? Float.MAX_VALUE :
+            (x == Float.NEGATIVE_INFINITY ? Float.MIN_VALUE : x));
+    }
+
+    // A slight modification of the false position algorithm on wikipedia.
+    // This only works for the ROCsq-x functions. It might be nice to have
+    // the function as an argument, but that would be awkward in java6.
+    // TODO: It is something to consider for java8 (or whenever lambda
+    // expressions make it into the language), depending on how closures
+    // and turn out. Same goes for the newton's method
+    // algorithm in Helpers.java
+    private float falsePositionROCsqMinusX(float x0, float x1,
+                                           final float x, final float err)
+    {
+        final int iterLimit = 100;
+        int side = 0;
+        float t = x1, ft = eliminateInf(ROCsq(t) - x);
+        float s = x0, fs = eliminateInf(ROCsq(s) - x);
+        float r = s, fr;
+        for (int i = 0; i < iterLimit && Math.abs(t - s) > err * Math.abs(t + s); i++) {
+            r = (fs * t - ft * s) / (fs - ft);
+            fr = ROCsq(r) - x;
+            if (sameSign(fr, ft)) {
+                ft = fr; t = r;
+                if (side < 0) {
+                    fs /= (1 << (-side));
+                    side--;
+                } else {
+                    side = -1;
+                }
+            } else if (fr * fs > 0) {
+                fs = fr; s = r;
+                if (side > 0) {
+                    ft /= (1 << side);
+                    side++;
+                } else {
+                    side = 1;
+                }
+            } else {
+                break;
+            }
+        }
+        return r;
+    }
+
+    private static boolean sameSign(float x, float y) {
+        // another way is to test if x*y > 0. This is bad for small x, y.
+        return (x < 0f && y < 0f) || (x > 0f && y > 0f);
+    }
+
+    // returns the radius of curvature squared at t of this curve
+    // see http://en.wikipedia.org/wiki/Radius_of_curvature_(applications)
+    private float ROCsq(final float t) {
+        // dx=xat(t) and dy=yat(t). These calls have been inlined for efficiency
+        final float dx = t * (t * dax + dbx) + cx;
+        final float dy = t * (t * day + dby) + cy;
+        final float ddx = 2f * dax * t + dbx;
+        final float ddy = 2f * day * t + dby;
+        final float dx2dy2 = dx*dx + dy*dy;
+        final float ddx2ddy2 = ddx*ddx + ddy*ddy;
+        final float ddxdxddydy = ddx*dx + ddy*dy;
+        return dx2dy2*((dx2dy2*dx2dy2) / (dx2dy2 * ddx2ddy2 - ddxdxddydy*ddxdxddydy));
+    }
+
+    // curve to be broken should be in pts
+    // this will change the contents of pts but not Ts
+    // TODO: There's no reason for Ts to be an array. All we need is a sequence
+    // of t values at which to subdivide. An array statisfies this condition,
+    // but is unnecessarily restrictive. Ts should be an Iterator<Float> instead.
+    // Doing this will also make dashing easier, since we could easily make
+    // LengthIterator an Iterator<Float> and feed it to this function to simplify
+    // the loop in Dasher.somethingTo.
+    BreakPtrIterator breakPtsAtTs(final float[] pts, final int type,
+                                  final float[] Ts, final int numTs)
+    {
+        assert pts.length >= 2*type && numTs <= Ts.length;
+
+        // initialize shared iterator:
+        iterator.init(pts, type, Ts, numTs);
+
+        return iterator;
+    }
+
+    static final class BreakPtrIterator {
+        private int nextCurveIdx;
+        private int curCurveOff;
+        private float prevT;
+        private float[] pts;
+        private int type;
+        private float[] ts;
+        private int numTs;
+
+        void init(final float[] pts, final int type,
+                  final float[] ts, final int numTs) {
+            this.pts = pts;
+            this.type = type;
+            this.ts = ts;
+            this.numTs = numTs;
+
+            nextCurveIdx = 0;
+            curCurveOff = 0;
+            prevT = 0f;
+        }
+
+        public boolean hasNext() {
+            return nextCurveIdx <= numTs;
+        }
+
+        public int next() {
+            int ret;
+            if (nextCurveIdx < numTs) {
+                float curT = ts[nextCurveIdx];
+                float splitT = (curT - prevT) / (1f - prevT);
+                Helpers.subdivideAt(splitT,
+                                    pts, curCurveOff,
+                                    pts, 0,
+                                    pts, type, type);
+                prevT = curT;
+                ret = 0;
+                curCurveOff = type;
+            } else {
+                ret = curCurveOff;
+            }
+            nextCurveIdx++;
+            return ret;
+        }
+    }
+}
+
diff --git a/src/share/classes/sun/java2d/marlin/Dasher.java b/src/share/classes/sun/java2d/marlin/Dasher.java
new file mode 100644
index 0000000..890bbf5
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/Dasher.java
@@ -0,0 +1,702 @@
+/*
+ * Copyright (c) 2007, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+import java.util.Arrays;
+import sun.awt.geom.PathConsumer2D;
+
+/**
+ * The <code>Dasher</code> class takes a series of linear commands
+ * (<code>moveTo</code>, <code>lineTo</code>, <code>close</code> and
+ * <code>end</code>) and breaks them into smaller segments according to a
+ * dash pattern array and a starting dash phase.
+ *
+ * <p> Issues: in J2Se, a zero length dash segment as drawn as a very
+ * short dash, whereas Pisces does not draw anything.  The PostScript
+ * semantics are unclear.
+ *
+ */
+final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst {
+
+    static final int REC_LIMIT = 4;
+    static final float ERR = 0.01f;
+    static final float MIN_T_INC = 1f / (1 << REC_LIMIT);
+
+    private PathConsumer2D out;
+    private float[] dash;
+    private int dashLen;
+    private float startPhase;
+    private boolean startDashOn;
+    private int startIdx;
+
+    private boolean starting;
+    private boolean needsMoveTo;
+
+    private int idx;
+    private boolean dashOn;
+    private float phase;
+
+    private float sx, sy;
+    private float x0, y0;
+
+    // temporary storage for the current curve
+    private final float[] curCurvepts;
+
+    // per-thread renderer context
+    final RendererContext rdrCtx;
+
+    // dashes array (dirty)
+    final float[] dashes_initial = new float[INITIAL_ARRAY];
+
+    // flag to recycle dash array copy
+    boolean recycleDashes;
+
+    // per-thread initial arrays (large enough to satisfy most usages
+    // +1 to avoid recycling in Helpers.widenArray()
+    private final float[] firstSegmentsBuffer_initial = new float[INITIAL_ARRAY + 1];
+
+    /**
+     * Constructs a <code>Dasher</code>.
+     * @param rdrCtx per-thread renderer context
+     */
+    Dasher(final RendererContext rdrCtx) {
+        this.rdrCtx = rdrCtx;
+
+        firstSegmentsBuffer = firstSegmentsBuffer_initial;
+
+        // we need curCurvepts to be able to contain 2 curves because when
+        // dashing curves, we need to subdivide it
+        curCurvepts = new float[8 * 2];
+    }
+
+    /**
+     * Initialize the <code>Dasher</code>.
+     *
+     * @param out an output <code>PathConsumer2D</code>.
+     * @param dash an array of <code>float</code>s containing the dash pattern
+     * @param dashLen length of the given dash array
+     * @param phase a <code>float</code> containing the dash phase
+     * @param recycleDashes true to indicate to recycle the given dash array
+     * @return this instance
+     */
+    Dasher init(final PathConsumer2D out, float[] dash, int dashLen,
+                float phase, boolean recycleDashes)
+    {
+        if (phase < 0f) {
+            throw new IllegalArgumentException("phase < 0 !");
+        }
+        this.out = out;
+
+        // Normalize so 0 <= phase < dash[0]
+        int idx = 0;
+        dashOn = true;
+        float d;
+        while (phase >= (d = dash[idx])) {
+            phase -= d;
+            idx = (idx + 1) % dashLen;
+            dashOn = !dashOn;
+        }
+
+        this.dash = dash;
+        this.dashLen = dashLen;
+        this.startPhase = this.phase = phase;
+        this.startDashOn = dashOn;
+        this.startIdx = idx;
+        this.starting = true;
+        needsMoveTo = false;
+        firstSegidx = 0;
+
+        this.recycleDashes = recycleDashes;
+
+        return this; // fluent API
+    }
+
+    /**
+     * Disposes this dasher:
+     * clean up before reusing this instance
+     */
+    void dispose() {
+        if (DO_CLEAN_DIRTY) {
+            // Force zero-fill dirty arrays:
+            Arrays.fill(curCurvepts, 0f);
+            Arrays.fill(firstSegmentsBuffer, 0f);
+        }
+        // Return arrays:
+        if (recycleDashes && dash != dashes_initial) {
+            rdrCtx.putDirtyFloatArray(dash);
+            dash = null;
+        }
+
+        if (firstSegmentsBuffer != firstSegmentsBuffer_initial) {
+            rdrCtx.putDirtyFloatArray(firstSegmentsBuffer);
+            firstSegmentsBuffer = firstSegmentsBuffer_initial;
+        }
+    }
+
+    @Override
+    public void moveTo(float x0, float y0) {
+        if (firstSegidx > 0) {
+            out.moveTo(sx, sy);
+            emitFirstSegments();
+        }
+        needsMoveTo = true;
+        this.idx = startIdx;
+        this.dashOn = this.startDashOn;
+        this.phase = this.startPhase;
+        this.sx = this.x0 = x0;
+        this.sy = this.y0 = y0;
+        this.starting = true;
+    }
+
+    private void emitSeg(float[] buf, int off, int type) {
+        switch (type) {
+        case 8:
+            out.curveTo(buf[off+0], buf[off+1],
+                        buf[off+2], buf[off+3],
+                        buf[off+4], buf[off+5]);
+            return;
+        case 6:
+            out.quadTo(buf[off+0], buf[off+1],
+                       buf[off+2], buf[off+3]);
+            return;
+        case 4:
+            out.lineTo(buf[off], buf[off+1]);
+            return;
+        default:
+        }
+    }
+
+    private void emitFirstSegments() {
+        final float[] fSegBuf = firstSegmentsBuffer;
+
+        for (int i = 0; i < firstSegidx; ) {
+            int type = (int)fSegBuf[i];
+            emitSeg(fSegBuf, i + 1, type);
+            i += (type - 1);
+        }
+        firstSegidx = 0;
+    }
+    // We don't emit the first dash right away. If we did, caps would be
+    // drawn on it, but we need joins to be drawn if there's a closePath()
+    // So, we store the path elements that make up the first dash in the
+    // buffer below.
+    private float[] firstSegmentsBuffer; // dynamic array
+    private int firstSegidx;
+
+    // precondition: pts must be in relative coordinates (relative to x0,y0)
+    // fullCurve is true iff the curve in pts has not been split.
+    private void goTo(float[] pts, int off, final int type) {
+        float x = pts[off + type - 4];
+        float y = pts[off + type - 3];
+        if (dashOn) {
+            if (starting) {
+                int len = type - 2 + 1;
+                int segIdx = firstSegidx;
+                float[] buf = firstSegmentsBuffer;
+                if (segIdx + len  > buf.length) {
+                    if (DO_STATS) {
+                        rdrCtx.stats.stat_array_dasher_firstSegmentsBuffer
+                            .add(segIdx + len);
+                    }
+                    firstSegmentsBuffer = buf
+                        = rdrCtx.widenDirtyFloatArray(buf, segIdx, segIdx + len);
+                }
+                buf[segIdx++] = type;
+                len--;
+                // small arraycopy (2, 4 or 6) but with offset:
+                System.arraycopy(pts, off, buf, segIdx, len);
+                segIdx += len;
+                firstSegidx = segIdx;
+            } else {
+                if (needsMoveTo) {
+                    out.moveTo(x0, y0);
+                    needsMoveTo = false;
+                }
+                emitSeg(pts, off, type);
+            }
+        } else {
+            starting = false;
+            needsMoveTo = true;
+        }
+        this.x0 = x;
+        this.y0 = y;
+    }
+
+    @Override
+    public void lineTo(float x1, float y1) {
+        float dx = x1 - x0;
+        float dy = y1 - y0;
+
+        float len = dx*dx + dy*dy;
+        if (len == 0f) {
+            return;
+        }
+        len = (float) Math.sqrt(len);
+
+        // The scaling factors needed to get the dx and dy of the
+        // transformed dash segments.
+        final float cx = dx / len;
+        final float cy = dy / len;
+
+        final float[] _curCurvepts = curCurvepts;
+        final float[] _dash = dash;
+
+        float leftInThisDashSegment;
+        float dashdx, dashdy, p;
+
+        while (true) {
+            leftInThisDashSegment = _dash[idx] - phase;
+
+            if (len <= leftInThisDashSegment) {
+                _curCurvepts[0] = x1;
+                _curCurvepts[1] = y1;
+                goTo(_curCurvepts, 0, 4);
+
+                // Advance phase within current dash segment
+                phase += len;
+                // TODO: compare float values using epsilon:
+                if (len == leftInThisDashSegment) {
+                    phase = 0f;
+                    idx = (idx + 1) % dashLen;
+                    dashOn = !dashOn;
+                }
+                return;
+            }
+
+            dashdx = _dash[idx] * cx;
+            dashdy = _dash[idx] * cy;
+
+            if (phase == 0f) {
+                _curCurvepts[0] = x0 + dashdx;
+                _curCurvepts[1] = y0 + dashdy;
+            } else {
+                p = leftInThisDashSegment / _dash[idx];
+                _curCurvepts[0] = x0 + p * dashdx;
+                _curCurvepts[1] = y0 + p * dashdy;
+            }
+
+            goTo(_curCurvepts, 0, 4);
+
+            len -= leftInThisDashSegment;
+            // Advance to next dash segment
+            idx = (idx + 1) % dashLen;
+            dashOn = !dashOn;
+            phase = 0f;
+        }
+    }
+
+    // shared instance in Dasher
+    private final LengthIterator li = new LengthIterator();
+
+    // preconditions: curCurvepts must be an array of length at least 2 * type,
+    // that contains the curve we want to dash in the first type elements
+    private void somethingTo(int type) {
+        if (pointCurve(curCurvepts, type)) {
+            return;
+        }
+        li.initializeIterationOnCurve(curCurvepts, type);
+
+        // initially the current curve is at curCurvepts[0...type]
+        int curCurveoff = 0;
+        float lastSplitT = 0f;
+        float t;
+        float leftInThisDashSegment = dash[idx] - phase;
+
+        while ((t = li.next(leftInThisDashSegment)) < 1f) {
+            if (t != 0f) {
+                Helpers.subdivideAt((t - lastSplitT) / (1f - lastSplitT),
+                                    curCurvepts, curCurveoff,
+                                    curCurvepts, 0,
+                                    curCurvepts, type, type);
+                lastSplitT = t;
+                goTo(curCurvepts, 2, type);
+                curCurveoff = type;
+            }
+            // Advance to next dash segment
+            idx = (idx + 1) % dashLen;
+            dashOn = !dashOn;
+            phase = 0f;
+            leftInThisDashSegment = dash[idx];
+        }
+        goTo(curCurvepts, curCurveoff+2, type);
+        phase += li.lastSegLen();
+        if (phase >= dash[idx]) {
+            phase = 0f;
+            idx = (idx + 1) % dashLen;
+            dashOn = !dashOn;
+        }
+        // reset LengthIterator:
+        li.reset();
+    }
+
+    private static boolean pointCurve(float[] curve, int type) {
+        for (int i = 2; i < type; i++) {
+            if (curve[i] != curve[i-2]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    // Objects of this class are used to iterate through curves. They return
+    // t values where the left side of the curve has a specified length.
+    // It does this by subdividing the input curve until a certain error
+    // condition has been met. A recursive subdivision procedure would
+    // return as many as 1<<limit curves, but this is an iterator and we
+    // don't need all the curves all at once, so what we carry out a
+    // lazy inorder traversal of the recursion tree (meaning we only move
+    // through the tree when we need the next subdivided curve). This saves
+    // us a lot of memory because at any one time we only need to store
+    // limit+1 curves - one for each level of the tree + 1.
+    // NOTE: the way we do things here is not enough to traverse a general
+    // tree; however, the trees we are interested in have the property that
+    // every non leaf node has exactly 2 children
+    static final class LengthIterator {
+        private enum Side {LEFT, RIGHT};
+        // Holds the curves at various levels of the recursion. The root
+        // (i.e. the original curve) is at recCurveStack[0] (but then it
+        // gets subdivided, the left half is put at 1, so most of the time
+        // only the right half of the original curve is at 0)
+        private final float[][] recCurveStack; // dirty
+        // sides[i] indicates whether the node at level i+1 in the path from
+        // the root to the current leaf is a left or right child of its parent.
+        private final Side[] sides; // dirty
+        private int curveType;
+        // lastT and nextT delimit the current leaf.
+        private float nextT;
+        private float lenAtNextT;
+        private float lastT;
+        private float lenAtLastT;
+        private float lenAtLastSplit;
+        private float lastSegLen;
+        // the current level in the recursion tree. 0 is the root. limit
+        // is the deepest possible leaf.
+        private int recLevel;
+        private boolean done;
+
+        // the lengths of the lines of the control polygon. Only its first
+        // curveType/2 - 1 elements are valid. This is an optimization. See
+        // next(float) for more detail.
+        private final float[] curLeafCtrlPolyLengths = new float[3];
+
+        LengthIterator() {
+            this.recCurveStack = new float[REC_LIMIT + 1][8];
+            this.sides = new Side[REC_LIMIT];
+            // if any methods are called without first initializing this object
+            // on a curve, we want it to fail ASAP.
+            this.nextT = Float.MAX_VALUE;
+            this.lenAtNextT = Float.MAX_VALUE;
+            this.lenAtLastSplit = Float.MIN_VALUE;
+            this.recLevel = Integer.MIN_VALUE;
+            this.lastSegLen = Float.MAX_VALUE;
+            this.done = true;
+        }
+
+        /**
+         * Reset this LengthIterator.
+         */
+        void reset() {
+            // keep data dirty
+            // as it appears not useful to reset data:
+            if (DO_CLEAN_DIRTY) {
+                final int recLimit = recCurveStack.length - 1;
+                for (int i = recLimit; i >= 0; i--) {
+                    Arrays.fill(recCurveStack[i], 0f);
+                }
+                Arrays.fill(sides, Side.LEFT);
+                Arrays.fill(curLeafCtrlPolyLengths, 0f);
+                Arrays.fill(nextRoots, 0f);
+                Arrays.fill(flatLeafCoefCache, 0f);
+                flatLeafCoefCache[2] = -1f;
+            }
+        }
+
+        void initializeIterationOnCurve(float[] pts, int type) {
+            // optimize arraycopy (8 values faster than 6 = type):
+            System.arraycopy(pts, 0, recCurveStack[0], 0, 8);
+            this.curveType = type;
+            this.recLevel = 0;
+            this.lastT = 0f;
+            this.lenAtLastT = 0f;
+            this.nextT = 0f;
+            this.lenAtNextT = 0f;
+            goLeft(); // initializes nextT and lenAtNextT properly
+            this.lenAtLastSplit = 0f;
+            if (recLevel > 0) {
+                this.sides[0] = Side.LEFT;
+                this.done = false;
+            } else {
+                // the root of the tree is a leaf so we're done.
+                this.sides[0] = Side.RIGHT;
+                this.done = true;
+            }
+            this.lastSegLen = 0f;
+        }
+
+        // 0 == false, 1 == true, -1 == invalid cached value.
+        private int cachedHaveLowAcceleration = -1;
+
+        private boolean haveLowAcceleration(float err) {
+            if (cachedHaveLowAcceleration == -1) {
+                final float len1 = curLeafCtrlPolyLengths[0];
+                final float len2 = curLeafCtrlPolyLengths[1];
+                // the test below is equivalent to !within(len1/len2, 1, err).
+                // It is using a multiplication instead of a division, so it
+                // should be a bit faster.
+                if (!Helpers.within(len1, len2, err*len2)) {
+                    cachedHaveLowAcceleration = 0;
+                    return false;
+                }
+                if (curveType == 8) {
+                    final float len3 = curLeafCtrlPolyLengths[2];
+                    // if len1 is close to 2 and 2 is close to 3, that probably
+                    // means 1 is close to 3 so the second part of this test might
+                    // not be needed, but it doesn't hurt to include it.
+                    final float errLen3 = err * len3;
+                    if (!(Helpers.within(len2, len3, errLen3) &&
+                          Helpers.within(len1, len3, errLen3))) {
+                        cachedHaveLowAcceleration = 0;
+                        return false;
+                    }
+                }
+                cachedHaveLowAcceleration = 1;
+                return true;
+            }
+
+            return (cachedHaveLowAcceleration == 1);
+        }
+
+        // we want to avoid allocations/gc so we keep this array so we
+        // can put roots in it,
+        private final float[] nextRoots = new float[4];
+
+        // caches the coefficients of the current leaf in its flattened
+        // form (see inside next() for what that means). The cache is
+        // invalid when it's third element is negative, since in any
+        // valid flattened curve, this would be >= 0.
+        private final float[] flatLeafCoefCache = new float[]{0f, 0f, -1f, 0f};
+
+        // returns the t value where the remaining curve should be split in
+        // order for the left subdivided curve to have length len. If len
+        // is >= than the length of the uniterated curve, it returns 1.
+        float next(final float len) {
+            final float targetLength = lenAtLastSplit + len;
+            while (lenAtNextT < targetLength) {
+                if (done) {
+                    lastSegLen = lenAtNextT - lenAtLastSplit;
+                    return 1f;
+                }
+                goToNextLeaf();
+            }
+            lenAtLastSplit = targetLength;
+            final float leaflen = lenAtNextT - lenAtLastT;
+            float t = (targetLength - lenAtLastT) / leaflen;
+
+            // cubicRootsInAB is a fairly expensive call, so we just don't do it
+            // if the acceleration in this section of the curve is small enough.
+            if (!haveLowAcceleration(0.05f)) {
+                // We flatten the current leaf along the x axis, so that we're
+                // left with a, b, c which define a 1D Bezier curve. We then
+                // solve this to get the parameter of the original leaf that
+                // gives us the desired length.
+                final float[] _flatLeafCoefCache = flatLeafCoefCache;
+
+                if (_flatLeafCoefCache[2] < 0) {
+                    float x = 0f + curLeafCtrlPolyLengths[0],
+                          y = x  + curLeafCtrlPolyLengths[1];
+                    if (curveType == 8) {
+                        float z = y + curLeafCtrlPolyLengths[2];
+                        _flatLeafCoefCache[0] = 3f * (x - y) + z;
+                        _flatLeafCoefCache[1] = 3f * (y - 2f * x);
+                        _flatLeafCoefCache[2] = 3f * x;
+                        _flatLeafCoefCache[3] = -z;
+                    } else if (curveType == 6) {
+                        _flatLeafCoefCache[0] = 0f;
+                        _flatLeafCoefCache[1] = y - 2f * x;
+                        _flatLeafCoefCache[2] = 2f * x;
+                        _flatLeafCoefCache[3] = -y;
+                    }
+                }
+                float a = _flatLeafCoefCache[0];
+                float b = _flatLeafCoefCache[1];
+                float c = _flatLeafCoefCache[2];
+                float d = t * _flatLeafCoefCache[3];
+
+                // we use cubicRootsInAB here, because we want only roots in 0, 1,
+                // and our quadratic root finder doesn't filter, so it's just a
+                // matter of convenience.
+                int n = Helpers.cubicRootsInAB(a, b, c, d, nextRoots, 0, 0, 1);
+                if (n == 1 && !Float.isNaN(nextRoots[0])) {
+                    t = nextRoots[0];
+                }
+            }
+            // t is relative to the current leaf, so we must make it a valid parameter
+            // of the original curve.
+            t = t * (nextT - lastT) + lastT;
+            if (t >= 1f) {
+                t = 1f;
+                done = true;
+            }
+            // even if done = true, if we're here, that means targetLength
+            // is equal to, or very, very close to the total length of the
+            // curve, so lastSegLen won't be too high. In cases where len
+            // overshoots the curve, this method will exit in the while
+            // loop, and lastSegLen will still be set to the right value.
+            lastSegLen = len;
+            return t;
+        }
+
+        float lastSegLen() {
+            return lastSegLen;
+        }
+
+        // go to the next leaf (in an inorder traversal) in the recursion tree
+        // preconditions: must be on a leaf, and that leaf must not be the root.
+        private void goToNextLeaf() {
+            // We must go to the first ancestor node that has an unvisited
+            // right child.
+            int _recLevel = recLevel;
+            final Side[] _sides = sides;
+
+            _recLevel--;
+            while(_sides[_recLevel] == Side.RIGHT) {
+                if (_recLevel == 0) {
+                    recLevel = 0;
+                    done = true;
+                    return;
+                }
+                _recLevel--;
+            }
+
+            _sides[_recLevel] = Side.RIGHT;
+            // optimize arraycopy (8 values faster than 6 = type):
+            System.arraycopy(recCurveStack[_recLevel], 0,
+                             recCurveStack[_recLevel+1], 0, 8);
+            _recLevel++;
+
+            recLevel = _recLevel;
+            goLeft();
+        }
+
+        // go to the leftmost node from the current node. Return its length.
+        private void goLeft() {
+            float len = onLeaf();
+            if (len >= 0f) {
+                lastT = nextT;
+                lenAtLastT = lenAtNextT;
+                nextT += (1 << (REC_LIMIT - recLevel)) * MIN_T_INC;
+                lenAtNextT += len;
+                // invalidate caches
+                flatLeafCoefCache[2] = -1f;
+                cachedHaveLowAcceleration = -1;
+            } else {
+                Helpers.subdivide(recCurveStack[recLevel], 0,
+                                  recCurveStack[recLevel+1], 0,
+                                  recCurveStack[recLevel], 0, curveType);
+                sides[recLevel] = Side.LEFT;
+                recLevel++;
+                goLeft();
+            }
+        }
+
+        // this is a bit of a hack. It returns -1 if we're not on a leaf, and
+        // the length of the leaf if we are on a leaf.
+        private float onLeaf() {
+            float[] curve = recCurveStack[recLevel];
+            float polyLen = 0f;
+
+            float x0 = curve[0], y0 = curve[1];
+            for (int i = 2; i < curveType; i += 2) {
+                final float x1 = curve[i], y1 = curve[i+1];
+                final float len = Helpers.linelen(x0, y0, x1, y1);
+                polyLen += len;
+                curLeafCtrlPolyLengths[i/2 - 1] = len;
+                x0 = x1;
+                y0 = y1;
+            }
+
+            final float lineLen = Helpers.linelen(curve[0], curve[1],
+                                                  curve[curveType-2],
+                                                  curve[curveType-1]);
+            if ((polyLen - lineLen) < ERR || recLevel == REC_LIMIT) {
+                return (polyLen + lineLen) / 2f;
+            }
+            return -1f;
+        }
+    }
+
+    @Override
+    public void curveTo(float x1, float y1,
+                        float x2, float y2,
+                        float x3, float y3)
+    {
+        final float[] _curCurvepts = curCurvepts;
+        _curCurvepts[0] = x0;        _curCurvepts[1] = y0;
+        _curCurvepts[2] = x1;        _curCurvepts[3] = y1;
+        _curCurvepts[4] = x2;        _curCurvepts[5] = y2;
+        _curCurvepts[6] = x3;        _curCurvepts[7] = y3;
+        somethingTo(8);
+    }
+
+    @Override
+    public void quadTo(float x1, float y1, float x2, float y2) {
+        final float[] _curCurvepts = curCurvepts;
+        _curCurvepts[0] = x0;        _curCurvepts[1] = y0;
+        _curCurvepts[2] = x1;        _curCurvepts[3] = y1;
+        _curCurvepts[4] = x2;        _curCurvepts[5] = y2;
+        somethingTo(6);
+    }
+
+    @Override
+    public void closePath() {
+        lineTo(sx, sy);
+        if (firstSegidx > 0) {
+            if (!dashOn || needsMoveTo) {
+                out.moveTo(sx, sy);
+            }
+            emitFirstSegments();
+        }
+        moveTo(sx, sy);
+    }
+
+    @Override
+    public void pathDone() {
+        if (firstSegidx > 0) {
+            out.moveTo(sx, sy);
+            emitFirstSegments();
+        }
+        out.pathDone();
+
+        // Dispose this instance:
+        dispose();
+    }
+
+    @Override
+    public long getNativeConsumer() {
+        throw new InternalError("Dasher does not use a native consumer");
+    }
+}
+
diff --git a/src/share/classes/sun/java2d/marlin/FloatArrayCache.java b/src/share/classes/sun/java2d/marlin/FloatArrayCache.java
new file mode 100644
index 0000000..87876b8
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/FloatArrayCache.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import static sun.java2d.marlin.MarlinUtils.logException;
+import static sun.java2d.marlin.MarlinUtils.logInfo;
+
+final class FloatArrayCache implements MarlinConst {
+
+    private final int arraySize;
+    private final ArrayDeque<float[]> floatArrays;
+    // stats
+    private int getOp = 0;
+    private int createOp = 0;
+    private int returnOp = 0;
+
+    void dumpStats() {
+        if (getOp > 0) {
+            logInfo("FloatArrayCache[" + arraySize + "]: get: " + getOp
+                    + " created: " + createOp + " - returned: " + returnOp
+                    + " :: cache size: " + floatArrays.size());
+        }
+    }
+
+    FloatArrayCache(final int arraySize) {
+        this.arraySize = arraySize;
+        // small but enough: almost 1 cache line
+        this.floatArrays = new ArrayDeque<float[]>(6);
+    }
+
+    float[] getArray() {
+        if (DO_STATS) {
+            getOp++;
+        }
+
+        // use cache
+        final float[] array = floatArrays.pollLast();
+
+        if (array != null) {
+            return array;
+        }
+
+        if (DO_STATS) {
+            createOp++;
+        }
+
+        return new float[arraySize];
+    }
+
+    void putDirtyArray(final float[] array, final int length) {
+        if (length != arraySize) {
+            if (DO_CHECKS) {
+                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
+            }
+            return;
+        }
+        if (DO_STATS) {
+            returnOp++;
+        }
+
+        // NO clean-up of array data = DIRTY ARRAY
+
+        if (DO_CLEAN_DIRTY) {
+            // Force zero-fill dirty arrays:
+            Arrays.fill(array, 0, array.length, 0f);
+        }
+
+        // fill cache:
+        floatArrays.addLast(array);
+    }
+
+    void putArray(final float[] array, final int length,
+                  final int fromIndex, final int toIndex)
+    {
+        if (length != arraySize) {
+            if (DO_CHECKS) {
+                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
+            }
+            return;
+        }
+        if (DO_STATS) {
+            returnOp++;
+        }
+
+        // clean-up array of dirty part[fromIndex; toIndex[
+        fill(array, fromIndex, toIndex, 0f);
+
+        // fill cache:
+        floatArrays.addLast(array);
+    }
+
+    static void fill(final float[] array, final int fromIndex,
+                     final int toIndex, final float value)
+    {
+        // clear array data:
+        /*
+         * Arrays.fill is faster than System.arraycopy(empty array)
+         * or Unsafe.setMemory(byte 0)
+         */
+        if (toIndex != 0) {
+            Arrays.fill(array, fromIndex, toIndex, value);
+        }
+
+        if (DO_CHECKS) {
+            check(array, fromIndex, toIndex, value);
+        }
+    }
+
+    static void check(final float[] array, final int fromIndex,
+                      final int toIndex, final float value)
+    {
+        if (DO_CHECKS) {
+            // check zero on full array:
+            for (int i = 0; i < array.length; i++) {
+                if (array[i] != value) {
+                    logException("Invalid value at: " + i + " = " + array[i]
+                            + " from: " + fromIndex + " to: " + toIndex + "\n"
+                            + Arrays.toString(array), new Throwable());
+
+                    // ensure array is correctly filled:
+                    Arrays.fill(array, value);
+
+                    return;
+                }
+            }
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/FloatMath.java b/src/share/classes/sun/java2d/marlin/FloatMath.java
new file mode 100644
index 0000000..81dc6f7
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/FloatMath.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ */
+package sun.java2d.marlin;
+
+import sun.misc.FloatConsts;
+
+/**
+ * Faster Math ceil / floor routines derived from StrictMath
+ */
+public final class FloatMath implements MarlinConst {
+
+    // overflow / NaN handling enabled:
+    static final boolean CHECK_OVERFLOW = true;
+    static final boolean CHECK_NAN = true;
+
+    private FloatMath() {
+        // utility class
+    }
+
+    // faster inlined min/max functions in the branch prediction is high
+    static float max(final float a, final float b) {
+        // no NaN handling
+        return (a >= b) ? a : b;
+    }
+
+    static int max(final int a, final int b) {
+        return (a >= b) ? a : b;
+    }
+
+    static int min(final int a, final int b) {
+        return (a <= b) ? a : b;
+    }
+
+    /**
+     * Returns the smallest (closest to negative infinity) {@code float} value
+     * that is greater than or equal to the argument and is equal to a
+     * mathematical integer. Special cases:
+     * <ul><li>If the argument value is already equal to a mathematical integer,
+     * then the result is the same as the argument.  <li>If the argument is NaN
+     * or an infinity or positive zero or negative zero, then the result is the
+     * same as the argument.  <li>If the argument value is less than zero but
+     * greater than -1.0, then the result is negative zero.</ul> Note that the
+     * value of {@code StrictMath.ceil(x)} is exactly the value of
+     * {@code -StrictMath.floor(-x)}.
+     *
+     * @param a a value.
+     * @return the smallest (closest to negative infinity) floating-point value
+     * that is greater than or equal to the argument and is equal to a
+     * mathematical integer.
+     */
+    public static float ceil_f(final float a) {
+        // Derived from StrictMath.ceil(double):
+
+        // Inline call to Math.getExponent(a) to
+        // compute only once Float.floatToRawIntBits(a)
+        final int doppel = Float.floatToRawIntBits(a);
+
+        final int exponent = ((doppel & FloatConsts.EXP_BIT_MASK)
+                >> (FloatConsts.SIGNIFICAND_WIDTH - 1))
+                - FloatConsts.EXP_BIAS;
+
+        if (exponent < 0) {
+            /*
+             * Absolute value of argument is less than 1.
+             * floorOrceil(-0.0) => -0.0
+             * floorOrceil(+0.0) => +0.0
+             */
+            return ((a == 0) ? a :
+                    ( (a < 0f) ? -0f : 1f) );
+        }
+        if (CHECK_OVERFLOW && (exponent >= 23)) { // 52 for double
+            /*
+             * Infinity, NaN, or a value so large it must be integral.
+             */
+            return a;
+        }
+        // Else the argument is either an integral value already XOR it
+        // has to be rounded to one.
+        assert exponent >= 0 && exponent <= 22; // 51 for double
+
+        final int intpart = doppel
+                & (~(FloatConsts.SIGNIF_BIT_MASK >> exponent));
+
+        if (intpart == doppel) {
+            return a; // integral value (including 0)
+        }
+
+        // 0 handled above as an integer
+        // sign: 1 for negative, 0 for positive numbers
+        // add : 0 for negative and 1 for positive numbers
+        return Float.intBitsToFloat(intpart) + ((~intpart) >>> 31);
+    }
+
+    /**
+     * Returns the largest (closest to positive infinity) {@code float} value
+     * that is less than or equal to the argument and is equal to a mathematical
+     * integer. Special cases:
+     * <ul><li>If the argument value is already equal to a mathematical integer,
+     * then the result is the same as the argument.  <li>If the argument is NaN
+     * or an infinity or positive zero or negative zero, then the result is the
+     * same as the argument.</ul>
+     *
+     * @param a a value.
+     * @return the largest (closest to positive infinity) floating-point value
+     * that less than or equal to the argument and is equal to a mathematical
+     * integer.
+     */
+    public static float floor_f(final float a) {
+        // Derived from StrictMath.floor(double):
+
+        // Inline call to Math.getExponent(a) to
+        // compute only once Float.floatToRawIntBits(a)
+        final int doppel = Float.floatToRawIntBits(a);
+
+        final int exponent = ((doppel & FloatConsts.EXP_BIT_MASK)
+                >> (FloatConsts.SIGNIFICAND_WIDTH - 1))
+                - FloatConsts.EXP_BIAS;
+
+        if (exponent < 0) {
+            /*
+             * Absolute value of argument is less than 1.
+             * floorOrceil(-0.0) => -0.0
+             * floorOrceil(+0.0) => +0.0
+             */
+            return ((a == 0) ? a :
+                    ( (a < 0f) ? -1f : 0f) );
+        }
+        if (CHECK_OVERFLOW && (exponent >= 23)) { // 52 for double
+            /*
+             * Infinity, NaN, or a value so large it must be integral.
+             */
+            return a;
+        }
+        // Else the argument is either an integral value already XOR it
+        // has to be rounded to one.
+        assert exponent >= 0 && exponent <= 22; // 51 for double
+
+        final int intpart = doppel
+                & (~(FloatConsts.SIGNIF_BIT_MASK >> exponent));
+
+        if (intpart == doppel) {
+            return a; // integral value (including 0)
+        }
+
+        // 0 handled above as an integer
+        // sign: 1 for negative, 0 for positive numbers
+        // add : -1 for negative and 0 for positive numbers
+        return Float.intBitsToFloat(intpart) + (intpart >> 31);
+    }
+
+    /**
+     * Faster alternative to ceil(float) optimized for the integer domain
+     * and supporting NaN and +/-Infinity.
+     *
+     * @param a a value.
+     * @return the largest (closest to positive infinity) integer value
+     * that less than or equal to the argument and is equal to a mathematical
+     * integer.
+     */
+    public static int ceil_int(final float a) {
+        final int intpart = (int) a;
+
+        if (a <= intpart
+                || (CHECK_OVERFLOW && intpart == Integer.MAX_VALUE)
+                || CHECK_NAN && Float.isNaN(a)) {
+            return intpart;
+        }
+        return intpart + 1;
+    }
+
+    /**
+     * Faster alternative to floor(float) optimized for the integer domain
+     * and supporting NaN and +/-Infinity.
+     *
+     * @param a a value.
+     * @return the largest (closest to positive infinity) floating-point value
+     * that less than or equal to the argument and is equal to a mathematical
+     * integer.
+     */
+    public static int floor_int(final float a) {
+        final int intpart = (int) a;
+
+        if (a >= intpart
+                || (CHECK_OVERFLOW && intpart == Integer.MIN_VALUE)
+                || CHECK_NAN && Float.isNaN(a)) {
+            return intpart;
+        }
+        return intpart - 1;
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/Helpers.java b/src/share/classes/sun/java2d/marlin/Helpers.java
new file mode 100644
index 0000000..0b0277d
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/Helpers.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2007, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+import static java.lang.Math.PI;
+import static java.lang.Math.cos;
+import static java.lang.Math.sqrt;
+import static java.lang.Math.cbrt;
+import static java.lang.Math.acos;
+
+final class Helpers implements MarlinConst {
+
+    private Helpers() {
+        throw new Error("This is a non instantiable class");
+    }
+
+    static boolean within(final float x, final float y, final float err) {
+        final float d = y - x;
+        return (d <= err && d >= -err);
+    }
+
+    static boolean within(final double x, final double y, final double err) {
+        final double d = y - x;
+        return (d <= err && d >= -err);
+    }
+
+    static int quadraticRoots(final float a, final float b,
+                              final float c, float[] zeroes, final int off)
+    {
+        int ret = off;
+        float t;
+        if (a != 0f) {
+            final float dis = b*b - 4*a*c;
+            if (dis > 0f) {
+                final float sqrtDis = (float)Math.sqrt(dis);
+                // depending on the sign of b we use a slightly different
+                // algorithm than the traditional one to find one of the roots
+                // so we can avoid adding numbers of different signs (which
+                // might result in loss of precision).
+                if (b >= 0f) {
+                    zeroes[ret++] = (2f * c) / (-b - sqrtDis);
+                    zeroes[ret++] = (-b - sqrtDis) / (2f * a);
+                } else {
+                    zeroes[ret++] = (-b + sqrtDis) / (2f * a);
+                    zeroes[ret++] = (2f * c) / (-b + sqrtDis);
+                }
+            } else if (dis == 0f) {
+                t = (-b) / (2f * a);
+                zeroes[ret++] = t;
+            }
+        } else {
+            if (b != 0f) {
+                t = (-c) / b;
+                zeroes[ret++] = t;
+            }
+        }
+        return ret - off;
+    }
+
+    // find the roots of g(t) = d*t^3 + a*t^2 + b*t + c in [A,B)
+    static int cubicRootsInAB(float d, float a, float b, float c,
+                              float[] pts, final int off,
+                              final float A, final float B)
+    {
+        if (d == 0f) {
+            int num = quadraticRoots(a, b, c, pts, off);
+            return filterOutNotInAB(pts, off, num, A, B) - off;
+        }
+        // From Graphics Gems:
+        // http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c
+        // (also from awt.geom.CubicCurve2D. But here we don't need as
+        // much accuracy and we don't want to create arrays so we use
+        // our own customized version).
+
+        // normal form: x^3 + ax^2 + bx + c = 0
+        a /= d;
+        b /= d;
+        c /= d;
+
+        //  substitute x = y - A/3 to eliminate quadratic term:
+        //     x^3 +Px + Q = 0
+        //
+        // Since we actually need P/3 and Q/2 for all of the
+        // calculations that follow, we will calculate
+        // p = P/3
+        // q = Q/2
+        // instead and use those values for simplicity of the code.
+        double sq_A = a * a;
+        double p = (1.0/3.0) * ((-1.0/3.0) * sq_A + b);
+        double q = (1.0/2.0) * ((2.0/27.0) * a * sq_A - (1.0/3.0) * a * b + c);
+
+        // use Cardano's formula
+
+        double cb_p = p * p * p;
+        double D = q * q + cb_p;
+
+        int num;
+        if (D < 0.0) {
+            // see: http://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method
+            final double phi = (1.0/3.0) * acos(-q / sqrt(-cb_p));
+            final double t = 2.0 * sqrt(-p);
+
+            pts[ off+0 ] =  (float)( t * cos(phi));
+            pts[ off+1 ] =  (float)(-t * cos(phi + (PI / 3.0)));
+            pts[ off+2 ] =  (float)(-t * cos(phi - (PI / 3.0)));
+            num = 3;
+        } else {
+            final double sqrt_D = sqrt(D);
+            final double u = cbrt(sqrt_D - q);
+            final double v = - cbrt(sqrt_D + q);
+
+            pts[ off ] = (float)(u + v);
+            num = 1;
+
+            if (within(D, 0.0, 1e-8)) {
+                pts[off+1] = -(pts[off] / 2f);
+                num = 2;
+            }
+        }
+
+        final float sub = (1f/3f) * a;
+
+        for (int i = 0; i < num; ++i) {
+            pts[ off+i ] -= sub;
+        }
+
+        return filterOutNotInAB(pts, off, num, A, B) - off;
+    }
+
+    static float evalCubic(final float a, final float b,
+                           final float c, final float d,
+                           final float t)
+    {
+        return t * (t * (t * a + b) + c) + d;
+    }
+
+    static float evalQuad(final float a, final float b,
+                          final float c, final float t)
+    {
+        return t * (t * a + b) + c;
+    }
+
+    // returns the index 1 past the last valid element remaining after filtering
+    static int filterOutNotInAB(float[] nums, final int off, final int len,
+                                final float a, final float b)
+    {
+        int ret = off;
+        for (int i = off, end = off + len; i < end; i++) {
+            if (nums[i] >= a && nums[i] < b) {
+                nums[ret++] = nums[i];
+            }
+        }
+        return ret;
+    }
+
+    static float polyLineLength(float[] poly, final int off, final int nCoords) {
+        assert nCoords % 2 == 0 && poly.length >= off + nCoords : "";
+        float acc = 0;
+        for (int i = off + 2; i < off + nCoords; i += 2) {
+            acc += linelen(poly[i], poly[i+1], poly[i-2], poly[i-1]);
+        }
+        return acc;
+    }
+
+    static float linelen(float x1, float y1, float x2, float y2) {
+        final float dx = x2 - x1;
+        final float dy = y2 - y1;
+        return (float)Math.sqrt(dx*dx + dy*dy);
+    }
+
+    static void subdivide(float[] src, int srcoff, float[] left, int leftoff,
+                          float[] right, int rightoff, int type)
+    {
+        switch(type) {
+        case 6:
+            Helpers.subdivideQuad(src, srcoff, left, leftoff, right, rightoff);
+            return;
+        case 8:
+            Helpers.subdivideCubic(src, srcoff, left, leftoff, right, rightoff);
+            return;
+        default:
+            throw new InternalError("Unsupported curve type");
+        }
+    }
+
+    static void isort(float[] a, int off, int len) {
+        for (int i = off + 1, end = off + len; i < end; i++) {
+            float ai = a[i];
+            int j = i - 1;
+            for (; j >= off && a[j] > ai; j--) {
+                a[j+1] = a[j];
+            }
+            a[j+1] = ai;
+        }
+    }
+
+    // Most of these are copied from classes in java.awt.geom because we need
+    // float versions of these functions, and Line2D, CubicCurve2D,
+    // QuadCurve2D don't provide them.
+    /**
+     * Subdivides the cubic curve specified by the coordinates
+     * stored in the <code>src</code> array at indices <code>srcoff</code>
+     * through (<code>srcoff</code>&nbsp;+&nbsp;7) and stores the
+     * resulting two subdivided curves into the two result arrays at the
+     * corresponding indices.
+     * Either or both of the <code>left</code> and <code>right</code>
+     * arrays may be <code>null</code> or a reference to the same array
+     * as the <code>src</code> array.
+     * Note that the last point in the first subdivided curve is the
+     * same as the first point in the second subdivided curve. Thus,
+     * it is possible to pass the same array for <code>left</code>
+     * and <code>right</code> and to use offsets, such as <code>rightoff</code>
+     * equals (<code>leftoff</code> + 6), in order
+     * to avoid allocating extra storage for this common point.
+     * @param src the array holding the coordinates for the source curve
+     * @param srcoff the offset into the array of the beginning of the
+     * the 6 source coordinates
+     * @param left the array for storing the coordinates for the first
+     * half of the subdivided curve
+     * @param leftoff the offset into the array of the beginning of the
+     * the 6 left coordinates
+     * @param right the array for storing the coordinates for the second
+     * half of the subdivided curve
+     * @param rightoff the offset into the array of the beginning of the
+     * the 6 right coordinates
+     * @since 1.7
+     */
+    static void subdivideCubic(float[] src, int srcoff,
+                               float[] left, int leftoff,
+                               float[] right, int rightoff)
+    {
+        float x1 = src[srcoff + 0];
+        float y1 = src[srcoff + 1];
+        float ctrlx1 = src[srcoff + 2];
+        float ctrly1 = src[srcoff + 3];
+        float ctrlx2 = src[srcoff + 4];
+        float ctrly2 = src[srcoff + 5];
+        float x2 = src[srcoff + 6];
+        float y2 = src[srcoff + 7];
+        if (left != null) {
+            left[leftoff + 0] = x1;
+            left[leftoff + 1] = y1;
+        }
+        if (right != null) {
+            right[rightoff + 6] = x2;
+            right[rightoff + 7] = y2;
+        }
+        x1 = (x1 + ctrlx1) / 2f;
+        y1 = (y1 + ctrly1) / 2f;
+        x2 = (x2 + ctrlx2) / 2f;
+        y2 = (y2 + ctrly2) / 2f;
+        float centerx = (ctrlx1 + ctrlx2) / 2f;
+        float centery = (ctrly1 + ctrly2) / 2f;
+        ctrlx1 = (x1 + centerx) / 2f;
+        ctrly1 = (y1 + centery) / 2f;
+        ctrlx2 = (x2 + centerx) / 2f;
+        ctrly2 = (y2 + centery) / 2f;
+        centerx = (ctrlx1 + ctrlx2) / 2f;
+        centery = (ctrly1 + ctrly2) / 2f;
+        if (left != null) {
+            left[leftoff + 2] = x1;
+            left[leftoff + 3] = y1;
+            left[leftoff + 4] = ctrlx1;
+            left[leftoff + 5] = ctrly1;
+            left[leftoff + 6] = centerx;
+            left[leftoff + 7] = centery;
+        }
+        if (right != null) {
+            right[rightoff + 0] = centerx;
+            right[rightoff + 1] = centery;
+            right[rightoff + 2] = ctrlx2;
+            right[rightoff + 3] = ctrly2;
+            right[rightoff + 4] = x2;
+            right[rightoff + 5] = y2;
+        }
+    }
+
+
+    static void subdivideCubicAt(float t, float[] src, int srcoff,
+                                 float[] left, int leftoff,
+                                 float[] right, int rightoff)
+    {
+        float x1 = src[srcoff + 0];
+        float y1 = src[srcoff + 1];
+        float ctrlx1 = src[srcoff + 2];
+        float ctrly1 = src[srcoff + 3];
+        float ctrlx2 = src[srcoff + 4];
+        float ctrly2 = src[srcoff + 5];
+        float x2 = src[srcoff + 6];
+        float y2 = src[srcoff + 7];
+        if (left != null) {
+            left[leftoff + 0] = x1;
+            left[leftoff + 1] = y1;
+        }
+        if (right != null) {
+            right[rightoff + 6] = x2;
+            right[rightoff + 7] = y2;
+        }
+        x1 = x1 + t * (ctrlx1 - x1);
+        y1 = y1 + t * (ctrly1 - y1);
+        x2 = ctrlx2 + t * (x2 - ctrlx2);
+        y2 = ctrly2 + t * (y2 - ctrly2);
+        float centerx = ctrlx1 + t * (ctrlx2 - ctrlx1);
+        float centery = ctrly1 + t * (ctrly2 - ctrly1);
+        ctrlx1 = x1 + t * (centerx - x1);
+        ctrly1 = y1 + t * (centery - y1);
+        ctrlx2 = centerx + t * (x2 - centerx);
+        ctrly2 = centery + t * (y2 - centery);
+        centerx = ctrlx1 + t * (ctrlx2 - ctrlx1);
+        centery = ctrly1 + t * (ctrly2 - ctrly1);
+        if (left != null) {
+            left[leftoff + 2] = x1;
+            left[leftoff + 3] = y1;
+            left[leftoff + 4] = ctrlx1;
+            left[leftoff + 5] = ctrly1;
+            left[leftoff + 6] = centerx;
+            left[leftoff + 7] = centery;
+        }
+        if (right != null) {
+            right[rightoff + 0] = centerx;
+            right[rightoff + 1] = centery;
+            right[rightoff + 2] = ctrlx2;
+            right[rightoff + 3] = ctrly2;
+            right[rightoff + 4] = x2;
+            right[rightoff + 5] = y2;
+        }
+    }
+
+    static void subdivideQuad(float[] src, int srcoff,
+                              float[] left, int leftoff,
+                              float[] right, int rightoff)
+    {
+        float x1 = src[srcoff + 0];
+        float y1 = src[srcoff + 1];
+        float ctrlx = src[srcoff + 2];
+        float ctrly = src[srcoff + 3];
+        float x2 = src[srcoff + 4];
+        float y2 = src[srcoff + 5];
+        if (left != null) {
+            left[leftoff + 0] = x1;
+            left[leftoff + 1] = y1;
+        }
+        if (right != null) {
+            right[rightoff + 4] = x2;
+            right[rightoff + 5] = y2;
+        }
+        x1 = (x1 + ctrlx) / 2f;
+        y1 = (y1 + ctrly) / 2f;
+        x2 = (x2 + ctrlx) / 2f;
+        y2 = (y2 + ctrly) / 2f;
+        ctrlx = (x1 + x2) / 2f;
+        ctrly = (y1 + y2) / 2f;
+        if (left != null) {
+            left[leftoff + 2] = x1;
+            left[leftoff + 3] = y1;
+            left[leftoff + 4] = ctrlx;
+            left[leftoff + 5] = ctrly;
+        }
+        if (right != null) {
+            right[rightoff + 0] = ctrlx;
+            right[rightoff + 1] = ctrly;
+            right[rightoff + 2] = x2;
+            right[rightoff + 3] = y2;
+        }
+    }
+
+    static void subdivideQuadAt(float t, float[] src, int srcoff,
+                                float[] left, int leftoff,
+                                float[] right, int rightoff)
+    {
+        float x1 = src[srcoff + 0];
+        float y1 = src[srcoff + 1];
+        float ctrlx = src[srcoff + 2];
+        float ctrly = src[srcoff + 3];
+        float x2 = src[srcoff + 4];
+        float y2 = src[srcoff + 5];
+        if (left != null) {
+            left[leftoff + 0] = x1;
+            left[leftoff + 1] = y1;
+        }
+        if (right != null) {
+            right[rightoff + 4] = x2;
+            right[rightoff + 5] = y2;
+        }
+        x1 = x1 + t * (ctrlx - x1);
+        y1 = y1 + t * (ctrly - y1);
+        x2 = ctrlx + t * (x2 - ctrlx);
+        y2 = ctrly + t * (y2 - ctrly);
+        ctrlx = x1 + t * (x2 - x1);
+        ctrly = y1 + t * (y2 - y1);
+        if (left != null) {
+            left[leftoff + 2] = x1;
+            left[leftoff + 3] = y1;
+            left[leftoff + 4] = ctrlx;
+            left[leftoff + 5] = ctrly;
+        }
+        if (right != null) {
+            right[rightoff + 0] = ctrlx;
+            right[rightoff + 1] = ctrly;
+            right[rightoff + 2] = x2;
+            right[rightoff + 3] = y2;
+        }
+    }
+
+    static void subdivideAt(float t, float[] src, int srcoff,
+                            float[] left, int leftoff,
+                            float[] right, int rightoff, int size)
+    {
+        switch(size) {
+        case 8:
+            subdivideCubicAt(t, src, srcoff, left, leftoff, right, rightoff);
+            return;
+        case 6:
+            subdivideQuadAt(t, src, srcoff, left, leftoff, right, rightoff);
+            return;
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/IntArrayCache.java b/src/share/classes/sun/java2d/marlin/IntArrayCache.java
new file mode 100644
index 0000000..917e992
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/IntArrayCache.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import static sun.java2d.marlin.MarlinUtils.logException;
+import static sun.java2d.marlin.MarlinUtils.logInfo;
+
+final class IntArrayCache implements MarlinConst {
+
+    private final int arraySize;
+    private final ArrayDeque<int[]> intArrays;
+    // stats
+    private int getOp = 0;
+    private int createOp = 0;
+    private int returnOp = 0;
+
+    void dumpStats() {
+        if (getOp > 0) {
+            logInfo("IntArrayCache[" + arraySize + "]: get: " + getOp
+                    + " created: " + createOp + " - returned: " + returnOp
+                    + " :: cache size: " + intArrays.size());
+        }
+    }
+
+    IntArrayCache(final int arraySize) {
+        this.arraySize = arraySize;
+        // small but enough: almost 1 cache line
+        this.intArrays = new ArrayDeque<int[]>(6);
+    }
+
+    int[] getArray() {
+        if (DO_STATS) {
+            getOp++;
+        }
+
+        // use cache:
+        final int[] array = intArrays.pollLast();
+        if (array != null) {
+            return array;
+        }
+
+        if (DO_STATS) {
+            createOp++;
+        }
+
+        return new int[arraySize];
+    }
+
+    void putDirtyArray(final int[] array, final int length) {
+        if (length != arraySize) {
+            if (DO_CHECKS) {
+                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
+            }
+            return;
+        }
+        if (DO_STATS) {
+            returnOp++;
+        }
+
+        // NO clean-up of array data = DIRTY ARRAY
+
+        if (DO_CLEAN_DIRTY) {
+            // Force zero-fill dirty arrays:
+            Arrays.fill(array, 0, array.length, 0);
+        }
+
+        // fill cache:
+        intArrays.addLast(array);
+    }
+
+    void putArray(final int[] array, final int length,
+                  final int fromIndex, final int toIndex)
+    {
+        if (length != arraySize) {
+            if (DO_CHECKS) {
+                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
+            }
+            return;
+        }
+        if (DO_STATS) {
+            returnOp++;
+        }
+
+        // clean-up array of dirty part[fromIndex; toIndex[
+        fill(array, fromIndex, toIndex, 0);
+
+        // fill cache:
+        intArrays.addLast(array);
+    }
+
+    static void fill(final int[] array, final int fromIndex,
+                     final int toIndex, final int value)
+    {
+        // clear array data:
+        /*
+         * Arrays.fill is faster than System.arraycopy(empty array)
+         * or Unsafe.setMemory(byte 0)
+         */
+        if (toIndex != 0) {
+            Arrays.fill(array, fromIndex, toIndex, value);
+        }
+
+        if (DO_CHECKS) {
+            check(array, fromIndex, toIndex, value);
+        }
+    }
+
+    static void check(final int[] array, final int fromIndex,
+                      final int toIndex, final int value)
+    {
+        if (DO_CHECKS) {
+            // check zero on full array:
+            for (int i = 0; i < array.length; i++) {
+                if (array[i] != value) {
+                    logException("Invalid value at: " + i + " = " + array[i]
+                            + " from: " + fromIndex + " to: " + toIndex + "\n"
+                            + Arrays.toString(array), new Throwable());
+
+                    // ensure array is correctly filled:
+                    Arrays.fill(array, value);
+
+                    return;
+                }
+            }
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/MarlinCache.java b/src/share/classes/sun/java2d/marlin/MarlinCache.java
new file mode 100644
index 0000000..54877a2
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/MarlinCache.java
@@ -0,0 +1,689 @@
+/*
+ * Copyright (c) 2007, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+import sun.misc.Unsafe;
+
+/**
+ * An object used to cache pre-rendered complex paths.
+ *
+ * @see Renderer
+ */
+public final class MarlinCache implements MarlinConst {
+
+    static final boolean FORCE_RLE = MarlinProperties.isForceRLE();
+    static final boolean FORCE_NO_RLE = MarlinProperties.isForceNoRLE();
+    // minimum width to try using RLE encoding:
+    static final int RLE_MIN_WIDTH
+        = Math.max(BLOCK_SIZE, MarlinProperties.getRLEMinWidth());
+    // maximum width for RLE encoding:
+    // values are stored as int [x|alpha] where alpha is 8 bits
+    static final int RLE_MAX_WIDTH = 1 << (24 - 1);
+
+    // 2048 (pixelSize) alpha values (width) x 32 rows (tile) = 64K bytes
+    // x1 instead of 4 bytes (RLE) ie 1/4 capacity or average good RLE compression
+    static final long INITIAL_CHUNK_ARRAY = TILE_SIZE * INITIAL_PIXEL_DIM; // 64K
+
+    // The alpha map used by this object (taken out of our map cache) to convert
+    // pixel coverage counts gotten from MarlinCache (which are in the range
+    // [0, maxalpha]) into alpha values, which are in [0,256).
+    static final byte[] ALPHA_MAP;
+
+    static final OffHeapArray ALPHA_MAP_UNSAFE;
+
+    static {
+        final byte[] _ALPHA_MAP = buildAlphaMap(MAX_AA_ALPHA);
+
+        ALPHA_MAP_UNSAFE = new OffHeapArray(_ALPHA_MAP, _ALPHA_MAP.length); // 1K
+        ALPHA_MAP =_ALPHA_MAP;
+
+        final Unsafe _unsafe = OffHeapArray.UNSAFE;
+        final long addr = ALPHA_MAP_UNSAFE.address;
+
+        for (int i = 0; i < _ALPHA_MAP.length; i++) {
+            _unsafe.putByte(addr + i, _ALPHA_MAP[i]);
+        }
+    }
+
+    int bboxX0, bboxY0, bboxX1, bboxY1;
+
+    // 1D dirty arrays
+    // row index in rowAAChunk[]
+    final long[] rowAAChunkIndex = new long[TILE_SIZE];
+    // first pixel (inclusive) for each row
+    final int[] rowAAx0 = new int[TILE_SIZE];
+    // last pixel (exclusive) for each row
+    final int[] rowAAx1 = new int[TILE_SIZE];
+    // encoding mode (0=raw, 1=RLE encoding) for each row
+    final int[] rowAAEnc = new int[TILE_SIZE];
+    // coded length (RLE encoding) for each row
+    final long[] rowAALen = new long[TILE_SIZE];
+    // last position in RLE decoding for each row (getAlpha):
+    final long[] rowAAPos = new long[TILE_SIZE];
+
+    // dirty off-heap array containing pixel coverages for (32) rows (packed)
+    // if encoding=raw, it contains alpha coverage values (val) as integer
+    // if encoding=RLE, it contains tuples (val, last x-coordinate exclusive)
+    // use rowAAx0/rowAAx1 to get row indices within this chunk
+    final OffHeapArray rowAAChunk;
+
+    // current position in rowAAChunk array
+    long rowAAChunkPos;
+
+    // touchedTile[i] is the sum of all the alphas in the tile with
+    // x=j*TILE_SIZE+bboxX0.
+    int[] touchedTile;
+
+    // per-thread renderer context
+    final RendererContext rdrCtx;
+
+    // large cached touchedTile (dirty)
+    final int[] touchedTile_initial = new int[INITIAL_ARRAY]; // 1 tile line
+
+    int tileMin, tileMax;
+
+    boolean useRLE = false;
+
+    MarlinCache(final RendererContext rdrCtx) {
+        this.rdrCtx = rdrCtx;
+
+        rowAAChunk = new OffHeapArray(rdrCtx.cleanerObj, INITIAL_CHUNK_ARRAY); // 64K
+
+        touchedTile = touchedTile_initial;
+
+        // tile used marks:
+        tileMin = Integer.MAX_VALUE;
+        tileMax = Integer.MIN_VALUE;
+    }
+
+    void init(int minx, int miny, int maxx, int maxy, int edgeSumDeltaY)
+    {
+        // assert maxy >= miny && maxx >= minx;
+        bboxX0 = minx;
+        bboxY0 = miny;
+        bboxX1 = maxx;
+        bboxY1 = maxy;
+
+        final int width = (maxx - minx);
+
+        if (FORCE_NO_RLE) {
+            useRLE = false;
+        } else if (FORCE_RLE) {
+            useRLE = true;
+        } else {
+            // heuristics: use both bbox area and complexity
+            // ie number of primitives:
+
+            // fast check min and max width (maxx < 23bits):
+            if (width <= RLE_MIN_WIDTH || width >= RLE_MAX_WIDTH) {
+                useRLE = false;
+            } else {
+                // perimeter approach: how fit the total length into given height:
+
+                // if stroking: meanCrossings /= 2 => divide edgeSumDeltaY by 2
+                final int heightSubPixel
+                    = (((maxy - miny) << SUBPIXEL_LG_POSITIONS_Y) << rdrCtx.stroking);
+
+                // check meanDist > block size:
+                // check width / (meanCrossings - 1) >= RLE_THRESHOLD
+
+                // fast case: (meanCrossingPerPixel <= 2) means 1 span only
+                useRLE = (edgeSumDeltaY <= (heightSubPixel << 1))
+                    // note: already checked (meanCrossingPerPixel <= 2)
+                    // rewritten to avoid division:
+                    || (width * heightSubPixel) >
+                            ((edgeSumDeltaY - heightSubPixel) << BLOCK_SIZE_LG);
+
+                if (DO_TRACE && !useRLE) {
+                    final float meanCrossings
+                        = ((float) edgeSumDeltaY) / heightSubPixel;
+                    final float meanDist = width / (meanCrossings - 1);
+
+                    System.out.println("High complexity: "
+                        + " for bbox[width = " + width
+                        + " height = " + (maxy - miny)
+                        + "] edgeSumDeltaY = " + edgeSumDeltaY
+                        + " heightSubPixel = " + heightSubPixel
+                        + " meanCrossings = "+ meanCrossings
+                        + " meanDist = " + meanDist
+                        + " width =  " + (width * heightSubPixel)
+                        + " <= criteria:  " + ((edgeSumDeltaY - heightSubPixel) << BLOCK_SIZE_LG)
+                    );
+                }
+            }
+        }
+
+        // the ceiling of (maxy - miny + 1) / TILE_SIZE;
+        final int nxTiles = (width + TILE_SIZE) >> TILE_SIZE_LG;
+
+        if (nxTiles > INITIAL_ARRAY) {
+            if (DO_STATS) {
+                rdrCtx.stats.stat_array_marlincache_touchedTile
+                    .add(nxTiles);
+            }
+            touchedTile = rdrCtx.getIntArray(nxTiles);
+        }
+    }
+
+    /**
+     * Disposes this cache:
+     * clean up before reusing this instance
+     */
+    void dispose() {
+        // Reset touchedTile if needed:
+        resetTileLine(0);
+
+        // Return arrays:
+        if (touchedTile != touchedTile_initial) {
+            rdrCtx.putIntArray(touchedTile, 0, 0); // already zero filled
+            touchedTile = touchedTile_initial;
+        }
+        // At last: resize back off-heap rowAA to initial size
+        if (rowAAChunk.length != INITIAL_CHUNK_ARRAY) {
+            // note: may throw OOME:
+            rowAAChunk.resize(INITIAL_CHUNK_ARRAY);
+        }
+        if (DO_CLEAN_DIRTY) {
+            // Force zero-fill dirty arrays:
+            rowAAChunk.fill(BYTE_0);
+        }
+    }
+
+    void resetTileLine(final int pminY) {
+        // update bboxY0 to process a complete tile line [0 - 32]
+        bboxY0 = pminY;
+
+        // reset current pos
+        if (DO_STATS) {
+            rdrCtx.stats.stat_cache_rowAAChunk.add(rowAAChunkPos);
+        }
+        rowAAChunkPos = 0L;
+
+        // Reset touchedTile:
+        if (tileMin != Integer.MAX_VALUE) {
+            if (DO_STATS) {
+                rdrCtx.stats.stat_cache_tiles.add(tileMax - tileMin);
+            }
+            // clean only dirty touchedTile:
+            if (tileMax == 1) {
+                touchedTile[0] = 0;
+            } else {
+                IntArrayCache.fill(touchedTile, tileMin, tileMax, 0);
+            }
+            // reset tile used marks:
+            tileMin = Integer.MAX_VALUE;
+            tileMax = Integer.MIN_VALUE;
+        }
+
+        if (DO_CLEAN_DIRTY) {
+            // Force zero-fill dirty arrays:
+            rowAAChunk.fill(BYTE_0);
+        }
+    }
+
+    void clearAARow(final int y) {
+        // process tile line [0 - 32]
+        final int row = y - bboxY0;
+
+        // update pixel range:
+        rowAAx0[row]  = 0; // first pixel inclusive
+        rowAAx1[row]  = 0; //  last pixel exclusive
+        rowAAEnc[row] = 0; // raw encoding
+
+        // note: leave rowAAChunkIndex[row] undefined
+        // and rowAALen[row] & rowAAPos[row] (RLE)
+    }
+
+    /**
+     * Copy the given alpha data into the rowAA cache
+     * @param alphaRow alpha data to copy from
+     * @param y y pixel coordinate
+     * @param px0 first pixel inclusive x0
+     * @param px1 last pixel exclusive x1
+     */
+    void copyAARowNoRLE(final int[] alphaRow, final int y,
+                   final int px0, final int px1)
+    {
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_copyAARow.start();
+        }
+
+        // skip useless pixels above boundary
+        final int px_bbox1 = FloatMath.min(px1, bboxX1);
+
+        if (DO_LOG_BOUNDS) {
+            MarlinUtils.logInfo("row = [" + px0 + " ... " + px_bbox1
+                                + " (" + px1 + ") [ for y=" + y);
+        }
+
+        final int row = y - bboxY0;
+
+        // update pixel range:
+        rowAAx0[row]  = px0;      // first pixel inclusive
+        rowAAx1[row]  = px_bbox1; //  last pixel exclusive
+        rowAAEnc[row] = 0; // raw encoding
+
+        // get current position (bytes):
+        final long pos = rowAAChunkPos;
+        // update row index to current position:
+        rowAAChunkIndex[row] = pos;
+
+        // determine need array size:
+        // for RLE encoding, position must be aligned to 4 bytes (int):
+        // align - 1 = 3 so add +3 and round-off by mask ~3 = -4
+        final long needSize = pos + ((px_bbox1 - px0 + 3) & -4);
+
+        // update next position (bytes):
+        rowAAChunkPos = needSize;
+
+        // update row data:
+        final OffHeapArray _rowAAChunk = rowAAChunk;
+        // ensure rowAAChunk capacity:
+        if (_rowAAChunk.length < needSize) {
+            expandRowAAChunk(needSize);
+        }
+        if (DO_STATS) {
+            rdrCtx.stats.stat_cache_rowAA.add(px_bbox1 - px0);
+        }
+
+        // rowAA contains only alpha values for range[x0; x1[
+        final int[] _touchedTile = touchedTile;
+        final int _TILE_SIZE_LG = TILE_SIZE_LG;
+
+        final int from = px0      - bboxX0; // first pixel inclusive
+        final int to   = px_bbox1 - bboxX0; //  last pixel exclusive
+
+        final Unsafe _unsafe = OffHeapArray.UNSAFE;
+        final long SIZE_BYTE = 1L;
+        final long addr_alpha = ALPHA_MAP_UNSAFE.address;
+        long addr_off = _rowAAChunk.address + pos;
+
+        // compute alpha sum into rowAA:
+        for (int x = from, val = 0; x < to; x++) {
+            // alphaRow is in [0; MAX_COVERAGE]
+            val += alphaRow[x]; // [from; to[
+
+            // ensure values are in [0; MAX_AA_ALPHA] range
+            if (DO_AA_RANGE_CHECK) {
+                if (val < 0) {
+                    System.out.println("Invalid coverage = " + val);
+                    val = 0;
+                }
+                if (val > MAX_AA_ALPHA) {
+                    System.out.println("Invalid coverage = " + val);
+                    val = MAX_AA_ALPHA;
+                }
+            }
+
+            // store alpha sum (as byte):
+            if (val == 0) {
+                _unsafe.putByte(addr_off, (byte)0); // [0..255]
+            } else {
+                _unsafe.putByte(addr_off, _unsafe.getByte(addr_alpha + val)); // [0..255]
+
+                // update touchedTile
+                _touchedTile[x >> _TILE_SIZE_LG] += val;
+            }
+            addr_off += SIZE_BYTE;
+        }
+
+        // update tile used marks:
+        int tx = from >> _TILE_SIZE_LG; // inclusive
+        if (tx < tileMin) {
+            tileMin = tx;
+        }
+
+        tx = ((to - 1) >> _TILE_SIZE_LG) + 1; // exclusive (+1 to be sure)
+        if (tx > tileMax) {
+            tileMax = tx;
+        }
+
+        if (DO_LOG_BOUNDS) {
+            MarlinUtils.logInfo("clear = [" + from + " ... " + to + "[");
+        }
+
+        // Clear alpha row for reuse:
+        IntArrayCache.fill(alphaRow, from, px1 - bboxX0, 0);
+
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_copyAARow.stop();
+        }
+    }
+
+    void copyAARowRLE_WithBlockFlags(final int[] blkFlags, final int[] alphaRow,
+                      final int y, final int px0, final int px1)
+    {
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_copyAARow.start();
+        }
+
+        // Copy rowAA data into the piscesCache if one is present
+        final int _bboxX0 = bboxX0;
+
+        // process tile line [0 - 32]
+        final int row  = y - bboxY0;
+        final int from = px0 - _bboxX0; // first pixel inclusive
+
+        // skip useless pixels above boundary
+        final int px_bbox1 = FloatMath.min(px1, bboxX1);
+        final int to       = px_bbox1 - _bboxX0; //  last pixel exclusive
+
+        if (DO_LOG_BOUNDS) {
+            MarlinUtils.logInfo("row = [" + px0 + " ... " + px_bbox1
+                                + " (" + px1 + ") [ for y=" + y);
+        }
+
+        // get current position:
+        final long initialPos = startRLERow(row, px0, px_bbox1);
+
+        // determine need array size:
+        // pessimistic: max needed size = deltaX x 4 (1 int)
+        final long needSize = initialPos + ((to - from) << 2);
+
+        // update row data:
+        OffHeapArray _rowAAChunk = rowAAChunk;
+        // ensure rowAAChunk capacity:
+        if (_rowAAChunk.length < needSize) {
+            expandRowAAChunk(needSize);
+        }
+
+        final Unsafe _unsafe = OffHeapArray.UNSAFE;
+        final long SIZE_INT = 4L;
+        final long addr_alpha = ALPHA_MAP_UNSAFE.address;
+        long addr_off = _rowAAChunk.address + initialPos;
+
+        final int[] _touchedTile = touchedTile;
+        final int _TILE_SIZE_LG = TILE_SIZE_LG;
+        final int _BLK_SIZE_LG  = BLOCK_SIZE_LG;
+
+        // traverse flagged blocks:
+        final int blkW = (from >> _BLK_SIZE_LG);
+        final int blkE = (to   >> _BLK_SIZE_LG) + 1;
+
+        // Perform run-length encoding and store results in the piscesCache
+        int val = 0;
+        int cx0 = from;
+        int runLen;
+
+        final int _MAX_VALUE = Integer.MAX_VALUE;
+        int last_t0 = _MAX_VALUE;
+
+        int skip = 0;
+
+        for (int t = blkW, blk_x0, blk_x1, cx, delta; t <= blkE; t++) {
+            if (blkFlags[t] != 0) {
+                blkFlags[t] = 0;
+
+                if (last_t0 == _MAX_VALUE) {
+                    last_t0 = t;
+                }
+                continue;
+            }
+            if (last_t0 != _MAX_VALUE) {
+                // emit blocks:
+                blk_x0 = FloatMath.max(last_t0 << _BLK_SIZE_LG, from);
+                last_t0 = _MAX_VALUE;
+
+                // (last block pixel+1) inclusive => +1
+                blk_x1 = FloatMath.min((t << _BLK_SIZE_LG) + 1, to);
+
+                for (cx = blk_x0; cx < blk_x1; cx++) {
+                    if ((delta = alphaRow[cx]) != 0) {
+                        alphaRow[cx] = 0;
+
+                        // not first rle entry:
+                        if (cx != cx0) {
+                            runLen = cx - cx0;
+
+                            // store alpha coverage (ensure within bounds):
+                            // as [absX|val] where:
+                            // absX is the absolute x-coordinate:
+                            // note: last pixel exclusive (>= 0)
+                            // note: it should check X is smaller than 23bits (overflow)!
+
+                            // check address alignment to 4 bytes:
+                            if (DO_CHECK_UNSAFE) {
+                                if ((addr_off & 3) != 0) {
+                                    MarlinUtils.logInfo("Misaligned Unsafe address: " + addr_off);
+                                }
+                            }
+
+                            // special case to encode entries into a single int:
+                            if (val == 0) {
+                                _unsafe.putInt(addr_off,
+                                    ((_bboxX0 + cx) << 8)
+                                );
+                            } else {
+                                _unsafe.putInt(addr_off,
+                                    ((_bboxX0 + cx) << 8)
+                                    | (((int) _unsafe.getByte(addr_alpha + val)) & 0xFF) // [0..255]
+                                );
+
+                                if (runLen == 1) {
+                                    _touchedTile[cx0 >> _TILE_SIZE_LG] += val;
+                                } else {
+                                    touchTile(cx0, val, cx, runLen, _touchedTile);
+                                }
+                            }
+                            addr_off += SIZE_INT;
+
+                            if (DO_STATS) {
+                                rdrCtx.stats.hist_tile_generator_encoding_runLen
+                                    .add(runLen);
+                            }
+                            cx0 = cx;
+                        }
+
+                        // alpha value = running sum of coverage delta:
+                        val += delta;
+
+                        // ensure values are in [0; MAX_AA_ALPHA] range
+                        if (DO_AA_RANGE_CHECK) {
+                            if (val < 0) {
+                                System.out.println("Invalid coverage = " + val);
+                                val = 0;
+                            }
+                            if (val > MAX_AA_ALPHA) {
+                                System.out.println("Invalid coverage = " + val);
+                                val = MAX_AA_ALPHA;
+                            }
+                        }
+                    }
+                }
+            } else if (DO_STATS) {
+                skip++;
+            }
+        }
+
+        // Process remaining RLE run:
+        runLen = to - cx0;
+
+        // store alpha coverage (ensure within bounds):
+        // as (int)[absX|val] where:
+        // absX is the absolute x-coordinate in bits 31 to 8 and val in bits 0..7
+        // note: last pixel exclusive (>= 0)
+        // note: it should check X is smaller than 23bits (overflow)!
+
+        // check address alignment to 4 bytes:
+        if (DO_CHECK_UNSAFE) {
+            if ((addr_off & 3) != 0) {
+                MarlinUtils.logInfo("Misaligned Unsafe address: " + addr_off);
+            }
+        }
+
+        // special case to encode entries into a single int:
+        if (val == 0) {
+            _unsafe.putInt(addr_off,
+                ((_bboxX0 + to) << 8)
+            );
+        } else {
+            _unsafe.putInt(addr_off,
+                ((_bboxX0 + to) << 8)
+                | (((int) _unsafe.getByte(addr_alpha + val)) & 0xFF) // [0..255]
+            );
+
+            if (runLen == 1) {
+                _touchedTile[cx0 >> _TILE_SIZE_LG] += val;
+            } else {
+                touchTile(cx0, val, to, runLen, _touchedTile);
+            }
+        }
+        addr_off += SIZE_INT;
+
+        if (DO_STATS) {
+            rdrCtx.stats.hist_tile_generator_encoding_runLen
+                .add(runLen);
+        }
+
+        long len = (addr_off - _rowAAChunk.address);
+
+        // update coded length as bytes:
+        rowAALen[row] = (len - initialPos);
+
+        // update current position:
+        rowAAChunkPos = len;
+
+        if (DO_STATS) {
+            rdrCtx.stats.stat_cache_rowAA.add(rowAALen[row]);
+            rdrCtx.stats.hist_tile_generator_encoding_ratio.add(
+                (100 * skip) / (blkE - blkW)
+            );
+        }
+
+        // update tile used marks:
+        int tx = from >> _TILE_SIZE_LG; // inclusive
+        if (tx < tileMin) {
+            tileMin = tx;
+        }
+
+        tx = ((to - 1) >> _TILE_SIZE_LG) + 1; // exclusive (+1 to be sure)
+        if (tx > tileMax) {
+            tileMax = tx;
+        }
+
+        // Clear alpha row for reuse:
+        if (px1 > bboxX1) {
+            alphaRow[to    ] = 0;
+            alphaRow[to + 1] = 0;
+        }
+        if (DO_CHECKS) {
+            IntArrayCache.check(blkFlags, blkW, blkE, 0);
+            IntArrayCache.check(alphaRow, from, px1 - bboxX0, 0);
+        }
+
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_copyAARow.stop();
+        }
+    }
+
+    long startRLERow(final int row, final int x0, final int x1) {
+        // rows are supposed to be added by increasing y.
+        rowAAx0[row]  = x0; // first pixel inclusive
+        rowAAx1[row]  = x1; // last pixel exclusive
+        rowAAEnc[row] = 1; // RLE encoding
+        rowAAPos[row] = 0L; // position = 0
+
+        // update row index to current position:
+        return (rowAAChunkIndex[row] = rowAAChunkPos);
+    }
+
+    private void expandRowAAChunk(final long needSize) {
+        if (DO_STATS) {
+            rdrCtx.stats.stat_array_marlincache_rowAAChunk
+                .add(needSize);
+        }
+
+        // note: throw IOOB if neededSize > 2Gb:
+        final long newSize = ArrayCache.getNewLargeSize(rowAAChunk.length, needSize);
+
+        rowAAChunk.resize(newSize);
+    }
+
+    private void touchTile(final int x0, final int val, final int x1,
+                           final int runLen,
+                           final int[] _touchedTile)
+    {
+        // the x and y of the current row, minus bboxX0, bboxY0
+        // process tile line [0 - 32]
+        final int _TILE_SIZE_LG = TILE_SIZE_LG;
+
+        // update touchedTile
+        int tx = (x0 >> _TILE_SIZE_LG);
+
+        // handle trivial case: same tile (x0, x0+runLen)
+        if (tx == (x1 >> _TILE_SIZE_LG)) {
+            // same tile:
+            _touchedTile[tx] += val * runLen;
+            return;
+        }
+
+        final int tx1 = (x1 - 1) >> _TILE_SIZE_LG;
+
+        if (tx <= tx1) {
+            final int nextTileXCoord = (tx + 1) << _TILE_SIZE_LG;
+            _touchedTile[tx++] += val * (nextTileXCoord - x0);
+        }
+        if (tx < tx1) {
+            // don't go all the way to tx1 - we need to handle the last
+            // tile as a special case (just like we did with the first
+            final int tileVal = (val << _TILE_SIZE_LG);
+            for (; tx < tx1; tx++) {
+                _touchedTile[tx] += tileVal;
+            }
+        }
+        // they will be equal unless x0 >> TILE_SIZE_LG == tx1
+        if (tx == tx1) {
+            final int txXCoord       =  tx      << _TILE_SIZE_LG;
+            final int nextTileXCoord = (tx + 1) << _TILE_SIZE_LG;
+
+            final int lastXCoord = (nextTileXCoord <= x1) ? nextTileXCoord : x1;
+            _touchedTile[tx] += val * (lastXCoord - txXCoord);
+        }
+    }
+
+    int alphaSumInTile(final int x) {
+        return touchedTile[(x - bboxX0) >> TILE_SIZE_LG];
+    }
+
+    @Override
+    public String toString() {
+        return "bbox = ["
+            + bboxX0 + ", " + bboxY0 + " => "
+            + bboxX1 + ", " + bboxY1 + "]\n";
+    }
+
+    private static byte[] buildAlphaMap(final int maxalpha) {
+        // double size !
+        final byte[] alMap = new byte[maxalpha << 1];
+        final int halfmaxalpha = maxalpha >> 2;
+        for (int i = 0; i <= maxalpha; i++) {
+            alMap[i] = (byte) ((i * 255 + halfmaxalpha) / maxalpha);
+//            System.out.println("alphaMap[" + i + "] = "
+//                               + Byte.toUnsignedInt(alMap[i]));
+        }
+        return alMap;
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/MarlinConst.java b/src/share/classes/sun/java2d/marlin/MarlinConst.java
new file mode 100644
index 0000000..22bf86d
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/MarlinConst.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+/**
+ * Marlin constant holder using System properties
+ */
+interface MarlinConst {
+    // enable Logs (logger or stdout)
+    static final boolean ENABLE_LOGS = MarlinProperties.isLoggingEnabled();
+    // use Logger instead of stdout
+    static final boolean USE_LOGGER = ENABLE_LOGS && MarlinProperties.isUseLogger();
+
+    // log new RendererContext
+    static final boolean LOG_CREATE_CONTEXT = ENABLE_LOGS
+        && MarlinProperties.isLogCreateContext();
+    // log misc.Unsafe alloc/realloc/free
+    static final boolean LOG_UNSAFE_MALLOC = ENABLE_LOGS
+        && MarlinProperties.isLogUnsafeMalloc();
+    // do check unsafe alignment:
+    static final boolean DO_CHECK_UNSAFE = false;
+
+    // do statistics
+    static final boolean DO_STATS = ENABLE_LOGS && MarlinProperties.isDoStats();
+    // do monitors
+    // disabled to reduce byte-code size a bit...
+    static final boolean DO_MONITORS = false;
+//    static final boolean DO_MONITORS = ENABLE_LOGS && MarlinProperties.isDoMonitors();
+    // do checks
+    static final boolean DO_CHECKS = ENABLE_LOGS && MarlinProperties.isDoChecks();
+
+    // do AA range checks: disable when algorithm / code is stable
+    static final boolean DO_AA_RANGE_CHECK = false;
+
+    // enable logs
+    static final boolean DO_LOG_WIDEN_ARRAY = ENABLE_LOGS && false;
+    // enable oversize logs
+    static final boolean DO_LOG_OVERSIZE = ENABLE_LOGS && false;
+    // enable traces
+    static final boolean DO_TRACE = ENABLE_LOGS && false;
+
+    // do flush monitors
+    static final boolean DO_FLUSH_MONITORS = true;
+    // use one polling thread to dump statistics/monitors
+    static final boolean USE_DUMP_THREAD = false;
+    // thread dump interval (ms)
+    static final long DUMP_INTERVAL = 5000L;
+
+    // do clean dirty array
+    static final boolean DO_CLEAN_DIRTY = false;
+
+    // flag to use line simplifier
+    static final boolean USE_SIMPLIFIER = MarlinProperties.isUseSimplifier();
+
+    // flag to enable logs related bounds checks
+    static final boolean DO_LOG_BOUNDS = ENABLE_LOGS && false;
+
+    // Initial Array sizing (initial context capacity) ~ 350K
+
+    // 2048 pixel (width x height) for initial capacity
+    static final int INITIAL_PIXEL_DIM
+        = MarlinProperties.getInitialImageSize();
+
+    // typical array sizes: only odd numbers allowed below
+    static final int INITIAL_ARRAY        = 256;
+    static final int INITIAL_SMALL_ARRAY  = 1024;
+    static final int INITIAL_MEDIUM_ARRAY = 4096;
+    static final int INITIAL_LARGE_ARRAY  = 8192;
+    // alpha row dimension
+    static final int INITIAL_AA_ARRAY     = INITIAL_PIXEL_DIM;
+
+    // initial edges (24 bytes) = 24K [ints] = 96K
+    static final int INITIAL_EDGES_CAPACITY = 4096 * 24; // 6 ints per edges
+
+    // zero value as byte
+    static final byte BYTE_0 = (byte) 0;
+
+    // subpixels expressed as log2
+    public static final int SUBPIXEL_LG_POSITIONS_X
+        = MarlinProperties.getSubPixel_Log2_X();
+    public static final int SUBPIXEL_LG_POSITIONS_Y
+        = MarlinProperties.getSubPixel_Log2_Y();
+
+    // number of subpixels
+    public static final int SUBPIXEL_POSITIONS_X = 1 << (SUBPIXEL_LG_POSITIONS_X);
+    public static final int SUBPIXEL_POSITIONS_Y = 1 << (SUBPIXEL_LG_POSITIONS_Y);
+
+    public static final float NORM_SUBPIXELS
+        = (float)Math.sqrt(( SUBPIXEL_POSITIONS_X * SUBPIXEL_POSITIONS_X
+                           + SUBPIXEL_POSITIONS_Y * SUBPIXEL_POSITIONS_Y)/2.0);
+
+    public static final int MAX_AA_ALPHA
+        = SUBPIXEL_POSITIONS_X * SUBPIXEL_POSITIONS_Y;
+
+    public static final int TILE_SIZE_LG = MarlinProperties.getTileSize_Log2();
+    public static final int TILE_SIZE = 1 << TILE_SIZE_LG; // 32 by default
+
+    public static final int BLOCK_SIZE_LG = MarlinProperties.getBlockSize_Log2();
+    public static final int BLOCK_SIZE    = 1 << BLOCK_SIZE_LG;
+}
diff --git a/src/share/classes/sun/java2d/marlin/MarlinProperties.java b/src/share/classes/sun/java2d/marlin/MarlinProperties.java
new file mode 100644
index 0000000..bbee15a
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/MarlinProperties.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2007, 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.
+ */
+
+package sun.java2d.marlin;
+
+import java.security.AccessController;
+import static sun.java2d.marlin.MarlinUtils.logInfo;
+import sun.security.action.GetPropertyAction;
+
+public final class MarlinProperties {
+
+    private MarlinProperties() {
+        // no-op
+    }
+
+    // marlin system properties
+
+    public static boolean isUseThreadLocal() {
+        return getBoolean("sun.java2d.renderer.useThreadLocal", "true");
+    }
+
+    /**
+     * Return the initial pixel size used to define initial arrays
+     * (tile AA chunk, alpha line, buckets)
+     *
+     * @return 64 < initial pixel size < 32768 (2048 by default)
+     */
+    public static int getInitialImageSize() {
+        return getInteger("sun.java2d.renderer.pixelsize", 2048, 64, 32 * 1024);
+    }
+
+    /**
+     * Return the log(2) corresponding to subpixel on x-axis (
+     *
+     * @return 1 (2 subpixels) < initial pixel size < 4 (256 subpixels)
+     * (3 by default ie 8 subpixels)
+     */
+    public static int getSubPixel_Log2_X() {
+        return getInteger("sun.java2d.renderer.subPixel_log2_X", 3, 1, 8);
+    }
+
+    /**
+     * Return the log(2) corresponding to subpixel on y-axis (
+     *
+     * @return 1 (2 subpixels) < initial pixel size < 8 (256 subpixels)
+     * (3 by default ie 8 subpixels)
+     */
+    public static int getSubPixel_Log2_Y() {
+        return getInteger("sun.java2d.renderer.subPixel_log2_Y", 3, 1, 8);
+    }
+
+    /**
+     * Return the log(2) corresponding to the square tile size in pixels
+     *
+     * @return 3 (8x8 pixels) < tile size < 8 (256x256 pixels)
+     * (5 by default ie 32x32 pixels)
+     */
+    public static int getTileSize_Log2() {
+        return getInteger("sun.java2d.renderer.tileSize_log2", 5, 3, 8);
+    }
+
+    /**
+     * Return the log(2) corresponding to the block size in pixels
+     *
+     * @return 3 (8 pixels) < block size < 8 (256 pixels)
+     * (5 by default ie 32 pixels)
+     */
+    public static int getBlockSize_Log2() {
+        return getInteger("sun.java2d.renderer.blockSize_log2", 5, 3, 8);
+    }
+
+    // RLE / blockFlags settings
+
+    public static boolean isForceRLE() {
+        return getBoolean("sun.java2d.renderer.forceRLE", "false");
+    }
+
+    public static boolean isForceNoRLE() {
+        return getBoolean("sun.java2d.renderer.forceNoRLE", "false");
+    }
+
+    public static boolean isUseTileFlags() {
+        return getBoolean("sun.java2d.renderer.useTileFlags", "true");
+    }
+
+    public static boolean isUseTileFlagsWithHeuristics() {
+        return isUseTileFlags()
+        && getBoolean("sun.java2d.renderer.useTileFlags.useHeuristics", "true");
+    }
+
+    public static int getRLEMinWidth() {
+        return getInteger("sun.java2d.renderer.rleMinWidth", 64, 0, Integer.MAX_VALUE);
+    }
+
+    // optimisation parameters
+
+    public static boolean isUseSimplifier() {
+        return getBoolean("sun.java2d.renderer.useSimplifier", "false");
+    }
+
+    // debugging parameters
+
+    public static boolean isDoStats() {
+        return getBoolean("sun.java2d.renderer.doStats", "false");
+    }
+
+    public static boolean isDoMonitors() {
+        return getBoolean("sun.java2d.renderer.doMonitors", "false");
+    }
+
+    public static boolean isDoChecks() {
+        return getBoolean("sun.java2d.renderer.doChecks", "false");
+    }
+
+    // logging parameters
+
+    public static boolean isLoggingEnabled() {
+        return getBoolean("sun.java2d.renderer.log", "false");
+    }
+
+    public static boolean isUseLogger() {
+        return getBoolean("sun.java2d.renderer.useLogger", "false");
+    }
+
+    public static boolean isLogCreateContext() {
+        return getBoolean("sun.java2d.renderer.logCreateContext", "false");
+    }
+
+    public static boolean isLogUnsafeMalloc() {
+        return getBoolean("sun.java2d.renderer.logUnsafeMalloc", "false");
+    }
+
+    // system property utilities
+    static boolean getBoolean(final String key, final String def) {
+        return Boolean.valueOf(AccessController.doPrivileged(
+                  new GetPropertyAction(key, def)));
+    }
+
+    static int getInteger(final String key, final int def,
+                                 final int min, final int max)
+    {
+        final String property = AccessController.doPrivileged(
+                                    new GetPropertyAction(key));
+
+        int value = def;
+        if (property != null) {
+            try {
+                value = Integer.decode(property);
+            } catch (NumberFormatException e) {
+                logInfo("Invalid integer value for " + key + " = " + property);
+            }
+        }
+
+        // check for invalid values
+        if ((value < min) || (value > max)) {
+            logInfo("Invalid value for " + key + " = " + value
+                    + "; expected value in range[" + min + ", " + max + "] !");
+            value = def;
+        }
+        return value;
+    }
+
+}
diff --git a/src/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java b/src/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java
new file mode 100644
index 0000000..b7d3af4
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java
@@ -0,0 +1,1108 @@
+/*
+ * Copyright (c) 2007, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+import java.awt.BasicStroke;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
+import java.security.AccessController;
+import static sun.java2d.marlin.MarlinUtils.logInfo;
+import sun.awt.geom.PathConsumer2D;
+import sun.java2d.ReentrantContextProvider;
+import sun.java2d.ReentrantContextProviderCLQ;
+import sun.java2d.ReentrantContextProviderTL;
+import sun.java2d.pipe.AATileGenerator;
+import sun.java2d.pipe.Region;
+import sun.java2d.pipe.RenderingEngine;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * Marlin RendererEngine implementation (derived from Pisces)
+ */
+public class MarlinRenderingEngine extends RenderingEngine
+                                   implements MarlinConst
+{
+    private static enum NormMode {ON_WITH_AA, ON_NO_AA, OFF}
+
+    private static final float MIN_PEN_SIZE = 1f / NORM_SUBPIXELS;
+
+    static final float UPPER_BND = Float.MAX_VALUE / 2.0f;
+    static final float LOWER_BND = -UPPER_BND;
+
+    /**
+     * Public constructor
+     */
+    public MarlinRenderingEngine() {
+        super();
+        logSettings(MarlinRenderingEngine.class.getName());
+    }
+
+    /**
+     * Create a widened path as specified by the parameters.
+     * <p>
+     * The specified {@code src} {@link Shape} is widened according
+     * to the specified attribute parameters as per the
+     * {@link BasicStroke} specification.
+     *
+     * @param src the source path to be widened
+     * @param width the width of the widened path as per {@code BasicStroke}
+     * @param caps the end cap decorations as per {@code BasicStroke}
+     * @param join the segment join decorations as per {@code BasicStroke}
+     * @param miterlimit the miter limit as per {@code BasicStroke}
+     * @param dashes the dash length array as per {@code BasicStroke}
+     * @param dashphase the initial dash phase as per {@code BasicStroke}
+     * @return the widened path stored in a new {@code Shape} object
+     * @since 1.7
+     */
+    @Override
+    public Shape createStrokedShape(Shape src,
+                                    float width,
+                                    int caps,
+                                    int join,
+                                    float miterlimit,
+                                    float[] dashes,
+                                    float dashphase)
+    {
+        final RendererContext rdrCtx = getRendererContext();
+        try {
+            // initialize a large copyable Path2D to avoid a lot of array growing:
+            final Path2D.Float p2d =
+                    (rdrCtx.p2d == null) ?
+                    (rdrCtx.p2d = new Path2D.Float(Path2D.WIND_NON_ZERO,
+                                                   INITIAL_MEDIUM_ARRAY))
+                    : rdrCtx.p2d;
+            // reset
+            p2d.reset();
+
+            strokeTo(rdrCtx,
+                     src,
+                     null,
+                     width,
+                     NormMode.OFF,
+                     caps,
+                     join,
+                     miterlimit,
+                     dashes,
+                     dashphase,
+                     rdrCtx.transformerPC2D.wrapPath2d(p2d)
+                    );
+
+            // Use Path2D copy constructor (trim)
+            return new Path2D.Float(p2d);
+
+        } finally {
+            // recycle the RendererContext instance
+            returnRendererContext(rdrCtx);
+        }
+    }
+
+    /**
+     * Sends the geometry for a widened path as specified by the parameters
+     * to the specified consumer.
+     * <p>
+     * The specified {@code src} {@link Shape} is widened according
+     * to the parameters specified by the {@link BasicStroke} object.
+     * Adjustments are made to the path as appropriate for the
+     * {@link VALUE_STROKE_NORMALIZE} hint if the {@code normalize}
+     * boolean parameter is true.
+     * Adjustments are made to the path as appropriate for the
+     * {@link VALUE_ANTIALIAS_ON} hint if the {@code antialias}
+     * boolean parameter is true.
+     * <p>
+     * The geometry of the widened path is forwarded to the indicated
+     * {@link PathConsumer2D} object as it is calculated.
+     *
+     * @param src the source path to be widened
+     * @param bs the {@code BasicSroke} object specifying the
+     *           decorations to be applied to the widened path
+     * @param normalize indicates whether stroke normalization should
+     *                  be applied
+     * @param antialias indicates whether or not adjustments appropriate
+     *                  to antialiased rendering should be applied
+     * @param consumer the {@code PathConsumer2D} instance to forward
+     *                 the widened geometry to
+     * @since 1.7
+     */
+    @Override
+    public void strokeTo(Shape src,
+                         AffineTransform at,
+                         BasicStroke bs,
+                         boolean thin,
+                         boolean normalize,
+                         boolean antialias,
+                         final PathConsumer2D consumer)
+    {
+        final NormMode norm = (normalize) ?
+                ((antialias) ? NormMode.ON_WITH_AA : NormMode.ON_NO_AA)
+                : NormMode.OFF;
+
+        final RendererContext rdrCtx = getRendererContext();
+        try {
+            strokeTo(rdrCtx, src, at, bs, thin, norm, antialias, consumer);
+        } finally {
+            // recycle the RendererContext instance
+            returnRendererContext(rdrCtx);
+        }
+    }
+
+    final void strokeTo(final RendererContext rdrCtx,
+                        Shape src,
+                        AffineTransform at,
+                        BasicStroke bs,
+                        boolean thin,
+                        NormMode normalize,
+                        boolean antialias,
+                        PathConsumer2D pc2d)
+    {
+        float lw;
+        if (thin) {
+            if (antialias) {
+                lw = userSpaceLineWidth(at, MIN_PEN_SIZE);
+            } else {
+                lw = userSpaceLineWidth(at, 1.0f);
+            }
+        } else {
+            lw = bs.getLineWidth();
+        }
+        strokeTo(rdrCtx,
+                 src,
+                 at,
+                 lw,
+                 normalize,
+                 bs.getEndCap(),
+                 bs.getLineJoin(),
+                 bs.getMiterLimit(),
+                 bs.getDashArray(),
+                 bs.getDashPhase(),
+                 pc2d);
+    }
+
+    private final float userSpaceLineWidth(AffineTransform at, float lw) {
+
+        float widthScale;
+
+        if (at == null) {
+            widthScale = 1.0f;
+        } else if ((at.getType() & (AffineTransform.TYPE_GENERAL_TRANSFORM  |
+                                    AffineTransform.TYPE_GENERAL_SCALE)) != 0) {
+            widthScale = (float)Math.sqrt(at.getDeterminant());
+        } else {
+            // First calculate the "maximum scale" of this transform.
+            double A = at.getScaleX();       // m00
+            double C = at.getShearX();       // m01
+            double B = at.getShearY();       // m10
+            double D = at.getScaleY();       // m11
+
+            /*
+             * Given a 2 x 2 affine matrix [ A B ] such that
+             *                             [ C D ]
+             * v' = [x' y'] = [Ax + Cy, Bx + Dy], we want to
+             * find the maximum magnitude (norm) of the vector v'
+             * with the constraint (x^2 + y^2 = 1).
+             * The equation to maximize is
+             *     |v'| = sqrt((Ax+Cy)^2+(Bx+Dy)^2)
+             * or  |v'| = sqrt((AA+BB)x^2 + 2(AC+BD)xy + (CC+DD)y^2).
+             * Since sqrt is monotonic we can maximize |v'|^2
+             * instead and plug in the substitution y = sqrt(1 - x^2).
+             * Trigonometric equalities can then be used to get
+             * rid of most of the sqrt terms.
+             */
+
+            double EA = A*A + B*B;          // x^2 coefficient
+            double EB = 2.0*(A*C + B*D);    // xy coefficient
+            double EC = C*C + D*D;          // y^2 coefficient
+
+            /*
+             * There is a lot of calculus omitted here.
+             *
+             * Conceptually, in the interests of understanding the
+             * terms that the calculus produced we can consider
+             * that EA and EC end up providing the lengths along
+             * the major axes and the hypot term ends up being an
+             * adjustment for the additional length along the off-axis
+             * angle of rotated or sheared ellipses as well as an
+             * adjustment for the fact that the equation below
+             * averages the two major axis lengths.  (Notice that
+             * the hypot term contains a part which resolves to the
+             * difference of these two axis lengths in the absence
+             * of rotation.)
+             *
+             * In the calculus, the ratio of the EB and (EA-EC) terms
+             * ends up being the tangent of 2*theta where theta is
+             * the angle that the long axis of the ellipse makes
+             * with the horizontal axis.  Thus, this equation is
+             * calculating the length of the hypotenuse of a triangle
+             * along that axis.
+             */
+
+            double hypot = Math.sqrt(EB*EB + (EA-EC)*(EA-EC));
+            // sqrt omitted, compare to squared limits below.
+            double widthsquared = ((EA + EC + hypot)/2.0);
+
+            widthScale = (float)Math.sqrt(widthsquared);
+        }
+
+        return (lw / widthScale);
+    }
+
+    final void strokeTo(final RendererContext rdrCtx,
+                        Shape src,
+                        AffineTransform at,
+                        float width,
+                        NormMode normalize,
+                        int caps,
+                        int join,
+                        float miterlimit,
+                        float[] dashes,
+                        float dashphase,
+                        PathConsumer2D pc2d)
+    {
+        // We use strokerat so that in Stroker and Dasher we can work only
+        // with the pre-transformation coordinates. This will repeat a lot of
+        // computations done in the path iterator, but the alternative is to
+        // work with transformed paths and compute untransformed coordinates
+        // as needed. This would be faster but I do not think the complexity
+        // of working with both untransformed and transformed coordinates in
+        // the same code is worth it.
+        // However, if a path's width is constant after a transformation,
+        // we can skip all this untransforming.
+
+        // As pathTo() will check transformed coordinates for invalid values
+        // (NaN / Infinity) to ignore such points, it is necessary to apply the
+        // transformation before the path processing.
+        AffineTransform strokerat = null;
+
+        int dashLen = -1;
+        boolean recycleDashes = false;
+
+        if (at != null && !at.isIdentity()) {
+            final double a = at.getScaleX();
+            final double b = at.getShearX();
+            final double c = at.getShearY();
+            final double d = at.getScaleY();
+            final double det = a * d - c * b;
+
+            if (Math.abs(det) <= (2f * Float.MIN_VALUE)) {
+                // this rendering engine takes one dimensional curves and turns
+                // them into 2D shapes by giving them width.
+                // However, if everything is to be passed through a singular
+                // transformation, these 2D shapes will be squashed down to 1D
+                // again so, nothing can be drawn.
+
+                // Every path needs an initial moveTo and a pathDone. If these
+                // are not there this causes a SIGSEGV in libawt.so (at the time
+                // of writing of this comment (September 16, 2010)). Actually,
+                // I am not sure if the moveTo is necessary to avoid the SIGSEGV
+                // but the pathDone is definitely needed.
+                pc2d.moveTo(0f, 0f);
+                pc2d.pathDone();
+                return;
+            }
+
+            // If the transform is a constant multiple of an orthogonal transformation
+            // then every length is just multiplied by a constant, so we just
+            // need to transform input paths to stroker and tell stroker
+            // the scaled width. This condition is satisfied if
+            // a*b == -c*d && a*a+c*c == b*b+d*d. In the actual check below, we
+            // leave a bit of room for error.
+            if (nearZero(a*b + c*d) && nearZero(a*a + c*c - (b*b + d*d))) {
+                final float scale = (float) Math.sqrt(a*a + c*c);
+
+                if (dashes != null) {
+                    recycleDashes = true;
+                    dashLen = dashes.length;
+                    final float[] newDashes;
+                    if (dashLen <= INITIAL_ARRAY) {
+                        newDashes = rdrCtx.dasher.dashes_initial;
+                    } else {
+                        if (DO_STATS) {
+                            rdrCtx.stats.stat_array_dasher_dasher
+                                .add(dashLen);
+                        }
+                        newDashes = rdrCtx.getDirtyFloatArray(dashLen);
+                    }
+                    System.arraycopy(dashes, 0, newDashes, 0, dashLen);
+                    dashes = newDashes;
+                    for (int i = 0; i < dashLen; i++) {
+                        dashes[i] *= scale;
+                    }
+                    dashphase *= scale;
+                }
+                width *= scale;
+
+                // by now strokerat == null. Input paths to
+                // stroker (and maybe dasher) will have the full transform at
+                // applied to them and nothing will happen to the output paths.
+            } else {
+                strokerat = at;
+
+                // by now strokerat == at. Input paths to
+                // stroker (and maybe dasher) will have the full transform at
+                // applied to them, then they will be normalized, and then
+                // the inverse of *only the non translation part of at* will
+                // be applied to the normalized paths. This won't cause problems
+                // in stroker, because, suppose at = T*A, where T is just the
+                // translation part of at, and A is the rest. T*A has already
+                // been applied to Stroker/Dasher's input. Then Ainv will be
+                // applied. Ainv*T*A is not equal to T, but it is a translation,
+                // which means that none of stroker's assumptions about its
+                // input will be violated. After all this, A will be applied
+                // to stroker's output.
+            }
+        } else {
+            // either at is null or it's the identity. In either case
+            // we don't transform the path.
+            at = null;
+        }
+
+        if (USE_SIMPLIFIER) {
+            // Use simplifier after stroker before Renderer
+            // to remove collinear segments (notably due to cap square)
+            pc2d = rdrCtx.simplifier.init(pc2d);
+        }
+
+        final TransformingPathConsumer2D transformerPC2D = rdrCtx.transformerPC2D;
+        pc2d = transformerPC2D.deltaTransformConsumer(pc2d, strokerat);
+
+        pc2d = rdrCtx.stroker.init(pc2d, width, caps, join, miterlimit);
+
+        if (dashes != null) {
+            if (!recycleDashes) {
+                dashLen = dashes.length;
+            }
+            pc2d = rdrCtx.dasher.init(pc2d, dashes, dashLen, dashphase,
+                                      recycleDashes);
+        }
+        pc2d = transformerPC2D.inverseDeltaTransformConsumer(pc2d, strokerat);
+
+        final PathIterator pi = getNormalizingPathIterator(rdrCtx, normalize,
+                                    src.getPathIterator(at));
+
+        pathTo(rdrCtx, pi, pc2d);
+
+        /*
+         * Pipeline seems to be:
+         * shape.getPathIterator(at)
+         * -> (NormalizingPathIterator)
+         * -> (inverseDeltaTransformConsumer)
+         * -> (Dasher)
+         * -> Stroker
+         * -> (deltaTransformConsumer)
+         *
+         * -> (CollinearSimplifier) to remove redundant segments
+         *
+         * -> pc2d = Renderer (bounding box)
+         */
+    }
+
+    private static boolean nearZero(final double num) {
+        return Math.abs(num) < 2.0 * Math.ulp(num);
+    }
+
+    PathIterator getNormalizingPathIterator(final RendererContext rdrCtx,
+                                            final NormMode mode,
+                                            final PathIterator src)
+    {
+        switch (mode) {
+            case ON_WITH_AA:
+                // NormalizingPathIterator NearestPixelCenter:
+                return rdrCtx.nPCPathIterator.init(src);
+            case ON_NO_AA:
+                // NearestPixel NormalizingPathIterator:
+                return rdrCtx.nPQPathIterator.init(src);
+            case OFF:
+                // return original path iterator if normalization is disabled:
+                return src;
+            default:
+                throw new InternalError("Unrecognized normalization mode");
+        }
+    }
+
+    abstract static class NormalizingPathIterator implements PathIterator {
+
+        private PathIterator src;
+
+        // the adjustment applied to the current position.
+        private float curx_adjust, cury_adjust;
+        // the adjustment applied to the last moveTo position.
+        private float movx_adjust, movy_adjust;
+
+        private final float[] tmp;
+
+        NormalizingPathIterator(final float[] tmp) {
+            this.tmp = tmp;
+        }
+
+        final NormalizingPathIterator init(final PathIterator src) {
+            this.src = src;
+            return this; // fluent API
+        }
+
+        /**
+         * Disposes this path iterator:
+         * clean up before reusing this instance
+         */
+        final void dispose() {
+            // free source PathIterator:
+            this.src = null;
+        }
+
+        @Override
+        public final int currentSegment(final float[] coords) {
+            int lastCoord;
+            final int type = src.currentSegment(coords);
+
+            switch(type) {
+                case PathIterator.SEG_MOVETO:
+                case PathIterator.SEG_LINETO:
+                    lastCoord = 0;
+                    break;
+                case PathIterator.SEG_QUADTO:
+                    lastCoord = 2;
+                    break;
+                case PathIterator.SEG_CUBICTO:
+                    lastCoord = 4;
+                    break;
+                case PathIterator.SEG_CLOSE:
+                    // we don't want to deal with this case later. We just exit now
+                    curx_adjust = movx_adjust;
+                    cury_adjust = movy_adjust;
+                    return type;
+                default:
+                    throw new InternalError("Unrecognized curve type");
+            }
+
+            // normalize endpoint
+            float coord, x_adjust, y_adjust;
+
+            coord = coords[lastCoord];
+            x_adjust = normCoord(coord); // new coord
+            coords[lastCoord] = x_adjust;
+            x_adjust -= coord;
+
+            coord = coords[lastCoord + 1];
+            y_adjust = normCoord(coord); // new coord
+            coords[lastCoord + 1] = y_adjust;
+            y_adjust -= coord;
+
+            // now that the end points are done, normalize the control points
+            switch(type) {
+                case PathIterator.SEG_MOVETO:
+                    movx_adjust = x_adjust;
+                    movy_adjust = y_adjust;
+                    break;
+                case PathIterator.SEG_LINETO:
+                    break;
+                case PathIterator.SEG_QUADTO:
+                    coords[0] += (curx_adjust + x_adjust) / 2f;
+                    coords[1] += (cury_adjust + y_adjust) / 2f;
+                    break;
+                case PathIterator.SEG_CUBICTO:
+                    coords[0] += curx_adjust;
+                    coords[1] += cury_adjust;
+                    coords[2] += x_adjust;
+                    coords[3] += y_adjust;
+                    break;
+                case PathIterator.SEG_CLOSE:
+                    // handled earlier
+                default:
+            }
+            curx_adjust = x_adjust;
+            cury_adjust = y_adjust;
+            return type;
+        }
+
+        abstract float normCoord(final float coord);
+
+        @Override
+        public final int currentSegment(final double[] coords) {
+            final float[] _tmp = tmp; // dirty
+            int type = this.currentSegment(_tmp);
+            for (int i = 0; i < 6; i++) {
+                coords[i] = _tmp[i];
+            }
+            return type;
+        }
+
+        @Override
+        public final int getWindingRule() {
+            return src.getWindingRule();
+        }
+
+        @Override
+        public final boolean isDone() {
+            if (src.isDone()) {
+                // Dispose this instance:
+                dispose();
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public final void next() {
+            src.next();
+        }
+
+        static final class NearestPixelCenter
+                                extends NormalizingPathIterator
+        {
+            NearestPixelCenter(final float[] tmp) {
+                super(tmp);
+            }
+
+            @Override
+            float normCoord(final float coord) {
+                // round to nearest pixel center
+                return FloatMath.floor_f(coord) + 0.5f;
+            }
+        }
+
+        static final class NearestPixelQuarter
+                                extends NormalizingPathIterator
+        {
+            NearestPixelQuarter(final float[] tmp) {
+                super(tmp);
+            }
+
+            @Override
+            float normCoord(final float coord) {
+                // round to nearest (0.25, 0.25) pixel quarter
+                return FloatMath.floor_f(coord + 0.25f) + 0.25f;
+            }
+        }
+    }
+
+    private static void pathTo(final RendererContext rdrCtx, final PathIterator pi,
+                               final PathConsumer2D pc2d)
+    {
+        // mark context as DIRTY:
+        rdrCtx.dirty = true;
+
+        final float[] coords = rdrCtx.float6;
+
+        pathToLoop(coords, pi, pc2d);
+
+        // mark context as CLEAN:
+        rdrCtx.dirty = false;
+    }
+
+    private static void pathToLoop(final float[] coords, final PathIterator pi,
+                                   final PathConsumer2D pc2d)
+    {
+        // ported from DuctusRenderingEngine.feedConsumer() but simplified:
+        // - removed skip flag = !subpathStarted
+        // - removed pathClosed (ie subpathStarted not set to false)
+        boolean subpathStarted = false;
+
+        for (; !pi.isDone(); pi.next()) {
+            switch (pi.currentSegment(coords)) {
+            case PathIterator.SEG_MOVETO:
+                /* Checking SEG_MOVETO coordinates if they are out of the
+                 * [LOWER_BND, UPPER_BND] range. This check also handles NaN
+                 * and Infinity values. Skipping next path segment in case of
+                 * invalid data.
+                 */
+                if (coords[0] < UPPER_BND && coords[0] > LOWER_BND &&
+                    coords[1] < UPPER_BND && coords[1] > LOWER_BND)
+                {
+                    pc2d.moveTo(coords[0], coords[1]);
+                    subpathStarted = true;
+                }
+                break;
+            case PathIterator.SEG_LINETO:
+                /* Checking SEG_LINETO coordinates if they are out of the
+                 * [LOWER_BND, UPPER_BND] range. This check also handles NaN
+                 * and Infinity values. Ignoring current path segment in case
+                 * of invalid data. If segment is skipped its endpoint
+                 * (if valid) is used to begin new subpath.
+                 */
+                if (coords[0] < UPPER_BND && coords[0] > LOWER_BND &&
+                    coords[1] < UPPER_BND && coords[1] > LOWER_BND)
+                {
+                    if (subpathStarted) {
+                        pc2d.lineTo(coords[0], coords[1]);
+                    } else {
+                        pc2d.moveTo(coords[0], coords[1]);
+                        subpathStarted = true;
+                    }
+                }
+                break;
+            case PathIterator.SEG_QUADTO:
+                // Quadratic curves take two points
+                /* Checking SEG_QUADTO coordinates if they are out of the
+                 * [LOWER_BND, UPPER_BND] range. This check also handles NaN
+                 * and Infinity values. Ignoring current path segment in case
+                 * of invalid endpoints's data. Equivalent to the SEG_LINETO
+                 * if endpoint coordinates are valid but there are invalid data
+                 * among other coordinates
+                 */
+                if (coords[2] < UPPER_BND && coords[2] > LOWER_BND &&
+                    coords[3] < UPPER_BND && coords[3] > LOWER_BND)
+                {
+                    if (subpathStarted) {
+                        if (coords[0] < UPPER_BND && coords[0] > LOWER_BND &&
+                            coords[1] < UPPER_BND && coords[1] > LOWER_BND)
+                        {
+                            pc2d.quadTo(coords[0], coords[1],
+                                        coords[2], coords[3]);
+                        } else {
+                            pc2d.lineTo(coords[2], coords[3]);
+                        }
+                    } else {
+                        pc2d.moveTo(coords[2], coords[3]);
+                        subpathStarted = true;
+                    }
+                }
+                break;
+            case PathIterator.SEG_CUBICTO:
+                // Cubic curves take three points
+                /* Checking SEG_CUBICTO coordinates if they are out of the
+                 * [LOWER_BND, UPPER_BND] range. This check also handles NaN
+                 * and Infinity values. Ignoring current path segment in case
+                 * of invalid endpoints's data. Equivalent to the SEG_LINETO
+                 * if endpoint coordinates are valid but there are invalid data
+                 * among other coordinates
+                 */
+                if (coords[4] < UPPER_BND && coords[4] > LOWER_BND &&
+                    coords[5] < UPPER_BND && coords[5] > LOWER_BND)
+                {
+                    if (subpathStarted) {
+                        if (coords[0] < UPPER_BND && coords[0] > LOWER_BND &&
+                            coords[1] < UPPER_BND && coords[1] > LOWER_BND &&
+                            coords[2] < UPPER_BND && coords[2] > LOWER_BND &&
+                            coords[3] < UPPER_BND && coords[3] > LOWER_BND)
+                        {
+                            pc2d.curveTo(coords[0], coords[1],
+                                         coords[2], coords[3],
+                                         coords[4], coords[5]);
+                        } else {
+                            pc2d.lineTo(coords[4], coords[5]);
+                        }
+                    } else {
+                        pc2d.moveTo(coords[4], coords[5]);
+                        subpathStarted = true;
+                    }
+                }
+                break;
+            case PathIterator.SEG_CLOSE:
+                if (subpathStarted) {
+                    pc2d.closePath();
+                    // do not set subpathStarted to false
+                    // in case of missing moveTo() after close()
+                }
+                break;
+            default:
+            }
+        }
+        pc2d.pathDone();
+    }
+
+    /**
+     * Construct an antialiased tile generator for the given shape with
+     * the given rendering attributes and store the bounds of the tile
+     * iteration in the bbox parameter.
+     * The {@code at} parameter specifies a transform that should affect
+     * both the shape and the {@code BasicStroke} attributes.
+     * The {@code clip} parameter specifies the current clip in effect
+     * in device coordinates and can be used to prune the data for the
+     * operation, but the renderer is not required to perform any
+     * clipping.
+     * If the {@code BasicStroke} parameter is null then the shape
+     * should be filled as is, otherwise the attributes of the
+     * {@code BasicStroke} should be used to specify a draw operation.
+     * The {@code thin} parameter indicates whether or not the
+     * transformed {@code BasicStroke} represents coordinates smaller
+     * than the minimum resolution of the antialiasing rasterizer as
+     * specified by the {@code getMinimumAAPenWidth()} method.
+     * <p>
+     * Upon returning, this method will fill the {@code bbox} parameter
+     * with 4 values indicating the bounds of the iteration of the
+     * tile generator.
+     * The iteration order of the tiles will be as specified by the
+     * pseudo-code:
+     * <pre>
+     *     for (y = bbox[1]; y < bbox[3]; y += tileheight) {
+     *         for (x = bbox[0]; x < bbox[2]; x += tilewidth) {
+     *         }
+     *     }
+     * </pre>
+     * If there is no output to be rendered, this method may return
+     * null.
+     *
+     * @param s the shape to be rendered (fill or draw)
+     * @param at the transform to be applied to the shape and the
+     *           stroke attributes
+     * @param clip the current clip in effect in device coordinates
+     * @param bs if non-null, a {@code BasicStroke} whose attributes
+     *           should be applied to this operation
+     * @param thin true if the transformed stroke attributes are smaller
+     *             than the minimum dropout pen width
+     * @param normalize true if the {@code VALUE_STROKE_NORMALIZE}
+     *                  {@code RenderingHint} is in effect
+     * @param bbox returns the bounds of the iteration
+     * @return the {@code AATileGenerator} instance to be consulted
+     *         for tile coverages, or null if there is no output to render
+     * @since 1.7
+     */
+    @Override
+    public AATileGenerator getAATileGenerator(Shape s,
+                                              AffineTransform at,
+                                              Region clip,
+                                              BasicStroke bs,
+                                              boolean thin,
+                                              boolean normalize,
+                                              int[] bbox)
+    {
+        MarlinTileGenerator ptg = null;
+        Renderer r = null;
+
+        final RendererContext rdrCtx = getRendererContext();
+        try {
+            // Test if at is identity:
+            final AffineTransform _at = (at != null && !at.isIdentity()) ? at
+                                        : null;
+
+            final NormMode norm = (normalize) ? NormMode.ON_WITH_AA : NormMode.OFF;
+
+            if (bs == null) {
+                // fill shape:
+                final PathIterator pi = getNormalizingPathIterator(rdrCtx, norm,
+                                            s.getPathIterator(_at));
+
+                // note: Winding rule may be EvenOdd ONLY for fill operations !
+                r = rdrCtx.renderer.init(clip.getLoX(), clip.getLoY(),
+                                         clip.getWidth(), clip.getHeight(),
+                                         pi.getWindingRule());
+
+                // TODO: subdivide quad/cubic curves into monotonic curves ?
+                pathTo(rdrCtx, pi, r);
+            } else {
+                // draw shape with given stroke:
+                r = rdrCtx.renderer.init(clip.getLoX(), clip.getLoY(),
+                                         clip.getWidth(), clip.getHeight(),
+                                         PathIterator.WIND_NON_ZERO);
+
+                strokeTo(rdrCtx, s, _at, bs, thin, norm, true, r);
+            }
+            if (r.endRendering()) {
+                ptg = rdrCtx.ptg.init();
+                ptg.getBbox(bbox);
+                // note: do not returnRendererContext(rdrCtx)
+                // as it will be called later by MarlinTileGenerator.dispose()
+                r = null;
+            }
+        } finally {
+            if (r != null) {
+                // dispose renderer:
+                r.dispose();
+                // recycle the RendererContext instance
+                MarlinRenderingEngine.returnRendererContext(rdrCtx);
+            }
+        }
+
+        // Return null to cancel AA tile generation (nothing to render)
+        return ptg;
+    }
+
+    @Override
+    public final AATileGenerator getAATileGenerator(double x, double y,
+                                                    double dx1, double dy1,
+                                                    double dx2, double dy2,
+                                                    double lw1, double lw2,
+                                                    Region clip,
+                                                    int[] bbox)
+    {
+        // REMIND: Deal with large coordinates!
+        double ldx1, ldy1, ldx2, ldy2;
+        boolean innerpgram = (lw1 > 0.0 && lw2 > 0.0);
+
+        if (innerpgram) {
+            ldx1 = dx1 * lw1;
+            ldy1 = dy1 * lw1;
+            ldx2 = dx2 * lw2;
+            ldy2 = dy2 * lw2;
+            x -= (ldx1 + ldx2) / 2.0;
+            y -= (ldy1 + ldy2) / 2.0;
+            dx1 += ldx1;
+            dy1 += ldy1;
+            dx2 += ldx2;
+            dy2 += ldy2;
+            if (lw1 > 1.0 && lw2 > 1.0) {
+                // Inner parallelogram was entirely consumed by stroke...
+                innerpgram = false;
+            }
+        } else {
+            ldx1 = ldy1 = ldx2 = ldy2 = 0.0;
+        }
+
+        MarlinTileGenerator ptg = null;
+        Renderer r = null;
+
+        final RendererContext rdrCtx = getRendererContext();
+        try {
+            r = rdrCtx.renderer.init(clip.getLoX(), clip.getLoY(),
+                                         clip.getWidth(), clip.getHeight(),
+                                         Renderer.WIND_EVEN_ODD);
+
+            r.moveTo((float) x, (float) y);
+            r.lineTo((float) (x+dx1), (float) (y+dy1));
+            r.lineTo((float) (x+dx1+dx2), (float) (y+dy1+dy2));
+            r.lineTo((float) (x+dx2), (float) (y+dy2));
+            r.closePath();
+
+            if (innerpgram) {
+                x += ldx1 + ldx2;
+                y += ldy1 + ldy2;
+                dx1 -= 2.0 * ldx1;
+                dy1 -= 2.0 * ldy1;
+                dx2 -= 2.0 * ldx2;
+                dy2 -= 2.0 * ldy2;
+                r.moveTo((float) x, (float) y);
+                r.lineTo((float) (x+dx1), (float) (y+dy1));
+                r.lineTo((float) (x+dx1+dx2), (float) (y+dy1+dy2));
+                r.lineTo((float) (x+dx2), (float) (y+dy2));
+                r.closePath();
+            }
+            r.pathDone();
+
+            if (r.endRendering()) {
+                ptg = rdrCtx.ptg.init();
+                ptg.getBbox(bbox);
+                // note: do not returnRendererContext(rdrCtx)
+                // as it will be called later by MarlinTileGenerator.dispose()
+                r = null;
+            }
+        } finally {
+            if (r != null) {
+                // dispose renderer:
+                r.dispose();
+                // recycle the RendererContext instance
+                MarlinRenderingEngine.returnRendererContext(rdrCtx);
+            }
+        }
+
+        // Return null to cancel AA tile generation (nothing to render)
+        return ptg;
+    }
+
+    /**
+     * Returns the minimum pen width that the antialiasing rasterizer
+     * can represent without dropouts occuring.
+     * @since 1.7
+     */
+    @Override
+    public float getMinimumAAPenSize() {
+        return MIN_PEN_SIZE;
+    }
+
+    static {
+        if (PathIterator.WIND_NON_ZERO != Renderer.WIND_NON_ZERO ||
+            PathIterator.WIND_EVEN_ODD != Renderer.WIND_EVEN_ODD ||
+            BasicStroke.JOIN_MITER != Stroker.JOIN_MITER ||
+            BasicStroke.JOIN_ROUND != Stroker.JOIN_ROUND ||
+            BasicStroke.JOIN_BEVEL != Stroker.JOIN_BEVEL ||
+            BasicStroke.CAP_BUTT != Stroker.CAP_BUTT ||
+            BasicStroke.CAP_ROUND != Stroker.CAP_ROUND ||
+            BasicStroke.CAP_SQUARE != Stroker.CAP_SQUARE)
+        {
+            throw new InternalError("mismatched renderer constants");
+        }
+    }
+
+    // --- RendererContext handling ---
+    // use ThreadLocal or ConcurrentLinkedQueue to get one RendererContext
+    private static final boolean USE_THREAD_LOCAL;
+
+    // reference type stored in either TL or CLQ
+    static final int REF_TYPE;
+
+    // Per-thread RendererContext
+    private static final ReentrantContextProvider<RendererContext> RDR_CTX_PROVIDER;
+
+    // Static initializer to use TL or CLQ mode
+    static {
+        USE_THREAD_LOCAL = MarlinProperties.isUseThreadLocal();
+
+        // Soft reference by default:
+        final String refType = AccessController.doPrivileged(
+                            new GetPropertyAction("sun.java2d.renderer.useRef",
+                            "soft"));
+        switch (refType) {
+            default:
+            case "soft":
+                REF_TYPE = ReentrantContextProvider.REF_SOFT;
+                break;
+            case "weak":
+                REF_TYPE = ReentrantContextProvider.REF_WEAK;
+                break;
+            case "hard":
+                REF_TYPE = ReentrantContextProvider.REF_HARD;
+                break;
+        }
+
+        if (USE_THREAD_LOCAL) {
+            RDR_CTX_PROVIDER = new ReentrantContextProviderTL<RendererContext>(REF_TYPE)
+                {
+                    @Override
+                    protected RendererContext newContext() {
+                        return RendererContext.createContext();
+                    }
+                };
+        } else {
+            RDR_CTX_PROVIDER = new ReentrantContextProviderCLQ<RendererContext>(REF_TYPE)
+                {
+                    @Override
+                    protected RendererContext newContext() {
+                        return RendererContext.createContext();
+                    }
+                };
+        }
+    }
+
+    private static boolean SETTINGS_LOGGED = !ENABLE_LOGS;
+
+    private static void logSettings(final String reClass) {
+        // log information at startup
+        if (SETTINGS_LOGGED) {
+            return;
+        }
+        SETTINGS_LOGGED = true;
+
+        String refType;
+        switch (REF_TYPE) {
+            default:
+            case ReentrantContextProvider.REF_HARD:
+                refType = "hard";
+                break;
+            case ReentrantContextProvider.REF_SOFT:
+                refType = "soft";
+                break;
+            case ReentrantContextProvider.REF_WEAK:
+                refType = "weak";
+                break;
+        }
+
+        logInfo("=========================================================="
+                + "=====================");
+
+        logInfo("Marlin software rasterizer           = ENABLED");
+        logInfo("Version                              = ["
+                + Version.getVersion() + "]");
+        logInfo("sun.java2d.renderer                  = "
+                + reClass);
+        logInfo("sun.java2d.renderer.useThreadLocal   = "
+                + USE_THREAD_LOCAL);
+        logInfo("sun.java2d.renderer.useRef           = "
+                + refType);
+
+        logInfo("sun.java2d.renderer.pixelsize        = "
+                + MarlinConst.INITIAL_PIXEL_DIM);
+        logInfo("sun.java2d.renderer.subPixel_log2_X  = "
+                + MarlinConst.SUBPIXEL_LG_POSITIONS_X);
+        logInfo("sun.java2d.renderer.subPixel_log2_Y  = "
+                + MarlinConst.SUBPIXEL_LG_POSITIONS_Y);
+        logInfo("sun.java2d.renderer.tileSize_log2    = "
+                + MarlinConst.TILE_SIZE_LG);
+
+        logInfo("sun.java2d.renderer.blockSize_log2   = "
+                + MarlinConst.BLOCK_SIZE_LG);
+
+        logInfo("sun.java2d.renderer.blockSize_log2   = "
+                + MarlinConst.BLOCK_SIZE_LG);
+
+        // RLE / blockFlags settings
+
+        logInfo("sun.java2d.renderer.forceRLE         = "
+                + MarlinProperties.isForceRLE());
+        logInfo("sun.java2d.renderer.forceNoRLE       = "
+                + MarlinProperties.isForceNoRLE());
+        logInfo("sun.java2d.renderer.useTileFlags     = "
+                + MarlinProperties.isUseTileFlags());
+        logInfo("sun.java2d.renderer.useTileFlags.useHeuristics = "
+                + MarlinProperties.isUseTileFlagsWithHeuristics());
+        logInfo("sun.java2d.renderer.rleMinWidth      = "
+                + MarlinCache.RLE_MIN_WIDTH);
+
+        // optimisation parameters
+        logInfo("sun.java2d.renderer.useSimplifier    = "
+                + MarlinConst.USE_SIMPLIFIER);
+
+        // debugging parameters
+        logInfo("sun.java2d.renderer.doStats          = "
+                + MarlinConst.DO_STATS);
+        logInfo("sun.java2d.renderer.doMonitors       = "
+                + MarlinConst.DO_MONITORS);
+        logInfo("sun.java2d.renderer.doChecks         = "
+                + MarlinConst.DO_CHECKS);
+
+        // logging parameters
+        logInfo("sun.java2d.renderer.useLogger        = "
+                + MarlinConst.USE_LOGGER);
+        logInfo("sun.java2d.renderer.logCreateContext = "
+                + MarlinConst.LOG_CREATE_CONTEXT);
+        logInfo("sun.java2d.renderer.logUnsafeMalloc  = "
+                + MarlinConst.LOG_UNSAFE_MALLOC);
+
+        // quality settings
+        logInfo("Renderer settings:");
+        logInfo("CUB_COUNT_LG = " + Renderer.CUB_COUNT_LG);
+        logInfo("CUB_DEC_BND  = " + Renderer.CUB_DEC_BND);
+        logInfo("CUB_INC_BND  = " + Renderer.CUB_INC_BND);
+        logInfo("QUAD_DEC_BND = " + Renderer.QUAD_DEC_BND);
+
+        logInfo("=========================================================="
+                + "=====================");
+    }
+
+    /**
+     * Get the RendererContext instance dedicated to the current thread
+     * @return RendererContext instance
+     */
+    @SuppressWarnings({"unchecked"})
+    static RendererContext getRendererContext() {
+        final RendererContext rdrCtx = RDR_CTX_PROVIDER.acquire();
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_pre_getAATileGenerator.start();
+        }
+        return rdrCtx;
+    }
+
+    /**
+     * Reset and return the given RendererContext instance for reuse
+     * @param rdrCtx RendererContext instance
+     */
+    static void returnRendererContext(final RendererContext rdrCtx) {
+        rdrCtx.dispose();
+
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_pre_getAATileGenerator.stop();
+        }
+        RDR_CTX_PROVIDER.release(rdrCtx);
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/MarlinTileGenerator.java b/src/share/classes/sun/java2d/marlin/MarlinTileGenerator.java
new file mode 100644
index 0000000..824660f
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/MarlinTileGenerator.java
@@ -0,0 +1,469 @@
+/*
+ * Copyright (c) 2007, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+import sun.java2d.pipe.AATileGenerator;
+import sun.misc.Unsafe;
+
+final class MarlinTileGenerator implements AATileGenerator, MarlinConst {
+
+    private static final int MAX_TILE_ALPHA_SUM = TILE_SIZE * TILE_SIZE
+                                                      * MAX_AA_ALPHA;
+
+    private final Renderer rdr;
+    private final MarlinCache cache;
+    private int x, y;
+
+    // per-thread renderer context
+    final RendererContext rdrCtx;
+
+    MarlinTileGenerator(Renderer r) {
+        this.rdr = r;
+        this.cache = r.cache;
+        this.rdrCtx = r.rdrCtx;
+    }
+
+    MarlinTileGenerator init() {
+        this.x = cache.bboxX0;
+        this.y = cache.bboxY0;
+
+        return this; // fluent API
+    }
+
+    /**
+     * Disposes this tile generator:
+     * clean up before reusing this instance
+     */
+    @Override
+    public void dispose() {
+        if (DO_MONITORS) {
+            // called from AAShapePipe.renderTiles() (render tiles end):
+            rdrCtx.stats.mon_pipe_renderTiles.stop();
+        }
+        // dispose cache:
+        cache.dispose();
+        // dispose renderer:
+        rdr.dispose();
+        // recycle the RendererContext instance
+        MarlinRenderingEngine.returnRendererContext(rdrCtx);
+    }
+
+    void getBbox(int[] bbox) {
+        bbox[0] = cache.bboxX0;
+        bbox[1] = cache.bboxY0;
+        bbox[2] = cache.bboxX1;
+        bbox[3] = cache.bboxY1;
+    }
+
+    /**
+     * Gets the width of the tiles that the generator batches output into.
+     * @return the width of the standard alpha tile
+     */
+    @Override
+    public int getTileWidth() {
+        if (DO_MONITORS) {
+            // called from AAShapePipe.renderTiles() (render tiles start):
+            rdrCtx.stats.mon_pipe_renderTiles.start();
+        }
+        return TILE_SIZE;
+    }
+
+    /**
+     * Gets the height of the tiles that the generator batches output into.
+     * @return the height of the standard alpha tile
+     */
+    @Override
+    public int getTileHeight() {
+        return TILE_SIZE;
+    }
+
+    /**
+     * Gets the typical alpha value that will characterize the current
+     * tile.
+     * The answer may be 0x00 to indicate that the current tile has
+     * no coverage in any of its pixels, or it may be 0xff to indicate
+     * that the current tile is completely covered by the path, or any
+     * other value to indicate non-trivial coverage cases.
+     * @return 0x00 for no coverage, 0xff for total coverage, or any other
+     *         value for partial coverage of the tile
+     */
+    @Override
+    public int getTypicalAlpha() {
+        int al = cache.alphaSumInTile(x);
+        // Note: if we have a filled rectangle that doesn't end on a tile
+        // border, we could still return 0xff, even though al!=maxTileAlphaSum
+        // This is because if we return 0xff, our users will fill a rectangle
+        // starting at x,y that has width = Math.min(TILE_SIZE, bboxX1-x),
+        // and height min(TILE_SIZE,bboxY1-y), which is what should happen.
+        // However, to support this, we would have to use 2 Math.min's
+        // and 2 multiplications per tile, instead of just 2 multiplications
+        // to compute maxTileAlphaSum. The savings offered would probably
+        // not be worth it, considering how rare this case is.
+        // Note: I have not tested this, so in the future if it is determined
+        // that it is worth it, it should be implemented. Perhaps this method's
+        // interface should be changed to take arguments the width and height
+        // of the current tile. This would eliminate the 2 Math.min calls that
+        // would be needed here, since our caller needs to compute these 2
+        // values anyway.
+        final int alpha = (al == 0x00 ? 0x00
+                              : (al == MAX_TILE_ALPHA_SUM ? 0xff : 0x80));
+        if (DO_STATS) {
+            rdrCtx.stats.hist_tile_generator_alpha.add(alpha);
+        }
+        return alpha;
+    }
+
+    /**
+     * Skips the current tile and moves on to the next tile.
+     * Either this method, or the getAlpha() method should be called
+     * once per tile, but not both.
+     */
+    @Override
+    public void nextTile() {
+        if ((x += TILE_SIZE) >= cache.bboxX1) {
+            x = cache.bboxX0;
+            y += TILE_SIZE;
+
+            if (y < cache.bboxY1) {
+                // compute for the tile line
+                // [ y; max(y + TILE_SIZE, bboxY1) ]
+                this.rdr.endRendering(y);
+            }
+        }
+    }
+
+    /**
+     * Gets the alpha coverage values for the current tile.
+     * Either this method, or the nextTile() method should be called
+     * once per tile, but not both.
+     */
+    @Override
+    public void getAlpha(final byte[] tile, final int offset,
+                                            final int rowstride)
+    {
+        if (cache.useRLE) {
+            getAlphaRLE(tile, offset, rowstride);
+        } else {
+            getAlphaNoRLE(tile, offset, rowstride);
+        }
+    }
+
+    /**
+     * Gets the alpha coverage values for the current tile.
+     * Either this method, or the nextTile() method should be called
+     * once per tile, but not both.
+     */
+    private void getAlphaNoRLE(final byte[] tile, final int offset,
+                               final int rowstride)
+    {
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_ptg_getAlpha.start();
+        }
+
+        // local vars for performance:
+        final MarlinCache _cache = this.cache;
+        final long[] rowAAChunkIndex = _cache.rowAAChunkIndex;
+        final int[] rowAAx0 = _cache.rowAAx0;
+        final int[] rowAAx1 = _cache.rowAAx1;
+
+        final int x0 = this.x;
+        final int x1 = FloatMath.min(x0 + TILE_SIZE, _cache.bboxX1);
+
+        // note: process tile line [0 - 32[
+        final int y0 = 0;
+        final int y1 = FloatMath.min(this.y + TILE_SIZE, _cache.bboxY1) - this.y;
+
+        if (DO_LOG_BOUNDS) {
+            MarlinUtils.logInfo("getAlpha = [" + x0 + " ... " + x1
+                                + "[ [" + y0 + " ... " + y1 + "[");
+        }
+
+        final Unsafe _unsafe = OffHeapArray.UNSAFE;
+        final long SIZE = 1L;
+        final long addr_rowAA = _cache.rowAAChunk.address;
+        long addr;
+
+        final int skipRowPixels = (rowstride - (x1 - x0));
+
+        int aax0, aax1, end;
+        int idx = offset;
+
+        for (int cy = y0, cx; cy < y1; cy++) {
+            // empty line (default)
+            cx = x0;
+
+            aax1 = rowAAx1[cy]; // exclusive
+
+            // quick check if there is AA data
+            // corresponding to this tile [x0; x1[
+            if (aax1 > x0) {
+                aax0 = rowAAx0[cy]; // inclusive
+
+                if (aax0 < x1) {
+                    // note: cx is the cursor pointer in the tile array
+                    // (left to right)
+                    cx = aax0;
+
+                    // ensure cx >= x0
+                    if (cx <= x0) {
+                        cx = x0;
+                    } else {
+                        // fill line start until first AA pixel rowAA exclusive:
+                        for (end = x0; end < cx; end++) {
+                            tile[idx++] = 0;
+                        }
+                    }
+
+                    // now: cx >= x0 but cx < aax0 (x1 < aax0)
+
+                    // Copy AA data (sum alpha data):
+                    addr = addr_rowAA + rowAAChunkIndex[cy] + (cx - aax0);
+
+                    for (end = (aax1 <= x1) ? aax1 : x1; cx < end; cx++) {
+                        // cx inside tile[x0; x1[ :
+                        tile[idx++] = _unsafe.getByte(addr); // [0..255]
+                        addr += SIZE;
+                    }
+                }
+            }
+
+            // fill line end
+            while (cx < x1) {
+                tile[idx++] = 0;
+                cx++;
+            }
+
+            if (DO_TRACE) {
+                for (int i = idx - (x1 - x0); i < idx; i++) {
+                    System.out.print(hex(tile[i], 2));
+                }
+                System.out.println();
+            }
+
+            idx += skipRowPixels;
+        }
+
+        nextTile();
+
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_ptg_getAlpha.stop();
+        }
+    }
+
+    /**
+     * Gets the alpha coverage values for the current tile.
+     * Either this method, or the nextTile() method should be called
+     * once per tile, but not both.
+     */
+    private void getAlphaRLE(final byte[] tile, final int offset,
+                             final int rowstride)
+    {
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_ptg_getAlpha.start();
+        }
+
+        // Decode run-length encoded alpha mask data
+        // The data for row j begins at cache.rowOffsetsRLE[j]
+        // and is encoded as a set of 2-byte pairs (val, runLen)
+        // terminated by a (0, 0) pair.
+
+        // local vars for performance:
+        final MarlinCache _cache = this.cache;
+        final long[] rowAAChunkIndex = _cache.rowAAChunkIndex;
+        final int[] rowAAx0 = _cache.rowAAx0;
+        final int[] rowAAx1 = _cache.rowAAx1;
+        final int[] rowAAEnc = _cache.rowAAEnc;
+        final long[] rowAALen = _cache.rowAALen;
+        final long[] rowAAPos = _cache.rowAAPos;
+
+        final int x0 = this.x;
+        final int x1 = FloatMath.min(x0 + TILE_SIZE, _cache.bboxX1);
+
+        // note: process tile line [0 - 32[
+        final int y0 = 0;
+        final int y1 = FloatMath.min(this.y + TILE_SIZE, _cache.bboxY1) - this.y;
+
+        if (DO_LOG_BOUNDS) {
+            MarlinUtils.logInfo("getAlpha = [" + x0 + " ... " + x1
+                                + "[ [" + y0 + " ... " + y1 + "[");
+        }
+
+        final Unsafe _unsafe = OffHeapArray.UNSAFE;
+        final long SIZE_BYTE = 1L;
+        final long SIZE_INT = 4L;
+        final long addr_rowAA = _cache.rowAAChunk.address;
+        long addr, addr_row, last_addr, addr_end;
+
+        final int skipRowPixels = (rowstride - (x1 - x0));
+
+        int cx, cy, cx1;
+        int rx0, rx1, runLen, end;
+        int packed;
+        byte val;
+        int idx = offset;
+
+        for (cy = y0; cy < y1; cy++) {
+            // empty line (default)
+            cx = x0;
+
+            if (rowAAEnc[cy] == 0) {
+                // Raw encoding:
+
+                final int aax1 = rowAAx1[cy]; // exclusive
+
+                // quick check if there is AA data
+                // corresponding to this tile [x0; x1[
+                if (aax1 > x0) {
+                    final int aax0 = rowAAx0[cy]; // inclusive
+
+                    if (aax0 < x1) {
+                        // note: cx is the cursor pointer in the tile array
+                        // (left to right)
+                        cx = aax0;
+
+                        // ensure cx >= x0
+                        if (cx <= x0) {
+                            cx = x0;
+                        } else {
+                            // fill line start until first AA pixel rowAA exclusive:
+                            for (end = x0; end < cx; end++) {
+                                tile[idx++] = 0;
+                            }
+                        }
+
+                        // now: cx >= x0 but cx < aax0 (x1 < aax0)
+
+                        // Copy AA data (sum alpha data):
+                        addr = addr_rowAA + rowAAChunkIndex[cy] + (cx - aax0);
+
+                        for (end = (aax1 <= x1) ? aax1 : x1; cx < end; cx++) {
+                            tile[idx++] = _unsafe.getByte(addr); // [0..255]
+                            addr += SIZE_BYTE;
+                        }
+                    }
+                }
+            } else {
+                // RLE encoding:
+
+                // quick check if there is AA data
+                // corresponding to this tile [x0; x1[
+                if (rowAAx1[cy] > x0) { // last pixel exclusive
+
+                    cx = rowAAx0[cy]; // inclusive
+                    if (cx > x1) {
+                        cx = x1;
+                    }
+
+                    // fill line start until first AA pixel rowAA exclusive:
+                    for (int i = x0; i < cx; i++) {
+                        tile[idx++] = 0;
+                    }
+
+                    // get row address:
+                    addr_row = addr_rowAA + rowAAChunkIndex[cy];
+                    // get row end address:
+                    addr_end = addr_row + rowAALen[cy]; // coded length
+
+                    // reuse previous iteration position:
+                    addr = addr_row + rowAAPos[cy];
+
+                    last_addr = 0L;
+
+                    while ((cx < x1) && (addr < addr_end)) {
+                        // keep current position:
+                        last_addr = addr;
+
+                        // packed value:
+                        packed = _unsafe.getInt(addr);
+
+                        // last exclusive pixel x-coordinate:
+                        cx1 = (packed >> 8);
+                        // as bytes:
+                        addr += SIZE_INT;
+
+                        rx0 = cx;
+                        if (rx0 < x0) {
+                            rx0 = x0;
+                        }
+                        rx1 = cx = cx1;
+                        if (rx1 > x1) {
+                            rx1 = x1;
+                            cx  = x1; // fix last x
+                        }
+                        // adjust runLen:
+                        runLen = rx1 - rx0;
+
+                        // ensure rx1 > rx0:
+                        if (runLen > 0) {
+                            val = (byte)(packed & 0xFF); // [0..255]
+
+                            do {
+                                tile[idx++] = val;
+                            } while (--runLen > 0);
+                        }
+                    }
+
+                    // Update last position in RLE entries:
+                    if (last_addr != 0L) {
+                        // Fix x0:
+                        rowAAx0[cy]  = cx; // inclusive
+                        // Fix position:
+                        rowAAPos[cy] = (last_addr - addr_row);
+                    }
+                }
+            }
+
+            // fill line end
+            while (cx < x1) {
+                tile[idx++] = 0;
+                cx++;
+            }
+
+            if (DO_TRACE) {
+                for (int i = idx - (x1 - x0); i < idx; i++) {
+                    System.out.print(hex(tile[i], 2));
+                }
+                System.out.println();
+            }
+
+            idx += skipRowPixels;
+        }
+
+        nextTile();
+
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_ptg_getAlpha.stop();
+        }
+    }
+
+    static String hex(int v, int d) {
+        String s = Integer.toHexString(v);
+        while (s.length() < d) {
+            s = "0" + s;
+        }
+        return s.substring(0, d);
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/MarlinUtils.java b/src/share/classes/sun/java2d/marlin/MarlinUtils.java
new file mode 100644
index 0000000..5645e70
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/MarlinUtils.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+
+public final class MarlinUtils {
+    // Marlin logger
+    private static final sun.util.logging.PlatformLogger LOG;
+
+    static {
+        if (MarlinConst.USE_LOGGER) {
+            LOG = sun.util.logging.PlatformLogger.getLogger("sun.java2d.marlin");
+        } else {
+            LOG = null;
+        }
+    }
+
+    private MarlinUtils() {
+        // no-op
+    }
+
+    public static void logInfo(final String msg) {
+        if (MarlinConst.USE_LOGGER) {
+            LOG.info(msg);
+        } else if (MarlinConst.ENABLE_LOGS) {
+            System.out.print("INFO: ");
+            System.out.println(msg);
+        }
+    }
+
+    public static void logException(final String msg, final Throwable th) {
+        if (MarlinConst.USE_LOGGER) {
+            LOG.warning(msg, th);
+        } else if (MarlinConst.ENABLE_LOGS) {
+            System.out.print("WARNING: ");
+            System.out.println(msg);
+            th.printStackTrace(System.err);
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/MergeSort.java b/src/share/classes/sun/java2d/marlin/MergeSort.java
new file mode 100644
index 0000000..52e1f63
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/MergeSort.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2009, 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.
+ */
+
+package sun.java2d.marlin;
+
+/**
+ * MergeSort adapted from (OpenJDK 8) java.util.Array.legacyMergeSort(Object[])
+ * to swap two arrays at the same time (x & y)
+ * and use external auxiliary storage for temporary arrays
+ */
+final class MergeSort {
+
+    // insertion sort threshold
+    public static final int INSERTION_SORT_THRESHOLD = 14;
+
+    /**
+     * Modified merge sort:
+     * Input arrays are in both auxX/auxY (sorted: 0 to insertionSortIndex)
+     *                     and x/y (unsorted: insertionSortIndex to toIndex)
+     * Outputs are stored in x/y arrays
+     */
+    static void mergeSortNoCopy(final int[] x, final int[] y,
+                                final int[] auxX, final int[] auxY,
+                                final int toIndex,
+                                final int insertionSortIndex)
+    {
+        if ((toIndex > x.length) || (toIndex > y.length)
+                || (toIndex > auxX.length) || (toIndex > auxY.length)) {
+            // explicit check to avoid bound checks within hot loops (below):
+            throw new ArrayIndexOutOfBoundsException("bad arguments: toIndex="
+                                                     + toIndex);
+        }
+
+        // sort second part only using merge / insertion sort
+        // in auxiliary storage (auxX/auxY)
+        mergeSort(x, y, x, auxX, y, auxY, insertionSortIndex, toIndex);
+
+        // final pass to merge both
+        // Merge sorted parts (auxX/auxY) into x/y arrays
+        if ((insertionSortIndex == 0)
+            || (auxX[insertionSortIndex - 1] <= auxX[insertionSortIndex])) {
+//            System.out.println("mergeSortNoCopy: ordered");
+            // 34 occurences
+            // no initial left part or both sublists (auxX, auxY) are sorted:
+            // copy back data into (x, y):
+            System.arraycopy(auxX, 0, x, 0, toIndex);
+            System.arraycopy(auxY, 0, y, 0, toIndex);
+            return;
+        }
+
+        for (int i = 0, p = 0, q = insertionSortIndex; i < toIndex; i++) {
+            if ((q >= toIndex) || ((p < insertionSortIndex)
+                                   && (auxX[p] <= auxX[q]))) {
+                x[i] = auxX[p];
+                y[i] = auxY[p];
+                p++;
+            } else {
+                x[i] = auxX[q];
+                y[i] = auxY[q];
+                q++;
+            }
+        }
+    }
+
+    /**
+     * Src is the source array that starts at index 0
+     * Dest is the (possibly larger) array destination with a possible offset
+     * low is the index in dest to start sorting
+     * high is the end index in dest to end sorting
+     */
+    private static void mergeSort(final int[] refX, final int[] refY,
+                                  final int[] srcX, final int[] dstX,
+                                  final int[] srcY, final int[] dstY,
+                                  final int low, final int high)
+    {
+        final int length = high - low;
+
+        /*
+         * Tuning parameter: list size at or below which insertion sort
+         * will be used in preference to mergesort.
+         */
+        if (length <= INSERTION_SORT_THRESHOLD) {
+            // Insertion sort on smallest arrays
+            dstX[low] = refX[low];
+            dstY[low] = refY[low];
+
+            for (int i = low + 1, j = low, x, y; i < high; j = i++) {
+                x = refX[i];
+                y = refY[i];
+
+                while (dstX[j] > x) {
+                    // swap element
+                    dstX[j + 1] = dstX[j];
+                    dstY[j + 1] = dstY[j];
+                    if (j-- == low) {
+                        break;
+                    }
+                }
+                dstX[j + 1] = x;
+                dstY[j + 1] = y;
+            }
+            return;
+        }
+
+        // Recursively sort halves of dest into src
+
+        // note: use signed shift (not >>>) for performance
+        // as indices are small enough to exceed Integer.MAX_VALUE
+        final int mid = (low + high) >> 1;
+
+        mergeSort(refX, refY, dstX, srcX, dstY, srcY, low, mid);
+        mergeSort(refX, refY, dstX, srcX, dstY, srcY, mid, high);
+
+        // If arrays are inverted ie all(A) > all(B) do swap A and B to dst
+        if (srcX[high - 1] <= srcX[low]) {
+//            System.out.println("mergeSort: inverse ordered");
+            // 1561 occurences
+            final int left = mid - low;
+            final int right = high - mid;
+            final int off = (left != right) ? 1 : 0;
+            // swap parts:
+            System.arraycopy(srcX, low, dstX, mid + off, left);
+            System.arraycopy(srcX, mid, dstX, low, right);
+            System.arraycopy(srcY, low, dstY, mid + off, left);
+            System.arraycopy(srcY, mid, dstY, low, right);
+            return;
+        }
+
+        // If arrays are already sorted, just copy from src to dest.  This is an
+        // optimization that results in faster sorts for nearly ordered lists.
+        if (srcX[mid - 1] <= srcX[mid]) {
+//            System.out.println("mergeSort: ordered");
+            // 14 occurences
+            System.arraycopy(srcX, low, dstX, low, length);
+            System.arraycopy(srcY, low, dstY, low, length);
+            return;
+        }
+
+        // Merge sorted halves (now in src) into dest
+        for (int i = low, p = low, q = mid; i < high; i++) {
+            if ((q >= high) || ((p < mid) && (srcX[p] <= srcX[q]))) {
+                dstX[i] = srcX[p];
+                dstY[i] = srcY[p];
+                p++;
+            } else {
+                dstX[i] = srcX[q];
+                dstY[i] = srcY[q];
+                q++;
+            }
+        }
+    }
+
+    private MergeSort() {
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/OffHeapArray.java b/src/share/classes/sun/java2d/marlin/OffHeapArray.java
new file mode 100644
index 0000000..77b216b
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/OffHeapArray.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2007, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+import static sun.java2d.marlin.MarlinConst.LOG_UNSAFE_MALLOC;
+
+import sun.misc.ThreadGroupUtils;
+import sun.misc.Unsafe;
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Vector;
+
+/**
+ *
+ * @author bourgesl
+ */
+final class OffHeapArray  {
+
+    // unsafe reference
+    static final Unsafe UNSAFE;
+    // size of int / float
+    static final int SIZE_INT;
+
+    // RendererContext reference queue
+    private static final ReferenceQueue<Object> rdrQueue
+        = new ReferenceQueue<Object>();
+    // reference list
+    private static final Vector<OffHeapReference> refList
+        = new Vector<OffHeapReference>(32);
+
+    static {
+        UNSAFE   = Unsafe.getUnsafe();
+        SIZE_INT = Unsafe.ARRAY_INT_INDEX_SCALE;
+
+        // Mimics Java2D Disposer:
+        AccessController.doPrivileged(
+            (PrivilegedAction<Void>) () -> {
+                /*
+                 * The thread must be a member of a thread group
+                 * which will not get GCed before VM exit.
+                 * Make its parent the top-level thread group.
+                 */
+                final ThreadGroup rootTG
+                    = ThreadGroupUtils.getRootThreadGroup();
+                final Thread t = new Thread(rootTG, new OffHeapDisposer(),
+                    "MarlinRenderer Disposer");
+                t.setContextClassLoader(null);
+                t.setDaemon(true);
+                t.setPriority(Thread.MAX_PRIORITY);
+                t.start();
+                return null;
+            }
+        );
+    }
+
+    /* members */
+    long address;
+    long length;
+    int  used;
+
+    OffHeapArray(final Object parent, final long len) {
+        // note: may throw OOME:
+        this.address = UNSAFE.allocateMemory(len);
+        this.length  = len;
+        this.used    = 0;
+        if (LOG_UNSAFE_MALLOC) {
+            MarlinUtils.logInfo(System.currentTimeMillis()
+                                + ": OffHeapArray.allocateMemory = "
+                                + len + " to addr = " + this.address);
+        }
+
+        // Create the phantom reference to ensure freeing off-heap memory:
+        refList.add(new OffHeapReference(parent, this));
+    }
+
+    /*
+     * As realloc may change the address, updating address is MANDATORY
+     * @param len new array length
+     * @throws OutOfMemoryError if the allocation is refused by the system
+     */
+    void resize(final long len) {
+        // note: may throw OOME:
+        this.address = UNSAFE.reallocateMemory(address, len);
+        this.length  = len;
+        if (LOG_UNSAFE_MALLOC) {
+            MarlinUtils.logInfo(System.currentTimeMillis()
+                                + ": OffHeapArray.reallocateMemory = "
+                                + len + " to addr = " + this.address);
+        }
+    }
+
+    void free() {
+        UNSAFE.freeMemory(this.address);
+        if (LOG_UNSAFE_MALLOC) {
+            MarlinUtils.logInfo(System.currentTimeMillis()
+                                + ": OffHeapEdgeArray.free = "
+                                + this.length
+                                + " at addr = " + this.address);
+        }
+    }
+
+    void fill(final byte val) {
+        UNSAFE.setMemory(this.address, this.length, val);
+    }
+
+    static final class OffHeapReference extends PhantomReference<Object> {
+
+        private final OffHeapArray array;
+
+        OffHeapReference(final Object parent, final OffHeapArray edges) {
+            super(parent, rdrQueue);
+            this.array = edges;
+        }
+
+        void dispose() {
+            // free off-heap blocks
+            this.array.free();
+        }
+    }
+
+    static final class OffHeapDisposer implements Runnable {
+        @Override
+        public void run() {
+            final Thread currentThread = Thread.currentThread();
+            OffHeapReference ref;
+
+            // check interrupted:
+            for (; !currentThread.isInterrupted();) {
+                try {
+                    ref = (OffHeapReference)rdrQueue.remove();
+                    ref.dispose();
+
+                    refList.remove(ref);
+
+                } catch (InterruptedException ie) {
+                    MarlinUtils.logException("OffHeapDisposer interrupted:",
+                                             ie);
+                }
+            }
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/Renderer.java b/src/share/classes/sun/java2d/marlin/Renderer.java
new file mode 100644
index 0000000..f8a9c71
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/Renderer.java
@@ -0,0 +1,1558 @@
+/*
+ * Copyright (c) 2007, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+import java.util.Arrays;
+import sun.awt.geom.PathConsumer2D;
+import static sun.java2d.marlin.OffHeapArray.SIZE_INT;
+import sun.misc.Unsafe;
+
+final class Renderer implements PathConsumer2D, MarlinConst {
+
+    static final boolean DISABLE_RENDER = false;
+
+    static final boolean ENABLE_BLOCK_FLAGS = MarlinProperties.isUseTileFlags();
+    static final boolean ENABLE_BLOCK_FLAGS_HEURISTICS = MarlinProperties.isUseTileFlagsWithHeuristics();
+
+    private static final int ALL_BUT_LSB = 0xfffffffe;
+    private static final int ERR_STEP_MAX = 0x7fffffff; // = 2^31 - 1
+
+    private static final double POWER_2_TO_32 = 0x1.0p32;
+
+    // use float to make tosubpix methods faster (no int to float conversion)
+    public static final float f_SUBPIXEL_POSITIONS_X
+        = (float) SUBPIXEL_POSITIONS_X;
+    public static final float f_SUBPIXEL_POSITIONS_Y
+        = (float) SUBPIXEL_POSITIONS_Y;
+    public static final int SUBPIXEL_MASK_X = SUBPIXEL_POSITIONS_X - 1;
+    public static final int SUBPIXEL_MASK_Y = SUBPIXEL_POSITIONS_Y - 1;
+
+    // number of subpixels corresponding to a tile line
+    private static final int SUBPIXEL_TILE
+        = TILE_SIZE << SUBPIXEL_LG_POSITIONS_Y;
+
+    // 2048 (pixelSize) pixels (height) x 8 subpixels = 64K
+    static final int INITIAL_BUCKET_ARRAY
+        = INITIAL_PIXEL_DIM * SUBPIXEL_POSITIONS_Y;
+
+    public static final int WIND_EVEN_ODD = 0;
+    public static final int WIND_NON_ZERO = 1;
+
+    // common to all types of input path segments.
+    // OFFSET as bytes
+    // only integer values:
+    public static final long OFF_CURX_OR  = 0;
+    public static final long OFF_ERROR    = OFF_CURX_OR  + SIZE_INT;
+    public static final long OFF_BUMP_X   = OFF_ERROR    + SIZE_INT;
+    public static final long OFF_BUMP_ERR = OFF_BUMP_X   + SIZE_INT;
+    public static final long OFF_NEXT     = OFF_BUMP_ERR + SIZE_INT;
+    public static final long OFF_YMAX     = OFF_NEXT     + SIZE_INT;
+
+    // size of one edge in bytes
+    public static final int SIZEOF_EDGE_BYTES = (int)(OFF_YMAX + SIZE_INT);
+
+    // curve break into lines
+    // cubic error in subpixels to decrement step
+    private static final float CUB_DEC_ERR_SUBPIX
+        = 2.5f * (NORM_SUBPIXELS / 8f); // 2.5 subpixel for typical 8x8 subpixels
+    // cubic error in subpixels to increment step
+    private static final float CUB_INC_ERR_SUBPIX
+        = 1f * (NORM_SUBPIXELS / 8f); // 1 subpixel for typical 8x8 subpixels
+
+    // cubic bind length to decrement step = 8 * error in subpixels
+    // pisces: 20 / 8
+    // openjfx pisces: 8 / 3.2
+    // multiply by 8 = error scale factor:
+    public static final float CUB_DEC_BND
+        = 8f * CUB_DEC_ERR_SUBPIX; // 20f means 2.5 subpixel error
+    // cubic bind length to increment step = 8 * error in subpixels
+    public static final float CUB_INC_BND
+        = 8f * CUB_INC_ERR_SUBPIX; // 8f means 1 subpixel error
+
+    // cubic countlg
+    public static final int CUB_COUNT_LG = 2;
+    // cubic count = 2^countlg
+    private static final int CUB_COUNT = 1 << CUB_COUNT_LG;
+    // cubic count^2 = 4^countlg
+    private static final int CUB_COUNT_2 = 1 << (2 * CUB_COUNT_LG);
+    // cubic count^3 = 8^countlg
+    private static final int CUB_COUNT_3 = 1 << (3 * CUB_COUNT_LG);
+    // cubic dt = 1 / count
+    private static final float CUB_INV_COUNT = 1f / CUB_COUNT;
+    // cubic dt^2 = 1 / count^2 = 1 / 4^countlg
+    private static final float CUB_INV_COUNT_2 = 1f / CUB_COUNT_2;
+    // cubic dt^3 = 1 / count^3 = 1 / 8^countlg
+    private static final float CUB_INV_COUNT_3 = 1f / CUB_COUNT_3;
+
+    // quad break into lines
+    // quadratic error in subpixels
+    private static final float QUAD_DEC_ERR_SUBPIX
+        = 1f * (NORM_SUBPIXELS / 8f); // 1 subpixel for typical 8x8 subpixels
+
+    // quadratic bind length to decrement step = 8 * error in subpixels
+    // pisces and openjfx pisces: 32
+    public static final float QUAD_DEC_BND
+        = 8f * QUAD_DEC_ERR_SUBPIX; // 8f means 1 subpixel error
+
+//////////////////////////////////////////////////////////////////////////////
+//  SCAN LINE
+//////////////////////////////////////////////////////////////////////////////
+    // crossings ie subpixel edge x coordinates
+    private int[] crossings;
+    // auxiliary storage for crossings (merge sort)
+    private int[] aux_crossings;
+
+    // indices into the segment pointer lists. They indicate the "active"
+    // sublist in the segment lists (the portion of the list that contains
+    // all the segments that cross the next scan line).
+    private int edgeCount;
+    private int[] edgePtrs;
+    // auxiliary storage for edge pointers (merge sort)
+    private int[] aux_edgePtrs;
+
+    // max used for both edgePtrs and crossings (stats only)
+    private int activeEdgeMaxUsed;
+
+    // per-thread initial arrays (large enough to satisfy most usages) (1024)
+    private final int[] crossings_initial = new int[INITIAL_SMALL_ARRAY]; // 4K
+    // +1 to avoid recycling in Helpers.widenArray()
+    private final int[] edgePtrs_initial  = new int[INITIAL_SMALL_ARRAY + 1]; // 4K
+    // merge sort initial arrays (large enough to satisfy most usages) (1024)
+    private final int[] aux_crossings_initial = new int[INITIAL_SMALL_ARRAY]; // 4K
+    // +1 to avoid recycling in Helpers.widenArray()
+    private final int[] aux_edgePtrs_initial  = new int[INITIAL_SMALL_ARRAY + 1]; // 4K
+
+//////////////////////////////////////////////////////////////////////////////
+//  EDGE LIST
+//////////////////////////////////////////////////////////////////////////////
+    private int edgeMinY = Integer.MAX_VALUE;
+    private int edgeMaxY = Integer.MIN_VALUE;
+    private float edgeMinX = Float.POSITIVE_INFINITY;
+    private float edgeMaxX = Float.NEGATIVE_INFINITY;
+
+    // edges [floats|ints] stored in off-heap memory
+    private final OffHeapArray edges;
+
+    private int[] edgeBuckets;
+    private int[] edgeBucketCounts; // 2*newedges + (1 if pruning needed)
+    // used range for edgeBuckets / edgeBucketCounts
+    private int buckets_minY;
+    private int buckets_maxY;
+    // sum of each edge delta Y (subpixels)
+    private int edgeSumDeltaY;
+
+    // +1 to avoid recycling in Helpers.widenArray()
+    private final int[] edgeBuckets_initial
+        = new int[INITIAL_BUCKET_ARRAY + 1]; // 64K
+    private final int[] edgeBucketCounts_initial
+        = new int[INITIAL_BUCKET_ARRAY + 1]; // 64K
+
+    // Flattens using adaptive forward differencing. This only carries out
+    // one iteration of the AFD loop. All it does is update AFD variables (i.e.
+    // X0, Y0, D*[X|Y], COUNT; not variables used for computing scanline crossings).
+    private void quadBreakIntoLinesAndAdd(float x0, float y0,
+                                          final Curve c,
+                                          final float x2, final float y2)
+    {
+        int count = 1; // dt = 1 / count
+
+        // maximum(ddX|Y) = norm(dbx, dby) * dt^2 (= 1)
+        float maxDD = FloatMath.max(Math.abs(c.dbx), Math.abs(c.dby));
+
+        final float _DEC_BND = QUAD_DEC_BND;
+
+        while (maxDD >= _DEC_BND) {
+            // divide step by half:
+            maxDD /= 4f; // error divided by 2^2 = 4
+
+            count <<= 1;
+            if (DO_STATS) {
+                rdrCtx.stats.stat_rdr_quadBreak_dec.add(count);
+            }
+        }
+
+        int nL = 0; // line count
+        if (count > 1) {
+            final float icount = 1f / count; // dt
+            final float icount2 = icount * icount; // dt^2
+
+            final float ddx = c.dbx * icount2;
+            final float ddy = c.dby * icount2;
+            float dx = c.bx * icount2 + c.cx * icount;
+            float dy = c.by * icount2 + c.cy * icount;
+
+            float x1, y1;
+
+            while (--count > 0) {
+                x1 = x0 + dx;
+                dx += ddx;
+                y1 = y0 + dy;
+                dy += ddy;
+
+                addLine(x0, y0, x1, y1);
+
+                if (DO_STATS) { nL++; }
+                x0 = x1;
+                y0 = y1;
+            }
+        }
+        addLine(x0, y0, x2, y2);
+
+        if (DO_STATS) {
+            rdrCtx.stats.stat_rdr_quadBreak.add(nL + 1);
+        }
+    }
+
+    // x0, y0 and x3,y3 are the endpoints of the curve. We could compute these
+    // using c.xat(0),c.yat(0) and c.xat(1),c.yat(1), but this might introduce
+    // numerical errors, and our callers already have the exact values.
+    // Another alternative would be to pass all the control points, and call
+    // c.set here, but then too many numbers are passed around.
+    private void curveBreakIntoLinesAndAdd(float x0, float y0,
+                                           final Curve c,
+                                           final float x3, final float y3)
+    {
+        int count           = CUB_COUNT;
+        final float icount  = CUB_INV_COUNT;   // dt
+        final float icount2 = CUB_INV_COUNT_2; // dt^2
+        final float icount3 = CUB_INV_COUNT_3; // dt^3
+
+        // the dx and dy refer to forward differencing variables, not the last
+        // coefficients of the "points" polynomial
+        float dddx, dddy, ddx, ddy, dx, dy;
+        dddx = 2f * c.dax * icount3;
+        dddy = 2f * c.day * icount3;
+        ddx = dddx + c.dbx * icount2;
+        ddy = dddy + c.dby * icount2;
+        dx = c.ax * icount3 + c.bx * icount2 + c.cx * icount;
+        dy = c.ay * icount3 + c.by * icount2 + c.cy * icount;
+
+        // we use x0, y0 to walk the line
+        float x1 = x0, y1 = y0;
+        int nL = 0; // line count
+
+        final float _DEC_BND = CUB_DEC_BND;
+        final float _INC_BND = CUB_INC_BND;
+
+        while (count > 0) {
+            // divide step by half:
+            while (Math.abs(ddx) >= _DEC_BND || Math.abs(ddy) >= _DEC_BND) {
+                dddx /= 8f;
+                dddy /= 8f;
+                ddx = ddx/4f - dddx;
+                ddy = ddy/4f - dddy;
+                dx = (dx - ddx) / 2f;
+                dy = (dy - ddy) / 2f;
+
+                count <<= 1;
+                if (DO_STATS) {
+                    rdrCtx.stats.stat_rdr_curveBreak_dec.add(count);
+                }
+            }
+
+            // double step:
+            // TODO: why use first derivative dX|Y instead of second ddX|Y ?
+            // both scale changes should use speed or acceleration to have the same metric.
+
+            // can only do this on even "count" values, because we must divide count by 2
+            while (count % 2 == 0
+                   && Math.abs(dx) <= _INC_BND && Math.abs(dy) <= _INC_BND)
+            {
+                dx = 2f * dx + ddx;
+                dy = 2f * dy + ddy;
+                ddx = 4f * (ddx + dddx);
+                ddy = 4f * (ddy + dddy);
+                dddx *= 8f;
+                dddy *= 8f;
+
+                count >>= 1;
+                if (DO_STATS) {
+                    rdrCtx.stats.stat_rdr_curveBreak_inc.add(count);
+                }
+            }
+            if (--count > 0) {
+                x1 += dx;
+                dx += ddx;
+                ddx += dddx;
+                y1 += dy;
+                dy += ddy;
+                ddy += dddy;
+            } else {
+                x1 = x3;
+                y1 = y3;
+            }
+
+            addLine(x0, y0, x1, y1);
+
+            if (DO_STATS) { nL++; }
+            x0 = x1;
+            y0 = y1;
+        }
+        if (DO_STATS) {
+            rdrCtx.stats.stat_rdr_curveBreak.add(nL);
+        }
+    }
+
+    private void addLine(float x1, float y1, float x2, float y2) {
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_addLine.start();
+        }
+        if (DO_STATS) {
+            rdrCtx.stats.stat_rdr_addLine.add(1);
+        }
+        int or = 1; // orientation of the line. 1 if y increases, 0 otherwise.
+        if (y2 < y1) {
+            or = 0;
+            float tmp = y2;
+            y2 = y1;
+            y1 = tmp;
+            tmp = x2;
+            x2 = x1;
+            x1 = tmp;
+        }
+
+        // convert subpixel coordinates (float) into pixel positions (int)
+
+        // The index of the pixel that holds the next HPC is at ceil(trueY - 0.5)
+        // Since y1 and y2 are biased by -0.5 in tosubpixy(), this is simply
+        // ceil(y1) or ceil(y2)
+        // upper integer (inclusive)
+        final int firstCrossing = FloatMath.max(FloatMath.ceil_int(y1), boundsMinY);
+
+        // note: use boundsMaxY (last Y exclusive) to compute correct coverage
+        // upper integer (exclusive)
+        final int lastCrossing  = FloatMath.min(FloatMath.ceil_int(y2), boundsMaxY);
+
+        /* skip horizontal lines in pixel space and clip edges
+           out of y range [boundsMinY; boundsMaxY] */
+        if (firstCrossing >= lastCrossing) {
+            if (DO_MONITORS) {
+                rdrCtx.stats.mon_rdr_addLine.stop();
+            }
+            if (DO_STATS) {
+                rdrCtx.stats.stat_rdr_addLine_skip.add(1);
+            }
+            return;
+        }
+
+        // edge min/max X/Y are in subpixel space (inclusive) within bounds:
+        // note: Use integer crossings to ensure consistent range within
+        // edgeBuckets / edgeBucketCounts arrays in case of NaN values (int = 0)
+        if (firstCrossing < edgeMinY) {
+            edgeMinY = firstCrossing;
+        }
+        if (lastCrossing > edgeMaxY) {
+            edgeMaxY = lastCrossing;
+        }
+
+        // Use double-precision for improved accuracy:
+        final double x1d   = x1;
+        final double y1d   = y1;
+        final double slope = (x1d - x2) / (y1d - y2);
+
+        if (slope >= 0.0) { // <==> x1 < x2
+            if (x1 < edgeMinX) {
+                edgeMinX = x1;
+            }
+            if (x2 > edgeMaxX) {
+                edgeMaxX = x2;
+            }
+        } else {
+            if (x2 < edgeMinX) {
+                edgeMinX = x2;
+            }
+            if (x1 > edgeMaxX) {
+                edgeMaxX = x1;
+            }
+        }
+
+        // local variables for performance:
+        final int _SIZEOF_EDGE_BYTES = SIZEOF_EDGE_BYTES;
+
+        final OffHeapArray _edges = edges;
+
+        // get free pointer (ie length in bytes)
+        final int edgePtr = _edges.used;
+
+        // use substraction to avoid integer overflow:
+        if (_edges.length - edgePtr < _SIZEOF_EDGE_BYTES) {
+            // suppose _edges.length > _SIZEOF_EDGE_BYTES
+            // so doubling size is enough to add needed bytes
+            // note: throw IOOB if neededSize > 2Gb:
+            final long edgeNewSize = ArrayCache.getNewLargeSize(_edges.length,
+                                        edgePtr + _SIZEOF_EDGE_BYTES);
+
+            if (DO_STATS) {
+                rdrCtx.stats.stat_rdr_edges_resizes.add(edgeNewSize);
+            }
+            _edges.resize(edgeNewSize);
+        }
+
+
+        final Unsafe _unsafe = OffHeapArray.UNSAFE;
+        final long SIZE_INT = 4L;
+        long addr   = _edges.address + edgePtr;
+
+        // The x value must be bumped up to its position at the next HPC we will evaluate.
+        // "firstcrossing" is the (sub)pixel number where the next crossing occurs
+        // thus, the actual coordinate of the next HPC is "firstcrossing + 0.5"
+        // so the Y distance we cover is "firstcrossing + 0.5 - trueY".
+        // Note that since y1 (and y2) are already biased by -0.5 in tosubpixy(), we have
+        // y1 = trueY - 0.5
+        // trueY = y1 + 0.5
+        // firstcrossing + 0.5 - trueY = firstcrossing + 0.5 - (y1 + 0.5)
+        //                             = firstcrossing - y1
+        // The x coordinate at that HPC is then:
+        // x1_intercept = x1 + (firstcrossing - y1) * slope
+        // The next VPC is then given by:
+        // VPC index = ceil(x1_intercept - 0.5), or alternately
+        // VPC index = floor(x1_intercept - 0.5 + 1 - epsilon)
+        // epsilon is hard to pin down in floating point, but easy in fixed point, so if
+        // we convert to fixed point then these operations get easier:
+        // long x1_fixed = x1_intercept * 2^32;  (fixed point 32.32 format)
+        // curx = next VPC = fixed_floor(x1_fixed - 2^31 + 2^32 - 1)
+        //                 = fixed_floor(x1_fixed + 2^31 - 1)
+        //                 = fixed_floor(x1_fixed + 0x7fffffff)
+        // and error       = fixed_fract(x1_fixed + 0x7fffffff)
+        final double x1_intercept = x1d + (firstCrossing - y1d) * slope;
+
+        // inlined scalb(x1_intercept, 32):
+        final long x1_fixed_biased = ((long) (POWER_2_TO_32 * x1_intercept))
+                                     + 0x7fffffffL;
+        // curx:
+        // last bit corresponds to the orientation
+        _unsafe.putInt(addr, (((int) (x1_fixed_biased >> 31L)) & ALL_BUT_LSB) | or);
+        addr += SIZE_INT;
+        _unsafe.putInt(addr,  ((int)  x1_fixed_biased) >>> 1);
+        addr += SIZE_INT;
+
+        // inlined scalb(slope, 32):
+        final long slope_fixed = (long) (POWER_2_TO_32 * slope);
+
+        // last bit set to 0 to keep orientation:
+        _unsafe.putInt(addr, (((int) (slope_fixed >> 31L)) & ALL_BUT_LSB));
+        addr += SIZE_INT;
+        _unsafe.putInt(addr,  ((int)  slope_fixed) >>> 1);
+        addr += SIZE_INT;
+
+        final int[] _edgeBuckets      = edgeBuckets;
+        final int[] _edgeBucketCounts = edgeBucketCounts;
+
+        final int _boundsMinY = boundsMinY;
+
+        // each bucket is a linked list. this method adds ptr to the
+        // start of the "bucket"th linked list.
+        final int bucketIdx = firstCrossing - _boundsMinY;
+
+        // pointer from bucket
+        _unsafe.putInt(addr, _edgeBuckets[bucketIdx]);
+        addr += SIZE_INT;
+        // y max (inclusive)
+        _unsafe.putInt(addr,  lastCrossing);
+
+        // Update buckets:
+        // directly the edge struct "pointer"
+        _edgeBuckets[bucketIdx]       = edgePtr;
+        _edgeBucketCounts[bucketIdx] += 2; // 1 << 1
+        // last bit means edge end
+        _edgeBucketCounts[lastCrossing - _boundsMinY] |= 0x1;
+
+        // update sum of delta Y (subpixels):
+        edgeSumDeltaY += (lastCrossing - firstCrossing);
+
+        // update free pointer (ie length in bytes)
+        _edges.used += _SIZEOF_EDGE_BYTES;
+
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_addLine.stop();
+        }
+    }
+
+// END EDGE LIST
+//////////////////////////////////////////////////////////////////////////////
+
+    // Cache to store RLE-encoded coverage mask of the current primitive
+    final MarlinCache cache;
+
+    // Bounds of the drawing region, at subpixel precision.
+    private int boundsMinX, boundsMinY, boundsMaxX, boundsMaxY;
+
+    // Current winding rule
+    private int windingRule;
+
+    // Current drawing position, i.e., final point of last segment
+    private float x0, y0;
+
+    // Position of most recent 'moveTo' command
+    private float sx0, sy0;
+
+    // per-thread renderer context
+    final RendererContext rdrCtx;
+    // dirty curve
+    private final Curve curve;
+
+    Renderer(final RendererContext rdrCtx) {
+        this.rdrCtx = rdrCtx;
+
+        this.edges = new OffHeapArray(rdrCtx.cleanerObj, INITIAL_EDGES_CAPACITY); // 96K
+
+        this.curve = rdrCtx.curve;
+
+        edgeBuckets = edgeBuckets_initial;
+        edgeBucketCounts = edgeBucketCounts_initial;
+
+        alphaLine  = alphaLine_initial;
+
+        this.cache = rdrCtx.cache;
+
+        // ScanLine:
+        crossings     = crossings_initial;
+        aux_crossings = aux_crossings_initial;
+        edgePtrs      = edgePtrs_initial;
+        aux_edgePtrs  = aux_edgePtrs_initial;
+
+        edgeCount = 0;
+        activeEdgeMaxUsed = 0;
+    }
+
+    Renderer init(final int pix_boundsX, final int pix_boundsY,
+                  final int pix_boundsWidth, final int pix_boundsHeight,
+                  final int windingRule) {
+
+        this.windingRule = windingRule;
+
+        // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
+        this.boundsMinX =  pix_boundsX << SUBPIXEL_LG_POSITIONS_X;
+        this.boundsMaxX =
+            (pix_boundsX + pix_boundsWidth) << SUBPIXEL_LG_POSITIONS_X;
+        this.boundsMinY =  pix_boundsY << SUBPIXEL_LG_POSITIONS_Y;
+        this.boundsMaxY =
+            (pix_boundsY + pix_boundsHeight) << SUBPIXEL_LG_POSITIONS_Y;
+
+        if (DO_LOG_BOUNDS) {
+            MarlinUtils.logInfo("boundsXY = [" + boundsMinX + " ... "
+                                + boundsMaxX + "[ [" + boundsMinY + " ... "
+                                + boundsMaxY + "[");
+        }
+
+        // see addLine: ceil(boundsMaxY) => boundsMaxY + 1
+        // +1 for edgeBucketCounts
+        final int edgeBucketsLength = (boundsMaxY - boundsMinY) + 1;
+
+        if (edgeBucketsLength > INITIAL_BUCKET_ARRAY) {
+            if (DO_STATS) {
+                rdrCtx.stats.stat_array_renderer_edgeBuckets
+                    .add(edgeBucketsLength);
+                rdrCtx.stats.stat_array_renderer_edgeBucketCounts
+                    .add(edgeBucketsLength);
+            }
+            edgeBuckets = rdrCtx.getIntArray(edgeBucketsLength);
+            edgeBucketCounts = rdrCtx.getIntArray(edgeBucketsLength);
+        }
+
+        edgeMinY = Integer.MAX_VALUE;
+        edgeMaxY = Integer.MIN_VALUE;
+        edgeMinX = Float.POSITIVE_INFINITY;
+        edgeMaxX = Float.NEGATIVE_INFINITY;
+
+        // reset used mark:
+        edgeCount = 0;
+        activeEdgeMaxUsed = 0;
+        edges.used = 0;
+
+        edgeSumDeltaY = 0;
+
+        return this; // fluent API
+    }
+
+    /**
+     * Disposes this renderer and recycle it clean up before reusing this instance
+     */
+    void dispose() {
+        if (DO_STATS) {
+            rdrCtx.stats.stat_rdr_activeEdges.add(activeEdgeMaxUsed);
+            rdrCtx.stats.stat_rdr_edges.add(edges.used);
+            rdrCtx.stats.stat_rdr_edges_count
+                .add(edges.used / SIZEOF_EDGE_BYTES);
+        }
+        if (DO_CLEAN_DIRTY) {
+            // Force zero-fill dirty arrays:
+            Arrays.fill(crossings,     0);
+            Arrays.fill(aux_crossings, 0);
+            Arrays.fill(edgePtrs,      0);
+            Arrays.fill(aux_edgePtrs,  0);
+        }
+        // Return arrays:
+        if (crossings != crossings_initial) {
+            rdrCtx.putDirtyIntArray(crossings);
+            crossings = crossings_initial;
+            if (aux_crossings != aux_crossings_initial) {
+                rdrCtx.putDirtyIntArray(aux_crossings);
+                aux_crossings = aux_crossings_initial;
+            }
+        }
+        if (edgePtrs != edgePtrs_initial) {
+            rdrCtx.putDirtyIntArray(edgePtrs);
+            edgePtrs = edgePtrs_initial;
+            if (aux_edgePtrs != aux_edgePtrs_initial) {
+                rdrCtx.putDirtyIntArray(aux_edgePtrs);
+                aux_edgePtrs = aux_edgePtrs_initial;
+            }
+        }
+        if (alphaLine != alphaLine_initial) {
+            rdrCtx.putIntArray(alphaLine, 0, 0); // already zero filled
+            alphaLine = alphaLine_initial;
+        }
+        if (blkFlags != blkFlags_initial) {
+            rdrCtx.putIntArray(blkFlags, 0, 0); // already zero filled
+            blkFlags = blkFlags_initial;
+        }
+
+        if (edgeMinY != Integer.MAX_VALUE) {
+            // if context is maked as DIRTY:
+            if (rdrCtx.dirty) {
+                // may happen if an exception if thrown in the pipeline processing:
+                // clear completely buckets arrays:
+                buckets_minY = 0;
+                buckets_maxY = boundsMaxY - boundsMinY;
+            }
+            // clear used part
+            if (edgeBuckets == edgeBuckets_initial) {
+                // fill only used part
+                IntArrayCache.fill(edgeBuckets,      buckets_minY,
+                                                     buckets_maxY,     0);
+                IntArrayCache.fill(edgeBucketCounts, buckets_minY,
+                                                     buckets_maxY + 1, 0);
+            } else {
+                 // clear only used part
+                rdrCtx.putIntArray(edgeBuckets,      buckets_minY,
+                                                     buckets_maxY);
+                edgeBuckets = edgeBuckets_initial;
+
+                rdrCtx.putIntArray(edgeBucketCounts, buckets_minY,
+                                                     buckets_maxY + 1);
+                edgeBucketCounts = edgeBucketCounts_initial;
+            }
+        } else if (edgeBuckets != edgeBuckets_initial) {
+            // unused arrays
+            rdrCtx.putIntArray(edgeBuckets, 0, 0);
+            edgeBuckets = edgeBuckets_initial;
+
+            rdrCtx.putIntArray(edgeBucketCounts, 0, 0);
+            edgeBucketCounts = edgeBucketCounts_initial;
+        }
+
+        // At last: resize back off-heap edges to initial size
+        if (edges.length != INITIAL_EDGES_CAPACITY) {
+            // note: may throw OOME:
+            edges.resize(INITIAL_EDGES_CAPACITY);
+        }
+        if (DO_CLEAN_DIRTY) {
+            // Force zero-fill dirty arrays:
+            edges.fill(BYTE_0);
+        }
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_endRendering.stop();
+        }
+    }
+
+    private static float tosubpixx(final float pix_x) {
+        return f_SUBPIXEL_POSITIONS_X * pix_x;
+    }
+
+    private static float tosubpixy(final float pix_y) {
+        // shift y by -0.5 for fast ceil(y - 0.5):
+        return f_SUBPIXEL_POSITIONS_Y * pix_y - 0.5f;
+    }
+
+    @Override
+    public void moveTo(float pix_x0, float pix_y0) {
+        closePath();
+        final float sx = tosubpixx(pix_x0);
+        final float sy = tosubpixy(pix_y0);
+        this.sx0 = sx;
+        this.sy0 = sy;
+        this.x0 = sx;
+        this.y0 = sy;
+    }
+
+    @Override
+    public void lineTo(float pix_x1, float pix_y1) {
+        final float x1 = tosubpixx(pix_x1);
+        final float y1 = tosubpixy(pix_y1);
+        addLine(x0, y0, x1, y1);
+        x0 = x1;
+        y0 = y1;
+    }
+
+    @Override
+    public void curveTo(float x1, float y1,
+            float x2, float y2,
+            float x3, float y3)
+    {
+        final float xe = tosubpixx(x3);
+        final float ye = tosubpixy(y3);
+        curve.set(x0, y0, tosubpixx(x1), tosubpixy(y1),
+                          tosubpixx(x2), tosubpixy(y2), xe, ye);
+        curveBreakIntoLinesAndAdd(x0, y0, curve, xe, ye);
+        x0 = xe;
+        y0 = ye;
+    }
+
+    @Override
+    public void quadTo(float x1, float y1, float x2, float y2) {
+        final float xe = tosubpixx(x2);
+        final float ye = tosubpixy(y2);
+        curve.set(x0, y0, tosubpixx(x1), tosubpixy(y1), xe, ye);
+        quadBreakIntoLinesAndAdd(x0, y0, curve, xe, ye);
+        x0 = xe;
+        y0 = ye;
+    }
+
+    @Override
+    public void closePath() {
+        addLine(x0, y0, sx0, sy0);
+        x0 = sx0;
+        y0 = sy0;
+    }
+
+    @Override
+    public void pathDone() {
+        closePath();
+    }
+
+    @Override
+    public long getNativeConsumer() {
+        throw new InternalError("Renderer does not use a native consumer.");
+    }
+
+    // clean alpha array (zero filled)
+    private int[] alphaLine;
+    // 2048 (pixelsize) pixel large
+    private final int[] alphaLine_initial = new int[INITIAL_AA_ARRAY]; // 8K
+
+    private void _endRendering(final int ymin, final int ymax) {
+        if (DISABLE_RENDER) {
+            return;
+        }
+
+        // Get X bounds as true pixel boundaries to compute correct pixel coverage:
+        final int bboxx0 = bbox_spminX;
+        final int bboxx1 = bbox_spmaxX;
+
+        final boolean windingRuleEvenOdd = (windingRule == WIND_EVEN_ODD);
+
+        // Useful when processing tile line by tile line
+        final int[] _alpha = alphaLine;
+
+        // local vars (performance):
+        final MarlinCache _cache = cache;
+        final OffHeapArray _edges = edges;
+        final int[] _edgeBuckets = edgeBuckets;
+        final int[] _edgeBucketCounts = edgeBucketCounts;
+
+        int[] _crossings = this.crossings;
+        int[] _edgePtrs  = this.edgePtrs;
+
+        // merge sort auxiliary storage:
+        int[] _aux_crossings = this.aux_crossings;
+        int[] _aux_edgePtrs  = this.aux_edgePtrs;
+
+        // copy constants:
+        final long _OFF_ERROR    = OFF_ERROR;
+        final long _OFF_BUMP_X   = OFF_BUMP_X;
+        final long _OFF_BUMP_ERR = OFF_BUMP_ERR;
+
+        final long _OFF_NEXT     = OFF_NEXT;
+        final long _OFF_YMAX     = OFF_YMAX;
+
+        final int _ALL_BUT_LSB   = ALL_BUT_LSB;
+        final int _ERR_STEP_MAX  = ERR_STEP_MAX;
+
+        // unsafe I/O:
+        final Unsafe _unsafe = OffHeapArray.UNSAFE;
+        final long    addr0  = _edges.address;
+        long addr;
+        final int _SUBPIXEL_LG_POSITIONS_X = SUBPIXEL_LG_POSITIONS_X;
+        final int _SUBPIXEL_LG_POSITIONS_Y = SUBPIXEL_LG_POSITIONS_Y;
+        final int _SUBPIXEL_MASK_X = SUBPIXEL_MASK_X;
+        final int _SUBPIXEL_MASK_Y = SUBPIXEL_MASK_Y;
+        final int _SUBPIXEL_POSITIONS_X = SUBPIXEL_POSITIONS_X;
+
+        final int _MIN_VALUE = Integer.MIN_VALUE;
+        final int _MAX_VALUE = Integer.MAX_VALUE;
+
+        // Now we iterate through the scanlines. We must tell emitRow the coord
+        // of the first non-transparent pixel, so we must keep accumulators for
+        // the first and last pixels of the section of the current pixel row
+        // that we will emit.
+        // We also need to accumulate pix_bbox, but the iterator does it
+        // for us. We will just get the values from it once this loop is done
+        int minX = _MAX_VALUE;
+        int maxX = _MIN_VALUE;
+
+        int y = ymin;
+        int bucket = y - boundsMinY;
+
+        int numCrossings = this.edgeCount;
+        int edgePtrsLen = _edgePtrs.length;
+        int crossingsLen = _crossings.length;
+        int _arrayMaxUsed = activeEdgeMaxUsed;
+        int ptrLen = 0, newCount, ptrEnd;
+
+        int bucketcount, i, j, ecur;
+        int cross, lastCross;
+        int x0, x1, tmp, sum, prev, curx, curxo, crorientation, err;
+        int pix_x, pix_xmaxm1, pix_xmax;
+
+        int low, high, mid, prevNumCrossings;
+        boolean useBinarySearch;
+
+        final int[] _blkFlags = blkFlags;
+        final int _BLK_SIZE_LG = BLOCK_SIZE_LG;
+        final int _BLK_SIZE = BLOCK_SIZE;
+
+        final boolean _enableBlkFlagsHeuristics = ENABLE_BLOCK_FLAGS_HEURISTICS && this.enableBlkFlags;
+
+        // Use block flags if large pixel span and few crossings:
+        // ie mean(distance between crossings) is high
+        boolean useBlkFlags = this.prevUseBlkFlags;
+
+        final int stroking = rdrCtx.stroking;
+
+        int lastY = -1; // last emited row
+
+
+        // Iteration on scanlines
+        for (; y < ymax; y++, bucket++) {
+            // --- from former ScanLineIterator.next()
+            bucketcount = _edgeBucketCounts[bucket];
+
+            // marker on previously sorted edges:
+            prevNumCrossings = numCrossings;
+
+            // bucketCount indicates new edge / edge end:
+            if (bucketcount != 0) {
+                if (DO_STATS) {
+                    rdrCtx.stats.stat_rdr_activeEdges_updates
+                        .add(numCrossings);
+                }
+
+                // last bit set to 1 means that edges ends
+                if ((bucketcount & 0x1) != 0) {
+                    // eviction in active edge list
+                    // cache edges[] address + offset
+                    addr = addr0 + _OFF_YMAX;
+
+                    for (i = 0, newCount = 0; i < numCrossings; i++) {
+                        // get the pointer to the edge
+                        ecur = _edgePtrs[i];
+                        // random access so use unsafe:
+                        if (_unsafe.getInt(addr + ecur) > y) {
+                            _edgePtrs[newCount++] = ecur;
+                        }
+                    }
+                    // update marker on sorted edges minus removed edges:
+                    prevNumCrossings = numCrossings = newCount;
+                }
+
+                ptrLen = bucketcount >> 1; // number of new edge
+
+                if (ptrLen != 0) {
+                    if (DO_STATS) {
+                        rdrCtx.stats.stat_rdr_activeEdges_adds
+                            .add(ptrLen);
+                        if (ptrLen > 10) {
+                            rdrCtx.stats.stat_rdr_activeEdges_adds_high
+                                .add(ptrLen);
+                        }
+                    }
+                    ptrEnd = numCrossings + ptrLen;
+
+                    if (edgePtrsLen < ptrEnd) {
+                        if (DO_STATS) {
+                            rdrCtx.stats.stat_array_renderer_edgePtrs
+                                .add(ptrEnd);
+                        }
+                        this.edgePtrs = _edgePtrs
+                            = rdrCtx.widenDirtyIntArray(_edgePtrs, numCrossings,
+                                                        ptrEnd);
+
+                        edgePtrsLen = _edgePtrs.length;
+                        // Get larger auxiliary storage:
+                        if (_aux_edgePtrs != aux_edgePtrs_initial) {
+                            rdrCtx.putDirtyIntArray(_aux_edgePtrs);
+                        }
+                        // use ArrayCache.getNewSize() to use the same growing
+                        // factor than widenDirtyIntArray():
+                        if (DO_STATS) {
+                            rdrCtx.stats.stat_array_renderer_aux_edgePtrs
+                                .add(ptrEnd);
+                        }
+                        this.aux_edgePtrs = _aux_edgePtrs
+                            = rdrCtx.getDirtyIntArray(
+                                ArrayCache.getNewSize(numCrossings, ptrEnd)
+                            );
+                    }
+
+                    // cache edges[] address + offset
+                    addr = addr0 + _OFF_NEXT;
+
+                    // add new edges to active edge list:
+                    for (ecur = _edgeBuckets[bucket];
+                         numCrossings < ptrEnd; numCrossings++)
+                    {
+                        // store the pointer to the edge
+                        _edgePtrs[numCrossings] = ecur;
+                        // random access so use unsafe:
+                        ecur = _unsafe.getInt(addr + ecur);
+                    }
+
+                    if (crossingsLen < numCrossings) {
+                        // Get larger array:
+                        if (_crossings != crossings_initial) {
+                            rdrCtx.putDirtyIntArray(_crossings);
+                        }
+                        if (DO_STATS) {
+                            rdrCtx.stats.stat_array_renderer_crossings
+                                .add(numCrossings);
+                        }
+                        this.crossings = _crossings
+                            = rdrCtx.getDirtyIntArray(numCrossings);
+
+                        // Get larger auxiliary storage:
+                        if (_aux_crossings != aux_crossings_initial) {
+                            rdrCtx.putDirtyIntArray(_aux_crossings);
+                        }
+                        if (DO_STATS) {
+                            rdrCtx.stats.stat_array_renderer_aux_crossings
+                                .add(numCrossings);
+                        }
+                        this.aux_crossings = _aux_crossings
+                            = rdrCtx.getDirtyIntArray(numCrossings);
+
+                        crossingsLen = _crossings.length;
+                    }
+                    if (DO_STATS) {
+                        // update max used mark
+                        if (numCrossings > _arrayMaxUsed) {
+                            _arrayMaxUsed = numCrossings;
+                        }
+                    }
+                } // ptrLen != 0
+            } // bucketCount != 0
+
+
+            if (numCrossings != 0) {
+                /*
+                 * thresholds to switch to optimized merge sort
+                 * for newly added edges + final merge pass.
+                 */
+                if ((ptrLen < 10) || (numCrossings < 40)) {
+                    if (DO_STATS) {
+                        rdrCtx.stats.hist_rdr_crossings
+                            .add(numCrossings);
+                        rdrCtx.stats.hist_rdr_crossings_adds
+                            .add(ptrLen);
+                    }
+
+                    /*
+                     * threshold to use binary insertion sort instead of
+                     * straight insertion sort (to reduce minimize comparisons).
+                     */
+                    useBinarySearch = (numCrossings >= 20);
+
+                    // if small enough:
+                    lastCross = _MIN_VALUE;
+
+                    for (i = 0; i < numCrossings; i++) {
+                        // get the pointer to the edge
+                        ecur = _edgePtrs[i];
+
+                        /* convert subpixel coordinates (float) into pixel
+                            positions (int) for coming scanline */
+                        /* note: it is faster to always update edges even
+                           if it is removed from AEL for coming or last scanline */
+
+                        // random access so use unsafe:
+                        addr = addr0 + ecur; // ecur + OFF_F_CURX
+
+                        // get current crossing:
+                        curx = _unsafe.getInt(addr);
+
+                        // update crossing with orientation at last bit:
+                        cross = curx;
+
+                        // Increment x using DDA (fixed point):
+                        curx += _unsafe.getInt(addr + _OFF_BUMP_X);
+
+                        // Increment error:
+                        err  =  _unsafe.getInt(addr + _OFF_ERROR)
+                              + _unsafe.getInt(addr + _OFF_BUMP_ERR);
+
+                        // Manual carry handling:
+                        // keep sign and carry bit only and ignore last bit (preserve orientation):
+                        _unsafe.putInt(addr,               curx - ((err >> 30) & _ALL_BUT_LSB));
+                        _unsafe.putInt(addr + _OFF_ERROR, (err & _ERR_STEP_MAX));
+
+                        if (DO_STATS) {
+                            rdrCtx.stats.stat_rdr_crossings_updates
+                                .add(numCrossings);
+                        }
+
+                        // insertion sort of crossings:
+                        if (cross < lastCross) {
+                            if (DO_STATS) {
+                                rdrCtx.stats.stat_rdr_crossings_sorts
+                                    .add(i);
+                            }
+
+                            /* use binary search for newly added edges
+                               in crossings if arrays are large enough */
+                            if (useBinarySearch && (i >= prevNumCrossings)) {
+                                if (DO_STATS) {
+                                    rdrCtx.stats.
+                                        stat_rdr_crossings_bsearch.add(i);
+                                }
+                                low = 0;
+                                high = i - 1;
+
+                                do {
+                                    // note: use signed shift (not >>>) for performance
+                                    // as indices are small enough to exceed Integer.MAX_VALUE
+                                    mid = (low + high) >> 1;
+
+                                    if (_crossings[mid] < cross) {
+                                        low = mid + 1;
+                                    } else {
+                                        high = mid - 1;
+                                    }
+                                } while (low <= high);
+
+                                for (j = i - 1; j >= low; j--) {
+                                    _crossings[j + 1] = _crossings[j];
+                                    _edgePtrs [j + 1] = _edgePtrs[j];
+                                }
+                                _crossings[low] = cross;
+                                _edgePtrs [low] = ecur;
+
+                            } else {
+                                j = i - 1;
+                                _crossings[i] = _crossings[j];
+                                _edgePtrs[i] = _edgePtrs[j];
+
+                                while ((--j >= 0) && (_crossings[j] > cross)) {
+                                    _crossings[j + 1] = _crossings[j];
+                                    _edgePtrs [j + 1] = _edgePtrs[j];
+                                }
+                                _crossings[j + 1] = cross;
+                                _edgePtrs [j + 1] = ecur;
+                            }
+
+                        } else {
+                            _crossings[i] = lastCross = cross;
+                        }
+                    }
+                } else {
+                    if (DO_STATS) {
+                        rdrCtx.stats.stat_rdr_crossings_msorts
+                            .add(numCrossings);
+                        rdrCtx.stats.hist_rdr_crossings_ratio
+                            .add((1000 * ptrLen) / numCrossings);
+                        rdrCtx.stats.hist_rdr_crossings_msorts
+                            .add(numCrossings);
+                        rdrCtx.stats.hist_rdr_crossings_msorts_adds
+                            .add(ptrLen);
+                    }
+
+                    // Copy sorted data in auxiliary arrays
+                    // and perform insertion sort on almost sorted data
+                    // (ie i < prevNumCrossings):
+
+                    lastCross = _MIN_VALUE;
+
+                    for (i = 0; i < numCrossings; i++) {
+                        // get the pointer to the edge
+                        ecur = _edgePtrs[i];
+
+                        /* convert subpixel coordinates (float) into pixel
+                            positions (int) for coming scanline */
+                        /* note: it is faster to always update edges even
+                           if it is removed from AEL for coming or last scanline */
+
+                        // random access so use unsafe:
+                        addr = addr0 + ecur; // ecur + OFF_F_CURX
+
+                        // get current crossing:
+                        curx = _unsafe.getInt(addr);
+
+                        // update crossing with orientation at last bit:
+                        cross = curx;
+
+                        // Increment x using DDA (fixed point):
+                        curx += _unsafe.getInt(addr + _OFF_BUMP_X);
+
+                        // Increment error:
+                        err  =  _unsafe.getInt(addr + _OFF_ERROR)
+                              + _unsafe.getInt(addr + _OFF_BUMP_ERR);
+
+                        // Manual carry handling:
+                        // keep sign and carry bit only and ignore last bit (preserve orientation):
+                        _unsafe.putInt(addr,               curx - ((err >> 30) & _ALL_BUT_LSB));
+                        _unsafe.putInt(addr + _OFF_ERROR, (err & _ERR_STEP_MAX));
+
+                        if (DO_STATS) {
+                            rdrCtx.stats.stat_rdr_crossings_updates
+                                .add(numCrossings);
+                        }
+
+                        if (i >= prevNumCrossings) {
+                            // simply store crossing as edgePtrs is in-place:
+                            // will be copied and sorted efficiently by mergesort later:
+                            _crossings[i]     = cross;
+
+                        } else if (cross < lastCross) {
+                            if (DO_STATS) {
+                                rdrCtx.stats.stat_rdr_crossings_sorts
+                                    .add(i);
+                            }
+
+                            // (straight) insertion sort of crossings:
+                            j = i - 1;
+                            _aux_crossings[i] = _aux_crossings[j];
+                            _aux_edgePtrs[i] = _aux_edgePtrs[j];
+
+                            while ((--j >= 0) && (_aux_crossings[j] > cross)) {
+                                _aux_crossings[j + 1] = _aux_crossings[j];
+                                _aux_edgePtrs [j + 1] = _aux_edgePtrs[j];
+                            }
+                            _aux_crossings[j + 1] = cross;
+                            _aux_edgePtrs [j + 1] = ecur;
+
+                        } else {
+                            // auxiliary storage:
+                            _aux_crossings[i] = lastCross = cross;
+                            _aux_edgePtrs [i] = ecur;
+                        }
+                    }
+
+                    // use Mergesort using auxiliary arrays (sort only right part)
+                    MergeSort.mergeSortNoCopy(_crossings,     _edgePtrs,
+                                              _aux_crossings, _aux_edgePtrs,
+                                              numCrossings,   prevNumCrossings);
+                }
+
+                // reset ptrLen
+                ptrLen = 0;
+                // --- from former ScanLineIterator.next()
+
+
+                /* note: bboxx0 and bboxx1 must be pixel boundaries
+                   to have correct coverage computation */
+
+                // right shift on crossings to get the x-coordinate:
+                curxo = _crossings[0];
+                x0    = curxo >> 1;
+                if (x0 < minX) {
+                    minX = x0; // subpixel coordinate
+                }
+
+                x1 = _crossings[numCrossings - 1] >> 1;
+                if (x1 > maxX) {
+                    maxX = x1; // subpixel coordinate
+                }
+
+
+                // compute pixel coverages
+                prev = curx = x0;
+                // to turn {0, 1} into {-1, 1}, multiply by 2 and subtract 1.
+                // last bit contains orientation (0 or 1)
+                crorientation = ((curxo & 0x1) << 1) - 1;
+
+                if (windingRuleEvenOdd) {
+                    sum = crorientation;
+
+                    // Even Odd winding rule: take care of mask ie sum(orientations)
+                    for (i = 1; i < numCrossings; i++) {
+                        curxo = _crossings[i];
+                        curx  =  curxo >> 1;
+                        // to turn {0, 1} into {-1, 1}, multiply by 2 and subtract 1.
+                        // last bit contains orientation (0 or 1)
+                        crorientation = ((curxo & 0x1) << 1) - 1;
+
+                        if ((sum & 0x1) != 0) {
+                            // TODO: perform line clipping on left-right sides
+                            // to avoid such bound checks:
+                            x0 = (prev > bboxx0) ? prev : bboxx0;
+                            x1 = (curx < bboxx1) ? curx : bboxx1;
+
+                            if (x0 < x1) {
+                                x0 -= bboxx0; // turn x0, x1 from coords to indices
+                                x1 -= bboxx0; // in the alpha array.
+
+                                pix_x      =  x0      >> _SUBPIXEL_LG_POSITIONS_X;
+                                pix_xmaxm1 = (x1 - 1) >> _SUBPIXEL_LG_POSITIONS_X;
+
+                                if (pix_x == pix_xmaxm1) {
+                                    // Start and end in same pixel
+                                    tmp = (x1 - x0); // number of subpixels
+                                    _alpha[pix_x    ] += tmp;
+                                    _alpha[pix_x + 1] -= tmp;
+
+                                    if (useBlkFlags) {
+                                        // flag used blocks:
+                                        _blkFlags[pix_x >> _BLK_SIZE_LG] = 1;
+                                    }
+                                } else {
+                                    tmp = (x0 & _SUBPIXEL_MASK_X);
+                                    _alpha[pix_x    ]
+                                        += (_SUBPIXEL_POSITIONS_X - tmp);
+                                    _alpha[pix_x + 1]
+                                        += tmp;
+
+                                    pix_xmax = x1 >> _SUBPIXEL_LG_POSITIONS_X;
+
+                                    tmp = (x1 & _SUBPIXEL_MASK_X);
+                                    _alpha[pix_xmax    ]
+                                        -= (_SUBPIXEL_POSITIONS_X - tmp);
+                                    _alpha[pix_xmax + 1]
+                                        -= tmp;
+
+                                    if (useBlkFlags) {
+                                        // flag used blocks:
+                                        _blkFlags[pix_x    >> _BLK_SIZE_LG] = 1;
+                                        _blkFlags[pix_xmax >> _BLK_SIZE_LG] = 1;
+                                    }
+                                }
+                            }
+                        }
+
+                        sum += crorientation;
+                        prev = curx;
+                    }
+                } else {
+                    // Non-zero winding rule: optimize that case (default)
+                    // and avoid processing intermediate crossings
+                    for (i = 1, sum = 0;; i++) {
+                        sum += crorientation;
+
+                        if (sum != 0) {
+                            // prev = min(curx)
+                            if (prev > curx) {
+                                prev = curx;
+                            }
+                        } else {
+                            // TODO: perform line clipping on left-right sides
+                            // to avoid such bound checks:
+                            x0 = (prev > bboxx0) ? prev : bboxx0;
+                            x1 = (curx < bboxx1) ? curx : bboxx1;
+
+                            if (x0 < x1) {
+                                x0 -= bboxx0; // turn x0, x1 from coords to indices
+                                x1 -= bboxx0; // in the alpha array.
+
+                                pix_x      =  x0      >> _SUBPIXEL_LG_POSITIONS_X;
+                                pix_xmaxm1 = (x1 - 1) >> _SUBPIXEL_LG_POSITIONS_X;
+
+                                if (pix_x == pix_xmaxm1) {
+                                    // Start and end in same pixel
+                                    tmp = (x1 - x0); // number of subpixels
+                                    _alpha[pix_x    ] += tmp;
+                                    _alpha[pix_x + 1] -= tmp;
+
+                                    if (useBlkFlags) {
+                                        // flag used blocks:
+                                        _blkFlags[pix_x >> _BLK_SIZE_LG] = 1;
+                                    }
+                                } else {
+                                    tmp = (x0 & _SUBPIXEL_MASK_X);
+                                    _alpha[pix_x    ]
+                                        += (_SUBPIXEL_POSITIONS_X - tmp);
+                                    _alpha[pix_x + 1]
+                                        += tmp;
+
+                                    pix_xmax = x1 >> _SUBPIXEL_LG_POSITIONS_X;
+
+                                    tmp = (x1 & _SUBPIXEL_MASK_X);
+                                    _alpha[pix_xmax    ]
+                                        -= (_SUBPIXEL_POSITIONS_X - tmp);
+                                    _alpha[pix_xmax + 1]
+                                        -= tmp;
+
+                                    if (useBlkFlags) {
+                                        // flag used blocks:
+                                        _blkFlags[pix_x    >> _BLK_SIZE_LG] = 1;
+                                        _blkFlags[pix_xmax >> _BLK_SIZE_LG] = 1;
+                                    }
+                                }
+                            }
+                            prev = _MAX_VALUE;
+                        }
+
+                        if (i == numCrossings) {
+                            break;
+                        }
+
+                        curxo = _crossings[i];
+                        curx  =  curxo >> 1;
+                        // to turn {0, 1} into {-1, 1}, multiply by 2 and subtract 1.
+                        // last bit contains orientation (0 or 1)
+                        crorientation = ((curxo & 0x1) << 1) - 1;
+                    }
+                }
+            } // numCrossings > 0
+
+            // even if this last row had no crossings, alpha will be zeroed
+            // from the last emitRow call. But this doesn't matter because
+            // maxX < minX, so no row will be emitted to the MarlinCache.
+            if ((y & _SUBPIXEL_MASK_Y) == _SUBPIXEL_MASK_Y) {
+                lastY = y >> _SUBPIXEL_LG_POSITIONS_Y;
+
+                // convert subpixel to pixel coordinate within boundaries:
+                minX = FloatMath.max(minX, bboxx0) >> _SUBPIXEL_LG_POSITIONS_X;
+                maxX = FloatMath.min(maxX, bboxx1) >> _SUBPIXEL_LG_POSITIONS_X;
+
+                if (maxX >= minX) {
+                    // note: alpha array will be zeroed by copyAARow()
+                    // +2 because alpha [pix_minX; pix_maxX+1]
+                    // fix range [x0; x1[
+                    copyAARow(_alpha, lastY, minX, maxX + 2, useBlkFlags);
+
+                    // speculative for next pixel row (scanline coherence):
+                    if (_enableBlkFlagsHeuristics) {
+                        // Use block flags if large pixel span and few crossings:
+                        // ie mean(distance between crossings) is larger than
+                        // 1 block size;
+
+                        // fast check width:
+                        maxX -= minX;
+
+                        // if stroking: numCrossings /= 2
+                        // => shift numCrossings by 1
+                        // condition = (width / (numCrossings - 1)) > blockSize
+                        useBlkFlags = (maxX > _BLK_SIZE) && (maxX >
+                            (((numCrossings >> stroking) - 1) << _BLK_SIZE_LG));
+
+                        if (DO_STATS) {
+                            tmp = FloatMath.max(1,
+                                    ((numCrossings >> stroking) - 1));
+                            rdrCtx.stats.hist_tile_generator_encoding_dist
+                                .add(maxX / tmp);
+                        }
+                    }
+                } else {
+                    _cache.clearAARow(lastY);
+                }
+                minX = _MAX_VALUE;
+                maxX = _MIN_VALUE;
+            }
+        } // scan line iterator
+
+        // Emit final row
+        y--;
+        y >>= _SUBPIXEL_LG_POSITIONS_Y;
+
+        // convert subpixel to pixel coordinate within boundaries:
+        minX = FloatMath.max(minX, bboxx0) >> _SUBPIXEL_LG_POSITIONS_X;
+        maxX = FloatMath.min(maxX, bboxx1) >> _SUBPIXEL_LG_POSITIONS_X;
+
+        if (maxX >= minX) {
+            // note: alpha array will be zeroed by copyAARow()
+            // +2 because alpha [pix_minX; pix_maxX+1]
+            // fix range [x0; x1[
+            copyAARow(_alpha, y, minX, maxX + 2, useBlkFlags);
+        } else if (y != lastY) {
+            _cache.clearAARow(y);
+        }
+
+        // update member:
+        edgeCount = numCrossings;
+        prevUseBlkFlags = useBlkFlags;
+
+        if (DO_STATS) {
+            // update max used mark
+            activeEdgeMaxUsed = _arrayMaxUsed;
+        }
+    }
+
+    boolean endRendering() {
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_endRendering.start();
+        }
+        if (edgeMinY == Integer.MAX_VALUE) {
+            return false; // undefined edges bounds
+        }
+
+        final int _boundsMinY = boundsMinY;
+        final int _boundsMaxY = boundsMaxY;
+
+        // bounds as inclusive intervals
+        final int spminX = FloatMath.max(FloatMath.ceil_int(edgeMinX - 0.5f), boundsMinX);
+        final int spmaxX = FloatMath.min(FloatMath.ceil_int(edgeMaxX - 0.5f), boundsMaxX - 1);
+
+        // edge Min/Max Y are already rounded to subpixels within bounds:
+        final int spminY = edgeMinY;
+        final int spmaxY;
+        int maxY = edgeMaxY;
+
+        if (maxY <= _boundsMaxY - 1) {
+            spmaxY = maxY;
+        } else {
+            spmaxY = _boundsMaxY - 1;
+            maxY   = _boundsMaxY;
+        }
+        buckets_minY = spminY - _boundsMinY;
+        buckets_maxY = maxY   - _boundsMinY;
+
+        if (DO_LOG_BOUNDS) {
+            MarlinUtils.logInfo("edgesXY = [" + edgeMinX + " ... " + edgeMaxX
+                                + "][" + edgeMinY + " ... " + edgeMaxY + "]");
+            MarlinUtils.logInfo("spXY    = [" + spminX + " ... " + spmaxX
+                                + "][" + spminY + " ... " + spmaxY + "]");
+        }
+
+        // test clipping for shapes out of bounds
+        if ((spminX > spmaxX) || (spminY > spmaxY)) {
+            return false;
+        }
+
+        // half open intervals
+        // inclusive:
+        final int pminX =  spminX                    >> SUBPIXEL_LG_POSITIONS_X;
+        // exclusive:
+        final int pmaxX = (spmaxX + SUBPIXEL_MASK_X) >> SUBPIXEL_LG_POSITIONS_X;
+        // inclusive:
+        final int pminY =  spminY                    >> SUBPIXEL_LG_POSITIONS_Y;
+        // exclusive:
+        final int pmaxY = (spmaxY + SUBPIXEL_MASK_Y) >> SUBPIXEL_LG_POSITIONS_Y;
+
+        // store BBox to answer ptg.getBBox():
+        this.cache.init(pminX, pminY, pmaxX, pmaxY, edgeSumDeltaY);
+
+        // Heuristics for using block flags:
+        if (ENABLE_BLOCK_FLAGS) {
+            enableBlkFlags = this.cache.useRLE;
+            prevUseBlkFlags = enableBlkFlags && !ENABLE_BLOCK_FLAGS_HEURISTICS;
+
+            if (enableBlkFlags) {
+                // ensure blockFlags array is large enough:
+                // note: +2 to ensure enough space left at end
+                final int nxTiles = ((pmaxX - pminX) >> TILE_SIZE_LG) + 2;
+                if (nxTiles > INITIAL_ARRAY) {
+                    blkFlags = rdrCtx.getIntArray(nxTiles);
+                }
+            }
+        }
+
+        // memorize the rendering bounding box:
+        /* note: bbox_spminX and bbox_spmaxX must be pixel boundaries
+           to have correct coverage computation */
+        // inclusive:
+        bbox_spminX = pminX << SUBPIXEL_LG_POSITIONS_X;
+        // exclusive:
+        bbox_spmaxX = pmaxX << SUBPIXEL_LG_POSITIONS_X;
+        // inclusive:
+        bbox_spminY = spminY;
+        // exclusive:
+        bbox_spmaxY = FloatMath.min(spmaxY + 1, pmaxY << SUBPIXEL_LG_POSITIONS_Y);
+
+        if (DO_LOG_BOUNDS) {
+            MarlinUtils.logInfo("pXY       = [" + pminX + " ... " + pmaxX
+                                + "[ [" + pminY + " ... " + pmaxY + "[");
+            MarlinUtils.logInfo("bbox_spXY = [" + bbox_spminX + " ... "
+                                + bbox_spmaxX + "[ [" + bbox_spminY + " ... "
+                                + bbox_spmaxY + "[");
+        }
+
+        // Prepare alpha line:
+        // add 2 to better deal with the last pixel in a pixel row.
+        final int width = (pmaxX - pminX) + 2;
+
+        // Useful when processing tile line by tile line
+        if (width > INITIAL_AA_ARRAY) {
+            if (DO_STATS) {
+                rdrCtx.stats.stat_array_renderer_alphaline
+                    .add(width);
+            }
+            alphaLine = rdrCtx.getIntArray(width);
+        }
+
+        // process first tile line:
+        endRendering(pminY);
+
+        return true;
+    }
+
+    private int bbox_spminX, bbox_spmaxX, bbox_spminY, bbox_spmaxY;
+
+    void endRendering(final int pminY) {
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_endRendering_Y.start();
+        }
+
+        final int spminY       = pminY << SUBPIXEL_LG_POSITIONS_Y;
+        final int fixed_spminY = FloatMath.max(bbox_spminY, spminY);
+
+        // avoid rendering for last call to nextTile()
+        if (fixed_spminY < bbox_spmaxY) {
+            // process a complete tile line ie scanlines for 32 rows
+            final int spmaxY = FloatMath.min(bbox_spmaxY, spminY + SUBPIXEL_TILE);
+
+            // process tile line [0 - 32]
+            cache.resetTileLine(pminY);
+
+            // Process only one tile line:
+            _endRendering(fixed_spminY, spmaxY);
+        }
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_endRendering_Y.stop();
+        }
+    }
+
+    private boolean enableBlkFlags = false;
+    private boolean prevUseBlkFlags = false;
+
+    private final int[] blkFlags_initial = new int[INITIAL_ARRAY]; // 1 tile line
+    /* block flags (0|1) */
+    private int[] blkFlags = blkFlags_initial;
+
+    void copyAARow(final int[] alphaRow,
+                   final int pix_y, final int pix_from, final int pix_to,
+                   final boolean useBlockFlags)
+    {
+        if (useBlockFlags) {
+            if (DO_STATS) {
+                rdrCtx.stats.hist_tile_generator_encoding.add(1);
+            }
+            cache.copyAARowRLE_WithBlockFlags(blkFlags, alphaRow, pix_y, pix_from, pix_to);
+        } else {
+            if (DO_STATS) {
+                rdrCtx.stats.hist_tile_generator_encoding.add(0);
+            }
+            cache.copyAARowNoRLE(alphaRow, pix_y, pix_from, pix_to);
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/RendererContext.java b/src/share/classes/sun/java2d/marlin/RendererContext.java
new file mode 100644
index 0000000..a11a1e8
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/RendererContext.java
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+import java.awt.geom.Path2D;
+import java.lang.ref.WeakReference;
+import java.util.concurrent.atomic.AtomicInteger;
+import sun.java2d.ReentrantContext;
+import sun.java2d.ReentrantContextProvider;
+import static sun.java2d.marlin.ArrayCache.*;
+import sun.java2d.marlin.MarlinRenderingEngine.NormalizingPathIterator;
+import static sun.java2d.marlin.MarlinUtils.logInfo;
+
+/**
+ * This class is a renderer context dedicated to a single thread
+ */
+final class RendererContext extends ReentrantContext implements MarlinConst {
+
+    // RendererContext creation counter
+    private static final AtomicInteger CTX_COUNT = new AtomicInteger(1);
+    // RendererContext statistics
+    final RendererStats stats = (DO_STATS || DO_MONITORS)
+                                       ? RendererStats.getInstance(): null;
+
+    private static final boolean USE_CACHE_HARD_REF = DO_STATS
+        || (MarlinRenderingEngine.REF_TYPE == ReentrantContextProvider.REF_WEAK);
+
+    /**
+     * Create a new renderer context
+     *
+     * @return new RendererContext instance
+     */
+    static RendererContext createContext() {
+        final RendererContext newCtx = new RendererContext("ctx"
+                    + Integer.toString(CTX_COUNT.getAndIncrement()));
+
+        if (DO_STATS || DO_MONITORS) {
+            RendererStats.ALL_CONTEXTS.add(newCtx);
+        }
+        return newCtx;
+    }
+
+    // context name (debugging purposes)
+    final String name;
+    // Smallest object used as Cleaner's parent reference
+    final Object cleanerObj = new Object();
+    // dirty flag indicating an exception occured during pipeline in pathTo()
+    boolean dirty = false;
+    // dynamic array caches kept using weak reference (low memory footprint)
+    WeakReference<ArrayCachesHolder> refArrayCaches = null;
+    // hard reference to array caches (for statistics)
+    ArrayCachesHolder hardRefArrayCaches = null;
+    // shared data
+    final float[] float6 = new float[6];
+    // shared curve (dirty) (Renderer / Stroker)
+    final Curve curve = new Curve();
+    // MarlinRenderingEngine NormalizingPathIterator NearestPixelCenter:
+    final NormalizingPathIterator nPCPathIterator;
+    // MarlinRenderingEngine NearestPixelQuarter NormalizingPathIterator:
+    final NormalizingPathIterator nPQPathIterator;
+    // MarlinRenderingEngine.TransformingPathConsumer2D
+    final TransformingPathConsumer2D transformerPC2D;
+    // recycled Path2D instance
+    Path2D.Float p2d = null;
+    final Renderer renderer;
+    final Stroker stroker;
+    // Simplifies out collinear lines
+    final CollinearSimplifier simplifier = new CollinearSimplifier();
+    final Dasher dasher;
+    final MarlinTileGenerator ptg;
+    final MarlinCache cache;
+    // flag indicating the shape is stroked (1) or filled (0)
+    int stroking = 0;
+
+    /**
+     * Constructor
+     *
+     * @param name context name (debugging)
+     */
+    RendererContext(final String name) {
+        if (LOG_CREATE_CONTEXT) {
+            MarlinUtils.logInfo("new RendererContext = " + name);
+        }
+
+        this.name = name;
+
+        // NormalizingPathIterator instances:
+        nPCPathIterator = new NormalizingPathIterator.NearestPixelCenter(float6);
+        nPQPathIterator  = new NormalizingPathIterator.NearestPixelQuarter(float6);
+
+        // MarlinRenderingEngine.TransformingPathConsumer2D
+        transformerPC2D = new TransformingPathConsumer2D();
+
+        // Renderer:
+        cache = new MarlinCache(this);
+        renderer = new Renderer(this); // needs MarlinCache from rdrCtx.cache
+        ptg = new MarlinTileGenerator(renderer);
+
+        stroker = new Stroker(this);
+        dasher = new Dasher(this);
+    }
+
+    /**
+     * Disposes this renderer context:
+     * clean up before reusing this context
+     */
+    void dispose() {
+        stroking = 0;
+        // reset hard reference to array caches if needed:
+        if (!USE_CACHE_HARD_REF) {
+            hardRefArrayCaches = null;
+        }
+        // if context is maked as DIRTY:
+        if (dirty) {
+            // may happen if an exception if thrown in the pipeline processing:
+            // force cleanup of all possible pipelined blocks (except Renderer):
+
+            // NormalizingPathIterator instances:
+            this.nPCPathIterator.dispose();
+            this.nPQPathIterator.dispose();
+            // Dasher:
+            this.dasher.dispose();
+            // Stroker:
+            this.stroker.dispose();
+
+            // mark context as CLEAN:
+            dirty = false;
+        }
+    }
+
+    // Array caches
+    ArrayCachesHolder getArrayCachesHolder() {
+        // Use hard reference first (cached resolved weak reference):
+        ArrayCachesHolder holder = hardRefArrayCaches;
+        if (holder == null) {
+            // resolve reference:
+            holder = (refArrayCaches != null)
+                     ? refArrayCaches.get()
+                     : null;
+            // create a new ArrayCachesHolder if none is available
+            if (holder == null) {
+                if (LOG_CREATE_CONTEXT) {
+                    MarlinUtils.logInfo("new ArrayCachesHolder for "
+                                        + "RendererContext = " + name);
+                }
+
+                holder = new ArrayCachesHolder();
+
+                if (USE_CACHE_HARD_REF) {
+                    // update hard reference:
+                    hardRefArrayCaches = holder;
+                } else {
+                    // update weak reference:
+                    refArrayCaches = new WeakReference<ArrayCachesHolder>(holder);
+                }
+            }
+        }
+        return holder;
+    }
+
+    // dirty byte array cache
+    ByteArrayCache getDirtyByteArrayCache(final int length) {
+        final int bucket = ArrayCache.getBucketDirtyBytes(length);
+        return getArrayCachesHolder().dirtyByteArrayCaches[bucket];
+    }
+
+    byte[] getDirtyByteArray(final int length) {
+        if (length <= MAX_DIRTY_BYTE_ARRAY_SIZE) {
+            return getDirtyByteArrayCache(length).getArray();
+        }
+
+        if (DO_STATS) {
+            incOversize();
+        }
+
+        if (DO_LOG_OVERSIZE) {
+            logInfo("getDirtyByteArray[oversize]: length=\t" + length);
+        }
+
+        return new byte[length];
+    }
+
+    void putDirtyByteArray(final byte[] array) {
+        final int length = array.length;
+        // odd sized array are non-cached arrays (initial arrays)
+        // ensure to never store initial arrays in cache:
+        if (((length & 0x1) == 0) && (length <= MAX_DIRTY_BYTE_ARRAY_SIZE)) {
+            getDirtyByteArrayCache(length).putDirtyArray(array, length);
+        }
+    }
+
+    byte[] widenDirtyByteArray(final byte[] in,
+                               final int usedSize, final int needSize)
+    {
+        final int length = in.length;
+        if (DO_CHECKS && length >= needSize) {
+            return in;
+        }
+        if (DO_STATS) {
+            incResizeDirtyByte();
+        }
+
+        // maybe change bucket:
+        // ensure getNewSize() > newSize:
+        final byte[] res = getDirtyByteArray(getNewSize(usedSize, needSize));
+
+        System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements
+
+        // maybe return current array:
+        // NO clean-up of array data = DIRTY ARRAY
+        putDirtyByteArray(in);
+
+        if (DO_LOG_WIDEN_ARRAY) {
+            logInfo("widenDirtyByteArray[" + res.length + "]: usedSize=\t"
+                    + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
+                    + needSize);
+        }
+        return res;
+    }
+
+    // int array cache
+    IntArrayCache getIntArrayCache(final int length) {
+        final int bucket = ArrayCache.getBucket(length);
+        return getArrayCachesHolder().intArrayCaches[bucket];
+    }
+
+    int[] getIntArray(final int length) {
+        if (length <= MAX_ARRAY_SIZE) {
+            return getIntArrayCache(length).getArray();
+        }
+
+        if (DO_STATS) {
+            incOversize();
+        }
+
+        if (DO_LOG_OVERSIZE) {
+            logInfo("getIntArray[oversize]: length=\t" + length);
+        }
+
+        return new int[length];
+    }
+
+    // unused
+    int[] widenIntArray(final int[] in, final int usedSize,
+                        final int needSize, final int clearTo)
+    {
+        final int length = in.length;
+        if (DO_CHECKS && length >= needSize) {
+            return in;
+        }
+        if (DO_STATS) {
+            incResizeInt();
+        }
+
+        // maybe change bucket:
+        // ensure getNewSize() > newSize:
+        final int[] res = getIntArray(getNewSize(usedSize, needSize));
+
+        System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements
+
+        // maybe return current array:
+        putIntArray(in, 0, clearTo); // ensure all array is cleared (grow-reduce algo)
+
+        if (DO_LOG_WIDEN_ARRAY) {
+            logInfo("widenIntArray[" + res.length + "]: usedSize=\t"
+                    + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
+                    + needSize);
+        }
+        return res;
+    }
+
+    void putIntArray(final int[] array, final int fromIndex,
+                     final int toIndex)
+    {
+        final int length = array.length;
+        // odd sized array are non-cached arrays (initial arrays)
+        // ensure to never store initial arrays in cache:
+        if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) {
+            getIntArrayCache(length).putArray(array, length, fromIndex, toIndex);
+        }
+    }
+
+    // dirty int array cache
+    IntArrayCache getDirtyIntArrayCache(final int length) {
+        final int bucket = ArrayCache.getBucket(length);
+        return getArrayCachesHolder().dirtyIntArrayCaches[bucket];
+    }
+
+    int[] getDirtyIntArray(final int length) {
+        if (length <= MAX_ARRAY_SIZE) {
+            return getDirtyIntArrayCache(length).getArray();
+        }
+
+        if (DO_STATS) {
+            incOversize();
+        }
+
+        if (DO_LOG_OVERSIZE) {
+            logInfo("getDirtyIntArray[oversize]: length=\t" + length);
+        }
+
+        return new int[length];
+    }
+
+    int[] widenDirtyIntArray(final int[] in,
+                             final int usedSize, final int needSize)
+    {
+        final int length = in.length;
+        if (DO_CHECKS && length >= needSize) {
+            return in;
+        }
+        if (DO_STATS) {
+            incResizeDirtyInt();
+        }
+
+        // maybe change bucket:
+        // ensure getNewSize() > newSize:
+        final int[] res = getDirtyIntArray(getNewSize(usedSize, needSize));
+
+        System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements
+
+        // maybe return current array:
+        // NO clean-up of array data = DIRTY ARRAY
+        putDirtyIntArray(in);
+
+        if (DO_LOG_WIDEN_ARRAY) {
+            logInfo("widenDirtyIntArray[" + res.length + "]: usedSize=\t"
+                    + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
+                    + needSize);
+        }
+        return res;
+    }
+
+    void putDirtyIntArray(final int[] array) {
+        final int length = array.length;
+        // odd sized array are non-cached arrays (initial arrays)
+        // ensure to never store initial arrays in cache:
+        if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) {
+            getDirtyIntArrayCache(length).putDirtyArray(array, length);
+        }
+    }
+
+    // dirty float array cache
+    FloatArrayCache getDirtyFloatArrayCache(final int length) {
+        final int bucket = ArrayCache.getBucket(length);
+        return getArrayCachesHolder().dirtyFloatArrayCaches[bucket];
+    }
+
+    float[] getDirtyFloatArray(final int length) {
+        if (length <= MAX_ARRAY_SIZE) {
+            return getDirtyFloatArrayCache(length).getArray();
+        }
+
+        if (DO_STATS) {
+            incOversize();
+        }
+
+        if (DO_LOG_OVERSIZE) {
+            logInfo("getDirtyFloatArray[oversize]: length=\t" + length);
+        }
+
+        return new float[length];
+    }
+
+    float[] widenDirtyFloatArray(final float[] in,
+                                 final int usedSize, final int needSize)
+    {
+        final int length = in.length;
+        if (DO_CHECKS && length >= needSize) {
+            return in;
+        }
+        if (DO_STATS) {
+            incResizeDirtyFloat();
+        }
+
+        // maybe change bucket:
+        // ensure getNewSize() > newSize:
+        final float[] res = getDirtyFloatArray(getNewSize(usedSize, needSize));
+
+        System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements
+
+        // maybe return current array:
+        // NO clean-up of array data = DIRTY ARRAY
+        putDirtyFloatArray(in);
+
+        if (DO_LOG_WIDEN_ARRAY) {
+            logInfo("widenDirtyFloatArray[" + res.length + "]: usedSize=\t"
+                    + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
+                    + needSize);
+        }
+        return res;
+    }
+
+    void putDirtyFloatArray(final float[] array) {
+        final int length = array.length;
+        // odd sized array are non-cached arrays (initial arrays)
+        // ensure to never store initial arrays in cache:
+        if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) {
+            getDirtyFloatArrayCache(length).putDirtyArray(array, length);
+        }
+    }
+
+    /* class holding all array cache instances */
+    static final class ArrayCachesHolder {
+        // zero-filled int array cache:
+        final IntArrayCache[] intArrayCaches;
+        // dirty array caches:
+        final IntArrayCache[] dirtyIntArrayCaches;
+        final FloatArrayCache[] dirtyFloatArrayCaches;
+        final ByteArrayCache[] dirtyByteArrayCaches;
+
+        ArrayCachesHolder() {
+            intArrayCaches = new IntArrayCache[BUCKETS];
+            dirtyIntArrayCaches = new IntArrayCache[BUCKETS];
+            dirtyFloatArrayCaches = new FloatArrayCache[BUCKETS];
+            dirtyByteArrayCaches = new ByteArrayCache[BUCKETS];
+
+            for (int i = 0; i < BUCKETS; i++) {
+                intArrayCaches[i] = new IntArrayCache(ARRAY_SIZES[i]);
+                // dirty array caches:
+                dirtyIntArrayCaches[i] = new IntArrayCache(ARRAY_SIZES[i]);
+                dirtyFloatArrayCaches[i] = new FloatArrayCache(ARRAY_SIZES[i]);
+                dirtyByteArrayCaches[i] = new ByteArrayCache(DIRTY_BYTE_ARRAY_SIZES[i]);
+            }
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/RendererStats.java b/src/share/classes/sun/java2d/marlin/RendererStats.java
new file mode 100644
index 0000000..9c2fa73
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/RendererStats.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import static sun.java2d.marlin.MarlinUtils.logInfo;
+import sun.java2d.marlin.stats.Histogram;
+import sun.java2d.marlin.stats.Monitor;
+import sun.java2d.marlin.stats.StatLong;
+import sun.misc.ThreadGroupUtils;
+
+/**
+ * This class gathers global rendering statistics for debugging purposes only
+ */
+public final class RendererStats implements MarlinConst {
+
+    // singleton
+    private static volatile RendererStats SINGLETON = null;
+
+    static RendererStats getInstance() {
+        if (SINGLETON == null) {
+            SINGLETON = new RendererStats();
+        }
+        return SINGLETON;
+    }
+
+    public static void dumpStats() {
+        if (SINGLETON != null) {
+            SINGLETON.dump();
+        }
+    }
+
+    /* RendererContext collection as hard references
+       (only used for debugging purposes) */
+    static final ConcurrentLinkedQueue<RendererContext> ALL_CONTEXTS
+        = new ConcurrentLinkedQueue<RendererContext>();
+    // stats
+    final StatLong stat_cache_rowAA
+        = new StatLong("cache.rowAA");
+    final StatLong stat_cache_rowAAChunk
+        = new StatLong("cache.rowAAChunk");
+    final StatLong stat_cache_tiles
+        = new StatLong("cache.tiles");
+    final StatLong stat_rdr_poly_stack_curves
+        = new StatLong("renderer.poly.stack.curves");
+    final StatLong stat_rdr_poly_stack_types
+        = new StatLong("renderer.poly.stack.types");
+    final StatLong stat_rdr_addLine
+        = new StatLong("renderer.addLine");
+    final StatLong stat_rdr_addLine_skip
+        = new StatLong("renderer.addLine.skip");
+    final StatLong stat_rdr_curveBreak
+        = new StatLong("renderer.curveBreakIntoLinesAndAdd");
+    final StatLong stat_rdr_curveBreak_dec
+        = new StatLong("renderer.curveBreakIntoLinesAndAdd.dec");
+    final StatLong stat_rdr_curveBreak_inc
+        = new StatLong("renderer.curveBreakIntoLinesAndAdd.inc");
+    final StatLong stat_rdr_quadBreak
+        = new StatLong("renderer.quadBreakIntoLinesAndAdd");
+    final StatLong stat_rdr_quadBreak_dec
+        = new StatLong("renderer.quadBreakIntoLinesAndAdd.dec");
+    final StatLong stat_rdr_edges
+        = new StatLong("renderer.edges");
+    final StatLong stat_rdr_edges_count
+        = new StatLong("renderer.edges.count");
+    final StatLong stat_rdr_edges_resizes
+        = new StatLong("renderer.edges.resize");
+    final StatLong stat_rdr_activeEdges
+        = new StatLong("renderer.activeEdges");
+    final StatLong stat_rdr_activeEdges_updates
+        = new StatLong("renderer.activeEdges.updates");
+    final StatLong stat_rdr_activeEdges_adds
+        = new StatLong("renderer.activeEdges.adds");
+    final StatLong stat_rdr_activeEdges_adds_high
+        = new StatLong("renderer.activeEdges.adds_high");
+    final StatLong stat_rdr_crossings_updates
+        = new StatLong("renderer.crossings.updates");
+    final StatLong stat_rdr_crossings_sorts
+        = new StatLong("renderer.crossings.sorts");
+    final StatLong stat_rdr_crossings_bsearch
+        = new StatLong("renderer.crossings.bsearch");
+    final StatLong stat_rdr_crossings_msorts
+        = new StatLong("renderer.crossings.msorts");
+    // growable arrays
+    final StatLong stat_array_dasher_dasher
+        = new StatLong("array.dasher.dasher.d_float");
+    final StatLong stat_array_dasher_firstSegmentsBuffer
+        = new StatLong("array.dasher.firstSegmentsBuffer.d_float");
+    final StatLong stat_array_stroker_polystack_curves
+        = new StatLong("array.stroker.polystack.curves.d_float");
+    final StatLong stat_array_stroker_polystack_curveTypes
+        = new StatLong("array.stroker.polystack.curveTypes.d_byte");
+    final StatLong stat_array_marlincache_rowAAChunk
+        = new StatLong("array.marlincache.rowAAChunk.d_byte");
+    final StatLong stat_array_marlincache_touchedTile
+        = new StatLong("array.marlincache.touchedTile.int");
+    final StatLong stat_array_renderer_alphaline
+        = new StatLong("array.renderer.alphaline.int");
+    final StatLong stat_array_renderer_crossings
+        = new StatLong("array.renderer.crossings.int");
+    final StatLong stat_array_renderer_aux_crossings
+        = new StatLong("array.renderer.aux_crossings.int");
+    final StatLong stat_array_renderer_edgeBuckets
+        = new StatLong("array.renderer.edgeBuckets.int");
+    final StatLong stat_array_renderer_edgeBucketCounts
+        = new StatLong("array.renderer.edgeBucketCounts.int");
+    final StatLong stat_array_renderer_edgePtrs
+        = new StatLong("array.renderer.edgePtrs.int");
+    final StatLong stat_array_renderer_aux_edgePtrs
+        = new StatLong("array.renderer.aux_edgePtrs.int");
+    // histograms
+    final Histogram hist_rdr_crossings
+        = new Histogram("renderer.crossings");
+    final Histogram hist_rdr_crossings_ratio
+        = new Histogram("renderer.crossings.ratio");
+    final Histogram hist_rdr_crossings_adds
+        = new Histogram("renderer.crossings.adds");
+    final Histogram hist_rdr_crossings_msorts
+        = new Histogram("renderer.crossings.msorts");
+    final Histogram hist_rdr_crossings_msorts_adds
+        = new Histogram("renderer.crossings.msorts.adds");
+    final Histogram hist_tile_generator_alpha
+        = new Histogram("tile_generator.alpha");
+    final Histogram hist_tile_generator_encoding
+        = new Histogram("tile_generator.encoding");
+    final Histogram hist_tile_generator_encoding_dist
+        = new Histogram("tile_generator.encoding.dist");
+    final Histogram hist_tile_generator_encoding_ratio
+        = new Histogram("tile_generator.encoding.ratio");
+    final Histogram hist_tile_generator_encoding_runLen
+        = new Histogram("tile_generator.encoding.runLen");
+    // all stats
+    final StatLong[] statistics = new StatLong[]{
+        stat_cache_rowAA,
+        stat_cache_rowAAChunk,
+        stat_cache_tiles,
+        stat_rdr_poly_stack_types,
+        stat_rdr_poly_stack_curves,
+        stat_rdr_addLine,
+        stat_rdr_addLine_skip,
+        stat_rdr_curveBreak,
+        stat_rdr_curveBreak_dec,
+        stat_rdr_curveBreak_inc,
+        stat_rdr_quadBreak,
+        stat_rdr_quadBreak_dec,
+        stat_rdr_edges,
+        stat_rdr_edges_count,
+        stat_rdr_edges_resizes,
+        stat_rdr_activeEdges,
+        stat_rdr_activeEdges_updates,
+        stat_rdr_activeEdges_adds,
+        stat_rdr_activeEdges_adds_high,
+        stat_rdr_crossings_updates,
+        stat_rdr_crossings_sorts,
+        stat_rdr_crossings_bsearch,
+        stat_rdr_crossings_msorts,
+        hist_rdr_crossings,
+        hist_rdr_crossings_ratio,
+        hist_rdr_crossings_adds,
+        hist_rdr_crossings_msorts,
+        hist_rdr_crossings_msorts_adds,
+        hist_tile_generator_alpha,
+        hist_tile_generator_encoding,
+        hist_tile_generator_encoding_dist,
+        hist_tile_generator_encoding_ratio,
+        hist_tile_generator_encoding_runLen,
+        stat_array_dasher_dasher,
+        stat_array_dasher_firstSegmentsBuffer,
+        stat_array_stroker_polystack_curves,
+        stat_array_stroker_polystack_curveTypes,
+        stat_array_marlincache_rowAAChunk,
+        stat_array_marlincache_touchedTile,
+        stat_array_renderer_alphaline,
+        stat_array_renderer_crossings,
+        stat_array_renderer_aux_crossings,
+        stat_array_renderer_edgeBuckets,
+        stat_array_renderer_edgeBucketCounts,
+        stat_array_renderer_edgePtrs,
+        stat_array_renderer_aux_edgePtrs
+    };
+    // monitors
+    final Monitor mon_pre_getAATileGenerator
+        = new Monitor("MarlinRenderingEngine.getAATileGenerator()");
+    final Monitor mon_rdr_addLine
+        = new Monitor("Renderer.addLine()");
+    final Monitor mon_rdr_endRendering
+        = new Monitor("Renderer.endRendering()");
+    final Monitor mon_rdr_endRendering_Y
+        = new Monitor("Renderer._endRendering(Y)");
+    final Monitor mon_rdr_copyAARow
+        = new Monitor("Renderer.copyAARow()");
+    final Monitor mon_pipe_renderTiles
+        = new Monitor("AAShapePipe.renderTiles()");
+    final Monitor mon_ptg_getAlpha
+        = new Monitor("MarlinTileGenerator.getAlpha()");
+    final Monitor mon_debug
+        = new Monitor("DEBUG()");
+    // all monitors
+    final Monitor[] monitors = new Monitor[]{
+        mon_pre_getAATileGenerator,
+        mon_rdr_addLine,
+        mon_rdr_endRendering,
+        mon_rdr_endRendering_Y,
+        mon_rdr_copyAARow,
+        mon_pipe_renderTiles,
+        mon_ptg_getAlpha,
+        mon_debug
+    };
+
+    private RendererStats() {
+        super();
+
+        AccessController.doPrivileged(
+            (PrivilegedAction<Void>) () -> {
+                final Thread hook = new Thread(
+                    ThreadGroupUtils.getRootThreadGroup(),
+                    new Runnable() {
+                        @Override
+                        public void run() {
+                            dump();
+                        }
+                    },
+                    "MarlinStatsHook"
+                );
+                hook.setContextClassLoader(null);
+                Runtime.getRuntime().addShutdownHook(hook);
+
+                if (USE_DUMP_THREAD) {
+                    final Timer statTimer = new Timer("RendererStats");
+                    statTimer.scheduleAtFixedRate(new TimerTask() {
+                        @Override
+                        public void run() {
+                            dump();
+                        }
+                    }, DUMP_INTERVAL, DUMP_INTERVAL);
+                }
+                return null;
+            }
+        );
+    }
+
+    void dump() {
+        if (DO_STATS) {
+            ArrayCache.dumpStats();
+        }
+        for (RendererContext rdrCtx : ALL_CONTEXTS) {
+            logInfo("RendererContext: " + rdrCtx.name);
+
+            if (DO_MONITORS) {
+                for (Monitor monitor : monitors) {
+                    if (monitor.count != 0) {
+                        logInfo(monitor.toString());
+                    }
+                }
+                // As getAATileGenerator percents:
+                final long total = mon_pre_getAATileGenerator.sum;
+                if (total != 0L) {
+                    for (Monitor monitor : monitors) {
+                        logInfo(monitor.name + " : "
+                                + ((100d * monitor.sum) / total) + " %");
+                    }
+                }
+                if (DO_FLUSH_MONITORS) {
+                    for (Monitor m : monitors) {
+                        m.reset();
+                    }
+                }
+            }
+
+            if (DO_STATS) {
+                for (StatLong stat : statistics) {
+                    if (stat.count != 0) {
+                        logInfo(stat.toString());
+                        stat.reset();
+                    }
+                }
+                // IntArrayCaches stats:
+                final RendererContext.ArrayCachesHolder holder
+                    = rdrCtx.getArrayCachesHolder();
+
+                logInfo("Array caches for thread: " + rdrCtx.name);
+
+                for (IntArrayCache cache : holder.intArrayCaches) {
+                    cache.dumpStats();
+                }
+
+                logInfo("Dirty Array caches for thread: " + rdrCtx.name);
+
+                for (IntArrayCache cache : holder.dirtyIntArrayCaches) {
+                    cache.dumpStats();
+                }
+                for (FloatArrayCache cache : holder.dirtyFloatArrayCaches) {
+                    cache.dumpStats();
+                }
+                for (ByteArrayCache cache : holder.dirtyByteArrayCaches) {
+                    cache.dumpStats();
+                }
+            }
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/Stroker.java b/src/share/classes/sun/java2d/marlin/Stroker.java
new file mode 100644
index 0000000..f25993b
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/Stroker.java
@@ -0,0 +1,1396 @@
+/*
+ * Copyright (c) 2007, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+import java.util.Arrays;
+import static java.lang.Math.ulp;
+import static java.lang.Math.sqrt;
+
+import sun.awt.geom.PathConsumer2D;
+import sun.java2d.marlin.Curve.BreakPtrIterator;
+
+
+// TODO: some of the arithmetic here is too verbose and prone to hard to
+// debug typos. We should consider making a small Point/Vector class that
+// has methods like plus(Point), minus(Point), dot(Point), cross(Point)and such
+final class Stroker implements PathConsumer2D, MarlinConst {
+
+    private static final int MOVE_TO = 0;
+    private static final int DRAWING_OP_TO = 1; // ie. curve, line, or quad
+    private static final int CLOSE = 2;
+
+    /**
+     * Constant value for join style.
+     */
+    public static final int JOIN_MITER = 0;
+
+    /**
+     * Constant value for join style.
+     */
+    public static final int JOIN_ROUND = 1;
+
+    /**
+     * Constant value for join style.
+     */
+    public static final int JOIN_BEVEL = 2;
+
+    /**
+     * Constant value for end cap style.
+     */
+    public static final int CAP_BUTT = 0;
+
+    /**
+     * Constant value for end cap style.
+     */
+    public static final int CAP_ROUND = 1;
+
+    /**
+     * Constant value for end cap style.
+     */
+    public static final int CAP_SQUARE = 2;
+
+    // pisces used to use fixed point arithmetic with 16 decimal digits. I
+    // didn't want to change the values of the constant below when I converted
+    // it to floating point, so that's why the divisions by 2^16 are there.
+    private static final float ROUND_JOIN_THRESHOLD = 1000/65536f;
+
+    private static final float C = 0.5522847498307933f;
+
+    private static final int MAX_N_CURVES = 11;
+
+    private PathConsumer2D out;
+
+    private int capStyle;
+    private int joinStyle;
+
+    private float lineWidth2;
+    private float invHalfLineWidth2Sq;
+
+    private final float[] offset0 = new float[2];
+    private final float[] offset1 = new float[2];
+    private final float[] offset2 = new float[2];
+    private final float[] miter = new float[2];
+    private float miterLimitSq;
+
+    private int prev;
+
+    // The starting point of the path, and the slope there.
+    private float sx0, sy0, sdx, sdy;
+    // the current point and the slope there.
+    private float cx0, cy0, cdx, cdy; // c stands for current
+    // vectors that when added to (sx0,sy0) and (cx0,cy0) respectively yield the
+    // first and last points on the left parallel path. Since this path is
+    // parallel, it's slope at any point is parallel to the slope of the
+    // original path (thought they may have different directions), so these
+    // could be computed from sdx,sdy and cdx,cdy (and vice versa), but that
+    // would be error prone and hard to read, so we keep these anyway.
+    private float smx, smy, cmx, cmy;
+
+    private final PolyStack reverse;
+
+    // This is where the curve to be processed is put. We give it
+    // enough room to store 2 curves: one for the current subdivision, the
+    // other for the rest of the curve.
+    private final float[] middle = new float[2 * 8];
+    private final float[] lp = new float[8];
+    private final float[] rp = new float[8];
+    private final float[] subdivTs = new float[MAX_N_CURVES - 1];
+
+    // per-thread renderer context
+    final RendererContext rdrCtx;
+
+    // dirty curve
+    final Curve curve;
+
+    /**
+     * Constructs a <code>Stroker</code>.
+     * @param rdrCtx per-thread renderer context
+     */
+    Stroker(final RendererContext rdrCtx) {
+        this.rdrCtx = rdrCtx;
+
+        this.reverse = new PolyStack(rdrCtx);
+        this.curve = rdrCtx.curve;
+    }
+
+    /**
+     * Inits the <code>Stroker</code>.
+     *
+     * @param pc2d an output <code>PathConsumer2D</code>.
+     * @param lineWidth the desired line width in pixels
+     * @param capStyle the desired end cap style, one of
+     * <code>CAP_BUTT</code>, <code>CAP_ROUND</code> or
+     * <code>CAP_SQUARE</code>.
+     * @param joinStyle the desired line join style, one of
+     * <code>JOIN_MITER</code>, <code>JOIN_ROUND</code> or
+     * <code>JOIN_BEVEL</code>.
+     * @param miterLimit the desired miter limit
+     * @return this instance
+     */
+    Stroker init(PathConsumer2D pc2d,
+              float lineWidth,
+              int capStyle,
+              int joinStyle,
+              float miterLimit)
+    {
+        this.out = pc2d;
+
+        this.lineWidth2 = lineWidth / 2f;
+        this.invHalfLineWidth2Sq = 1f / (2f * lineWidth2 * lineWidth2);
+        this.capStyle = capStyle;
+        this.joinStyle = joinStyle;
+
+        float limit = miterLimit * lineWidth2;
+        this.miterLimitSq = limit * limit;
+
+        this.prev = CLOSE;
+
+        rdrCtx.stroking = 1;
+
+        return this; // fluent API
+    }
+
+    /**
+     * Disposes this stroker:
+     * clean up before reusing this instance
+     */
+    void dispose() {
+        reverse.dispose();
+
+        if (DO_CLEAN_DIRTY) {
+            // Force zero-fill dirty arrays:
+            Arrays.fill(offset0, 0f);
+            Arrays.fill(offset1, 0f);
+            Arrays.fill(offset2, 0f);
+            Arrays.fill(miter, 0f);
+            Arrays.fill(middle, 0f);
+            Arrays.fill(lp, 0f);
+            Arrays.fill(rp, 0f);
+            Arrays.fill(subdivTs, 0f);
+        }
+    }
+
+    private static void computeOffset(final float lx, final float ly,
+                                      final float w, final float[] m)
+    {
+        float len = lx*lx + ly*ly;
+        if (len == 0f) {
+            m[0] = 0f;
+            m[1] = 0f;
+        } else {
+            len = (float) sqrt(len);
+            m[0] =  (ly * w) / len;
+            m[1] = -(lx * w) / len;
+        }
+    }
+
+    // Returns true if the vectors (dx1, dy1) and (dx2, dy2) are
+    // clockwise (if dx1,dy1 needs to be rotated clockwise to close
+    // the smallest angle between it and dx2,dy2).
+    // This is equivalent to detecting whether a point q is on the right side
+    // of a line passing through points p1, p2 where p2 = p1+(dx1,dy1) and
+    // q = p2+(dx2,dy2), which is the same as saying p1, p2, q are in a
+    // clockwise order.
+    // NOTE: "clockwise" here assumes coordinates with 0,0 at the bottom left.
+    private static boolean isCW(final float dx1, final float dy1,
+                                final float dx2, final float dy2)
+    {
+        return dx1 * dy2 <= dy1 * dx2;
+    }
+
+    private void drawRoundJoin(float x, float y,
+                               float omx, float omy, float mx, float my,
+                               boolean rev,
+                               float threshold)
+    {
+        if ((omx == 0f && omy == 0f) || (mx == 0f && my == 0f)) {
+            return;
+        }
+
+        float domx = omx - mx;
+        float domy = omy - my;
+        float len = domx*domx + domy*domy;
+        if (len < threshold) {
+            return;
+        }
+
+        if (rev) {
+            omx = -omx;
+            omy = -omy;
+            mx  = -mx;
+            my  = -my;
+        }
+        drawRoundJoin(x, y, omx, omy, mx, my, rev);
+    }
+
+    private void drawRoundJoin(float cx, float cy,
+                               float omx, float omy,
+                               float mx, float my,
+                               boolean rev)
+    {
+        // The sign of the dot product of mx,my and omx,omy is equal to the
+        // the sign of the cosine of ext
+        // (ext is the angle between omx,omy and mx,my).
+        final float cosext = omx * mx + omy * my;
+        // If it is >=0, we know that abs(ext) is <= 90 degrees, so we only
+        // need 1 curve to approximate the circle section that joins omx,omy
+        // and mx,my.
+        final int numCurves = (cosext >= 0f) ? 1 : 2;
+
+        switch (numCurves) {
+        case 1:
+            drawBezApproxForArc(cx, cy, omx, omy, mx, my, rev);
+            break;
+        case 2:
+            // we need to split the arc into 2 arcs spanning the same angle.
+            // The point we want will be one of the 2 intersections of the
+            // perpendicular bisector of the chord (omx,omy)->(mx,my) and the
+            // circle. We could find this by scaling the vector
+            // (omx+mx, omy+my)/2 so that it has length=lineWidth2 (and thus lies
+            // on the circle), but that can have numerical problems when the angle
+            // between omx,omy and mx,my is close to 180 degrees. So we compute a
+            // normal of (omx,omy)-(mx,my). This will be the direction of the
+            // perpendicular bisector. To get one of the intersections, we just scale
+            // this vector that its length is lineWidth2 (this works because the
+            // perpendicular bisector goes through the origin). This scaling doesn't
+            // have numerical problems because we know that lineWidth2 divided by
+            // this normal's length is at least 0.5 and at most sqrt(2)/2 (because
+            // we know the angle of the arc is > 90 degrees).
+            float nx = my - omy, ny = omx - mx;
+            float nlen = (float) sqrt(nx*nx + ny*ny);
+            float scale = lineWidth2/nlen;
+            float mmx = nx * scale, mmy = ny * scale;
+
+            // if (isCW(omx, omy, mx, my) != isCW(mmx, mmy, mx, my)) then we've
+            // computed the wrong intersection so we get the other one.
+            // The test above is equivalent to if (rev).
+            if (rev) {
+                mmx = -mmx;
+                mmy = -mmy;
+            }
+            drawBezApproxForArc(cx, cy, omx, omy, mmx, mmy, rev);
+            drawBezApproxForArc(cx, cy, mmx, mmy, mx, my, rev);
+            break;
+        default:
+        }
+    }
+
+    // the input arc defined by omx,omy and mx,my must span <= 90 degrees.
+    private void drawBezApproxForArc(final float cx, final float cy,
+                                     final float omx, final float omy,
+                                     final float mx, final float my,
+                                     boolean rev)
+    {
+        final float cosext2 = (omx * mx + omy * my) * invHalfLineWidth2Sq;
+
+        // check round off errors producing cos(ext) > 1 and a NaN below
+        // cos(ext) == 1 implies colinear segments and an empty join anyway
+        if (cosext2 >= 0.5f) {
+            // just return to avoid generating a flat curve:
+            return;
+        }
+
+        // cv is the length of P1-P0 and P2-P3 divided by the radius of the arc
+        // (so, cv assumes the arc has radius 1). P0, P1, P2, P3 are the points that
+        // define the bezier curve we're computing.
+        // It is computed using the constraints that P1-P0 and P3-P2 are parallel
+        // to the arc tangents at the endpoints, and that |P1-P0|=|P3-P2|.
+        float cv = (float) ((4.0 / 3.0) * sqrt(0.5 - cosext2) /
+                            (1.0 + sqrt(cosext2 + 0.5)));
+        // if clockwise, we need to negate cv.
+        if (rev) { // rev is equivalent to isCW(omx, omy, mx, my)
+            cv = -cv;
+        }
+        final float x1 = cx + omx;
+        final float y1 = cy + omy;
+        final float x2 = x1 - cv * omy;
+        final float y2 = y1 + cv * omx;
+
+        final float x4 = cx + mx;
+        final float y4 = cy + my;
+        final float x3 = x4 + cv * my;
+        final float y3 = y4 - cv * mx;
+
+        emitCurveTo(x1, y1, x2, y2, x3, y3, x4, y4, rev);
+    }
+
+    private void drawRoundCap(float cx, float cy, float mx, float my) {
+        final float Cmx = C * mx;
+        final float Cmy = C * my;
+        emitCurveTo(cx + mx - Cmy, cy + my + Cmx,
+                    cx - my + Cmx, cy + mx + Cmy,
+                    cx - my,       cy + mx);
+        emitCurveTo(cx - my - Cmx, cy + mx - Cmy,
+                    cx - mx - Cmy, cy - my + Cmx,
+                    cx - mx,       cy - my);
+    }
+
+    // Put the intersection point of the lines (x0, y0) -> (x1, y1)
+    // and (x0p, y0p) -> (x1p, y1p) in m[off] and m[off+1].
+    // If the lines are parallel, it will put a non finite number in m.
+    private static void computeIntersection(final float x0, final float y0,
+                                            final float x1, final float y1,
+                                            final float x0p, final float y0p,
+                                            final float x1p, final float y1p,
+                                            final float[] m, int off)
+    {
+        float x10 = x1 - x0;
+        float y10 = y1 - y0;
+        float x10p = x1p - x0p;
+        float y10p = y1p - y0p;
+
+        float den = x10*y10p - x10p*y10;
+        float t = x10p*(y0-y0p) - y10p*(x0-x0p);
+        t /= den;
+        m[off++] = x0 + t*x10;
+        m[off]   = y0 + t*y10;
+    }
+
+    private void drawMiter(final float pdx, final float pdy,
+                           final float x0, final float y0,
+                           final float dx, final float dy,
+                           float omx, float omy, float mx, float my,
+                           boolean rev)
+    {
+        if ((mx == omx && my == omy) ||
+            (pdx == 0f && pdy == 0f) ||
+            (dx == 0f && dy == 0f))
+        {
+            return;
+        }
+
+        if (rev) {
+            omx = -omx;
+            omy = -omy;
+            mx  = -mx;
+            my  = -my;
+        }
+
+        computeIntersection((x0 - pdx) + omx, (y0 - pdy) + omy, x0 + omx, y0 + omy,
+                            (dx + x0) + mx, (dy + y0) + my, x0 + mx, y0 + my,
+                            miter, 0);
+
+        final float miterX = miter[0];
+        final float miterY = miter[1];
+        float lenSq = (miterX-x0)*(miterX-x0) + (miterY-y0)*(miterY-y0);
+
+        // If the lines are parallel, lenSq will be either NaN or +inf
+        // (actually, I'm not sure if the latter is possible. The important
+        // thing is that -inf is not possible, because lenSq is a square).
+        // For both of those values, the comparison below will fail and
+        // no miter will be drawn, which is correct.
+        if (lenSq < miterLimitSq) {
+            emitLineTo(miterX, miterY, rev);
+        }
+    }
+
+    @Override
+    public void moveTo(float x0, float y0) {
+        if (prev == DRAWING_OP_TO) {
+            finish();
+        }
+        this.sx0 = this.cx0 = x0;
+        this.sy0 = this.cy0 = y0;
+        this.cdx = this.sdx = 1f;
+        this.cdy = this.sdy = 0f;
+        this.prev = MOVE_TO;
+    }
+
+    @Override
+    public void lineTo(float x1, float y1) {
+        float dx = x1 - cx0;
+        float dy = y1 - cy0;
+        if (dx == 0f && dy == 0f) {
+            dx = 1f;
+        }
+        computeOffset(dx, dy, lineWidth2, offset0);
+        final float mx = offset0[0];
+        final float my = offset0[1];
+
+        drawJoin(cdx, cdy, cx0, cy0, dx, dy, cmx, cmy, mx, my);
+
+        emitLineTo(cx0 + mx, cy0 + my);
+        emitLineTo( x1 + mx,  y1 + my);
+
+        emitLineToRev(cx0 - mx, cy0 - my);
+        emitLineToRev( x1 - mx,  y1 - my);
+
+        this.cmx = mx;
+        this.cmy = my;
+        this.cdx = dx;
+        this.cdy = dy;
+        this.cx0 = x1;
+        this.cy0 = y1;
+        this.prev = DRAWING_OP_TO;
+    }
+
+    @Override
+    public void closePath() {
+        if (prev != DRAWING_OP_TO) {
+            if (prev == CLOSE) {
+                return;
+            }
+            emitMoveTo(cx0, cy0 - lineWidth2);
+            this.cmx = this.smx = 0f;
+            this.cmy = this.smy = -lineWidth2;
+            this.cdx = this.sdx = 1f;
+            this.cdy = this.sdy = 0f;
+            finish();
+            return;
+        }
+
+        if (cx0 != sx0 || cy0 != sy0) {
+            lineTo(sx0, sy0);
+        }
+
+        drawJoin(cdx, cdy, cx0, cy0, sdx, sdy, cmx, cmy, smx, smy);
+
+        emitLineTo(sx0 + smx, sy0 + smy);
+
+        emitMoveTo(sx0 - smx, sy0 - smy);
+        emitReverse();
+
+        this.prev = CLOSE;
+        emitClose();
+    }
+
+    private void emitReverse() {
+        reverse.popAll(out);
+    }
+
+    @Override
+    public void pathDone() {
+        if (prev == DRAWING_OP_TO) {
+            finish();
+        }
+
+        out.pathDone();
+
+        // this shouldn't matter since this object won't be used
+        // after the call to this method.
+        this.prev = CLOSE;
+
+        // Dispose this instance:
+        dispose();
+    }
+
+    private void finish() {
+        if (capStyle == CAP_ROUND) {
+            drawRoundCap(cx0, cy0, cmx, cmy);
+        } else if (capStyle == CAP_SQUARE) {
+            emitLineTo(cx0 - cmy + cmx, cy0 + cmx + cmy);
+            emitLineTo(cx0 - cmy - cmx, cy0 + cmx - cmy);
+        }
+
+        emitReverse();
+
+        if (capStyle == CAP_ROUND) {
+            drawRoundCap(sx0, sy0, -smx, -smy);
+        } else if (capStyle == CAP_SQUARE) {
+            emitLineTo(sx0 + smy - smx, sy0 - smx - smy);
+            emitLineTo(sx0 + smy + smx, sy0 - smx + smy);
+        }
+
+        emitClose();
+    }
+
+    private void emitMoveTo(final float x0, final float y0) {
+        out.moveTo(x0, y0);
+    }
+
+    private void emitLineTo(final float x1, final float y1) {
+        out.lineTo(x1, y1);
+    }
+
+    private void emitLineToRev(final float x1, final float y1) {
+        reverse.pushLine(x1, y1);
+    }
+
+    private void emitLineTo(final float x1, final float y1,
+                            final boolean rev)
+    {
+        if (rev) {
+            emitLineToRev(x1, y1);
+        } else {
+            emitLineTo(x1, y1);
+        }
+    }
+
+    private void emitQuadTo(final float x1, final float y1,
+                            final float x2, final float y2)
+    {
+        out.quadTo(x1, y1, x2, y2);
+    }
+
+    private void emitQuadToRev(final float x0, final float y0,
+                               final float x1, final float y1)
+    {
+        reverse.pushQuad(x0, y0, x1, y1);
+    }
+
+    private void emitCurveTo(final float x1, final float y1,
+                             final float x2, final float y2,
+                             final float x3, final float y3)
+    {
+        out.curveTo(x1, y1, x2, y2, x3, y3);
+    }
+
+    private void emitCurveToRev(final float x0, final float y0,
+                                final float x1, final float y1,
+                                final float x2, final float y2)
+    {
+        reverse.pushCubic(x0, y0, x1, y1, x2, y2);
+    }
+
+    private void emitCurveTo(final float x0, final float y0,
+                             final float x1, final float y1,
+                             final float x2, final float y2,
+                             final float x3, final float y3, final boolean rev)
+    {
+        if (rev) {
+            reverse.pushCubic(x0, y0, x1, y1, x2, y2);
+        } else {
+            out.curveTo(x1, y1, x2, y2, x3, y3);
+        }
+    }
+
+    private void emitClose() {
+        out.closePath();
+    }
+
+    private void drawJoin(float pdx, float pdy,
+                          float x0, float y0,
+                          float dx, float dy,
+                          float omx, float omy,
+                          float mx, float my)
+    {
+        if (prev != DRAWING_OP_TO) {
+            emitMoveTo(x0 + mx, y0 + my);
+            this.sdx = dx;
+            this.sdy = dy;
+            this.smx = mx;
+            this.smy = my;
+        } else {
+            boolean cw = isCW(pdx, pdy, dx, dy);
+            if (joinStyle == JOIN_MITER) {
+                drawMiter(pdx, pdy, x0, y0, dx, dy, omx, omy, mx, my, cw);
+            } else if (joinStyle == JOIN_ROUND) {
+                drawRoundJoin(x0, y0,
+                              omx, omy,
+                              mx, my, cw,
+                              ROUND_JOIN_THRESHOLD);
+            }
+            emitLineTo(x0, y0, !cw);
+        }
+        prev = DRAWING_OP_TO;
+    }
+
+    private static boolean within(final float x1, final float y1,
+                                  final float x2, final float y2,
+                                  final float ERR)
+    {
+        assert ERR > 0 : "";
+        // compare taxicab distance. ERR will always be small, so using
+        // true distance won't give much benefit
+        return (Helpers.within(x1, x2, ERR) &&  // we want to avoid calling Math.abs
+                Helpers.within(y1, y2, ERR)); // this is just as good.
+    }
+
+    private void getLineOffsets(float x1, float y1,
+                                float x2, float y2,
+                                float[] left, float[] right) {
+        computeOffset(x2 - x1, y2 - y1, lineWidth2, offset0);
+        final float mx = offset0[0];
+        final float my = offset0[1];
+        left[0] = x1 + mx;
+        left[1] = y1 + my;
+        left[2] = x2 + mx;
+        left[3] = y2 + my;
+        right[0] = x1 - mx;
+        right[1] = y1 - my;
+        right[2] = x2 - mx;
+        right[3] = y2 - my;
+    }
+
+    private int computeOffsetCubic(float[] pts, final int off,
+                                   float[] leftOff, float[] rightOff)
+    {
+        // if p1=p2 or p3=p4 it means that the derivative at the endpoint
+        // vanishes, which creates problems with computeOffset. Usually
+        // this happens when this stroker object is trying to winden
+        // a curve with a cusp. What happens is that curveTo splits
+        // the input curve at the cusp, and passes it to this function.
+        // because of inaccuracies in the splitting, we consider points
+        // equal if they're very close to each other.
+        final float x1 = pts[off + 0], y1 = pts[off + 1];
+        final float x2 = pts[off + 2], y2 = pts[off + 3];
+        final float x3 = pts[off + 4], y3 = pts[off + 5];
+        final float x4 = pts[off + 6], y4 = pts[off + 7];
+
+        float dx4 = x4 - x3;
+        float dy4 = y4 - y3;
+        float dx1 = x2 - x1;
+        float dy1 = y2 - y1;
+
+        // if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
+        // in which case ignore if p1 == p2
+        final boolean p1eqp2 = within(x1,y1,x2,y2, 6f * ulp(y2));
+        final boolean p3eqp4 = within(x3,y3,x4,y4, 6f * ulp(y4));
+        if (p1eqp2 && p3eqp4) {
+            getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
+            return 4;
+        } else if (p1eqp2) {
+            dx1 = x3 - x1;
+            dy1 = y3 - y1;
+        } else if (p3eqp4) {
+            dx4 = x4 - x2;
+            dy4 = y4 - y2;
+        }
+
+        // if p2-p1 and p4-p3 are parallel, that must mean this curve is a line
+        float dotsq = (dx1 * dx4 + dy1 * dy4);
+        dotsq *= dotsq;
+        float l1sq = dx1 * dx1 + dy1 * dy1, l4sq = dx4 * dx4 + dy4 * dy4;
+        if (Helpers.within(dotsq, l1sq * l4sq, 4f * ulp(dotsq))) {
+            getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
+            return 4;
+        }
+
+//      What we're trying to do in this function is to approximate an ideal
+//      offset curve (call it I) of the input curve B using a bezier curve Bp.
+//      The constraints I use to get the equations are:
+//
+//      1. The computed curve Bp should go through I(0) and I(1). These are
+//      x1p, y1p, x4p, y4p, which are p1p and p4p. We still need to find
+//      4 variables: the x and y components of p2p and p3p (i.e. x2p, y2p, x3p, y3p).
+//
+//      2. Bp should have slope equal in absolute value to I at the endpoints. So,
+//      (by the way, the operator || in the comments below means "aligned with".
+//      It is defined on vectors, so when we say I'(0) || Bp'(0) we mean that
+//      vectors I'(0) and Bp'(0) are aligned, which is the same as saying
+//      that the tangent lines of I and Bp at 0 are parallel. Mathematically
+//      this means (I'(t) || Bp'(t)) <==> (I'(t) = c * Bp'(t)) where c is some
+//      nonzero constant.)
+//      I'(0) || Bp'(0) and I'(1) || Bp'(1). Obviously, I'(0) || B'(0) and
+//      I'(1) || B'(1); therefore, Bp'(0) || B'(0) and Bp'(1) || B'(1).
+//      We know that Bp'(0) || (p2p-p1p) and Bp'(1) || (p4p-p3p) and the same
+//      is true for any bezier curve; therefore, we get the equations
+//          (1) p2p = c1 * (p2-p1) + p1p
+//          (2) p3p = c2 * (p4-p3) + p4p
+//      We know p1p, p4p, p2, p1, p3, and p4; therefore, this reduces the number
+//      of unknowns from 4 to 2 (i.e. just c1 and c2).
+//      To eliminate these 2 unknowns we use the following constraint:
+//
+//      3. Bp(0.5) == I(0.5). Bp(0.5)=(x,y) and I(0.5)=(xi,yi), and I should note
+//      that I(0.5) is *the only* reason for computing dxm,dym. This gives us
+//          (3) Bp(0.5) = (p1p + 3 * (p2p + p3p) + p4p)/8, which is equivalent to
+//          (4) p2p + p3p = (Bp(0.5)*8 - p1p - p4p) / 3
+//      We can substitute (1) and (2) from above into (4) and we get:
+//          (5) c1*(p2-p1) + c2*(p4-p3) = (Bp(0.5)*8 - p1p - p4p)/3 - p1p - p4p
+//      which is equivalent to
+//          (6) c1*(p2-p1) + c2*(p4-p3) = (4/3) * (Bp(0.5) * 2 - p1p - p4p)
+//
+//      The right side of this is a 2D vector, and we know I(0.5), which gives us
+//      Bp(0.5), which gives us the value of the right side.
+//      The left side is just a matrix vector multiplication in disguise. It is
+//
+//      [x2-x1, x4-x3][c1]
+//      [y2-y1, y4-y3][c2]
+//      which, is equal to
+//      [dx1, dx4][c1]
+//      [dy1, dy4][c2]
+//      At this point we are left with a simple linear system and we solve it by
+//      getting the inverse of the matrix above. Then we use [c1,c2] to compute
+//      p2p and p3p.
+
+        float x = (x1 + 3f * (x2 + x3) + x4) / 8f;
+        float y = (y1 + 3f * (y2 + y3) + y4) / 8f;
+        // (dxm,dym) is some tangent of B at t=0.5. This means it's equal to
+        // c*B'(0.5) for some constant c.
+        float dxm = x3 + x4 - x1 - x2, dym = y3 + y4 - y1 - y2;
+
+        // this computes the offsets at t=0, 0.5, 1, using the property that
+        // for any bezier curve the vectors p2-p1 and p4-p3 are parallel to
+        // the (dx/dt, dy/dt) vectors at the endpoints.
+        computeOffset(dx1, dy1, lineWidth2, offset0);
+        computeOffset(dxm, dym, lineWidth2, offset1);
+        computeOffset(dx4, dy4, lineWidth2, offset2);
+        float x1p = x1 + offset0[0]; // start
+        float y1p = y1 + offset0[1]; // point
+        float xi  = x  + offset1[0]; // interpolation
+        float yi  = y  + offset1[1]; // point
+        float x4p = x4 + offset2[0]; // end
+        float y4p = y4 + offset2[1]; // point
+
+        float invdet43 = 4f / (3f * (dx1 * dy4 - dy1 * dx4));
+
+        float two_pi_m_p1_m_p4x = 2f * xi - x1p - x4p;
+        float two_pi_m_p1_m_p4y = 2f * yi - y1p - y4p;
+        float c1 = invdet43 * (dy4 * two_pi_m_p1_m_p4x - dx4 * two_pi_m_p1_m_p4y);
+        float c2 = invdet43 * (dx1 * two_pi_m_p1_m_p4y - dy1 * two_pi_m_p1_m_p4x);
+
+        float x2p, y2p, x3p, y3p;
+        x2p = x1p + c1*dx1;
+        y2p = y1p + c1*dy1;
+        x3p = x4p + c2*dx4;
+        y3p = y4p + c2*dy4;
+
+        leftOff[0] = x1p; leftOff[1] = y1p;
+        leftOff[2] = x2p; leftOff[3] = y2p;
+        leftOff[4] = x3p; leftOff[5] = y3p;
+        leftOff[6] = x4p; leftOff[7] = y4p;
+
+        x1p = x1 - offset0[0]; y1p = y1 - offset0[1];
+        xi = xi - 2f * offset1[0]; yi = yi - 2f * offset1[1];
+        x4p = x4 - offset2[0]; y4p = y4 - offset2[1];
+
+        two_pi_m_p1_m_p4x = 2f * xi - x1p - x4p;
+        two_pi_m_p1_m_p4y = 2f * yi - y1p - y4p;
+        c1 = invdet43 * (dy4 * two_pi_m_p1_m_p4x - dx4 * two_pi_m_p1_m_p4y);
+        c2 = invdet43 * (dx1 * two_pi_m_p1_m_p4y - dy1 * two_pi_m_p1_m_p4x);
+
+        x2p = x1p + c1*dx1;
+        y2p = y1p + c1*dy1;
+        x3p = x4p + c2*dx4;
+        y3p = y4p + c2*dy4;
+
+        rightOff[0] = x1p; rightOff[1] = y1p;
+        rightOff[2] = x2p; rightOff[3] = y2p;
+        rightOff[4] = x3p; rightOff[5] = y3p;
+        rightOff[6] = x4p; rightOff[7] = y4p;
+        return 8;
+    }
+
+    // return the kind of curve in the right and left arrays.
+    private int computeOffsetQuad(float[] pts, final int off,
+                                  float[] leftOff, float[] rightOff)
+    {
+        final float x1 = pts[off + 0], y1 = pts[off + 1];
+        final float x2 = pts[off + 2], y2 = pts[off + 3];
+        final float x3 = pts[off + 4], y3 = pts[off + 5];
+
+        final float dx3 = x3 - x2;
+        final float dy3 = y3 - y2;
+        final float dx1 = x2 - x1;
+        final float dy1 = y2 - y1;
+
+        // this computes the offsets at t = 0, 1
+        computeOffset(dx1, dy1, lineWidth2, offset0);
+        computeOffset(dx3, dy3, lineWidth2, offset1);
+
+        leftOff[0]  = x1 + offset0[0]; leftOff[1]  = y1 + offset0[1];
+        leftOff[4]  = x3 + offset1[0]; leftOff[5]  = y3 + offset1[1];
+        rightOff[0] = x1 - offset0[0]; rightOff[1] = y1 - offset0[1];
+        rightOff[4] = x3 - offset1[0]; rightOff[5] = y3 - offset1[1];
+
+        float x1p = leftOff[0]; // start
+        float y1p = leftOff[1]; // point
+        float x3p = leftOff[4]; // end
+        float y3p = leftOff[5]; // point
+
+        // Corner cases:
+        // 1. If the two control vectors are parallel, we'll end up with NaN's
+        //    in leftOff (and rightOff in the body of the if below), so we'll
+        //    do getLineOffsets, which is right.
+        // 2. If the first or second two points are equal, then (dx1,dy1)==(0,0)
+        //    or (dx3,dy3)==(0,0), so (x1p, y1p)==(x1p+dx1, y1p+dy1)
+        //    or (x3p, y3p)==(x3p-dx3, y3p-dy3), which means that
+        //    computeIntersection will put NaN's in leftOff and right off, and
+        //    we will do getLineOffsets, which is right.
+        computeIntersection(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, leftOff, 2);
+        float cx = leftOff[2];
+        float cy = leftOff[3];
+
+        if (!(isFinite(cx) && isFinite(cy))) {
+            // maybe the right path is not degenerate.
+            x1p = rightOff[0];
+            y1p = rightOff[1];
+            x3p = rightOff[4];
+            y3p = rightOff[5];
+            computeIntersection(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, rightOff, 2);
+            cx = rightOff[2];
+            cy = rightOff[3];
+            if (!(isFinite(cx) && isFinite(cy))) {
+                // both are degenerate. This curve is a line.
+                getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
+                return 4;
+            }
+            // {left,right}Off[0,1,4,5] are already set to the correct values.
+            leftOff[2] = 2f * x2 - cx;
+            leftOff[3] = 2f * y2 - cy;
+            return 6;
+        }
+
+        // rightOff[2,3] = (x2,y2) - ((left_x2, left_y2) - (x2, y2))
+        // == 2*(x2, y2) - (left_x2, left_y2)
+        rightOff[2] = 2f * x2 - cx;
+        rightOff[3] = 2f * y2 - cy;
+        return 6;
+    }
+
+    private static boolean isFinite(float x) {
+        return (Float.NEGATIVE_INFINITY < x && x < Float.POSITIVE_INFINITY);
+    }
+
+    // If this class is compiled with ecj, then Hotspot crashes when OSR
+    // compiling this function. See bugs 7004570 and 6675699
+    // TODO: until those are fixed, we should work around that by
+    // manually inlining this into curveTo and quadTo.
+/******************************* WORKAROUND **********************************
+    private void somethingTo(final int type) {
+        // need these so we can update the state at the end of this method
+        final float xf = middle[type-2], yf = middle[type-1];
+        float dxs = middle[2] - middle[0];
+        float dys = middle[3] - middle[1];
+        float dxf = middle[type - 2] - middle[type - 4];
+        float dyf = middle[type - 1] - middle[type - 3];
+        switch(type) {
+        case 6:
+            if ((dxs == 0f && dys == 0f) ||
+                (dxf == 0f && dyf == 0f)) {
+               dxs = dxf = middle[4] - middle[0];
+               dys = dyf = middle[5] - middle[1];
+            }
+            break;
+        case 8:
+            boolean p1eqp2 = (dxs == 0f && dys == 0f);
+            boolean p3eqp4 = (dxf == 0f && dyf == 0f);
+            if (p1eqp2) {
+                dxs = middle[4] - middle[0];
+                dys = middle[5] - middle[1];
+                if (dxs == 0f && dys == 0f) {
+                    dxs = middle[6] - middle[0];
+                    dys = middle[7] - middle[1];
+                }
+            }
+            if (p3eqp4) {
+                dxf = middle[6] - middle[2];
+                dyf = middle[7] - middle[3];
+                if (dxf == 0f && dyf == 0f) {
+                    dxf = middle[6] - middle[0];
+                    dyf = middle[7] - middle[1];
+                }
+            }
+        }
+        if (dxs == 0f && dys == 0f) {
+            // this happens iff the "curve" is just a point
+            lineTo(middle[0], middle[1]);
+            return;
+        }
+        // if these vectors are too small, normalize them, to avoid future
+        // precision problems.
+        if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
+            float len = (float) sqrt(dxs*dxs + dys*dys);
+            dxs /= len;
+            dys /= len;
+        }
+        if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
+            float len = (float) sqrt(dxf*dxf + dyf*dyf);
+            dxf /= len;
+            dyf /= len;
+        }
+
+        computeOffset(dxs, dys, lineWidth2, offset0);
+        final float mx = offset0[0];
+        final float my = offset0[1];
+        drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, mx, my);
+
+        int nSplits = findSubdivPoints(curve, middle, subdivTs, type, lineWidth2);
+
+        int kind = 0;
+        BreakPtrIterator it = curve.breakPtsAtTs(middle, type, subdivTs, nSplits);
+        while(it.hasNext()) {
+            int curCurveOff = it.next();
+
+            switch (type) {
+            case 8:
+                kind = computeOffsetCubic(middle, curCurveOff, lp, rp);
+                break;
+            case 6:
+                kind = computeOffsetQuad(middle, curCurveOff, lp, rp);
+                break;
+            }
+            emitLineTo(lp[0], lp[1]);
+            switch(kind) {
+            case 8:
+                emitCurveTo(lp[2], lp[3], lp[4], lp[5], lp[6], lp[7]);
+                emitCurveToRev(rp[0], rp[1], rp[2], rp[3], rp[4], rp[5]);
+                break;
+            case 6:
+                emitQuadTo(lp[2], lp[3], lp[4], lp[5]);
+                emitQuadToRev(rp[0], rp[1], rp[2], rp[3]);
+                break;
+            case 4:
+                emitLineTo(lp[2], lp[3]);
+                emitLineTo(rp[0], rp[1], true);
+                break;
+            }
+            emitLineTo(rp[kind - 2], rp[kind - 1], true);
+        }
+
+        this.cmx = (lp[kind - 2] - rp[kind - 2]) / 2;
+        this.cmy = (lp[kind - 1] - rp[kind - 1]) / 2;
+        this.cdx = dxf;
+        this.cdy = dyf;
+        this.cx0 = xf;
+        this.cy0 = yf;
+        this.prev = DRAWING_OP_TO;
+    }
+****************************** END WORKAROUND *******************************/
+
+    // finds values of t where the curve in pts should be subdivided in order
+    // to get good offset curves a distance of w away from the middle curve.
+    // Stores the points in ts, and returns how many of them there were.
+    private static int findSubdivPoints(final Curve c, float[] pts, float[] ts,
+                                        final int type, final float w)
+    {
+        final float x12 = pts[2] - pts[0];
+        final float y12 = pts[3] - pts[1];
+        // if the curve is already parallel to either axis we gain nothing
+        // from rotating it.
+        if (y12 != 0f && x12 != 0f) {
+            // we rotate it so that the first vector in the control polygon is
+            // parallel to the x-axis. This will ensure that rotated quarter
+            // circles won't be subdivided.
+            final float hypot = (float) sqrt(x12 * x12 + y12 * y12);
+            final float cos = x12 / hypot;
+            final float sin = y12 / hypot;
+            final float x1 = cos * pts[0] + sin * pts[1];
+            final float y1 = cos * pts[1] - sin * pts[0];
+            final float x2 = cos * pts[2] + sin * pts[3];
+            final float y2 = cos * pts[3] - sin * pts[2];
+            final float x3 = cos * pts[4] + sin * pts[5];
+            final float y3 = cos * pts[5] - sin * pts[4];
+
+            switch(type) {
+            case 8:
+                final float x4 = cos * pts[6] + sin * pts[7];
+                final float y4 = cos * pts[7] - sin * pts[6];
+                c.set(x1, y1, x2, y2, x3, y3, x4, y4);
+                break;
+            case 6:
+                c.set(x1, y1, x2, y2, x3, y3);
+                break;
+            default:
+            }
+        } else {
+            c.set(pts, type);
+        }
+
+        int ret = 0;
+        // we subdivide at values of t such that the remaining rotated
+        // curves are monotonic in x and y.
+        ret += c.dxRoots(ts, ret);
+        ret += c.dyRoots(ts, ret);
+        // subdivide at inflection points.
+        if (type == 8) {
+            // quadratic curves can't have inflection points
+            ret += c.infPoints(ts, ret);
+        }
+
+        // now we must subdivide at points where one of the offset curves will have
+        // a cusp. This happens at ts where the radius of curvature is equal to w.
+        ret += c.rootsOfROCMinusW(ts, ret, w, 0.0001f);
+
+        ret = Helpers.filterOutNotInAB(ts, 0, ret, 0.0001f, 0.9999f);
+        Helpers.isort(ts, 0, ret);
+        return ret;
+    }
+
+    @Override public void curveTo(float x1, float y1,
+                                  float x2, float y2,
+                                  float x3, float y3)
+    {
+        final float[] mid = middle;
+
+        mid[0] = cx0; mid[1] = cy0;
+        mid[2] = x1;  mid[3] = y1;
+        mid[4] = x2;  mid[5] = y2;
+        mid[6] = x3;  mid[7] = y3;
+
+        // inlined version of somethingTo(8);
+        // See the TODO on somethingTo
+
+        // need these so we can update the state at the end of this method
+        final float xf = mid[6], yf = mid[7];
+        float dxs = mid[2] - mid[0];
+        float dys = mid[3] - mid[1];
+        float dxf = mid[6] - mid[4];
+        float dyf = mid[7] - mid[5];
+
+        boolean p1eqp2 = (dxs == 0f && dys == 0f);
+        boolean p3eqp4 = (dxf == 0f && dyf == 0f);
+        if (p1eqp2) {
+            dxs = mid[4] - mid[0];
+            dys = mid[5] - mid[1];
+            if (dxs == 0f && dys == 0f) {
+                dxs = mid[6] - mid[0];
+                dys = mid[7] - mid[1];
+            }
+        }
+        if (p3eqp4) {
+            dxf = mid[6] - mid[2];
+            dyf = mid[7] - mid[3];
+            if (dxf == 0f && dyf == 0f) {
+                dxf = mid[6] - mid[0];
+                dyf = mid[7] - mid[1];
+            }
+        }
+        if (dxs == 0f && dys == 0f) {
+            // this happens if the "curve" is just a point
+            lineTo(mid[0], mid[1]);
+            return;
+        }
+
+        // if these vectors are too small, normalize them, to avoid future
+        // precision problems.
+        if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
+            float len = (float) sqrt(dxs*dxs + dys*dys);
+            dxs /= len;
+            dys /= len;
+        }
+        if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
+            float len = (float) sqrt(dxf*dxf + dyf*dyf);
+            dxf /= len;
+            dyf /= len;
+        }
+
+        computeOffset(dxs, dys, lineWidth2, offset0);
+        drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, offset0[0], offset0[1]);
+
+        int nSplits = findSubdivPoints(curve, mid, subdivTs, 8, lineWidth2);
+
+        final float[] l = lp;
+        final float[] r = rp;
+
+        int kind = 0;
+        BreakPtrIterator it = curve.breakPtsAtTs(mid, 8, subdivTs, nSplits);
+        while(it.hasNext()) {
+            int curCurveOff = it.next();
+
+            kind = computeOffsetCubic(mid, curCurveOff, l, r);
+            emitLineTo(l[0], l[1]);
+
+            switch(kind) {
+            case 8:
+                emitCurveTo(l[2], l[3], l[4], l[5], l[6], l[7]);
+                emitCurveToRev(r[0], r[1], r[2], r[3], r[4], r[5]);
+                break;
+            case 4:
+                emitLineTo(l[2], l[3]);
+                emitLineToRev(r[0], r[1]);
+                break;
+            default:
+            }
+            emitLineToRev(r[kind - 2], r[kind - 1]);
+        }
+
+        this.cmx = (l[kind - 2] - r[kind - 2]) / 2f;
+        this.cmy = (l[kind - 1] - r[kind - 1]) / 2f;
+        this.cdx = dxf;
+        this.cdy = dyf;
+        this.cx0 = xf;
+        this.cy0 = yf;
+        this.prev = DRAWING_OP_TO;
+    }
+
+    @Override public void quadTo(float x1, float y1, float x2, float y2) {
+        final float[] mid = middle;
+
+        mid[0] = cx0; mid[1] = cy0;
+        mid[2] = x1;  mid[3] = y1;
+        mid[4] = x2;  mid[5] = y2;
+
+        // inlined version of somethingTo(8);
+        // See the TODO on somethingTo
+
+        // need these so we can update the state at the end of this method
+        final float xf = mid[4], yf = mid[5];
+        float dxs = mid[2] - mid[0];
+        float dys = mid[3] - mid[1];
+        float dxf = mid[4] - mid[2];
+        float dyf = mid[5] - mid[3];
+        if ((dxs == 0f && dys == 0f) || (dxf == 0f && dyf == 0f)) {
+            dxs = dxf = mid[4] - mid[0];
+            dys = dyf = mid[5] - mid[1];
+        }
+        if (dxs == 0f && dys == 0f) {
+            // this happens if the "curve" is just a point
+            lineTo(mid[0], mid[1]);
+            return;
+        }
+        // if these vectors are too small, normalize them, to avoid future
+        // precision problems.
+        if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
+            float len = (float) sqrt(dxs*dxs + dys*dys);
+            dxs /= len;
+            dys /= len;
+        }
+        if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
+            float len = (float) sqrt(dxf*dxf + dyf*dyf);
+            dxf /= len;
+            dyf /= len;
+        }
+
+        computeOffset(dxs, dys, lineWidth2, offset0);
+        drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, offset0[0], offset0[1]);
+
+        int nSplits = findSubdivPoints(curve, mid, subdivTs, 6, lineWidth2);
+
+        final float[] l = lp;
+        final float[] r = rp;
+
+        int kind = 0;
+        BreakPtrIterator it = curve.breakPtsAtTs(mid, 6, subdivTs, nSplits);
+        while(it.hasNext()) {
+            int curCurveOff = it.next();
+
+            kind = computeOffsetQuad(mid, curCurveOff, l, r);
+            emitLineTo(l[0], l[1]);
+
+            switch(kind) {
+            case 6:
+                emitQuadTo(l[2], l[3], l[4], l[5]);
+                emitQuadToRev(r[0], r[1], r[2], r[3]);
+                break;
+            case 4:
+                emitLineTo(l[2], l[3]);
+                emitLineToRev(r[0], r[1]);
+                break;
+            default:
+            }
+            emitLineToRev(r[kind - 2], r[kind - 1]);
+        }
+
+        this.cmx = (l[kind - 2] - r[kind - 2]) / 2f;
+        this.cmy = (l[kind - 1] - r[kind - 1]) / 2f;
+        this.cdx = dxf;
+        this.cdy = dyf;
+        this.cx0 = xf;
+        this.cy0 = yf;
+        this.prev = DRAWING_OP_TO;
+    }
+
+    @Override public long getNativeConsumer() {
+        throw new InternalError("Stroker doesn't use a native consumer");
+    }
+
+    // a stack of polynomial curves where each curve shares endpoints with
+    // adjacent ones.
+    static final class PolyStack {
+        private static final byte TYPE_LINETO  = (byte) 0;
+        private static final byte TYPE_QUADTO  = (byte) 1;
+        private static final byte TYPE_CUBICTO = (byte) 2;
+
+        float[] curves;
+        int end;
+        byte[] curveTypes;
+        int numCurves;
+
+        // per-thread renderer context
+        final RendererContext rdrCtx;
+
+        // per-thread initial arrays (large enough to satisfy most usages: 8192)
+        // +1 to avoid recycling in Helpers.widenArray()
+        private final float[] curves_initial = new float[INITIAL_LARGE_ARRAY + 1]; // 32K
+        private final byte[] curveTypes_initial = new byte[INITIAL_LARGE_ARRAY + 1]; // 8K
+
+        // used marks (stats only)
+        int curveTypesUseMark;
+        int curvesUseMark;
+
+        /**
+         * Constructor
+         * @param rdrCtx per-thread renderer context
+         */
+        PolyStack(final RendererContext rdrCtx) {
+            this.rdrCtx = rdrCtx;
+
+            curves = curves_initial;
+            curveTypes = curveTypes_initial;
+            end = 0;
+            numCurves = 0;
+
+            if (DO_STATS) {
+                curveTypesUseMark = 0;
+                curvesUseMark = 0;
+            }
+        }
+
+        /**
+         * Disposes this PolyStack:
+         * clean up before reusing this instance
+         */
+        void dispose() {
+            end = 0;
+            numCurves = 0;
+
+            if (DO_STATS) {
+                rdrCtx.stats.stat_rdr_poly_stack_types
+                    .add(curveTypesUseMark);
+                rdrCtx.stats.stat_rdr_poly_stack_curves
+                    .add(curvesUseMark);
+                // reset marks
+                curveTypesUseMark = 0;
+                curvesUseMark = 0;
+            }
+
+            // Return arrays:
+            // curves and curveTypes are kept dirty
+            if (curves != curves_initial) {
+                rdrCtx.putDirtyFloatArray(curves);
+                curves = curves_initial;
+            }
+
+            if (curveTypes != curveTypes_initial) {
+                rdrCtx.putDirtyByteArray(curveTypes);
+                curveTypes = curveTypes_initial;
+            }
+        }
+
+        private void ensureSpace(final int n) {
+            // use substraction to avoid integer overflow:
+            if (curves.length - end < n) {
+                if (DO_STATS) {
+                    rdrCtx.stats.stat_array_stroker_polystack_curves
+                        .add(end + n);
+                }
+                curves = rdrCtx.widenDirtyFloatArray(curves, end, end + n);
+            }
+            if (curveTypes.length <= numCurves) {
+                if (DO_STATS) {
+                    rdrCtx.stats.stat_array_stroker_polystack_curveTypes
+                        .add(numCurves + 1);
+                }
+                curveTypes = rdrCtx.widenDirtyByteArray(curveTypes,
+                                                        numCurves,
+                                                        numCurves + 1);
+            }
+        }
+
+        void pushCubic(float x0, float y0,
+                       float x1, float y1,
+                       float x2, float y2)
+        {
+            ensureSpace(6);
+            curveTypes[numCurves++] = TYPE_CUBICTO;
+            // we reverse the coordinate order to make popping easier
+            final float[] _curves = curves;
+            int e = end;
+            _curves[e++] = x2;    _curves[e++] = y2;
+            _curves[e++] = x1;    _curves[e++] = y1;
+            _curves[e++] = x0;    _curves[e++] = y0;
+            end = e;
+        }
+
+        void pushQuad(float x0, float y0,
+                      float x1, float y1)
+        {
+            ensureSpace(4);
+            curveTypes[numCurves++] = TYPE_QUADTO;
+            final float[] _curves = curves;
+            int e = end;
+            _curves[e++] = x1;    _curves[e++] = y1;
+            _curves[e++] = x0;    _curves[e++] = y0;
+            end = e;
+        }
+
+        void pushLine(float x, float y) {
+            ensureSpace(2);
+            curveTypes[numCurves++] = TYPE_LINETO;
+            curves[end++] = x;    curves[end++] = y;
+        }
+
+        void popAll(PathConsumer2D io) {
+            if (DO_STATS) {
+                // update used marks:
+                if (numCurves > curveTypesUseMark) {
+                    curveTypesUseMark = numCurves;
+                }
+                if (end > curvesUseMark) {
+                    curvesUseMark = end;
+                }
+            }
+            final byte[]  _curveTypes = curveTypes;
+            final float[] _curves = curves;
+            int nc = numCurves;
+            int e  = end;
+
+            while (nc != 0) {
+                switch(_curveTypes[--nc]) {
+                case TYPE_LINETO:
+                    e -= 2;
+                    io.lineTo(_curves[e], _curves[e+1]);
+                    continue;
+                case TYPE_QUADTO:
+                    e -= 4;
+                    io.quadTo(_curves[e+0], _curves[e+1],
+                              _curves[e+2], _curves[e+3]);
+                    continue;
+                case TYPE_CUBICTO:
+                    e -= 6;
+                    io.curveTo(_curves[e+0], _curves[e+1],
+                               _curves[e+2], _curves[e+3],
+                               _curves[e+4], _curves[e+5]);
+                    continue;
+                default:
+                }
+            }
+            numCurves = 0;
+            end = 0;
+        }
+
+        @Override
+        public String toString() {
+            String ret = "";
+            int nc = numCurves;
+            int e  = end;
+            int len;
+            while (nc != 0) {
+                switch(curveTypes[--nc]) {
+                case TYPE_LINETO:
+                    len = 2;
+                    ret += "line: ";
+                    break;
+                case TYPE_QUADTO:
+                    len = 4;
+                    ret += "quad: ";
+                    break;
+                case TYPE_CUBICTO:
+                    len = 6;
+                    ret += "cubic: ";
+                    break;
+                default:
+                    len = 0;
+                }
+                e -= len;
+                ret += Arrays.toString(Arrays.copyOfRange(curves, e, e+len))
+                                       + "\n";
+            }
+            return ret;
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/TransformingPathConsumer2D.java b/src/share/classes/sun/java2d/marlin/TransformingPathConsumer2D.java
new file mode 100644
index 0000000..db8f8dd
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/TransformingPathConsumer2D.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2007, 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.
+ */
+
+package sun.java2d.marlin;
+
+import sun.awt.geom.PathConsumer2D;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Path2D;
+
+final class TransformingPathConsumer2D {
+
+    TransformingPathConsumer2D() {
+        // used by RendererContext
+    }
+
+    // recycled PathConsumer2D instance from wrapPath2d()
+    private final Path2DWrapper        wp_Path2DWrapper        = new Path2DWrapper();
+
+    PathConsumer2D wrapPath2d(Path2D.Float p2d)
+    {
+        return wp_Path2DWrapper.init(p2d);
+    }
+
+    // recycled PathConsumer2D instances from deltaTransformConsumer()
+    private final DeltaScaleFilter     dt_DeltaScaleFilter     = new DeltaScaleFilter();
+    private final DeltaTransformFilter dt_DeltaTransformFilter = new DeltaTransformFilter();
+
+    PathConsumer2D deltaTransformConsumer(PathConsumer2D out,
+                                          AffineTransform at)
+    {
+        if (at == null) {
+            return out;
+        }
+        float mxx = (float) at.getScaleX();
+        float mxy = (float) at.getShearX();
+        float myx = (float) at.getShearY();
+        float myy = (float) at.getScaleY();
+
+        if (mxy == 0f && myx == 0f) {
+            if (mxx == 1f && myy == 1f) {
+                return out;
+            } else {
+                return dt_DeltaScaleFilter.init(out, mxx, myy);
+            }
+        } else {
+            return dt_DeltaTransformFilter.init(out, mxx, mxy, myx, myy);
+        }
+    }
+
+    // recycled PathConsumer2D instances from inverseDeltaTransformConsumer()
+    private final DeltaScaleFilter     iv_DeltaScaleFilter     = new DeltaScaleFilter();
+    private final DeltaTransformFilter iv_DeltaTransformFilter = new DeltaTransformFilter();
+
+    PathConsumer2D inverseDeltaTransformConsumer(PathConsumer2D out,
+                                                 AffineTransform at)
+    {
+        if (at == null) {
+            return out;
+        }
+        float mxx = (float) at.getScaleX();
+        float mxy = (float) at.getShearX();
+        float myx = (float) at.getShearY();
+        float myy = (float) at.getScaleY();
+
+        if (mxy == 0f && myx == 0f) {
+            if (mxx == 1f && myy == 1f) {
+                return out;
+            } else {
+                return iv_DeltaScaleFilter.init(out, 1.0f/mxx, 1.0f/myy);
+            }
+        } else {
+            float det = mxx * myy - mxy * myx;
+            return iv_DeltaTransformFilter.init(out,
+                                                myy / det,
+                                               -mxy / det,
+                                               -myx / det,
+                                                mxx / det);
+        }
+    }
+
+
+    static final class DeltaScaleFilter implements PathConsumer2D {
+        private PathConsumer2D out;
+        private float sx, sy;
+
+        DeltaScaleFilter() {}
+
+        DeltaScaleFilter init(PathConsumer2D out,
+                              float mxx, float myy)
+        {
+            this.out = out;
+            sx = mxx;
+            sy = myy;
+            return this; // fluent API
+        }
+
+        @Override
+        public void moveTo(float x0, float y0) {
+            out.moveTo(x0 * sx, y0 * sy);
+        }
+
+        @Override
+        public void lineTo(float x1, float y1) {
+            out.lineTo(x1 * sx, y1 * sy);
+        }
+
+        @Override
+        public void quadTo(float x1, float y1,
+                           float x2, float y2)
+        {
+            out.quadTo(x1 * sx, y1 * sy,
+                       x2 * sx, y2 * sy);
+        }
+
+        @Override
+        public void curveTo(float x1, float y1,
+                            float x2, float y2,
+                            float x3, float y3)
+        {
+            out.curveTo(x1 * sx, y1 * sy,
+                        x2 * sx, y2 * sy,
+                        x3 * sx, y3 * sy);
+        }
+
+        @Override
+        public void closePath() {
+            out.closePath();
+        }
+
+        @Override
+        public void pathDone() {
+            out.pathDone();
+        }
+
+        @Override
+        public long getNativeConsumer() {
+            return 0;
+        }
+    }
+
+    static final class DeltaTransformFilter implements PathConsumer2D {
+        private PathConsumer2D out;
+        private float mxx, mxy, myx, myy;
+
+        DeltaTransformFilter() {}
+
+        DeltaTransformFilter init(PathConsumer2D out,
+                                  float mxx, float mxy,
+                                  float myx, float myy)
+        {
+            this.out = out;
+            this.mxx = mxx;
+            this.mxy = mxy;
+            this.myx = myx;
+            this.myy = myy;
+            return this; // fluent API
+        }
+
+        @Override
+        public void moveTo(float x0, float y0) {
+            out.moveTo(x0 * mxx + y0 * mxy,
+                       x0 * myx + y0 * myy);
+        }
+
+        @Override
+        public void lineTo(float x1, float y1) {
+            out.lineTo(x1 * mxx + y1 * mxy,
+                       x1 * myx + y1 * myy);
+        }
+
+        @Override
+        public void quadTo(float x1, float y1,
+                           float x2, float y2)
+        {
+            out.quadTo(x1 * mxx + y1 * mxy,
+                       x1 * myx + y1 * myy,
+                       x2 * mxx + y2 * mxy,
+                       x2 * myx + y2 * myy);
+        }
+
+        @Override
+        public void curveTo(float x1, float y1,
+                            float x2, float y2,
+                            float x3, float y3)
+        {
+            out.curveTo(x1 * mxx + y1 * mxy,
+                        x1 * myx + y1 * myy,
+                        x2 * mxx + y2 * mxy,
+                        x2 * myx + y2 * myy,
+                        x3 * mxx + y3 * mxy,
+                        x3 * myx + y3 * myy);
+        }
+
+        @Override
+        public void closePath() {
+            out.closePath();
+        }
+
+        @Override
+        public void pathDone() {
+            out.pathDone();
+        }
+
+        @Override
+        public long getNativeConsumer() {
+            return 0;
+        }
+    }
+
+    static final class Path2DWrapper implements PathConsumer2D {
+        private Path2D.Float p2d;
+
+        Path2DWrapper() {}
+
+        Path2DWrapper init(Path2D.Float p2d) {
+            this.p2d = p2d;
+            return this;
+        }
+
+        @Override
+        public void moveTo(float x0, float y0) {
+            p2d.moveTo(x0, y0);
+        }
+
+        @Override
+        public void lineTo(float x1, float y1) {
+            p2d.lineTo(x1, y1);
+        }
+
+        @Override
+        public void closePath() {
+            p2d.closePath();
+        }
+
+        @Override
+        public void pathDone() {}
+
+        @Override
+        public void curveTo(float x1, float y1,
+                            float x2, float y2,
+                            float x3, float y3)
+        {
+            p2d.curveTo(x1, y1, x2, y2, x3, y3);
+        }
+
+        @Override
+        public void quadTo(float x1, float y1, float x2, float y2) {
+            p2d.quadTo(x1, y1, x2, y2);
+        }
+
+        @Override
+        public long getNativeConsumer() {
+            throw new InternalError("Not using a native peer");
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/Version.java b/src/share/classes/sun/java2d/marlin/Version.java
new file mode 100644
index 0000000..dc0a925
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/Version.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ */
+
+package sun.java2d.marlin;
+
+public final class Version {
+
+    private static final String VERSION = "marlin-0.7.3.4-Unsafe-OpenJDK";
+
+    public static String getVersion() {
+        return VERSION;
+    }
+
+    private Version() {
+    }
+
+}
diff --git a/src/share/classes/sun/java2d/marlin/stats/Histogram.java b/src/share/classes/sun/java2d/marlin/stats/Histogram.java
new file mode 100644
index 0000000..92865cb
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/stats/Histogram.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ */
+
+package sun.java2d.marlin.stats;
+
+/**
+ * Generic histogram based on long statistics
+ */
+public final class Histogram extends StatLong {
+
+    static final int BUCKET = 2;
+    static final int MAX = 20;
+    static final int LAST = MAX - 1;
+    static final int[] STEPS = new int[MAX];
+
+    static {
+            STEPS[0] = 0;
+            STEPS[1] = 1;
+
+            for (int i = 2; i < MAX; i++) {
+                STEPS[i] = STEPS[i - 1] * BUCKET;
+            }
+//            System.out.println("Histogram.STEPS = " + Arrays.toString(STEPS));
+    }
+
+    static int bucket(int val) {
+        for (int i = 1; i < MAX; i++) {
+            if (val < STEPS[i]) {
+                return i - 1;
+            }
+        }
+        return LAST;
+    }
+
+    private final StatLong[] stats = new StatLong[MAX];
+
+    public Histogram(final String name) {
+        super(name);
+        for (int i = 0; i < MAX; i++) {
+            stats[i] = new StatLong(String.format("%5s .. %5s", STEPS[i],
+                                    ((i + 1 < MAX) ? STEPS[i + 1] : "~")));
+        }
+    }
+
+    @Override
+    public void reset() {
+        super.reset();
+        for (int i = 0; i < MAX; i++) {
+            stats[i].reset();
+        }
+    }
+
+    @Override
+    public void add(int val) {
+        super.add(val);
+        stats[bucket(val)].add(val);
+    }
+
+    @Override
+    public void add(long val) {
+        add((int) val);
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder(2048);
+        super.toString(sb).append(" { ");
+
+        for (int i = 0; i < MAX; i++) {
+            if (stats[i].count != 0l) {
+                sb.append("\n        ").append(stats[i].toString());
+            }
+        }
+
+        return sb.append(" }").toString();
+    }
+}
+
diff --git a/src/share/classes/sun/java2d/marlin/stats/Monitor.java b/src/share/classes/sun/java2d/marlin/stats/Monitor.java
new file mode 100644
index 0000000..dcb3c8b
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/stats/Monitor.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package sun.java2d.marlin.stats;
+
+/**
+ * Generic monitor ie gathers time statistics as nanos.
+ */
+public final class Monitor extends StatLong {
+
+    private static final long INVALID = -1L;
+
+    private long start = INVALID;
+
+    public Monitor(final String name) {
+        super(name);
+    }
+
+    public void start() {
+        start = System.nanoTime();
+    }
+
+    public void stop() {
+        final long elapsed = System.nanoTime() - start;
+        if (start != INVALID && elapsed > 0l) {
+            add(elapsed);
+        }
+        start = INVALID;
+    }
+}
+
diff --git a/src/share/classes/sun/java2d/marlin/stats/StatLong.java b/src/share/classes/sun/java2d/marlin/stats/StatLong.java
new file mode 100644
index 0000000..50f906f
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/stats/StatLong.java
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+package sun.java2d.marlin.stats;
+
+/**
+ * Statistics as long values
+ */
+public class StatLong {
+
+    public final String name;
+    public long count = 0l;
+    public long sum = 0l;
+    public long min = Integer.MAX_VALUE;
+    public long max = Integer.MIN_VALUE;
+
+    public StatLong(final String name) {
+        this.name = name;
+    }
+
+    public void reset() {
+        count = 0l;
+        sum = 0l;
+        min = Integer.MAX_VALUE;
+        max = Integer.MIN_VALUE;
+    }
+
+    public void add(final int val) {
+        count++;
+        sum += val;
+        if (val < min) {
+            min = val;
+        }
+        if (val > max) {
+            max = val;
+        }
+    }
+
+    public void add(final long val) {
+        count++;
+        sum += val;
+        if (val < min) {
+            min = val;
+        }
+        if (val > max) {
+            max = val;
+        }
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder(128);
+        toString(sb);
+        return sb.toString();
+    }
+
+    public final StringBuilder toString(final StringBuilder sb) {
+        sb.append(name).append('[').append(count);
+        sb.append("] sum: ").append(sum).append(" avg: ");
+        sb.append(trimTo3Digits(((double) sum) / count));
+        sb.append(" [").append(min).append(" | ").append(max).append("]");
+        return sb;
+    }
+
+    /**
+     * Adjust the given double value to keep only 3 decimal digits
+     *
+     * @param value value to adjust
+     * @return double value with only 3 decimal digits
+     */
+    public static double trimTo3Digits(final double value) {
+        return ((long) (1e3d * value)) / 1e3d;
+    }
+}
+
diff --git a/src/share/classes/sun/java2d/opengl/OGLSurfaceData.java b/src/share/classes/sun/java2d/opengl/OGLSurfaceData.java
index a0529bd..f3cf40c 100644
--- a/src/share/classes/sun/java2d/opengl/OGLSurfaceData.java
+++ b/src/share/classes/sun/java2d/opengl/OGLSurfaceData.java
@@ -410,12 +410,10 @@
      * more code just to support a few uncommon cases.
      */
     public boolean canRenderLCDText(SunGraphics2D sg2d) {
-        return
-            graphicsConfig.isCapPresent(CAPS_EXT_LCD_SHADER) &&
-            sg2d.surfaceData.getTransparency() == Transparency.OPAQUE &&
-            sg2d.paintState <= SunGraphics2D.PAINT_OPAQUECOLOR &&
-            (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY ||
-             (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA && canHandleComposite(sg2d.composite)));
+        return graphicsConfig.isCapPresent(CAPS_EXT_LCD_SHADER) &&
+                sg2d.paintState <= SunGraphics2D.PAINT_OPAQUECOLOR &&
+                (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY ||
+                        (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA && canHandleComposite(sg2d.composite)));
     }
 
     private boolean canHandleComposite(Composite c) {
diff --git a/src/share/classes/sun/java2d/opengl/OGLTextRenderer.java b/src/share/classes/sun/java2d/opengl/OGLTextRenderer.java
index 21b2903..b402e8a 100644
--- a/src/share/classes/sun/java2d/opengl/OGLTextRenderer.java
+++ b/src/share/classes/sun/java2d/opengl/OGLTextRenderer.java
@@ -27,6 +27,7 @@
 
 import java.awt.Composite;
 import sun.font.GlyphList;
+import sun.java2d.InvalidPipeException;
 import sun.java2d.SunGraphics2D;
 import sun.java2d.loops.GraphicsPrimitive;
 import sun.java2d.pipe.BufferedTextPipe;
@@ -48,7 +49,13 @@
     @Override
     protected void validateContext(SunGraphics2D sg2d, Composite comp) {
         // assert rq.lock.isHeldByCurrentThread();
-        OGLSurfaceData oglDst = (OGLSurfaceData)sg2d.surfaceData;
+        OGLSurfaceData oglDst;
+        try {
+            oglDst = (OGLSurfaceData) sg2d.surfaceData;
+        } catch (ClassCastException e) {
+            throw new InvalidPipeException("wrong surface data type: " +
+                                           sg2d.surfaceData);
+        }
         OGLContext.validateContext(oglDst, oglDst,
                                    sg2d.getCompClip(), comp,
                                    null, sg2d.paint, sg2d,
diff --git a/src/share/classes/sun/java2d/pipe/AATextRenderer.java b/src/share/classes/sun/java2d/pipe/AATextRenderer.java
index 5b8350f..7a78464 100644
--- a/src/share/classes/sun/java2d/pipe/AATextRenderer.java
+++ b/src/share/classes/sun/java2d/pipe/AATextRenderer.java
@@ -25,7 +25,7 @@
 
 package sun.java2d.pipe;
 
-import java.awt.font.GlyphVector;
+import sun.awt.SunHints;
 import sun.java2d.SunGraphics2D;
 import sun.font.GlyphList;
 
@@ -38,8 +38,7 @@
     implements LoopBasedPipe
 {
    protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) {
-       sg2d.loops.drawGlyphListAALoop.DrawGlyphListAA(sg2d, sg2d.surfaceData,
-                                                      gl);
+       drawGlyphList(sg2d, gl, SunHints.INTVAL_TEXT_ANTIALIAS_ON);
    }
 
 }
diff --git a/src/share/classes/sun/java2d/pipe/DrawImage.java b/src/share/classes/sun/java2d/pipe/DrawImage.java
index cfa130b..a7e181e 100644
--- a/src/share/classes/sun/java2d/pipe/DrawImage.java
+++ b/src/share/classes/sun/java2d/pipe/DrawImage.java
@@ -736,9 +736,10 @@
         atfm.scale(m00, m11);
         atfm.translate(srcX-sx1, srcY-sy1);
 
-        final int scale = SurfaceManager.getImageScale(img);
-        final int imgW = img.getWidth(null) * scale;
-        final int imgH = img.getHeight(null) * scale;
+        final double scaleX = SurfaceManager.getImageScaleX(img);
+        final double scaleY = SurfaceManager.getImageScaleY(img);
+        final int imgW = (int) Math.ceil(img.getWidth(null) * scaleX);
+        final int imgH = (int) Math.ceil(img.getHeight(null) * scaleY);
         srcW += srcX;
         srcH += srcY;
         // Make sure we are not out of bounds
diff --git a/src/share/classes/sun/java2d/pipe/GlyphListLoopPipe.java b/src/share/classes/sun/java2d/pipe/GlyphListLoopPipe.java
index 86830d9..6885371 100644
--- a/src/share/classes/sun/java2d/pipe/GlyphListLoopPipe.java
+++ b/src/share/classes/sun/java2d/pipe/GlyphListLoopPipe.java
@@ -25,8 +25,8 @@
 
 package sun.java2d.pipe;
 
-import java.awt.font.GlyphVector;
 import sun.awt.SunHints;
+import sun.font.SunFontManager;
 import sun.java2d.SunGraphics2D;
 import sun.font.GlyphList;
 
@@ -41,20 +41,45 @@
 {
     protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl,
                                  int aaHint) {
-        switch (aaHint) {
-         case SunHints.INTVAL_TEXT_ANTIALIAS_OFF:
-             sg2d.loops.drawGlyphListLoop.
-                 DrawGlyphList(sg2d, sg2d.surfaceData, gl);
-             return;
-         case SunHints.INTVAL_TEXT_ANTIALIAS_ON:
-             sg2d.loops.drawGlyphListAALoop.
-                 DrawGlyphListAA(sg2d, sg2d.surfaceData, gl);
-             return;
-        case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
-        case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
-            sg2d.loops.drawGlyphListLCDLoop.
-                DrawGlyphListLCD(sg2d,sg2d.surfaceData, gl);
-            return;
+        int prevBorder = 0;
+        boolean isColor = false;
+        int len = gl.getNumGlyphs();
+        gl.startGlyphIteration();
+        if (SunFontManager.getInstance().areColorGlyphsSupported()) {
+            for (int i = 0; i < len; i++) {
+                boolean newIsColor = gl.isColorGlyph(i);
+                if (newIsColor != isColor) {
+                    drawGlyphListSegment(sg2d, gl, prevBorder, i, aaHint, isColor);
+                    prevBorder = i;
+                    isColor = newIsColor;
+                }
+            }
+        }
+        drawGlyphListSegment(sg2d, gl, prevBorder, len, aaHint, isColor);
+    }
+
+    private void drawGlyphListSegment(SunGraphics2D sg2d, GlyphList gl, int fromglyph, int toGlyph,
+                                      int aaHint, boolean isColor) {
+        if (fromglyph >= toGlyph) return;
+        if (isColor) {
+            sg2d.loops.drawGlyphListColorLoop.
+                    DrawGlyphListColor(sg2d, sg2d.surfaceData, gl, fromglyph, toGlyph);
+        } else {
+            switch (aaHint) {
+                case SunHints.INTVAL_TEXT_ANTIALIAS_OFF:
+                    sg2d.loops.drawGlyphListLoop.
+                            DrawGlyphList(sg2d, sg2d.surfaceData, gl, fromglyph, toGlyph);
+                    return;
+                case SunHints.INTVAL_TEXT_ANTIALIAS_ON:
+                    sg2d.loops.drawGlyphListAALoop.
+                            DrawGlyphListAA(sg2d, sg2d.surfaceData, gl, fromglyph, toGlyph);
+                    return;
+                case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
+                case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
+                    sg2d.loops.drawGlyphListLCDLoop.
+                            DrawGlyphListLCD(sg2d, sg2d.surfaceData, gl, fromglyph, toGlyph);
+                    return;
+            }
         }
     }
 }
diff --git a/src/share/classes/sun/java2d/pipe/LCDTextRenderer.java b/src/share/classes/sun/java2d/pipe/LCDTextRenderer.java
index 44eab9b..daf88d4 100644
--- a/src/share/classes/sun/java2d/pipe/LCDTextRenderer.java
+++ b/src/share/classes/sun/java2d/pipe/LCDTextRenderer.java
@@ -25,10 +25,9 @@
 
 package sun.java2d.pipe;
 
-import java.awt.font.GlyphVector;
+import sun.awt.SunHints;
 import sun.java2d.SunGraphics2D;
 import sun.font.GlyphList;
-import static sun.awt.SunHints.*;
 
 /**
  * A delegate pipe of SG2D for drawing LCD text with
@@ -38,7 +37,7 @@
 public class LCDTextRenderer extends GlyphListLoopPipe {
 
     protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) {
-        sg2d.loops.drawGlyphListLCDLoop.
-            DrawGlyphListLCD(sg2d, sg2d.surfaceData, gl);
+        drawGlyphList(sg2d, gl, SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB);
+
     }
 }
diff --git a/src/share/classes/sun/java2d/pipe/RenderingEngine.java b/src/share/classes/sun/java2d/pipe/RenderingEngine.java
index 3c2a77c..88b87d8 100644
--- a/src/share/classes/sun/java2d/pipe/RenderingEngine.java
+++ b/src/share/classes/sun/java2d/pipe/RenderingEngine.java
@@ -123,13 +123,11 @@
                     final String ductusREClass = "sun.dc.DuctusRenderingEngine";
                     String reClass =
                         System.getProperty("sun.java2d.renderer", ductusREClass);
-                    if (reClass.equals(ductusREClass)) {
-                        try {
-                            Class<?> cls = Class.forName(ductusREClass);
-                            return (RenderingEngine) cls.newInstance();
-                        } catch (ReflectiveOperationException ignored) {
-                            // not found
-                        }
+                    try {
+                        Class<?> cls = Class.forName(reClass);
+                        return (RenderingEngine) cls.newInstance();
+                    } catch (ReflectiveOperationException ignored) {
+                        // not found
                     }
 
                     ServiceLoader<RenderingEngine> reLoader =
diff --git a/src/share/classes/sun/java2d/pipe/SolidTextRenderer.java b/src/share/classes/sun/java2d/pipe/SolidTextRenderer.java
index 6c6f98c..6ffe349 100644
--- a/src/share/classes/sun/java2d/pipe/SolidTextRenderer.java
+++ b/src/share/classes/sun/java2d/pipe/SolidTextRenderer.java
@@ -25,7 +25,6 @@
 
 package sun.java2d.pipe;
 
-import java.awt.font.GlyphVector;
 import sun.awt.SunHints;
 import sun.java2d.SunGraphics2D;
 import sun.font.GlyphList;
@@ -39,6 +38,6 @@
     implements LoopBasedPipe
 {
     protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) {
-        sg2d.loops.drawGlyphListLoop.DrawGlyphList(sg2d, sg2d.surfaceData, gl);
+        drawGlyphList(sg2d, gl, SunHints.INTVAL_TEXT_ANTIALIAS_OFF);
     }
 }
diff --git a/src/share/classes/sun/java2d/pipe/TextRenderer.java b/src/share/classes/sun/java2d/pipe/TextRenderer.java
index 6b63ba3..34f471e 100644
--- a/src/share/classes/sun/java2d/pipe/TextRenderer.java
+++ b/src/share/classes/sun/java2d/pipe/TextRenderer.java
@@ -60,6 +60,7 @@
                                         bounds[3] - bounds[1]);
             Shape s = sg2d.untransformShape(r);
             ctx = outpipe.startSequence(sg2d, s, r, bounds);
+            gl.startGlyphIteration();
             for (int i = 0; i < num; i++) {
                 gl.setGlyphIndex(i);
                 int metrics[] = gl.getMetrics();
@@ -79,7 +80,7 @@
                 }
                 if (gx2 > cx2) gx2 = cx2;
                 if (gy2 > cy2) gy2 = cy2;
-                if (gx2 > gx1 && gy2 > gy1 &&
+                if (gx2 > gx1 && gy2 > gy1 && !gl.isColorGlyph(i) &&
                     outpipe.needTile(ctx, gx1, gy1, gx2 - gx1, gy2 - gy1))
                 {
                     byte alpha[] = gl.getGrayBits();
diff --git a/src/share/classes/sun/swing/SwingUtilities2.java b/src/share/classes/sun/swing/SwingUtilities2.java
index af8f626..64e3700 100644
--- a/src/share/classes/sun/swing/SwingUtilities2.java
+++ b/src/share/classes/sun/swing/SwingUtilities2.java
@@ -159,7 +159,7 @@
 
         Object aaHint;
         Integer lcdContrastHint;
-        FontRenderContext frc;
+        Map<Object, FontRenderContext> cache = new HashMap<>();
 
         /* These are rarely constructed objects, and only when a complete
          * UI is being updated, so the cost of the tests here is minimal
@@ -176,8 +176,49 @@
             }
             this.aaHint = aaHint;
             this.lcdContrastHint = lcdContrastHint;
-            this.frc = new FontRenderContext(null, aaHint,
-                                             VALUE_FRACTIONALMETRICS_DEFAULT);
+        }
+
+        private static class KeyPair {
+
+            private final Object key1;
+            private final Object key2;
+
+            public KeyPair(Object key1, Object key2) {
+                this.key1 = key1;
+                this.key2 = key2;
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                if (!(obj instanceof KeyPair)) {
+                    return false;
+                }
+                KeyPair that = (KeyPair) obj;
+                return this.key1.equals(that.key1) && this.key2.equals(that.key2);
+            }
+
+            @Override
+            public int hashCode() {
+                return key1.hashCode() + 37 * key2.hashCode();
+            }
+        }
+
+        // [tav] see JDK-8142966
+        FontRenderContext getFRC(AffineTransform tx) {
+            if (tx == null && aaHint == null) {
+                return null;
+            }
+            Object key = (tx == null)
+                ? aaHint
+                : (aaHint == null ? tx : new KeyPair(tx, aaHint));
+
+            FontRenderContext frc = cache.get(key);
+            if (frc == null) {
+                aaHint = (aaHint == null) ? VALUE_ANTIALIAS_OFF : aaHint;
+                frc = new FontRenderContext(tx, aaHint, VALUE_FRACTIONALMETRICS_DEFAULT);
+                cache.put(key, frc);
+            }
+            return frc;
         }
     }
 
@@ -1119,10 +1160,11 @@
      */
     private static FontRenderContext getFRCProperty(JComponent c) {
         if (c != null) {
-            AATextInfo info =
-                (AATextInfo)c.getClientProperty(AA_TEXT_PROPERTY_KEY);
+            GraphicsConfiguration gc = c.getGraphicsConfiguration();
+            AffineTransform tx = (gc == null) ? null : gc.getDefaultTransform();
+            AATextInfo info = (AATextInfo)c.getClientProperty(AA_TEXT_PROPERTY_KEY);
             if (info != null) {
-                return info.frc;
+                return info.getFRC(tx);
             }
         }
         return null;
diff --git a/src/share/lib/fonts/DroidSans-Bold.ttf b/src/share/lib/fonts/DroidSans-Bold.ttf
new file mode 100644
index 0000000..d065b64
--- /dev/null
+++ b/src/share/lib/fonts/DroidSans-Bold.ttf
Binary files differ
diff --git a/src/share/lib/fonts/DroidSans.ttf b/src/share/lib/fonts/DroidSans.ttf
new file mode 100644
index 0000000..ad1efca
--- /dev/null
+++ b/src/share/lib/fonts/DroidSans.ttf
Binary files differ
diff --git a/src/share/lib/fonts/DroidSansMono.ttf b/src/share/lib/fonts/DroidSansMono.ttf
new file mode 100644
index 0000000..a007071
--- /dev/null
+++ b/src/share/lib/fonts/DroidSansMono.ttf
Binary files differ
diff --git a/src/share/lib/fonts/DroidSansMonoDotted.ttf b/src/share/lib/fonts/DroidSansMonoDotted.ttf
new file mode 100644
index 0000000..e56a5ca
--- /dev/null
+++ b/src/share/lib/fonts/DroidSansMonoDotted.ttf
Binary files differ
diff --git a/src/share/lib/fonts/DroidSansMonoSlashed.ttf b/src/share/lib/fonts/DroidSansMonoSlashed.ttf
new file mode 100644
index 0000000..8c44b47
--- /dev/null
+++ b/src/share/lib/fonts/DroidSansMonoSlashed.ttf
Binary files differ
diff --git a/src/share/lib/fonts/DroidSerif-Bold.ttf b/src/share/lib/fonts/DroidSerif-Bold.ttf
new file mode 100644
index 0000000..838d255
--- /dev/null
+++ b/src/share/lib/fonts/DroidSerif-Bold.ttf
Binary files differ
diff --git a/src/share/lib/fonts/DroidSerif-BoldItalic.ttf b/src/share/lib/fonts/DroidSerif-BoldItalic.ttf
new file mode 100644
index 0000000..0b1601f
--- /dev/null
+++ b/src/share/lib/fonts/DroidSerif-BoldItalic.ttf
Binary files differ
diff --git a/src/share/lib/fonts/DroidSerif-Italic.ttf b/src/share/lib/fonts/DroidSerif-Italic.ttf
new file mode 100644
index 0000000..2972809
--- /dev/null
+++ b/src/share/lib/fonts/DroidSerif-Italic.ttf
Binary files differ
diff --git a/src/share/lib/fonts/DroidSerif-Regular.ttf b/src/share/lib/fonts/DroidSerif-Regular.ttf
new file mode 100644
index 0000000..5b4fe81
--- /dev/null
+++ b/src/share/lib/fonts/DroidSerif-Regular.ttf
Binary files differ
diff --git a/src/share/lib/fonts/LICENSE.txt b/src/share/lib/fonts/LICENSE.txt
new file mode 100644
index 0000000..a4a4b17
--- /dev/null
+++ b/src/share/lib/fonts/LICENSE.txt
@@ -0,0 +1,13 @@
+Copyright 2000-2016 JetBrains s.r.o.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/src/share/lib/fonts/fonts.dir b/src/share/lib/fonts/fonts.dir
new file mode 100644
index 0000000..1344314
--- /dev/null
+++ b/src/share/lib/fonts/fonts.dir
@@ -0,0 +1,170 @@
+169
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-adobe-standard
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-ascii-0
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-iso10646-1
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-iso8859-1
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-iso8859-10
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-iso8859-13
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-iso8859-15
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-iso8859-16
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-iso8859-2
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-iso8859-3
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-iso8859-4
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-iso8859-5
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-iso8859-9
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-koi8-e
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-koi8-r
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-koi8-ru
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-koi8-u
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-koi8-uni
+DroidSans-Bold.ttf -misc-droid sans-bold-r-normal--0-0-0-0-p-0-microsoft-cp1252
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-adobe-standard
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-ascii-0
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-iso10646-1
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-iso8859-1
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-iso8859-10
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-iso8859-13
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-iso8859-15
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-iso8859-16
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-iso8859-2
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-iso8859-3
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-iso8859-4
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-iso8859-5
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-iso8859-9
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-koi8-e
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-koi8-r
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-koi8-ru
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-koi8-u
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-koi8-uni
+DroidSans.ttf -misc-droid sans-medium-r-normal--0-0-0-0-p-0-microsoft-cp1252
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-adobe-standard
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-ascii-0
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-iso10646-1
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-iso8859-1
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-iso8859-10
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-iso8859-13
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-iso8859-15
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-iso8859-16
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-iso8859-2
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-iso8859-3
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-iso8859-4
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-iso8859-5
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-iso8859-9
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-koi8-e
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-koi8-r
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-koi8-ru
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-koi8-u
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-koi8-uni
+DroidSansMono.ttf -misc-droid sans mono-medium-r-normal--0-0-0-0-m-0-microsoft-cp1252
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-adobe-standard
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-ascii-0
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-iso10646-1
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-iso8859-1
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-iso8859-10
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-iso8859-13
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-iso8859-15
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-iso8859-2
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-iso8859-3
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-iso8859-4
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-iso8859-5
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-iso8859-9
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-koi8-e
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-koi8-r
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-koi8-ru
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-koi8-u
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-koi8-uni
+DroidSansMonoDotted.ttf -misc-droid sans mono dotted-medium-r-normal--0-0-0-0-m-0-microsoft-cp1252
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-adobe-standard
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-ascii-0
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-iso10646-1
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-iso8859-1
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-iso8859-10
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-iso8859-13
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-iso8859-15
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-iso8859-2
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-iso8859-3
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-iso8859-4
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-iso8859-5
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-iso8859-9
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-koi8-e
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-koi8-r
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-koi8-ru
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-koi8-u
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-koi8-uni
+DroidSansMonoSlashed.ttf -misc-droid sans mono slashed-medium-r-normal--0-0-0-0-m-0-microsoft-cp1252
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-adobe-standard
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-ascii-0
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-iso10646-1
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-iso8859-1
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-iso8859-10
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-iso8859-13
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-iso8859-15
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-iso8859-16
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-iso8859-2
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-iso8859-3
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-iso8859-4
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-iso8859-5
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-iso8859-9
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-koi8-e
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-koi8-r
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-koi8-ru
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-koi8-u
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-koi8-uni
+DroidSerif-Bold.ttf -misc-droid serif-bold-r-normal--0-0-0-0-p-0-microsoft-cp1252
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-adobe-standard
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-ascii-0
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-iso10646-1
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-iso8859-1
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-iso8859-10
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-iso8859-13
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-iso8859-15
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-iso8859-16
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-iso8859-2
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-iso8859-3
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-iso8859-4
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-iso8859-5
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-iso8859-9
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-koi8-e
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-koi8-r
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-koi8-ru
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-koi8-u
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-koi8-uni
+DroidSerif-BoldItalic.ttf -misc-droid serif-bold-i-normal--0-0-0-0-p-0-microsoft-cp1252
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-adobe-standard
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-ascii-0
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-iso10646-1
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-iso8859-1
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-iso8859-10
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-iso8859-13
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-iso8859-15
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-iso8859-16
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-iso8859-2
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-iso8859-3
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-iso8859-4
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-iso8859-5
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-iso8859-9
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-koi8-e
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-koi8-r
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-koi8-ru
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-koi8-u
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-koi8-uni
+DroidSerif-Italic.ttf -misc-droid serif-medium-i-normal--0-0-0-0-p-0-microsoft-cp1252
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-adobe-standard
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-ascii-0
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-iso10646-1
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-iso8859-1
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-iso8859-10
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-iso8859-13
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-iso8859-15
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-iso8859-16
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-iso8859-2
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-iso8859-3
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-iso8859-4
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-iso8859-5
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-iso8859-9
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-koi8-e
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-koi8-r
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-koi8-ru
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-koi8-u
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-koi8-uni
+DroidSerif-Regular.ttf -misc-droid serif-medium-r-normal--0-0-0-0-p-0-microsoft-cp1252
diff --git a/src/share/lib/security/blacklisted.certs b/src/share/lib/security/blacklisted.certs
index 5042b62..00a1dcf 100644
--- a/src/share/lib/security/blacklisted.certs
+++ b/src/share/lib/security/blacklisted.certs
@@ -1,20 +1,20 @@
 Algorithm=SHA-256

-76A45A496031E4DD2D7ED23E8F6FF97DBDEA980BAAC8B0BA94D7EDB551348645

-4CBBF8256BC9888A8007B2F386940A2E394378B0D903CBB3863C5A6394B889CE

-D24566BF315F4E597D6E381C87119FB4198F5E9E2607F5F4AB362EF7E2E7672F

 14E6D2764A4B06701C6CBC376A253775F79C782FBCB6C0EE6F99DE4BA1024ADD

-D3A936E1A7775A45217C8296A1F22AC5631DCDEC45594099E78EEEBBEDCBA967

-5E83124D68D24E8E177E306DF643D5EA99C5A94D6FC34B072F7544A1CABB7C7B

-9ED8F9B0E8E42A1656B8E1DD18F42BA42DC06FE52686173BA2FC70E756F207DC

-FDEDB5BDFCB67411513A61AEE5CB5B5D7C52AF06028EFC996CC1B05B1D6CEA2B

-A686FEE577C88AB664D0787ECDFFF035F4806F3DE418DC9E4D516324FFF02083

-4FEE0163686ECBD65DB968E7494F55D84B25486D438E9DE558D629D28CD4D176

-8A1BD21661C60015065212CC98B1ABB50DFD14C872A208E66BAE890F25C448AF

-B8686723E415534BC0DBD16326F9486F85B0B0799BF6639334E61DAAE67F36CD

-3946901F46B0071E90D78279E82FABABCA177231A704BE72C5B0E8918566EA66

 31C8FD37DB9B56E708B03D1F01848B068C6DA66F36FB5D82C008C6040FA3E133

+3946901F46B0071E90D78279E82FABABCA177231A704BE72C5B0E8918566EA66

 450F1B421BB05C8609854884559C323319619E8B06B001EA2DCBB74A23AA3BE2

-FC02FD48DB92D4DCE6F11679D38354CF750CFC7F584A520EB90BDE80E241F2BD

+4CBBF8256BC9888A8007B2F386940A2E394378B0D903CBB3863C5A6394B889CE

+4FEE0163686ECBD65DB968E7494F55D84B25486D438E9DE558D629D28CD4D176

+5E83124D68D24E8E177E306DF643D5EA99C5A94D6FC34B072F7544A1CABB7C7B

+76A45A496031E4DD2D7ED23E8F6FF97DBDEA980BAAC8B0BA94D7EDB551348645

+8A1BD21661C60015065212CC98B1ABB50DFD14C872A208E66BAE890F25C448AF

+9ED8F9B0E8E42A1656B8E1DD18F42BA42DC06FE52686173BA2FC70E756F207DC

+A686FEE577C88AB664D0787ECDFFF035F4806F3DE418DC9E4D516324FFF02083

+B8686723E415534BC0DBD16326F9486F85B0B0799BF6639334E61DAAE67F36CD

+D24566BF315F4E597D6E381C87119FB4198F5E9E2607F5F4AB362EF7E2E7672F

+D3A936E1A7775A45217C8296A1F22AC5631DCDEC45594099E78EEEBBEDCBA967

 DF21016B00FC54F9FE3BC8B039911BB216E9162FAD2FD14D990AB96E951B49BE

-F5B6F88F75D391A4B1EB336F9E201239FB6B1377DB8CFA7B84736216E5AFFFD7

 EC30C9C3065A06BB07DC5B1C6B497F370C1CA65C0F30C08E042BA6BCECC78F2C

+F5B6F88F75D391A4B1EB336F9E201239FB6B1377DB8CFA7B84736216E5AFFFD7

+FC02FD48DB92D4DCE6F11679D38354CF750CFC7F584A520EB90BDE80E241F2BD

+FDEDB5BDFCB67411513A61AEE5CB5B5D7C52AF06028EFC996CC1B05B1D6CEA2B

diff --git a/src/share/lib/security/cacerts b/src/share/lib/security/cacerts
index c408465..318a166 100644
--- a/src/share/lib/security/cacerts
+++ b/src/share/lib/security/cacerts
Binary files differ
diff --git a/src/share/native/java/lang/System.c b/src/share/native/java/lang/System.c
index 5c36460..afeb5bb 100644
--- a/src/share/native/java/lang/System.c
+++ b/src/share/native/java/lang/System.c
@@ -109,9 +109,9 @@
     } else ((void) 0)
 
 #ifndef VENDOR /* Third party may overwrite this. */
-#define VENDOR "Oracle Corporation"
-#define VENDOR_URL "http://java.oracle.com/"
-#define VENDOR_URL_BUG "http://bugreport.sun.com/bugreport/"
+#define VENDOR "JetBrains s.r.o"
+#define VENDOR_URL "https://www.jetbrains.com/"
+#define VENDOR_URL_BUG "https://youtrack.jetbrains.com"
 #endif
 
 #define JAVA_MAX_SUPPORTED_VERSION 52
diff --git a/src/share/native/sun/font/ColorGlyphSurfaceData.c b/src/share/native/sun/font/ColorGlyphSurfaceData.c
new file mode 100644
index 0000000..a231c29
--- /dev/null
+++ b/src/share/native/sun/font/ColorGlyphSurfaceData.c
@@ -0,0 +1,55 @@
+#include "jni_util.h"
+#include "fontscalerdefs.h"
+#include "SurfaceData.h"
+
+typedef struct _GlyphOps {
+    SurfaceDataOps sdOps;
+    GlyphInfo*     glyph;
+} GlyphOps;
+
+static jint Glyph_Lock(JNIEnv *env,
+                       SurfaceDataOps *ops,
+                       SurfaceDataRasInfo *pRasInfo,
+                       jint lockflags)
+{
+    SurfaceDataBounds bounds;
+    GlyphInfo *glyph;
+    if (lockflags & (SD_LOCK_WRITE | SD_LOCK_LUT | SD_LOCK_INVCOLOR | SD_LOCK_INVGRAY)) {
+        JNU_ThrowInternalError(env, "Unsupported mode for glyph image surface");
+        return SD_FAILURE;
+    }
+    glyph = ((GlyphOps*)ops)->glyph;
+    bounds.x1 = 0;
+    bounds.y1 = 0;
+    bounds.x2 = glyph->width;
+    bounds.y2 = glyph->height;
+    SurfaceData_IntersectBounds(&pRasInfo->bounds, &bounds);
+    return SD_SUCCESS;
+}
+
+static void Glyph_GetRasInfo(JNIEnv *env,
+                             SurfaceDataOps *ops,
+                             SurfaceDataRasInfo *pRasInfo)
+{
+    GlyphInfo *glyph = ((GlyphOps*)ops)->glyph;
+
+    pRasInfo->rasBase = glyph->image;
+    pRasInfo->pixelStride = 4;
+    pRasInfo->scanStride = glyph->rowBytes;
+    pRasInfo->pixelBitOffset = 0;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_font_ColorGlyphSurfaceData_initOps(JNIEnv *env, jobject sData)
+{
+    GlyphOps *ops = (GlyphOps*) SurfaceData_InitOps(env, sData, sizeof(GlyphOps));
+    ops->sdOps.Lock = Glyph_Lock;
+    ops->sdOps.GetRasInfo = Glyph_GetRasInfo;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_font_ColorGlyphSurfaceData_setCurrentGlyph(JNIEnv *env, jobject sData, jlong imgPtr)
+{
+    GlyphOps *ops = (GlyphOps*) SurfaceData_GetOpsNoSetup(env, sData);
+    ops->glyph = (GlyphInfo*) jlong_to_ptr(imgPtr);
+}
\ No newline at end of file
diff --git a/src/share/native/sun/font/DrawGlyphList.c b/src/share/native/sun/font/DrawGlyphList.c
index c4dcdf9..4626c47 100644
--- a/src/share/native/sun/font/DrawGlyphList.c
+++ b/src/share/native/sun/font/DrawGlyphList.c
@@ -50,7 +50,7 @@
 #define FLOOR_ASSIGN(l, r)\
  if ((r)<0) (l) = ((int)floor(r)); else (l) = ((int)(r))
 
-GlyphBlitVector* setupBlitVector(JNIEnv *env, jobject glyphlist) {
+GlyphBlitVector* setupBlitVector(JNIEnv *env, jobject glyphlist, jint fromGlyph, jint toGlyph) {
 
     int g;
     size_t bytesNeeded;
@@ -61,7 +61,7 @@
 
     jfloat x = (*env)->GetFloatField(env, glyphlist, sunFontIDs.glyphListX);
     jfloat y = (*env)->GetFloatField(env, glyphlist, sunFontIDs.glyphListY);
-    jint len =  (*env)->GetIntField(env, glyphlist, sunFontIDs.glyphListLen);
+    jint len =  toGlyph - fromGlyph;
     jlongArray glyphImages = (jlongArray)
         (*env)->GetObjectField(env, glyphlist, sunFontIDs.glyphImages);
     jfloatArray glyphPositions =
@@ -84,13 +84,8 @@
         return (GlyphBlitVector*)NULL;
     }
 
-    /* Add 0.5 to x and y and then use floor (or an equivalent operation)
-     * to round down the glyph positions to integral pixel positions.
-     */
-    x += 0.5f;
-    y += 0.5f;
     if (glyphPositions) {
-        int n = -1;
+        int n = fromGlyph * 2 - 1;
 
         positions =
           (*env)->GetPrimitiveArrayCritical(env, glyphPositions, NULL);
@@ -105,7 +100,7 @@
             jfloat px = x + positions[++n];
             jfloat py = y + positions[++n];
 
-            ginfo = (GlyphInfo*)imagePtrs[g];
+            ginfo = (GlyphInfo*)imagePtrs[g + fromGlyph];
             gbv->glyphs[g].glyphInfo = ginfo;
             gbv->glyphs[g].pixels = ginfo->image;
             gbv->glyphs[g].width = ginfo->width;
@@ -118,7 +113,7 @@
                                               positions, JNI_ABORT);
     } else {
         for (g=0; g<len; g++) {
-            ginfo = (GlyphInfo*)imagePtrs[g];
+            ginfo = (GlyphInfo*)imagePtrs[g + fromGlyph];
             gbv->glyphs[g].glyphInfo = ginfo;
             gbv->glyphs[g].pixels = ginfo->image;
             gbv->glyphs[g].width = ginfo->width;
@@ -135,6 +130,12 @@
 
     (*env)->ReleasePrimitiveArrayCritical(env, glyphImages, imagePtrs,
                                           JNI_ABORT);
+
+    if (!glyphPositions) {
+        (*env)->SetFloatField(env, glyphlist, sunFontIDs.glyphListX, x);
+        (*env)->SetFloatField(env, glyphlist, sunFontIDs.glyphListY, y);
+    }
+
     return gbv;
 }
 
@@ -305,12 +306,12 @@
 /*
  * Class:     sun_java2d_loops_DrawGlyphList
  * Method:    DrawGlyphList
- * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Lsun/java2d/font/GlyphList;J)V
+ * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Lsun/java2d/font/GlyphList;JJ)V
  */
 JNIEXPORT void JNICALL
 Java_sun_java2d_loops_DrawGlyphList_DrawGlyphList
     (JNIEnv *env, jobject self,
-     jobject sg2d, jobject sData, jobject glyphlist) {
+     jobject sg2d, jobject sData, jobject glyphlist, jint fromGlyph, jint toGlyph) {
 
     jint pixel, color;
     GlyphBlitVector* gbv;
@@ -320,7 +321,7 @@
         return;
     }
 
-    if ((gbv = setupBlitVector(env, glyphlist)) == NULL) {
+    if ((gbv = setupBlitVector(env, glyphlist, fromGlyph, toGlyph)) == NULL) {
         return;
     }
 
@@ -335,12 +336,12 @@
 /*
  * Class:     sun_java2d_loops_DrawGlyphListAA
  * Method:    DrawGlyphListAA
- * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Lsun/java2d/font/GlyphList;J)V
+ * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Lsun/java2d/font/GlyphList;JJ)V
  */
 JNIEXPORT void JNICALL
 Java_sun_java2d_loops_DrawGlyphListAA_DrawGlyphListAA
     (JNIEnv *env, jobject self,
-     jobject sg2d, jobject sData, jobject glyphlist) {
+     jobject sg2d, jobject sData, jobject glyphlist, jint fromGlyph, jint toGlyph) {
 
     jint pixel, color;
     GlyphBlitVector* gbv;
@@ -350,7 +351,7 @@
         return;
     }
 
-    if ((gbv = setupBlitVector(env, glyphlist)) == NULL) {
+    if ((gbv = setupBlitVector(env, glyphlist, fromGlyph, toGlyph)) == NULL) {
         return;
     }
     pixel = GrPrim_Sg2dGetPixel(env, sg2d);
@@ -363,12 +364,12 @@
 /*
  * Class:     sun_java2d_loops_DrawGlyphListLCD
  * Method:    DrawGlyphListLCD
- * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Lsun/java2d/font/GlyphList;J)V
+ * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Lsun/java2d/font/GlyphList;JJ)V
  */
 JNIEXPORT void JNICALL
 Java_sun_java2d_loops_DrawGlyphListLCD_DrawGlyphListLCD
     (JNIEnv *env, jobject self,
-     jobject sg2d, jobject sData, jobject glyphlist) {
+     jobject sg2d, jobject sData, jobject glyphlist, jint fromGlyph, jint toGlyph) {
 
     jint pixel, color, contrast;
     jboolean rgbOrder;
@@ -379,7 +380,7 @@
         return;
     }
 
-    if ((gbv = setupLCDBlitVector(env, glyphlist)) == NULL) {
+    if ((gbv = setupLCDBlitVector(env, glyphlist, fromGlyph, toGlyph)) == NULL) {
         return;
     }
     pixel = GrPrim_Sg2dGetPixel(env, sg2d);
@@ -481,7 +482,7 @@
  *  rendered fractional metrics, there's typically more space between the
  *  glyphs. Perhaps disabling X-axis grid-fitting will help with that.
  */
-GlyphBlitVector* setupLCDBlitVector(JNIEnv *env, jobject glyphlist) {
+GlyphBlitVector* setupLCDBlitVector(JNIEnv *env, jobject glyphlist, jint fromGlyph, jint toGlyph) {
 
     int g;
     size_t bytesNeeded;
@@ -492,7 +493,7 @@
 
     jfloat x = (*env)->GetFloatField(env, glyphlist, sunFontIDs.glyphListX);
     jfloat y = (*env)->GetFloatField(env, glyphlist, sunFontIDs.glyphListY);
-    jint len =  (*env)->GetIntField(env, glyphlist, sunFontIDs.glyphListLen);
+    jint len =  toGlyph - fromGlyph;
     jlongArray glyphImages = (jlongArray)
         (*env)->GetObjectField(env, glyphlist, sunFontIDs.glyphImages);
     jfloatArray glyphPositions =
@@ -531,22 +532,15 @@
      * heterogenous
      */
     if (subPixPos && len > 0) {
-        ginfo = (GlyphInfo*)imagePtrs[0];
+        ginfo = (GlyphInfo*)imagePtrs[fromGlyph];
         /* rowBytes==width tests if its a B&W or LCD glyph */
         if (ginfo->width == ginfo->rowBytes) {
             subPixPos = JNI_FALSE;
         }
     }
-    if (subPixPos) {
-        x += 0.1666667f;
-        y += 0.1666667f;
-    } else {
-        x += 0.5f;
-        y += 0.5f;
-    }
 
      if (glyphPositions) {
-        int n = -1;
+        int n = fromGlyph * 2 - 1;
 
         positions =
           (*env)->GetPrimitiveArrayCritical(env, glyphPositions, NULL);
@@ -560,7 +554,7 @@
         for (g=0; g<len; g++) {
             jfloat px, py;
 
-            ginfo = (GlyphInfo*)imagePtrs[g];
+            ginfo = (GlyphInfo*)imagePtrs[g + fromGlyph];
             gbv->glyphs[g].glyphInfo = ginfo;
             gbv->glyphs[g].pixels = ginfo->image;
             gbv->glyphs[g].width = ginfo->width;
@@ -596,7 +590,12 @@
              */
             if (subPixPos) {
                 int frac;
-                float pos = px + ginfo->topLeftX;
+                float pos;
+
+                px += 0.1666667f - 0.5f;
+                py += 0.1666667f - 0.5f;
+
+                pos = px + ginfo->topLeftX;
                 FLOOR_ASSIGN(gbv->glyphs[g].x, pos);
                 /* Calculate the fractional pixel position - ie the subpixel
                  * position within the RGB/BGR triple. We are rounding to
@@ -635,7 +634,9 @@
                                               positions, JNI_ABORT);
     } else {
         for (g=0; g<len; g++) {
-            ginfo = (GlyphInfo*)imagePtrs[g];
+            jfloat px = x;
+            jfloat py = y;
+            ginfo = (GlyphInfo*)imagePtrs[g + fromGlyph];
             gbv->glyphs[g].glyphInfo = ginfo;
             gbv->glyphs[g].pixels = ginfo->image;
             gbv->glyphs[g].width = ginfo->width;
@@ -644,7 +645,12 @@
 
             if (subPixPos) {
                 int frac;
-                float pos = x + ginfo->topLeftX;
+                float pos;
+
+                px += 0.1666667f - 0.5f;
+                py += 0.1666667f - 0.5f;
+
+                pos = px + ginfo->topLeftX;
                 FLOOR_ASSIGN(gbv->glyphs[g].x, pos);
                 frac = (int)((pos - gbv->glyphs[g].x)*3);
                 if (frac == 0) {
@@ -654,10 +660,11 @@
                     gbv->glyphs[g].x += 1;
                 }
             } else {
-                FLOOR_ASSIGN(gbv->glyphs[g].x, x + ginfo->topLeftX);
+                FLOOR_ASSIGN(gbv->glyphs[g].x, px + ginfo->topLeftX);
                 gbv->glyphs[g].rowBytesOffset = 0;
             }
-            FLOOR_ASSIGN(gbv->glyphs[g].y, y + ginfo->topLeftY);
+            FLOOR_ASSIGN(gbv->glyphs[g].y, py + ginfo->topLeftY);
+
             /* copy image data into this array at x/y locations */
             x += ginfo->advanceX;
             y += ginfo->advanceY;
@@ -666,6 +673,11 @@
 
     (*env)->ReleasePrimitiveArrayCritical(env, glyphImages, imagePtrs,
                                           JNI_ABORT);
+    if (!glyphPositions) {
+        (*env)->SetFloatField(env, glyphlist, sunFontIDs.glyphListX, x);
+        (*env)->SetFloatField(env, glyphlist, sunFontIDs.glyphListY, y);
+    }
+
     return gbv;
 }
 
diff --git a/src/share/native/sun/font/HBShaper.c b/src/share/native/sun/font/HBShaper.c
new file mode 100644
index 0000000..47b6029
--- /dev/null
+++ b/src/share/native/sun/font/HBShaper.c
@@ -0,0 +1,327 @@
+/*
+ * 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 jmethodID gvdGrowMID = 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);
+    CHECK_NULL_RETURN(gvdGrowMID = (*env)->GetMethodID(env, gvdClass, "grow", "()V"), 0);
+    jniInited = 1;
+    return jniInited;
+}
+
+// gmask is the composite font slot mask
+// baseindex is to be added to the character (code point) index.
+jboolean storeGVData(JNIEnv* env,
+                     jobject gvdata, jint slot,
+                     jint baseIndex, int offset, jobject startPt,
+                     int charCount, int glyphCount, hb_glyph_info_t *glyphInfo,
+                     hb_glyph_position_t *glyphPos, float devScale) {
+
+    int i, needToGrow;
+    float x=0, y=0;
+    float startX, startY, advX, advY;
+    float scale = 1.0f / HBFloatToFixedScale / devScale;
+    unsigned int* glyphs;
+    float* positions;
+    int initialCount, glyphArrayLen, posArrayLen, maxGlyphs, storeadv, maxStore;
+    unsigned int* indices;
+    jarray glyphArray, posArray, inxArray;
+
+    if (!init_JNI_IDs(env)) {
+        return JNI_FALSE;
+    }
+
+    initialCount = (*env)->GetIntField(env, gvdata, gvdCountFID);
+    do {
+        glyphArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdGlyphsFID);
+        posArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdPositionsFID);
+        inxArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdIndicesFID);
+        if (glyphArray == NULL || posArray == NULL || inxArray == NULL) {
+            JNU_ThrowArrayIndexOutOfBoundsException(env, "");
+            return JNI_FALSE;
+        }
+        glyphArrayLen = (*env)->GetArrayLength(env, glyphArray);
+        posArrayLen = (*env)->GetArrayLength(env, posArray);
+        maxGlyphs = (charCount > glyphCount) ? charCount : glyphCount;
+        maxStore = maxGlyphs + initialCount;
+        needToGrow = (maxStore > glyphArrayLen) ||
+                     (maxStore * 2 + 2 >  posArrayLen);
+        if (needToGrow) {
+            (*env)->CallVoidMethod(env, gvdata, gvdGrowMID);
+            if ((*env)->ExceptionCheck(env)) {
+                return JNI_FALSE;
+            }
+        }
+    } while (needToGrow);
+
+    getFloat(env, startPt, &startX, &startY);
+
+    glyphs =
+        (unsigned int*)(*env)->GetPrimitiveArrayCritical(env, glyphArray, NULL);
+    if (glyphs == NULL) {
+        return JNI_FALSE;
+    }
+    positions = (jfloat*)(*env)->GetPrimitiveArrayCritical(env, posArray, NULL);
+    if (positions == NULL) {
+        (*env)->ReleasePrimitiveArrayCritical(env, glyphArray, glyphs, 0);
+        return JNI_FALSE;
+    }
+    indices =
+        (unsigned int*)(*env)->GetPrimitiveArrayCritical(env, inxArray, NULL);
+    if (indices == NULL) {
+        (*env)->ReleasePrimitiveArrayCritical(env, glyphArray, glyphs, 0);
+        (*env)->ReleasePrimitiveArrayCritical(env, posArray, positions, 0);
+        return JNI_FALSE;
+    }
+
+    for (i = 0; i < glyphCount; i++) {
+        int storei = i + initialCount;
+        int cluster = glyphInfo[i].cluster - offset;
+        indices[storei] = baseIndex + cluster;
+        glyphs[storei] = (unsigned int)(glyphInfo[i].codepoint & 0x00FFFFFF | slot);
+        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;
+        storei++;
+    }
+    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.
+    advX = startX + x;
+    advY = startY + y;
+    positions[(storeadv*2)] = advX;
+    positions[(storeadv*2)+1] = advY;
+    (*env)->ReleasePrimitiveArrayCritical(env, glyphArray, glyphs, 0);
+    (*env)->ReleasePrimitiveArrayCritical(env, posArray, positions, 0);
+    (*env)->ReleasePrimitiveArrayCritical(env, inxArray, indices, 0);
+    putFloat(env, startPt, advX, advY);
+    (*env)->SetIntField(env, gvdata, gvdCountFID, storeadv);
+
+    return JNI_TRUE;
+}
+
+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 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]);
+    if (!aat && (getenv("HB_NODEVTX") != NULL)) {
+        fi->devScale = fi->xPtSize / fi->ptSize;
+    } else {
+        fi->devScale = 1.0f;
+    }
+    return fi;
+}
+
+
+#define TYPO_KERN 0x00000001
+#define TYPO_LIGA 0x00000002
+#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 pFace,
+     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_face_t* hbface;
+     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;
+     char* kern = (flags & TYPO_KERN) ? "kern" : "-kern";
+     char* liga = (flags & TYPO_LIGA) ? "liga" : "-liga";
+     jboolean ret;
+     unsigned int buflen;
+
+     JDKFontInfo *jdkFontInfo =
+         createJDKFontInfo(env, font2D, fontStrike, ptSize, 
+                           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;
+
+     hbface = (hb_face_t*) jlong_to_ptr(pFace);
+     hbfont = hb_jdk_font_create(hbface, 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);
+     hb_buffer_set_cluster_level(buffer,
+                                 HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
+
+     chars = (*env)->GetCharArrayElements(env, text, NULL);
+     if ((*env)->ExceptionCheck(env)) {
+         hb_buffer_destroy(buffer);
+         hb_font_destroy(hbfont);
+         free((void*)jdkFontInfo);
+         return JNI_FALSE;
+     }
+     len = (*env)->GetArrayLength(env, text);
+
+     hb_buffer_add_utf16(buffer, chars, len, offset, limit-offset);
+
+     features = calloc(2, sizeof(hb_feature_t));
+     if (features) {
+         hb_feature_from_string(kern, -1, &features[featureCount++]);
+         hb_feature_from_string(liga, -1, &features[featureCount++]);
+     }
+
+     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);
+
+     ret = storeGVData(env, gvdata, slot, baseIndex, offset, startPt,
+                       limit - offset, glyphCount, glyphInfo, glyphPos,
+                       jdkFontInfo->devScale);
+
+     hb_buffer_destroy (buffer);
+     hb_font_destroy(hbfont);
+     free((void*)jdkFontInfo);
+     if (features != NULL) free(features);
+     (*env)->ReleaseCharArrayElements(env, text, chars, JNI_ABORT);
+     return ret;
+}
+
diff --git a/src/share/native/sun/font/fontconfig.h b/src/share/native/sun/font/fontconfig.h
new file mode 100644
index 0000000..2258251
--- /dev/null
+++ b/src/share/native/sun/font/fontconfig.h
@@ -0,0 +1,1010 @@
+/*
+ * fontconfig/fontconfig/fontconfig.h
+ *
+ * Copyright © 2001 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the author(s) not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  The authors make no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FONTCONFIG_H_
+#define _FONTCONFIG_H_
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+
+#if defined(__GNUC__) && (__GNUC__ >= 4)
+#define FC_ATTRIBUTE_SENTINEL(x) __attribute__((__sentinel__(0)))
+#else
+#define FC_ATTRIBUTE_SENTINEL(x)
+#endif
+
+#ifndef FcPublic
+#define FcPublic
+#endif
+
+typedef unsigned char	FcChar8;
+typedef unsigned short	FcChar16;
+typedef unsigned int	FcChar32;
+typedef int		FcBool;
+
+/*
+ * Current Fontconfig version number.  This same number
+ * must appear in the fontconfig configure.in file. Yes,
+ * it'a a pain to synchronize version numbers like this.
+ */
+
+#define FC_MAJOR	2
+#define FC_MINOR	11
+#define FC_REVISION	1
+
+#define FC_VERSION	((FC_MAJOR * 10000) + (FC_MINOR * 100) + (FC_REVISION))
+
+/*
+ * Current font cache file format version
+ * This is appended to the cache files so that multiple
+ * versions of the library will peacefully coexist
+ *
+ * Change this value whenever the disk format for the cache file
+ * changes in any non-compatible way.  Try to avoid such changes as
+ * it means multiple copies of the font information.
+ */
+
+#define FC_CACHE_VERSION    "4"
+
+#define FcTrue		1
+#define FcFalse		0
+
+#define FC_FAMILY	    "family"		/* String */
+#define FC_STYLE	    "style"		/* String */
+#define FC_SLANT	    "slant"		/* Int */
+#define FC_WEIGHT	    "weight"		/* Int */
+#define FC_SIZE		    "size"		/* Double */
+#define FC_ASPECT	    "aspect"		/* Double */
+#define FC_PIXEL_SIZE	    "pixelsize"		/* Double */
+#define FC_SPACING	    "spacing"		/* Int */
+#define FC_FOUNDRY	    "foundry"		/* String */
+#define FC_ANTIALIAS	    "antialias"		/* Bool (depends) */
+#define FC_HINTING	    "hinting"		/* Bool (true) */
+#define FC_HINT_STYLE	    "hintstyle"		/* Int */
+#define FC_VERTICAL_LAYOUT  "verticallayout"	/* Bool (false) */
+#define FC_AUTOHINT	    "autohint"		/* Bool (false) */
+/* FC_GLOBAL_ADVANCE is deprecated. this is simply ignored on freetype 2.4.5 or later */
+#define FC_GLOBAL_ADVANCE   "globaladvance"	/* Bool (true) */
+#define FC_WIDTH	    "width"		/* Int */
+#define FC_FILE		    "file"		/* String */
+#define FC_INDEX	    "index"		/* Int */
+#define FC_FT_FACE	    "ftface"		/* FT_Face */
+#define FC_RASTERIZER	    "rasterizer"	/* String (deprecated) */
+#define FC_OUTLINE	    "outline"		/* Bool */
+#define FC_SCALABLE	    "scalable"		/* Bool */
+#define FC_SCALE	    "scale"		/* double */
+#define FC_DPI		    "dpi"		/* double */
+#define FC_RGBA		    "rgba"		/* Int */
+#define FC_MINSPACE	    "minspace"		/* Bool use minimum line spacing */
+#define FC_SOURCE	    "source"		/* String (deprecated) */
+#define FC_CHARSET	    "charset"		/* CharSet */
+#define FC_LANG		    "lang"		/* String RFC 3066 langs */
+#define FC_FONTVERSION	    "fontversion"	/* Int from 'head' table */
+#define FC_FULLNAME	    "fullname"		/* String */
+#define FC_FAMILYLANG	    "familylang"	/* String RFC 3066 langs */
+#define FC_STYLELANG	    "stylelang"		/* String RFC 3066 langs */
+#define FC_FULLNAMELANG	    "fullnamelang"	/* String RFC 3066 langs */
+#define FC_CAPABILITY       "capability"	/* String */
+#define FC_FONTFORMAT	    "fontformat"	/* String */
+#define FC_EMBOLDEN	    "embolden"		/* Bool - true if emboldening needed*/
+#define FC_EMBEDDED_BITMAP  "embeddedbitmap"	/* Bool - true to enable embedded bitmaps */
+#define FC_DECORATIVE	    "decorative"	/* Bool - true if style is a decorative variant */
+#define FC_LCD_FILTER	    "lcdfilter"		/* Int */
+#define FC_FONT_FEATURES    "fontfeatures"	/* String */
+#define FC_NAMELANG	    "namelang"		/* String RFC 3866 langs */
+#define FC_PRGNAME	    "prgname"		/* String */
+#define FC_HASH		    "hash"		/* String */
+#define FC_POSTSCRIPT_NAME  "postscriptname"	/* String */
+
+#define FC_CACHE_SUFFIX		    ".cache-" FC_CACHE_VERSION
+#define FC_DIR_CACHE_FILE	    "fonts.cache-" FC_CACHE_VERSION
+#define FC_USER_CACHE_FILE	    ".fonts.cache-" FC_CACHE_VERSION
+
+/* Adjust outline rasterizer */
+#define FC_CHAR_WIDTH	    "charwidth"	/* Int */
+#define FC_CHAR_HEIGHT	    "charheight"/* Int */
+#define FC_MATRIX	    "matrix"    /* FcMatrix */
+
+#define FC_WEIGHT_THIN		    0
+#define FC_WEIGHT_EXTRALIGHT	    40
+#define FC_WEIGHT_ULTRALIGHT	    FC_WEIGHT_EXTRALIGHT
+#define FC_WEIGHT_LIGHT		    50
+#define FC_WEIGHT_BOOK		    75
+#define FC_WEIGHT_REGULAR	    80
+#define FC_WEIGHT_NORMAL	    FC_WEIGHT_REGULAR
+#define FC_WEIGHT_MEDIUM	    100
+#define FC_WEIGHT_DEMIBOLD	    180
+#define FC_WEIGHT_SEMIBOLD	    FC_WEIGHT_DEMIBOLD
+#define FC_WEIGHT_BOLD		    200
+#define FC_WEIGHT_EXTRABOLD	    205
+#define FC_WEIGHT_ULTRABOLD	    FC_WEIGHT_EXTRABOLD
+#define FC_WEIGHT_BLACK		    210
+#define FC_WEIGHT_HEAVY		    FC_WEIGHT_BLACK
+#define FC_WEIGHT_EXTRABLACK	    215
+#define FC_WEIGHT_ULTRABLACK	    FC_WEIGHT_EXTRABLACK
+
+#define FC_SLANT_ROMAN		    0
+#define FC_SLANT_ITALIC		    100
+#define FC_SLANT_OBLIQUE	    110
+
+#define FC_WIDTH_ULTRACONDENSED	    50
+#define FC_WIDTH_EXTRACONDENSED	    63
+#define FC_WIDTH_CONDENSED	    75
+#define FC_WIDTH_SEMICONDENSED	    87
+#define FC_WIDTH_NORMAL		    100
+#define FC_WIDTH_SEMIEXPANDED	    113
+#define FC_WIDTH_EXPANDED	    125
+#define FC_WIDTH_EXTRAEXPANDED	    150
+#define FC_WIDTH_ULTRAEXPANDED	    200
+
+#define FC_PROPORTIONAL		    0
+#define FC_DUAL			    90
+#define FC_MONO			    100
+#define FC_CHARCELL		    110
+
+/* sub-pixel order */
+#define FC_RGBA_UNKNOWN	    0
+#define FC_RGBA_RGB	    1
+#define FC_RGBA_BGR	    2
+#define FC_RGBA_VRGB	    3
+#define FC_RGBA_VBGR	    4
+#define FC_RGBA_NONE	    5
+
+/* hinting style */
+#define FC_HINT_NONE        0
+#define FC_HINT_SLIGHT      1
+#define FC_HINT_MEDIUM      2
+#define FC_HINT_FULL        3
+
+/* LCD filter */
+#define FC_LCD_NONE	    0
+#define FC_LCD_DEFAULT	    1
+#define FC_LCD_LIGHT	    2
+#define FC_LCD_LEGACY	    3
+
+typedef enum _FcType {
+    FcTypeUnknown = -1,
+    FcTypeVoid,
+    FcTypeInteger,
+    FcTypeDouble,
+    FcTypeString,
+    FcTypeBool,
+    FcTypeMatrix,
+    FcTypeCharSet,
+    FcTypeFTFace,
+    FcTypeLangSet
+} FcType;
+
+typedef struct _FcMatrix {
+    double xx, xy, yx, yy;
+} FcMatrix;
+
+#define FcMatrixInit(m)	((m)->xx = (m)->yy = 1, \
+			 (m)->xy = (m)->yx = 0)
+
+/*
+ * A data structure to represent the available glyphs in a font.
+ * This is represented as a sparse boolean btree.
+ */
+
+typedef struct _FcCharSet FcCharSet;
+
+typedef struct _FcObjectType {
+    const char	*object;
+    FcType	type;
+} FcObjectType;
+
+typedef struct _FcConstant {
+    const FcChar8  *name;
+    const char	*object;
+    int		value;
+} FcConstant;
+
+typedef enum _FcResult {
+    FcResultMatch, FcResultNoMatch, FcResultTypeMismatch, FcResultNoId,
+    FcResultOutOfMemory
+} FcResult;
+
+typedef struct _FcPattern   FcPattern;
+
+typedef struct _FcLangSet   FcLangSet;
+
+typedef struct _FcValue {
+    FcType	type;
+    union {
+	const FcChar8	*s;
+	int		i;
+	FcBool		b;
+	double		d;
+	const FcMatrix	*m;
+	const FcCharSet	*c;
+	void		*f;
+	const FcLangSet	*l;
+    } u;
+} FcValue;
+
+typedef struct _FcFontSet {
+    int		nfont;
+    int		sfont;
+    FcPattern	**fonts;
+} FcFontSet;
+
+typedef struct _FcObjectSet {
+    int		nobject;
+    int		sobject;
+    const char	**objects;
+} FcObjectSet;
+    
+typedef enum _FcMatchKind {
+    FcMatchPattern, FcMatchFont, FcMatchScan
+} FcMatchKind;
+
+typedef enum _FcLangResult {
+    FcLangEqual = 0,
+    FcLangDifferentCountry = 1,
+    FcLangDifferentTerritory = 1,
+    FcLangDifferentLang = 2
+} FcLangResult;
+
+typedef enum _FcSetName {
+    FcSetSystem = 0,
+    FcSetApplication = 1
+} FcSetName;
+
+typedef struct _FcAtomic FcAtomic;
+
+#if defined(__cplusplus) || defined(c_plusplus) /* for C++ V2.0 */
+#define _FCFUNCPROTOBEGIN extern "C" {	/* do not leave open across includes */
+#define _FCFUNCPROTOEND }
+#else
+#define _FCFUNCPROTOBEGIN
+#define _FCFUNCPROTOEND
+#endif
+
+typedef enum { FcEndianBig, FcEndianLittle } FcEndian;
+
+typedef struct _FcConfig    FcConfig;
+
+typedef struct _FcGlobalCache	FcFileCache;
+
+typedef struct _FcBlanks    FcBlanks;
+
+typedef struct _FcStrList   FcStrList;
+
+typedef struct _FcStrSet    FcStrSet;
+
+typedef struct _FcCache	    FcCache;
+
+_FCFUNCPROTOBEGIN
+
+/* fcblanks.c */
+FcPublic FcBlanks *
+FcBlanksCreate (void);
+
+FcPublic void
+FcBlanksDestroy (FcBlanks *b);
+
+FcPublic FcBool
+FcBlanksAdd (FcBlanks *b, FcChar32 ucs4);
+
+FcPublic FcBool
+FcBlanksIsMember (FcBlanks *b, FcChar32 ucs4);
+
+/* fccache.c */
+
+FcPublic const FcChar8 *
+FcCacheDir(const FcCache *c);
+
+FcPublic FcFontSet *
+FcCacheCopySet(const FcCache *c);
+
+FcPublic const FcChar8 *
+FcCacheSubdir (const FcCache *c, int i);
+
+FcPublic int
+FcCacheNumSubdir (const FcCache *c);
+
+FcPublic int
+FcCacheNumFont (const FcCache *c);
+
+FcPublic FcBool
+FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config);
+
+FcPublic FcBool
+FcDirCacheValid (const FcChar8 *cache_file);
+
+FcPublic FcBool
+FcDirCacheClean (const FcChar8 *cache_dir, FcBool verbose);
+
+FcPublic void
+FcCacheCreateTagFile (const FcConfig *config);
+
+/* fccfg.c */
+FcPublic FcChar8 *
+FcConfigHome (void);
+
+FcPublic FcBool
+FcConfigEnableHome (FcBool enable);
+
+FcPublic FcChar8 *
+FcConfigFilename (const FcChar8 *url);
+    
+FcPublic FcConfig *
+FcConfigCreate (void);
+
+FcPublic FcConfig *
+FcConfigReference (FcConfig *config);
+
+FcPublic void
+FcConfigDestroy (FcConfig *config);
+
+FcPublic FcBool
+FcConfigSetCurrent (FcConfig *config);
+
+FcPublic FcConfig *
+FcConfigGetCurrent (void);
+
+FcPublic FcBool
+FcConfigUptoDate (FcConfig *config);
+    
+FcPublic FcBool
+FcConfigBuildFonts (FcConfig *config);
+
+FcPublic FcStrList *
+FcConfigGetFontDirs (FcConfig   *config);
+
+FcPublic FcStrList *
+FcConfigGetConfigDirs (FcConfig   *config);
+
+FcPublic FcStrList *
+FcConfigGetConfigFiles (FcConfig    *config);
+
+FcPublic FcChar8 *
+FcConfigGetCache (FcConfig  *config);
+
+FcPublic FcBlanks *
+FcConfigGetBlanks (FcConfig *config);
+
+FcPublic FcStrList *
+FcConfigGetCacheDirs (const FcConfig	*config);
+
+FcPublic int
+FcConfigGetRescanInterval (FcConfig *config);
+
+FcPublic FcBool
+FcConfigSetRescanInterval (FcConfig *config, int rescanInterval);
+
+FcPublic FcFontSet *
+FcConfigGetFonts (FcConfig	*config,
+		  FcSetName	set);
+
+FcPublic FcBool
+FcConfigAppFontAddFile (FcConfig    *config,
+			const FcChar8  *file);
+
+FcPublic FcBool
+FcConfigAppFontAddDir (FcConfig	    *config,
+		       const FcChar8   *dir);
+
+FcPublic void
+FcConfigAppFontClear (FcConfig	    *config);
+
+FcPublic FcBool
+FcConfigSubstituteWithPat (FcConfig	*config,
+			   FcPattern	*p,
+			   FcPattern	*p_pat,
+			   FcMatchKind	kind);
+
+FcPublic FcBool
+FcConfigSubstitute (FcConfig	*config,
+		    FcPattern	*p,
+		    FcMatchKind	kind);
+
+FcPublic const FcChar8 *
+FcConfigGetSysRoot (const FcConfig *config);
+
+FcPublic void
+FcConfigSetSysRoot (FcConfig      *config,
+		    const FcChar8 *sysroot);
+
+/* fccharset.c */
+FcPublic FcCharSet*
+FcCharSetCreate (void);
+
+/* deprecated alias for FcCharSetCreate */
+FcPublic FcCharSet *
+FcCharSetNew (void);
+
+FcPublic void
+FcCharSetDestroy (FcCharSet *fcs);
+
+FcPublic FcBool
+FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4);
+
+FcPublic FcBool
+FcCharSetDelChar (FcCharSet *fcs, FcChar32 ucs4);
+
+FcPublic FcCharSet*
+FcCharSetCopy (FcCharSet *src);
+
+FcPublic FcBool
+FcCharSetEqual (const FcCharSet *a, const FcCharSet *b);
+
+FcPublic FcCharSet*
+FcCharSetIntersect (const FcCharSet *a, const FcCharSet *b);
+
+FcPublic FcCharSet*
+FcCharSetUnion (const FcCharSet *a, const FcCharSet *b);
+
+FcPublic FcCharSet*
+FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b);
+
+FcPublic FcBool
+FcCharSetMerge (FcCharSet *a, const FcCharSet *b, FcBool *changed);
+
+FcPublic FcBool
+FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4);
+
+FcPublic FcChar32
+FcCharSetCount (const FcCharSet *a);
+
+FcPublic FcChar32
+FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b);
+
+FcPublic FcChar32
+FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b);
+
+FcPublic FcBool
+FcCharSetIsSubset (const FcCharSet *a, const FcCharSet *b);
+
+#define FC_CHARSET_MAP_SIZE (256/32)
+#define FC_CHARSET_DONE	((FcChar32) -1)
+
+FcPublic FcChar32
+FcCharSetFirstPage (const FcCharSet *a, 
+		    FcChar32	    map[FC_CHARSET_MAP_SIZE],
+		    FcChar32	    *next);
+
+FcPublic FcChar32
+FcCharSetNextPage (const FcCharSet  *a, 
+		   FcChar32	    map[FC_CHARSET_MAP_SIZE],
+		   FcChar32	    *next);
+
+/*
+ * old coverage API, rather hard to use correctly
+ */
+
+FcPublic FcChar32
+FcCharSetCoverage (const FcCharSet *a, FcChar32 page, FcChar32 *result);
+
+/* fcdbg.c */
+FcPublic void
+FcValuePrint (const FcValue v);
+
+FcPublic void
+FcPatternPrint (const FcPattern *p);
+
+FcPublic void
+FcFontSetPrint (const FcFontSet *s);
+
+/* fcdefault.c */
+FcPublic FcStrSet *
+FcGetDefaultLangs (void);
+
+FcPublic void
+FcDefaultSubstitute (FcPattern *pattern);
+
+/* fcdir.c */
+FcPublic FcBool
+FcFileIsDir (const FcChar8 *file);
+
+FcPublic FcBool
+FcFileScan (FcFontSet	    *set,
+	    FcStrSet	    *dirs,
+	    FcFileCache	    *cache,
+	    FcBlanks	    *blanks,
+	    const FcChar8   *file,
+	    FcBool	    force);
+
+FcPublic FcBool
+FcDirScan (FcFontSet	    *set,
+	   FcStrSet	    *dirs,
+	   FcFileCache	    *cache,
+	   FcBlanks	    *blanks,
+	   const FcChar8    *dir,
+	   FcBool	    force);
+
+FcPublic FcBool
+FcDirSave (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir);
+
+FcPublic FcCache *
+FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file);
+
+FcPublic FcCache *
+FcDirCacheRescan (const FcChar8 *dir, FcConfig *config);
+    
+FcPublic FcCache *
+FcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config);
+
+FcPublic FcCache *
+FcDirCacheLoadFile (const FcChar8 *cache_file, struct stat *file_stat);
+
+FcPublic void
+FcDirCacheUnload (FcCache *cache);
+
+/* fcfreetype.c */
+FcPublic FcPattern *
+FcFreeTypeQuery (const FcChar8 *file, int id, FcBlanks *blanks, int *count);
+
+/* fcfs.c */
+
+FcPublic FcFontSet *
+FcFontSetCreate (void);
+
+FcPublic void
+FcFontSetDestroy (FcFontSet *s);
+
+FcPublic FcBool
+FcFontSetAdd (FcFontSet *s, FcPattern *font);
+
+/* fcinit.c */
+FcPublic FcConfig *
+FcInitLoadConfig (void);
+
+FcPublic FcConfig *
+FcInitLoadConfigAndFonts (void);
+
+FcPublic FcBool
+FcInit (void);
+
+FcPublic void
+FcFini (void);
+
+FcPublic int
+FcGetVersion (void);
+
+FcPublic FcBool
+FcInitReinitialize (void);
+
+FcPublic FcBool
+FcInitBringUptoDate (void);
+
+/* fclang.c */
+FcPublic FcStrSet *
+FcGetLangs (void);
+
+FcPublic FcChar8 *
+FcLangNormalize (const FcChar8 *lang);
+
+FcPublic const FcCharSet *
+FcLangGetCharSet (const FcChar8 *lang);
+
+FcPublic FcLangSet*
+FcLangSetCreate (void);
+
+FcPublic void
+FcLangSetDestroy (FcLangSet *ls);
+
+FcPublic FcLangSet*
+FcLangSetCopy (const FcLangSet *ls);
+
+FcPublic FcBool
+FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang);
+
+FcPublic FcBool
+FcLangSetDel (FcLangSet *ls, const FcChar8 *lang);
+
+FcPublic FcLangResult
+FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang);
+
+FcPublic FcLangResult
+FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb);
+
+FcPublic FcBool
+FcLangSetContains (const FcLangSet *lsa, const FcLangSet *lsb);
+
+FcPublic FcBool
+FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb);
+
+FcPublic FcChar32
+FcLangSetHash (const FcLangSet *ls);
+
+FcPublic FcStrSet *
+FcLangSetGetLangs (const FcLangSet *ls);
+
+FcPublic FcLangSet *
+FcLangSetUnion (const FcLangSet *a, const FcLangSet *b);
+
+FcPublic FcLangSet *
+FcLangSetSubtract (const FcLangSet *a, const FcLangSet *b);
+
+/* fclist.c */
+FcPublic FcObjectSet *
+FcObjectSetCreate (void);
+
+FcPublic FcBool
+FcObjectSetAdd (FcObjectSet *os, const char *object);
+
+FcPublic void
+FcObjectSetDestroy (FcObjectSet *os);
+
+FcPublic FcObjectSet *
+FcObjectSetVaBuild (const char *first, va_list va);
+
+FcPublic FcObjectSet *
+FcObjectSetBuild (const char *first, ...) FC_ATTRIBUTE_SENTINEL(0);
+
+FcPublic FcFontSet *
+FcFontSetList (FcConfig	    *config,
+	       FcFontSet    **sets,
+	       int	    nsets,
+	       FcPattern    *p,
+	       FcObjectSet  *os);
+
+FcPublic FcFontSet *
+FcFontList (FcConfig	*config,
+	    FcPattern	*p,
+	    FcObjectSet *os);
+
+/* fcatomic.c */
+
+FcPublic FcAtomic *
+FcAtomicCreate (const FcChar8   *file);
+
+FcPublic FcBool
+FcAtomicLock (FcAtomic *atomic);
+
+FcPublic FcChar8 *
+FcAtomicNewFile (FcAtomic *atomic);
+
+FcPublic FcChar8 *
+FcAtomicOrigFile (FcAtomic *atomic);
+
+FcPublic FcBool
+FcAtomicReplaceOrig (FcAtomic *atomic);
+
+FcPublic void
+FcAtomicDeleteNew (FcAtomic *atomic);
+
+FcPublic void
+FcAtomicUnlock (FcAtomic *atomic);
+
+FcPublic void
+FcAtomicDestroy (FcAtomic *atomic);
+
+/* fcmatch.c */
+FcPublic FcPattern *
+FcFontSetMatch (FcConfig    *config,
+		FcFontSet   **sets,
+		int	    nsets,
+		FcPattern   *p,
+		FcResult    *result);
+
+FcPublic FcPattern *
+FcFontMatch (FcConfig	*config,
+	     FcPattern	*p, 
+	     FcResult	*result);
+
+FcPublic FcPattern *
+FcFontRenderPrepare (FcConfig	    *config,
+		     FcPattern	    *pat,
+		     FcPattern	    *font);
+
+FcPublic FcFontSet *
+FcFontSetSort (FcConfig	    *config,
+	       FcFontSet    **sets,
+	       int	    nsets,
+	       FcPattern    *p,
+	       FcBool	    trim,
+	       FcCharSet    **csp,
+	       FcResult	    *result);
+
+FcPublic FcFontSet *
+FcFontSort (FcConfig	 *config,
+	    FcPattern    *p,
+	    FcBool	 trim,
+	    FcCharSet    **csp,
+	    FcResult	 *result);
+
+FcPublic void
+FcFontSetSortDestroy (FcFontSet *fs);
+
+/* fcmatrix.c */
+FcPublic FcMatrix *
+FcMatrixCopy (const FcMatrix *mat);
+
+FcPublic FcBool
+FcMatrixEqual (const FcMatrix *mat1, const FcMatrix *mat2);
+
+FcPublic void
+FcMatrixMultiply (FcMatrix *result, const FcMatrix *a, const FcMatrix *b);
+
+FcPublic void
+FcMatrixRotate (FcMatrix *m, double c, double s);
+
+FcPublic void
+FcMatrixScale (FcMatrix *m, double sx, double sy);
+
+FcPublic void
+FcMatrixShear (FcMatrix *m, double sh, double sv);
+
+/* fcname.c */
+
+/* Deprecated.  Does nothing.  Returns FcFalse. */
+FcPublic FcBool
+FcNameRegisterObjectTypes (const FcObjectType *types, int ntype);
+
+/* Deprecated.  Does nothing.  Returns FcFalse. */
+FcPublic FcBool
+FcNameUnregisterObjectTypes (const FcObjectType *types, int ntype);
+
+FcPublic const FcObjectType *
+FcNameGetObjectType (const char *object);
+
+/* Deprecated.  Does nothing.  Returns FcFalse. */
+FcPublic FcBool
+FcNameRegisterConstants (const FcConstant *consts, int nconsts);
+
+/* Deprecated.  Does nothing.  Returns FcFalse. */
+FcPublic FcBool
+FcNameUnregisterConstants (const FcConstant *consts, int nconsts);
+
+FcPublic const FcConstant *
+FcNameGetConstant (const FcChar8 *string);
+
+FcPublic FcBool
+FcNameConstant (const FcChar8 *string, int *result);
+
+FcPublic FcPattern *
+FcNameParse (const FcChar8 *name);
+
+FcPublic FcChar8 *
+FcNameUnparse (FcPattern *pat);
+
+/* fcpat.c */
+FcPublic FcPattern *
+FcPatternCreate (void);
+
+FcPublic FcPattern *
+FcPatternDuplicate (const FcPattern *p);
+
+FcPublic void
+FcPatternReference (FcPattern *p);
+
+FcPublic FcPattern *
+FcPatternFilter (FcPattern *p, const FcObjectSet *os);
+
+FcPublic void
+FcValueDestroy (FcValue v);
+
+FcPublic FcBool
+FcValueEqual (FcValue va, FcValue vb);
+
+FcPublic FcValue
+FcValueSave (FcValue v);
+
+FcPublic void
+FcPatternDestroy (FcPattern *p);
+
+FcPublic FcBool
+FcPatternEqual (const FcPattern *pa, const FcPattern *pb);
+
+FcPublic FcBool
+FcPatternEqualSubset (const FcPattern *pa, const FcPattern *pb, const FcObjectSet *os);
+
+FcPublic FcChar32
+FcPatternHash (const FcPattern *p);
+
+FcPublic FcBool
+FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append);
+    
+FcPublic FcBool
+FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append);
+    
+FcPublic FcResult
+FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v);
+    
+FcPublic FcBool
+FcPatternDel (FcPattern *p, const char *object);
+
+FcPublic FcBool
+FcPatternRemove (FcPattern *p, const char *object, int id);
+
+FcPublic FcBool
+FcPatternAddInteger (FcPattern *p, const char *object, int i);
+
+FcPublic FcBool
+FcPatternAddDouble (FcPattern *p, const char *object, double d);
+
+FcPublic FcBool
+FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s);
+
+FcPublic FcBool
+FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s);
+
+FcPublic FcBool
+FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c);
+
+FcPublic FcBool
+FcPatternAddBool (FcPattern *p, const char *object, FcBool b);
+
+FcPublic FcBool
+FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls);
+
+FcPublic FcResult
+FcPatternGetInteger (const FcPattern *p, const char *object, int n, int *i);
+
+FcPublic FcResult
+FcPatternGetDouble (const FcPattern *p, const char *object, int n, double *d);
+
+FcPublic FcResult
+FcPatternGetString (const FcPattern *p, const char *object, int n, FcChar8 ** s);
+
+FcPublic FcResult
+FcPatternGetMatrix (const FcPattern *p, const char *object, int n, FcMatrix **s);
+
+FcPublic FcResult
+FcPatternGetCharSet (const FcPattern *p, const char *object, int n, FcCharSet **c);
+
+FcPublic FcResult
+FcPatternGetBool (const FcPattern *p, const char *object, int n, FcBool *b);
+
+FcPublic FcResult
+FcPatternGetLangSet (const FcPattern *p, const char *object, int n, FcLangSet **ls);
+
+FcPublic FcPattern *
+FcPatternVaBuild (FcPattern *p, va_list va);
+    
+FcPublic FcPattern *
+FcPatternBuild (FcPattern *p, ...) FC_ATTRIBUTE_SENTINEL(0);
+
+FcPublic FcChar8 *
+FcPatternFormat (FcPattern *pat, const FcChar8 *format);
+
+/* fcstr.c */
+
+FcPublic FcChar8 *
+FcStrCopy (const FcChar8 *s);
+
+FcPublic FcChar8 *
+FcStrCopyFilename (const FcChar8 *s);
+    
+FcPublic FcChar8 *
+FcStrPlus (const FcChar8 *s1, const FcChar8 *s2);
+    
+FcPublic void
+FcStrFree (FcChar8 *s);
+
+/* These are ASCII only, suitable only for pattern element names */
+#define FcIsUpper(c)	((0101 <= (c) && (c) <= 0132))
+#define FcIsLower(c)	((0141 <= (c) && (c) <= 0172))
+#define FcToLower(c)	(FcIsUpper(c) ? (c) - 0101 + 0141 : (c))
+
+FcPublic FcChar8 *
+FcStrDowncase (const FcChar8 *s);
+
+FcPublic int
+FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2);
+
+FcPublic int
+FcStrCmp (const FcChar8 *s1, const FcChar8 *s2);
+
+FcPublic const FcChar8 *
+FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2);
+
+FcPublic const FcChar8 *
+FcStrStr (const FcChar8 *s1, const FcChar8 *s2);
+
+FcPublic int
+FcUtf8ToUcs4 (const FcChar8 *src_orig,
+	      FcChar32	    *dst,
+	      int	    len);
+
+FcPublic FcBool
+FcUtf8Len (const FcChar8    *string,
+	   int		    len,
+	   int		    *nchar,
+	   int		    *wchar);
+
+#define FC_UTF8_MAX_LEN	6
+
+FcPublic int
+FcUcs4ToUtf8 (FcChar32	ucs4,
+	      FcChar8	dest[FC_UTF8_MAX_LEN]);
+
+FcPublic int
+FcUtf16ToUcs4 (const FcChar8	*src_orig,
+	       FcEndian		endian,
+	       FcChar32		*dst,
+	       int		len);	    /* in bytes */
+
+FcPublic FcBool
+FcUtf16Len (const FcChar8   *string,
+	    FcEndian	    endian,
+	    int		    len,	    /* in bytes */
+	    int		    *nchar,
+	    int		    *wchar);
+
+FcPublic FcChar8 *
+FcStrDirname (const FcChar8 *file);
+
+FcPublic FcChar8 *
+FcStrBasename (const FcChar8 *file);
+
+FcPublic FcStrSet *
+FcStrSetCreate (void);
+
+FcPublic FcBool
+FcStrSetMember (FcStrSet *set, const FcChar8 *s);
+
+FcPublic FcBool
+FcStrSetEqual (FcStrSet *sa, FcStrSet *sb);
+
+FcPublic FcBool
+FcStrSetAdd (FcStrSet *set, const FcChar8 *s);
+
+FcPublic FcBool
+FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s);
+
+FcPublic FcBool
+FcStrSetDel (FcStrSet *set, const FcChar8 *s);
+
+FcPublic void
+FcStrSetDestroy (FcStrSet *set);
+
+FcPublic FcStrList *
+FcStrListCreate (FcStrSet *set);
+
+FcPublic void
+FcStrListFirst (FcStrList *list);
+
+FcPublic FcChar8 *
+FcStrListNext (FcStrList *list);
+
+FcPublic void
+FcStrListDone (FcStrList *list);
+
+/* fcxml.c */
+FcPublic FcBool
+FcConfigParseAndLoad (FcConfig *config, const FcChar8 *file, FcBool complain);
+
+_FCFUNCPROTOEND
+
+#undef FC_ATTRIBUTE_SENTINEL
+
+
+#ifndef _FCINT_H_
+
+/*
+ * Deprecated functions are placed here to help users fix their code without
+ * digging through documentation
+ */
+ 
+#define FcConfigGetRescanInverval   FcConfigGetRescanInverval_REPLACE_BY_FcConfigGetRescanInterval
+#define FcConfigSetRescanInverval   FcConfigSetRescanInverval_REPLACE_BY_FcConfigSetRescanInterval
+
+#endif
+
+#endif /* _FONTCONFIG_H_ */
diff --git a/src/share/native/sun/font/freetypeScaler.c b/src/share/native/sun/font/freetypeScaler.c
index 1e417cb..cac025d 100644
--- a/src/share/native/sun/font/freetypeScaler.c
+++ b/src/share/native/sun/font/freetypeScaler.c
@@ -25,19 +25,35 @@
 
 #include "jni.h"
 #include "jni_util.h"
-#include "jlong.h"
+#include "jvm_md.h"
 #include "sunfontids.h"
 #include "sun_font_FreetypeFontScaler.h"
 
-#include<stdlib.h>
+#include <stdlib.h>
+#if defined(_WIN32) || defined(MACOSX)
+#define DISABLE_FONTCONFIG
+#endif
+
 #include <math.h>
+
+#ifndef DISABLE_FONTCONFIG
+#include <dlfcn.h>
+#endif
+
 #include "ft2build.h"
+#include FT_LCD_FILTER_H
 #include FT_FREETYPE_H
 #include FT_GLYPH_H
 #include FT_BBOX_H
 #include FT_SIZES_H
 #include FT_OUTLINE_H
 #include FT_SYNTHESIS_H
+#include FT_LCD_FILTER_H
+
+#ifndef DISABLE_FONTCONFIG
+/* Use bundled fontconfig.h for now */
+#include "fontconfig.h"
+#endif
 
 #include "fontscaler.h"
 
@@ -45,7 +61,24 @@
 #define  FloatToFTFixed(f) (FT_Fixed)((f) * (float)(ftFixed1))
 #define  FTFixedToFloat(x) ((x) / (float)(ftFixed1))
 #define  FT26Dot6ToFloat(x)  ((x) / ((float) (1<<6)))
-#define  ROUND(x) ((int) (x+0.5))
+#define  FT26Dot6ToDouble(x)  ((x) / ((double) (1<<6)))
+#define  ROUND(x) ((int) ((x<0) ? (x-0.5) : (x+0.5)))
+#define  DEFAULT_DPI 72
+#define  MAX_DPI 1024
+#define  ADJUST_FONT_SIZE(X, DPI) (((X)*DEFAULT_DPI + ((DPI)>>1))/(DPI))
+#define  MAX_FCSIZE_LTL_DISABLED 12.0
+
+#ifndef DISABLE_FONTCONFIG
+#define FONTCONFIG_DLL JNI_LIB_NAME("fontconfig")
+#define FONTCONFIG_DLL_VERSIONED VERSIONED_JNI_LIB_NAME("fontconfig", "1")
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE  1
+#endif
 
 typedef struct {
     /* Important note:
@@ -77,7 +110,12 @@
     jint       fmType;        /* fractional metrics - on/off */
     jboolean   doBold;        /* perform algorithmic bolding? */
     jboolean   doItalize;     /* perform algorithmic italicizing? */
-    int        renderFlags;   /* configuration specific to particular engine */
+
+    /* Fontconfig info */
+    FT_Render_Mode  renderFlags;
+    FT_Int32        loadFlags;
+    FT_LcdFilter    lcdFilter;
+
     int        pathType;
     int        ptsz;          /* size in points */
 } FTScalerContext;
@@ -93,12 +131,165 @@
 /**************** Error handling utilities *****************/
 
 static jmethodID invalidateScalerMID;
+static jmethodID getDefaultToolkitMID;
+static jclass tkClass;
+static jmethodID getScreenResolutionMID;
+static jfieldID platNameFID;
+
+#ifndef DISABLE_FONTCONFIG
+typedef FcBool (*FcPatternAddPtrType) (FcPattern *p, const char *object, FcValue value, FcBool append);
+typedef FcBool (*FcPatternAddBoolPtrType) (FcPattern *p, const char *object, FcBool b);
+typedef FcBool (*FcPatternAddDoublePtrType) (FcPattern *p, const char *object, double d);
+typedef FcBool (*FcConfigSubstitutePtrType) (FcConfig *config, FcPattern *p, FcMatchKind kind);
+typedef void (*FcDefaultSubstitutePtrType) (FcPattern *pattern);
+typedef FcPattern* (*FcPatternCreatePtrType) ();
+typedef FcPattern* (*FcFontMatchPtrType) (FcConfig *config, FcPattern *p, FcResult *result);
+typedef void (*FcPatternDestroyPtrType) (FcPattern *p);
+typedef FcResult (*FcPatternGetBoolPtrType) (const FcPattern *p, const char *object, int n, FcBool *b);
+typedef FcResult (*FcPatternGetIntegerPtrType) (const FcPattern *p, const char *object, int n, int *i);
+typedef FT_Error (*FtLibrarySetLcdFilterPtrType) (FT_Library library, FT_LcdFilter  filter);
+#endif
+
+static void *libFontConfig = NULL;
+static jboolean logFC = JNI_FALSE;
+static jboolean logFFS = JNI_FALSE;
+
+#ifndef DISABLE_FONTCONFIG
+static FcPatternAddPtrType FcPatternAddPtr;
+static FcPatternAddBoolPtrType FcPatternAddBoolPtr;
+static FcPatternAddDoublePtrType FcPatternAddDoublePtr;
+static FcConfigSubstitutePtrType FcConfigSubstitutePtr;
+static FcDefaultSubstitutePtrType FcDefaultSubstitutePtr;
+static FcPatternCreatePtrType FcPatternCreatePtr;
+static FcFontMatchPtrType FcFontMatchPtr;
+static FcPatternDestroyPtrType FcPatternDestroyPtr;
+static FcPatternGetBoolPtrType FcPatternGetBoolPtr;
+static FcPatternGetIntegerPtrType FcPatternGetIntegerPtr;
+#endif
+
+static void* openFontConfig() {
+    void* libfontconfig = NULL;
+#ifndef DISABLE_FONTCONFIG
+    char *fcLogEnabled = getenv("OPENJDK_FFS_LOG_FC");
+
+    if (fcLogEnabled != NULL && !strcmp(fcLogEnabled, "yes")) {
+        logFC = JNI_TRUE;
+    }
+
+    char *useFC = getenv("OPENJDK_FFS_USE_FC");
+    if (useFC != NULL && !strcmp(useFC, "no")) {
+        if (logFC) fprintf(stderr, "FC_LOG: fontconfig disabled in freetypescaler\n");
+        return NULL;
+    }
+
+    libfontconfig = dlopen(FONTCONFIG_DLL_VERSIONED, RTLD_LOCAL | RTLD_LAZY);
+    if (libfontconfig == NULL) {
+        libfontconfig = dlopen(FONTCONFIG_DLL, RTLD_LOCAL | RTLD_LAZY);
+        if (libfontconfig == NULL) {
+            if (logFC) fprintf(stderr, "FC_LOG: cannot open %s\n", FONTCONFIG_DLL);
+            return NULL;
+        }
+    }
+#endif
+    return libfontconfig;
+}
 
 JNIEXPORT void JNICALL
 Java_sun_font_FreetypeFontScaler_initIDs(
-        JNIEnv *env, jobject scaler, jclass FFSClass) {
+        JNIEnv *env, jobject scaler, jclass FFSClass, jclass TKClass, jclass PFClass) {
+    char *fssLogEnabled = getenv("OPENJDK_LOG_FFS");
+
+    if (fssLogEnabled != NULL && !strcmp(fssLogEnabled, "yes")) {
+        logFFS = JNI_TRUE;
+    }
+
     invalidateScalerMID =
         (*env)->GetMethodID(env, FFSClass, "invalidateScaler", "()V");
+    getDefaultToolkitMID =
+        (*env)->GetStaticMethodID(env, TKClass, "getDefaultToolkit",
+                                  "()Ljava/awt/Toolkit;");
+    getScreenResolutionMID =
+        (*env)->GetMethodID(env, TKClass, "getScreenResolution", "()I");
+    tkClass = (*env)->NewGlobalRef(env, TKClass);
+    platNameFID = (*env)->GetFieldID(env, PFClass, "platName", "Ljava/lang/String;");
+    libFontConfig = openFontConfig();
+#ifndef DISABLE_FONTCONFIG
+    if (libFontConfig) {
+        FcPatternAddPtr = (FcPatternAddPtrType) dlsym(libFontConfig, "FcPatternAdd");
+        FcPatternAddBoolPtr = (FcPatternAddBoolPtrType) dlsym(libFontConfig, "FcPatternAddBool");
+        FcPatternAddDoublePtr = (FcPatternAddDoublePtrType) dlsym(libFontConfig, "FcPatternAddDouble");
+        FcConfigSubstitutePtr = (FcConfigSubstitutePtrType) dlsym(libFontConfig, "FcConfigSubstitute");
+        FcDefaultSubstitutePtr = (FcDefaultSubstitutePtrType)  dlsym(libFontConfig, "FcDefaultSubstitute");
+        FcPatternCreatePtr = (FcPatternCreatePtrType)  dlsym(libFontConfig, "FcPatternCreate");
+        FcFontMatchPtr = (FcFontMatchPtrType)  dlsym(libFontConfig, "FcFontMatch");
+        FcPatternDestroyPtr = (FcPatternDestroyPtrType)  dlsym(libFontConfig, "FcPatternDestroy");
+        FcPatternGetBoolPtr = (FcPatternGetBoolPtrType)  dlsym(libFontConfig, "FcPatternGetBool");
+        FcPatternGetIntegerPtr = (FcPatternGetIntegerPtrType)  dlsym(libFontConfig, "FcPatternGetInteger");
+    }
+#endif
+}
+
+static FT_Error FT_Library_SetLcdFilter_Proxy(FT_Library library, FT_LcdFilter  filter) {
+#ifndef DISABLE_FONTCONFIG
+    static FtLibrarySetLcdFilterPtrType FtLibrarySetLcdFilterPtr = NULL;
+    static int ftLibrarySetLcdFilterNotChecked = 1;
+    if (ftLibrarySetLcdFilterNotChecked) {
+        if (logFC) fprintf(stderr, "FC_LOG: Lookup FT_Library_SetLcdFilter: ");
+        FtLibrarySetLcdFilterPtr = (FtLibrarySetLcdFilterPtrType) dlsym(RTLD_DEFAULT, "FT_Library_SetLcdFilter");
+        if (logFC) fprintf(stderr, (FtLibrarySetLcdFilterPtr)? "found\n" : "not found\n");
+        ftLibrarySetLcdFilterNotChecked = 0;
+    }
+    if (FtLibrarySetLcdFilterPtr) {
+        return (*FtLibrarySetLcdFilterPtr)(library, filter);
+    } else {
+        if (logFC) fprintf(stderr, "FC_LOG: Skipping FT_Library_SetLcdFilter\n");
+    }
+
+    return 0;
+#else
+    return FT_Library_SetLcdFilter(library, filter);
+#endif
+}
+
+static char* getPhysFontName(JNIEnv *env, jobject font2d) {
+    jstring jstr;
+    jstr = (*env)->GetObjectField(env, font2d, platNameFID);
+    return (char*)(*env)->GetStringUTFChars(env, jstr, NULL);
+}
+
+static int getScreenResolution(JNIEnv *env) {
+/*
+ * Actual screen dpi is necessary only for fontconfig requests
+ */
+#ifndef DISABLE_FONTCONFIG
+    jthrowable exc;
+    jclass tk = (*env)->CallStaticObjectMethod(
+        env, tkClass, getDefaultToolkitMID);
+    int dpi = (*env)->CallIntMethod(env, tk, getScreenResolutionMID);
+
+    /* Test if there is no exception here (can get java.awt.HeadlessException)
+     * Fallback to default DPI otherwise
+     */
+    exc = (*env)->ExceptionOccurred(env);
+    if (exc) {
+        (*env)->ExceptionClear(env);
+        return DEFAULT_DPI;
+    }
+
+    /* Some configurations report invalid dpi settings */
+    if (dpi > MAX_DPI) {
+        if (logFFS) {
+            fprintf(stderr, "FFS_LOG: Invalid dpi reported (%d) replaced with default (%d)\n", dpi, DEFAULT_DPI);
+        }
+        return DEFAULT_DPI;
+    }
+    if (logFFS) {
+        fprintf(stderr, "FFS_LOG: Screen Resolution (%d) dpi\n", dpi);
+    }
+    return dpi;
+#else
+    return DEFAULT_DPI;
+#endif
 }
 
 static void freeNativeResources(JNIEnv *env, FTScalerInfo* scalerInfo) {
@@ -371,26 +562,248 @@
     return ptr_to_jlong(context);
 }
 
-static int setupFTContext(JNIEnv *env,
-                          jobject font2D,
-                          FTScalerInfo *scalerInfo,
-                          FTScalerContext *context) {
-    int errCode = 0;
+static void setDefaultScalerSettings(FTScalerContext *context) {
+    if (context->aaType == TEXT_AA_OFF) {
+        context->loadFlags = FT_LOAD_TARGET_MONO;
+    } else if (context->aaType == TEXT_AA_ON) {
+        context->loadFlags = FT_LOAD_TARGET_NORMAL;
+    } else {
+        context->lcdFilter = FT_LCD_FILTER_LIGHT;
+        if (context->aaType == TEXT_AA_LCD_HRGB ||
+            context->aaType == TEXT_AA_LCD_HBGR) {
+            context->loadFlags = FT_LOAD_TARGET_LCD;
+        } else {
+            context->loadFlags = FT_LOAD_TARGET_LCD_V;
+        }
+    }
+    context->renderFlags = FT_LOAD_TARGET_MODE(context->loadFlags);
+}
 
+#ifndef DISABLE_FONTCONFIG
+static void setupLoadRenderFlags(FTScalerContext *context, int fcHintStyle, FcBool fcAutohint, FcBool fcAutohintSet,
+                          FT_Int32 fcLoadFlags, FT_Render_Mode fcRenderFlags, double fcSize)
+{
+    if (fcSize > MAX_FCSIZE_LTL_DISABLED  ||  !fcAutohintSet || fcAutohint) {
+        switch (fcHintStyle) {
+            case FC_HINT_NONE:
+                context->loadFlags = FT_LOAD_NO_HINTING;
+                break;
+            case FC_HINT_SLIGHT:
+                context->loadFlags = (fcRenderFlags != FT_RENDER_MODE_MONO) ? FT_LOAD_TARGET_LIGHT : FT_LOAD_NO_HINTING;
+                break;
+            default:
+                context->loadFlags = fcLoadFlags;
+        }
+    } else {
+        context->loadFlags = fcLoadFlags;
+    }
+
+    context->renderFlags = fcRenderFlags;
+
+    if (fcAutohintSet && fcAutohint) {
+        context->loadFlags |= FT_LOAD_FORCE_AUTOHINT;
+    }
+}
+#endif
+
+static int setupFTContext(JNIEnv *env, jobject font2D, FTScalerInfo *scalerInfo, FTScalerContext *context,
+                          FT_Bool configureFont) {
+    int errCode = 0;
     scalerInfo->env = env;
     scalerInfo->font2D = font2D;
 
     if (context != NULL) {
+        FT_UInt dpi = (FT_UInt) getScreenResolution(env);
         FT_Set_Transform(scalerInfo->face, &context->transform, NULL);
 
-        errCode = FT_Set_Char_Size(scalerInfo->face, 0, context->ptsz, 72, 72);
+        errCode = FT_Set_Char_Size(scalerInfo->face, 0, ADJUST_FONT_SIZE(context->ptsz, dpi), dpi, dpi);
+        if (errCode) return errCode;
 
-        if (errCode == 0) {
-            errCode = FT_Activate_Size(scalerInfo->face->size);
+        errCode = FT_Activate_Size(scalerInfo->face->size);
+        if (errCode) return errCode;
+        if (configureFont) {
+            context->renderFlags = FT_RENDER_MODE_NORMAL;
+            context->lcdFilter = FT_LCD_FILTER_NONE;
+            context->loadFlags = FT_LOAD_DEFAULT;
+
+            if (libFontConfig == NULL) {
+                setDefaultScalerSettings(context);
+                return 0;
+            }
+#ifndef DISABLE_FONTCONFIG
+            FcPattern *fcPattern = 0;
+            fcPattern = (*FcPatternCreatePtr)();
+            FcValue fcValue;
+            fcValue.type = FcTypeString;
+            char *fontName = getPhysFontName(env, font2D);
+
+            if (logFC) fprintf(stderr, "FC_LOG: %s ", fontName);
+
+            fcValue.u.s = fontName;
+            (*FcPatternAddPtr)(fcPattern, FC_FILE, fcValue, FcTrue);
+            (*FcPatternAddBoolPtr)(fcPattern, FC_SCALABLE, FcTrue);
+            double fcSize = FT26Dot6ToDouble(ADJUST_FONT_SIZE(context->ptsz, dpi));
+            (*FcPatternAddDoublePtr)(fcPattern, FC_SIZE, fcSize);
+
+            if (logFC) fprintf(stderr, " size=%f", fcSize);
+
+            (*FcConfigSubstitutePtr)(0, fcPattern, FcMatchPattern);
+            (*FcDefaultSubstitutePtr)(fcPattern);
+            FcResult matchResult = FcResultNoMatch;
+            FcPattern *resultPattern = 0;
+            resultPattern = (*FcFontMatchPtr)(0, fcPattern, &matchResult);
+            if (matchResult != FcResultMatch) {
+                (*FcPatternDestroyPtr)(fcPattern);
+                if (logFC) fprintf(stderr, " - NOT FOUND\n");
+                setDefaultScalerSettings(context);
+                return 0;
+            }
+            if (logFC) fprintf(stderr, "\nFC_LOG:   ");
+            (*FcPatternDestroyPtr)(fcPattern);
+            FcPattern *pattern = resultPattern;
+
+            FcBool fcHinting = FcFalse;
+            FcBool fcHintingSet = (*FcPatternGetBoolPtr)(pattern, FC_HINTING, 0, &fcHinting) == FcResultMatch;
+
+            if (logFC && fcHintingSet) fprintf(stderr, "FC_HINTING(%d) ", fcHinting);
+
+            int fcHintStyle = FC_HINT_NONE;
+            FcBool fcHintStyleSet = (*FcPatternGetIntegerPtr)(pattern, FC_HINT_STYLE, 0, &fcHintStyle) == FcResultMatch;
+
+            if (logFC && fcHintStyleSet) {
+                switch (fcHintStyle) {
+                    case FC_HINT_NONE:
+                        fprintf(stderr, "FC_HINT_NONE ");
+                        break;
+                    case FC_HINT_SLIGHT:
+                        fprintf(stderr, "FC_HINT_SLIGHT ");
+                        break;
+                    case FC_HINT_MEDIUM:
+                        fprintf(stderr, "FC_HINT_MEDIUM ");
+                        break;
+                    case FC_HINT_FULL:
+                        fprintf(stderr, "FC_HINT_FULL ");
+                        break;
+                    default:
+                        fprintf(stderr, "FC_HINT_UNKNOWN ");
+                        break;
+                }
+            }
+
+            if (fcHintingSet && !fcHinting) {
+                fcHintStyleSet = FcTrue;
+                fcHintStyle = FC_HINT_NONE;
+            }
+
+            if (fcHintStyleSet && fcHintStyle == FC_HINT_NONE) {
+                fcHinting = FcFalse;
+            }
+
+            FcBool fcAntialias = FcFalse;
+            FcBool fcAntialiasSet = (*FcPatternGetBoolPtr)(pattern, FC_ANTIALIAS, 0, &fcAntialias) == FcResultMatch;
+
+            if (logFC) {
+                switch(context->aaType) {
+                    case TEXT_AA_ON:
+                        fprintf(stderr, "JDK_AA_ON ");
+                        break;
+                    case TEXT_AA_OFF:
+                        fprintf(stderr, "JDK_AA_OFF ");
+                        break;
+                    case TEXT_AA_LCD_HRGB:
+                        fprintf(stderr, "JDK_AA_LCD_HRGB ");
+                        break;
+                    case TEXT_AA_LCD_HBGR:
+                        fprintf(stderr, "JDK_AA_LCD_HBGR ");
+                        break;
+                    default:
+                        fprintf(stderr, "JDK_AA_UNKNOWN ");
+                        break;
+                }
+                if (fcAntialiasSet) fprintf(stderr, "FC_ANTIALIAS(%d) ", fcAntialias);
+            }
+
+            FcBool fcAutohint = FcFalse;
+            FcBool fcAutohintSet = (*FcPatternGetBoolPtr)(pattern, FC_AUTOHINT, 0, &fcAutohint) == FcResultMatch;
+
+            if (logFC && fcAutohintSet) fprintf(stderr, "FC_AUTOHINT(%d) ", fcAutohint);
+
+            if (context->aaType == TEXT_AA_ON) { // Greyscale AA
+                setupLoadRenderFlags(context, fcHintStyle, fcAutohint, fcAutohintSet, FT_LOAD_DEFAULT, FT_RENDER_MODE_NORMAL, fcSize);
+            }
+            else if (context->aaType == TEXT_AA_OFF) { // No AA
+                setupLoadRenderFlags(context, fcHintStyle, fcAutohint, fcAutohintSet, FT_LOAD_TARGET_MONO, FT_RENDER_MODE_MONO, fcSize);
+            } else {
+                int fcRGBA = FC_RGBA_UNKNOWN;
+                if (fcAntialiasSet && fcAntialias) {
+                    if ((*FcPatternGetIntegerPtr)(pattern, FC_RGBA, 0, &fcRGBA) == FcResultMatch) {
+                        switch (fcRGBA) {
+                            case FC_RGBA_RGB:
+                            case FC_RGBA_BGR:
+                                if (logFC) fprintf(stderr, fcRGBA == FC_RGBA_RGB ? "FC_RGBA_RGB " : "FC_RGBA_BGR ");
+                                setupLoadRenderFlags(context, fcHintStyle, fcAutohint, fcAutohintSet,
+                                                     FT_LOAD_TARGET_LCD, FT_RENDER_MODE_LCD, fcSize);
+                                break;
+                            case FC_RGBA_VRGB:
+                            case FC_RGBA_VBGR:
+                                if (logFC) fprintf(stderr, fcRGBA == FC_RGBA_VRGB ? "FC_RGBA_VRGB " : "FC_RGBA_VBGR ");
+                                setupLoadRenderFlags(context, fcHintStyle, fcAutohint, fcAutohintSet,
+                                                     FT_LOAD_TARGET_LCD_V, FT_RENDER_MODE_LCD_V, fcSize);
+                                break;
+                            case FC_RGBA_NONE:
+                                if (logFC) fprintf(stderr, "FC_RGBA_NONE ");
+                                break;
+                            default:
+                                if (logFC) fprintf(stderr, "FC_RGBA_UNKNOWN ");
+                                break;
+                        }
+                    }
+                }
+                if (fcRGBA == FC_RGBA_UNKNOWN || fcRGBA == FC_RGBA_NONE) {
+
+                    if (context->aaType == TEXT_AA_LCD_HRGB ||
+                        context->aaType == TEXT_AA_LCD_HBGR) {
+                        setupLoadRenderFlags(context, fcHintStyle, fcAutohint, fcAutohintSet,
+                                             FT_LOAD_TARGET_LCD, FT_RENDER_MODE_LCD, fcSize);
+                    } else {
+                        setupLoadRenderFlags(context, fcHintStyle, fcAutohint, fcAutohintSet,
+                                             FT_LOAD_TARGET_LCD_V, FT_RENDER_MODE_LCD_V, fcSize);
+                    }
+                }
+            }
+            
+            FT_LcdFilter fcLCDFilter;
+            FcBool fcLCDFilterSet = (*FcPatternGetIntegerPtr)(pattern, FC_LCD_FILTER, 0, &fcLCDFilter) == FcResultMatch;
+            context->lcdFilter = FT_LCD_FILTER_DEFAULT;
+            if (fcLCDFilterSet) {
+                switch (fcLCDFilter) {
+                    case FC_LCD_NONE:
+                        if (logFC) fprintf(stderr, "FC_LCD_NONE");
+                        context->lcdFilter = FT_LCD_FILTER_NONE;
+                        break;
+                    case FC_LCD_LIGHT:
+                        if (logFC) fprintf(stderr, "FC_LCD_LIGHT");
+                        context->lcdFilter = FT_LCD_FILTER_LIGHT;
+                        break;
+                    case FC_LCD_LEGACY:
+                        if (logFC) fprintf(stderr, "FC_LCD_LEGACY");
+                        context->lcdFilter = FT_LCD_FILTER_LEGACY;
+                        break;
+                    case FC_LCD_DEFAULT:
+                        if (logFC) fprintf(stderr, "FC_LCD_DEFAULT");
+                        break;
+                    default:
+                        if (logFC) fprintf(stderr, "FC_LCD_UNKNOWN");
+                        ;
+                }
+            }
+            (*FcPatternDestroyPtr)(pattern);
+            if (logFC) fprintf(stderr, "\n");
+#endif
         }
     }
 
-    return errCode;
+    return 0;
 }
 
 /* ftsynth.c uses (0x10000, 0x06000, 0x0, 0x10000) matrix to get oblique
@@ -425,7 +838,7 @@
                                  f0, f0, f0, f0, f0, f0, f0, f0, f0, f0);
     }
 
-    errCode = setupFTContext(env, font2D, scalerInfo, context);
+    errCode = setupFTContext(env, font2D, scalerInfo, context, FALSE);
 
     if (errCode) {
         metrics = (*env)->NewObject(env,
@@ -670,28 +1083,60 @@
     int error, imageSize;
     UInt16 width, height;
     GlyphInfo *glyphInfo;
-    int glyph_index;
-    int renderFlags = FT_LOAD_RENDER, target;
     FT_GlyphSlot ftglyph;
+    FT_Library library;
 
     FTScalerContext* context =
         (FTScalerContext*) jlong_to_ptr(pScalerContext);
     FTScalerInfo *scalerInfo =
              (FTScalerInfo*) jlong_to_ptr(pScaler);
 
-    if (isNullScalerContext(context) || scalerInfo == NULL) {
-        return ptr_to_jlong(getNullGlyphImage());
+    if (logFFS) {
+        fprintf(stderr, "FFS_LOG: getGlyphImageNative '%c'(%d) ",
+                (glyphCode >= 0x20 && glyphCode <=0x7E)? glyphCode : ' ',
+                glyphCode);
     }
 
-    error = setupFTContext(env, font2D, scalerInfo, context);
+    if (isNullScalerContext(context) || scalerInfo == NULL) {
+        if (logFFS) fprintf(stderr, "FFS_LOG: NULL context or info\n");
+        return ptr_to_jlong(getNullGlyphImage());
+    }
+    else if (logFFS){
+        char* aaTypeStr;
+        switch (context->aaType) {
+            case TEXT_AA_ON:
+                aaTypeStr = "AA_ON";
+                break;
+            case TEXT_AA_OFF:
+                aaTypeStr = "AA_OFF";
+                break;
+            case TEXT_AA_LCD_HBGR:
+                aaTypeStr = "AA_LCD_HBGR";
+                break;
+            case TEXT_AA_LCD_VBGR:
+                aaTypeStr = "AA_LCD_VBGR";
+                break;
+            case TEXT_AA_LCD_HRGB:
+                aaTypeStr = "AA_LCD_HRGB";
+                break;
+            default:
+                aaTypeStr = "AA_UNKNOWN";
+                break;
+        }
+        fprintf(stderr, "%s size=%.2f\n", aaTypeStr,
+                ((double)context->ptsz)/64.0);
+    }
+
+    error = setupFTContext(env, font2D, scalerInfo, context, TRUE);
     if (error) {
+        if (logFFS) fprintf(stderr, "FFS_LOG: Cannot setup FT context\n");
         invalidateJavaScaler(env, scaler, scalerInfo);
         return ptr_to_jlong(getNullGlyphImage());
     }
 
     /* if algorithmic styling is required then we do not request bitmap */
     if (context->doBold || context->doItalize) {
-        renderFlags =  FT_LOAD_DEFAULT;
+        context->loadFlags =  FT_LOAD_DEFAULT;
     }
 
     /* NB: in case of non identity transform
@@ -699,29 +1144,15 @@
      and apply it explicitly after hinting is performed.
      Or we can disable hinting. */
 
-    /* select appropriate hinting mode */
-    if (context->aaType == TEXT_AA_OFF) {
-        target = FT_LOAD_TARGET_MONO;
-    } else if (context->aaType == TEXT_AA_ON) {
-        target = FT_LOAD_TARGET_NORMAL;
-    } else if (context->aaType == TEXT_AA_LCD_HRGB ||
-               context->aaType == TEXT_AA_LCD_HBGR) {
-        target = FT_LOAD_TARGET_LCD;
-    } else {
-        target = FT_LOAD_TARGET_LCD_V;
-    }
-    renderFlags |= target;
-
-    glyph_index = FT_Get_Char_Index(scalerInfo->face, glyphCode);
-
-    error = FT_Load_Glyph(scalerInfo->face, glyphCode, renderFlags);
-    if (error) {
+    if (FT_Load_Glyph(scalerInfo->face, glyphCode, context->loadFlags)) {
         //do not destroy scaler yet.
         //this can be problem of particular context (e.g. with bad transform)
         return ptr_to_jlong(getNullGlyphImage());
     }
 
     ftglyph = scalerInfo->face->glyph;
+    library = ftglyph->library;
+    FT_Library_SetLcdFilter_Proxy(library, context->lcdFilter);
 
     /* apply styles */
     if (context->doBold) { /* if bold style */
@@ -734,7 +1165,7 @@
     /* generate bitmap if it is not done yet
      e.g. if algorithmic styling is performed and style was added to outline */
     if (ftglyph->format == FT_GLYPH_FORMAT_OUTLINE) {
-        FT_Render_Glyph(ftglyph, FT_LOAD_TARGET_MODE(target));
+        FT_Render_Glyph(ftglyph, context->renderFlags);
     }
 
     width  = (UInt16) ftglyph->bitmap.width;
@@ -872,7 +1303,7 @@
     /* Freetype functions *may* cause callback to java
        that can use cached values. Make sure our cache is up to date.
        NB: scaler context is not important at this point, can use NULL. */
-    int errCode = setupFTContext(env, font2D, scalerInfo, NULL);
+    int errCode = setupFTContext(env, font2D, scalerInfo, NULL, FALSE);
     if (errCode) {
         return;
     }
@@ -935,7 +1366,7 @@
     /* Freetype functions *may* cause callback to java
        that can use cached values. Make sure our cache is up to date.
        Scaler context is not important here, can use NULL. */
-    errCode = setupFTContext(env, font2D, scalerInfo, NULL);
+    errCode = setupFTContext(env, font2D, scalerInfo, NULL, FALSE);
     if (errCode) {
         return 0;
     }
@@ -949,26 +1380,25 @@
 static FT_Outline* getFTOutline(JNIEnv* env, jobject font2D,
         FTScalerContext *context, FTScalerInfo* scalerInfo,
         jint glyphCode, jfloat xpos, jfloat ypos) {
-    int renderFlags;
-    int glyph_index;
+
     FT_Error error;
     FT_GlyphSlot ftglyph;
+    FT_Int32 loadFlags;
 
     if (glyphCode >= INVISIBLE_GLYPHS ||
             isNullScalerContext(context) || scalerInfo == NULL) {
         return NULL;
     }
 
-    error = setupFTContext(env, font2D, scalerInfo, context);
+    error = setupFTContext(env, font2D, scalerInfo, context, TRUE);
     if (error) {
         return NULL;
     }
 
-    renderFlags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP;
+    // We cannot get an outline from bitmap version of glyph
+    loadFlags = context->loadFlags | FT_LOAD_NO_BITMAP;
 
-    glyph_index = FT_Get_Char_Index(scalerInfo->face, glyphCode);
-
-    error = FT_Load_Glyph(scalerInfo->face, glyphCode, renderFlags);
+    error = FT_Load_Glyph(scalerInfo->face, glyphCode, loadFlags);
     if (error) {
         return NULL;
     }
@@ -1424,3 +1854,12 @@
     return (*env)->NewObject(env, sunFontIDs.pt2DFloatClass,
                              sunFontIDs.pt2DFloatCtr, x, y);
 }
+
+JNIEXPORT void JNICALL
+JNI_OnUnload(JavaVM *vm, void *reserved) {
+    if (libFontConfig != NULL) {
+#ifndef DISABLE_FONTCONFIG
+        dlclose(libFontConfig);
+#endif
+    }
+}
diff --git a/src/share/native/sun/font/glyphblitting.h b/src/share/native/sun/font/glyphblitting.h
index 76dc05a..53a8ed8 100644
--- a/src/share/native/sun/font/glyphblitting.h
+++ b/src/share/native/sun/font/glyphblitting.h
@@ -40,8 +40,8 @@
 } GlyphBlitVector;
 
 extern jint RefineBounds(GlyphBlitVector *gbv, SurfaceDataBounds *bounds);
-extern GlyphBlitVector* setupBlitVector(JNIEnv *env, jobject glyphlist);
-extern GlyphBlitVector* setupLCDBlitVector(JNIEnv *env, jobject glyphlist);
+extern GlyphBlitVector* setupBlitVector(JNIEnv *env, jobject glyphlist, jint fromGlyph, jint toGlyph);
+extern GlyphBlitVector* setupLCDBlitVector(JNIEnv *env, jobject glyphlist, jint fromGlyph, jint toGlyph);
 
 #ifdef  __cplusplus
 }
diff --git a/src/share/native/sun/font/harfbuzz/hb-atomic-private.hh b/src/share/native/sun/font/harfbuzz/hb-atomic-private.hh
new file mode 100644
index 0000000..778e30b
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-atomic-private.hh
@@ -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 */
diff --git a/src/share/native/sun/font/harfbuzz/hb-blob.cpp b/src/share/native/sun/font/harfbuzz/hb-blob.cpp
new file mode 100644
index 0000000..5068dc1
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-blob.cpp
@@ -0,0 +1,478 @@
+/*
+ * 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 ||
+      !(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;
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-blob.h b/src/share/native/sun/font/harfbuzz/hb-blob.h
new file mode 100644
index 0000000..ff44e18
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-blob.h
@@ -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_EXTERN 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_EXTERN hb_blob_t *
+hb_blob_create_sub_blob (hb_blob_t    *parent,
+                         unsigned int  offset,
+                         unsigned int  length);
+
+HB_EXTERN hb_blob_t *
+hb_blob_get_empty (void);
+
+HB_EXTERN hb_blob_t *
+hb_blob_reference (hb_blob_t *blob);
+
+HB_EXTERN void
+hb_blob_destroy (hb_blob_t *blob);
+
+HB_EXTERN 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);
+
+
+HB_EXTERN void *
+hb_blob_get_user_data (hb_blob_t          *blob,
+                       hb_user_data_key_t *key);
+
+
+HB_EXTERN void
+hb_blob_make_immutable (hb_blob_t *blob);
+
+HB_EXTERN hb_bool_t
+hb_blob_is_immutable (hb_blob_t *blob);
+
+
+HB_EXTERN unsigned int
+hb_blob_get_length (hb_blob_t *blob);
+
+HB_EXTERN const char *
+hb_blob_get_data (hb_blob_t *blob, unsigned int *length);
+
+HB_EXTERN char *
+hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length);
+
+
+HB_END_DECLS
+
+#endif /* HB_BLOB_H */
diff --git a/src/share/native/sun/font/harfbuzz/hb-buffer-deserialize-json.hh b/src/share/native/sun/font/harfbuzz/hb-buffer-deserialize-json.hh
new file mode 100644
index 0000000..5d43871
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-buffer-deserialize-json.hh
@@ -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 */
diff --git a/src/share/native/sun/font/harfbuzz/hb-buffer-deserialize-text.hh b/src/share/native/sun/font/harfbuzz/hb-buffer-deserialize-text.hh
new file mode 100644
index 0000000..c45442c
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-buffer-deserialize-text.hh
@@ -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 */
diff --git a/src/share/native/sun/font/harfbuzz/hb-buffer-private.hh b/src/share/native/sun/font/harfbuzz/hb-buffer-private.hh
new file mode 100644
index 0000000..1fc2252
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-buffer-private.hh
@@ -0,0 +1,296 @@
+/*
+ * 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"
+
+
+#ifndef HB_BUFFER_MAX_EXPANSION_FACTOR
+#define HB_BUFFER_MAX_EXPANSION_FACTOR 32
+#endif
+#ifndef HB_BUFFER_MAX_LEN_MIN
+#define HB_BUFFER_MAX_LEN_MIN 8192
+#endif
+#ifndef HB_BUFFER_MAX_LEN_DEFAULT
+#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */
+#endif
+
+ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20);
+ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
+
+HB_MARK_AS_FLAG_T (hb_buffer_flags_t);
+HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t);
+
+enum hb_buffer_scratch_flags_t {
+  HB_BUFFER_SCRATCH_FLAG_DEFAULT                        = 0x00000000u,
+  HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII                  = 0x00000001u,
+  HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES         = 0x00000002u,
+  HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK             = 0x00000004u,
+  HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT            = 0x00000008u,
+  /* Reserved for complex shapers' internal use. */
+  HB_BUFFER_SCRATCH_FLAG_COMPLEX0                       = 0x01000000u,
+  HB_BUFFER_SCRATCH_FLAG_COMPLEX1                       = 0x02000000u,
+  HB_BUFFER_SCRATCH_FLAG_COMPLEX2                       = 0x04000000u,
+  HB_BUFFER_SCRATCH_FLAG_COMPLEX3                       = 0x08000000u,
+};
+HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_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. */
+  hb_buffer_scratch_flags_t scratch_flags; /* Have space-flallback, etc. */
+  unsigned int max_len; /* Maximum allowed len. */
+
+  /* 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 ? out_len - 1 : 0]; }
+  inline hb_glyph_info_t prev (void) const { return out_info[out_len ? out_len - 1 : 0]; }
+
+  inline bool has_separate_output (void) const { return info != out_info; }
+
+  unsigned int serial;
+
+  /* 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];
+
+  /* Debugging API */
+  hb_buffer_message_func_t message_func;
+  void *message_data;
+  hb_destroy_func_t message_destroy;
+
+  /* Internal debugging. */
+  /* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
+#ifndef HB_NDEBUG
+  uint8_t allocated_var_bits;
+#endif
+  inline void allocate_var (unsigned int start, unsigned int count)
+  {
+#ifndef HB_NDEBUG
+    unsigned int end = start + count;
+    assert (end <= 8);
+    unsigned int bits = (1<<end) - (1<<start);
+    assert (0 == (allocated_var_bits & bits));
+    allocated_var_bits |= bits;
+#endif
+  }
+  inline void deallocate_var (unsigned int start, unsigned int count)
+  {
+#ifndef HB_NDEBUG
+    unsigned int end = start + count;
+    assert (end <= 8);
+    unsigned int bits = (1<<end) - (1<<start);
+    assert (bits == (allocated_var_bits & bits));
+    allocated_var_bits &= ~bits;
+#endif
+  }
+  inline void assert_var (unsigned int start, unsigned int count)
+  {
+#ifndef HB_NDEBUG
+    unsigned int end = start + count;
+    assert (end <= 8);
+    unsigned int bits = (1<<end) - (1<<start);
+    assert (bits == (allocated_var_bits & bits));
+#endif
+  }
+  inline void deallocate_var_all (void)
+  {
+#ifndef HB_NDEBUG
+    allocated_var_bits = 0;
+#endif
+  }
+
+
+  /* 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 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 *));
+
+  inline bool messaging (void) { return unlikely (message_func); }
+  inline bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
+  {
+    if (!messaging ())
+      return true;
+    va_list ap;
+    va_start (ap, fmt);
+    bool ret = message_impl (font, fmt, ap);
+    va_end (ap);
+    return ret;
+  }
+  HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
+};
+
+
+#define HB_BUFFER_XALLOCATE_VAR(b, func, var) \
+  b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \
+           sizeof (b->info[0].var))
+#define HB_BUFFER_ALLOCATE_VAR(b, var)          HB_BUFFER_XALLOCATE_VAR (b, allocate_var,   var ())
+#define HB_BUFFER_DEALLOCATE_VAR(b, var)        HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var ())
+#define HB_BUFFER_ASSERT_VAR(b, var)            HB_BUFFER_XALLOCATE_VAR (b, assert_var,     var ())
+
+
+#endif /* HB_BUFFER_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-buffer-serialize.cpp b/src/share/native/sun/font/harfbuzz/hb-buffer-serialize.cpp
new file mode 100644
index 0000000..0047743
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-buffer-serialize.cpp
@@ -0,0 +1,454 @@
+/*
+ * 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:
+ *
+ * Returns a list of supported buffer serialization formats.
+ *
+ * Return value: (transfer none):
+ * A string array of buffer serialization formats. Should not be freed.
+ *
+ * Since: 0.9.7
+ **/
+const char **
+hb_buffer_serialize_list_formats (void)
+{
+  return serialize_formats;
+}
+
+/**
+ * hb_buffer_serialize_format_from_string:
+ * @str: (array length=len) (element-type uint8_t): a string to parse
+ * @len: length of @str, or -1 if string is %NULL terminated
+ *
+ * Parses a string into an #hb_buffer_serialize_format_t. Does not check if
+ * @str is a valid buffer serialization format, use
+ * hb_buffer_serialize_list_formats() to get the list of supported formats.
+ *
+ * Return value:
+ * The parsed #hb_buffer_serialize_format_t.
+ *
+ * Since: 0.9.7
+ **/
+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: an #hb_buffer_serialize_format_t to convert.
+ *
+ * Converts @format to the string corresponding it, or %NULL if it is not a valid
+ * #hb_buffer_serialize_format_t.
+ *
+ * Return value: (transfer none):
+ * A %NULL terminated string corresponding to @format. Should not be freed.
+ *
+ * Since: 0.9.7
+ **/
+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;
+}
+
+/**
+ * hb_buffer_serialize_glyphs:
+ * @buffer: an #hb_buffer_t buffer.
+ * @start: the first item in @buffer to serialize.
+ * @end: the last item in @buffer to serialize.
+ * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
+ *       write serialized buffer into.
+ * @buf_size: the size of @buf.
+ * @buf_consumed: (out) (allow-none): if not %NULL, will be set to the number of byes written into @buf.
+ * @font: (allow-none): the #hb_font_t used to shape this buffer, needed to
+ *        read glyph names and extents. If %NULL, and empty font will be used.
+ * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
+ * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
+ *         to serialize.
+ *
+ * Serializes @buffer into a textual representation of its glyph content,
+ * useful for showing the contents of the buffer, for example during debugging.
+ * There are currently two supported serialization formats:
+ *
+ * ## text
+ * A human-readable, plain text format.
+ * The serialized glyphs will look something like:
+ *
+ * ```
+ * [uni0651=0@518,0+0|uni0628=0+1897]
+ * ```
+ * - The serialized glyphs are delimited with `[` and `]`.
+ * - Glyphs are separated with `|`
+ * - Each glyph starts with glyph name, or glyph index if
+ *   #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set. Then,
+ *   - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, `=` then #hb_glyph_info_t.cluster.
+ *   - If #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set, the #hb_glyph_position_t in the format:
+ *     - If both #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not 0, `@x_offset,y_offset`. Then,
+ *     - `+x_advance`, then `,y_advance` if #hb_glyph_position_t.y_advance is not 0. Then,
+ *   - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the
+ *     #hb_glyph_extents_t in the format
+ *     `&lt;x_bearing,y_bearing,width,height&gt;`
+ *
+ * ## json
+ * TODO.
+ *
+ * Return value:
+ * The number of serialized items.
+ *
+ * Since: 0.9.7
+ **/
+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,
+                            hb_font_t *font,
+                            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 (!buffer->have_positions)
+    flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
+
+  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: an #hb_buffer_t buffer.
+ * @buf: (array length=buf_len):
+ * @buf_len:
+ * @end_ptr: (out):
+ * @font:
+ * @format:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.7
+ **/
+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;
+
+  }
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-buffer.cpp b/src/share/native/sun/font/harfbuzz/hb-buffer.cpp
new file mode 100644
index 0000000..aca2198
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-buffer.cpp
@@ -0,0 +1,1818 @@
+/*
+ * 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
+
+/**
+ * SECTION: hb-buffer
+ * @title: Buffers
+ * @short_description: Input and output buffers
+ * @include: hb.h
+ *
+ * Buffers serve dual role in HarfBuzz; they hold the input characters that are
+ * passed hb_shape(), and after shaping they hold the output glyphs.
+ **/
+
+/**
+ * hb_segment_properties_equal:
+ * @a: first #hb_segment_properties_t to compare.
+ * @b: second #hb_segment_properties_t to compare.
+ *
+ * Checks the equality of two #hb_segment_properties_t's.
+ *
+ * Return value:
+ * %true if all properties of @a equal those of @b, false otherwise.
+ *
+ * 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;
+
+}
+
+/**
+ * hb_segment_properties_hash:
+ * @p: #hb_segment_properties_t to hash.
+ *
+ * Creates a hash representing @p.
+ *
+ * Return value:
+ * A hash of @p.
+ *
+ * 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;
+  if (unlikely (size > max_len))
+  {
+    in_error = true;
+    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]));
+  if (idx + count > len)
+  {
+    /* Under memory failure we might expose this area.  At least
+     * clean it up.  Oh well... */
+    memset (info + len, 0, (idx + count - len) * 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;
+  scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
+
+  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 (context, 0, sizeof context);
+  memset (context_len, 0, sizeof context_len);
+
+  deallocate_var_all ();
+}
+
+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;
+  }
+  if (unlikely (in_error))
+    return false;
+
+  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;
+
+    /* This will blow in our face if memory allocation fails later
+     * in this same lookup... */
+    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 ();
+  }
+}
+
+
+/* Public API */
+
+/**
+ * hb_buffer_create: (Xconstructor)
+ *
+ * Creates a new #hb_buffer_t with all properties to defaults.
+ *
+ * Return value: (transfer full):
+ * A newly allocated #hb_buffer_t with a reference count of 1. The initial
+ * reference count should be released with hb_buffer_destroy() when you are done
+ * using the #hb_buffer_t. This function never returns %NULL. If memory cannot
+ * be allocated, a special #hb_buffer_t object will be returned on which
+ * hb_buffer_allocation_successful() returns %false.
+ *
+ * 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->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
+
+  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_SCRATCH_FLAG_DEFAULT,
+    HB_BUFFER_MAX_LEN_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: an #hb_buffer_t.
+ *
+ * Increases the reference count on @buffer by one. This prevents @buffer from
+ * being destroyed until a matching call to hb_buffer_destroy() is made.
+ *
+ * Return value: (transfer full):
+ * The referenced #hb_buffer_t.
+ *
+ * Since: 0.9.2
+ **/
+hb_buffer_t *
+hb_buffer_reference (hb_buffer_t *buffer)
+{
+  return hb_object_reference (buffer);
+}
+
+/**
+ * hb_buffer_destroy: (skip)
+ * @buffer: an #hb_buffer_t.
+ *
+ * Deallocate the @buffer.
+ * Decreases the reference count on @buffer by one. If the result is zero, then
+ * @buffer and all associated resources are freed. See hb_buffer_reference().
+ *
+ * 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);
+  if (buffer->message_destroy)
+    buffer->message_destroy (buffer->message_data);
+
+  free (buffer);
+}
+
+/**
+ * hb_buffer_set_user_data: (skip)
+ * @buffer: an #hb_buffer_t.
+ * @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: an #hb_buffer_t.
+ * @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: an #hb_buffer_t.
+ * @content_type: the type of buffer contents to set
+ *
+ * Sets the type of @buffer contents, buffers are either empty, contain
+ * characters (before shaping) or glyphs (the result of shaping).
+ *
+ * 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: an #hb_buffer_t.
+ *
+ * see hb_buffer_set_content_type().
+ *
+ * Return value:
+ * The type of @buffer contents.
+ *
+ * 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: an #hb_buffer_t.
+ * @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: an #hb_buffer_t.
+ *
+ *
+ *
+ * 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: an #hb_buffer_t.
+ * @direction: the #hb_direction_t of the @buffer
+ *
+ * Set the text flow direction of the buffer. No shaping can happen without
+ * setting @buffer direction, and it controls the visual direction for the
+ * output glyphs; for RTL direction the glyphs will be reversed. Many layout
+ * features depend on the proper setting of the direction, for example,
+ * reversing RTL text before shaping, then shaping with LTR direction is not
+ * the same as keeping the text in logical order and shaping with RTL
+ * 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: an #hb_buffer_t.
+ *
+ * See hb_buffer_set_direction()
+ *
+ * Return value:
+ * The direction of the @buffer.
+ *
+ * Since: 0.9.2
+ **/
+hb_direction_t
+hb_buffer_get_direction (hb_buffer_t    *buffer)
+{
+  return buffer->props.direction;
+}
+
+/**
+ * hb_buffer_set_script:
+ * @buffer: an #hb_buffer_t.
+ * @script: an #hb_script_t to set.
+ *
+ * Sets the script of @buffer to @script.
+ *
+ * Script is crucial for choosing the proper shaping behaviour for scripts that
+ * require it (e.g. Arabic) and the which OpenType features defined in the font
+ * to be applied.
+ *
+ * You can pass one of the predefined #hb_script_t values, or use
+ * hb_script_from_string() or hb_script_from_iso15924_tag() to get the
+ * corresponding script from an ISO 15924 script tag.
+ *
+ * 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: an #hb_buffer_t.
+ *
+ * See hb_buffer_set_script().
+ *
+ * Return value:
+ * The #hb_script_t of the @buffer.
+ *
+ * Since: 0.9.2
+ **/
+hb_script_t
+hb_buffer_get_script (hb_buffer_t *buffer)
+{
+  return buffer->props.script;
+}
+
+/**
+ * hb_buffer_set_language:
+ * @buffer: an #hb_buffer_t.
+ * @language: an hb_language_t to set.
+ *
+ * Sets the language of @buffer to @language.
+ *
+ * Languages are crucial for selecting which OpenType feature to apply to the
+ * buffer which can result in applying language-specific behaviour. Languages
+ * are orthogonal to the scripts, and though they are related, they are
+ * different concepts and should not be confused with each other.
+ *
+ * Use hb_language_from_string() to convert from ISO 639 language codes to
+ * #hb_language_t.
+ *
+ * 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: an #hb_buffer_t.
+ *
+ * See hb_buffer_set_language().
+ *
+ * Return value: (transfer none):
+ * The #hb_language_t of the buffer. Must not be freed by the caller.
+ *
+ * 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: an #hb_buffer_t.
+ * @props: an #hb_segment_properties_t to use.
+ *
+ * Sets the segment properties of the buffer, a shortcut for calling
+ * hb_buffer_set_direction(), hb_buffer_set_script() and
+ * hb_buffer_set_language() individually.
+ *
+ * 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: an #hb_buffer_t.
+ * @props: (out): the output #hb_segment_properties_t.
+ *
+ * Sets @props to the #hb_segment_properties_t of @buffer.
+ *
+ * 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: an #hb_buffer_t.
+ * @flags: the buffer flags to set.
+ *
+ * Sets @buffer flags to @flags. See #hb_buffer_flags_t.
+ *
+ * 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: an #hb_buffer_t.
+ *
+ * See hb_buffer_set_flags().
+ *
+ * Return value:
+ * The @buffer flags.
+ *
+ * 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: an #hb_buffer_t.
+ * @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: an #hb_buffer_t.
+ *
+ *
+ *
+ * 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: an #hb_buffer_t.
+ * @replacement: the replacement #hb_codepoint_t
+ *
+ * Sets the #hb_codepoint_t that replaces invalid entries for a given encoding
+ * when adding text to @buffer.
+ *
+ * Default is %HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT.
+ *
+ * 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: an #hb_buffer_t.
+ *
+ * See hb_buffer_set_replacement_codepoint().
+ *
+ * Return value:
+ * The @buffer replacement #hb_codepoint_t.
+ *
+ * Since: 0.9.31
+ **/
+hb_codepoint_t
+hb_buffer_get_replacement_codepoint (hb_buffer_t    *buffer)
+{
+  return buffer->replacement;
+}
+
+
+/**
+ * hb_buffer_reset:
+ * @buffer: an #hb_buffer_t.
+ *
+ * Resets the buffer to its initial status, as if it was just newly created
+ * with hb_buffer_create().
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_buffer_reset (hb_buffer_t *buffer)
+{
+  buffer->reset ();
+}
+
+/**
+ * hb_buffer_clear_contents:
+ * @buffer: an #hb_buffer_t.
+ *
+ * Similar to hb_buffer_reset(), but does not clear the Unicode functions and
+ * the replacement code point.
+ *
+ * Since: 0.9.11
+ **/
+void
+hb_buffer_clear_contents (hb_buffer_t *buffer)
+{
+  buffer->clear ();
+}
+
+/**
+ * hb_buffer_pre_allocate:
+ * @buffer: an #hb_buffer_t.
+ * @size: number of items to pre allocate.
+ *
+ * Pre allocates memory for @buffer to fit at least @size number of items.
+ *
+ * Return value:
+ * %true if @buffer memory allocation succeeded, %false otherwise.
+ *
+ * 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: an #hb_buffer_t.
+ *
+ * Check if allocating memory for the buffer succeeded.
+ *
+ * Return value:
+ * %true if @buffer memory allocation succeeded, %false otherwise.
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_buffer_allocation_successful (hb_buffer_t  *buffer)
+{
+  return !buffer->in_error;
+}
+
+/**
+ * hb_buffer_add:
+ * @buffer: an #hb_buffer_t.
+ * @codepoint: a Unicode code point.
+ * @cluster: the cluster value of @codepoint.
+ *
+ * Appends a character with the Unicode value of @codepoint to @buffer, and
+ * gives it the initial cluster value of @cluster. Clusters can be any thing
+ * the client wants, they are usually used to refer to the index of the
+ * character in the input text stream and are output in
+ * #hb_glyph_info_t.cluster field.
+ *
+ * This function does not check the validity of @codepoint, it is up to the
+ * caller to ensure it is a valid Unicode code point.
+ *
+ * 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: an #hb_buffer_t.
+ * @length: the new length of @buffer.
+ *
+ * Similar to hb_buffer_pre_allocate(), but clears any new items added at the
+ * end.
+ *
+ * Return value:
+ * %true if @buffer memory allocation succeeded, %false otherwise.
+ *
+ * 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: an #hb_buffer_t.
+ *
+ * Returns the number of items in the buffer.
+ *
+ * Return value:
+ * The @buffer length.
+ * The value valid as long as buffer has not been modified.
+ *
+ * Since: 0.9.2
+ **/
+unsigned int
+hb_buffer_get_length (hb_buffer_t *buffer)
+{
+  return buffer->len;
+}
+
+/**
+ * hb_buffer_get_glyph_infos:
+ * @buffer: an #hb_buffer_t.
+ * @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):
+ * The @buffer glyph information array.
+ * The value valid as long as buffer has not been modified.
+ *
+ * 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: an #hb_buffer_t.
+ * @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):
+ * The @buffer glyph position array.
+ * The value valid as long as buffer has not been modified.
+ *
+ * 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: an #hb_buffer_t.
+ *
+ * Reverses buffer contents.
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_buffer_reverse (hb_buffer_t *buffer)
+{
+  buffer->reverse ();
+}
+
+/**
+ * hb_buffer_reverse_range:
+ * @buffer: an #hb_buffer_t.
+ * @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: an #hb_buffer_t.
+ *
+ * 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: an #hb_buffer_t.
+ *
+ * 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: an #hb_buffer_t.
+ * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8
+ *               characters to append.
+ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @item_offset: the offset of the first character to add to the @buffer.
+ * @item_length: the number of characters to add to the @buffer, or -1 for the
+ *               end of @text (assuming it is %NULL terminated).
+ *
+ * See hb_buffer_add_codepoints().
+ *
+ * Replaces invalid UTF-8 characters with the @buffer replacement code point,
+ * see hb_buffer_set_replacement_codepoint().
+ *
+ * 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: an #hb_buffer_t.
+ * @text: (array length=text_length): an array of UTF-16 characters to append.
+ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @item_offset: the offset of the first character to add to the @buffer.
+ * @item_length: the number of characters to add to the @buffer, or -1 for the
+ *               end of @text (assuming it is %NULL terminated).
+ *
+ * See hb_buffer_add_codepoints().
+ *
+ * Replaces invalid UTF-16 characters with the @buffer replacement code point,
+ * see hb_buffer_set_replacement_codepoint().
+ *
+ * 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: an #hb_buffer_t.
+ * @text: (array length=text_length): an array of UTF-32 characters to append.
+ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @item_offset: the offset of the first character to add to the @buffer.
+ * @item_length: the number of characters to add to the @buffer, or -1 for the
+ *               end of @text (assuming it is %NULL terminated).
+ *
+ * See hb_buffer_add_codepoints().
+ *
+ * Replaces invalid UTF-32 characters with the @buffer replacement code point,
+ * see hb_buffer_set_replacement_codepoint().
+ *
+ * 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: an #hb_buffer_t.
+ * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8
+ *               characters to append.
+ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @item_offset: the offset of the first character to add to the @buffer.
+ * @item_length: the number of characters to add to the @buffer, or -1 for the
+ *               end of @text (assuming it is %NULL terminated).
+ *
+ * Similar to hb_buffer_add_codepoints(), but allows only access to first 256
+ * Unicode code points that can fit in 8-bit strings.
+ *
+ * <note>Has nothing to do with non-Unicode Latin-1 encoding.</note>
+ *
+ * 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 #hb_buffer_t to append characters to.
+ * @text: (array length=text_length): an array of Unicode code points to append.
+ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @item_offset: the offset of the first code point to add to the @buffer.
+ * @item_length: the number of code points to add to the @buffer, or -1 for the
+ *               end of @text (assuming it is %NULL terminated).
+ *
+ * Appends characters from @text array to @buffer. The @item_offset is the
+ * position of the first character from @text that will be appended, and
+ * @item_length is the number of character. When shaping part of a larger text
+ * (e.g. a run of text from a paragraph), instead of passing just the substring
+ * corresponding to the run, it is preferable to pass the whole
+ * paragraph and specify the run start and length as @item_offset and
+ * @item_length, respectively, to give HarfBuzz the full context to be able,
+ * for example, to do cross-run Arabic shaping or properly handle combining
+ * marks at stat of run.
+ *
+ * This function does not check the validity of @text, it is up to the caller
+ * to ensure it contains a valid Unicode code points.
+ *
+ * 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: an #hb_buffer_t.
+ *
+ * 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.</note>
+ *
+ * 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;
+    }
+  }
+}
+
+/*
+ * Debugging.
+ */
+
+/**
+ * hb_buffer_set_message_func:
+ * @buffer: an #hb_buffer_t.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.1.3
+ **/
+void
+hb_buffer_set_message_func (hb_buffer_t *buffer,
+                            hb_buffer_message_func_t func,
+                            void *user_data, hb_destroy_func_t destroy)
+{
+  if (buffer->message_destroy)
+    buffer->message_destroy (buffer->message_data);
+
+  if (func) {
+    buffer->message_func = func;
+    buffer->message_data = user_data;
+    buffer->message_destroy = destroy;
+  } else {
+    buffer->message_func = NULL;
+    buffer->message_data = NULL;
+    buffer->message_destroy = NULL;
+  }
+}
+
+bool
+hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
+{
+  char buf[100];
+  vsnprintf (buf, sizeof (buf),  fmt, ap);
+  return (bool) this->message_func (this, font, buf, this->message_data);
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-buffer.h b/src/share/native/sun/font/harfbuzz/hb-buffer.h
new file mode 100644
index 0000000..688e809
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-buffer.h
@@ -0,0 +1,472 @@
+/*
+ * 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
+
+/**
+ * hb_glyph_info_t:
+ * @codepoint: either a Unicode code point (before shaping) or a glyph index
+ *             (after shaping).
+ * @mask:
+ * @cluster: the index of the character in the original text that corresponds
+ *           to this #hb_glyph_info_t, or whatever the client passes to
+ *           hb_buffer_add(). More than one #hb_glyph_info_t can have the same
+ *           @cluster value, if they resulted from the same character (e.g. one
+ *           to many glyph substitution), and when more than one character gets
+ *           merged in the same glyph (e.g. many to one glyph substitution) the
+ *           #hb_glyph_info_t will have the smallest cluster value of them.
+ *           By default some characters are merged into the same cluster
+ *           (e.g. combining marks have the same cluster as their bases)
+ *           even if they are separate glyphs, hb_buffer_set_cluster_level()
+ *           allow selecting more fine-grained cluster handling.
+ *
+ * The #hb_glyph_info_t is the structure that holds information about the
+ * glyphs and their relation to input text.
+ *
+ */
+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;
+
+/**
+ * hb_glyph_position_t:
+ * @x_advance: how much the line advances after drawing this glyph when setting
+ *             text in horizontal direction.
+ * @y_advance: how much the line advances after drawing this glyph when setting
+ *             text in vertical direction.
+ * @x_offset: how much the glyph moves on the X-axis before drawing it, this
+ *            should not affect how much the line advances.
+ * @y_offset: how much the glyph moves on the Y-axis before drawing it, this
+ *            should not affect how much the line advances.
+ *
+ * The #hb_glyph_position_t is the structure that holds the positions of the
+ * glyph in both horizontal and vertical directions. All positions in
+ * #hb_glyph_position_t are relative to the current point.
+ *
+ */
+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;
+
+/**
+ * hb_segment_properties_t:
+ * @direction: the #hb_direction_t of the buffer, see hb_buffer_set_direction().
+ * @script: the #hb_script_t of the buffer, see hb_buffer_set_script().
+ * @language: the #hb_language_t of the buffer, see hb_buffer_set_language().
+ *
+ * The structure that holds various text properties of an #hb_buffer_t. Can be
+ * set and retrieved using hb_buffer_set_segment_properties() and
+ * hb_buffer_get_segment_properties(), respectively.
+ */
+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_EXTERN hb_bool_t
+hb_segment_properties_equal (const hb_segment_properties_t *a,
+                             const hb_segment_properties_t *b);
+
+HB_EXTERN unsigned int
+hb_segment_properties_hash (const hb_segment_properties_t *p);
+
+
+
+/**
+ * hb_buffer_t:
+ *
+ * The main structure holding the input text and its properties before shaping,
+ * and output glyphs and their information after shaping.
+ */
+
+typedef struct hb_buffer_t hb_buffer_t;
+
+HB_EXTERN hb_buffer_t *
+hb_buffer_create (void);
+
+HB_EXTERN hb_buffer_t *
+hb_buffer_get_empty (void);
+
+HB_EXTERN hb_buffer_t *
+hb_buffer_reference (hb_buffer_t *buffer);
+
+HB_EXTERN void
+hb_buffer_destroy (hb_buffer_t *buffer);
+
+HB_EXTERN 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);
+
+HB_EXTERN void *
+hb_buffer_get_user_data (hb_buffer_t        *buffer,
+                         hb_user_data_key_t *key);
+
+/**
+ * hb_buffer_content_type_t:
+ * @HB_BUFFER_CONTENT_TYPE_INVALID: Initial value for new buffer.
+ * @HB_BUFFER_CONTENT_TYPE_UNICODE: The buffer contains input characters (before shaping).
+ * @HB_BUFFER_CONTENT_TYPE_GLYPHS: The buffer contains output glyphs (after shaping).
+ */
+typedef enum {
+  HB_BUFFER_CONTENT_TYPE_INVALID = 0,
+  HB_BUFFER_CONTENT_TYPE_UNICODE,
+  HB_BUFFER_CONTENT_TYPE_GLYPHS
+} hb_buffer_content_type_t;
+
+HB_EXTERN void
+hb_buffer_set_content_type (hb_buffer_t              *buffer,
+                            hb_buffer_content_type_t  content_type);
+
+HB_EXTERN hb_buffer_content_type_t
+hb_buffer_get_content_type (hb_buffer_t *buffer);
+
+
+HB_EXTERN void
+hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
+                             hb_unicode_funcs_t *unicode_funcs);
+
+HB_EXTERN hb_unicode_funcs_t *
+hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer);
+
+HB_EXTERN void
+hb_buffer_set_direction (hb_buffer_t    *buffer,
+                         hb_direction_t  direction);
+
+HB_EXTERN hb_direction_t
+hb_buffer_get_direction (hb_buffer_t *buffer);
+
+HB_EXTERN void
+hb_buffer_set_script (hb_buffer_t *buffer,
+                      hb_script_t  script);
+
+HB_EXTERN hb_script_t
+hb_buffer_get_script (hb_buffer_t *buffer);
+
+HB_EXTERN void
+hb_buffer_set_language (hb_buffer_t   *buffer,
+                        hb_language_t  language);
+
+
+HB_EXTERN hb_language_t
+hb_buffer_get_language (hb_buffer_t *buffer);
+
+HB_EXTERN void
+hb_buffer_set_segment_properties (hb_buffer_t *buffer,
+                                  const hb_segment_properties_t *props);
+
+HB_EXTERN void
+hb_buffer_get_segment_properties (hb_buffer_t *buffer,
+                                  hb_segment_properties_t *props);
+
+HB_EXTERN void
+hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
+
+
+/**
+ * hb_buffer_flags_t:
+ * @HB_BUFFER_FLAG_DEFAULT: the default buffer flag.
+ * @HB_BUFFER_FLAG_BOT: flag indicating that special handling of the beginning
+ *                      of text paragraph can be applied to this buffer. Should usually
+ *                      be set, unless you are passing to the buffer only part
+ *                      of the text without the full context.
+ * @HB_BUFFER_FLAG_EOT: flag indicating that special handling of the end of text
+ *                      paragraph can be applied to this buffer, similar to
+ *                      @HB_BUFFER_FLAG_EOT.
+ * @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES:
+ *                      flag indication that character with Default_Ignorable
+ *                      Unicode property should use the corresponding glyph
+ *                      from the font, instead of hiding them (currently done
+ *                      by replacing them with the space glyph and zeroing the
+ *                      advance width.)
+ *
+ * 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;
+
+HB_EXTERN void
+hb_buffer_set_flags (hb_buffer_t       *buffer,
+                     hb_buffer_flags_t  flags);
+
+HB_EXTERN 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;
+
+HB_EXTERN void
+hb_buffer_set_cluster_level (hb_buffer_t               *buffer,
+                             hb_buffer_cluster_level_t  cluster_level);
+
+HB_EXTERN hb_buffer_cluster_level_t
+hb_buffer_get_cluster_level (hb_buffer_t *buffer);
+
+/**
+ * HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT:
+ *
+ * The default code point for replacing invalid characters in a given encoding.
+ * Set to U+FFFD REPLACEMENT CHARACTER.
+ *
+ * Since: 0.9.31
+ */
+#define HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT 0xFFFDu
+
+HB_EXTERN void
+hb_buffer_set_replacement_codepoint (hb_buffer_t    *buffer,
+                                     hb_codepoint_t  replacement);
+
+HB_EXTERN hb_codepoint_t
+hb_buffer_get_replacement_codepoint (hb_buffer_t    *buffer);
+
+
+HB_EXTERN void
+hb_buffer_reset (hb_buffer_t *buffer);
+
+HB_EXTERN void
+hb_buffer_clear_contents (hb_buffer_t *buffer);
+
+HB_EXTERN hb_bool_t
+hb_buffer_pre_allocate (hb_buffer_t  *buffer,
+                        unsigned int  size);
+
+
+HB_EXTERN hb_bool_t
+hb_buffer_allocation_successful (hb_buffer_t  *buffer);
+
+HB_EXTERN void
+hb_buffer_reverse (hb_buffer_t *buffer);
+
+HB_EXTERN void
+hb_buffer_reverse_range (hb_buffer_t *buffer,
+                         unsigned int start, unsigned int end);
+
+HB_EXTERN void
+hb_buffer_reverse_clusters (hb_buffer_t *buffer);
+
+
+/* Filling the buffer in */
+
+HB_EXTERN void
+hb_buffer_add (hb_buffer_t    *buffer,
+               hb_codepoint_t  codepoint,
+               unsigned int    cluster);
+
+HB_EXTERN void
+hb_buffer_add_utf8 (hb_buffer_t  *buffer,
+                    const char   *text,
+                    int           text_length,
+                    unsigned int  item_offset,
+                    int           item_length);
+
+HB_EXTERN void
+hb_buffer_add_utf16 (hb_buffer_t    *buffer,
+                     const uint16_t *text,
+                     int             text_length,
+                     unsigned int    item_offset,
+                     int             item_length);
+
+HB_EXTERN void
+hb_buffer_add_utf32 (hb_buffer_t    *buffer,
+                     const uint32_t *text,
+                     int             text_length,
+                     unsigned int    item_offset,
+                     int             item_length);
+
+HB_EXTERN void
+hb_buffer_add_latin1 (hb_buffer_t   *buffer,
+                      const uint8_t *text,
+                      int            text_length,
+                      unsigned int   item_offset,
+                      int            item_length);
+
+HB_EXTERN 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_EXTERN hb_bool_t
+hb_buffer_set_length (hb_buffer_t  *buffer,
+                      unsigned int  length);
+
+HB_EXTERN unsigned int
+hb_buffer_get_length (hb_buffer_t *buffer);
+
+/* Getting glyphs out of the buffer */
+
+HB_EXTERN hb_glyph_info_t *
+hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
+                           unsigned int *length);
+
+HB_EXTERN hb_glyph_position_t *
+hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
+                               unsigned int *length);
+
+
+HB_EXTERN void
+hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
+
+
+/*
+ * Serialize
+ */
+
+/**
+ * hb_buffer_serialize_flags_t:
+ * @HB_BUFFER_SERIALIZE_FLAG_DEFAULT: serialize glyph names, clusters and positions.
+ * @HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS: do not serialize glyph cluster.
+ * @HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS: do not serialize glyph position information.
+ * @HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES: do no serialize glyph name.
+ * @HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS: serialize glyph extents.
+ *
+ * Flags that control what glyph information are serialized in hb_buffer_serialize_glyphs().
+ *
+ * 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;
+
+/**
+ * hb_buffer_serialize_format_t:
+ * @HB_BUFFER_SERIALIZE_FORMAT_TEXT: a human-readable, plain text format.
+ * @HB_BUFFER_SERIALIZE_FORMAT_JSON: a machine-readable JSON format.
+ * @HB_BUFFER_SERIALIZE_FORMAT_INVALID: invalid format.
+ *
+ * The buffer serialization and de-serialization format used in
+ * hb_buffer_serialize_glyphs() and hb_buffer_deserialize_glyphs().
+ *
+ * Since: 0.9.2
+ */
+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;
+
+HB_EXTERN hb_buffer_serialize_format_t
+hb_buffer_serialize_format_from_string (const char *str, int len);
+
+HB_EXTERN const char *
+hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format);
+
+HB_EXTERN const char **
+hb_buffer_serialize_list_formats (void);
+
+HB_EXTERN 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,
+                            hb_font_t *font,
+                            hb_buffer_serialize_format_t format,
+                            hb_buffer_serialize_flags_t flags);
+
+HB_EXTERN hb_bool_t
+hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
+                              const char *buf,
+                              int buf_len,
+                              const char **end_ptr,
+                              hb_font_t *font,
+                              hb_buffer_serialize_format_t format);
+
+
+/*
+ * Debugging.
+ */
+
+typedef hb_bool_t       (*hb_buffer_message_func_t)     (hb_buffer_t *buffer,
+                                                         hb_font_t   *font,
+                                                         const char  *message,
+                                                         void        *user_data);
+
+HB_EXTERN void
+hb_buffer_set_message_func (hb_buffer_t *buffer,
+                            hb_buffer_message_func_t func,
+                            void *user_data, hb_destroy_func_t destroy);
+
+
+HB_END_DECLS
+
+#endif /* HB_BUFFER_H */
diff --git a/src/share/native/sun/font/harfbuzz/hb-cache-private.hh b/src/share/native/sun/font/harfbuzz/hb-cache-private.hh
new file mode 100644
index 0000000..19b70b7
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-cache-private.hh
@@ -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 */
diff --git a/src/share/native/sun/font/harfbuzz/hb-common.cpp b/src/share/native/sun/font/harfbuzz/hb-common.cpp
new file mode 100644
index 0000000..d7b75ac
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-common.cpp
@@ -0,0 +1,607 @@
+/*
+ * 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: (out caller-allocates) (array fixed-size=4) (element-type uint8_t):
+ *
+ *
+ *
+ * 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): a string representing
+ *       ISO 639 language code
+ * @len: length of the @str, or -1 if it is %NULL-terminated.
+ *
+ * Converts @str representing an ISO 639 language code to the corresponding
+ * #hb_language_t.
+ *
+ * Return value: (transfer none):
+ * The #hb_language_t corresponding to the ISO 639 language code.
+ *
+ * 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: an #hb_language_t to convert.
+ *
+ * See hb_language_from_string().
+ *
+ * Return value: (transfer none):
+ * A %NULL-terminated string representing the @language. Must not be freed by
+ * the caller.
+ *
+ * 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: an #hb_tag_t representing an ISO 15924 tag.
+ *
+ * Converts an ISO 15924 script tag to a corresponding #hb_script_t.
+ *
+ * Return value:
+ * An #hb_script_t corresponding to the ISO 15924 tag.
+ *
+ * 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:
+ * @str: (array length=len) (element-type uint8_t): a string representing an
+ *       ISO 15924 tag.
+ * @len: length of the @str, or -1 if it is %NULL-terminated.
+ *
+ * Converts a string @str representing an ISO 15924 script tag to a
+ * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
+ * hb_script_from_iso15924_tag().
+ *
+ * Return value:
+ * An #hb_script_t corresponding to the ISO 15924 tag.
+ *
+ * Since: 0.9.2
+ **/
+hb_script_t
+hb_script_from_string (const char *str, int len)
+{
+  return hb_script_from_iso15924_tag (hb_tag_from_string (str, len));
+}
+
+/**
+ * hb_script_to_iso15924_tag:
+ * @script: an #hb_script_ to convert.
+ *
+ * See hb_script_from_iso15924_tag().
+ *
+ * Return value:
+ * An #hb_tag_t representing an ISO 15924 script tag.
+ *
+ * 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:
+
+    /* Unicode-9.0 additions */
+    case HB_SCRIPT_ADLAM:
+
+      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, (bool) replace);
+
+  return ret;
+}
+
+void *
+hb_user_data_array_t::get (hb_user_data_key_t *key)
+{
+  hb_user_data_item_t item = {NULL, NULL, 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);
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-common.h b/src/share/native/sun/font/harfbuzz/hb-common.h
new file mode 100644
index 0000000..ae57c3b
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-common.h
@@ -0,0 +1,367 @@
+/*
+ * 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_EXTERN hb_tag_t
+hb_tag_from_string (const char *str, int len);
+
+/* buf should have 4 bytes. */
+HB_EXTERN void
+hb_tag_to_string (hb_tag_t tag, char *buf);
+
+
+/**
+ * hb_direction_t:
+ * @HB_DIRECTION_INVALID: Initial, unset direction.
+ * @HB_DIRECTION_LTR: Text is set horizontally from left to right.
+ * @HB_DIRECTION_RTL: Text is set horizontally from right to left.
+ * @HB_DIRECTION_TTB: Text is set vertically from top to bottom.
+ * @HB_DIRECTION_BTT: Text is set vertically from bottom to top.
+ */
+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_EXTERN hb_direction_t
+hb_direction_from_string (const char *str, int len);
+
+HB_EXTERN 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;
+
+HB_EXTERN hb_language_t
+hb_language_from_string (const char *str, int len);
+
+HB_EXTERN const char *
+hb_language_to_string (hb_language_t language);
+
+#define HB_LANGUAGE_INVALID ((hb_language_t) NULL)
+
+HB_EXTERN 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'),
+
+  /*
+   * Since 1.3.0
+   */
+  /*9.0*/ HB_SCRIPT_ADLAM                       = HB_TAG ('A','d','l','m'),
+  /*9.0*/ HB_SCRIPT_BHAIKSUKI                   = HB_TAG ('B','h','k','s'),
+  /*9.0*/ HB_SCRIPT_MARCHEN                     = HB_TAG ('M','a','r','c'),
+  /*9.0*/ HB_SCRIPT_OSAGE                       = HB_TAG ('O','s','g','e'),
+  /*9.0*/ HB_SCRIPT_TANGUT                      = HB_TAG ('T','a','n','g'),
+  /*9.0*/ HB_SCRIPT_NEWA                        = HB_TAG ('N','e','w','a'),
+
+  /* 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_EXTERN hb_script_t
+hb_script_from_iso15924_tag (hb_tag_t tag);
+
+HB_EXTERN hb_script_t
+hb_script_from_string (const char *str, int len);
+
+HB_EXTERN hb_tag_t
+hb_script_to_iso15924_tag (hb_script_t script);
+
+HB_EXTERN 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 */
diff --git a/src/share/native/sun/font/harfbuzz/hb-coretext.cpp b/src/share/native/sun/font/harfbuzz/hb-coretext.cpp
new file mode 100644
index 0000000..bd769a0
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-coretext.cpp
@@ -0,0 +1,1290 @@
+/*
+ * 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
+#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 CTFontDescriptorRef
+get_last_resort_font_desc (void)
+{
+  // TODO Handle allocation failures?
+  CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
+  CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
+                                           (const void **) &last_resort,
+                                           1,
+                                           &kCFTypeArrayCallBacks);
+  CFRelease (last_resort);
+  CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
+                                                   (const void **) &kCTFontCascadeListAttribute,
+                                                   (const void **) &cascade_list,
+                                                   1,
+                                                   &kCFTypeDictionaryKeyCallBacks,
+                                                   &kCFTypeDictionaryValueCallBacks);
+  CFRelease (cascade_list);
+
+  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
+  CFRelease (attributes);
+  return font_desc;
+}
+
+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);
+}
+
+static CGFontRef
+create_cg_font (hb_face_t *face)
+{
+  CGFontRef cg_font = NULL;
+  if (face->destroy == (hb_destroy_func_t) CGFontRelease)
+  {
+    cg_font = 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))
+    {
+      cg_font = CGFontCreateWithDataProvider (provider);
+      if (unlikely (!cg_font))
+        DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
+      CGDataProviderRelease (provider);
+    }
+  }
+  return cg_font;
+}
+
+static CTFontRef
+create_ct_font (CGFontRef cg_font, CGFloat font_size)
+{
+  CTFontRef ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, NULL, NULL);
+  if (unlikely (!ct_font)) {
+    DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
+    return NULL;
+  }
+  CFURLRef original_url = (CFURLRef)CTFontCopyAttribute(ct_font, kCTFontURLAttribute);
+
+  /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
+   * font fallback which we don't need anyway. */
+  {
+    CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
+    CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, NULL, last_resort_font_desc);
+    CFRelease (last_resort_font_desc);
+    if (new_ct_font)
+    {
+      /* The CTFontCreateCopyWithAttributes call fails to stay on the same font
+       * when reconfiguring the cascade list and may switch to a different font
+       * when there are fonts that go by the same name, since the descriptor is
+       * just name and size.
+       *
+       * Avoid reconfiguring the cascade lists if the new font is outside the
+       * system locations that we cannot access from the sandboxed renderer
+       * process in Blink. This can be detected by the new file URL location
+       * that the newly found font points to. */
+      CFURLRef new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
+      // Keep reconfigured font if URL cannot be retrieved (seems to be the case
+      // on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
+      if (!original_url || !new_url || CFEqual (original_url, new_url)) {
+        CFRelease (ct_font);
+        ct_font = new_ct_font;
+      } else {
+        CFRelease (new_ct_font);
+        DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
+      }
+      if (new_url)
+        CFRelease (new_url);
+    }
+    else
+      DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
+  }
+
+  if (original_url)
+    CFRelease (original_url);
+  return ct_font;
+}
+
+struct hb_coretext_shaper_face_data_t {
+  CGFontRef cg_font;
+  CTFontRef ct_font;
+};
+
+hb_coretext_shaper_face_data_t *
+_hb_coretext_shaper_face_data_create (hb_face_t *face)
+{
+  hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t));
+  if (unlikely (!data))
+    return NULL;
+
+  data->cg_font = create_cg_font (face);
+  if (unlikely (!data->cg_font))
+  {
+    DEBUG_MSG (CORETEXT, face, "CGFont creation failed..");
+    free (data);
+    return NULL;
+  }
+
+  /* We use 36pt size instead of UPEM, because CoreText implements the 'trak' table,
+   * which can make the font too tight at large sizes.  36pt should be a good semi-neutral
+   * size.
+   *
+   * Since we always create CTFont at a fixed size, our CTFont lives in face_data
+   * instead of font_data.  Which is good, because when people change scale on
+   * hb_font_t, we won't need to update our CTFont. */
+  data->ct_font = create_ct_font (data->cg_font, 36.);
+  if (unlikely (!data->ct_font))
+  {
+    DEBUG_MSG (CORETEXT, face, "CTFont creation failed.");
+    CFRelease (data->cg_font);
+    free (data);
+    return NULL;
+  }
+
+  return data;
+}
+
+void
+_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
+{
+  CFRelease (data->ct_font);
+  CFRelease (data->cg_font);
+  free (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->cg_font;
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_coretext_shaper_font_data_t {};
+
+hb_coretext_shaper_font_data_t *
+_hb_coretext_shaper_font_data_create (hb_font_t *font HB_UNUSED)
+{
+  return (hb_coretext_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *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)
+{
+  hb_face_t *face = font->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->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);
+
+  CGFloat ct_font_size = CTFontGetSize (face_data->ct_font);
+  CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
+  CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
+
+  /* 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... */
+  if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+  {
+    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 (face_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;
+  }
+  {
+    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, face_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, face_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
+         * construct a hb_face to begin with.
+         *
+         * See: http://github.com/behdad/harfbuzz/pull/36
+         *
+         * Also see: https://bugs.chromium.org/p/chromium/issues/detail?id=597098
+         */
+        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->cg_font);
+            CFRelease (run_cg_font);
+          }
+        }
+        if (!matched)
+        {
+          CFStringRef font_ps_name = CTFontCopyName (face_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;
+        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
+ */
+
+/*
+ * 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);
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-coretext.h b/src/share/native/sun/font/harfbuzz/hb-coretext.h
new file mode 100644
index 0000000..82066e4
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-coretext.h
@@ -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_EXTERN hb_face_t *
+hb_coretext_face_create (CGFontRef cg_font);
+
+
+HB_EXTERN CGFontRef
+hb_coretext_face_get_cg_font (hb_face_t *face);
+
+HB_EXTERN CTFontRef
+hb_coretext_font_get_ct_font (hb_font_t *font);
+
+
+HB_END_DECLS
+
+#endif /* HB_CORETEXT_H */
diff --git a/src/share/native/sun/font/harfbuzz/hb-deprecated.h b/src/share/native/sun/font/harfbuzz/hb-deprecated.h
new file mode 100644
index 0000000..3943a00
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-deprecated.h
@@ -0,0 +1,61 @@
+/*
+ * 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
+
+typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
+                                               hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+                                               hb_codepoint_t *glyph,
+                                               void *user_data);
+
+HB_EXTERN void
+hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
+                              hb_font_get_glyph_func_t func,
+                              void *user_data, hb_destroy_func_t destroy);
+
+#endif
+
+HB_END_DECLS
+
+#endif /* HB_DEPRECATED_H */
diff --git a/src/share/native/sun/font/harfbuzz/hb-face-private.hh b/src/share/native/sun/font/harfbuzz/hb-face-private.hh
new file mode 100644
index 0000000..c4266ff
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-face-private.hh
@@ -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 */
diff --git a/src/share/native/sun/font/harfbuzz/hb-face.cpp b/src/share/native/sun/font/harfbuzz/hb-face.cpp
new file mode 100644
index 0000000..b5019a1
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-face.cpp
@@ -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);
+}
+
+
diff --git a/src/share/native/sun/font/harfbuzz/hb-face.h b/src/share/native/sun/font/harfbuzz/hb-face.h
new file mode 100644
index 0000000..08ffca3
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-face.h
@@ -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_EXTERN 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_EXTERN 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_EXTERN hb_face_t *
+hb_face_get_empty (void);
+
+HB_EXTERN hb_face_t *
+hb_face_reference (hb_face_t *face);
+
+HB_EXTERN void
+hb_face_destroy (hb_face_t *face);
+
+HB_EXTERN 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);
+
+
+HB_EXTERN void *
+hb_face_get_user_data (hb_face_t          *face,
+                       hb_user_data_key_t *key);
+
+HB_EXTERN void
+hb_face_make_immutable (hb_face_t *face);
+
+HB_EXTERN hb_bool_t
+hb_face_is_immutable (hb_face_t *face);
+
+
+HB_EXTERN hb_blob_t *
+hb_face_reference_table (hb_face_t *face,
+                         hb_tag_t   tag);
+
+HB_EXTERN hb_blob_t *
+hb_face_reference_blob (hb_face_t *face);
+
+HB_EXTERN void
+hb_face_set_index (hb_face_t    *face,
+                   unsigned int  index);
+
+HB_EXTERN unsigned int
+hb_face_get_index (hb_face_t    *face);
+
+HB_EXTERN void
+hb_face_set_upem (hb_face_t    *face,
+                  unsigned int  upem);
+
+HB_EXTERN unsigned int
+hb_face_get_upem (hb_face_t *face);
+
+HB_EXTERN void
+hb_face_set_glyph_count (hb_face_t    *face,
+                         unsigned int  glyph_count);
+
+HB_EXTERN unsigned int
+hb_face_get_glyph_count (hb_face_t *face);
+
+
+HB_END_DECLS
+
+#endif /* HB_FACE_H */
diff --git a/src/share/native/sun/font/harfbuzz/hb-fallback-shape.cpp b/src/share/native/sun/font/harfbuzz/hb-fallback-shape.cpp
new file mode 100644
index 0000000..dee7d7d
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-fallback-shape.cpp
@@ -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 = (bool) font->get_nominal_glyph (' ', &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_nominal_glyph (info[i].codepoint, &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;
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-font-private.hh b/src/share/native/sun/font/harfbuzz/hb-font-private.hh
new file mode 100644
index 0000000..d7b4877
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-font-private.hh
@@ -0,0 +1,524 @@
+/*
+ * 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 (font_h_extents) \
+  HB_FONT_FUNC_IMPLEMENT (font_v_extents) \
+  HB_FONT_FUNC_IMPLEMENT (nominal_glyph) \
+  HB_FONT_FUNC_IMPLEMENT (variation_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;
+
+  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;
+
+  /* Don't access these directly.  Call font->get_*() instead. */
+  union get_t {
+    struct get_funcs_t {
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
+      HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+    } f;
+    void (*array[VAR]) (void);
+  } get;
+};
+
+
+
+/*
+ * 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 */
+
+  HB_INTERNAL bool has_func (unsigned int i);
+
+  /* has_* ... */
+#define HB_FONT_FUNC_IMPLEMENT(name) \
+  bool \
+  has_##name##_func (void) \
+  { \
+    hb_font_funcs_t *funcs = this->klass; \
+    unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
+    return has_func (i); \
+  }
+  HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+
+  inline hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
+  {
+    memset (extents, 0, sizeof (*extents));
+    return klass->get.f.font_h_extents (this, user_data,
+                                        extents,
+                                        klass->user_data.font_h_extents);
+  }
+  inline hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
+  {
+    memset (extents, 0, sizeof (*extents));
+    return klass->get.f.font_v_extents (this, user_data,
+                                        extents,
+                                        klass->user_data.font_v_extents);
+  }
+
+  inline bool has_glyph (hb_codepoint_t unicode)
+  {
+    hb_codepoint_t glyph;
+    return get_nominal_glyph (unicode, &glyph);
+  }
+
+  inline hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
+                                      hb_codepoint_t *glyph)
+  {
+    *glyph = 0;
+    return klass->get.f.nominal_glyph (this, user_data,
+                                       unicode, glyph,
+                                       klass->user_data.nominal_glyph);
+  }
+
+  inline hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+                                        hb_codepoint_t *glyph)
+  {
+    *glyph = 0;
+    return klass->get.f.variation_glyph (this, user_data,
+                                         unicode, variation_selector, glyph,
+                                         klass->user_data.variation_glyph);
+  }
+
+  inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
+  {
+    return klass->get.f.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.f.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.f.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.f.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.f.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.f.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.f.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.f.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.f.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.f.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_extents_for_direction (hb_direction_t direction,
+                                         hb_font_extents_t *extents)
+  {
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
+      if (!get_font_h_extents (extents))
+      {
+        extents->ascender = y_scale * .8;
+        extents->descender = y_scale - extents->ascender;
+        extents->line_gap = 0;
+      }
+    } else {
+      if (!get_font_v_extents (extents))
+      {
+        extents->ascender = x_scale / 2;
+        extents->descender = x_scale - extents->ascender;
+        extents->line_gap = 0;
+      }
+    }
+  }
+
+  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_extents.ascender */
+    *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_h_origin (hb_codepoint_t glyph,
+                                  hb_position_t *x, hb_position_t *y)
+  {
+    hb_position_t origin_x, origin_y;
+
+    get_glyph_h_origin (glyph, &origin_x, &origin_y);
+
+    *x += origin_x;
+    *y += origin_y;
+  }
+  inline void add_glyph_v_origin (hb_codepoint_t glyph,
+                                  hb_position_t *x, hb_position_t *y)
+  {
+    hb_position_t origin_x, origin_y;
+
+    get_glyph_v_origin (glyph, &origin_x, &origin_y);
+
+    *x += origin_x;
+    *y += origin_y;
+  }
+  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_h_origin (hb_codepoint_t glyph,
+                                       hb_position_t *x, hb_position_t *y)
+  {
+    hb_position_t origin_x, origin_y;
+
+    get_glyph_h_origin (glyph, &origin_x, &origin_y);
+
+    *x -= origin_x;
+    *y -= origin_y;
+  }
+  inline void subtract_glyph_v_origin (hb_codepoint_t glyph,
+                                       hb_position_t *x, hb_position_t *y)
+  {
+    hb_position_t origin_x, origin_y;
+
+    get_glyph_v_origin (glyph, &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_nominal_glyph (unichar, glyph))
+        return true;
+    }
+
+    return false;
+  }
+
+  private:
+  inline hb_position_t em_scale (int16_t v, int scale)
+  {
+    int upem = face->get_upem ();
+    int64_t scaled = v * (int64_t) scale;
+    scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
+    return (hb_position_t) (scaled / 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 */
diff --git a/src/share/native/sun/font/harfbuzz/hb-font.cpp b/src/share/native/sun/font/harfbuzz/hb-font.cpp
new file mode 100644
index 0000000..eb0f9fc
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-font.cpp
@@ -0,0 +1,1667 @@
+/*
+ * 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_font_h_extents_nil (hb_font_t *font,
+                                void *font_data HB_UNUSED,
+                                hb_font_extents_t *metrics,
+                                void *user_data HB_UNUSED)
+{
+  memset (metrics, 0, sizeof (*metrics));
+  return false;
+}
+static hb_bool_t
+hb_font_get_font_h_extents_parent (hb_font_t *font,
+                                   void *font_data HB_UNUSED,
+                                   hb_font_extents_t *metrics,
+                                   void *user_data HB_UNUSED)
+{
+  hb_bool_t ret = font->parent->get_font_h_extents (metrics);
+  if (ret) {
+    metrics->ascender = font->parent_scale_y_distance (metrics->ascender);
+    metrics->descender = font->parent_scale_y_distance (metrics->descender);
+    metrics->line_gap = font->parent_scale_y_distance (metrics->line_gap);
+  }
+  return ret;
+}
+
+static hb_bool_t
+hb_font_get_font_v_extents_nil (hb_font_t *font,
+                                void *font_data HB_UNUSED,
+                                hb_font_extents_t *metrics,
+                                void *user_data HB_UNUSED)
+{
+  memset (metrics, 0, sizeof (*metrics));
+  return false;
+}
+static hb_bool_t
+hb_font_get_font_v_extents_parent (hb_font_t *font,
+                                   void *font_data HB_UNUSED,
+                                   hb_font_extents_t *metrics,
+                                   void *user_data HB_UNUSED)
+{
+  hb_bool_t ret = font->parent->get_font_v_extents (metrics);
+  if (ret) {
+    metrics->ascender = font->parent_scale_x_distance (metrics->ascender);
+    metrics->descender = font->parent_scale_x_distance (metrics->descender);
+    metrics->line_gap = font->parent_scale_x_distance (metrics->line_gap);
+  }
+  return ret;
+}
+
+static hb_bool_t
+hb_font_get_nominal_glyph_nil (hb_font_t *font HB_UNUSED,
+                               void *font_data HB_UNUSED,
+                               hb_codepoint_t unicode,
+                               hb_codepoint_t *glyph,
+                               void *user_data HB_UNUSED)
+{
+  *glyph = 0;
+  return false;
+}
+static hb_bool_t
+hb_font_get_nominal_glyph_parent (hb_font_t *font,
+                                  void *font_data HB_UNUSED,
+                                  hb_codepoint_t unicode,
+                                  hb_codepoint_t *glyph,
+                                  void *user_data HB_UNUSED)
+{
+  return font->parent->get_nominal_glyph (unicode, glyph);
+}
+
+static hb_bool_t
+hb_font_get_variation_glyph_nil (hb_font_t *font HB_UNUSED,
+                                 void *font_data HB_UNUSED,
+                                 hb_codepoint_t unicode,
+                                 hb_codepoint_t variation_selector,
+                                 hb_codepoint_t *glyph,
+                                 void *user_data HB_UNUSED)
+{
+  *glyph = 0;
+  return false;
+}
+static hb_bool_t
+hb_font_get_variation_glyph_parent (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)
+{
+  return font->parent->get_variation_glyph (unicode, variation_selector, glyph);
+}
+
+
+static hb_position_t
+hb_font_get_glyph_h_advance_nil (hb_font_t *font HB_UNUSED,
+                                 void *font_data HB_UNUSED,
+                                 hb_codepoint_t glyph,
+                                 void *user_data HB_UNUSED)
+{
+  return font->x_scale;
+}
+static hb_position_t
+hb_font_get_glyph_h_advance_parent (hb_font_t *font,
+                                    void *font_data HB_UNUSED,
+                                    hb_codepoint_t glyph,
+                                    void *user_data HB_UNUSED)
+{
+  return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
+}
+
+static hb_position_t
+hb_font_get_glyph_v_advance_nil (hb_font_t *font HB_UNUSED,
+                                 void *font_data HB_UNUSED,
+                                 hb_codepoint_t glyph,
+                                 void *user_data HB_UNUSED)
+{
+  /* TODO use font_extents.ascender+descender */
+  return font->y_scale;
+}
+static hb_position_t
+hb_font_get_glyph_v_advance_parent (hb_font_t *font,
+                                    void *font_data HB_UNUSED,
+                                    hb_codepoint_t glyph,
+                                    void *user_data HB_UNUSED)
+{
+  return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
+}
+
+static hb_bool_t
+hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED,
+                                void *font_data HB_UNUSED,
+                                hb_codepoint_t glyph,
+                                hb_position_t *x,
+                                hb_position_t *y,
+                                void *user_data HB_UNUSED)
+{
+  *x = *y = 0;
+  return true;
+}
+static hb_bool_t
+hb_font_get_glyph_h_origin_parent (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)
+{
+  hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y);
+  if (ret)
+    font->parent_scale_position (x, y);
+  return ret;
+}
+
+static hb_bool_t
+hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED,
+                                void *font_data HB_UNUSED,
+                                hb_codepoint_t glyph,
+                                hb_position_t *x,
+                                hb_position_t *y,
+                                void *user_data HB_UNUSED)
+{
+  *x = *y = 0;
+  return false;
+}
+static hb_bool_t
+hb_font_get_glyph_v_origin_parent (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)
+{
+  hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y);
+  if (ret)
+    font->parent_scale_position (x, y);
+  return ret;
+}
+
+static hb_position_t
+hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED,
+                                 void *font_data HB_UNUSED,
+                                 hb_codepoint_t left_glyph,
+                                 hb_codepoint_t right_glyph,
+                                 void *user_data HB_UNUSED)
+{
+  return 0;
+}
+static hb_position_t
+hb_font_get_glyph_h_kerning_parent (hb_font_t *font,
+                                    void *font_data HB_UNUSED,
+                                    hb_codepoint_t left_glyph,
+                                    hb_codepoint_t right_glyph,
+                                    void *user_data HB_UNUSED)
+{
+  return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
+}
+
+static hb_position_t
+hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
+                                 void *font_data HB_UNUSED,
+                                 hb_codepoint_t top_glyph,
+                                 hb_codepoint_t bottom_glyph,
+                                 void *user_data HB_UNUSED)
+{
+  return 0;
+}
+static hb_position_t
+hb_font_get_glyph_v_kerning_parent (hb_font_t *font,
+                                    void *font_data HB_UNUSED,
+                                    hb_codepoint_t top_glyph,
+                                    hb_codepoint_t bottom_glyph,
+                                    void *user_data HB_UNUSED)
+{
+  return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
+}
+
+static hb_bool_t
+hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
+                               void *font_data HB_UNUSED,
+                               hb_codepoint_t glyph,
+                               hb_glyph_extents_t *extents,
+                               void *user_data HB_UNUSED)
+{
+  memset (extents, 0, sizeof (*extents));
+  return false;
+}
+static hb_bool_t
+hb_font_get_glyph_extents_parent (hb_font_t *font,
+                                  void *font_data HB_UNUSED,
+                                  hb_codepoint_t glyph,
+                                  hb_glyph_extents_t *extents,
+                                  void *user_data HB_UNUSED)
+{
+  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;
+}
+
+static hb_bool_t
+hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED,
+                                     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)
+{
+  *x = *y = 0;
+  return false;
+}
+static hb_bool_t
+hb_font_get_glyph_contour_point_parent (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)
+{
+  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;
+}
+
+static hb_bool_t
+hb_font_get_glyph_name_nil (hb_font_t *font HB_UNUSED,
+                            void *font_data HB_UNUSED,
+                            hb_codepoint_t glyph,
+                            char *name, unsigned int size,
+                            void *user_data HB_UNUSED)
+{
+  if (size) *name = '\0';
+  return false;
+}
+static hb_bool_t
+hb_font_get_glyph_name_parent (hb_font_t *font,
+                               void *font_data HB_UNUSED,
+                               hb_codepoint_t glyph,
+                               char *name, unsigned int size,
+                               void *user_data HB_UNUSED)
+{
+  return font->parent->get_glyph_name (glyph, name, size);
+}
+
+static hb_bool_t
+hb_font_get_glyph_from_name_nil (hb_font_t *font HB_UNUSED,
+                                 void *font_data HB_UNUSED,
+                                 const char *name, int len, /* -1 means nul-terminated */
+                                 hb_codepoint_t *glyph,
+                                 void *user_data HB_UNUSED)
+{
+  *glyph = 0;
+  return false;
+}
+static hb_bool_t
+hb_font_get_glyph_from_name_parent (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)
+{
+  return font->parent->get_glyph_from_name (name, len, glyph);
+}
+
+static const hb_font_funcs_t _hb_font_funcs_nil = {
+  HB_OBJECT_HEADER_STATIC,
+
+  true, /* immutable */
+
+  {
+#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+  },
+  {
+#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+  },
+  {
+    {
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
+      HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+    }
+  }
+};
+static const hb_font_funcs_t _hb_font_funcs_parent = {
+  HB_OBJECT_HEADER_STATIC,
+
+  true, /* immutable */
+
+  {
+#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+  },
+  {
+#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+  },
+  {
+    {
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_parent,
+      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_parent.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_parent);
+}
+
+/**
+ * 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.f.name = func;                                           \
+    ffuncs->user_data.name = user_data;                                  \
+    ffuncs->destroy.name = destroy;                                      \
+  } else {                                                               \
+    ffuncs->get.f.name = hb_font_get_##name##_parent;                    \
+    ffuncs->user_data.name = NULL;                                       \
+    ffuncs->destroy.name = NULL;                                         \
+  }                                                                      \
+}
+
+HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+
+bool
+hb_font_t::has_func (unsigned int i)
+{
+  if (parent && parent != hb_font_get_empty () && parent->has_func (i))
+    return true;
+  return this->klass->get.array[i] != _hb_font_funcs_parent.get.array[i];
+}
+
+/* Public getters */
+
+/**
+ * hb_font_get_h_extents:
+ * @font: a font.
+ * @extents: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.1.3
+ **/
+hb_bool_t
+hb_font_get_h_extents (hb_font_t *font,
+                       hb_font_extents_t *extents)
+{
+  return font->get_font_h_extents (extents);
+}
+
+/**
+ * hb_font_get_v_extents:
+ * @font: a font.
+ * @extents: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.1.3
+ **/
+hb_bool_t
+hb_font_get_v_extents (hb_font_t *font,
+                       hb_font_extents_t *extents)
+{
+  return font->get_font_v_extents (extents);
+}
+
+/**
+ * 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)
+{
+  if (unlikely (variation_selector))
+    return font->get_variation_glyph (unicode, variation_selector, glyph);
+  return font->get_nominal_glyph (unicode, glyph);
+}
+
+/**
+ * hb_font_get_nominal_glyph:
+ * @font: a font.
+ * @unicode:
+ * @glyph: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.2.3
+ **/
+hb_bool_t
+hb_font_get_nominal_glyph (hb_font_t *font,
+                           hb_codepoint_t unicode,
+                           hb_codepoint_t *glyph)
+{
+  return font->get_nominal_glyph (unicode, glyph);
+}
+
+/**
+ * hb_font_get_variation_glyph:
+ * @font: a font.
+ * @unicode:
+ * @variation_selector:
+ * @glyph: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.2.3
+ **/
+hb_bool_t
+hb_font_get_variation_glyph (hb_font_t *font,
+                             hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+                             hb_codepoint_t *glyph)
+{
+  return font->get_variation_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_extents_for_direction:
+ * @font: a font.
+ * @direction:
+ * @extents:
+ *
+ *
+ *
+ * Since: 1.1.3
+ **/
+void
+hb_font_get_extents_for_direction (hb_font_t *font,
+                                   hb_direction_t direction,
+                                   hb_font_extents_t *extents)
+{
+  return font->get_extents_for_direction (direction, extents);
+}
+/**
+ * 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->parent = hb_font_get_empty ();
+  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),
+
+    1000, /* x_scale */
+    1000, /* 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)
+    return;
+
+  font->x_ppem = x_ppem;
+  font->y_ppem = y_ppem;
+}
+
+/**
+ * hb_font_get_ppem:
+ * @font: a font.
+ * @x_ppem: (out):
+ * @y_ppem: (out):
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_font_get_ppem (hb_font_t *font,
+                  unsigned int *x_ppem,
+                  unsigned int *y_ppem)
+{
+  if (x_ppem) *x_ppem = font->x_ppem;
+  if (y_ppem) *y_ppem = font->y_ppem;
+}
+
+
+#ifndef HB_DISABLE_DEPRECATED
+
+/*
+ * Deprecated get_glyph_func():
+ */
+
+struct hb_trampoline_closure_t
+{
+  void *user_data;
+  hb_destroy_func_t destroy;
+  unsigned int ref_count;
+};
+
+template <typename FuncType>
+struct hb_trampoline_t
+{
+  hb_trampoline_closure_t closure; /* Must be first. */
+  FuncType func;
+};
+
+template <typename FuncType>
+static hb_trampoline_t<FuncType> *
+trampoline_create (FuncType           func,
+                   void              *user_data,
+                   hb_destroy_func_t  destroy)
+{
+  typedef hb_trampoline_t<FuncType> trampoline_t;
+
+  trampoline_t *trampoline = (trampoline_t *) calloc (1, sizeof (trampoline_t));
+
+  if (unlikely (!trampoline))
+    return NULL;
+
+  trampoline->closure.user_data = user_data;
+  trampoline->closure.destroy = destroy;
+  trampoline->closure.ref_count = 1;
+  trampoline->func = func;
+
+  return trampoline;
+}
+
+static void
+trampoline_reference (hb_trampoline_closure_t *closure)
+{
+  closure->ref_count++;
+}
+
+static void
+trampoline_destroy (void *user_data)
+{
+  hb_trampoline_closure_t *closure = (hb_trampoline_closure_t *) user_data;
+
+  if (--closure->ref_count)
+    return;
+
+  if (closure->destroy)
+    closure->destroy (closure->user_data);
+  free (closure);
+}
+
+typedef hb_trampoline_t<hb_font_get_glyph_func_t> hb_font_get_glyph_trampoline_t;
+
+static hb_bool_t
+hb_font_get_nominal_glyph_trampoline (hb_font_t *font,
+                                      void *font_data,
+                                      hb_codepoint_t unicode,
+                                      hb_codepoint_t *glyph,
+                                      void *user_data)
+{
+  hb_font_get_glyph_trampoline_t *trampoline = (hb_font_get_glyph_trampoline_t *) user_data;
+  return trampoline->func (font, font_data, unicode, 0, glyph, trampoline->closure.user_data);
+}
+
+static hb_bool_t
+hb_font_get_variation_glyph_trampoline (hb_font_t *font,
+                                        void *font_data,
+                                        hb_codepoint_t unicode,
+                                        hb_codepoint_t variation_selector,
+                                        hb_codepoint_t *glyph,
+                                        void *user_data)
+{
+  hb_font_get_glyph_trampoline_t *trampoline = (hb_font_get_glyph_trampoline_t *) user_data;
+  return trampoline->func (font, font_data, unicode, variation_selector, glyph, trampoline->closure.user_data);
+}
+
+/**
+ * hb_font_funcs_set_glyph_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * Deprecated.  Use hb_font_funcs_set_nominal_glyph_func() and
+ * hb_font_funcs_set_variation_glyph_func() instead.
+ *
+ * Since: 0.9.2
+ * Deprecated: 1.2.3
+ **/
+void
+hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
+                              hb_font_get_glyph_func_t func,
+                              void *user_data, hb_destroy_func_t destroy)
+{
+  hb_font_get_glyph_trampoline_t *trampoline;
+
+  trampoline = trampoline_create (func, user_data, destroy);
+  if (unlikely (!trampoline))
+  {
+    if (destroy)
+      destroy (user_data);
+    return;
+  }
+
+  hb_font_funcs_set_nominal_glyph_func (ffuncs,
+                                        hb_font_get_nominal_glyph_trampoline,
+                                        trampoline,
+                                        trampoline_destroy);
+
+  trampoline_reference (&trampoline->closure);
+  hb_font_funcs_set_variation_glyph_func (ffuncs,
+                                          hb_font_get_variation_glyph_trampoline,
+                                          trampoline,
+                                          trampoline_destroy);
+}
+
+#endif /* HB_DISABLE_DEPRECATED */
diff --git a/src/share/native/sun/font/harfbuzz/hb-font.h b/src/share/native/sun/font/harfbuzz/hb-font.h
new file mode 100644
index 0000000..da9a3a7
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-font.h
@@ -0,0 +1,609 @@
+/*
+ * 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_FONT_H
+#define HB_FONT_H
+
+#include "hb-common.h"
+#include "hb-face.h"
+
+HB_BEGIN_DECLS
+
+
+typedef struct hb_font_t hb_font_t;
+
+
+/*
+ * hb_font_funcs_t
+ */
+
+typedef struct hb_font_funcs_t hb_font_funcs_t;
+
+HB_EXTERN hb_font_funcs_t *
+hb_font_funcs_create (void);
+
+HB_EXTERN hb_font_funcs_t *
+hb_font_funcs_get_empty (void);
+
+HB_EXTERN hb_font_funcs_t *
+hb_font_funcs_reference (hb_font_funcs_t *ffuncs);
+
+HB_EXTERN void
+hb_font_funcs_destroy (hb_font_funcs_t *ffuncs);
+
+HB_EXTERN 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);
+
+
+HB_EXTERN void *
+hb_font_funcs_get_user_data (hb_font_funcs_t    *ffuncs,
+                             hb_user_data_key_t *key);
+
+
+HB_EXTERN void
+hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs);
+
+HB_EXTERN hb_bool_t
+hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs);
+
+
+/* font and glyph extents */
+
+/* Note that typically ascender is positive and descender negative in coordinate systems that grow up. */
+typedef struct hb_font_extents_t
+{
+  hb_position_t ascender; /* typographic ascender. */
+  hb_position_t descender; /* typographic descender. */
+  hb_position_t line_gap; /* suggested line spacing gap. */
+  /*< private >*/
+  hb_position_t reserved9;
+  hb_position_t reserved8;
+  hb_position_t reserved7;
+  hb_position_t reserved6;
+  hb_position_t reserved5;
+  hb_position_t reserved4;
+  hb_position_t reserved3;
+  hb_position_t reserved2;
+  hb_position_t reserved1;
+} hb_font_extents_t;
+
+/* Note that height is negative in coordinate systems that grow up. */
+typedef struct hb_glyph_extents_t
+{
+  hb_position_t x_bearing; /* left side of glyph from origin. */
+  hb_position_t y_bearing; /* top side of glyph from origin. */
+  hb_position_t width; /* distance from left to right side. */
+  hb_position_t height; /* distance from top to bottom side. */
+} hb_glyph_extents_t;
+
+/* func types */
+
+typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *font_data,
+                                                       hb_font_extents_t *metrics,
+                                                       void *user_data);
+typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t;
+typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
+
+
+typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *font_data,
+                                                       hb_codepoint_t unicode,
+                                                       hb_codepoint_t *glyph,
+                                                       void *user_data);
+typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void *font_data,
+                                                         hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+                                                         hb_codepoint_t *glyph,
+                                                         void *user_data);
+
+
+typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void *font_data,
+                                                           hb_codepoint_t glyph,
+                                                           void *user_data);
+typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_h_advance_func_t;
+typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t;
+
+typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *font_data,
+                                                      hb_codepoint_t glyph,
+                                                      hb_position_t *x, hb_position_t *y,
+                                                      void *user_data);
+typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t;
+typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t;
+
+typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
+                                                           hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
+                                                           void *user_data);
+typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
+typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
+
+
+typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
+                                                       hb_codepoint_t glyph,
+                                                       hb_glyph_extents_t *extents,
+                                                       void *user_data);
+typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, void *font_data,
+                                                             hb_codepoint_t glyph, unsigned int point_index,
+                                                             hb_position_t *x, hb_position_t *y,
+                                                             void *user_data);
+
+
+typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_data,
+                                                    hb_codepoint_t glyph,
+                                                    char *name, unsigned int size,
+                                                    void *user_data);
+typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *font_data,
+                                                         const char *name, int len, /* -1 means nul-terminated */
+                                                         hb_codepoint_t *glyph,
+                                                         void *user_data);
+
+
+/* func setters */
+
+/**
+ * hb_font_funcs_set_font_h_extents_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.1.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_font_h_extents_func (hb_font_funcs_t *ffuncs,
+                                       hb_font_get_font_h_extents_func_t func,
+                                       void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_font_v_extents_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.1.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_font_v_extents_func (hb_font_funcs_t *ffuncs,
+                                       hb_font_get_font_v_extents_func_t func,
+                                       void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_nominal_glyph_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.2.3
+ **/
+HB_EXTERN void
+hb_font_funcs_set_nominal_glyph_func (hb_font_funcs_t *ffuncs,
+                                      hb_font_get_nominal_glyph_func_t func,
+                                      void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_variation_glyph_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.2.3
+ **/
+HB_EXTERN void
+hb_font_funcs_set_variation_glyph_func (hb_font_funcs_t *ffuncs,
+                                        hb_font_get_variation_glyph_func_t func,
+                                        void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_h_advance_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs,
+                                        hb_font_get_glyph_h_advance_func_t func,
+                                        void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_v_advance_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs,
+                                        hb_font_get_glyph_v_advance_func_t func,
+                                        void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_h_origin_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs,
+                                       hb_font_get_glyph_h_origin_func_t func,
+                                       void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_v_origin_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
+                                       hb_font_get_glyph_v_origin_func_t func,
+                                       void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_h_kerning_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
+                                        hb_font_get_glyph_h_kerning_func_t func,
+                                        void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_v_kerning_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
+                                        hb_font_get_glyph_v_kerning_func_t func,
+                                        void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_extents_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs,
+                                      hb_font_get_glyph_extents_func_t func,
+                                      void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_contour_point_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs,
+                                            hb_font_get_glyph_contour_point_func_t func,
+                                            void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_name_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs,
+                                   hb_font_get_glyph_name_func_t func,
+                                   void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_from_name_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
+                                        hb_font_get_glyph_from_name_func_t func,
+                                        void *user_data, hb_destroy_func_t destroy);
+
+/* func dispatch */
+
+HB_EXTERN hb_bool_t
+hb_font_get_h_extents (hb_font_t *font,
+                       hb_font_extents_t *extents);
+HB_EXTERN hb_bool_t
+hb_font_get_v_extents (hb_font_t *font,
+                       hb_font_extents_t *extents);
+
+HB_EXTERN hb_bool_t
+hb_font_get_nominal_glyph (hb_font_t *font,
+                           hb_codepoint_t unicode,
+                           hb_codepoint_t *glyph);
+HB_EXTERN hb_bool_t
+hb_font_get_variation_glyph (hb_font_t *font,
+                             hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+                             hb_codepoint_t *glyph);
+
+HB_EXTERN hb_position_t
+hb_font_get_glyph_h_advance (hb_font_t *font,
+                             hb_codepoint_t glyph);
+HB_EXTERN hb_position_t
+hb_font_get_glyph_v_advance (hb_font_t *font,
+                             hb_codepoint_t glyph);
+
+HB_EXTERN 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);
+HB_EXTERN 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);
+
+HB_EXTERN hb_position_t
+hb_font_get_glyph_h_kerning (hb_font_t *font,
+                             hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
+HB_EXTERN hb_position_t
+hb_font_get_glyph_v_kerning (hb_font_t *font,
+                             hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
+
+HB_EXTERN hb_bool_t
+hb_font_get_glyph_extents (hb_font_t *font,
+                           hb_codepoint_t glyph,
+                           hb_glyph_extents_t *extents);
+
+HB_EXTERN 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);
+
+HB_EXTERN hb_bool_t
+hb_font_get_glyph_name (hb_font_t *font,
+                        hb_codepoint_t glyph,
+                        char *name, unsigned int size);
+HB_EXTERN 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);
+
+
+/* high-level funcs, with fallback */
+
+/* Calls either hb_font_get_nominal_glyph() if variation_selector is 0,
+ * otherwise callse hb_font_get_variation_glyph(). */
+HB_EXTERN hb_bool_t
+hb_font_get_glyph (hb_font_t *font,
+                   hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+                   hb_codepoint_t *glyph);
+
+HB_EXTERN void
+hb_font_get_extents_for_direction (hb_font_t *font,
+                                   hb_direction_t direction,
+                                   hb_font_extents_t *extents);
+HB_EXTERN 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);
+HB_EXTERN 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);
+HB_EXTERN 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);
+HB_EXTERN 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);
+
+HB_EXTERN 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);
+
+HB_EXTERN 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);
+
+HB_EXTERN 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);
+
+/* Generates gidDDD if glyph has no name. */
+HB_EXTERN void
+hb_font_glyph_to_string (hb_font_t *font,
+                         hb_codepoint_t glyph,
+                         char *s, unsigned int size);
+/* Parses gidDDD and uniUUUU strings automatically. */
+HB_EXTERN 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);
+
+
+/*
+ * hb_font_t
+ */
+
+/* Fonts are very light-weight objects */
+
+HB_EXTERN hb_font_t *
+hb_font_create (hb_face_t *face);
+
+HB_EXTERN hb_font_t *
+hb_font_create_sub_font (hb_font_t *parent);
+
+HB_EXTERN hb_font_t *
+hb_font_get_empty (void);
+
+HB_EXTERN hb_font_t *
+hb_font_reference (hb_font_t *font);
+
+HB_EXTERN void
+hb_font_destroy (hb_font_t *font);
+
+HB_EXTERN 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);
+
+
+HB_EXTERN void *
+hb_font_get_user_data (hb_font_t          *font,
+                       hb_user_data_key_t *key);
+
+HB_EXTERN void
+hb_font_make_immutable (hb_font_t *font);
+
+HB_EXTERN hb_bool_t
+hb_font_is_immutable (hb_font_t *font);
+
+HB_EXTERN void
+hb_font_set_parent (hb_font_t *font,
+                    hb_font_t *parent);
+
+HB_EXTERN hb_font_t *
+hb_font_get_parent (hb_font_t *font);
+
+HB_EXTERN hb_face_t *
+hb_font_get_face (hb_font_t *font);
+
+
+HB_EXTERN void
+hb_font_set_funcs (hb_font_t         *font,
+                   hb_font_funcs_t   *klass,
+                   void              *font_data,
+                   hb_destroy_func_t  destroy);
+
+/* Be *very* careful with this function! */
+HB_EXTERN void
+hb_font_set_funcs_data (hb_font_t         *font,
+                        void              *font_data,
+                        hb_destroy_func_t  destroy);
+
+
+HB_EXTERN void
+hb_font_set_scale (hb_font_t *font,
+                   int x_scale,
+                   int y_scale);
+
+HB_EXTERN void
+hb_font_get_scale (hb_font_t *font,
+                   int *x_scale,
+                   int *y_scale);
+
+/*
+ * A zero value means "no hinting in that direction"
+ */
+HB_EXTERN void
+hb_font_set_ppem (hb_font_t *font,
+                  unsigned int x_ppem,
+                  unsigned int y_ppem);
+
+HB_EXTERN void
+hb_font_get_ppem (hb_font_t *font,
+                  unsigned int *x_ppem,
+                  unsigned int *y_ppem);
+
+
+HB_END_DECLS
+
+#endif /* HB_FONT_H */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ft.cpp b/src/share/native/sun/font/harfbuzz/hb-ft.cpp
new file mode 100644
index 0000000..fb3c1df
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ft.cpp
@@ -0,0 +1,724 @@
+/*
+ * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2009  Keith Stribley
+ * Copyright © 2015  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-ft.h"
+
+#include "hb-font-private.hh"
+
+#include FT_ADVANCES_H
+#include FT_TRUETYPE_TABLES_H
+
+
+
+#ifndef HB_DEBUG_FT
+#define HB_DEBUG_FT (HB_DEBUG+0)
+#endif
+
+
+/* TODO:
+ *
+ * In general, this file does a fine job of what it's supposed to do.
+ * There are, however, things that need more work:
+ *
+ *   - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy.
+ *     Have not investigated.
+ *
+ *   - FreeType works in 26.6 mode.  Clients can decide to use that mode, and everything
+ *     would work fine.  However, we also abuse this API for performing in font-space,
+ *     but don't pass the correct flags to FreeType.  We just abuse the no-hinting mode
+ *     for that, such that no rounding etc happens.  As such, we don't set ppem, and
+ *     pass NO_HINTING as load_flags.  Would be much better to use NO_SCALE, and scale
+ *     ourselves, like we do in uniscribe, etc.
+ *
+ *   - We don't handle / allow for emboldening / obliqueing.
+ *
+ *   - In the future, we should add constructors to create fonts in font space?
+ *
+ *   - FT_Load_Glyph() is exteremely costly.  Do something about it?
+ */
+
+
+struct hb_ft_font_t
+{
+  FT_Face ft_face;
+  int load_flags;
+  bool symbol; /* Whether selected cmap is symbol cmap. */
+  bool unref; /* Whether to destroy ft_face when done. */
+};
+
+static hb_ft_font_t *
+_hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
+{
+  hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
+
+  if (unlikely (!ft_font))
+    return NULL;
+
+  ft_font->ft_face = ft_face;
+  ft_font->symbol = symbol;
+  ft_font->unref = unref;
+
+  ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
+
+  return ft_font;
+}
+
+static void
+_hb_ft_face_destroy (FT_Face ft_face)
+{
+  FT_Done_Face (ft_face);
+}
+
+static void
+_hb_ft_font_destroy (hb_ft_font_t *ft_font)
+{
+  if (ft_font->unref)
+    _hb_ft_face_destroy (ft_font->ft_face);
+
+  free (ft_font);
+}
+
+/**
+ * hb_ft_font_set_load_flags:
+ * @font:
+ * @load_flags:
+ *
+ *
+ *
+ * Since: 1.0.5
+ **/
+void
+hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
+{
+  if (font->immutable)
+    return;
+
+  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
+    return;
+
+  hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
+
+  ft_font->load_flags = load_flags;
+}
+
+/**
+ * hb_ft_font_get_load_flags:
+ * @font:
+ *
+ *
+ *
+ * Return value:
+ * Since: 1.0.5
+ **/
+int
+hb_ft_font_get_load_flags (hb_font_t *font)
+{
+  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
+    return 0;
+
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
+
+  return ft_font->load_flags;
+}
+
+FT_Face
+hb_ft_font_get_face (hb_font_t *font)
+{
+  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
+    return NULL;
+
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
+
+  return ft_font->ft_face;
+}
+
+
+
+static hb_bool_t
+hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
+                         void *font_data,
+                         hb_codepoint_t unicode,
+                         hb_codepoint_t *glyph,
+                         void *user_data HB_UNUSED)
+{
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode);
+
+  if (unlikely (!g))
+  {
+    if (unlikely (ft_font->symbol) && unicode <= 0x00FFu)
+    {
+      /* For symbol-encoded OpenType fonts, we duplicate the
+       * U+F000..F0FF range at U+0000..U+00FF.  That's what
+       * Windows seems to do, and that's hinted about at:
+       * http://www.microsoft.com/typography/otspec/recom.htm
+       * under "Non-Standard (Symbol) Fonts". */
+      g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode);
+      if (!g)
+        return false;
+    }
+    else
+      return false;
+  }
+
+  *glyph = g;
+  return true;
+}
+
+static hb_bool_t
+hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED,
+                           void *font_data,
+                           hb_codepoint_t unicode,
+                           hb_codepoint_t variation_selector,
+                           hb_codepoint_t *glyph,
+                           void *user_data HB_UNUSED)
+{
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
+
+  if (unlikely (!g))
+    return false;
+
+  *glyph = g;
+  return true;
+}
+
+static hb_position_t
+hb_ft_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
+                           void *font_data,
+                           hb_codepoint_t glyph,
+                           void *user_data HB_UNUSED)
+{
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Fixed v;
+
+  if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v)))
+    return 0;
+
+  if (font->x_scale < 0)
+    v = -v;
+
+  return (v + (1<<9)) >> 10;
+}
+
+static hb_position_t
+hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
+                           void *font_data,
+                           hb_codepoint_t glyph,
+                           void *user_data HB_UNUSED)
+{
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Fixed v;
+
+  if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
+    return 0;
+
+  if (font->y_scale < 0)
+    v = -v;
+
+  /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
+   * have a Y growing upward.  Hence the extra negation. */
+  return (-v + (1<<9)) >> 10;
+}
+
+static hb_bool_t
+hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
+                          void *font_data,
+                          hb_codepoint_t glyph,
+                          hb_position_t *x,
+                          hb_position_t *y,
+                          void *user_data HB_UNUSED)
+{
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Face ft_face = ft_font->ft_face;
+
+  if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
+    return false;
+
+  /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
+   * have a Y growing upward.  Hence the extra negation. */
+  *x = ft_face->glyph->metrics.horiBearingX -   ft_face->glyph->metrics.vertBearingX;
+  *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
+
+  if (font->x_scale < 0)
+    *x = -*x;
+  if (font->y_scale < 0)
+    *y = -*y;
+
+  return true;
+}
+
+static hb_position_t
+hb_ft_get_glyph_h_kerning (hb_font_t *font,
+                           void *font_data,
+                           hb_codepoint_t left_glyph,
+                           hb_codepoint_t right_glyph,
+                           void *user_data HB_UNUSED)
+{
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Vector kerningv;
+
+  FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
+  if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
+    return 0;
+
+  return kerningv.x;
+}
+
+static hb_bool_t
+hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
+                         void *font_data,
+                         hb_codepoint_t glyph,
+                         hb_glyph_extents_t *extents,
+                         void *user_data HB_UNUSED)
+{
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Face ft_face = ft_font->ft_face;
+
+  if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
+    return false;
+
+  extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
+  extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
+  extents->width = ft_face->glyph->metrics.width;
+  extents->height = -ft_face->glyph->metrics.height;
+  if (font->x_scale < 0)
+  {
+    extents->x_bearing = -extents->x_bearing;
+    extents->width = -extents->width;
+  }
+  if (font->y_scale < 0)
+  {
+    extents->y_bearing = -extents->y_bearing;
+    extents->height = -extents->height;
+  }
+  return true;
+}
+
+static hb_bool_t
+hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
+                               void *font_data,
+                               hb_codepoint_t glyph,
+                               unsigned int point_index,
+                               hb_position_t *x,
+                               hb_position_t *y,
+                               void *user_data HB_UNUSED)
+{
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Face ft_face = ft_font->ft_face;
+
+  if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
+      return false;
+
+  if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
+      return false;
+
+  if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points))
+      return false;
+
+  *x = ft_face->glyph->outline.points[point_index].x;
+  *y = ft_face->glyph->outline.points[point_index].y;
+
+  return true;
+}
+
+static hb_bool_t
+hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED,
+                      void *font_data,
+                      hb_codepoint_t glyph,
+                      char *name, unsigned int size,
+                      void *user_data HB_UNUSED)
+{
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+
+  hb_bool_t ret = !FT_Get_Glyph_Name (ft_font->ft_face, glyph, name, size);
+  if (ret && (size && !*name))
+    ret = false;
+
+  return ret;
+}
+
+static hb_bool_t
+hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
+                           void *font_data,
+                           const char *name, int len, /* -1 means nul-terminated */
+                           hb_codepoint_t *glyph,
+                           void *user_data HB_UNUSED)
+{
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Face ft_face = ft_font->ft_face;
+
+  if (len < 0)
+    *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name);
+  else {
+    /* Make a nul-terminated version. */
+    char buf[128];
+    len = MIN (len, (int) sizeof (buf) - 1);
+    strncpy (buf, name, len);
+    buf[len] = '\0';
+    *glyph = FT_Get_Name_Index (ft_face, buf);
+  }
+
+  if (*glyph == 0)
+  {
+    /* Check whether the given name was actually the name of glyph 0. */
+    char buf[128];
+    if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) &&
+        len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len))
+      return true;
+  }
+
+  return *glyph != 0;
+}
+
+static hb_bool_t
+hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
+                          void *font_data,
+                          hb_font_extents_t *metrics,
+                          void *user_data HB_UNUSED)
+{
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Face ft_face = ft_font->ft_face;
+  metrics->ascender = ft_face->size->metrics.ascender;
+  metrics->descender = ft_face->size->metrics.descender;
+  metrics->line_gap = ft_face->size->metrics.height - (ft_face->size->metrics.ascender - ft_face->size->metrics.descender);
+  if (font->y_scale < 0)
+  {
+    metrics->ascender = -metrics->ascender;
+    metrics->descender = -metrics->descender;
+    metrics->line_gap = -metrics->line_gap;
+  }
+  return true;
+}
+
+static hb_font_funcs_t *static_ft_funcs = NULL;
+
+#ifdef HB_USE_ATEXIT
+static
+void free_static_ft_funcs (void)
+{
+  hb_font_funcs_destroy (static_ft_funcs);
+}
+#endif
+
+static void
+_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
+{
+retry:
+  hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
+
+  if (unlikely (!funcs))
+  {
+    funcs = hb_font_funcs_create ();
+
+    hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, NULL, NULL);
+    //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, NULL, NULL);
+    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, NULL, NULL);
+    hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, NULL, NULL);
+    hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, NULL, NULL);
+    hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, NULL, NULL);
+    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, NULL, NULL);
+    hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, NULL, NULL);
+    hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, NULL, NULL);
+    //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, NULL, NULL);
+    hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, NULL, NULL);
+    hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, NULL, NULL);
+    hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, NULL, NULL);
+    hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, NULL, NULL);
+
+    hb_font_funcs_make_immutable (funcs);
+
+    if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, NULL, funcs)) {
+      hb_font_funcs_destroy (funcs);
+      goto retry;
+    }
+
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_ft_funcs); /* First person registers atexit() callback. */
+#endif
+  };
+
+  bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
+
+  hb_font_set_funcs (font,
+                     funcs,
+                     _hb_ft_font_create (ft_face, symbol, unref),
+                     (hb_destroy_func_t) _hb_ft_font_destroy);
+}
+
+
+static hb_blob_t *
+reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+{
+  FT_Face ft_face = (FT_Face) user_data;
+  FT_Byte *buffer;
+  FT_ULong  length = 0;
+  FT_Error error;
+
+  /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
+
+  error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length);
+  if (error)
+    return NULL;
+
+  buffer = (FT_Byte *) malloc (length);
+  if (buffer == NULL)
+    return NULL;
+
+  error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
+  if (error)
+    return NULL;
+
+  return hb_blob_create ((const char *) buffer, length,
+                         HB_MEMORY_MODE_WRITABLE,
+                         buffer, free);
+}
+
+/**
+ * hb_ft_face_create:
+ * @ft_face: (destroy destroy) (scope notified):
+ * @destroy:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ * Since: 0.9.2
+ **/
+hb_face_t *
+hb_ft_face_create (FT_Face           ft_face,
+                   hb_destroy_func_t destroy)
+{
+  hb_face_t *face;
+
+  if (ft_face->stream->read == NULL) {
+    hb_blob_t *blob;
+
+    blob = hb_blob_create ((const char *) ft_face->stream->base,
+                           (unsigned int) ft_face->stream->size,
+                           HB_MEMORY_MODE_READONLY,
+                           ft_face, destroy);
+    face = hb_face_create (blob, ft_face->face_index);
+    hb_blob_destroy (blob);
+  } else {
+    face = hb_face_create_for_tables (reference_table, ft_face, destroy);
+  }
+
+  hb_face_set_index (face, ft_face->face_index);
+  hb_face_set_upem (face, ft_face->units_per_EM);
+
+  return face;
+}
+
+/**
+ * hb_ft_face_create_referenced:
+ * @ft_face:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ * Since: 0.9.38
+ **/
+hb_face_t *
+hb_ft_face_create_referenced (FT_Face ft_face)
+{
+  FT_Reference_Face (ft_face);
+  return hb_ft_face_create (ft_face, (hb_destroy_func_t) _hb_ft_face_destroy);
+}
+
+static void
+hb_ft_face_finalize (FT_Face ft_face)
+{
+  hb_face_destroy ((hb_face_t *) ft_face->generic.data);
+}
+
+/**
+ * hb_ft_face_create_cached:
+ * @ft_face:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ * Since: 0.9.2
+ **/
+hb_face_t *
+hb_ft_face_create_cached (FT_Face ft_face)
+{
+  if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
+  {
+    if (ft_face->generic.finalizer)
+      ft_face->generic.finalizer (ft_face);
+
+    ft_face->generic.data = hb_ft_face_create (ft_face, NULL);
+    ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
+  }
+
+  return hb_face_reference ((hb_face_t *) ft_face->generic.data);
+}
+
+
+/**
+ * hb_ft_font_create:
+ * @ft_face: (destroy destroy) (scope notified):
+ * @destroy:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ * Since: 0.9.2
+ **/
+hb_font_t *
+hb_ft_font_create (FT_Face           ft_face,
+                   hb_destroy_func_t destroy)
+{
+  hb_font_t *font;
+  hb_face_t *face;
+
+  face = hb_ft_face_create (ft_face, destroy);
+  font = hb_font_create (face);
+  hb_face_destroy (face);
+  _hb_ft_font_set_funcs (font, ft_face, false);
+  hb_font_set_scale (font,
+                     (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16),
+                     (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16));
+#if 0 /* hb-ft works in no-hinting model */
+  hb_font_set_ppem (font,
+                    ft_face->size->metrics.x_ppem,
+                    ft_face->size->metrics.y_ppem);
+#endif
+
+  return font;
+}
+
+/**
+ * hb_ft_font_create_referenced:
+ * @ft_face:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ * Since: 0.9.38
+ **/
+hb_font_t *
+hb_ft_font_create_referenced (FT_Face ft_face)
+{
+  FT_Reference_Face (ft_face);
+  return hb_ft_font_create (ft_face, (hb_destroy_func_t) _hb_ft_face_destroy);
+}
+
+
+/* Thread-safe, lock-free, FT_Library */
+
+static FT_Library ft_library;
+
+#ifdef HB_USE_ATEXIT
+static
+void free_ft_library (void)
+{
+  FT_Done_FreeType (ft_library);
+}
+#endif
+
+static FT_Library
+get_ft_library (void)
+{
+retry:
+  FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
+
+  if (unlikely (!library))
+  {
+    /* Not found; allocate one. */
+    if (FT_Init_FreeType (&library))
+      return NULL;
+
+    if (!hb_atomic_ptr_cmpexch (&ft_library, NULL, library)) {
+      FT_Done_FreeType (library);
+      goto retry;
+    }
+
+#ifdef HB_USE_ATEXIT
+    atexit (free_ft_library); /* First person registers atexit() callback. */
+#endif
+  }
+
+  return library;
+}
+
+static void
+_release_blob (FT_Face ft_face)
+{
+  hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
+}
+
+void
+hb_ft_font_set_funcs (hb_font_t *font)
+{
+  hb_blob_t *blob = hb_face_reference_blob (font->face);
+  unsigned int blob_length;
+  const char *blob_data = hb_blob_get_data (blob, &blob_length);
+  if (unlikely (!blob_length))
+    DEBUG_MSG (FT, font, "Font face has empty blob");
+
+  FT_Face ft_face = NULL;
+  FT_Error err = FT_New_Memory_Face (get_ft_library (),
+                                     (const FT_Byte *) blob_data,
+                                     blob_length,
+                                     hb_face_get_index (font->face),
+                                     &ft_face);
+
+  if (unlikely (err)) {
+    hb_blob_destroy (blob);
+    DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed");
+    return;
+  }
+
+  if (FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE))
+    FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL);
+
+  FT_Set_Char_Size (ft_face,
+                    abs (font->x_scale), abs (font->y_scale),
+                    0, 0);
+#if 0
+                    font->x_ppem * 72 * 64 / font->x_scale,
+                    font->y_ppem * 72 * 64 / font->y_scale);
+#endif
+  if (font->x_scale < 0 || font->y_scale < 0)
+  {
+    FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
+                          0, font->y_scale < 0 ? -1 : +1};
+    FT_Set_Transform (ft_face, &matrix, NULL);
+  }
+
+  ft_face->generic.data = blob;
+  ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
+
+  _hb_ft_font_set_funcs (font, ft_face, true);
+  hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-ft.h b/src/share/native/sun/font/harfbuzz/hb-ft.h
new file mode 100644
index 0000000..196b045
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ft.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2015  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_FT_H
+#define HB_FT_H
+
+#include "hb.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+HB_BEGIN_DECLS
+
+/*
+ * Note: FreeType is not thread-safe.
+ * Hence, these functions are not either.
+ */
+
+/*
+ * hb-face from ft-face.
+ */
+
+/* This one creates a new hb-face for given ft-face.
+ * When the returned hb-face is destroyed, the destroy
+ * callback is called (if not NULL), with the ft-face passed
+ * to it.
+ *
+ * The client is responsible to make sure that ft-face is
+ * destroyed after hb-face is destroyed.
+ *
+ * Most often you don't want this function.  You should use either
+ * hb_ft_face_create_cached(), or hb_ft_face_create_referenced().
+ * In particular, if you are going to pass NULL as destroy, you
+ * probably should use (the more recent) hb_ft_face_create_referenced()
+ * instead.
+ */
+HB_EXTERN hb_face_t *
+hb_ft_face_create (FT_Face           ft_face,
+                   hb_destroy_func_t destroy);
+
+/* This version is like hb_ft_face_create(), except that it caches
+ * the hb-face using the generic pointer of the ft-face.  This means
+ * that subsequent calls to this function with the same ft-face will
+ * return the same hb-face (correctly referenced).
+ *
+ * Client is still responsible for making sure that ft-face is destroyed
+ * after hb-face is.
+ */
+HB_EXTERN hb_face_t *
+hb_ft_face_create_cached (FT_Face ft_face);
+
+/* This version is like hb_ft_face_create(), except that it calls
+ * FT_Reference_Face() on ft-face, as such keeping ft-face alive
+ * as long as the hb-face is.
+ *
+ * This is the most convenient version to use.  Use it unless you have
+ * very good reasons not to.
+ */
+HB_EXTERN hb_face_t *
+hb_ft_face_create_referenced (FT_Face ft_face);
+
+
+/*
+ * hb-font from ft-face.
+ */
+
+/*
+ * Note:
+ *
+ * Set face size on ft-face before creating hb-font from it.
+ * Otherwise hb-ft would NOT pick up the font size correctly.
+ */
+
+/* See notes on hb_ft_face_create().  Same issues re lifecycle-management
+ * apply here.  Use hb_ft_font_create_referenced() if you can. */
+HB_EXTERN hb_font_t *
+hb_ft_font_create (FT_Face           ft_face,
+                   hb_destroy_func_t destroy);
+
+/* See notes on hb_ft_face_create_referenced() re lifecycle-management
+ * issues. */
+HB_EXTERN hb_font_t *
+hb_ft_font_create_referenced (FT_Face ft_face);
+
+HB_EXTERN FT_Face
+hb_ft_font_get_face (hb_font_t *font);
+
+HB_EXTERN void
+hb_ft_font_set_load_flags (hb_font_t *font, int load_flags);
+
+HB_EXTERN int
+hb_ft_font_get_load_flags (hb_font_t *font);
+
+/* Makes an hb_font_t use FreeType internally to implement font functions. */
+HB_EXTERN void
+hb_ft_font_set_funcs (hb_font_t *font);
+
+
+HB_END_DECLS
+
+#endif /* HB_FT_H */
diff --git a/src/share/native/sun/font/harfbuzz/hb-mutex-private.hh b/src/share/native/sun/font/harfbuzz/hb-mutex-private.hh
new file mode 100644
index 0000000..a69d886
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-mutex-private.hh
@@ -0,0 +1,141 @@
+/*
+ * 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_MUTEX_PRIVATE_HH
+#define HB_MUTEX_PRIVATE_HH
+
+#include "hb-private.hh"
+
+
+/* mutex */
+
+/* We need external help for these */
+
+#if defined(HB_MUTEX_IMPL_INIT) \
+ && defined(hb_mutex_impl_init) \
+ && defined(hb_mutex_impl_lock) \
+ && defined(hb_mutex_impl_unlock) \
+ && defined(hb_mutex_impl_finish)
+
+/* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */
+
+
+#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
+
+#include <windows.h>
+typedef CRITICAL_SECTION hb_mutex_impl_t;
+#define HB_MUTEX_IMPL_INIT      {0}
+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#define hb_mutex_impl_init(M)   InitializeCriticalSectionEx (M, 0, 0)
+#else
+#define hb_mutex_impl_init(M)   InitializeCriticalSection (M)
+#endif
+#define hb_mutex_impl_lock(M)   EnterCriticalSection (M)
+#define hb_mutex_impl_unlock(M) LeaveCriticalSection (M)
+#define hb_mutex_impl_finish(M) DeleteCriticalSection (M)
+
+
+#elif !defined(HB_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__))
+
+#include <pthread.h>
+typedef pthread_mutex_t hb_mutex_impl_t;
+#define HB_MUTEX_IMPL_INIT      PTHREAD_MUTEX_INITIALIZER
+#define hb_mutex_impl_init(M)   pthread_mutex_init (M, NULL)
+#define hb_mutex_impl_lock(M)   pthread_mutex_lock (M)
+#define hb_mutex_impl_unlock(M) pthread_mutex_unlock (M)
+#define hb_mutex_impl_finish(M) pthread_mutex_destroy (M)
+
+
+#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
+
+#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
+# include <sched.h>
+# define HB_SCHED_YIELD() sched_yield ()
+#else
+# define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END
+#endif
+
+/* This actually is not a totally awful implementation. */
+typedef volatile int hb_mutex_impl_t;
+#define HB_MUTEX_IMPL_INIT      0
+#define hb_mutex_impl_init(M)   *(M) = 0
+#define hb_mutex_impl_lock(M)   HB_STMT_START { while (__sync_lock_test_and_set((M), 1)) HB_SCHED_YIELD (); } HB_STMT_END
+#define hb_mutex_impl_unlock(M) __sync_lock_release (M)
+#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
+
+
+#elif !defined(HB_NO_MT)
+
+#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
+# include <sched.h>
+# define HB_SCHED_YIELD() sched_yield ()
+#else
+# define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END
+#endif
+
+#define HB_MUTEX_INT_NIL 1 /* Warn that fallback implementation is in use. */
+typedef volatile int hb_mutex_impl_t;
+#define HB_MUTEX_IMPL_INIT      0
+#define hb_mutex_impl_init(M)   *(M) = 0
+#define hb_mutex_impl_lock(M)   HB_STMT_START { while (*(M)) HB_SCHED_YIELD (); (*(M))++; } HB_STMT_END
+#define hb_mutex_impl_unlock(M) (*(M))--;
+#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
+
+
+#else /* HB_NO_MT */
+
+typedef int hb_mutex_impl_t;
+#define HB_MUTEX_IMPL_INIT      0
+#define hb_mutex_impl_init(M)   HB_STMT_START {} HB_STMT_END
+#define hb_mutex_impl_lock(M)   HB_STMT_START {} HB_STMT_END
+#define hb_mutex_impl_unlock(M) HB_STMT_START {} HB_STMT_END
+#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
+
+
+#endif
+
+
+#define HB_MUTEX_INIT           {HB_MUTEX_IMPL_INIT}
+
+struct hb_mutex_t
+{
+  /* TODO Add tracing. */
+
+  hb_mutex_impl_t m;
+
+  inline void init   (void) { hb_mutex_impl_init   (&m); }
+  inline void lock   (void) { hb_mutex_impl_lock   (&m); }
+  inline void unlock (void) { hb_mutex_impl_unlock (&m); }
+  inline void finish (void) { hb_mutex_impl_finish (&m); }
+};
+
+
+#endif /* HB_MUTEX_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-object-private.hh b/src/share/native/sun/font/harfbuzz/hb-object-private.hh
new file mode 100644
index 0000000..f2bb23e
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-object-private.hh
@@ -0,0 +1,202 @@
+/*
+ * 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_OBJECT_PRIVATE_HH
+#define HB_OBJECT_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-atomic-private.hh"
+#include "hb-mutex-private.hh"
+
+
+/* Debug */
+
+#ifndef HB_DEBUG_OBJECT
+#define HB_DEBUG_OBJECT (HB_DEBUG+0)
+#endif
+
+
+/* reference_count */
+
+#define HB_REFERENCE_COUNT_INERT_VALUE -1
+#define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD
+#define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT(HB_REFERENCE_COUNT_INERT_VALUE)}
+
+struct hb_reference_count_t
+{
+  hb_atomic_int_t ref_count;
+
+  inline void init (int v) { ref_count.set_unsafe (v); }
+  inline int get_unsafe (void) const { return ref_count.get_unsafe (); }
+  inline int inc (void) { return ref_count.inc (); }
+  inline int dec (void) { return ref_count.dec (); }
+  inline void finish (void) { ref_count.set_unsafe (HB_REFERENCE_COUNT_POISON_VALUE); }
+
+  inline bool is_inert (void) const { return ref_count.get_unsafe () == HB_REFERENCE_COUNT_INERT_VALUE; }
+  inline bool is_valid (void) const { return ref_count.get_unsafe () > 0; }
+};
+
+
+/* user_data */
+
+#define HB_USER_DATA_ARRAY_INIT {HB_MUTEX_INIT, HB_LOCKABLE_SET_INIT}
+struct hb_user_data_array_t
+{
+  struct hb_user_data_item_t {
+    hb_user_data_key_t *key;
+    void *data;
+    hb_destroy_func_t destroy;
+
+    inline bool operator == (hb_user_data_key_t *other_key) const { return key == other_key; }
+    inline bool operator == (hb_user_data_item_t &other) const { return key == other.key; }
+
+    void finish (void) { if (destroy) destroy (data); }
+  };
+
+  hb_mutex_t lock;
+  hb_lockable_set_t<hb_user_data_item_t, hb_mutex_t> items;
+
+  inline void init (void) { lock.init (); items.init (); }
+
+  HB_INTERNAL bool set (hb_user_data_key_t *key,
+                        void *              data,
+                        hb_destroy_func_t   destroy,
+                        hb_bool_t           replace);
+
+  HB_INTERNAL void *get (hb_user_data_key_t *key);
+
+  inline void finish (void) { items.finish (lock); lock.finish (); }
+};
+
+
+/* object_header */
+
+struct hb_object_header_t
+{
+  hb_reference_count_t ref_count;
+  hb_user_data_array_t user_data;
+
+#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INIT, HB_USER_DATA_ARRAY_INIT}
+
+  private:
+  ASSERT_POD ();
+};
+
+
+/* object */
+
+template <typename Type>
+static inline void hb_object_trace (const Type *obj, const char *function)
+{
+  DEBUG_MSG (OBJECT, (void *) obj,
+             "%s refcount=%d",
+             function,
+             obj ? obj->header.ref_count.get_unsafe () : 0);
+}
+
+template <typename Type>
+static inline Type *hb_object_create (void)
+{
+  Type *obj = (Type *) calloc (1, sizeof (Type));
+
+  if (unlikely (!obj))
+    return obj;
+
+  hb_object_init (obj);
+  hb_object_trace (obj, HB_FUNC);
+  return obj;
+}
+template <typename Type>
+static inline void hb_object_init (Type *obj)
+{
+  obj->header.ref_count.init (1);
+  obj->header.user_data.init ();
+}
+template <typename Type>
+static inline bool hb_object_is_inert (const Type *obj)
+{
+  return unlikely (obj->header.ref_count.is_inert ());
+}
+template <typename Type>
+static inline bool hb_object_is_valid (const Type *obj)
+{
+  return likely (obj->header.ref_count.is_valid ());
+}
+template <typename Type>
+static inline Type *hb_object_reference (Type *obj)
+{
+  hb_object_trace (obj, HB_FUNC);
+  if (unlikely (!obj || hb_object_is_inert (obj)))
+    return obj;
+  assert (hb_object_is_valid (obj));
+  obj->header.ref_count.inc ();
+  return obj;
+}
+template <typename Type>
+static inline bool hb_object_destroy (Type *obj)
+{
+  hb_object_trace (obj, HB_FUNC);
+  if (unlikely (!obj || hb_object_is_inert (obj)))
+    return false;
+  assert (hb_object_is_valid (obj));
+  if (obj->header.ref_count.dec () != 1)
+    return false;
+
+  obj->header.ref_count.finish (); /* Do this before user_data */
+  obj->header.user_data.finish ();
+  return true;
+}
+template <typename Type>
+static inline bool hb_object_set_user_data (Type               *obj,
+                                            hb_user_data_key_t *key,
+                                            void *              data,
+                                            hb_destroy_func_t   destroy,
+                                            hb_bool_t           replace)
+{
+  if (unlikely (!obj || hb_object_is_inert (obj)))
+    return false;
+  assert (hb_object_is_valid (obj));
+  return obj->header.user_data.set (key, data, destroy, replace);
+}
+
+template <typename Type>
+static inline void *hb_object_get_user_data (Type               *obj,
+                                             hb_user_data_key_t *key)
+{
+  if (unlikely (!obj || hb_object_is_inert (obj)))
+    return NULL;
+  assert (hb_object_is_valid (obj));
+  return obj->header.user_data.get (key);
+}
+
+
+#endif /* HB_OBJECT_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-open-file-private.hh b/src/share/native/sun/font/harfbuzz/hb-open-file-private.hh
new file mode 100644
index 0000000..943d96c
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-open-file-private.hh
@@ -0,0 +1,268 @@
+/*
+ * Copyright © 2007,2008,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
+ */
+
+#ifndef HB_OPEN_FILE_PRIVATE_HH
+#define HB_OPEN_FILE_PRIVATE_HH
+
+#include "hb-open-type-private.hh"
+
+
+namespace OT {
+
+
+/*
+ *
+ * The OpenType Font File
+ *
+ */
+
+
+/*
+ * Organization of an OpenType Font
+ */
+
+struct OpenTypeFontFile;
+struct OffsetTable;
+struct TTCHeader;
+
+
+typedef struct TableRecord
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  Tag           tag;            /* 4-byte identifier. */
+  CheckSum      checkSum;       /* CheckSum for this table. */
+  ULONG         offset;         /* Offset from beginning of TrueType font
+                                 * file. */
+  ULONG         length;         /* Length of this table. */
+  public:
+  DEFINE_SIZE_STATIC (16);
+} OpenTypeTable;
+
+typedef struct OffsetTable
+{
+  friend struct OpenTypeFontFile;
+
+  inline unsigned int get_table_count (void) const
+  { return numTables; }
+  inline const TableRecord& get_table (unsigned int i) const
+  {
+    if (unlikely (i >= numTables)) return Null(TableRecord);
+    return tables[i];
+  }
+  inline bool find_table_index (hb_tag_t tag, unsigned int *table_index) const
+  {
+    Tag t;
+    t.set (tag);
+    unsigned int count = numTables;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (t == tables[i].tag)
+      {
+        if (table_index) *table_index = i;
+        return true;
+      }
+    }
+    if (table_index) *table_index = Index::NOT_FOUND_INDEX;
+    return false;
+  }
+  inline const TableRecord& get_table_by_tag (hb_tag_t tag) const
+  {
+    unsigned int table_index;
+    find_table_index (tag, &table_index);
+    return get_table (table_index);
+  }
+
+  public:
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables));
+  }
+
+  protected:
+  Tag           sfnt_version;   /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */
+  USHORT        numTables;      /* Number of tables. */
+  USHORT        searchRangeZ;   /* (Maximum power of 2 <= numTables) x 16 */
+  USHORT        entrySelectorZ; /* Log2(maximum power of 2 <= numTables). */
+  USHORT        rangeShiftZ;    /* NumTables x 16-searchRange. */
+  TableRecord   tables[VAR];    /* TableRecord entries. numTables items */
+  public:
+  DEFINE_SIZE_ARRAY (12, tables);
+} OpenTypeFontFace;
+
+
+/*
+ * TrueType Collections
+ */
+
+struct TTCHeaderVersion1
+{
+  friend struct TTCHeader;
+
+  inline unsigned int get_face_count (void) const { return table.len; }
+  inline const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (table.sanitize (c, this));
+  }
+
+  protected:
+  Tag           ttcTag;         /* TrueType Collection ID string: 'ttcf' */
+  FixedVersion<>version;        /* Version of the TTC Header (1.0),
+                                 * 0x00010000u */
+  ArrayOf<OffsetTo<OffsetTable, ULONG>, ULONG>
+                table;          /* Array of offsets to the OffsetTable for each font
+                                 * from the beginning of the file */
+  public:
+  DEFINE_SIZE_ARRAY (12, table);
+};
+
+struct TTCHeader
+{
+  friend struct OpenTypeFontFile;
+
+  private:
+
+  inline unsigned int get_face_count (void) const
+  {
+    switch (u.header.version.major) {
+    case 2: /* version 2 is compatible with version 1 */
+    case 1: return u.version1.get_face_count ();
+    default:return 0;
+    }
+  }
+  inline const OpenTypeFontFace& get_face (unsigned int i) const
+  {
+    switch (u.header.version.major) {
+    case 2: /* version 2 is compatible with version 1 */
+    case 1: return u.version1.get_face (i);
+    default:return Null(OpenTypeFontFace);
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!u.header.version.sanitize (c))) return_trace (false);
+    switch (u.header.version.major) {
+    case 2: /* version 2 is compatible with version 1 */
+    case 1: return_trace (u.version1.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  protected:
+  union {
+  struct {
+  Tag           ttcTag;         /* TrueType Collection ID string: 'ttcf' */
+  FixedVersion<>version;        /* Version of the TTC Header (1.0 or 2.0),
+                                 * 0x00010000u or 0x00020000u */
+  }                     header;
+  TTCHeaderVersion1     version1;
+  } u;
+};
+
+
+/*
+ * OpenType Font File
+ */
+
+struct OpenTypeFontFile
+{
+  static const hb_tag_t tableTag        = HB_TAG ('_','_','_','_'); /* Sanitizer needs this. */
+
+  static const hb_tag_t CFFTag          = HB_TAG ('O','T','T','O'); /* OpenType with Postscript outlines */
+  static const hb_tag_t TrueTypeTag     = HB_TAG ( 0 , 1 , 0 , 0 ); /* OpenType with TrueType outlines */
+  static const hb_tag_t TTCTag          = HB_TAG ('t','t','c','f'); /* TrueType Collection */
+  static const hb_tag_t TrueTag         = HB_TAG ('t','r','u','e'); /* Obsolete Apple TrueType */
+  static const hb_tag_t Typ1Tag         = HB_TAG ('t','y','p','1'); /* Obsolete Apple Type1 font in SFNT container */
+
+  inline hb_tag_t get_tag (void) const { return u.tag; }
+
+  inline unsigned int get_face_count (void) const
+  {
+    switch (u.tag) {
+    case CFFTag:        /* All the non-collection tags */
+    case TrueTag:
+    case Typ1Tag:
+    case TrueTypeTag:   return 1;
+    case TTCTag:        return u.ttcHeader.get_face_count ();
+    default:            return 0;
+    }
+  }
+  inline const OpenTypeFontFace& get_face (unsigned int i) const
+  {
+    switch (u.tag) {
+    /* Note: for non-collection SFNT data we ignore index.  This is because
+     * Apple dfont container is a container of SFNT's.  So each SFNT is a
+     * non-TTC, but the index is more than zero. */
+    case CFFTag:        /* All the non-collection tags */
+    case TrueTag:
+    case Typ1Tag:
+    case TrueTypeTag:   return u.fontFace;
+    case TTCTag:        return u.ttcHeader.get_face (i);
+    default:            return Null(OpenTypeFontFace);
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!u.tag.sanitize (c))) return_trace (false);
+    switch (u.tag) {
+    case CFFTag:        /* All the non-collection tags */
+    case TrueTag:
+    case Typ1Tag:
+    case TrueTypeTag:   return_trace (u.fontFace.sanitize (c));
+    case TTCTag:        return_trace (u.ttcHeader.sanitize (c));
+    default:            return_trace (true);
+    }
+  }
+
+  protected:
+  union {
+  Tag                   tag;            /* 4-byte identifier. */
+  OpenTypeFontFace      fontFace;
+  TTCHeader             ttcHeader;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (4, tag);
+};
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OPEN_FILE_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-open-type-private.hh b/src/share/native/sun/font/harfbuzz/hb-open-type-private.hh
new file mode 100644
index 0000000..27c5f17
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-open-type-private.hh
@@ -0,0 +1,1063 @@
+/*
+ * Copyright © 2007,2008,2009,2010  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
+ */
+
+#ifndef HB_OPEN_TYPE_PRIVATE_HH
+#define HB_OPEN_TYPE_PRIVATE_HH
+
+#include "hb-private.hh"
+
+
+namespace OT {
+
+
+
+/*
+ * Casts
+ */
+
+/* Cast to struct T, reference to reference */
+template<typename Type, typename TObject>
+static inline const Type& CastR(const TObject &X)
+{ return reinterpret_cast<const Type&> (X); }
+template<typename Type, typename TObject>
+static inline Type& CastR(TObject &X)
+{ return reinterpret_cast<Type&> (X); }
+
+/* Cast to struct T, pointer to pointer */
+template<typename Type, typename TObject>
+static inline const Type* CastP(const TObject *X)
+{ return reinterpret_cast<const Type*> (X); }
+template<typename Type, typename TObject>
+static inline Type* CastP(TObject *X)
+{ return reinterpret_cast<Type*> (X); }
+
+/* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
+ * location pointed to by P plus Ofs bytes. */
+template<typename Type>
+static inline const Type& StructAtOffset(const void *P, unsigned int offset)
+{ return * reinterpret_cast<const Type*> ((const char *) P + offset); }
+template<typename Type>
+static inline Type& StructAtOffset(void *P, unsigned int offset)
+{ return * reinterpret_cast<Type*> ((char *) P + offset); }
+
+/* StructAfter<T>(X) returns the struct T& that is placed after X.
+ * Works with X of variable size also.  X must implement get_size() */
+template<typename Type, typename TObject>
+static inline const Type& StructAfter(const TObject &X)
+{ return StructAtOffset<Type>(&X, X.get_size()); }
+template<typename Type, typename TObject>
+static inline Type& StructAfter(TObject &X)
+{ return StructAtOffset<Type>(&X, X.get_size()); }
+
+
+
+/*
+ * Size checking
+ */
+
+/* Check _assertion in a method environment */
+#define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
+  inline void _instance_assertion_on_line_##_line (void) const \
+  { \
+    ASSERT_STATIC (_assertion); \
+    ASSERT_INSTANCE_POD (*this); /* Make sure it's POD. */ \
+  }
+# define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion)
+# define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion)
+
+/* Check that _code compiles in a method environment */
+#define _DEFINE_COMPILES_ASSERTION1(_line, _code) \
+  inline void _compiles_assertion_on_line_##_line (void) const \
+  { _code; }
+# define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1 (_line, _code)
+# define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code)
+
+
+#define DEFINE_SIZE_STATIC(size) \
+  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \
+  static const unsigned int static_size = (size); \
+  static const unsigned int min_size = (size); \
+  inline unsigned int get_size (void) const { return (size); }
+
+#define DEFINE_SIZE_UNION(size, _member) \
+  DEFINE_INSTANCE_ASSERTION (this->u._member.static_size == (size)); \
+  static const unsigned int min_size = (size)
+
+#define DEFINE_SIZE_MIN(size) \
+  DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)); \
+  static const unsigned int min_size = (size)
+
+#define DEFINE_SIZE_ARRAY(size, array) \
+  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \
+  DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \
+  static const unsigned int min_size = (size)
+
+#define DEFINE_SIZE_ARRAY2(size, array1, array2) \
+  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \
+  DEFINE_COMPILES_ASSERTION ((void) array1[0].static_size; (void) array2[0].static_size) \
+  static const unsigned int min_size = (size)
+
+
+
+/*
+ * Null objects
+ */
+
+/* Global nul-content Null pool.  Enlarge as necessary. */
+/* TODO This really should be a extern HB_INTERNAL and defined somewhere... */
+static const void *_NullPool[(256+8) / sizeof (void *)];
+
+/* Generic nul-content Null objects. */
+template <typename Type>
+static inline const Type& Null (void) {
+  ASSERT_STATIC (sizeof (Type) <= sizeof (_NullPool));
+  return *CastP<Type> (_NullPool);
+}
+
+/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
+#define DEFINE_NULL_DATA(Type, data) \
+static const char _Null##Type[sizeof (Type) + 1] = data; /* +1 is for nul-termination in data */ \
+template <> \
+/*static*/ inline const Type& Null<Type> (void) { \
+  return *CastP<Type> (_Null##Type); \
+} /* The following line really exists such that we end in a place needing semicolon */ \
+ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
+
+/* Accessor macro. */
+#define Null(Type) Null<Type>()
+
+
+/*
+ * Dispatch
+ */
+
+template <typename Context, typename Return, unsigned int MaxDebugDepth>
+struct hb_dispatch_context_t
+{
+  static const unsigned int max_debug_depth = MaxDebugDepth;
+  typedef Return return_t;
+  template <typename T, typename F>
+  inline bool may_dispatch (const T *obj, const F *format) { return true; }
+  static return_t no_dispatch_return_value (void) { return Context::default_return_value (); }
+};
+
+
+/*
+ * Sanitize
+ */
+
+#ifndef HB_DEBUG_SANITIZE
+#define HB_DEBUG_SANITIZE (HB_DEBUG+0)
+#endif
+
+
+#define TRACE_SANITIZE(this) \
+        hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
+        (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+         "");
+
+/* This limits sanitizing time on really broken fonts. */
+#ifndef HB_SANITIZE_MAX_EDITS
+#define HB_SANITIZE_MAX_EDITS 32
+#endif
+
+struct hb_sanitize_context_t :
+       hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE>
+{
+  inline hb_sanitize_context_t (void) :
+        debug_depth (0),
+        start (NULL), end (NULL),
+        writable (false), edit_count (0),
+        blob (NULL) {}
+
+  inline const char *get_name (void) { return "SANITIZE"; }
+  template <typename T, typename F>
+  inline bool may_dispatch (const T *obj, const F *format)
+  { return format->sanitize (this); }
+  template <typename T>
+  inline return_t dispatch (const T &obj) { return obj.sanitize (this); }
+  static return_t default_return_value (void) { return true; }
+  static return_t no_dispatch_return_value (void) { return false; }
+  bool stop_sublookup_iteration (const return_t r) const { return !r; }
+
+  inline void init (hb_blob_t *b)
+  {
+    this->blob = hb_blob_reference (b);
+    this->writable = false;
+  }
+
+  inline void start_processing (void)
+  {
+    this->start = hb_blob_get_data (this->blob, NULL);
+    this->end = this->start + hb_blob_get_length (this->blob);
+    assert (this->start <= this->end); /* Must not overflow. */
+    this->edit_count = 0;
+    this->debug_depth = 0;
+
+    DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1,
+                     "start [%p..%p] (%lu bytes)",
+                     this->start, this->end,
+                     (unsigned long) (this->end - this->start));
+  }
+
+  inline void end_processing (void)
+  {
+    DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1,
+                     "end [%p..%p] %u edit requests",
+                     this->start, this->end, this->edit_count);
+
+    hb_blob_destroy (this->blob);
+    this->blob = NULL;
+    this->start = this->end = NULL;
+  }
+
+  inline bool check_range (const void *base, unsigned int len) const
+  {
+    const char *p = (const char *) base;
+    bool ok = this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len;
+
+    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+       "check_range [%p..%p] (%d bytes) in [%p..%p] -> %s",
+       p, p + len, len,
+       this->start, this->end,
+       ok ? "OK" : "OUT-OF-RANGE");
+
+    return likely (ok);
+  }
+
+  inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
+  {
+    const char *p = (const char *) base;
+    bool overflows = _hb_unsigned_int_mul_overflows (len, record_size);
+    unsigned int array_size = record_size * len;
+    bool ok = !overflows && this->check_range (base, array_size);
+
+    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+       "check_array [%p..%p] (%d*%d=%d bytes) in [%p..%p] -> %s",
+       p, p + (record_size * len), record_size, len, (unsigned int) array_size,
+       this->start, this->end,
+       overflows ? "OVERFLOWS" : ok ? "OK" : "OUT-OF-RANGE");
+
+    return likely (ok);
+  }
+
+  template <typename Type>
+  inline bool check_struct (const Type *obj) const
+  {
+    return likely (this->check_range (obj, obj->min_size));
+  }
+
+  inline bool may_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED)
+  {
+    if (this->edit_count >= HB_SANITIZE_MAX_EDITS)
+      return false;
+
+    const char *p = (const char *) base;
+    this->edit_count++;
+
+    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+       "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
+       this->edit_count,
+       p, p + len, len,
+       this->start, this->end,
+       this->writable ? "GRANTED" : "DENIED");
+
+    return this->writable;
+  }
+
+  template <typename Type, typename ValueType>
+  inline bool try_set (const Type *obj, const ValueType &v) {
+    if (this->may_edit (obj, obj->static_size)) {
+      const_cast<Type *> (obj)->set (v);
+      return true;
+    }
+    return false;
+  }
+
+  mutable unsigned int debug_depth;
+  const char *start, *end;
+  bool writable;
+  unsigned int edit_count;
+  hb_blob_t *blob;
+};
+
+
+
+/* Template to sanitize an object. */
+template <typename Type>
+struct Sanitizer
+{
+  static hb_blob_t *sanitize (hb_blob_t *blob) {
+    hb_sanitize_context_t c[1];
+    bool sane;
+
+    /* TODO is_sane() stuff */
+
+    c->init (blob);
+
+  retry:
+    DEBUG_MSG_FUNC (SANITIZE, c->start, "start");
+
+    c->start_processing ();
+
+    if (unlikely (!c->start)) {
+      c->end_processing ();
+      return blob;
+    }
+
+    Type *t = CastP<Type> (const_cast<char *> (c->start));
+
+    sane = t->sanitize (c);
+    if (sane) {
+      if (c->edit_count) {
+        DEBUG_MSG_FUNC (SANITIZE, c->start, "passed first round with %d edits; going for second round", c->edit_count);
+
+        /* sanitize again to ensure no toe-stepping */
+        c->edit_count = 0;
+        sane = t->sanitize (c);
+        if (c->edit_count) {
+          DEBUG_MSG_FUNC (SANITIZE, c->start, "requested %d edits in second round; FAILLING", c->edit_count);
+          sane = false;
+        }
+      }
+    } else {
+      unsigned int edit_count = c->edit_count;
+      if (edit_count && !c->writable) {
+        c->start = hb_blob_get_data_writable (blob, NULL);
+        c->end = c->start + hb_blob_get_length (blob);
+
+        if (c->start) {
+          c->writable = true;
+          /* ok, we made it writable by relocating.  try again */
+          DEBUG_MSG_FUNC (SANITIZE, c->start, "retry");
+          goto retry;
+        }
+      }
+    }
+
+    c->end_processing ();
+
+    DEBUG_MSG_FUNC (SANITIZE, c->start, sane ? "PASSED" : "FAILED");
+    if (sane)
+      return blob;
+    else {
+      hb_blob_destroy (blob);
+      return hb_blob_get_empty ();
+    }
+  }
+
+  static const Type* lock_instance (hb_blob_t *blob) {
+    hb_blob_make_immutable (blob);
+    const char *base = hb_blob_get_data (blob, NULL);
+    return unlikely (!base) ? &Null(Type) : CastP<Type> (base);
+  }
+};
+
+
+
+/*
+ * Serialize
+ */
+
+#ifndef HB_DEBUG_SERIALIZE
+#define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
+#endif
+
+
+#define TRACE_SERIALIZE(this) \
+        hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
+        (&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
+         "");
+
+
+struct hb_serialize_context_t
+{
+  inline hb_serialize_context_t (void *start_, unsigned int size)
+  {
+    this->start = (char *) start_;
+    this->end = this->start + size;
+
+    this->ran_out_of_room = false;
+    this->head = this->start;
+    this->debug_depth = 0;
+  }
+
+  template <typename Type>
+  inline Type *start_serialize (void)
+  {
+    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
+                     "start [%p..%p] (%lu bytes)",
+                     this->start, this->end,
+                     (unsigned long) (this->end - this->start));
+
+    return start_embed<Type> ();
+  }
+
+  inline void end_serialize (void)
+  {
+    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
+                     "end [%p..%p] serialized %d bytes; %s",
+                     this->start, this->end,
+                     (int) (this->head - this->start),
+                     this->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room");
+
+  }
+
+  template <typename Type>
+  inline Type *copy (void)
+  {
+    assert (!this->ran_out_of_room);
+    unsigned int len = this->head - this->start;
+    void *p = malloc (len);
+    if (p)
+      memcpy (p, this->start, len);
+    return reinterpret_cast<Type *> (p);
+  }
+
+  template <typename Type>
+  inline Type *allocate_size (unsigned int size)
+  {
+    if (unlikely (this->ran_out_of_room || this->end - this->head < ptrdiff_t (size))) {
+      this->ran_out_of_room = true;
+      return NULL;
+    }
+    memset (this->head, 0, size);
+    char *ret = this->head;
+    this->head += size;
+    return reinterpret_cast<Type *> (ret);
+  }
+
+  template <typename Type>
+  inline Type *allocate_min (void)
+  {
+    return this->allocate_size<Type> (Type::min_size);
+  }
+
+  template <typename Type>
+  inline Type *start_embed (void)
+  {
+    Type *ret = reinterpret_cast<Type *> (this->head);
+    return ret;
+  }
+
+  template <typename Type>
+  inline Type *embed (const Type &obj)
+  {
+    unsigned int size = obj.get_size ();
+    Type *ret = this->allocate_size<Type> (size);
+    if (unlikely (!ret)) return NULL;
+    memcpy (ret, obj, size);
+    return ret;
+  }
+
+  template <typename Type>
+  inline Type *extend_min (Type &obj)
+  {
+    unsigned int size = obj.min_size;
+    assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
+    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
+    return reinterpret_cast<Type *> (&obj);
+  }
+
+  template <typename Type>
+  inline Type *extend (Type &obj)
+  {
+    unsigned int size = obj.get_size ();
+    assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
+    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
+    return reinterpret_cast<Type *> (&obj);
+  }
+
+  inline void truncate (void *new_head)
+  {
+    assert (this->start < new_head && new_head <= this->head);
+    this->head = (char *) new_head;
+  }
+
+  unsigned int debug_depth;
+  char *start, *end, *head;
+  bool ran_out_of_room;
+};
+
+template <typename Type>
+struct Supplier
+{
+  inline Supplier (const Type *array, unsigned int len_)
+  {
+    head = array;
+    len = len_;
+  }
+  inline const Type operator [] (unsigned int i) const
+  {
+    if (unlikely (i >= len)) return Type ();
+    return head[i];
+  }
+
+  inline void advance (unsigned int count)
+  {
+    if (unlikely (count > len))
+      count = len;
+    len -= count;
+    head += count;
+  }
+
+  private:
+  inline Supplier (const Supplier<Type> &); /* Disallow copy */
+  inline Supplier<Type>& operator= (const Supplier<Type> &); /* Disallow copy */
+
+  unsigned int len;
+  const Type *head;
+};
+
+
+
+
+/*
+ *
+ * The OpenType Font File: Data Types
+ */
+
+
+/* "The following data types are used in the OpenType font file.
+ *  All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
+
+/*
+ * Int types
+ */
+
+
+template <typename Type, int Bytes> struct BEInt;
+
+template <typename Type>
+struct BEInt<Type, 1>
+{
+  public:
+  inline void set (Type V)
+  {
+    v = V;
+  }
+  inline operator Type (void) const
+  {
+    return v;
+  }
+  private: uint8_t v;
+};
+template <typename Type>
+struct BEInt<Type, 2>
+{
+  public:
+  inline void set (Type V)
+  {
+    v[0] = (V >>  8) & 0xFF;
+    v[1] = (V      ) & 0xFF;
+  }
+  inline operator Type (void) const
+  {
+    return (v[0] <<  8)
+         + (v[1]      );
+  }
+  private: uint8_t v[2];
+};
+template <typename Type>
+struct BEInt<Type, 3>
+{
+  public:
+  inline void set (Type V)
+  {
+    v[0] = (V >> 16) & 0xFF;
+    v[1] = (V >>  8) & 0xFF;
+    v[2] = (V      ) & 0xFF;
+  }
+  inline operator Type (void) const
+  {
+    return (v[0] << 16)
+         + (v[1] <<  8)
+         + (v[2]      );
+  }
+  private: uint8_t v[3];
+};
+template <typename Type>
+struct BEInt<Type, 4>
+{
+  public:
+  inline void set (Type V)
+  {
+    v[0] = (V >> 24) & 0xFF;
+    v[1] = (V >> 16) & 0xFF;
+    v[2] = (V >>  8) & 0xFF;
+    v[3] = (V      ) & 0xFF;
+  }
+  inline operator Type (void) const
+  {
+    return (v[0] << 24)
+         + (v[1] << 16)
+         + (v[2] <<  8)
+         + (v[3]      );
+  }
+  private: uint8_t v[4];
+};
+
+/* Integer types in big-endian order and no alignment requirement */
+template <typename Type, unsigned int Size>
+struct IntType
+{
+  inline void set (Type i) { v.set (i); }
+  inline operator Type(void) const { return v; }
+  inline bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
+  inline bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); }
+  static inline int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); }
+  inline int cmp (Type a) const
+  {
+    Type b = v;
+    if (sizeof (Type) < sizeof (int))
+      return (int) a - (int) b;
+    else
+      return a < b ? -1 : a == b ? 0 : +1;
+  }
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this)));
+  }
+  protected:
+  BEInt<Type, Size> v;
+  public:
+  DEFINE_SIZE_STATIC (Size);
+};
+
+typedef IntType<uint8_t , 1> BYTE;      /* 8-bit unsigned integer. */
+typedef IntType<uint16_t, 2> USHORT;    /* 16-bit unsigned integer. */
+typedef IntType<int16_t,  2> SHORT;     /* 16-bit signed integer. */
+typedef IntType<uint32_t, 4> ULONG;     /* 32-bit unsigned integer. */
+typedef IntType<int32_t,  4> LONG;      /* 32-bit signed integer. */
+typedef IntType<uint32_t, 3> UINT24;    /* 24-bit unsigned integer. */
+
+/* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */
+typedef SHORT FWORD;
+
+/* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */
+typedef USHORT UFWORD;
+
+/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
+struct F2DOT14 : SHORT
+{
+  //inline float to_float (void) const { return ???; }
+  //inline void set_float (float f) { v.set (f * ???); }
+  public:
+  DEFINE_SIZE_STATIC (2);
+};
+
+/* 32-bit signed fixed-point number (16.16). */
+struct Fixed: LONG
+{
+  //inline float to_float (void) const { return ???; }
+  //inline void set_float (float f) { v.set (f * ???); }
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+/* Date represented in number of seconds since 12:00 midnight, January 1,
+ * 1904. The value is represented as a signed 64-bit integer. */
+struct LONGDATETIME
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this)));
+  }
+  protected:
+  LONG major;
+  ULONG minor;
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+/* Array of four uint8s (length = 32 bits) used to identify a script, language
+ * system, feature, or baseline */
+struct Tag : ULONG
+{
+  /* What the char* converters return is NOT nul-terminated.  Print using "%.4s" */
+  inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v); }
+  inline operator char* (void) { return reinterpret_cast<char *> (&this->v); }
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+DEFINE_NULL_DATA (Tag, "    ");
+
+/* Glyph index number, same as uint16 (length = 16 bits) */
+struct GlyphID : USHORT {
+  static inline int cmp (const GlyphID *a, const GlyphID *b) { return b->USHORT::cmp (*a); }
+  inline int cmp (hb_codepoint_t a) const { return (int) a - (int) *this; }
+};
+
+/* Script/language-system/feature index */
+struct Index : USHORT {
+  static const unsigned int NOT_FOUND_INDEX = 0xFFFFu;
+};
+DEFINE_NULL_DATA (Index, "\xff\xff");
+
+/* Offset, Null offset = 0 */
+template <typename Type=USHORT>
+struct Offset : Type
+{
+  inline bool is_null (void) const { return 0 == *this; }
+  public:
+  DEFINE_SIZE_STATIC (sizeof(Type));
+};
+
+
+/* CheckSum */
+struct CheckSum : ULONG
+{
+  /* This is reference implementation from the spec. */
+  static inline uint32_t CalcTableChecksum (const ULONG *Table, uint32_t Length)
+  {
+    uint32_t Sum = 0L;
+    const ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size;
+
+    while (Table < EndPtr)
+      Sum += *Table++;
+    return Sum;
+  }
+
+  /* Note: data should be 4byte aligned and have 4byte padding at the end. */
+  inline void set_for_data (const void *data, unsigned int length)
+  { set (CalcTableChecksum ((const ULONG *) data, length)); }
+
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+
+/*
+ * Version Numbers
+ */
+
+template <typename FixedType=USHORT>
+struct FixedVersion
+{
+  inline uint32_t to_int (void) const { return (major << (sizeof(FixedType) * 8)) + minor; }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  FixedType major;
+  FixedType minor;
+  public:
+  DEFINE_SIZE_STATIC (2 * sizeof(FixedType));
+};
+
+
+
+/*
+ * Template subclasses of Offset that do the dereferencing.
+ * Use: (base+offset)
+ */
+
+template <typename Type, typename OffsetType=USHORT>
+struct OffsetTo : Offset<OffsetType>
+{
+  inline const Type& operator () (const void *base) const
+  {
+    unsigned int offset = *this;
+    if (unlikely (!offset)) return Null(Type);
+    return StructAtOffset<Type> (base, offset);
+  }
+
+  inline Type& serialize (hb_serialize_context_t *c, const void *base)
+  {
+    Type *t = c->start_embed<Type> ();
+    this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
+    return *t;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this))) return_trace (false);
+    unsigned int offset = *this;
+    if (unlikely (!offset)) return_trace (true);
+    const Type &obj = StructAtOffset<Type> (base, offset);
+    return_trace (likely (obj.sanitize (c)) || neuter (c));
+  }
+  template <typename T>
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this))) return_trace (false);
+    unsigned int offset = *this;
+    if (unlikely (!offset)) return_trace (true);
+    const Type &obj = StructAtOffset<Type> (base, offset);
+    return_trace (likely (obj.sanitize (c, user_data)) || neuter (c));
+  }
+
+  /* Set the offset to Null */
+  inline bool neuter (hb_sanitize_context_t *c) const {
+    return c->try_set (this, 0);
+  }
+  DEFINE_SIZE_STATIC (sizeof(OffsetType));
+};
+template <typename Base, typename OffsetType, typename Type>
+static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType> &offset) { return offset (base); }
+template <typename Base, typename OffsetType, typename Type>
+static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType> &offset) { return offset (base); }
+
+
+/*
+ * Array Types
+ */
+
+/* An array with a number of elements. */
+template <typename Type, typename LenType=USHORT>
+struct ArrayOf
+{
+  const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
+  {
+    unsigned int count = len;
+    if (unlikely (start_offset > count))
+      count = 0;
+    else
+      count -= start_offset;
+    count = MIN (count, *pcount);
+    *pcount = count;
+    return array + start_offset;
+  }
+
+  inline const Type& operator [] (unsigned int i) const
+  {
+    if (unlikely (i >= len)) return Null(Type);
+    return array[i];
+  }
+  inline Type& operator [] (unsigned int i)
+  {
+    return array[i];
+  }
+  inline unsigned int get_size (void) const
+  { return len.static_size + len * Type::static_size; }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                         unsigned int items_len)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    len.set (items_len); /* TODO(serialize) Overflow? */
+    if (unlikely (!c->extend (*this))) return_trace (false);
+    return_trace (true);
+  }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                         Supplier<Type> &items,
+                         unsigned int items_len)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!serialize (c, items_len))) return_trace (false);
+    for (unsigned int i = 0; i < items_len; i++)
+      array[i] = items[i];
+    items.advance (items_len);
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!sanitize_shallow (c))) return_trace (false);
+
+    /* Note: for structs that do not reference other structs,
+     * we do not need to call their sanitize() as we already did
+     * a bound check on the aggregate array size.  We just include
+     * a small unreachable expression to make sure the structs
+     * pointed to do have a simple sanitize(), ie. they do not
+     * reference other structs via offsets.
+     */
+    (void) (false && array[0].sanitize (c));
+
+    return_trace (true);
+  }
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!sanitize_shallow (c))) return_trace (false);
+    unsigned int count = len;
+    for (unsigned int i = 0; i < count; i++)
+      if (unlikely (!array[i].sanitize (c, base)))
+        return_trace (false);
+    return_trace (true);
+  }
+  template <typename T>
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!sanitize_shallow (c))) return_trace (false);
+    unsigned int count = len;
+    for (unsigned int i = 0; i < count; i++)
+      if (unlikely (!array[i].sanitize (c, base, user_data)))
+        return_trace (false);
+    return_trace (true);
+  }
+
+  template <typename SearchType>
+  inline int lsearch (const SearchType &x) const
+  {
+    unsigned int count = len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!this->array[i].cmp (x))
+        return i;
+    return -1;
+  }
+
+  private:
+  inline bool sanitize_shallow (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && c->check_array (array, Type::static_size, len));
+  }
+
+  public:
+  LenType len;
+  Type array[VAR];
+  public:
+  DEFINE_SIZE_ARRAY (sizeof (LenType), array);
+};
+
+/* Array of Offset's */
+template <typename Type>
+struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
+
+/* Array of offsets relative to the beginning of the array itself. */
+template <typename Type>
+struct OffsetListOf : OffsetArrayOf<Type>
+{
+  inline const Type& operator [] (unsigned int i) const
+  {
+    if (unlikely (i >= this->len)) return Null(Type);
+    return this+this->array[i];
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (OffsetArrayOf<Type>::sanitize (c, this));
+  }
+  template <typename T>
+  inline bool sanitize (hb_sanitize_context_t *c, T user_data) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (OffsetArrayOf<Type>::sanitize (c, this, user_data));
+  }
+};
+
+
+/* An array starting at second element. */
+template <typename Type, typename LenType=USHORT>
+struct HeadlessArrayOf
+{
+  inline const Type& operator [] (unsigned int i) const
+  {
+    if (unlikely (i >= len || !i)) return Null(Type);
+    return array[i-1];
+  }
+  inline unsigned int get_size (void) const
+  { return len.static_size + (len ? len - 1 : 0) * Type::static_size; }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                         Supplier<Type> &items,
+                         unsigned int items_len)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    len.set (items_len); /* TODO(serialize) Overflow? */
+    if (unlikely (!items_len)) return_trace (true);
+    if (unlikely (!c->extend (*this))) return_trace (false);
+    for (unsigned int i = 0; i < items_len - 1; i++)
+      array[i] = items[i];
+    items.advance (items_len - 1);
+    return_trace (true);
+  }
+
+  inline bool sanitize_shallow (hb_sanitize_context_t *c) const
+  {
+    return c->check_struct (this)
+        && c->check_array (this, Type::static_size, len);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!sanitize_shallow (c))) return_trace (false);
+
+    /* Note: for structs that do not reference other structs,
+     * we do not need to call their sanitize() as we already did
+     * a bound check on the aggregate array size.  We just include
+     * a small unreachable expression to make sure the structs
+     * pointed to do have a simple sanitize(), ie. they do not
+     * reference other structs via offsets.
+     */
+    (void) (false && array[0].sanitize (c));
+
+    return_trace (true);
+  }
+
+  LenType len;
+  Type array[VAR];
+  public:
+  DEFINE_SIZE_ARRAY (sizeof (LenType), array);
+};
+
+
+/* An array with sorted elements.  Supports binary searching. */
+template <typename Type, typename LenType=USHORT>
+struct SortedArrayOf : ArrayOf<Type, LenType>
+{
+  template <typename SearchType>
+  inline int bsearch (const SearchType &x) const
+  {
+    /* Hand-coded bsearch here since this is in the hot inner loop. */
+    int min = 0, max = (int) this->len - 1;
+    while (min <= max)
+    {
+      int mid = (min + max) / 2;
+      int c = this->array[mid].cmp (x);
+      if (c < 0)
+        max = mid - 1;
+      else if (c > 0)
+        min = mid + 1;
+      else
+        return mid;
+    }
+    return -1;
+  }
+};
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OPEN_TYPE_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-cmap-table.hh b/src/share/native/sun/font/harfbuzz/hb-ot-cmap-table.hh
new file mode 100644
index 0000000..7827c09
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-cmap-table.hh
@@ -0,0 +1,535 @@
+/*
+ * Copyright © 2014  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_OT_CMAP_TABLE_HH
+#define HB_OT_CMAP_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+
+namespace OT {
+
+
+/*
+ * cmap -- Character To Glyph Index Mapping Table
+ */
+
+#define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
+
+
+struct CmapSubtableFormat0
+{
+  inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+  {
+    hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0;
+    if (!gid)
+      return false;
+    *glyph = gid;
+    return true;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  USHORT        format;         /* Format number is set to 0. */
+  USHORT        lengthZ;        /* Byte length of this subtable. */
+  USHORT        languageZ;      /* Ignore. */
+  BYTE          glyphIdArray[256];/* An array that maps character
+                                 * code to glyph index values. */
+  public:
+  DEFINE_SIZE_STATIC (6 + 256);
+};
+
+struct CmapSubtableFormat4
+{
+  struct accelerator_t
+  {
+    inline void init (const CmapSubtableFormat4 *subtable)
+    {
+      segCount = subtable->segCountX2 / 2;
+      endCount = subtable->values;
+      startCount = endCount + segCount + 1;
+      idDelta = startCount + segCount;
+      idRangeOffset = idDelta + segCount;
+      glyphIdArray = idRangeOffset + segCount;
+      glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2;
+    }
+
+    static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
+    {
+      const accelerator_t *thiz = (const accelerator_t *) obj;
+
+      /* Custom two-array bsearch. */
+      int min = 0, max = (int) thiz->segCount - 1;
+      const USHORT *startCount = thiz->startCount;
+      const USHORT *endCount = thiz->endCount;
+      unsigned int i;
+      while (min <= max)
+      {
+        int mid = (min + max) / 2;
+        if (codepoint < startCount[mid])
+          max = mid - 1;
+        else if (codepoint > endCount[mid])
+          min = mid + 1;
+        else
+        {
+          i = mid;
+          goto found;
+        }
+      }
+      return false;
+
+    found:
+      hb_codepoint_t gid;
+      unsigned int rangeOffset = thiz->idRangeOffset[i];
+      if (rangeOffset == 0)
+        gid = codepoint + thiz->idDelta[i];
+      else
+      {
+        /* Somebody has been smoking... */
+        unsigned int index = rangeOffset / 2 + (codepoint - thiz->startCount[i]) + i - thiz->segCount;
+        if (unlikely (index >= thiz->glyphIdArrayLength))
+          return false;
+        gid = thiz->glyphIdArray[index];
+        if (unlikely (!gid))
+          return false;
+        gid += thiz->idDelta[i];
+      }
+
+      *glyph = gid & 0xFFFFu;
+      return true;
+    }
+
+    const USHORT *endCount;
+    const USHORT *startCount;
+    const USHORT *idDelta;
+    const USHORT *idRangeOffset;
+    const USHORT *glyphIdArray;
+    unsigned int segCount;
+    unsigned int glyphIdArrayLength;
+  };
+
+  inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+  {
+    accelerator_t accel;
+    accel.init (this);
+    return accel.get_glyph_func (&accel, codepoint, glyph);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this)))
+      return_trace (false);
+
+    if (unlikely (!c->check_range (this, length)))
+    {
+      /* Some broken fonts have too long of a "length" value.
+       * If that is the case, just change the value to truncate
+       * the subtable at the end of the blob. */
+      uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535,
+                                            (uintptr_t) (c->end -
+                                                         (char *) this));
+      if (!c->try_set (&length, new_length))
+        return_trace (false);
+    }
+
+    return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
+  }
+
+  protected:
+  USHORT        format;         /* Format number is set to 4. */
+  USHORT        length;         /* This is the length in bytes of the
+                                 * subtable. */
+  USHORT        languageZ;      /* Ignore. */
+  USHORT        segCountX2;     /* 2 x segCount. */
+  USHORT        searchRangeZ;   /* 2 * (2**floor(log2(segCount))) */
+  USHORT        entrySelectorZ; /* log2(searchRange/2) */
+  USHORT        rangeShiftZ;    /* 2 x segCount - searchRange */
+
+  USHORT        values[VAR];
+#if 0
+  USHORT        endCount[segCount];     /* End characterCode for each segment,
+                                         * last=0xFFFFu. */
+  USHORT        reservedPad;            /* Set to 0. */
+  USHORT        startCount[segCount];   /* Start character code for each segment. */
+  SHORT         idDelta[segCount];      /* Delta for all character codes in segment. */
+  USHORT        idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
+  USHORT        glyphIdArray[VAR];      /* Glyph index array (arbitrary length) */
+#endif
+
+  public:
+  DEFINE_SIZE_ARRAY (14, values);
+};
+
+struct CmapSubtableLongGroup
+{
+  friend struct CmapSubtableFormat12;
+  friend struct CmapSubtableFormat13;
+
+  int cmp (hb_codepoint_t codepoint) const
+  {
+    if (codepoint < startCharCode) return -1;
+    if (codepoint > endCharCode)   return +1;
+    return 0;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  private:
+  ULONG         startCharCode;  /* First character code in this group. */
+  ULONG         endCharCode;    /* Last character code in this group. */
+  ULONG         glyphID;        /* Glyph index; interpretation depends on
+                                 * subtable format. */
+  public:
+  DEFINE_SIZE_STATIC (12);
+};
+
+template <typename UINT>
+struct CmapSubtableTrimmed
+{
+  inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+  {
+    /* Rely on our implicit array bound-checking. */
+    hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
+    if (!gid)
+      return false;
+    *glyph = gid;
+    return true;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && glyphIdArray.sanitize (c));
+  }
+
+  protected:
+  UINT          formatReserved; /* Subtable format and (maybe) padding. */
+  UINT          lengthZ;        /* Byte length of this subtable. */
+  UINT          languageZ;      /* Ignore. */
+  UINT          startCharCode;  /* First character code covered. */
+  ArrayOf<GlyphID, UINT>
+                glyphIdArray;   /* Array of glyph index values for character
+                                 * codes in the range. */
+  public:
+  DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
+};
+
+struct CmapSubtableFormat6  : CmapSubtableTrimmed<USHORT> {};
+struct CmapSubtableFormat10 : CmapSubtableTrimmed<ULONG > {};
+
+template <typename T>
+struct CmapSubtableLongSegmented
+{
+  inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+  {
+    int i = groups.bsearch (codepoint);
+    if (i == -1)
+      return false;
+    *glyph = T::group_get_glyph (groups[i], codepoint);
+    return true;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && groups.sanitize (c));
+  }
+
+  protected:
+  USHORT        format;         /* Subtable format; set to 12. */
+  USHORT        reservedZ;      /* Reserved; set to 0. */
+  ULONG         lengthZ;        /* Byte length of this subtable. */
+  ULONG         languageZ;      /* Ignore. */
+  SortedArrayOf<CmapSubtableLongGroup, ULONG>
+                groups;         /* Groupings. */
+  public:
+  DEFINE_SIZE_ARRAY (16, groups);
+};
+
+struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
+{
+  static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
+                                                hb_codepoint_t u)
+  { return group.glyphID + (u - group.startCharCode); }
+};
+
+struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
+{
+  static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
+                                                hb_codepoint_t u HB_UNUSED)
+  { return group.glyphID; }
+};
+
+typedef enum
+{
+  GLYPH_VARIANT_NOT_FOUND = 0,
+  GLYPH_VARIANT_FOUND = 1,
+  GLYPH_VARIANT_USE_DEFAULT = 2
+} glyph_variant_t;
+
+struct UnicodeValueRange
+{
+  inline int cmp (const hb_codepoint_t &codepoint) const
+  {
+    if (codepoint < startUnicodeValue) return -1;
+    if (codepoint > startUnicodeValue + additionalCount) return +1;
+    return 0;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  UINT24        startUnicodeValue;      /* First value in this range. */
+  BYTE          additionalCount;        /* Number of additional values in this
+                                         * range. */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+typedef SortedArrayOf<UnicodeValueRange, ULONG> DefaultUVS;
+
+struct UVSMapping
+{
+  inline int cmp (const hb_codepoint_t &codepoint) const
+  {
+    return unicodeValue.cmp (codepoint);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  UINT24        unicodeValue;   /* Base Unicode value of the UVS */
+  GlyphID       glyphID;        /* Glyph ID of the UVS */
+  public:
+  DEFINE_SIZE_STATIC (5);
+};
+
+typedef SortedArrayOf<UVSMapping, ULONG> NonDefaultUVS;
+
+struct VariationSelectorRecord
+{
+  inline glyph_variant_t get_glyph (hb_codepoint_t codepoint,
+                                    hb_codepoint_t *glyph,
+                                    const void *base) const
+  {
+    int i;
+    const DefaultUVS &defaults = base+defaultUVS;
+    i = defaults.bsearch (codepoint);
+    if (i != -1)
+      return GLYPH_VARIANT_USE_DEFAULT;
+    const NonDefaultUVS &nonDefaults = base+nonDefaultUVS;
+    i = nonDefaults.bsearch (codepoint);
+    if (i != -1)
+    {
+      *glyph = nonDefaults[i].glyphID;
+       return GLYPH_VARIANT_FOUND;
+    }
+    return GLYPH_VARIANT_NOT_FOUND;
+  }
+
+  inline int cmp (const hb_codepoint_t &variation_selector) const
+  {
+    return varSelector.cmp (variation_selector);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  defaultUVS.sanitize (c, base) &&
+                  nonDefaultUVS.sanitize (c, base));
+  }
+
+  UINT24        varSelector;    /* Variation selector. */
+  OffsetTo<DefaultUVS, ULONG>
+                defaultUVS;     /* Offset to Default UVS Table. May be 0. */
+  OffsetTo<NonDefaultUVS, ULONG>
+                nonDefaultUVS;  /* Offset to Non-Default UVS Table. May be 0. */
+  public:
+  DEFINE_SIZE_STATIC (11);
+};
+
+struct CmapSubtableFormat14
+{
+  inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
+                                            hb_codepoint_t variation_selector,
+                                            hb_codepoint_t *glyph) const
+  {
+    return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  record.sanitize (c, this));
+  }
+
+  protected:
+  USHORT        format;         /* Format number is set to 14. */
+  ULONG         lengthZ;        /* Byte length of this subtable. */
+  SortedArrayOf<VariationSelectorRecord, ULONG>
+                record;         /* Variation selector records; sorted
+                                 * in increasing order of `varSelector'. */
+  public:
+  DEFINE_SIZE_ARRAY (10, record);
+};
+
+struct CmapSubtable
+{
+  /* Note: We intentionally do NOT implement subtable formats 2 and 8. */
+
+  inline bool get_glyph (hb_codepoint_t codepoint,
+                         hb_codepoint_t *glyph) const
+  {
+    switch (u.format) {
+    case  0: return u.format0 .get_glyph(codepoint, glyph);
+    case  4: return u.format4 .get_glyph(codepoint, glyph);
+    case  6: return u.format6 .get_glyph(codepoint, glyph);
+    case 10: return u.format10.get_glyph(codepoint, glyph);
+    case 12: return u.format12.get_glyph(codepoint, glyph);
+    case 13: return u.format13.get_glyph(codepoint, glyph);
+    case 14:
+    default: return false;
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.format.sanitize (c)) return_trace (false);
+    switch (u.format) {
+    case  0: return_trace (u.format0 .sanitize (c));
+    case  4: return_trace (u.format4 .sanitize (c));
+    case  6: return_trace (u.format6 .sanitize (c));
+    case 10: return_trace (u.format10.sanitize (c));
+    case 12: return_trace (u.format12.sanitize (c));
+    case 13: return_trace (u.format13.sanitize (c));
+    case 14: return_trace (u.format14.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  public:
+  union {
+  USHORT                format;         /* Format identifier */
+  CmapSubtableFormat0   format0;
+  CmapSubtableFormat4   format4;
+  CmapSubtableFormat6   format6;
+  CmapSubtableFormat10  format10;
+  CmapSubtableFormat12  format12;
+  CmapSubtableFormat13  format13;
+  CmapSubtableFormat14  format14;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+};
+
+
+struct EncodingRecord
+{
+  inline int cmp (const EncodingRecord &other) const
+  {
+    int ret;
+    ret = platformID.cmp (other.platformID);
+    if (ret) return ret;
+    ret = encodingID.cmp (other.encodingID);
+    if (ret) return ret;
+    return 0;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  subtable.sanitize (c, base));
+  }
+
+  USHORT        platformID;     /* Platform ID. */
+  USHORT        encodingID;     /* Platform-specific encoding ID. */
+  OffsetTo<CmapSubtable, ULONG>
+                subtable;       /* Byte offset from beginning of table to the subtable for this encoding. */
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+struct cmap
+{
+  static const hb_tag_t tableTag        = HB_OT_TAG_cmap;
+
+  inline const CmapSubtable *find_subtable (unsigned int platform_id,
+                                            unsigned int encoding_id) const
+  {
+    EncodingRecord key;
+    key.platformID.set (platform_id);
+    key.encodingID.set (encoding_id);
+
+    /* Note: We can use bsearch, but since it has no performance
+     * implications, we use lsearch and as such accept fonts with
+     * unsorted subtable list. */
+    int result = encodingRecord./*bsearch*/lsearch (key);
+    if (result == -1 || !encodingRecord[result].subtable)
+      return NULL;
+
+    return &(this+encodingRecord[result].subtable);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  likely (version == 0) &&
+                  encodingRecord.sanitize (c, this));
+  }
+
+  USHORT                version;        /* Table version number (0). */
+  SortedArrayOf<EncodingRecord>
+                        encodingRecord; /* Encoding tables. */
+  public:
+  DEFINE_SIZE_ARRAY (4, encodingRecord);
+};
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_CMAP_TABLE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-font.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-font.cpp
new file mode 100644
index 0000000..3c63f33
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-font.cpp
@@ -0,0 +1,561 @@
+/*
+ * Copyright © 2011,2014  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, Roozbeh Pournader
+ */
+
+#include "hb-private.hh"
+
+#include "hb-ot.h"
+
+#include "hb-font-private.hh"
+
+#include "hb-ot-cmap-table.hh"
+#include "hb-ot-glyf-table.hh"
+#include "hb-ot-head-table.hh"
+#include "hb-ot-hhea-table.hh"
+#include "hb-ot-hmtx-table.hh"
+#include "hb-ot-os2-table.hh"
+//#include "hb-ot-post-table.hh"
+
+
+struct hb_ot_face_metrics_accelerator_t
+{
+  unsigned int num_metrics;
+  unsigned int num_advances;
+  unsigned int default_advance;
+  unsigned short ascender;
+  unsigned short descender;
+  unsigned short line_gap;
+
+  const OT::_mtx *table;
+  hb_blob_t *blob;
+
+  inline void init (hb_face_t *face,
+                    hb_tag_t _hea_tag,
+                    hb_tag_t _mtx_tag,
+                    hb_tag_t os2_tag)
+  {
+    this->default_advance = face->get_upem ();
+
+    bool got_font_extents = false;
+    if (os2_tag)
+    {
+      hb_blob_t *os2_blob = OT::Sanitizer<OT::os2>::sanitize (face->reference_table (os2_tag));
+      const OT::os2 *os2 = OT::Sanitizer<OT::os2>::lock_instance (os2_blob);
+#define USE_TYPO_METRICS (1u<<7)
+      if (0 != (os2->fsSelection & USE_TYPO_METRICS))
+      {
+        this->ascender = os2->sTypoAscender;
+        this->descender = os2->sTypoDescender;
+        this->line_gap = os2->sTypoLineGap;
+        got_font_extents = (this->ascender | this->descender) != 0;
+      }
+      hb_blob_destroy (os2_blob);
+    }
+
+    hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag));
+    const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob);
+    this->num_advances = _hea->numberOfLongMetrics;
+    if (!got_font_extents)
+    {
+      this->ascender = _hea->ascender;
+      this->descender = _hea->descender;
+      this->line_gap = _hea->lineGap;
+    }
+    hb_blob_destroy (_hea_blob);
+
+    this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag));
+
+    /* Cap num_metrics() and num_advances() based on table length. */
+    unsigned int len = hb_blob_get_length (this->blob);
+    if (unlikely (this->num_advances * 4 > len))
+      this->num_advances = len / 4;
+    this->num_metrics = this->num_advances + (len - 4 * this->num_advances) / 2;
+
+    /* We MUST set num_metrics to zero if num_advances is zero.
+     * Our get_advance() depends on that. */
+    if (unlikely (!this->num_advances))
+    {
+      this->num_metrics = this->num_advances = 0;
+      hb_blob_destroy (this->blob);
+      this->blob = hb_blob_get_empty ();
+    }
+    this->table = OT::Sanitizer<OT::_mtx>::lock_instance (this->blob);
+  }
+
+  inline void fini (void)
+  {
+    hb_blob_destroy (this->blob);
+  }
+
+  inline unsigned int get_advance (hb_codepoint_t glyph) const
+  {
+    if (unlikely (glyph >= this->num_metrics))
+    {
+      /* If this->num_metrics is zero, it means we don't have the metrics table
+       * for this direction: return default advance.  Otherwise, it means that the
+       * glyph index is out of bound: return zero. */
+      if (this->num_metrics)
+        return 0;
+      else
+        return this->default_advance;
+    }
+
+    if (glyph >= this->num_advances)
+      glyph = this->num_advances - 1;
+
+    return this->table->longMetric[glyph].advance;
+  }
+};
+
+struct hb_ot_face_glyf_accelerator_t
+{
+  bool short_offset;
+  unsigned int num_glyphs;
+  const OT::loca *loca;
+  const OT::glyf *glyf;
+  hb_blob_t *loca_blob;
+  hb_blob_t *glyf_blob;
+  unsigned int glyf_len;
+
+  inline void init (hb_face_t *face)
+  {
+    hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (face->reference_table (HB_OT_TAG_head));
+    const OT::head *head = OT::Sanitizer<OT::head>::lock_instance (head_blob);
+    if ((unsigned int) head->indexToLocFormat > 1 || head->glyphDataFormat != 0)
+    {
+      /* Unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
+      hb_blob_destroy (head_blob);
+      return;
+    }
+    this->short_offset = 0 == head->indexToLocFormat;
+    hb_blob_destroy (head_blob);
+
+    this->loca_blob = OT::Sanitizer<OT::loca>::sanitize (face->reference_table (HB_OT_TAG_loca));
+    this->loca = OT::Sanitizer<OT::loca>::lock_instance (this->loca_blob);
+    this->glyf_blob = OT::Sanitizer<OT::glyf>::sanitize (face->reference_table (HB_OT_TAG_glyf));
+    this->glyf = OT::Sanitizer<OT::glyf>::lock_instance (this->glyf_blob);
+
+    this->num_glyphs = MAX (1u, hb_blob_get_length (this->loca_blob) / (this->short_offset ? 2 : 4)) - 1;
+    this->glyf_len = hb_blob_get_length (this->glyf_blob);
+  }
+
+  inline void fini (void)
+  {
+    hb_blob_destroy (this->loca_blob);
+    hb_blob_destroy (this->glyf_blob);
+  }
+
+  inline bool get_extents (hb_codepoint_t glyph,
+                           hb_glyph_extents_t *extents) const
+  {
+    if (unlikely (glyph >= this->num_glyphs))
+      return false;
+
+    unsigned int start_offset, end_offset;
+    if (this->short_offset)
+    {
+      start_offset = 2 * this->loca->u.shortsZ[glyph];
+      end_offset   = 2 * this->loca->u.shortsZ[glyph + 1];
+    }
+    else
+    {
+      start_offset = this->loca->u.longsZ[glyph];
+      end_offset   = this->loca->u.longsZ[glyph + 1];
+    }
+
+    if (start_offset > end_offset || end_offset > this->glyf_len)
+      return false;
+
+    if (end_offset - start_offset < OT::glyfGlyphHeader::static_size)
+      return true; /* Empty glyph; zero extents. */
+
+    const OT::glyfGlyphHeader &glyph_header = OT::StructAtOffset<OT::glyfGlyphHeader> (this->glyf, start_offset);
+
+    extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax);
+    extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax);
+    extents->width     = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing;
+    extents->height    = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing;
+
+    return true;
+  }
+};
+
+typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
+                                          hb_codepoint_t codepoint,
+                                          hb_codepoint_t *glyph);
+
+template <typename Type>
+static inline bool get_glyph_from (const void *obj,
+                                   hb_codepoint_t codepoint,
+                                   hb_codepoint_t *glyph)
+{
+  const Type *typed_obj = (const Type *) obj;
+  return typed_obj->get_glyph (codepoint, glyph);
+}
+
+template <typename Type>
+static inline bool get_glyph_from_symbol (const void *obj,
+                                          hb_codepoint_t codepoint,
+                                          hb_codepoint_t *glyph)
+{
+  const Type *typed_obj = (const Type *) obj;
+  if (likely (typed_obj->get_glyph (codepoint, glyph)))
+    return true;
+
+  if (codepoint <= 0x00FFu)
+  {
+    /* For symbol-encoded OpenType fonts, we duplicate the
+     * U+F000..F0FF range at U+0000..U+00FF.  That's what
+     * Windows seems to do, and that's hinted about at:
+     * http://www.microsoft.com/typography/otspec/recom.htm
+     * under "Non-Standard (Symbol) Fonts". */
+    return typed_obj->get_glyph (0xF000u + codepoint, glyph);
+  }
+
+  return false;
+}
+
+struct hb_ot_face_cmap_accelerator_t
+{
+  hb_cmap_get_glyph_func_t get_glyph_func;
+  const void *get_glyph_data;
+  OT::CmapSubtableFormat4::accelerator_t format4_accel;
+
+  const OT::CmapSubtableFormat14 *uvs_table;
+  hb_blob_t *blob;
+
+  inline void init (hb_face_t *face)
+  {
+    this->blob = OT::Sanitizer<OT::cmap>::sanitize (face->reference_table (HB_OT_TAG_cmap));
+    const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob);
+    const OT::CmapSubtable *subtable = NULL;
+    const OT::CmapSubtableFormat14 *subtable_uvs = NULL;
+
+    bool symbol = false;
+    /* 32-bit subtables. */
+    if (!subtable) subtable = cmap->find_subtable (3, 10);
+    if (!subtable) subtable = cmap->find_subtable (0, 6);
+    if (!subtable) subtable = cmap->find_subtable (0, 4);
+    /* 16-bit subtables. */
+    if (!subtable) subtable = cmap->find_subtable (3, 1);
+    if (!subtable) subtable = cmap->find_subtable (0, 3);
+    if (!subtable) subtable = cmap->find_subtable (0, 2);
+    if (!subtable) subtable = cmap->find_subtable (0, 1);
+    if (!subtable) subtable = cmap->find_subtable (0, 0);
+    if (!subtable)(subtable = cmap->find_subtable (3, 0)) && (symbol = true);
+    /* Meh. */
+    if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
+
+    /* UVS subtable. */
+    if (!subtable_uvs)
+    {
+      const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
+      if (st && st->u.format == 14)
+        subtable_uvs = &st->u.format14;
+    }
+    /* Meh. */
+    if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtableFormat14);
+
+    this->uvs_table = subtable_uvs;
+
+    this->get_glyph_data = subtable;
+    if (unlikely (symbol))
+      this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
+    else
+      switch (subtable->u.format) {
+      /* Accelerate format 4 and format 12. */
+      default: this->get_glyph_func = get_glyph_from<OT::CmapSubtable>;         break;
+      case 12: this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>; break;
+      case  4:
+        {
+          this->format4_accel.init (&subtable->u.format4);
+          this->get_glyph_data = &this->format4_accel;
+          this->get_glyph_func = this->format4_accel.get_glyph_func;
+        }
+        break;
+      }
+  }
+
+  inline void fini (void)
+  {
+    hb_blob_destroy (this->blob);
+  }
+
+  inline bool get_nominal_glyph (hb_codepoint_t  unicode,
+                                 hb_codepoint_t *glyph) const
+  {
+    return this->get_glyph_func (this->get_glyph_data, unicode, glyph);
+  }
+
+  inline bool get_variation_glyph (hb_codepoint_t  unicode,
+                                   hb_codepoint_t  variation_selector,
+                                   hb_codepoint_t *glyph) const
+  {
+    switch (this->uvs_table->get_glyph_variant (unicode,
+                                                variation_selector,
+                                                glyph))
+    {
+      case OT::GLYPH_VARIANT_NOT_FOUND:         return false;
+      case OT::GLYPH_VARIANT_FOUND:             return true;
+      case OT::GLYPH_VARIANT_USE_DEFAULT:       break;
+    }
+
+    return get_nominal_glyph (unicode, glyph);
+  }
+};
+
+template <typename T>
+struct hb_lazy_loader_t
+{
+  inline void init (hb_face_t *face_)
+  {
+    face = face_;
+    instance = NULL;
+  }
+
+  inline void fini (void)
+  {
+    if (instance && instance != &OT::Null(T))
+    {
+      instance->fini();
+      free (instance);
+    }
+  }
+
+  inline const T* operator-> (void) const
+  {
+  retry:
+    T *p = (T *) hb_atomic_ptr_get (&instance);
+    if (unlikely (!p))
+    {
+      p = (T *) calloc (1, sizeof (T));
+      if (unlikely (!p))
+        return &OT::Null(T);
+      p->init (face);
+      if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), NULL, p)))
+      {
+        p->fini ();
+        goto retry;
+      }
+    }
+    return p;
+  }
+
+  private:
+  hb_face_t *face;
+  T *instance;
+};
+
+struct hb_ot_font_t
+{
+  hb_ot_face_cmap_accelerator_t cmap;
+  hb_ot_face_metrics_accelerator_t h_metrics;
+  hb_ot_face_metrics_accelerator_t v_metrics;
+  hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf;
+};
+
+
+static hb_ot_font_t *
+_hb_ot_font_create (hb_face_t *face)
+{
+  hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));
+
+  if (unlikely (!ot_font))
+    return NULL;
+
+  ot_font->cmap.init (face);
+  ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_os2);
+  ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_TAG_NONE); /* TODO Can we do this lazily? */
+  ot_font->glyf.init (face);
+
+  return ot_font;
+}
+
+static void
+_hb_ot_font_destroy (hb_ot_font_t *ot_font)
+{
+  ot_font->cmap.fini ();
+  ot_font->h_metrics.fini ();
+  ot_font->v_metrics.fini ();
+  ot_font->glyf.fini ();
+
+  free (ot_font);
+}
+
+
+static hb_bool_t
+hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
+                         void *font_data,
+                         hb_codepoint_t unicode,
+                         hb_codepoint_t *glyph,
+                         void *user_data HB_UNUSED)
+
+{
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  return ot_font->cmap.get_nominal_glyph (unicode, glyph);
+}
+
+static hb_bool_t
+hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED,
+                           void *font_data,
+                           hb_codepoint_t unicode,
+                           hb_codepoint_t variation_selector,
+                           hb_codepoint_t *glyph,
+                           void *user_data HB_UNUSED)
+{
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  return ot_font->cmap.get_variation_glyph (unicode, variation_selector, glyph);
+}
+
+static hb_position_t
+hb_ot_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
+                           void *font_data,
+                           hb_codepoint_t glyph,
+                           void *user_data HB_UNUSED)
+{
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  return font->em_scale_x (ot_font->h_metrics.get_advance (glyph));
+}
+
+static hb_position_t
+hb_ot_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
+                           void *font_data,
+                           hb_codepoint_t glyph,
+                           void *user_data HB_UNUSED)
+{
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph));
+}
+
+static hb_bool_t
+hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
+                         void *font_data,
+                         hb_codepoint_t glyph,
+                         hb_glyph_extents_t *extents,
+                         void *user_data HB_UNUSED)
+{
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  bool ret = ot_font->glyf->get_extents (glyph, extents);
+  extents->x_bearing = font->em_scale_x (extents->x_bearing);
+  extents->y_bearing = font->em_scale_y (extents->y_bearing);
+  extents->width     = font->em_scale_x (extents->width);
+  extents->height    = font->em_scale_y (extents->height);
+  return ret;
+}
+
+static hb_bool_t
+hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED,
+                          void *font_data,
+                          hb_font_extents_t *metrics,
+                          void *user_data HB_UNUSED)
+{
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender);
+  metrics->descender = font->em_scale_y (ot_font->h_metrics.descender);
+  metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap);
+  return true;
+}
+
+static hb_bool_t
+hb_ot_get_font_v_extents (hb_font_t *font HB_UNUSED,
+                          void *font_data,
+                          hb_font_extents_t *metrics,
+                          void *user_data HB_UNUSED)
+{
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender);
+  metrics->descender = font->em_scale_x (ot_font->v_metrics.descender);
+  metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap);
+  return true;
+}
+
+static hb_font_funcs_t *static_ot_funcs = NULL;
+
+#ifdef HB_USE_ATEXIT
+static
+void free_static_ot_funcs (void)
+{
+  hb_font_funcs_destroy (static_ot_funcs);
+}
+#endif
+
+static hb_font_funcs_t *
+_hb_ot_get_font_funcs (void)
+{
+retry:
+  hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
+
+  if (unlikely (!funcs))
+  {
+    funcs = hb_font_funcs_create ();
+
+    hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, NULL, NULL);
+    hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, NULL, NULL);
+    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, NULL, NULL);
+    hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, NULL, NULL);
+    hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, NULL, NULL);
+    hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, NULL, NULL);
+    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, NULL, NULL);
+    //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, NULL, NULL);
+    //hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, NULL, NULL); TODO
+    //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, NULL, NULL);
+    hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, NULL, NULL);
+    //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, NULL, NULL); TODO
+    //hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, NULL, NULL); TODO
+    //hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, NULL, NULL); TODO
+
+    hb_font_funcs_make_immutable (funcs);
+
+    if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, NULL, funcs)) {
+      hb_font_funcs_destroy (funcs);
+      goto retry;
+    }
+
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_ot_funcs); /* First person registers atexit() callback. */
+#endif
+  };
+
+  return funcs;
+}
+
+
+/**
+ * hb_ot_font_set_funcs:
+ *
+ * Since: 0.9.28
+ **/
+void
+hb_ot_font_set_funcs (hb_font_t *font)
+{
+  hb_ot_font_t *ot_font = _hb_ot_font_create (font->face);
+  if (unlikely (!ot_font))
+    return;
+
+  hb_font_set_funcs (font,
+                     _hb_ot_get_font_funcs (),
+                     ot_font,
+                     (hb_destroy_func_t) _hb_ot_font_destroy);
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-font.h b/src/share/native/sun/font/harfbuzz/hb-ot-font.h
new file mode 100644
index 0000000..80eaa54
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-font.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2014  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, Roozbeh Pournader
+ */
+
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
+#ifndef HB_OT_FONT_H
+#define HB_OT_FONT_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+
+HB_EXTERN void
+hb_ot_font_set_funcs (hb_font_t *font);
+
+
+HB_END_DECLS
+
+#endif /* HB_OT_FONT_H */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-glyf-table.hh b/src/share/native/sun/font/harfbuzz/hb-ot-glyf-table.hh
new file mode 100644
index 0000000..cdb2393
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-glyf-table.hh
@@ -0,0 +1,104 @@
+/*
+ * Copyright © 2015  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_OT_GLYF_TABLE_HH
+#define HB_OT_GLYF_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+
+namespace OT {
+
+
+/*
+ * loca -- Index to Location
+ */
+
+#define HB_OT_TAG_loca HB_TAG('l','o','c','a')
+
+
+struct loca
+{
+  static const hb_tag_t tableTag = HB_OT_TAG_loca;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (true);
+  }
+
+  public:
+  union {
+    USHORT      shortsZ[VAR];           /* Location offset divided by 2. */
+    ULONG       longsZ[VAR];            /* Location offset. */
+  } u;
+  DEFINE_SIZE_ARRAY (0, u.longsZ);
+};
+
+
+/*
+ * glyf -- TrueType Glyph Data
+ */
+
+#define HB_OT_TAG_glyf HB_TAG('g','l','y','f')
+
+
+struct glyf
+{
+  static const hb_tag_t tableTag = HB_OT_TAG_glyf;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    /* We don't check for anything specific here.  The users of the
+     * struct do all the hard work... */
+    return_trace (true);
+  }
+
+  public:
+  BYTE          dataX[VAR];             /* Glyphs data. */
+
+  DEFINE_SIZE_ARRAY (0, dataX);
+};
+
+struct glyfGlyphHeader
+{
+  SHORT         numberOfContours;       /* If the number of contours is
+                                         * greater than or equal to zero,
+                                         * this is a simple glyph; if negative,
+                                         * this is a composite glyph. */
+  FWORD         xMin;                   /* Minimum x for coordinate data. */
+  FWORD         yMin;                   /* Minimum y for coordinate data. */
+  FWORD         xMax;                   /* Maximum x for coordinate data. */
+  FWORD         yMax;                   /* Maximum y for coordinate data. */
+
+  DEFINE_SIZE_STATIC (10);
+};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_GLYF_TABLE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-head-table.hh b/src/share/native/sun/font/harfbuzz/hb-ot-head-table.hh
new file mode 100644
index 0000000..16d18c8
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-head-table.hh
@@ -0,0 +1,154 @@
+/*
+ * Copyright © 2010  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
+ */
+
+#ifndef HB_OT_HEAD_TABLE_HH
+#define HB_OT_HEAD_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+
+namespace OT {
+
+
+/*
+ * head -- Font Header
+ */
+
+#define HB_OT_TAG_head HB_TAG('h','e','a','d')
+
+struct head
+{
+  static const hb_tag_t tableTag        = HB_OT_TAG_head;
+
+  inline unsigned int get_upem (void) const
+  {
+    unsigned int upem = unitsPerEm;
+    /* If no valid head table found, assume 1000, which matches typical Type1 usage. */
+    return 16 <= upem && upem <= 16384 ? upem : 1000;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  version.major == 1 &&
+                  magicNumber == 0x5F0F3CF5u);
+  }
+
+  protected:
+  FixedVersion<>version;                /* Version of the head table--currently
+                                         * 0x00010000u for version 1.0. */
+  FixedVersion<>fontRevision;           /* Set by font manufacturer. */
+  ULONG         checkSumAdjustment;     /* To compute: set it to 0, sum the
+                                         * entire font as ULONG, then store
+                                         * 0xB1B0AFBAu - sum. */
+  ULONG         magicNumber;            /* Set to 0x5F0F3CF5u. */
+  USHORT        flags;                  /* Bit 0: Baseline for font at y=0;
+                                         * Bit 1: Left sidebearing point at x=0;
+                                         * Bit 2: Instructions may depend on point size;
+                                         * Bit 3: Force ppem to integer values for all
+                                         *   internal scaler math; may use fractional
+                                         *   ppem sizes if this bit is clear;
+                                         * Bit 4: Instructions may alter advance width
+                                         *   (the advance widths might not scale linearly);
+
+                                         * Bits 5-10: These should be set according to
+                                         *   Apple's specification. However, they are not
+                                         *   implemented in OpenType.
+                                         * Bit 5: This bit should be set in fonts that are
+                                         *   intended to e laid out vertically, and in
+                                         *   which the glyphs have been drawn such that an
+                                         *   x-coordinate of 0 corresponds to the desired
+                                         *   vertical baseline.
+                                         * Bit 6: This bit must be set to zero.
+                                         * Bit 7: This bit should be set if the font
+                                         *   requires layout for correct linguistic
+                                         *   rendering (e.g. Arabic fonts).
+                                         * Bit 8: This bit should be set for a GX font
+                                         *   which has one or more metamorphosis effects
+                                         *   designated as happening by default.
+                                         * Bit 9: This bit should be set if the font
+                                         *   contains any strong right-to-left glyphs.
+                                         * Bit 10: This bit should be set if the font
+                                         *   contains Indic-style rearrangement effects.
+
+                                         * Bit 11: Font data is 'lossless,' as a result
+                                         *   of having been compressed and decompressed
+                                         *   with the Agfa MicroType Express engine.
+                                         * Bit 12: Font converted (produce compatible metrics)
+                                         * Bit 13: Font optimized for ClearType™.
+                                         *   Note, fonts that rely on embedded bitmaps (EBDT)
+                                         *   for rendering should not be considered optimized
+                                         *   for ClearType, and therefore should keep this bit
+                                         *   cleared.
+                                         * Bit 14: Last Resort font. If set, indicates that
+                                         * the glyphs encoded in the cmap subtables are simply
+                                         * generic symbolic representations of code point
+                                         * ranges and don’t truly represent support for those
+                                         * code points. If unset, indicates that the glyphs
+                                         * encoded in the cmap subtables represent proper
+                                         * support for those code points.
+                                         * Bit 15: Reserved, set to 0. */
+  USHORT        unitsPerEm;             /* Valid range is from 16 to 16384. This value
+                                         * should be a power of 2 for fonts that have
+                                         * TrueType outlines. */
+  LONGDATETIME  created;                /* Number of seconds since 12:00 midnight,
+                                           January 1, 1904. 64-bit integer */
+  LONGDATETIME  modified;               /* Number of seconds since 12:00 midnight,
+                                           January 1, 1904. 64-bit integer */
+  SHORT         xMin;                   /* For all glyph bounding boxes. */
+  SHORT         yMin;                   /* For all glyph bounding boxes. */
+  SHORT         xMax;                   /* For all glyph bounding boxes. */
+  SHORT         yMax;                   /* For all glyph bounding boxes. */
+  USHORT        macStyle;               /* Bit 0: Bold (if set to 1);
+                                         * Bit 1: Italic (if set to 1)
+                                         * Bit 2: Underline (if set to 1)
+                                         * Bit 3: Outline (if set to 1)
+                                         * Bit 4: Shadow (if set to 1)
+                                         * Bit 5: Condensed (if set to 1)
+                                         * Bit 6: Extended (if set to 1)
+                                         * Bits 7-15: Reserved (set to 0). */
+  USHORT        lowestRecPPEM;          /* Smallest readable size in pixels. */
+  SHORT         fontDirectionHint;      /* Deprecated (Set to 2).
+                                         * 0: Fully mixed directional glyphs;
+                                         * 1: Only strongly left to right;
+                                         * 2: Like 1 but also contains neutrals;
+                                         * -1: Only strongly right to left;
+                                         * -2: Like -1 but also contains neutrals. */
+  public:
+  SHORT         indexToLocFormat;       /* 0 for short offsets, 1 for long. */
+  SHORT         glyphDataFormat;        /* 0 for current format. */
+
+  DEFINE_SIZE_STATIC (54);
+};
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_HEAD_TABLE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-hhea-table.hh b/src/share/native/sun/font/harfbuzz/hb-ot-hhea-table.hh
new file mode 100644
index 0000000..c63f466
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-hhea-table.hh
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_HHEA_TABLE_HH
+#define HB_OT_HHEA_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+
+namespace OT {
+
+
+/*
+ * hhea -- The Horizontal Header Table
+ * vhea -- The Vertical Header Table
+ */
+
+#define HB_OT_TAG_hhea HB_TAG('h','h','e','a')
+#define HB_OT_TAG_vhea HB_TAG('v','h','e','a')
+
+
+struct _hea
+{
+  static const hb_tag_t tableTag = HB_TAG('_','h','e','a');
+
+  static const hb_tag_t hheaTag = HB_OT_TAG_hhea;
+  static const hb_tag_t vheaTag = HB_OT_TAG_vhea;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && likely (version.major == 1));
+  }
+
+  public:
+  FixedVersion<>version;                /* 0x00010000u for version 1.0. */
+  FWORD         ascender;               /* Typographic ascent. */
+  FWORD         descender;              /* Typographic descent. */
+  FWORD         lineGap;                /* Typographic line gap. */
+  UFWORD        advanceMax;             /* Maximum advance width/height value in
+                                         * metrics table. */
+  FWORD         minLeadingBearing;      /* Minimum left/top sidebearing value in
+                                         * metrics table. */
+  FWORD         minTrailingBearing;     /* Minimum right/bottom sidebearing value;
+                                         * calculated as Min(aw - lsb -
+                                         * (xMax - xMin)) for horizontal. */
+  FWORD         maxExtent;              /* horizontal: Max(lsb + (xMax - xMin)),
+                                         * vertical: minLeadingBearing+(yMax-yMin). */
+  SHORT         caretSlopeRise;         /* Used to calculate the slope of the
+                                         * cursor (rise/run); 1 for vertical caret,
+                                         * 0 for horizontal.*/
+  SHORT         caretSlopeRun;          /* 0 for vertical caret, 1 for horizontal. */
+  SHORT         caretOffset;            /* The amount by which a slanted
+                                         * highlight on a glyph needs
+                                         * to be shifted to produce the
+                                         * best appearance. Set to 0 for
+                                         * non-slanted fonts. */
+  SHORT         reserved1;              /* Set to 0. */
+  SHORT         reserved2;              /* Set to 0. */
+  SHORT         reserved3;              /* Set to 0. */
+  SHORT         reserved4;              /* Set to 0. */
+  SHORT         metricDataFormat;       /* 0 for current format. */
+  USHORT        numberOfLongMetrics;    /* Number of LongMetric entries in metric
+                                         * table. */
+  public:
+  DEFINE_SIZE_STATIC (36);
+};
+
+struct hhea : _hea {
+  static const hb_tag_t tableTag        = HB_OT_TAG_hhea;
+};
+struct vhea : _hea {
+  static const hb_tag_t tableTag        = HB_OT_TAG_vhea;
+};
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_HHEA_TABLE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-hmtx-table.hh b/src/share/native/sun/font/harfbuzz/hb-ot-hmtx-table.hh
new file mode 100644
index 0000000..2ec501c
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-hmtx-table.hh
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_HMTX_TABLE_HH
+#define HB_OT_HMTX_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+
+namespace OT {
+
+
+/*
+ * hmtx -- The Horizontal Metrics Table
+ * vmtx -- The Vertical Metrics Table
+ */
+
+#define HB_OT_TAG_hmtx HB_TAG('h','m','t','x')
+#define HB_OT_TAG_vmtx HB_TAG('v','m','t','x')
+
+
+struct LongMetric
+{
+  UFWORD        advance; /* Advance width/height. */
+  FWORD         lsb; /* Leading (left/top) side bearing. */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+struct _mtx
+{
+  static const hb_tag_t tableTag = HB_TAG('_','m','t','x');
+
+  static const hb_tag_t hmtxTag = HB_OT_TAG_hmtx;
+  static const hb_tag_t vmtxTag = HB_OT_TAG_vmtx;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    /* We don't check for anything specific here.  The users of the
+     * struct do all the hard work... */
+    return_trace (true);
+  }
+
+  public:
+  LongMetric    longMetric[VAR];        /* Paired advance width and leading
+                                         * bearing values for each glyph. The
+                                         * value numOfHMetrics comes from
+                                         * the 'hhea' table. If the font is
+                                         * monospaced, only one entry need
+                                         * be in the array, but that entry is
+                                         * required. The last entry applies to
+                                         * all subsequent glyphs. */
+  FWORD         leadingBearingX[VAR];   /* Here the advance is assumed
+                                         * to be the same as the advance
+                                         * for the last entry above. The
+                                         * number of entries in this array is
+                                         * derived from numGlyphs (from 'maxp'
+                                         * table) minus numberOfLongMetrics.
+                                         * This generally is used with a run
+                                         * of monospaced glyphs (e.g., Kanji
+                                         * fonts or Courier fonts). Only one
+                                         * run is allowed and it must be at
+                                         * the end. This allows a monospaced
+                                         * font to vary the side bearing
+                                         * values for each glyph. */
+  public:
+  DEFINE_SIZE_ARRAY2 (0, longMetric, leadingBearingX);
+};
+
+struct hmtx : _mtx {
+  static const hb_tag_t tableTag        = HB_OT_TAG_hmtx;
+};
+struct vmtx : _mtx {
+  static const hb_tag_t tableTag        = HB_OT_TAG_vmtx;
+};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_HMTX_TABLE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-layout-common-private.hh b/src/share/native/sun/font/harfbuzz/hb-ot-layout-common-private.hh
new file mode 100644
index 0000000..f6d966c
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-layout-common-private.hh
@@ -0,0 +1,1242 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * Copyright © 2010,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_OT_LAYOUT_COMMON_PRIVATE_HH
+#define HB_OT_LAYOUT_COMMON_PRIVATE_HH
+
+#include "hb-ot-layout-private.hh"
+#include "hb-open-type-private.hh"
+#include "hb-set-private.hh"
+
+
+#ifndef HB_MAX_NESTING_LEVEL
+#define HB_MAX_NESTING_LEVEL    6
+#endif
+#ifndef HB_MAX_CONTEXT_LENGTH
+#define HB_MAX_CONTEXT_LENGTH   64
+#endif
+
+
+namespace OT {
+
+
+#define TRACE_DISPATCH(this, format) \
+        hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
+        (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+         "format %d", (int) format);
+
+
+#define NOT_COVERED             ((unsigned int) -1)
+
+
+
+/*
+ *
+ * OpenType Layout Common Table Formats
+ *
+ */
+
+
+/*
+ * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
+ */
+
+template <typename Type>
+struct Record
+{
+  inline int cmp (hb_tag_t a) const {
+    return tag.cmp (a);
+  }
+
+  struct sanitize_closure_t {
+    hb_tag_t tag;
+    const void *list_base;
+  };
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    const sanitize_closure_t closure = {tag, base};
+    return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
+  }
+
+  Tag           tag;            /* 4-byte Tag identifier */
+  OffsetTo<Type>
+                offset;         /* Offset from beginning of object holding
+                                 * the Record */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+template <typename Type>
+struct RecordArrayOf : SortedArrayOf<Record<Type> > {
+  inline const Tag& get_tag (unsigned int i) const
+  {
+    /* We cheat slightly and don't define separate Null objects
+     * for Record types.  Instead, we return the correct Null(Tag)
+     * here. */
+    if (unlikely (i >= this->len)) return Null(Tag);
+    return (*this)[i].tag;
+  }
+  inline unsigned int get_tags (unsigned int start_offset,
+                                unsigned int *record_count /* IN/OUT */,
+                                hb_tag_t     *record_tags /* OUT */) const
+  {
+    if (record_count) {
+      const Record<Type> *arr = this->sub_array (start_offset, record_count);
+      unsigned int count = *record_count;
+      for (unsigned int i = 0; i < count; i++)
+        record_tags[i] = arr[i].tag;
+    }
+    return this->len;
+  }
+  inline bool find_index (hb_tag_t tag, unsigned int *index) const
+  {
+    /* If we want to allow non-sorted data, we can lsearch(). */
+    int i = this->/*lsearch*/bsearch (tag);
+    if (i != -1) {
+        if (index) *index = i;
+        return true;
+    } else {
+      if (index) *index = Index::NOT_FOUND_INDEX;
+      return false;
+    }
+  }
+};
+
+template <typename Type>
+struct RecordListOf : RecordArrayOf<Type>
+{
+  inline const Type& operator [] (unsigned int i) const
+  { return this+RecordArrayOf<Type>::operator [](i).offset; }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (RecordArrayOf<Type>::sanitize (c, this));
+  }
+};
+
+
+struct RangeRecord
+{
+  inline int cmp (hb_codepoint_t g) const {
+    return g < start ? -1 : g <= end ? 0 : +1 ;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  inline bool intersects (const hb_set_t *glyphs) const {
+    return glyphs->intersects (start, end);
+  }
+
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const {
+    glyphs->add_range (start, end);
+  }
+
+  GlyphID       start;          /* First GlyphID in the range */
+  GlyphID       end;            /* Last GlyphID in the range */
+  USHORT        value;          /* Value */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+DEFINE_NULL_DATA (RangeRecord, "\000\001");
+
+
+struct IndexArray : ArrayOf<Index>
+{
+  inline unsigned int get_indexes (unsigned int start_offset,
+                                   unsigned int *_count /* IN/OUT */,
+                                   unsigned int *_indexes /* OUT */) const
+  {
+    if (_count) {
+      const USHORT *arr = this->sub_array (start_offset, _count);
+      unsigned int count = *_count;
+      for (unsigned int i = 0; i < count; i++)
+        _indexes[i] = arr[i];
+    }
+    return this->len;
+  }
+};
+
+
+struct Script;
+struct LangSys;
+struct Feature;
+
+
+struct LangSys
+{
+  inline unsigned int get_feature_count (void) const
+  { return featureIndex.len; }
+  inline hb_tag_t get_feature_index (unsigned int i) const
+  { return featureIndex[i]; }
+  inline unsigned int get_feature_indexes (unsigned int start_offset,
+                                           unsigned int *feature_count /* IN/OUT */,
+                                           unsigned int *feature_indexes /* OUT */) const
+  { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
+
+  inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; }
+  inline unsigned int get_required_feature_index (void) const
+  {
+    if (reqFeatureIndex == 0xFFFFu)
+      return Index::NOT_FOUND_INDEX;
+   return reqFeatureIndex;;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c,
+                        const Record<LangSys>::sanitize_closure_t * = NULL) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && featureIndex.sanitize (c));
+  }
+
+  Offset<>      lookupOrderZ;   /* = Null (reserved for an offset to a
+                                 * reordering table) */
+  USHORT        reqFeatureIndex;/* Index of a feature required for this
+                                 * language system--if no required features
+                                 * = 0xFFFFu */
+  IndexArray    featureIndex;   /* Array of indices into the FeatureList */
+  public:
+  DEFINE_SIZE_ARRAY (6, featureIndex);
+};
+DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF");
+
+
+struct Script
+{
+  inline unsigned int get_lang_sys_count (void) const
+  { return langSys.len; }
+  inline const Tag& get_lang_sys_tag (unsigned int i) const
+  { return langSys.get_tag (i); }
+  inline unsigned int get_lang_sys_tags (unsigned int start_offset,
+                                         unsigned int *lang_sys_count /* IN/OUT */,
+                                         hb_tag_t     *lang_sys_tags /* OUT */) const
+  { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
+  inline const LangSys& get_lang_sys (unsigned int i) const
+  {
+    if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
+    return this+langSys[i].offset;
+  }
+  inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
+  { return langSys.find_index (tag, index); }
+
+  inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
+  inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
+
+  inline bool sanitize (hb_sanitize_context_t *c,
+                        const Record<Script>::sanitize_closure_t * = NULL) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
+  }
+
+  protected:
+  OffsetTo<LangSys>
+                defaultLangSys; /* Offset to DefaultLangSys table--from
+                                 * beginning of Script table--may be Null */
+  RecordArrayOf<LangSys>
+                langSys;        /* Array of LangSysRecords--listed
+                                 * alphabetically by LangSysTag */
+  public:
+  DEFINE_SIZE_ARRAY (4, langSys);
+};
+
+typedef RecordListOf<Script> ScriptList;
+
+
+/* http://www.microsoft.com/typography/otspec/features_pt.htm#size */
+struct FeatureParamsSize
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this))) return_trace (false);
+
+    /* This subtable has some "history", if you will.  Some earlier versions of
+     * Adobe tools calculated the offset of the FeatureParams sutable from the
+     * beginning of the FeatureList table!  Now, that is dealt with in the
+     * Feature implementation.  But we still need to be able to tell junk from
+     * real data.  Note: We don't check that the nameID actually exists.
+     *
+     * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk :
+     *
+     * Yes, it is correct that a new version of the AFDKO (version 2.0) will be
+     * coming out soon, and that the makeotf program will build a font with a
+     * 'size' feature that is correct by the specification.
+     *
+     * The specification for this feature tag is in the "OpenType Layout Tag
+     * Registry". You can see a copy of this at:
+     * http://partners.adobe.com/public/developer/opentype/index_tag8.html#size
+     *
+     * Here is one set of rules to determine if the 'size' feature is built
+     * correctly, or as by the older versions of MakeOTF. You may be able to do
+     * better.
+     *
+     * Assume that the offset to the size feature is according to specification,
+     * and make the following value checks. If it fails, assume the the size
+     * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it.
+     * If this fails, reject the 'size' feature. The older makeOTF's calculated the
+     * offset from the beginning of the FeatureList table, rather than from the
+     * beginning of the 'size' Feature table.
+     *
+     * If "design size" == 0:
+     *     fails check
+     *
+     * Else if ("subfamily identifier" == 0 and
+     *     "range start" == 0 and
+     *     "range end" == 0 and
+     *     "range start" == 0 and
+     *     "menu name ID" == 0)
+     *     passes check: this is the format used when there is a design size
+     * specified, but there is no recommended size range.
+     *
+     * Else if ("design size" <  "range start" or
+     *     "design size" >   "range end" or
+     *     "range end" <= "range start" or
+     *     "menu name ID"  < 256 or
+     *     "menu name ID"  > 32767 or
+     *     menu name ID is not a name ID which is actually in the name table)
+     *     fails test
+     * Else
+     *     passes test.
+     */
+
+    if (!designSize)
+      return_trace (false);
+    else if (subfamilyID == 0 &&
+             subfamilyNameID == 0 &&
+             rangeStart == 0 &&
+             rangeEnd == 0)
+      return_trace (true);
+    else if (designSize < rangeStart ||
+             designSize > rangeEnd ||
+             subfamilyNameID < 256 ||
+             subfamilyNameID > 32767)
+      return_trace (false);
+    else
+      return_trace (true);
+  }
+
+  USHORT        designSize;     /* Represents the design size in 720/inch
+                                 * units (decipoints).  The design size entry
+                                 * must be non-zero.  When there is a design
+                                 * size but no recommended size range, the
+                                 * rest of the array will consist of zeros. */
+  USHORT        subfamilyID;    /* Has no independent meaning, but serves
+                                 * as an identifier that associates fonts
+                                 * in a subfamily. All fonts which share a
+                                 * Preferred or Font Family name and which
+                                 * differ only by size range shall have the
+                                 * same subfamily value, and no fonts which
+                                 * differ in weight or style shall have the
+                                 * same subfamily value. If this value is
+                                 * zero, the remaining fields in the array
+                                 * will be ignored. */
+  USHORT        subfamilyNameID;/* If the preceding value is non-zero, this
+                                 * value must be set in the range 256 - 32767
+                                 * (inclusive). It records the value of a
+                                 * field in the name table, which must
+                                 * contain English-language strings encoded
+                                 * in Windows Unicode and Macintosh Roman,
+                                 * and may contain additional strings
+                                 * localized to other scripts and languages.
+                                 * Each of these strings is the name an
+                                 * application should use, in combination
+                                 * with the family name, to represent the
+                                 * subfamily in a menu.  Applications will
+                                 * choose the appropriate version based on
+                                 * their selection criteria. */
+  USHORT        rangeStart;     /* Large end of the recommended usage range
+                                 * (inclusive), stored in 720/inch units
+                                 * (decipoints). */
+  USHORT        rangeEnd;       /* Small end of the recommended usage range
+                                   (exclusive), stored in 720/inch units
+                                 * (decipoints). */
+  public:
+  DEFINE_SIZE_STATIC (10);
+};
+
+/* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */
+struct FeatureParamsStylisticSet
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    /* Right now minorVersion is at zero.  Which means, any table supports
+     * the uiNameID field. */
+    return_trace (c->check_struct (this));
+  }
+
+  USHORT        version;        /* (set to 0): This corresponds to a “minor”
+                                 * version number. Additional data may be
+                                 * added to the end of this Feature Parameters
+                                 * table in the future. */
+
+  USHORT        uiNameID;       /* The 'name' table name ID that specifies a
+                                 * string (or strings, for multiple languages)
+                                 * for a user-interface label for this
+                                 * feature.  The values of uiLabelNameId and
+                                 * sampleTextNameId are expected to be in the
+                                 * font-specific name ID range (256-32767),
+                                 * though that is not a requirement in this
+                                 * Feature Parameters specification. The
+                                 * user-interface label for the feature can
+                                 * be provided in multiple languages. An
+                                 * English string should be included as a
+                                 * fallback. The string should be kept to a
+                                 * minimal length to fit comfortably with
+                                 * different application interfaces. */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+/* http://www.microsoft.com/typography/otspec/features_ae.htm#cv01-cv99 */
+struct FeatureParamsCharacterVariants
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  characters.sanitize (c));
+  }
+
+  USHORT        format;                 /* Format number is set to 0. */
+  USHORT        featUILableNameID;      /* The ‘name’ table name ID that
+                                         * specifies a string (or strings,
+                                         * for multiple languages) for a
+                                         * user-interface label for this
+                                         * feature. (May be NULL.) */
+  USHORT        featUITooltipTextNameID;/* The ‘name’ table name ID that
+                                         * specifies a string (or strings,
+                                         * for multiple languages) that an
+                                         * application can use for tooltip
+                                         * text for this feature. (May be
+                                         * NULL.) */
+  USHORT        sampleTextNameID;       /* The ‘name’ table name ID that
+                                         * specifies sample text that
+                                         * illustrates the effect of this
+                                         * feature. (May be NULL.) */
+  USHORT        numNamedParameters;     /* Number of named parameters. (May
+                                         * be zero.) */
+  USHORT        firstParamUILabelNameID;/* The first ‘name’ table name ID
+                                         * used to specify strings for
+                                         * user-interface labels for the
+                                         * feature parameters. (Must be zero
+                                         * if numParameters is zero.) */
+  ArrayOf<UINT24>
+                characters;             /* Array of the Unicode Scalar Value
+                                         * of the characters for which this
+                                         * feature provides glyph variants.
+                                         * (May be zero.) */
+  public:
+  DEFINE_SIZE_ARRAY (14, characters);
+};
+
+struct FeatureParams
+{
+  inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
+  {
+    TRACE_SANITIZE (this);
+    if (tag == HB_TAG ('s','i','z','e'))
+      return_trace (u.size.sanitize (c));
+    if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
+      return_trace (u.stylisticSet.sanitize (c));
+    if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
+      return_trace (u.characterVariants.sanitize (c));
+    return_trace (true);
+  }
+
+  inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const
+  {
+    if (tag == HB_TAG ('s','i','z','e'))
+      return u.size;
+    return Null(FeatureParamsSize);
+  }
+
+  private:
+  union {
+  FeatureParamsSize                     size;
+  FeatureParamsStylisticSet             stylisticSet;
+  FeatureParamsCharacterVariants        characterVariants;
+  } u;
+  DEFINE_SIZE_STATIC (17);
+};
+
+struct Feature
+{
+  inline unsigned int get_lookup_count (void) const
+  { return lookupIndex.len; }
+  inline hb_tag_t get_lookup_index (unsigned int i) const
+  { return lookupIndex[i]; }
+  inline unsigned int get_lookup_indexes (unsigned int start_index,
+                                          unsigned int *lookup_count /* IN/OUT */,
+                                          unsigned int *lookup_tags /* OUT */) const
+  { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
+
+  inline const FeatureParams &get_feature_params (void) const
+  { return this+featureParams; }
+
+  inline bool sanitize (hb_sanitize_context_t *c,
+                        const Record<Feature>::sanitize_closure_t *closure) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
+      return_trace (false);
+
+    /* Some earlier versions of Adobe tools calculated the offset of the
+     * FeatureParams subtable from the beginning of the FeatureList table!
+     *
+     * If sanitizing "failed" for the FeatureParams subtable, try it with the
+     * alternative location.  We would know sanitize "failed" if old value
+     * of the offset was non-zero, but it's zeroed now.
+     *
+     * Only do this for the 'size' feature, since at the time of the faulty
+     * Adobe tools, only the 'size' feature had FeatureParams defined.
+     */
+
+    OffsetTo<FeatureParams> orig_offset = featureParams;
+    if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
+      return_trace (false);
+
+    if (likely (orig_offset.is_null ()))
+      return_trace (true);
+
+    if (featureParams == 0 && closure &&
+        closure->tag == HB_TAG ('s','i','z','e') &&
+        closure->list_base && closure->list_base < this)
+    {
+      unsigned int new_offset_int = (unsigned int) orig_offset -
+                                    (((char *) this) - ((char *) closure->list_base));
+
+      OffsetTo<FeatureParams> new_offset;
+      /* Check that it did not overflow. */
+      new_offset.set (new_offset_int);
+      if (new_offset == new_offset_int &&
+          c->try_set (&featureParams, new_offset) &&
+          !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
+        return_trace (false);
+
+      if (c->edit_count > 1)
+        c->edit_count--; /* This was a "legitimate" edit; don't contribute to error count. */
+    }
+
+    return_trace (true);
+  }
+
+  OffsetTo<FeatureParams>
+                 featureParams; /* Offset to Feature Parameters table (if one
+                                 * has been defined for the feature), relative
+                                 * to the beginning of the Feature Table; = Null
+                                 * if not required */
+  IndexArray     lookupIndex;   /* Array of LookupList indices */
+  public:
+  DEFINE_SIZE_ARRAY (4, lookupIndex);
+};
+
+typedef RecordListOf<Feature> FeatureList;
+
+
+struct LookupFlag : USHORT
+{
+  enum Flags {
+    RightToLeft         = 0x0001u,
+    IgnoreBaseGlyphs    = 0x0002u,
+    IgnoreLigatures     = 0x0004u,
+    IgnoreMarks         = 0x0008u,
+    IgnoreFlags         = 0x000Eu,
+    UseMarkFilteringSet = 0x0010u,
+    Reserved            = 0x00E0u,
+    MarkAttachmentType  = 0xFF00u
+  };
+  public:
+  DEFINE_SIZE_STATIC (2);
+};
+
+} /* namespace OT */
+/* This has to be outside the namespace. */
+HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
+namespace OT {
+
+struct Lookup
+{
+  inline unsigned int get_subtable_count (void) const { return subTable.len; }
+
+  template <typename SubTableType>
+  inline const SubTableType& get_subtable (unsigned int i) const
+  { return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; }
+
+  template <typename SubTableType>
+  inline const OffsetArrayOf<SubTableType>& get_subtables (void) const
+  { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
+  template <typename SubTableType>
+  inline OffsetArrayOf<SubTableType>& get_subtables (void)
+  { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
+
+  inline unsigned int get_type (void) const { return lookupType; }
+
+  /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
+   * higher 16-bit is mark-filtering-set if the lookup uses one.
+   * Not to be confused with glyph_props which is very similar. */
+  inline uint32_t get_props (void) const
+  {
+    unsigned int flag = lookupFlag;
+    if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
+    {
+      const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+      flag += (markFilteringSet << 16);
+    }
+    return flag;
+  }
+
+  template <typename SubTableType, typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    unsigned int lookup_type = get_type ();
+    TRACE_DISPATCH (this, lookup_type);
+    unsigned int count = get_subtable_count ();
+    for (unsigned int i = 0; i < count; i++) {
+      typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type);
+      if (c->stop_sublookup_iteration (r))
+        return_trace (r);
+    }
+    return_trace (c->default_return_value ());
+  }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                         unsigned int lookup_type,
+                         uint32_t lookup_props,
+                         unsigned int num_subtables)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    lookupType.set (lookup_type);
+    lookupFlag.set (lookup_props & 0xFFFFu);
+    if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
+    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
+    {
+      USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+      markFilteringSet.set (lookup_props >> 16);
+    }
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    /* Real sanitize of the subtables is done by GSUB/GPOS/... */
+    if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
+    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
+    {
+      const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+      if (!markFilteringSet.sanitize (c)) return_trace (false);
+    }
+    return_trace (true);
+  }
+
+  private:
+  USHORT        lookupType;             /* Different enumerations for GSUB and GPOS */
+  USHORT        lookupFlag;             /* Lookup qualifiers */
+  ArrayOf<Offset<> >
+                subTable;               /* Array of SubTables */
+  USHORT        markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets
+                                         * structure. This field is only present if bit
+                                         * UseMarkFilteringSet of lookup flags is set. */
+  public:
+  DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
+};
+
+typedef OffsetListOf<Lookup> LookupList;
+
+
+/*
+ * Coverage Table
+ */
+
+struct CoverageFormat1
+{
+  friend struct Coverage;
+
+  private:
+  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
+  {
+    int i = glyphArray.bsearch (glyph_id);
+    ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED);
+    return i;
+  }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                         Supplier<GlyphID> &glyphs,
+                         unsigned int num_glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    glyphArray.len.set (num_glyphs);
+    if (unlikely (!c->extend (glyphArray))) return_trace (false);
+    for (unsigned int i = 0; i < num_glyphs; i++)
+      glyphArray[i] = glyphs[i];
+    glyphs.advance (num_glyphs);
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (glyphArray.sanitize (c));
+  }
+
+  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
+    return glyphs->has (glyphArray[index]);
+  }
+
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const {
+    unsigned int count = glyphArray.len;
+    for (unsigned int i = 0; i < count; i++)
+      glyphs->add (glyphArray[i]);
+  }
+
+  public:
+  /* Older compilers need this to be public. */
+  struct Iter {
+    inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
+    inline bool more (void) { return i < c->glyphArray.len; }
+    inline void next (void) { i++; }
+    inline uint16_t get_glyph (void) { return c->glyphArray[i]; }
+    inline uint16_t get_coverage (void) { return i; }
+
+    private:
+    const struct CoverageFormat1 *c;
+    unsigned int i;
+  };
+  private:
+
+  protected:
+  USHORT        coverageFormat; /* Format identifier--format = 1 */
+  SortedArrayOf<GlyphID>
+                glyphArray;     /* Array of GlyphIDs--in numerical order */
+  public:
+  DEFINE_SIZE_ARRAY (4, glyphArray);
+};
+
+struct CoverageFormat2
+{
+  friend struct Coverage;
+
+  private:
+  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
+  {
+    int i = rangeRecord.bsearch (glyph_id);
+    if (i != -1) {
+      const RangeRecord &range = rangeRecord[i];
+      return (unsigned int) range.value + (glyph_id - range.start);
+    }
+    return NOT_COVERED;
+  }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                         Supplier<GlyphID> &glyphs,
+                         unsigned int num_glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+
+    if (unlikely (!num_glyphs))
+    {
+      rangeRecord.len.set (0);
+      return_trace (true);
+    }
+
+    unsigned int num_ranges = 1;
+    for (unsigned int i = 1; i < num_glyphs; i++)
+      if (glyphs[i - 1] + 1 != glyphs[i])
+        num_ranges++;
+    rangeRecord.len.set (num_ranges);
+    if (unlikely (!c->extend (rangeRecord))) return_trace (false);
+
+    unsigned int range = 0;
+    rangeRecord[range].start = glyphs[0];
+    rangeRecord[range].value.set (0);
+    for (unsigned int i = 1; i < num_glyphs; i++)
+      if (glyphs[i - 1] + 1 != glyphs[i]) {
+        range++;
+        rangeRecord[range].start = glyphs[i];
+        rangeRecord[range].value.set (i);
+        rangeRecord[range].end = glyphs[i];
+      } else {
+        rangeRecord[range].end = glyphs[i];
+      }
+    glyphs.advance (num_glyphs);
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (rangeRecord.sanitize (c));
+  }
+
+  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
+    unsigned int i;
+    unsigned int count = rangeRecord.len;
+    for (i = 0; i < count; i++) {
+      const RangeRecord &range = rangeRecord[i];
+      if (range.value <= index &&
+          index < (unsigned int) range.value + (range.end - range.start) &&
+          range.intersects (glyphs))
+        return true;
+      else if (index < range.value)
+        return false;
+    }
+    return false;
+  }
+
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const {
+    unsigned int count = rangeRecord.len;
+    for (unsigned int i = 0; i < count; i++)
+      rangeRecord[i].add_coverage (glyphs);
+  }
+
+  public:
+  /* Older compilers need this to be public. */
+  struct Iter {
+    inline void init (const CoverageFormat2 &c_) {
+      c = &c_;
+      coverage = 0;
+      i = 0;
+      j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0;
+    }
+    inline bool more (void) { return i < c->rangeRecord.len; }
+    inline void next (void) {
+      coverage++;
+      if (j == c->rangeRecord[i].end) {
+        i++;
+        if (more ())
+          j = c->rangeRecord[i].start;
+        return;
+      }
+      j++;
+    }
+    inline uint16_t get_glyph (void) { return j; }
+    inline uint16_t get_coverage (void) { return coverage; }
+
+    private:
+    const struct CoverageFormat2 *c;
+    unsigned int i, j, coverage;
+  };
+  private:
+
+  protected:
+  USHORT        coverageFormat; /* Format identifier--format = 2 */
+  SortedArrayOf<RangeRecord>
+                rangeRecord;    /* Array of glyph ranges--ordered by
+                                 * Start GlyphID. rangeCount entries
+                                 * long */
+  public:
+  DEFINE_SIZE_ARRAY (4, rangeRecord);
+};
+
+struct Coverage
+{
+  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
+  {
+    switch (u.format) {
+    case 1: return u.format1.get_coverage(glyph_id);
+    case 2: return u.format2.get_coverage(glyph_id);
+    default:return NOT_COVERED;
+    }
+  }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                         Supplier<GlyphID> &glyphs,
+                         unsigned int num_glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    unsigned int num_ranges = 1;
+    for (unsigned int i = 1; i < num_glyphs; i++)
+      if (glyphs[i - 1] + 1 != glyphs[i])
+        num_ranges++;
+    u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
+    switch (u.format) {
+    case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs));
+    case 2: return_trace (u.format2.serialize (c, glyphs, num_glyphs));
+    default:return_trace (false);
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.format.sanitize (c)) return_trace (false);
+    switch (u.format) {
+    case 1: return_trace (u.format1.sanitize (c));
+    case 2: return_trace (u.format2.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  inline bool intersects (const hb_set_t *glyphs) const {
+    /* TODO speed this up */
+    Coverage::Iter iter;
+    for (iter.init (*this); iter.more (); iter.next ()) {
+      if (glyphs->has (iter.get_glyph ()))
+        return true;
+    }
+    return false;
+  }
+
+  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
+    switch (u.format) {
+    case 1: return u.format1.intersects_coverage (glyphs, index);
+    case 2: return u.format2.intersects_coverage (glyphs, index);
+    default:return false;
+    }
+  }
+
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const {
+    switch (u.format) {
+    case 1: u.format1.add_coverage (glyphs); break;
+    case 2: u.format2.add_coverage (glyphs); break;
+    default:                                 break;
+    }
+  }
+
+  struct Iter {
+    Iter (void) : format (0) {};
+    inline void init (const Coverage &c_) {
+      format = c_.u.format;
+      switch (format) {
+      case 1: u.format1.init (c_.u.format1); return;
+      case 2: u.format2.init (c_.u.format2); return;
+      default:                               return;
+      }
+    }
+    inline bool more (void) {
+      switch (format) {
+      case 1: return u.format1.more ();
+      case 2: return u.format2.more ();
+      default:return false;
+      }
+    }
+    inline void next (void) {
+      switch (format) {
+      case 1: u.format1.next (); break;
+      case 2: u.format2.next (); break;
+      default:                   break;
+      }
+    }
+    inline uint16_t get_glyph (void) {
+      switch (format) {
+      case 1: return u.format1.get_glyph ();
+      case 2: return u.format2.get_glyph ();
+      default:return 0;
+      }
+    }
+    inline uint16_t get_coverage (void) {
+      switch (format) {
+      case 1: return u.format1.get_coverage ();
+      case 2: return u.format2.get_coverage ();
+      default:return -1;
+      }
+    }
+
+    private:
+    unsigned int format;
+    union {
+    CoverageFormat1::Iter       format1;
+    CoverageFormat2::Iter       format2;
+    } u;
+  };
+
+  protected:
+  union {
+  USHORT                format;         /* Format identifier */
+  CoverageFormat1       format1;
+  CoverageFormat2       format2;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+};
+
+
+/*
+ * Class Definition Table
+ */
+
+struct ClassDefFormat1
+{
+  friend struct ClassDef;
+
+  private:
+  inline unsigned int get_class (hb_codepoint_t glyph_id) const
+  {
+    unsigned int i = (unsigned int) (glyph_id - startGlyph);
+    if (unlikely (i < classValue.len))
+      return classValue[i];
+    return 0;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && classValue.sanitize (c));
+  }
+
+  template <typename set_t>
+  inline void add_class (set_t *glyphs, unsigned int klass) const {
+    unsigned int count = classValue.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (classValue[i] == klass)
+        glyphs->add (startGlyph + i);
+  }
+
+  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
+    unsigned int count = classValue.len;
+    if (klass == 0)
+    {
+      /* Match if there's any glyph that is not listed! */
+      hb_codepoint_t g = -1;
+      if (!hb_set_next (glyphs, &g))
+        return false;
+      if (g < startGlyph)
+        return true;
+      g = startGlyph + count - 1;
+      if (hb_set_next (glyphs, &g))
+        return true;
+      /* Fall through. */
+    }
+    for (unsigned int i = 0; i < count; i++)
+      if (classValue[i] == klass && glyphs->has (startGlyph + i))
+        return true;
+    return false;
+  }
+
+  protected:
+  USHORT        classFormat;            /* Format identifier--format = 1 */
+  GlyphID       startGlyph;             /* First GlyphID of the classValueArray */
+  ArrayOf<USHORT>
+                classValue;             /* Array of Class Values--one per GlyphID */
+  public:
+  DEFINE_SIZE_ARRAY (6, classValue);
+};
+
+struct ClassDefFormat2
+{
+  friend struct ClassDef;
+
+  private:
+  inline unsigned int get_class (hb_codepoint_t glyph_id) const
+  {
+    int i = rangeRecord.bsearch (glyph_id);
+    if (unlikely (i != -1))
+      return rangeRecord[i].value;
+    return 0;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (rangeRecord.sanitize (c));
+  }
+
+  template <typename set_t>
+  inline void add_class (set_t *glyphs, unsigned int klass) const {
+    unsigned int count = rangeRecord.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (rangeRecord[i].value == klass)
+        rangeRecord[i].add_coverage (glyphs);
+  }
+
+  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
+    unsigned int count = rangeRecord.len;
+    if (klass == 0)
+    {
+      /* Match if there's any glyph that is not listed! */
+      hb_codepoint_t g = (hb_codepoint_t) -1;
+      for (unsigned int i = 0; i < count; i++)
+      {
+        if (!hb_set_next (glyphs, &g))
+          break;
+        if (g < rangeRecord[i].start)
+          return true;
+        g = rangeRecord[i].end;
+      }
+      if (g != (hb_codepoint_t) -1 && hb_set_next (glyphs, &g))
+        return true;
+      /* Fall through. */
+    }
+    for (unsigned int i = 0; i < count; i++)
+      if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
+        return true;
+    return false;
+  }
+
+  protected:
+  USHORT        classFormat;    /* Format identifier--format = 2 */
+  SortedArrayOf<RangeRecord>
+                rangeRecord;    /* Array of glyph ranges--ordered by
+                                 * Start GlyphID */
+  public:
+  DEFINE_SIZE_ARRAY (4, rangeRecord);
+};
+
+struct ClassDef
+{
+  inline unsigned int get_class (hb_codepoint_t glyph_id) const
+  {
+    switch (u.format) {
+    case 1: return u.format1.get_class(glyph_id);
+    case 2: return u.format2.get_class(glyph_id);
+    default:return 0;
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.format.sanitize (c)) return_trace (false);
+    switch (u.format) {
+    case 1: return_trace (u.format1.sanitize (c));
+    case 2: return_trace (u.format2.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  inline void add_class (hb_set_t *glyphs, unsigned int klass) const {
+    switch (u.format) {
+    case 1: u.format1.add_class (glyphs, klass); return;
+    case 2: u.format2.add_class (glyphs, klass); return;
+    default:return;
+    }
+  }
+
+  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
+    switch (u.format) {
+    case 1: return u.format1.intersects_class (glyphs, klass);
+    case 2: return u.format2.intersects_class (glyphs, klass);
+    default:return false;
+    }
+  }
+
+  protected:
+  union {
+  USHORT                format;         /* Format identifier */
+  ClassDefFormat1       format1;
+  ClassDefFormat2       format2;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+};
+
+
+/*
+ * Device Tables
+ */
+
+struct Device
+{
+
+  inline hb_position_t get_x_delta (hb_font_t *font) const
+  { return get_delta (font->x_ppem, font->x_scale); }
+
+  inline hb_position_t get_y_delta (hb_font_t *font) const
+  { return get_delta (font->y_ppem, font->y_scale); }
+
+  inline unsigned int get_size (void) const
+  {
+    unsigned int f = deltaFormat;
+    if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
+    return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
+  }
+
+  private:
+
+  inline int get_delta (unsigned int ppem, int scale) const
+  {
+    if (!ppem) return 0;
+
+    int pixels = get_delta_pixels (ppem);
+
+    if (!pixels) return 0;
+
+    return (int) (pixels * (int64_t) scale / ppem);
+  }
+  inline int get_delta_pixels (unsigned int ppem_size) const
+  {
+    unsigned int f = deltaFormat;
+    if (unlikely (f < 1 || f > 3))
+      return 0;
+
+    if (ppem_size < startSize || ppem_size > endSize)
+      return 0;
+
+    unsigned int s = ppem_size - startSize;
+
+    unsigned int byte = deltaValue[s >> (4 - f)];
+    unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
+    unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
+
+    int delta = bits & mask;
+
+    if ((unsigned int) delta >= ((mask + 1) >> 1))
+      delta -= mask + 1;
+
+    return delta;
+  }
+
+  protected:
+  USHORT        startSize;              /* Smallest size to correct--in ppem */
+  USHORT        endSize;                /* Largest size to correct--in ppem */
+  USHORT        deltaFormat;            /* Format of DeltaValue array data: 1, 2, or 3
+                                         * 1    Signed 2-bit value, 8 values per uint16
+                                         * 2    Signed 4-bit value, 4 values per uint16
+                                         * 3    Signed 8-bit value, 2 values per uint16
+                                         */
+  USHORT        deltaValue[VAR];        /* Array of compressed data */
+  public:
+  DEFINE_SIZE_ARRAY (6, deltaValue);
+};
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-layout-gdef-table.hh b/src/share/native/sun/font/harfbuzz/hb-ot-layout-gdef-table.hh
new file mode 100644
index 0000000..b77ce74
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-layout-gdef-table.hh
@@ -0,0 +1,443 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * Copyright © 2010,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_OT_LAYOUT_GDEF_TABLE_HH
+#define HB_OT_LAYOUT_GDEF_TABLE_HH
+
+#include "hb-ot-layout-common-private.hh"
+
+#include "hb-font-private.hh"
+
+
+namespace OT {
+
+
+/*
+ * Attachment List Table
+ */
+
+typedef ArrayOf<USHORT> AttachPoint;    /* Array of contour point indices--in
+                                         * increasing numerical order */
+
+struct AttachList
+{
+  inline unsigned int get_attach_points (hb_codepoint_t glyph_id,
+                                         unsigned int start_offset,
+                                         unsigned int *point_count /* IN/OUT */,
+                                         unsigned int *point_array /* OUT */) const
+  {
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
+    if (index == NOT_COVERED)
+    {
+      if (point_count)
+        *point_count = 0;
+      return 0;
+    }
+
+    const AttachPoint &points = this+attachPoint[index];
+
+    if (point_count) {
+      const USHORT *array = points.sub_array (start_offset, point_count);
+      unsigned int count = *point_count;
+      for (unsigned int i = 0; i < count; i++)
+        point_array[i] = array[i];
+    }
+
+    return points.len;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
+  }
+
+  protected:
+  OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table -- from
+                                         * beginning of AttachList table */
+  OffsetArrayOf<AttachPoint>
+                attachPoint;            /* Array of AttachPoint tables
+                                         * in Coverage Index order */
+  public:
+  DEFINE_SIZE_ARRAY (4, attachPoint);
+};
+
+/*
+ * Ligature Caret Table
+ */
+
+struct CaretValueFormat1
+{
+  friend struct CaretValue;
+
+  private:
+  inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id HB_UNUSED) const
+  {
+    return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  USHORT        caretValueFormat;       /* Format identifier--format = 1 */
+  SHORT         coordinate;             /* X or Y value, in design units */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+struct CaretValueFormat2
+{
+  friend struct CaretValue;
+
+  private:
+  inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
+  {
+    hb_position_t x, y;
+    if (font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y))
+      return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
+    else
+      return 0;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  USHORT        caretValueFormat;       /* Format identifier--format = 2 */
+  USHORT        caretValuePoint;        /* Contour point index on glyph */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+struct CaretValueFormat3
+{
+  friend struct CaretValue;
+
+  inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id HB_UNUSED) const
+  {
+    return HB_DIRECTION_IS_HORIZONTAL (direction) ?
+           font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font) :
+           font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
+  }
+
+  protected:
+  USHORT        caretValueFormat;       /* Format identifier--format = 3 */
+  SHORT         coordinate;             /* X or Y value, in design units */
+  OffsetTo<Device>
+                deviceTable;            /* Offset to Device table for X or Y
+                                         * value--from beginning of CaretValue
+                                         * table */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+struct CaretValue
+{
+  inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
+  {
+    switch (u.format) {
+    case 1: return u.format1.get_caret_value (font, direction, glyph_id);
+    case 2: return u.format2.get_caret_value (font, direction, glyph_id);
+    case 3: return u.format3.get_caret_value (font, direction, glyph_id);
+    default:return 0;
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.format.sanitize (c)) return_trace (false);
+    switch (u.format) {
+    case 1: return_trace (u.format1.sanitize (c));
+    case 2: return_trace (u.format2.sanitize (c));
+    case 3: return_trace (u.format3.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  protected:
+  union {
+  USHORT                format;         /* Format identifier */
+  CaretValueFormat1     format1;
+  CaretValueFormat2     format2;
+  CaretValueFormat3     format3;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+};
+
+struct LigGlyph
+{
+  inline unsigned int get_lig_carets (hb_font_t *font,
+                                      hb_direction_t direction,
+                                      hb_codepoint_t glyph_id,
+                                      unsigned int start_offset,
+                                      unsigned int *caret_count /* IN/OUT */,
+                                      hb_position_t *caret_array /* OUT */) const
+  {
+    if (caret_count) {
+      const OffsetTo<CaretValue> *array = carets.sub_array (start_offset, caret_count);
+      unsigned int count = *caret_count;
+      for (unsigned int i = 0; i < count; i++)
+        caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id);
+    }
+
+    return carets.len;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (carets.sanitize (c, this));
+  }
+
+  protected:
+  OffsetArrayOf<CaretValue>
+                carets;                 /* Offset array of CaretValue tables
+                                         * --from beginning of LigGlyph table
+                                         * --in increasing coordinate order */
+  public:
+  DEFINE_SIZE_ARRAY (2, carets);
+};
+
+struct LigCaretList
+{
+  inline unsigned int get_lig_carets (hb_font_t *font,
+                                      hb_direction_t direction,
+                                      hb_codepoint_t glyph_id,
+                                      unsigned int start_offset,
+                                      unsigned int *caret_count /* IN/OUT */,
+                                      hb_position_t *caret_array /* OUT */) const
+  {
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
+    if (index == NOT_COVERED)
+    {
+      if (caret_count)
+        *caret_count = 0;
+      return 0;
+    }
+    const LigGlyph &lig_glyph = this+ligGlyph[index];
+    return lig_glyph.get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
+  }
+
+  protected:
+  OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of LigCaretList table */
+  OffsetArrayOf<LigGlyph>
+                ligGlyph;               /* Array of LigGlyph tables
+                                         * in Coverage Index order */
+  public:
+  DEFINE_SIZE_ARRAY (4, ligGlyph);
+};
+
+
+struct MarkGlyphSetsFormat1
+{
+  inline bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
+  { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 1 */
+  ArrayOf<OffsetTo<Coverage, ULONG> >
+                coverage;               /* Array of long offsets to mark set
+                                         * coverage tables */
+  public:
+  DEFINE_SIZE_ARRAY (4, coverage);
+};
+
+struct MarkGlyphSets
+{
+  inline bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
+  {
+    switch (u.format) {
+    case 1: return u.format1.covers (set_index, glyph_id);
+    default:return false;
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.format.sanitize (c)) return_trace (false);
+    switch (u.format) {
+    case 1: return_trace (u.format1.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  protected:
+  union {
+  USHORT                format;         /* Format identifier */
+  MarkGlyphSetsFormat1  format1;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+};
+
+
+/*
+ * GDEF -- The Glyph Definition Table
+ */
+
+struct GDEF
+{
+  static const hb_tag_t tableTag        = HB_OT_TAG_GDEF;
+
+  enum GlyphClasses {
+    UnclassifiedGlyph   = 0,
+    BaseGlyph           = 1,
+    LigatureGlyph       = 2,
+    MarkGlyph           = 3,
+    ComponentGlyph      = 4
+  };
+
+  inline bool has_glyph_classes (void) const { return glyphClassDef != 0; }
+  inline unsigned int get_glyph_class (hb_codepoint_t glyph) const
+  { return (this+glyphClassDef).get_class (glyph); }
+  inline void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
+  { (this+glyphClassDef).add_class (glyphs, klass); }
+
+  inline bool has_mark_attachment_types (void) const { return markAttachClassDef != 0; }
+  inline unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
+  { return (this+markAttachClassDef).get_class (glyph); }
+
+  inline bool has_attach_points (void) const { return attachList != 0; }
+  inline unsigned int get_attach_points (hb_codepoint_t glyph_id,
+                                         unsigned int start_offset,
+                                         unsigned int *point_count /* IN/OUT */,
+                                         unsigned int *point_array /* OUT */) const
+  { return (this+attachList).get_attach_points (glyph_id, start_offset, point_count, point_array); }
+
+  inline bool has_lig_carets (void) const { return ligCaretList != 0; }
+  inline unsigned int get_lig_carets (hb_font_t *font,
+                                      hb_direction_t direction,
+                                      hb_codepoint_t glyph_id,
+                                      unsigned int start_offset,
+                                      unsigned int *caret_count /* IN/OUT */,
+                                      hb_position_t *caret_array /* OUT */) const
+  { return (this+ligCaretList).get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array); }
+
+  inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002u && markGlyphSetsDef[0] != 0; }
+  inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
+  { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (version.sanitize (c) &&
+                  likely (version.major == 1) &&
+                  glyphClassDef.sanitize (c, this) &&
+                  attachList.sanitize (c, this) &&
+                  ligCaretList.sanitize (c, this) &&
+                  markAttachClassDef.sanitize (c, this) &&
+                  (version.to_int () < 0x00010002u || markGlyphSetsDef[0].sanitize (c, this)));
+  }
+
+
+  /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
+   * glyph class and other bits, and high 8-bit gthe mark attachment type (if any).
+   * Not to be confused with lookup_props which is very similar. */
+  inline unsigned int get_glyph_props (hb_codepoint_t glyph) const
+  {
+    unsigned int klass = get_glyph_class (glyph);
+
+    ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs);
+    ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures);
+    ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks);
+
+    switch (klass) {
+    default:                    return 0;
+    case BaseGlyph:             return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
+    case LigatureGlyph:         return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
+    case MarkGlyph:
+          klass = get_mark_attachment_type (glyph);
+          return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
+    }
+  }
+
+
+  protected:
+  FixedVersion<>version;                /* Version of the GDEF table--currently
+                                         * 0x00010002u */
+  OffsetTo<ClassDef>
+                glyphClassDef;          /* Offset to class definition table
+                                         * for glyph type--from beginning of
+                                         * GDEF header (may be Null) */
+  OffsetTo<AttachList>
+                attachList;             /* Offset to list of glyphs with
+                                         * attachment points--from beginning
+                                         * of GDEF header (may be Null) */
+  OffsetTo<LigCaretList>
+                ligCaretList;           /* Offset to list of positioning points
+                                         * for ligature carets--from beginning
+                                         * of GDEF header (may be Null) */
+  OffsetTo<ClassDef>
+                markAttachClassDef;     /* Offset to class definition table for
+                                         * mark attachment type--from beginning
+                                         * of GDEF header (may be Null) */
+  OffsetTo<MarkGlyphSets>
+                markGlyphSetsDef[VAR];  /* Offset to the table of mark set
+                                         * definitions--from beginning of GDEF
+                                         * header (may be NULL).  Introduced
+                                         * in version 00010002. */
+  public:
+  DEFINE_SIZE_ARRAY (12, markGlyphSetsDef);
+};
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_LAYOUT_GDEF_TABLE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-layout-gpos-table.hh b/src/share/native/sun/font/harfbuzz/hb-ot-layout-gpos-table.hh
new file mode 100644
index 0000000..c065e17
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-layout-gpos-table.hh
@@ -0,0 +1,1657 @@
+/*
+ * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
+ * Copyright © 2010,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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_LAYOUT_GPOS_TABLE_HH
+#define HB_OT_LAYOUT_GPOS_TABLE_HH
+
+#include "hb-ot-layout-gsubgpos-private.hh"
+
+
+namespace OT {
+
+
+/* buffer **position** var allocations */
+#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
+#define attach_type() var.u8[2] /* attachment type */
+/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */
+
+enum attach_type_t {
+  ATTACH_TYPE_NONE      = 0X00,
+
+  /* Each attachment should be either a mark or a cursive; can't be both. */
+  ATTACH_TYPE_MARK      = 0X01,
+  ATTACH_TYPE_CURSIVE   = 0X02,
+};
+
+
+/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
+
+typedef USHORT Value;
+
+typedef Value ValueRecord[VAR];
+
+struct ValueFormat : USHORT
+{
+  enum Flags {
+    xPlacement  = 0x0001u,      /* Includes horizontal adjustment for placement */
+    yPlacement  = 0x0002u,      /* Includes vertical adjustment for placement */
+    xAdvance    = 0x0004u,      /* Includes horizontal adjustment for advance */
+    yAdvance    = 0x0008u,      /* Includes vertical adjustment for advance */
+    xPlaDevice  = 0x0010u,      /* Includes horizontal Device table for placement */
+    yPlaDevice  = 0x0020u,      /* Includes vertical Device table for placement */
+    xAdvDevice  = 0x0040u,      /* Includes horizontal Device table for advance */
+    yAdvDevice  = 0x0080u,      /* Includes vertical Device table for advance */
+    ignored     = 0x0F00u,      /* Was used in TrueType Open for MM fonts */
+    reserved    = 0xF000u,      /* For future use */
+
+    devices     = 0x00F0u       /* Mask for having any Device table */
+  };
+
+/* All fields are options.  Only those available advance the value pointer. */
+#if 0
+  SHORT         xPlacement;             /* Horizontal adjustment for
+                                         * placement--in design units */
+  SHORT         yPlacement;             /* Vertical adjustment for
+                                         * placement--in design units */
+  SHORT         xAdvance;               /* Horizontal adjustment for
+                                         * advance--in design units (only used
+                                         * for horizontal writing) */
+  SHORT         yAdvance;               /* Vertical adjustment for advance--in
+                                         * design units (only used for vertical
+                                         * writing) */
+  Offset        xPlaDevice;             /* Offset to Device table for
+                                         * horizontal placement--measured from
+                                         * beginning of PosTable (may be NULL) */
+  Offset        yPlaDevice;             /* Offset to Device table for vertical
+                                         * placement--measured from beginning
+                                         * of PosTable (may be NULL) */
+  Offset        xAdvDevice;             /* Offset to Device table for
+                                         * horizontal advance--measured from
+                                         * beginning of PosTable (may be NULL) */
+  Offset        yAdvDevice;             /* Offset to Device table for vertical
+                                         * advance--measured from beginning of
+                                         * PosTable (may be NULL) */
+#endif
+
+  inline unsigned int get_len (void) const
+  { return _hb_popcount32 ((unsigned int) *this); }
+  inline unsigned int get_size (void) const
+  { return get_len () * Value::static_size; }
+
+  void apply_value (hb_font_t            *font,
+                    hb_direction_t        direction,
+                    const void           *base,
+                    const Value          *values,
+                    hb_glyph_position_t  &glyph_pos) const
+  {
+    unsigned int x_ppem, y_ppem;
+    unsigned int format = *this;
+    hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction);
+
+    if (!format) return;
+
+    if (format & xPlacement) glyph_pos.x_offset  += font->em_scale_x (get_short (values++));
+    if (format & yPlacement) glyph_pos.y_offset  += font->em_scale_y (get_short (values++));
+    if (format & xAdvance) {
+      if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values));
+      values++;
+    }
+    /* y_advance values grow downward but font-space grows upward, hence negation */
+    if (format & yAdvance) {
+      if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values));
+      values++;
+    }
+
+    if (!has_device ()) return;
+
+    x_ppem = font->x_ppem;
+    y_ppem = font->y_ppem;
+
+    if (!x_ppem && !y_ppem) return;
+
+    /* pixel -> fractional pixel */
+    if (format & xPlaDevice) {
+      if (x_ppem) glyph_pos.x_offset  += (base + get_device (values)).get_x_delta (font);
+      values++;
+    }
+    if (format & yPlaDevice) {
+      if (y_ppem) glyph_pos.y_offset  += (base + get_device (values)).get_y_delta (font);
+      values++;
+    }
+    if (format & xAdvDevice) {
+      if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font);
+      values++;
+    }
+    if (format & yAdvDevice) {
+      /* y_advance values grow downward but font-space grows upward, hence negation */
+      if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font);
+      values++;
+    }
+  }
+
+  private:
+  inline bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
+  {
+    unsigned int format = *this;
+
+    if (format & xPlacement) values++;
+    if (format & yPlacement) values++;
+    if (format & xAdvance)   values++;
+    if (format & yAdvance)   values++;
+
+    if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
+    if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
+    if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
+    if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
+
+    return true;
+  }
+
+  static inline OffsetTo<Device>& get_device (Value* value)
+  { return *CastP<OffsetTo<Device> > (value); }
+  static inline const OffsetTo<Device>& get_device (const Value* value)
+  { return *CastP<OffsetTo<Device> > (value); }
+
+  static inline const SHORT& get_short (const Value* value)
+  { return *CastP<SHORT> (value); }
+
+  public:
+
+  inline bool has_device (void) const {
+    unsigned int format = *this;
+    return (format & devices) != 0;
+  }
+
+  inline bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
+  }
+
+  inline bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
+  {
+    TRACE_SANITIZE (this);
+    unsigned int len = get_len ();
+
+    if (!c->check_array (values, get_size (), count)) return_trace (false);
+
+    if (!has_device ()) return_trace (true);
+
+    for (unsigned int i = 0; i < count; i++) {
+      if (!sanitize_value_devices (c, base, values))
+        return_trace (false);
+      values += len;
+    }
+
+    return_trace (true);
+  }
+
+  /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
+  inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
+  {
+    TRACE_SANITIZE (this);
+
+    if (!has_device ()) return_trace (true);
+
+    for (unsigned int i = 0; i < count; i++) {
+      if (!sanitize_value_devices (c, base, values))
+        return_trace (false);
+      values += stride;
+    }
+
+    return_trace (true);
+  }
+};
+
+
+struct AnchorFormat1
+{
+  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
+                          hb_position_t *x, hb_position_t *y) const
+  {
+      *x = font->em_scale_x (xCoordinate);
+      *y = font->em_scale_y (yCoordinate);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 1 */
+  SHORT         xCoordinate;            /* Horizontal value--in design units */
+  SHORT         yCoordinate;            /* Vertical value--in design units */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+struct AnchorFormat2
+{
+  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
+                          hb_position_t *x, hb_position_t *y) const
+  {
+      unsigned int x_ppem = font->x_ppem;
+      unsigned int y_ppem = font->y_ppem;
+      hb_position_t cx, cy;
+      hb_bool_t ret;
+
+      ret = (x_ppem || y_ppem) &&
+             font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
+      *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
+      *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 2 */
+  SHORT         xCoordinate;            /* Horizontal value--in design units */
+  SHORT         yCoordinate;            /* Vertical value--in design units */
+  USHORT        anchorPoint;            /* Index to glyph contour point */
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+struct AnchorFormat3
+{
+  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
+                          hb_position_t *x, hb_position_t *y) const
+  {
+      *x = font->em_scale_x (xCoordinate);
+      *y = font->em_scale_y (yCoordinate);
+
+      if (font->x_ppem)
+        *x += (this+xDeviceTable).get_x_delta (font);
+      if (font->y_ppem)
+        *y += (this+yDeviceTable).get_x_delta (font);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 3 */
+  SHORT         xCoordinate;            /* Horizontal value--in design units */
+  SHORT         yCoordinate;            /* Vertical value--in design units */
+  OffsetTo<Device>
+                xDeviceTable;           /* Offset to Device table for X
+                                         * coordinate-- from beginning of
+                                         * Anchor table (may be NULL) */
+  OffsetTo<Device>
+                yDeviceTable;           /* Offset to Device table for Y
+                                         * coordinate-- from beginning of
+                                         * Anchor table (may be NULL) */
+  public:
+  DEFINE_SIZE_STATIC (10);
+};
+
+struct Anchor
+{
+  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
+                          hb_position_t *x, hb_position_t *y) const
+  {
+    *x = *y = 0;
+    switch (u.format) {
+    case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
+    case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
+    case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
+    default:                                             return;
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.format.sanitize (c)) return_trace (false);
+    switch (u.format) {
+    case 1: return_trace (u.format1.sanitize (c));
+    case 2: return_trace (u.format2.sanitize (c));
+    case 3: return_trace (u.format3.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  protected:
+  union {
+  USHORT                format;         /* Format identifier */
+  AnchorFormat1         format1;
+  AnchorFormat2         format2;
+  AnchorFormat3         format3;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+};
+
+
+struct AnchorMatrix
+{
+  inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const {
+    *found = false;
+    if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
+    *found = !matrixZ[row * cols + col].is_null ();
+    return this+matrixZ[row * cols + col];
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
+  {
+    TRACE_SANITIZE (this);
+    if (!c->check_struct (this)) return_trace (false);
+    if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return_trace (false);
+    unsigned int count = rows * cols;
+    if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false);
+    for (unsigned int i = 0; i < count; i++)
+      if (!matrixZ[i].sanitize (c, this)) return_trace (false);
+    return_trace (true);
+  }
+
+  USHORT        rows;                   /* Number of rows */
+  protected:
+  OffsetTo<Anchor>
+                matrixZ[VAR];           /* Matrix of offsets to Anchor tables--
+                                         * from beginning of AnchorMatrix table */
+  public:
+  DEFINE_SIZE_ARRAY (2, matrixZ);
+};
+
+
+struct MarkRecord
+{
+  friend struct MarkArray;
+
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
+  }
+
+  protected:
+  USHORT        klass;                  /* Class defined for this mark */
+  OffsetTo<Anchor>
+                markAnchor;             /* Offset to Anchor table--from
+                                         * beginning of MarkArray table */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+struct MarkArray : ArrayOf<MarkRecord>  /* Array of MarkRecords--in Coverage order */
+{
+  inline bool apply (hb_apply_context_t *c,
+                     unsigned int mark_index, unsigned int glyph_index,
+                     const AnchorMatrix &anchors, unsigned int class_count,
+                     unsigned int glyph_pos) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
+    unsigned int mark_class = record.klass;
+
+    const Anchor& mark_anchor = this + record.markAnchor;
+    bool found;
+    const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
+    /* If this subtable doesn't have an anchor for this base and this class,
+     * return false such that the subsequent subtables have a chance at it. */
+    if (unlikely (!found)) return_trace (false);
+
+    hb_position_t mark_x, mark_y, base_x, base_y;
+
+    mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y);
+    glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
+
+    hb_glyph_position_t &o = buffer->cur_pos();
+    o.x_offset = base_x - mark_x;
+    o.y_offset = base_y - mark_y;
+    o.attach_type() = ATTACH_TYPE_MARK;
+    o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
+    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
+
+    buffer->idx++;
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (ArrayOf<MarkRecord>::sanitize (c, this));
+  }
+};
+
+
+/* Lookups */
+
+struct SinglePosFormat1
+{
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    valueFormat.apply_value (c->font, c->direction, this,
+                             values, buffer->cur_pos());
+
+    buffer->idx++;
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  coverage.sanitize (c, this) &&
+                  valueFormat.sanitize_value (c, this, values));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 1 */
+  OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of subtable */
+  ValueFormat   valueFormat;            /* Defines the types of data in the
+                                         * ValueRecord */
+  ValueRecord   values;                 /* Defines positioning
+                                         * value(s)--applied to all glyphs in
+                                         * the Coverage table */
+  public:
+  DEFINE_SIZE_ARRAY (6, values);
+};
+
+struct SinglePosFormat2
+{
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    if (likely (index >= valueCount)) return_trace (false);
+
+    valueFormat.apply_value (c->font, c->direction, this,
+                             &values[index * valueFormat.get_len ()],
+                             buffer->cur_pos());
+
+    buffer->idx++;
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  coverage.sanitize (c, this) &&
+                  valueFormat.sanitize_values (c, this, values, valueCount));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 2 */
+  OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of subtable */
+  ValueFormat   valueFormat;            /* Defines the types of data in the
+                                         * ValueRecord */
+  USHORT        valueCount;             /* Number of ValueRecords */
+  ValueRecord   values;                 /* Array of ValueRecords--positioning
+                                         * values applied to glyphs */
+  public:
+  DEFINE_SIZE_ARRAY (8, values);
+};
+
+struct SinglePos
+{
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1));
+    case 2: return_trace (c->dispatch (u.format2));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  USHORT                format;         /* Format identifier */
+  SinglePosFormat1      format1;
+  SinglePosFormat2      format2;
+  } u;
+};
+
+
+struct PairValueRecord
+{
+  friend struct PairSet;
+
+  protected:
+  GlyphID       secondGlyph;            /* GlyphID of second glyph in the
+                                         * pair--first glyph is listed in the
+                                         * Coverage table */
+  ValueRecord   values;                 /* Positioning data for the first glyph
+                                         * followed by for second glyph */
+  public:
+  DEFINE_SIZE_ARRAY (2, values);
+};
+
+struct PairSet
+{
+  friend struct PairPosFormat1;
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c,
+                              const ValueFormat *valueFormats) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int len1 = valueFormats[0].get_len ();
+    unsigned int len2 = valueFormats[1].get_len ();
+    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
+
+    const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
+    unsigned int count = len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      c->input->add (record->secondGlyph);
+      record = &StructAtOffset<PairValueRecord> (record, record_size);
+    }
+  }
+
+  inline bool apply (hb_apply_context_t *c,
+                     const ValueFormat *valueFormats,
+                     unsigned int pos) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int len1 = valueFormats[0].get_len ();
+    unsigned int len2 = valueFormats[1].get_len ();
+    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
+
+    const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ);
+    unsigned int count = len;
+
+    /* Hand-coded bsearch. */
+    if (unlikely (!count))
+      return_trace (false);
+    hb_codepoint_t x = buffer->info[pos].codepoint;
+    int min = 0, max = (int) count - 1;
+    while (min <= max)
+    {
+      int mid = (min + max) / 2;
+      const PairValueRecord *record = &StructAtOffset<PairValueRecord> (record_array, record_size * mid);
+      hb_codepoint_t mid_x = record->secondGlyph;
+      if (x < mid_x)
+        max = mid - 1;
+      else if (x > mid_x)
+        min = mid + 1;
+      else
+      {
+        valueFormats[0].apply_value (c->font, c->direction, this,
+                                     &record->values[0], buffer->cur_pos());
+        valueFormats[1].apply_value (c->font, c->direction, this,
+                                     &record->values[len1], buffer->pos[pos]);
+        if (len2)
+          pos++;
+        buffer->idx = pos;
+        return_trace (true);
+      }
+    }
+
+    return_trace (false);
+  }
+
+  struct sanitize_closure_t {
+    const void *base;
+    const ValueFormat *valueFormats;
+    unsigned int len1; /* valueFormats[0].get_len() */
+    unsigned int stride; /* 1 + len1 + len2 */
+  };
+
+  inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
+  {
+    TRACE_SANITIZE (this);
+    if (!(c->check_struct (this)
+       && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return_trace (false);
+
+    unsigned int count = len;
+    const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
+    return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) &&
+                  closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
+  }
+
+  protected:
+  USHORT        len;                    /* Number of PairValueRecords */
+  USHORT        arrayZ[VAR];            /* Array of PairValueRecords--ordered
+                                         * by GlyphID of the second glyph */
+  public:
+  DEFINE_SIZE_ARRAY (2, arrayZ);
+};
+
+struct PairPosFormat1
+{
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+    unsigned int count = pairSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
+    if (!skippy_iter.next ()) return_trace (false);
+
+    return_trace ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+
+    if (!c->check_struct (this)) return_trace (false);
+
+    unsigned int len1 = valueFormat1.get_len ();
+    unsigned int len2 = valueFormat2.get_len ();
+    PairSet::sanitize_closure_t closure = {
+      this,
+      &valueFormat1,
+      len1,
+      1 + len1 + len2
+    };
+
+    return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 1 */
+  OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of subtable */
+  ValueFormat   valueFormat1;           /* Defines the types of data in
+                                         * ValueRecord1--for the first glyph
+                                         * in the pair--may be zero (0) */
+  ValueFormat   valueFormat2;           /* Defines the types of data in
+                                         * ValueRecord2--for the second glyph
+                                         * in the pair--may be zero (0) */
+  OffsetArrayOf<PairSet>
+                pairSet;                /* Array of PairSet tables
+                                         * ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_ARRAY (10, pairSet);
+};
+
+struct PairPosFormat2
+{
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+
+    unsigned int count1 = class1Count;
+    const ClassDef &klass1 = this+classDef1;
+    for (unsigned int i = 0; i < count1; i++)
+      klass1.add_class (c->input, i);
+
+    unsigned int count2 = class2Count;
+    const ClassDef &klass2 = this+classDef2;
+    for (unsigned int i = 0; i < count2; i++)
+      klass2.add_class (c->input, i);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
+    if (!skippy_iter.next ()) return_trace (false);
+
+    unsigned int len1 = valueFormat1.get_len ();
+    unsigned int len2 = valueFormat2.get_len ();
+    unsigned int record_len = len1 + len2;
+
+    unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
+    unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
+    if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false);
+
+    const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
+    valueFormat1.apply_value (c->font, c->direction, this,
+                              v, buffer->cur_pos());
+    valueFormat2.apply_value (c->font, c->direction, this,
+                              v + len1, buffer->pos[skippy_iter.idx]);
+
+    buffer->idx = skippy_iter.idx;
+    if (len2)
+      buffer->idx++;
+
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!(c->check_struct (this)
+       && coverage.sanitize (c, this)
+       && classDef1.sanitize (c, this)
+       && classDef2.sanitize (c, this))) return_trace (false);
+
+    unsigned int len1 = valueFormat1.get_len ();
+    unsigned int len2 = valueFormat2.get_len ();
+    unsigned int stride = len1 + len2;
+    unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
+    unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
+    return_trace (c->check_array (values, record_size, count) &&
+                  valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
+                  valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 2 */
+  OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of subtable */
+  ValueFormat   valueFormat1;           /* ValueRecord definition--for the
+                                         * first glyph of the pair--may be zero
+                                         * (0) */
+  ValueFormat   valueFormat2;           /* ValueRecord definition--for the
+                                         * second glyph of the pair--may be
+                                         * zero (0) */
+  OffsetTo<ClassDef>
+                classDef1;              /* Offset to ClassDef table--from
+                                         * beginning of PairPos subtable--for
+                                         * the first glyph of the pair */
+  OffsetTo<ClassDef>
+                classDef2;              /* Offset to ClassDef table--from
+                                         * beginning of PairPos subtable--for
+                                         * the second glyph of the pair */
+  USHORT        class1Count;            /* Number of classes in ClassDef1
+                                         * table--includes Class0 */
+  USHORT        class2Count;            /* Number of classes in ClassDef2
+                                         * table--includes Class0 */
+  ValueRecord   values;                 /* Matrix of value pairs:
+                                         * class1-major, class2-minor,
+                                         * Each entry has value1 and value2 */
+  public:
+  DEFINE_SIZE_ARRAY (16, values);
+};
+
+struct PairPos
+{
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1));
+    case 2: return_trace (c->dispatch (u.format2));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  USHORT                format;         /* Format identifier */
+  PairPosFormat1        format1;
+  PairPosFormat2        format2;
+  } u;
+};
+
+
+struct EntryExitRecord
+{
+  friend struct CursivePosFormat1;
+
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
+  }
+
+  protected:
+  OffsetTo<Anchor>
+                entryAnchor;            /* Offset to EntryAnchor table--from
+                                         * beginning of CursivePos
+                                         * subtable--may be NULL */
+  OffsetTo<Anchor>
+                exitAnchor;             /* Offset to ExitAnchor table--from
+                                         * beginning of CursivePos
+                                         * subtable--may be NULL */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+static void
+reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent);
+
+struct CursivePosFormat1
+{
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+
+    const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
+    if (!this_record.exitAnchor) return_trace (false);
+
+    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
+    if (!skippy_iter.next ()) return_trace (false);
+
+    const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
+    if (!next_record.entryAnchor) return_trace (false);
+
+    unsigned int i = buffer->idx;
+    unsigned int j = skippy_iter.idx;
+
+    hb_position_t entry_x, entry_y, exit_x, exit_y;
+    (this+this_record.exitAnchor).get_anchor (c->font, buffer->info[i].codepoint, &exit_x, &exit_y);
+    (this+next_record.entryAnchor).get_anchor (c->font, buffer->info[j].codepoint, &entry_x, &entry_y);
+
+    hb_glyph_position_t *pos = buffer->pos;
+
+    hb_position_t d;
+    /* Main-direction adjustment */
+    switch (c->direction) {
+      case HB_DIRECTION_LTR:
+        pos[i].x_advance  =  exit_x + pos[i].x_offset;
+
+        d = entry_x + pos[j].x_offset;
+        pos[j].x_advance -= d;
+        pos[j].x_offset  -= d;
+        break;
+      case HB_DIRECTION_RTL:
+        d = exit_x + pos[i].x_offset;
+        pos[i].x_advance -= d;
+        pos[i].x_offset  -= d;
+
+        pos[j].x_advance  =  entry_x + pos[j].x_offset;
+        break;
+      case HB_DIRECTION_TTB:
+        pos[i].y_advance  =  exit_y + pos[i].y_offset;
+
+        d = entry_y + pos[j].y_offset;
+        pos[j].y_advance -= d;
+        pos[j].y_offset  -= d;
+        break;
+      case HB_DIRECTION_BTT:
+        d = exit_y + pos[i].y_offset;
+        pos[i].y_advance -= d;
+        pos[i].y_offset  -= d;
+
+        pos[j].y_advance  =  entry_y;
+        break;
+      case HB_DIRECTION_INVALID:
+      default:
+        break;
+    }
+
+    /* Cross-direction adjustment */
+
+    /* We attach child to parent (think graph theory and rooted trees whereas
+     * the root stays on baseline and each node aligns itself against its
+     * parent.
+     *
+     * Optimize things for the case of RightToLeft, as that's most common in
+     * Arabinc. */
+    unsigned int child  = i;
+    unsigned int parent = j;
+    hb_position_t x_offset = entry_x - exit_x;
+    hb_position_t y_offset = entry_y - exit_y;
+    if  (!(c->lookup_props & LookupFlag::RightToLeft))
+    {
+      unsigned int k = child;
+      child = parent;
+      parent = k;
+      x_offset = -x_offset;
+      y_offset = -y_offset;
+    }
+
+    /* If child was already connected to someone else, walk through its old
+     * chain and reverse the link direction, such that the whole tree of its
+     * previous connection now attaches to new parent.  Watch out for case
+     * where new parent is on the path from old chain...
+     */
+    reverse_cursive_minor_offset (pos, child, c->direction, parent);
+
+    pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
+    pos[child].attach_chain() = (int) parent - (int) child;
+    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
+      pos[child].y_offset = y_offset;
+    else
+      pos[child].x_offset = x_offset;
+
+    buffer->idx = j;
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 1 */
+  OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of subtable */
+  ArrayOf<EntryExitRecord>
+                entryExitRecord;        /* Array of EntryExit records--in
+                                         * Coverage Index order */
+  public:
+  DEFINE_SIZE_ARRAY (6, entryExitRecord);
+};
+
+struct CursivePos
+{
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  USHORT                format;         /* Format identifier */
+  CursivePosFormat1     format1;
+  } u;
+};
+
+
+typedef AnchorMatrix BaseArray;         /* base-major--
+                                         * in order of BaseCoverage Index--,
+                                         * mark-minor--
+                                         * ordered by class--zero-based. */
+
+struct MarkBasePosFormat1
+{
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+markCoverage).add_coverage (c->input);
+    (this+baseCoverage).add_coverage (c->input);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+markCoverage;
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (mark_index == NOT_COVERED)) return_trace (false);
+
+    /* Now we search backwards for a non-mark glyph */
+    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
+    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
+    do {
+      if (!skippy_iter.prev ()) return_trace (false);
+      /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
+      if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
+      skippy_iter.reject ();
+    } while (1);
+
+    /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
+    //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); }
+
+    unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
+    if (base_index == NOT_COVERED) return_trace (false);
+
+    return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  markCoverage.sanitize (c, this) &&
+                  baseCoverage.sanitize (c, this) &&
+                  markArray.sanitize (c, this) &&
+                  baseArray.sanitize (c, this, (unsigned int) classCount));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 1 */
+  OffsetTo<Coverage>
+                markCoverage;           /* Offset to MarkCoverage table--from
+                                         * beginning of MarkBasePos subtable */
+  OffsetTo<Coverage>
+                baseCoverage;           /* Offset to BaseCoverage table--from
+                                         * beginning of MarkBasePos subtable */
+  USHORT        classCount;             /* Number of classes defined for marks */
+  OffsetTo<MarkArray>
+                markArray;              /* Offset to MarkArray table--from
+                                         * beginning of MarkBasePos subtable */
+  OffsetTo<BaseArray>
+                baseArray;              /* Offset to BaseArray table--from
+                                         * beginning of MarkBasePos subtable */
+  public:
+  DEFINE_SIZE_STATIC (12);
+};
+
+struct MarkBasePos
+{
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  USHORT                format;         /* Format identifier */
+  MarkBasePosFormat1    format1;
+  } u;
+};
+
+
+typedef AnchorMatrix LigatureAttach;    /* component-major--
+                                         * in order of writing direction--,
+                                         * mark-minor--
+                                         * ordered by class--zero-based. */
+
+typedef OffsetListOf<LigatureAttach> LigatureArray;
+                                        /* Array of LigatureAttach
+                                         * tables ordered by
+                                         * LigatureCoverage Index */
+
+struct MarkLigPosFormat1
+{
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+markCoverage).add_coverage (c->input);
+    (this+ligatureCoverage).add_coverage (c->input);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+markCoverage;
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (mark_index == NOT_COVERED)) return_trace (false);
+
+    /* Now we search backwards for a non-mark glyph */
+    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
+    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
+    if (!skippy_iter.prev ()) return_trace (false);
+
+    /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
+    //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
+
+    unsigned int j = skippy_iter.idx;
+    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
+    if (lig_index == NOT_COVERED) return_trace (false);
+
+    const LigatureArray& lig_array = this+ligatureArray;
+    const LigatureAttach& lig_attach = lig_array[lig_index];
+
+    /* Find component to attach to */
+    unsigned int comp_count = lig_attach.rows;
+    if (unlikely (!comp_count)) return_trace (false);
+
+    /* We must now check whether the ligature ID of the current mark glyph
+     * is identical to the ligature ID of the found ligature.  If yes, we
+     * can directly use the component index.  If not, we attach the mark
+     * glyph to the last component of the ligature. */
+    unsigned int comp_index;
+    unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
+    unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+    unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
+    if (lig_id && lig_id == mark_id && mark_comp > 0)
+      comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
+    else
+      comp_index = comp_count - 1;
+
+    return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  markCoverage.sanitize (c, this) &&
+                  ligatureCoverage.sanitize (c, this) &&
+                  markArray.sanitize (c, this) &&
+                  ligatureArray.sanitize (c, this, (unsigned int) classCount));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 1 */
+  OffsetTo<Coverage>
+                markCoverage;           /* Offset to Mark Coverage table--from
+                                         * beginning of MarkLigPos subtable */
+  OffsetTo<Coverage>
+                ligatureCoverage;       /* Offset to Ligature Coverage
+                                         * table--from beginning of MarkLigPos
+                                         * subtable */
+  USHORT        classCount;             /* Number of defined mark classes */
+  OffsetTo<MarkArray>
+                markArray;              /* Offset to MarkArray table--from
+                                         * beginning of MarkLigPos subtable */
+  OffsetTo<LigatureArray>
+                ligatureArray;          /* Offset to LigatureArray table--from
+                                         * beginning of MarkLigPos subtable */
+  public:
+  DEFINE_SIZE_STATIC (12);
+};
+
+struct MarkLigPos
+{
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  USHORT                format;         /* Format identifier */
+  MarkLigPosFormat1     format1;
+  } u;
+};
+
+
+typedef AnchorMatrix Mark2Array;        /* mark2-major--
+                                         * in order of Mark2Coverage Index--,
+                                         * mark1-minor--
+                                         * ordered by class--zero-based. */
+
+struct MarkMarkPosFormat1
+{
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+mark1Coverage).add_coverage (c->input);
+    (this+mark2Coverage).add_coverage (c->input);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+mark1Coverage;
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (mark1_index == NOT_COVERED)) return_trace (false);
+
+    /* now we search backwards for a suitable mark glyph until a non-mark glyph */
+    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
+    skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
+    if (!skippy_iter.prev ()) return_trace (false);
+
+    if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return_trace (false); }
+
+    unsigned int j = skippy_iter.idx;
+
+    unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
+    unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
+    unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
+    unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
+
+    if (likely (id1 == id2)) {
+      if (id1 == 0) /* Marks belonging to the same base. */
+        goto good;
+      else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
+        goto good;
+    } else {
+      /* If ligature ids don't match, it may be the case that one of the marks
+       * itself is a ligature.  In which case match. */
+      if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
+        goto good;
+    }
+
+    /* Didn't match. */
+    return_trace (false);
+
+    good:
+    unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
+    if (mark2_index == NOT_COVERED) return_trace (false);
+
+    return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  mark1Coverage.sanitize (c, this) &&
+                  mark2Coverage.sanitize (c, this) &&
+                  mark1Array.sanitize (c, this) &&
+                  mark2Array.sanitize (c, this, (unsigned int) classCount));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 1 */
+  OffsetTo<Coverage>
+                mark1Coverage;          /* Offset to Combining Mark1 Coverage
+                                         * table--from beginning of MarkMarkPos
+                                         * subtable */
+  OffsetTo<Coverage>
+                mark2Coverage;          /* Offset to Combining Mark2 Coverage
+                                         * table--from beginning of MarkMarkPos
+                                         * subtable */
+  USHORT        classCount;             /* Number of defined mark classes */
+  OffsetTo<MarkArray>
+                mark1Array;             /* Offset to Mark1Array table--from
+                                         * beginning of MarkMarkPos subtable */
+  OffsetTo<Mark2Array>
+                mark2Array;             /* Offset to Mark2Array table--from
+                                         * beginning of MarkMarkPos subtable */
+  public:
+  DEFINE_SIZE_STATIC (12);
+};
+
+struct MarkMarkPos
+{
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  USHORT                format;         /* Format identifier */
+  MarkMarkPosFormat1    format1;
+  } u;
+};
+
+
+struct ContextPos : Context {};
+
+struct ChainContextPos : ChainContext {};
+
+struct ExtensionPos : Extension<ExtensionPos>
+{
+  typedef struct PosLookupSubTable LookupSubTable;
+};
+
+
+
+/*
+ * PosLookup
+ */
+
+
+struct PosLookupSubTable
+{
+  friend struct PosLookup;
+
+  enum Type {
+    Single              = 1,
+    Pair                = 2,
+    Cursive             = 3,
+    MarkBase            = 4,
+    MarkLig             = 5,
+    MarkMark            = 6,
+    Context             = 7,
+    ChainContext        = 8,
+    Extension           = 9
+  };
+
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
+  {
+    TRACE_DISPATCH (this, lookup_type);
+    if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
+    switch (lookup_type) {
+    case Single:                return_trace (u.single.dispatch (c));
+    case Pair:                  return_trace (u.pair.dispatch (c));
+    case Cursive:               return_trace (u.cursive.dispatch (c));
+    case MarkBase:              return_trace (u.markBase.dispatch (c));
+    case MarkLig:               return_trace (u.markLig.dispatch (c));
+    case MarkMark:              return_trace (u.markMark.dispatch (c));
+    case Context:               return_trace (u.context.dispatch (c));
+    case ChainContext:          return_trace (u.chainContext.dispatch (c));
+    case Extension:             return_trace (u.extension.dispatch (c));
+    default:                    return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  USHORT                sub_format;
+  SinglePos             single;
+  PairPos               pair;
+  CursivePos            cursive;
+  MarkBasePos           markBase;
+  MarkLigPos            markLig;
+  MarkMarkPos           markMark;
+  ContextPos            context;
+  ChainContextPos       chainContext;
+  ExtensionPos          extension;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, sub_format);
+};
+
+
+struct PosLookup : Lookup
+{
+  inline const PosLookupSubTable& get_subtable (unsigned int i) const
+  { return Lookup::get_subtable<PosLookupSubTable> (i); }
+
+  inline bool is_reverse (void) const
+  {
+    return false;
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    return_trace (dispatch (c));
+  }
+
+  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    return_trace (dispatch (c));
+  }
+
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const
+  {
+    hb_add_coverage_context_t<set_t> c (glyphs);
+    dispatch (&c);
+  }
+
+  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
+
+  template <typename context_t>
+  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
+
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  { return Lookup::dispatch<PosLookupSubTable> (c); }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!Lookup::sanitize (c))) return_trace (false);
+    return_trace (dispatch (c));
+  }
+};
+
+typedef OffsetListOf<PosLookup> PosLookupList;
+
+/*
+ * GPOS -- The Glyph Positioning Table
+ */
+
+struct GPOS : GSUBGPOS
+{
+  static const hb_tag_t tableTag        = HB_OT_TAG_GPOS;
+
+  inline const PosLookup& get_lookup (unsigned int i) const
+  { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
+
+  static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
+  static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
+  static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
+    const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
+    return_trace (list.sanitize (c, this));
+  }
+  public:
+  DEFINE_SIZE_STATIC (10);
+};
+
+
+static void
+reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
+{
+  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
+  if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
+    return;
+
+  pos[i].attach_chain() = 0;
+
+  unsigned int j = (int) i + chain;
+
+  /* Stop if we see new parent in the chain. */
+  if (j == new_parent)
+    return;
+
+  reverse_cursive_minor_offset (pos, j, direction, new_parent);
+
+  if (HB_DIRECTION_IS_HORIZONTAL (direction))
+    pos[j].y_offset = -pos[i].y_offset;
+  else
+    pos[j].x_offset = -pos[i].x_offset;
+
+  pos[j].attach_chain() = -chain;
+  pos[j].attach_type() = type;
+}
+static void
+propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
+{
+  /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
+   * offset of glyph they are attached to. */
+  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
+  if (likely (!chain))
+    return;
+
+  unsigned int j = (int) i + chain;
+
+  pos[i].attach_chain() = 0;
+
+  propagate_attachment_offsets (pos, j, direction);
+
+  assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE));
+
+  if (type & ATTACH_TYPE_CURSIVE)
+  {
+    if (HB_DIRECTION_IS_HORIZONTAL (direction))
+      pos[i].y_offset += pos[j].y_offset;
+    else
+      pos[i].x_offset += pos[j].x_offset;
+  }
+  else /*if (type & ATTACH_TYPE_MARK)*/
+  {
+    pos[i].x_offset += pos[j].x_offset;
+    pos[i].y_offset += pos[j].y_offset;
+
+    assert (j < i);
+    if (HB_DIRECTION_IS_FORWARD (direction))
+      for (unsigned int k = j; k < i; k++) {
+        pos[i].x_offset -= pos[k].x_advance;
+        pos[i].y_offset -= pos[k].y_advance;
+      }
+    else
+      for (unsigned int k = j + 1; k < i + 1; k++) {
+        pos[i].x_offset += pos[k].x_advance;
+        pos[i].y_offset += pos[k].y_advance;
+      }
+  }
+}
+
+void
+GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
+{
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+    buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
+}
+
+void
+GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
+{
+  //_hb_buffer_assert_gsubgpos_vars (buffer);
+}
+
+void
+GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
+{
+  _hb_buffer_assert_gsubgpos_vars (buffer);
+
+  unsigned int len;
+  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
+  hb_direction_t direction = buffer->props.direction;
+
+  /* Handle attachments */
+  if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
+    for (unsigned int i = 0; i < len; i++)
+      propagate_attachment_offsets (pos, i, direction);
+}
+
+
+/* Out-of-class implementation for methods recursing */
+
+template <typename context_t>
+/*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
+{
+  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
+  const PosLookup &l = gpos.get_lookup (lookup_index);
+  return l.dispatch (c);
+}
+
+/*static*/ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
+{
+  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
+  const PosLookup &l = gpos.get_lookup (lookup_index);
+  unsigned int saved_lookup_props = c->lookup_props;
+  unsigned int saved_lookup_index = c->lookup_index;
+  c->set_lookup_index (lookup_index);
+  c->set_lookup_props (l.get_props ());
+  bool ret = l.dispatch (c);
+  c->set_lookup_index (saved_lookup_index);
+  c->set_lookup_props (saved_lookup_props);
+  return ret;
+}
+
+
+#undef attach_chain
+#undef attach_type
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-layout-gsub-table.hh b/src/share/native/sun/font/harfbuzz/hb-ot-layout-gsub-table.hh
new file mode 100644
index 0000000..44dcd12
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-layout-gsub-table.hh
@@ -0,0 +1,1351 @@
+/*
+ * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
+ * Copyright © 2010,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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
+#define HB_OT_LAYOUT_GSUB_TABLE_HH
+
+#include "hb-ot-layout-gsubgpos-private.hh"
+
+
+namespace OT {
+
+
+struct SingleSubstFormat1
+{
+  inline void closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      hb_codepoint_t glyph_id = iter.get_glyph ();
+      if (c->glyphs->has (glyph_id))
+        c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
+    }
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      hb_codepoint_t glyph_id = iter.get_glyph ();
+      c->input->add (glyph_id);
+      c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
+    }
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    /* According to the Adobe Annotated OpenType Suite, result is always
+     * limited to 16bit. */
+    glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
+    c->replace_glyph (glyph_id);
+
+    return_trace (true);
+  }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                         Supplier<GlyphID> &glyphs,
+                         unsigned int num_glyphs,
+                         int delta)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
+    deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 1 */
+  OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of Substitution table */
+  SHORT         deltaGlyphID;           /* Add to original GlyphID to get
+                                         * substitute GlyphID */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+struct SingleSubstFormat2
+{
+  inline void closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      if (c->glyphs->has (iter.get_glyph ()))
+        c->glyphs->add (substitute[iter.get_coverage ()]);
+    }
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      c->input->add (iter.get_glyph ());
+      c->output->add (substitute[iter.get_coverage ()]);
+    }
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    if (unlikely (index >= substitute.len)) return_trace (false);
+
+    glyph_id = substitute[index];
+    c->replace_glyph (glyph_id);
+
+    return_trace (true);
+  }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                         Supplier<GlyphID> &glyphs,
+                         Supplier<GlyphID> &substitutes,
+                         unsigned int num_glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return_trace (false);
+    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 2 */
+  OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of Substitution table */
+  ArrayOf<GlyphID>
+                substitute;             /* Array of substitute
+                                         * GlyphIDs--ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_ARRAY (6, substitute);
+};
+
+struct SingleSubst
+{
+  inline bool serialize (hb_serialize_context_t *c,
+                         Supplier<GlyphID> &glyphs,
+                         Supplier<GlyphID> &substitutes,
+                         unsigned int num_glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (u.format))) return_trace (false);
+    unsigned int format = 2;
+    int delta = 0;
+    if (num_glyphs) {
+      format = 1;
+      /* TODO(serialize) check for wrap-around */
+      delta = substitutes[0] - glyphs[0];
+      for (unsigned int i = 1; i < num_glyphs; i++)
+        if (delta != substitutes[i] - glyphs[i]) {
+          format = 2;
+          break;
+        }
+    }
+    u.format.set (format);
+    switch (u.format) {
+    case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs, delta));
+    case 2: return_trace (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
+    default:return_trace (false);
+    }
+  }
+
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1));
+    case 2: return_trace (c->dispatch (u.format2));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  USHORT                format;         /* Format identifier */
+  SingleSubstFormat1    format1;
+  SingleSubstFormat2    format2;
+  } u;
+};
+
+
+struct Sequence
+{
+  inline void closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    unsigned int count = substitute.len;
+    for (unsigned int i = 0; i < count; i++)
+      c->glyphs->add (substitute[i]);
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int count = substitute.len;
+    for (unsigned int i = 0; i < count; i++)
+      c->output->add (substitute[i]);
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int count = substitute.len;
+
+    /* Special-case to make it in-place and not consider this
+     * as a "multiplied" substitution. */
+    if (unlikely (count == 1))
+    {
+      c->replace_glyph (substitute.array[0]);
+      return_trace (true);
+    }
+    /* Spec disallows this, but Uniscribe allows it.
+     * https://github.com/behdad/harfbuzz/issues/253 */
+    else if (unlikely (count == 0))
+    {
+      c->buffer->delete_glyph ();
+      return_trace (true);
+    }
+
+    unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
+                         HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
+
+    for (unsigned int i = 0; i < count; i++) {
+      _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
+      c->output_glyph_for_component (substitute.array[i], klass);
+    }
+    c->buffer->skip_glyph ();
+
+    return_trace (true);
+  }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                         Supplier<GlyphID> &glyphs,
+                         unsigned int num_glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false);
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (substitute.sanitize (c));
+  }
+
+  protected:
+  ArrayOf<GlyphID>
+                substitute;             /* String of GlyphIDs to substitute */
+  public:
+  DEFINE_SIZE_ARRAY (2, substitute);
+};
+
+struct MultipleSubstFormat1
+{
+  inline void closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      if (c->glyphs->has (iter.get_glyph ()))
+        (this+sequence[iter.get_coverage ()]).closure (c);
+    }
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+    unsigned int count = sequence.len;
+    for (unsigned int i = 0; i < count; i++)
+        (this+sequence[i]).collect_glyphs (c);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    return_trace ((this+sequence[index]).apply (c));
+  }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                         Supplier<GlyphID> &glyphs,
+                         Supplier<unsigned int> &substitute_len_list,
+                         unsigned int num_glyphs,
+                         Supplier<GlyphID> &substitute_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false);
+    for (unsigned int i = 0; i < num_glyphs; i++)
+      if (unlikely (!sequence[i].serialize (c, this).serialize (c,
+                                                                substitute_glyphs_list,
+                                                                substitute_len_list[i]))) return_trace (false);
+    substitute_len_list.advance (num_glyphs);
+    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 1 */
+  OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of Substitution table */
+  OffsetArrayOf<Sequence>
+                sequence;               /* Array of Sequence tables
+                                         * ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_ARRAY (6, sequence);
+};
+
+struct MultipleSubst
+{
+  inline bool serialize (hb_serialize_context_t *c,
+                         Supplier<GlyphID> &glyphs,
+                         Supplier<unsigned int> &substitute_len_list,
+                         unsigned int num_glyphs,
+                         Supplier<GlyphID> &substitute_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (u.format))) return_trace (false);
+    unsigned int format = 1;
+    u.format.set (format);
+    switch (u.format) {
+    case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
+    default:return_trace (false);
+    }
+  }
+
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  USHORT                format;         /* Format identifier */
+  MultipleSubstFormat1  format1;
+  } u;
+};
+
+
+typedef ArrayOf<GlyphID> AlternateSet;  /* Array of alternate GlyphIDs--in
+                                         * arbitrary order */
+
+struct AlternateSubstFormat1
+{
+  inline void closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      if (c->glyphs->has (iter.get_glyph ())) {
+        const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
+        unsigned int count = alt_set.len;
+        for (unsigned int i = 0; i < count; i++)
+          c->glyphs->add (alt_set[i]);
+      }
+    }
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      c->input->add (iter.get_glyph ());
+      const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
+      unsigned int count = alt_set.len;
+      for (unsigned int i = 0; i < count; i++)
+        c->output->add (alt_set[i]);
+    }
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
+
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    const AlternateSet &alt_set = this+alternateSet[index];
+
+    if (unlikely (!alt_set.len)) return_trace (false);
+
+    hb_mask_t glyph_mask = c->buffer->cur().mask;
+    hb_mask_t lookup_mask = c->lookup_mask;
+
+    /* Note: This breaks badly if two features enabled this lookup together. */
+    unsigned int shift = _hb_ctz (lookup_mask);
+    unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
+
+    if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false);
+
+    glyph_id = alt_set[alt_index - 1];
+
+    c->replace_glyph (glyph_id);
+
+    return_trace (true);
+  }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                         Supplier<GlyphID> &glyphs,
+                         Supplier<unsigned int> &alternate_len_list,
+                         unsigned int num_glyphs,
+                         Supplier<GlyphID> &alternate_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
+    for (unsigned int i = 0; i < num_glyphs; i++)
+      if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
+                                                                    alternate_glyphs_list,
+                                                                    alternate_len_list[i]))) return_trace (false);
+    alternate_len_list.advance (num_glyphs);
+    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 1 */
+  OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of Substitution table */
+  OffsetArrayOf<AlternateSet>
+                alternateSet;           /* Array of AlternateSet tables
+                                         * ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_ARRAY (6, alternateSet);
+};
+
+struct AlternateSubst
+{
+  inline bool serialize (hb_serialize_context_t *c,
+                         Supplier<GlyphID> &glyphs,
+                         Supplier<unsigned int> &alternate_len_list,
+                         unsigned int num_glyphs,
+                         Supplier<GlyphID> &alternate_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (u.format))) return_trace (false);
+    unsigned int format = 1;
+    u.format.set (format);
+    switch (u.format) {
+    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
+    default:return_trace (false);
+    }
+  }
+
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  USHORT                format;         /* Format identifier */
+  AlternateSubstFormat1 format1;
+  } u;
+};
+
+
+struct Ligature
+{
+  inline void closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    unsigned int count = component.len;
+    for (unsigned int i = 1; i < count; i++)
+      if (!c->glyphs->has (component[i]))
+        return;
+    c->glyphs->add (ligGlyph);
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int count = component.len;
+    for (unsigned int i = 1; i < count; i++)
+      c->input->add (component[i]);
+    c->output->add (ligGlyph);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    if (c->len != component.len)
+      return_trace (false);
+
+    for (unsigned int i = 1; i < c->len; i++)
+      if (likely (c->glyphs[i] != component[i]))
+        return_trace (false);
+
+    return_trace (true);
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int count = component.len;
+
+    if (unlikely (!count)) return_trace (false);
+
+    /* Special-case to make it in-place and not consider this
+     * as a "ligated" substitution. */
+    if (unlikely (count == 1))
+    {
+      c->replace_glyph (ligGlyph);
+      return_trace (true);
+    }
+
+    bool is_mark_ligature = false;
+    unsigned int total_component_count = 0;
+
+    unsigned int match_length = 0;
+    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
+
+    if (likely (!match_input (c, count,
+                              &component[1],
+                              match_glyph,
+                              NULL,
+                              &match_length,
+                              match_positions,
+                              &is_mark_ligature,
+                              &total_component_count)))
+      return_trace (false);
+
+    ligate_input (c,
+                  count,
+                  match_positions,
+                  match_length,
+                  ligGlyph,
+                  is_mark_ligature,
+                  total_component_count);
+
+    return_trace (true);
+  }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                         GlyphID ligature,
+                         Supplier<GlyphID> &components, /* Starting from second */
+                         unsigned int num_components /* Including first component */)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    ligGlyph = ligature;
+    if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
+    return_trace (true);
+  }
+
+  public:
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
+  }
+
+  protected:
+  GlyphID       ligGlyph;               /* GlyphID of ligature to substitute */
+  HeadlessArrayOf<GlyphID>
+                component;              /* Array of component GlyphIDs--start
+                                         * with the second  component--ordered
+                                         * in writing direction */
+  public:
+  DEFINE_SIZE_ARRAY (4, component);
+};
+
+struct LigatureSet
+{
+  inline void closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    unsigned int num_ligs = ligature.len;
+    for (unsigned int i = 0; i < num_ligs; i++)
+      (this+ligature[i]).closure (c);
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int num_ligs = ligature.len;
+    for (unsigned int i = 0; i < num_ligs; i++)
+      (this+ligature[i]).collect_glyphs (c);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    unsigned int num_ligs = ligature.len;
+    for (unsigned int i = 0; i < num_ligs; i++)
+    {
+      const Ligature &lig = this+ligature[i];
+      if (lig.would_apply (c))
+        return_trace (true);
+    }
+    return_trace (false);
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int num_ligs = ligature.len;
+    for (unsigned int i = 0; i < num_ligs; i++)
+    {
+      const Ligature &lig = this+ligature[i];
+      if (lig.apply (c)) return_trace (true);
+    }
+
+    return_trace (false);
+  }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                         Supplier<GlyphID> &ligatures,
+                         Supplier<unsigned int> &component_count_list,
+                         unsigned int num_ligatures,
+                         Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
+    for (unsigned int i = 0; i < num_ligatures; i++)
+      if (unlikely (!ligature[i].serialize (c, this).serialize (c,
+                                                                ligatures[i],
+                                                                component_list,
+                                                                component_count_list[i]))) return_trace (false);
+    ligatures.advance (num_ligatures);
+    component_count_list.advance (num_ligatures);
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (ligature.sanitize (c, this));
+  }
+
+  protected:
+  OffsetArrayOf<Ligature>
+                ligature;               /* Array LigatureSet tables
+                                         * ordered by preference */
+  public:
+  DEFINE_SIZE_ARRAY (2, ligature);
+};
+
+struct LigatureSubstFormat1
+{
+  inline void closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      if (c->glyphs->has (iter.get_glyph ()))
+        (this+ligatureSet[iter.get_coverage ()]).closure (c);
+    }
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      c->input->add (iter.get_glyph ());
+      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
+    }
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    const LigatureSet &lig_set = this+ligatureSet[index];
+    return_trace (lig_set.would_apply (c));
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
+
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    const LigatureSet &lig_set = this+ligatureSet[index];
+    return_trace (lig_set.apply (c));
+  }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                         Supplier<GlyphID> &first_glyphs,
+                         Supplier<unsigned int> &ligature_per_first_glyph_count_list,
+                         unsigned int num_first_glyphs,
+                         Supplier<GlyphID> &ligatures_list,
+                         Supplier<unsigned int> &component_count_list,
+                         Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
+    for (unsigned int i = 0; i < num_first_glyphs; i++)
+      if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
+                                                                   ligatures_list,
+                                                                   component_count_list,
+                                                                   ligature_per_first_glyph_count_list[i],
+                                                                   component_list))) return_trace (false);
+    ligature_per_first_glyph_count_list.advance (num_first_glyphs);
+    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 1 */
+  OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of Substitution table */
+  OffsetArrayOf<LigatureSet>
+                ligatureSet;            /* Array LigatureSet tables
+                                         * ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_ARRAY (6, ligatureSet);
+};
+
+struct LigatureSubst
+{
+  inline bool serialize (hb_serialize_context_t *c,
+                         Supplier<GlyphID> &first_glyphs,
+                         Supplier<unsigned int> &ligature_per_first_glyph_count_list,
+                         unsigned int num_first_glyphs,
+                         Supplier<GlyphID> &ligatures_list,
+                         Supplier<unsigned int> &component_count_list,
+                         Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (u.format))) return_trace (false);
+    unsigned int format = 1;
+    u.format.set (format);
+    switch (u.format) {
+    case 1: return_trace (u.format1.serialize (c,
+                                               first_glyphs,
+                                               ligature_per_first_glyph_count_list,
+                                               num_first_glyphs,
+                                               ligatures_list,
+                                               component_count_list,
+                                               component_list));
+    default:return_trace (false);
+    }
+  }
+
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  USHORT                format;         /* Format identifier */
+  LigatureSubstFormat1  format1;
+  } u;
+};
+
+
+struct ContextSubst : Context {};
+
+struct ChainContextSubst : ChainContext {};
+
+struct ExtensionSubst : Extension<ExtensionSubst>
+{
+  typedef struct SubstLookupSubTable LookupSubTable;
+
+  inline bool is_reverse (void) const;
+};
+
+
+struct ReverseChainSingleSubstFormat1
+{
+  inline void closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+    unsigned int count;
+
+    count = backtrack.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!(this+backtrack[i]).intersects (c->glyphs))
+        return;
+
+    count = lookahead.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!(this+lookahead[i]).intersects (c->glyphs))
+        return;
+
+    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      if (c->glyphs->has (iter.get_glyph ()))
+        c->glyphs->add (substitute[iter.get_coverage ()]);
+    }
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+    unsigned int count;
+
+    (this+coverage).add_coverage (c->input);
+
+    count = backtrack.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+backtrack[i]).add_coverage (c->before);
+
+    count = lookahead.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+lookahead[i]).add_coverage (c->after);
+
+    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+    count = substitute.len;
+    for (unsigned int i = 0; i < count; i++)
+      c->output->add (substitute[i]);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
+      return_trace (false); /* No chaining to this type */
+
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+
+    if (match_backtrack (c,
+                         backtrack.len, (USHORT *) backtrack.array,
+                         match_coverage, this) &&
+        match_lookahead (c,
+                         lookahead.len, (USHORT *) lookahead.array,
+                         match_coverage, this,
+                         1))
+    {
+      c->replace_glyph_inplace (substitute[index]);
+      /* Note: We DON'T decrease buffer->idx.  The main loop does it
+       * for us.  This is useful for preventing surprises if someone
+       * calls us through a Context lookup. */
+      return_trace (true);
+    }
+
+    return_trace (false);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
+      return_trace (false);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    if (!lookahead.sanitize (c, this))
+      return_trace (false);
+    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+    return_trace (substitute.sanitize (c));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 1 */
+  OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of table */
+  OffsetArrayOf<Coverage>
+                backtrack;              /* Array of coverage tables
+                                         * in backtracking sequence, in  glyph
+                                         * sequence order */
+  OffsetArrayOf<Coverage>
+                lookaheadX;             /* Array of coverage tables
+                                         * in lookahead sequence, in glyph
+                                         * sequence order */
+  ArrayOf<GlyphID>
+                substituteX;            /* Array of substitute
+                                         * GlyphIDs--ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_MIN (10);
+};
+
+struct ReverseChainSingleSubst
+{
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  USHORT                                format;         /* Format identifier */
+  ReverseChainSingleSubstFormat1        format1;
+  } u;
+};
+
+
+
+/*
+ * SubstLookup
+ */
+
+struct SubstLookupSubTable
+{
+  friend struct SubstLookup;
+
+  enum Type {
+    Single              = 1,
+    Multiple            = 2,
+    Alternate           = 3,
+    Ligature            = 4,
+    Context             = 5,
+    ChainContext        = 6,
+    Extension           = 7,
+    ReverseChainSingle  = 8
+  };
+
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
+  {
+    TRACE_DISPATCH (this, lookup_type);
+    if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
+    switch (lookup_type) {
+    case Single:                return_trace (u.single.dispatch (c));
+    case Multiple:              return_trace (u.multiple.dispatch (c));
+    case Alternate:             return_trace (u.alternate.dispatch (c));
+    case Ligature:              return_trace (u.ligature.dispatch (c));
+    case Context:               return_trace (u.context.dispatch (c));
+    case ChainContext:          return_trace (u.chainContext.dispatch (c));
+    case Extension:             return_trace (u.extension.dispatch (c));
+    case ReverseChainSingle:    return_trace (u.reverseChainContextSingle.dispatch (c));
+    default:                    return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  USHORT                        sub_format;
+  SingleSubst                   single;
+  MultipleSubst                 multiple;
+  AlternateSubst                alternate;
+  LigatureSubst                 ligature;
+  ContextSubst                  context;
+  ChainContextSubst             chainContext;
+  ExtensionSubst                extension;
+  ReverseChainSingleSubst       reverseChainContextSingle;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, sub_format);
+};
+
+
+struct SubstLookup : Lookup
+{
+  inline const SubstLookupSubTable& get_subtable (unsigned int i) const
+  { return Lookup::get_subtable<SubstLookupSubTable> (i); }
+
+  inline static bool lookup_type_is_reverse (unsigned int lookup_type)
+  { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
+
+  inline bool is_reverse (void) const
+  {
+    unsigned int type = get_type ();
+    if (unlikely (type == SubstLookupSubTable::Extension))
+      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
+    return lookup_type_is_reverse (type);
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    return_trace (dispatch (c));
+  }
+
+  inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
+    return_trace (dispatch (c));
+  }
+
+  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
+    return_trace (dispatch (c));
+  }
+
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const
+  {
+    hb_add_coverage_context_t<set_t> c (glyphs);
+    dispatch (&c);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c,
+                           const hb_ot_layout_lookup_accelerator_t *accel) const
+  {
+    TRACE_WOULD_APPLY (this);
+    if (unlikely (!c->len))  return_trace (false);
+    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
+      return_trace (dispatch (c));
+  }
+
+  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
+
+  inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
+                                                  unsigned int i)
+  { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
+
+  inline bool serialize_single (hb_serialize_context_t *c,
+                                uint32_t lookup_props,
+                                Supplier<GlyphID> &glyphs,
+                                Supplier<GlyphID> &substitutes,
+                                unsigned int num_glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false);
+    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
+  }
+
+  inline bool serialize_multiple (hb_serialize_context_t *c,
+                                  uint32_t lookup_props,
+                                  Supplier<GlyphID> &glyphs,
+                                  Supplier<unsigned int> &substitute_len_list,
+                                  unsigned int num_glyphs,
+                                  Supplier<GlyphID> &substitute_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false);
+    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
+                                                                  glyphs,
+                                                                  substitute_len_list,
+                                                                  num_glyphs,
+                                                                  substitute_glyphs_list));
+  }
+
+  inline bool serialize_alternate (hb_serialize_context_t *c,
+                                   uint32_t lookup_props,
+                                   Supplier<GlyphID> &glyphs,
+                                   Supplier<unsigned int> &alternate_len_list,
+                                   unsigned int num_glyphs,
+                                   Supplier<GlyphID> &alternate_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false);
+    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
+                                                                   glyphs,
+                                                                   alternate_len_list,
+                                                                   num_glyphs,
+                                                                   alternate_glyphs_list));
+  }
+
+  inline bool serialize_ligature (hb_serialize_context_t *c,
+                                  uint32_t lookup_props,
+                                  Supplier<GlyphID> &first_glyphs,
+                                  Supplier<unsigned int> &ligature_per_first_glyph_count_list,
+                                  unsigned int num_first_glyphs,
+                                  Supplier<GlyphID> &ligatures_list,
+                                  Supplier<unsigned int> &component_count_list,
+                                  Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false);
+    return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
+                                                                  first_glyphs,
+                                                                  ligature_per_first_glyph_count_list,
+                                                                  num_first_glyphs,
+                                                                  ligatures_list,
+                                                                  component_count_list,
+                                                                  component_list));
+  }
+
+  template <typename context_t>
+  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
+
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  { return Lookup::dispatch<SubstLookupSubTable> (c); }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!Lookup::sanitize (c))) return_trace (false);
+    if (unlikely (!dispatch (c))) return_trace (false);
+
+    if (unlikely (get_type () == SubstLookupSubTable::Extension))
+    {
+      /* The spec says all subtables of an Extension lookup should
+       * have the same type.  This is specially important if one has
+       * a reverse type! */
+      unsigned int type = get_subtable (0).u.extension.get_type ();
+      unsigned int count = get_subtable_count ();
+      for (unsigned int i = 1; i < count; i++)
+        if (get_subtable (i).u.extension.get_type () != type)
+          return_trace (false);
+    }
+    return_trace (true);
+  }
+};
+
+typedef OffsetListOf<SubstLookup> SubstLookupList;
+
+/*
+ * GSUB -- The Glyph Substitution Table
+ */
+
+struct GSUB : GSUBGPOS
+{
+  static const hb_tag_t tableTag        = HB_OT_TAG_GSUB;
+
+  inline const SubstLookup& get_lookup (unsigned int i) const
+  { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
+
+  static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
+    const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
+    return_trace (list.sanitize (c, this));
+  }
+  public:
+  DEFINE_SIZE_STATIC (10);
+};
+
+
+void
+GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
+{
+  _hb_buffer_assert_gsubgpos_vars (buffer);
+
+  const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+  {
+    unsigned int props = gdef.get_glyph_props (info[i].codepoint);
+    if (!props)
+    {
+      /* Never mark default-ignorables as marks.
+       * They won't get in the way of lookups anyway,
+       * but having them as mark will cause them to be skipped
+       * over if the lookup-flag says so, but at least for the
+       * Mongolian variation selectors, looks like Uniscribe
+       * marks them as non-mark.  Some Mongolian fonts without
+       * GDEF rely on this.  Another notable character that
+       * this applies to is COMBINING GRAPHEME JOINER. */
+      props = (_hb_glyph_info_get_general_category (&info[i]) !=
+               HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
+               _hb_glyph_info_is_default_ignorable (&info[i])) ?
+              HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
+              HB_OT_LAYOUT_GLYPH_PROPS_MARK;
+    }
+    _hb_glyph_info_set_glyph_props (&info[i], props);
+    _hb_glyph_info_clear_lig_props (&info[i]);
+    buffer->info[i].syllable() = 0;
+  }
+}
+
+
+/* Out-of-class implementation for methods recursing */
+
+/*static*/ inline bool ExtensionSubst::is_reverse (void) const
+{
+  unsigned int type = get_type ();
+  if (unlikely (type == SubstLookupSubTable::Extension))
+    return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
+  return SubstLookup::lookup_type_is_reverse (type);
+}
+
+template <typename context_t>
+/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
+{
+  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
+  const SubstLookup &l = gsub.get_lookup (lookup_index);
+  return l.dispatch (c);
+}
+
+/*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
+{
+  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
+  const SubstLookup &l = gsub.get_lookup (lookup_index);
+  unsigned int saved_lookup_props = c->lookup_props;
+  unsigned int saved_lookup_index = c->lookup_index;
+  c->set_lookup_index (lookup_index);
+  c->set_lookup_props (l.get_props ());
+  bool ret = l.dispatch (c);
+  c->set_lookup_index (saved_lookup_index);
+  c->set_lookup_props (saved_lookup_props);
+  return ret;
+}
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-layout-gsubgpos-private.hh b/src/share/native/sun/font/harfbuzz/hb-ot-layout-gsubgpos-private.hh
new file mode 100644
index 0000000..73cfb77
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-layout-gsubgpos-private.hh
@@ -0,0 +1,2299 @@
+/*
+ * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
+ * Copyright © 2010,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_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
+#define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
+
+#include "hb-buffer-private.hh"
+#include "hb-ot-layout-gdef-table.hh"
+#include "hb-set-private.hh"
+
+
+namespace OT {
+
+
+#ifndef HB_DEBUG_CLOSURE
+#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
+#endif
+
+#define TRACE_CLOSURE(this) \
+        hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
+        (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+         "");
+
+struct hb_closure_context_t :
+       hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
+{
+  inline const char *get_name (void) { return "CLOSURE"; }
+  typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
+  template <typename T>
+  inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
+  static return_t default_return_value (void) { return HB_VOID; }
+  bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
+  return_t recurse (unsigned int lookup_index)
+  {
+    if (unlikely (nesting_level_left == 0 || !recurse_func))
+      return default_return_value ();
+
+    nesting_level_left--;
+    recurse_func (this, lookup_index);
+    nesting_level_left++;
+    return HB_VOID;
+  }
+
+  hb_face_t *face;
+  hb_set_t *glyphs;
+  recurse_func_t recurse_func;
+  unsigned int nesting_level_left;
+  unsigned int debug_depth;
+
+  hb_closure_context_t (hb_face_t *face_,
+                        hb_set_t *glyphs_,
+                        unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
+                          face (face_),
+                          glyphs (glyphs_),
+                          recurse_func (NULL),
+                          nesting_level_left (nesting_level_left_),
+                          debug_depth (0) {}
+
+  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+};
+
+
+
+#ifndef HB_DEBUG_WOULD_APPLY
+#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
+#endif
+
+#define TRACE_WOULD_APPLY(this) \
+        hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
+        (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+         "%d glyphs", c->len);
+
+struct hb_would_apply_context_t :
+       hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
+{
+  inline const char *get_name (void) { return "WOULD_APPLY"; }
+  template <typename T>
+  inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
+  static return_t default_return_value (void) { return false; }
+  bool stop_sublookup_iteration (return_t r) const { return r; }
+
+  hb_face_t *face;
+  const hb_codepoint_t *glyphs;
+  unsigned int len;
+  bool zero_context;
+  unsigned int debug_depth;
+
+  hb_would_apply_context_t (hb_face_t *face_,
+                            const hb_codepoint_t *glyphs_,
+                            unsigned int len_,
+                            bool zero_context_) :
+                              face (face_),
+                              glyphs (glyphs_),
+                              len (len_),
+                              zero_context (zero_context_),
+                              debug_depth (0) {}
+};
+
+
+
+#ifndef HB_DEBUG_COLLECT_GLYPHS
+#define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
+#endif
+
+#define TRACE_COLLECT_GLYPHS(this) \
+        hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
+        (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+         "");
+
+struct hb_collect_glyphs_context_t :
+       hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
+{
+  inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
+  typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
+  template <typename T>
+  inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
+  static return_t default_return_value (void) { return HB_VOID; }
+  bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
+  return_t recurse (unsigned int lookup_index)
+  {
+    if (unlikely (nesting_level_left == 0 || !recurse_func))
+      return default_return_value ();
+
+    /* Note that GPOS sets recurse_func to NULL already, so it doesn't get
+     * past the previous check.  For GSUB, we only want to collect the output
+     * glyphs in the recursion.  If output is not requested, we can go home now.
+     *
+     * Note further, that the above is not exactly correct.  A recursed lookup
+     * is allowed to match input that is not matched in the context, but that's
+     * not how most fonts are built.  It's possible to relax that and recurse
+     * with all sets here if it proves to be an issue.
+     */
+
+    if (output == hb_set_get_empty ())
+      return HB_VOID;
+
+    /* Return if new lookup was recursed to before. */
+    if (recursed_lookups.has (lookup_index))
+      return HB_VOID;
+
+    hb_set_t *old_before = before;
+    hb_set_t *old_input  = input;
+    hb_set_t *old_after  = after;
+    before = input = after = hb_set_get_empty ();
+
+    nesting_level_left--;
+    recurse_func (this, lookup_index);
+    nesting_level_left++;
+
+    before = old_before;
+    input  = old_input;
+    after  = old_after;
+
+    recursed_lookups.add (lookup_index);
+
+    return HB_VOID;
+  }
+
+  hb_face_t *face;
+  hb_set_t *before;
+  hb_set_t *input;
+  hb_set_t *after;
+  hb_set_t *output;
+  recurse_func_t recurse_func;
+  hb_set_t recursed_lookups;
+  unsigned int nesting_level_left;
+  unsigned int debug_depth;
+
+  hb_collect_glyphs_context_t (hb_face_t *face_,
+                               hb_set_t  *glyphs_before, /* OUT. May be NULL */
+                               hb_set_t  *glyphs_input,  /* OUT. May be NULL */
+                               hb_set_t  *glyphs_after,  /* OUT. May be NULL */
+                               hb_set_t  *glyphs_output, /* OUT. May be NULL */
+                               unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
+                              face (face_),
+                              before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
+                              input  (glyphs_input  ? glyphs_input  : hb_set_get_empty ()),
+                              after  (glyphs_after  ? glyphs_after  : hb_set_get_empty ()),
+                              output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
+                              recurse_func (NULL),
+                              recursed_lookups (),
+                              nesting_level_left (nesting_level_left_),
+                              debug_depth (0)
+  {
+    recursed_lookups.init ();
+  }
+  ~hb_collect_glyphs_context_t (void)
+  {
+    recursed_lookups.fini ();
+  }
+
+  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+};
+
+
+
+#ifndef HB_DEBUG_GET_COVERAGE
+#define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
+#endif
+
+/* XXX Can we remove this? */
+
+template <typename set_t>
+struct hb_add_coverage_context_t :
+       hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
+{
+  inline const char *get_name (void) { return "GET_COVERAGE"; }
+  typedef const Coverage &return_t;
+  template <typename T>
+  inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
+  static return_t default_return_value (void) { return Null(Coverage); }
+  bool stop_sublookup_iteration (return_t r) const
+  {
+    r.add_coverage (set);
+    return false;
+  }
+
+  hb_add_coverage_context_t (set_t *set_) :
+                            set (set_),
+                            debug_depth (0) {}
+
+  set_t *set;
+  unsigned int debug_depth;
+};
+
+
+
+#ifndef HB_DEBUG_APPLY
+#define HB_DEBUG_APPLY (HB_DEBUG+0)
+#endif
+
+#define TRACE_APPLY(this) \
+        hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
+        (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+         "idx %d gid %u lookup %d", \
+         c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index);
+
+struct hb_apply_context_t :
+       hb_dispatch_context_t<hb_apply_context_t, bool, HB_DEBUG_APPLY>
+{
+  struct matcher_t
+  {
+    inline matcher_t (void) :
+             lookup_props (0),
+             ignore_zwnj (false),
+             ignore_zwj (false),
+             mask (-1),
+#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
+             syllable arg1(0),
+#undef arg1
+             match_func (NULL),
+             match_data (NULL) {};
+
+    typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
+
+    inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
+    inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
+    inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
+    inline void set_mask (hb_mask_t mask_) { mask = mask_; }
+    inline void set_syllable (uint8_t syllable_)  { syllable = syllable_; }
+    inline void set_match_func (match_func_t match_func_,
+                                const void *match_data_)
+    { match_func = match_func_; match_data = match_data_; }
+
+    enum may_match_t {
+      MATCH_NO,
+      MATCH_YES,
+      MATCH_MAYBE
+    };
+
+    inline may_match_t may_match (const hb_glyph_info_t &info,
+                                  const USHORT          *glyph_data) const
+    {
+      if (!(info.mask & mask) ||
+          (syllable && syllable != info.syllable ()))
+        return MATCH_NO;
+
+      if (match_func)
+        return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
+
+      return MATCH_MAYBE;
+    }
+
+    enum may_skip_t {
+      SKIP_NO,
+      SKIP_YES,
+      SKIP_MAYBE
+    };
+
+    inline may_skip_t
+    may_skip (const hb_apply_context_t *c,
+              const hb_glyph_info_t    &info) const
+    {
+      if (!c->check_glyph_property (&info, lookup_props))
+        return SKIP_YES;
+
+      if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_fvs (&info) &&
+                    (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
+                    (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
+        return SKIP_MAYBE;
+
+      return SKIP_NO;
+    }
+
+    protected:
+    unsigned int lookup_props;
+    bool ignore_zwnj;
+    bool ignore_zwj;
+    hb_mask_t mask;
+    uint8_t syllable;
+    match_func_t match_func;
+    const void *match_data;
+  };
+
+  struct skipping_iterator_t
+  {
+    inline void init (hb_apply_context_t *c_, bool context_match = false)
+    {
+      c = c_;
+      match_glyph_data = NULL,
+      matcher.set_match_func (NULL, NULL);
+      matcher.set_lookup_props (c->lookup_props);
+      /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
+      matcher.set_ignore_zwnj (context_match || c->table_index == 1);
+      /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
+      matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
+      matcher.set_mask (context_match ? -1 : c->lookup_mask);
+    }
+    inline void set_lookup_props (unsigned int lookup_props)
+    {
+      matcher.set_lookup_props (lookup_props);
+    }
+    inline void set_match_func (matcher_t::match_func_t match_func_,
+                                const void *match_data_,
+                                const USHORT glyph_data[])
+    {
+      matcher.set_match_func (match_func_, match_data_);
+      match_glyph_data = glyph_data;
+    }
+
+    inline void reset (unsigned int start_index_,
+                       unsigned int num_items_)
+    {
+      idx = start_index_;
+      num_items = num_items_;
+      end = c->buffer->len;
+      matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
+    }
+
+    inline void reject (void) { num_items++; match_glyph_data--; }
+
+    inline bool next (void)
+    {
+      assert (num_items > 0);
+      while (idx + num_items < end)
+      {
+        idx++;
+        const hb_glyph_info_t &info = c->buffer->info[idx];
+
+        matcher_t::may_skip_t skip = matcher.may_skip (c, info);
+        if (unlikely (skip == matcher_t::SKIP_YES))
+          continue;
+
+        matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
+        if (match == matcher_t::MATCH_YES ||
+            (match == matcher_t::MATCH_MAYBE &&
+             skip == matcher_t::SKIP_NO))
+        {
+          num_items--;
+          match_glyph_data++;
+          return true;
+        }
+
+        if (skip == matcher_t::SKIP_NO)
+          return false;
+      }
+      return false;
+    }
+    inline bool prev (void)
+    {
+      assert (num_items > 0);
+      while (idx >= num_items)
+      {
+        idx--;
+        const hb_glyph_info_t &info = c->buffer->out_info[idx];
+
+        matcher_t::may_skip_t skip = matcher.may_skip (c, info);
+        if (unlikely (skip == matcher_t::SKIP_YES))
+          continue;
+
+        matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
+        if (match == matcher_t::MATCH_YES ||
+            (match == matcher_t::MATCH_MAYBE &&
+             skip == matcher_t::SKIP_NO))
+        {
+          num_items--;
+          match_glyph_data++;
+          return true;
+        }
+
+        if (skip == matcher_t::SKIP_NO)
+          return false;
+      }
+      return false;
+    }
+
+    unsigned int idx;
+    protected:
+    hb_apply_context_t *c;
+    matcher_t matcher;
+    const USHORT *match_glyph_data;
+
+    unsigned int num_items;
+    unsigned int end;
+  };
+
+
+  inline const char *get_name (void) { return "APPLY"; }
+  typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
+  template <typename T>
+  inline return_t dispatch (const T &obj) { return obj.apply (this); }
+  static return_t default_return_value (void) { return false; }
+  bool stop_sublookup_iteration (return_t r) const { return r; }
+  return_t recurse (unsigned int lookup_index)
+  {
+    if (unlikely (nesting_level_left == 0 || !recurse_func))
+      return default_return_value ();
+
+    nesting_level_left--;
+    bool ret = recurse_func (this, lookup_index);
+    nesting_level_left++;
+    return ret;
+  }
+
+  unsigned int table_index; /* GSUB/GPOS */
+  hb_font_t *font;
+  hb_face_t *face;
+  hb_buffer_t *buffer;
+  hb_direction_t direction;
+  hb_mask_t lookup_mask;
+  bool auto_zwj;
+  recurse_func_t recurse_func;
+  unsigned int nesting_level_left;
+  unsigned int lookup_props;
+  const GDEF &gdef;
+  bool has_glyph_classes;
+  skipping_iterator_t iter_input, iter_context;
+  unsigned int lookup_index;
+  unsigned int debug_depth;
+
+
+  hb_apply_context_t (unsigned int table_index_,
+                      hb_font_t *font_,
+                      hb_buffer_t *buffer_) :
+                        table_index (table_index_),
+                        font (font_), face (font->face), buffer (buffer_),
+                        direction (buffer_->props.direction),
+                        lookup_mask (1),
+                        auto_zwj (true),
+                        recurse_func (NULL),
+                        nesting_level_left (HB_MAX_NESTING_LEVEL),
+                        lookup_props (0),
+                        gdef (*hb_ot_layout_from_face (face)->gdef),
+                        has_glyph_classes (gdef.has_glyph_classes ()),
+                        iter_input (),
+                        iter_context (),
+                        lookup_index ((unsigned int) -1),
+                        debug_depth (0) {}
+
+  inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
+  inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
+  inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+  inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
+  inline void set_lookup_props (unsigned int lookup_props_)
+  {
+    lookup_props = lookup_props_;
+    iter_input.init (this, false);
+    iter_context.init (this, true);
+  }
+
+  inline bool
+  match_properties_mark (hb_codepoint_t  glyph,
+                         unsigned int    glyph_props,
+                         unsigned int    match_props) const
+  {
+    /* If using mark filtering sets, the high short of
+     * match_props has the set index.
+     */
+    if (match_props & LookupFlag::UseMarkFilteringSet)
+      return gdef.mark_set_covers (match_props >> 16, glyph);
+
+    /* The second byte of match_props has the meaning
+     * "ignore marks of attachment type different than
+     * the attachment type specified."
+     */
+    if (match_props & LookupFlag::MarkAttachmentType)
+      return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
+
+    return true;
+  }
+
+  inline bool
+  check_glyph_property (const hb_glyph_info_t *info,
+                        unsigned int  match_props) const
+  {
+    hb_codepoint_t glyph = info->codepoint;
+    unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
+
+    /* Not covered, if, for example, glyph class is ligature and
+     * match_props includes LookupFlags::IgnoreLigatures
+     */
+    if (glyph_props & match_props & LookupFlag::IgnoreFlags)
+      return false;
+
+    if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
+      return match_properties_mark (glyph, glyph_props, match_props);
+
+    return true;
+  }
+
+  inline void _set_glyph_props (hb_codepoint_t glyph_index,
+                          unsigned int class_guess = 0,
+                          bool ligature = false,
+                          bool component = false) const
+  {
+    unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
+                          HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
+    add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
+    if (ligature)
+    {
+      add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
+      /* In the only place that the MULTIPLIED bit is used, Uniscribe
+       * seems to only care about the "last" transformation between
+       * Ligature and Multiple substitions.  Ie. if you ligate, expand,
+       * and ligate again, it forgives the multiplication and acts as
+       * if only ligation happened.  As such, clear MULTIPLIED bit.
+       */
+      add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
+    }
+    if (component)
+      add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
+    if (likely (has_glyph_classes))
+      _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
+    else if (class_guess)
+      _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
+  }
+
+  inline void replace_glyph (hb_codepoint_t glyph_index) const
+  {
+    _set_glyph_props (glyph_index);
+    buffer->replace_glyph (glyph_index);
+  }
+  inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
+  {
+    _set_glyph_props (glyph_index);
+    buffer->cur().codepoint = glyph_index;
+  }
+  inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
+                                           unsigned int class_guess) const
+  {
+    _set_glyph_props (glyph_index, class_guess, true);
+    buffer->replace_glyph (glyph_index);
+  }
+  inline void output_glyph_for_component (hb_codepoint_t glyph_index,
+                                          unsigned int class_guess) const
+  {
+    _set_glyph_props (glyph_index, class_guess, false, true);
+    buffer->output_glyph (glyph_index);
+  }
+};
+
+
+
+typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
+typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
+typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
+
+struct ContextClosureFuncs
+{
+  intersects_func_t intersects;
+};
+struct ContextCollectGlyphsFuncs
+{
+  collect_glyphs_func_t collect;
+};
+struct ContextApplyFuncs
+{
+  match_func_t match;
+};
+
+
+static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
+{
+  return glyphs->has (value);
+}
+static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
+{
+  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
+  return class_def.intersects_class (glyphs, value);
+}
+static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
+{
+  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
+  return (data+coverage).intersects (glyphs);
+}
+
+static inline bool intersects_array (hb_closure_context_t *c,
+                                     unsigned int count,
+                                     const USHORT values[],
+                                     intersects_func_t intersects_func,
+                                     const void *intersects_data)
+{
+  for (unsigned int i = 0; i < count; i++)
+    if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
+      return false;
+  return true;
+}
+
+
+static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
+{
+  glyphs->add (value);
+}
+static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data)
+{
+  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
+  class_def.add_class (glyphs, value);
+}
+static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
+{
+  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
+  (data+coverage).add_coverage (glyphs);
+}
+static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
+                                  hb_set_t *glyphs,
+                                  unsigned int count,
+                                  const USHORT values[],
+                                  collect_glyphs_func_t collect_func,
+                                  const void *collect_data)
+{
+  for (unsigned int i = 0; i < count; i++)
+    collect_func (glyphs, values[i], collect_data);
+}
+
+
+static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
+{
+  return glyph_id == value;
+}
+static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
+{
+  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
+  return class_def.get_class (glyph_id) == value;
+}
+static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
+{
+  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
+  return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
+}
+
+static inline bool would_match_input (hb_would_apply_context_t *c,
+                                      unsigned int count, /* Including the first glyph (not matched) */
+                                      const USHORT input[], /* Array of input values--start with second glyph */
+                                      match_func_t match_func,
+                                      const void *match_data)
+{
+  if (count != c->len)
+    return false;
+
+  for (unsigned int i = 1; i < count; i++)
+    if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
+      return false;
+
+  return true;
+}
+static inline bool match_input (hb_apply_context_t *c,
+                                unsigned int count, /* Including the first glyph (not matched) */
+                                const USHORT input[], /* Array of input values--start with second glyph */
+                                match_func_t match_func,
+                                const void *match_data,
+                                unsigned int *end_offset,
+                                unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
+                                bool *p_is_mark_ligature = NULL,
+                                unsigned int *p_total_component_count = NULL)
+{
+  TRACE_APPLY (NULL);
+
+  if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
+
+  hb_buffer_t *buffer = c->buffer;
+
+  hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+  skippy_iter.reset (buffer->idx, count - 1);
+  skippy_iter.set_match_func (match_func, match_data, input);
+
+  /*
+   * This is perhaps the trickiest part of OpenType...  Remarks:
+   *
+   * - If all components of the ligature were marks, we call this a mark ligature.
+   *
+   * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
+   *   it as a ligature glyph.
+   *
+   * - Ligatures cannot be formed across glyphs attached to different components
+   *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
+   *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
+   *   However, it would be wrong to ligate that SHADDA,FATHA sequence.o
+   *   There is an exception to this: If a ligature tries ligating with marks that
+   *   belong to it itself, go ahead, assuming that the font designer knows what
+   *   they are doing (otherwise it can break Indic stuff when a matra wants to
+   *   ligate with a conjunct...)
+   */
+
+  bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
+
+  unsigned int total_component_count = 0;
+  total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
+
+  unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+  unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
+
+  match_positions[0] = buffer->idx;
+  for (unsigned int i = 1; i < count; i++)
+  {
+    if (!skippy_iter.next ()) return_trace (false);
+
+    match_positions[i] = skippy_iter.idx;
+
+    unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
+    unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
+
+    if (first_lig_id && first_lig_comp) {
+      /* If first component was attached to a previous ligature component,
+       * all subsequent components should be attached to the same ligature
+       * component, otherwise we shouldn't ligate them. */
+      if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
+        return_trace (false);
+    } else {
+      /* If first component was NOT attached to a previous ligature component,
+       * all subsequent components should also NOT be attached to any ligature
+       * component, unless they are attached to the first component itself! */
+      if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
+        return_trace (false);
+    }
+
+    is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
+    total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
+  }
+
+  *end_offset = skippy_iter.idx - buffer->idx + 1;
+
+  if (p_is_mark_ligature)
+    *p_is_mark_ligature = is_mark_ligature;
+
+  if (p_total_component_count)
+    *p_total_component_count = total_component_count;
+
+  return_trace (true);
+}
+static inline bool ligate_input (hb_apply_context_t *c,
+                                 unsigned int count, /* Including the first glyph */
+                                 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
+                                 unsigned int match_length,
+                                 hb_codepoint_t lig_glyph,
+                                 bool is_mark_ligature,
+                                 unsigned int total_component_count)
+{
+  TRACE_APPLY (NULL);
+
+  hb_buffer_t *buffer = c->buffer;
+
+  buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
+
+  /*
+   * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
+   *   the ligature to keep its old ligature id.  This will allow it to attach to
+   *   a base ligature in GPOS.  Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
+   *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
+   *   ligature id and component value of 2.  Then if SHADDA,FATHA form a ligature
+   *   later, we don't want them to lose their ligature id/component, otherwise
+   *   GPOS will fail to correctly position the mark ligature on top of the
+   *   LAM,LAM,HEH ligature.  See:
+   *     https://bugzilla.gnome.org/show_bug.cgi?id=676343
+   *
+   * - If a ligature is formed of components that some of which are also ligatures
+   *   themselves, and those ligature components had marks attached to *their*
+   *   components, we have to attach the marks to the new ligature component
+   *   positions!  Now *that*'s tricky!  And these marks may be following the
+   *   last component of the whole sequence, so we should loop forward looking
+   *   for them and update them.
+   *
+   *   Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
+   *   'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
+   *   id and component == 1.  Now, during 'liga', the LAM and the LAM-HEH ligature
+   *   form a LAM-LAM-HEH ligature.  We need to reassign the SHADDA and FATHA to
+   *   the new ligature with a component value of 2.
+   *
+   *   This in fact happened to a font...  See:
+   *   https://bugzilla.gnome.org/show_bug.cgi?id=437633
+   */
+
+  unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
+  unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer);
+  unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+  unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
+  unsigned int components_so_far = last_num_components;
+
+  if (!is_mark_ligature)
+  {
+    _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
+    if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
+    {
+      _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
+    }
+  }
+  c->replace_glyph_with_ligature (lig_glyph, klass);
+
+  for (unsigned int i = 1; i < count; i++)
+  {
+    while (buffer->idx < match_positions[i] && !buffer->in_error)
+    {
+      if (!is_mark_ligature) {
+        unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
+        if (this_comp == 0)
+          this_comp = last_num_components;
+        unsigned int new_lig_comp = components_so_far - last_num_components +
+                                    MIN (this_comp, last_num_components);
+          _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
+      }
+      buffer->next_glyph ();
+    }
+
+    last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+    last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
+    components_so_far += last_num_components;
+
+    /* Skip the base glyph */
+    buffer->idx++;
+  }
+
+  if (!is_mark_ligature && last_lig_id) {
+    /* Re-adjust components for any marks following. */
+    for (unsigned int i = buffer->idx; i < buffer->len; i++) {
+      if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
+        unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
+        if (!this_comp)
+          break;
+        unsigned int new_lig_comp = components_so_far - last_num_components +
+                                    MIN (this_comp, last_num_components);
+        _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
+      } else
+        break;
+    }
+  }
+  return_trace (true);
+}
+
+static inline bool match_backtrack (hb_apply_context_t *c,
+                                    unsigned int count,
+                                    const USHORT backtrack[],
+                                    match_func_t match_func,
+                                    const void *match_data)
+{
+  TRACE_APPLY (NULL);
+
+  hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
+  skippy_iter.reset (c->buffer->backtrack_len (), count);
+  skippy_iter.set_match_func (match_func, match_data, backtrack);
+
+  for (unsigned int i = 0; i < count; i++)
+    if (!skippy_iter.prev ())
+      return_trace (false);
+
+  return_trace (true);
+}
+
+static inline bool match_lookahead (hb_apply_context_t *c,
+                                    unsigned int count,
+                                    const USHORT lookahead[],
+                                    match_func_t match_func,
+                                    const void *match_data,
+                                    unsigned int offset)
+{
+  TRACE_APPLY (NULL);
+
+  hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
+  skippy_iter.reset (c->buffer->idx + offset - 1, count);
+  skippy_iter.set_match_func (match_func, match_data, lookahead);
+
+  for (unsigned int i = 0; i < count; i++)
+    if (!skippy_iter.next ())
+      return_trace (false);
+
+  return_trace (true);
+}
+
+
+
+struct LookupRecord
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  USHORT        sequenceIndex;          /* Index into current glyph
+                                         * sequence--first glyph = 0 */
+  USHORT        lookupListIndex;        /* Lookup to apply to that
+                                         * position--zero--based */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+
+template <typename context_t>
+static inline void recurse_lookups (context_t *c,
+                                    unsigned int lookupCount,
+                                    const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
+{
+  for (unsigned int i = 0; i < lookupCount; i++)
+    c->recurse (lookupRecord[i].lookupListIndex);
+}
+
+static inline bool apply_lookup (hb_apply_context_t *c,
+                                 unsigned int count, /* Including the first glyph */
+                                 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
+                                 unsigned int lookupCount,
+                                 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
+                                 unsigned int match_length)
+{
+  TRACE_APPLY (NULL);
+
+  hb_buffer_t *buffer = c->buffer;
+  unsigned int end;
+
+  /* All positions are distance from beginning of *output* buffer.
+   * Adjust. */
+  {
+    unsigned int bl = buffer->backtrack_len ();
+    end = bl + match_length;
+
+    int delta = bl - buffer->idx;
+    /* Convert positions to new indexing. */
+    for (unsigned int j = 0; j < count; j++)
+      match_positions[j] += delta;
+  }
+
+  for (unsigned int i = 0; i < lookupCount && !buffer->in_error; i++)
+  {
+    unsigned int idx = lookupRecord[i].sequenceIndex;
+    if (idx >= count)
+      continue;
+
+    /* Don't recurse to ourself at same position.
+     * Note that this test is too naive, it doesn't catch longer loops. */
+    if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
+      continue;
+
+    buffer->move_to (match_positions[idx]);
+
+    unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
+    if (!c->recurse (lookupRecord[i].lookupListIndex))
+      continue;
+
+    unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
+    int delta = new_len - orig_len;
+
+    if (!delta)
+        continue;
+
+    /* Recursed lookup changed buffer len.  Adjust. */
+
+    end = int (end) + delta;
+    if (end <= match_positions[idx])
+    {
+      /* There can't be any further changes. */
+      assert (end == match_positions[idx]);
+      break;
+    }
+
+    unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
+
+    if (delta > 0)
+    {
+      if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
+        break;
+    }
+    else
+    {
+      /* NOTE: delta is negative. */
+      delta = MAX (delta, (int) next - (int) count);
+      next -= delta;
+    }
+
+    /* Shift! */
+    memmove (match_positions + next + delta, match_positions + next,
+             (count - next) * sizeof (match_positions[0]));
+    next += delta;
+    count += delta;
+
+    /* Fill in new entries. */
+    for (unsigned int j = idx + 1; j < next; j++)
+      match_positions[j] = match_positions[j - 1] + 1;
+
+    /* And fixup the rest. */
+    for (; next < count; next++)
+      match_positions[next] += delta;
+  }
+
+  buffer->move_to (end);
+
+  return_trace (true);
+}
+
+
+
+/* Contextual lookups */
+
+struct ContextClosureLookupContext
+{
+  ContextClosureFuncs funcs;
+  const void *intersects_data;
+};
+
+struct ContextCollectGlyphsLookupContext
+{
+  ContextCollectGlyphsFuncs funcs;
+  const void *collect_data;
+};
+
+struct ContextApplyLookupContext
+{
+  ContextApplyFuncs funcs;
+  const void *match_data;
+};
+
+static inline void context_closure_lookup (hb_closure_context_t *c,
+                                           unsigned int inputCount, /* Including the first glyph (not matched) */
+                                           const USHORT input[], /* Array of input values--start with second glyph */
+                                           unsigned int lookupCount,
+                                           const LookupRecord lookupRecord[],
+                                           ContextClosureLookupContext &lookup_context)
+{
+  if (intersects_array (c,
+                        inputCount ? inputCount - 1 : 0, input,
+                        lookup_context.funcs.intersects, lookup_context.intersects_data))
+    recurse_lookups (c,
+                     lookupCount, lookupRecord);
+}
+
+static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
+                                                  unsigned int inputCount, /* Including the first glyph (not matched) */
+                                                  const USHORT input[], /* Array of input values--start with second glyph */
+                                                  unsigned int lookupCount,
+                                                  const LookupRecord lookupRecord[],
+                                                  ContextCollectGlyphsLookupContext &lookup_context)
+{
+  collect_array (c, c->input,
+                 inputCount ? inputCount - 1 : 0, input,
+                 lookup_context.funcs.collect, lookup_context.collect_data);
+  recurse_lookups (c,
+                   lookupCount, lookupRecord);
+}
+
+static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
+                                               unsigned int inputCount, /* Including the first glyph (not matched) */
+                                               const USHORT input[], /* Array of input values--start with second glyph */
+                                               unsigned int lookupCount HB_UNUSED,
+                                               const LookupRecord lookupRecord[] HB_UNUSED,
+                                               ContextApplyLookupContext &lookup_context)
+{
+  return would_match_input (c,
+                            inputCount, input,
+                            lookup_context.funcs.match, lookup_context.match_data);
+}
+static inline bool context_apply_lookup (hb_apply_context_t *c,
+                                         unsigned int inputCount, /* Including the first glyph (not matched) */
+                                         const USHORT input[], /* Array of input values--start with second glyph */
+                                         unsigned int lookupCount,
+                                         const LookupRecord lookupRecord[],
+                                         ContextApplyLookupContext &lookup_context)
+{
+  unsigned int match_length = 0;
+  unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
+  return match_input (c,
+                      inputCount, input,
+                      lookup_context.funcs.match, lookup_context.match_data,
+                      &match_length, match_positions)
+      && apply_lookup (c,
+                       inputCount, match_positions,
+                       lookupCount, lookupRecord,
+                       match_length);
+}
+
+struct Rule
+{
+  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
+  {
+    TRACE_CLOSURE (this);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
+    context_closure_lookup (c,
+                            inputCount, inputZ,
+                            lookupCount, lookupRecord,
+                            lookup_context);
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
+    context_collect_glyphs_lookup (c,
+                                   inputCount, inputZ,
+                                   lookupCount, lookupRecord,
+                                   lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
+  {
+    TRACE_WOULD_APPLY (this);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
+    return_trace (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
+  }
+
+  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
+  {
+    TRACE_APPLY (this);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
+    return_trace (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
+  }
+
+  public:
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return inputCount.sanitize (c)
+        && lookupCount.sanitize (c)
+        && c->check_range (inputZ,
+                           inputZ[0].static_size * inputCount
+                           + lookupRecordX[0].static_size * lookupCount);
+  }
+
+  protected:
+  USHORT        inputCount;             /* Total number of glyphs in input
+                                         * glyph sequence--includes the first
+                                         * glyph */
+  USHORT        lookupCount;            /* Number of LookupRecords */
+  USHORT        inputZ[VAR];            /* Array of match inputs--start with
+                                         * second glyph */
+  LookupRecord  lookupRecordX[VAR];     /* Array of LookupRecords--in
+                                         * design order */
+  public:
+  DEFINE_SIZE_ARRAY2 (4, inputZ, lookupRecordX);
+};
+
+struct RuleSet
+{
+  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
+  {
+    TRACE_CLOSURE (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      (this+rule[i]).closure (c, lookup_context);
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      (this+rule[i]).collect_glyphs (c, lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
+  {
+    TRACE_WOULD_APPLY (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+    {
+      if ((this+rule[i]).would_apply (c, lookup_context))
+        return_trace (true);
+    }
+    return_trace (false);
+  }
+
+  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
+  {
+    TRACE_APPLY (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+    {
+      if ((this+rule[i]).apply (c, lookup_context))
+        return_trace (true);
+    }
+    return_trace (false);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (rule.sanitize (c, this));
+  }
+
+  protected:
+  OffsetArrayOf<Rule>
+                rule;                   /* Array of Rule tables
+                                         * ordered by preference */
+  public:
+  DEFINE_SIZE_ARRAY (2, rule);
+};
+
+
+struct ContextFormat1
+{
+  inline void closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+
+    const Coverage &cov = (this+coverage);
+
+    struct ContextClosureLookupContext lookup_context = {
+      {intersects_glyph},
+      NULL
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (cov.intersects_coverage (c->glyphs, i)) {
+        const RuleSet &rule_set = this+ruleSet[i];
+        rule_set.closure (c, lookup_context);
+      }
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+
+    struct ContextCollectGlyphsLookupContext lookup_context = {
+      {collect_glyph},
+      NULL
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+
+    const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
+    struct ContextApplyLookupContext lookup_context = {
+      {match_glyph},
+      NULL
+    };
+    return_trace (rule_set.would_apply (c, lookup_context));
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED))
+      return_trace (false);
+
+    const RuleSet &rule_set = this+ruleSet[index];
+    struct ContextApplyLookupContext lookup_context = {
+      {match_glyph},
+      NULL
+    };
+    return_trace (rule_set.apply (c, lookup_context));
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 1 */
+  OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of table */
+  OffsetArrayOf<RuleSet>
+                ruleSet;                /* Array of RuleSet tables
+                                         * ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_ARRAY (6, ruleSet);
+};
+
+
+struct ContextFormat2
+{
+  inline void closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    if (!(this+coverage).intersects (c->glyphs))
+      return;
+
+    const ClassDef &class_def = this+classDef;
+
+    struct ContextClosureLookupContext lookup_context = {
+      {intersects_class},
+      &class_def
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (class_def.intersects_class (c->glyphs, i)) {
+        const RuleSet &rule_set = this+ruleSet[i];
+        rule_set.closure (c, lookup_context);
+      }
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+
+    const ClassDef &class_def = this+classDef;
+    struct ContextCollectGlyphsLookupContext lookup_context = {
+      {collect_class},
+      &class_def
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+
+    const ClassDef &class_def = this+classDef;
+    unsigned int index = class_def.get_class (c->glyphs[0]);
+    const RuleSet &rule_set = this+ruleSet[index];
+    struct ContextApplyLookupContext lookup_context = {
+      {match_class},
+      &class_def
+    };
+    return_trace (rule_set.would_apply (c, lookup_context));
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    const ClassDef &class_def = this+classDef;
+    index = class_def.get_class (c->buffer->cur().codepoint);
+    const RuleSet &rule_set = this+ruleSet[index];
+    struct ContextApplyLookupContext lookup_context = {
+      {match_class},
+      &class_def
+    };
+    return_trace (rule_set.apply (c, lookup_context));
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 2 */
+  OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of table */
+  OffsetTo<ClassDef>
+                classDef;               /* Offset to glyph ClassDef table--from
+                                         * beginning of table */
+  OffsetArrayOf<RuleSet>
+                ruleSet;                /* Array of RuleSet tables
+                                         * ordered by class */
+  public:
+  DEFINE_SIZE_ARRAY (8, ruleSet);
+};
+
+
+struct ContextFormat3
+{
+  inline void closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    if (!(this+coverageZ[0]).intersects (c->glyphs))
+      return;
+
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
+    struct ContextClosureLookupContext lookup_context = {
+      {intersects_coverage},
+      this
+    };
+    context_closure_lookup (c,
+                            glyphCount, (const USHORT *) (coverageZ + 1),
+                            lookupCount, lookupRecord,
+                            lookup_context);
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverageZ[0]).add_coverage (c->input);
+
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
+    struct ContextCollectGlyphsLookupContext lookup_context = {
+      {collect_coverage},
+      this
+    };
+
+    context_collect_glyphs_lookup (c,
+                                   glyphCount, (const USHORT *) (coverageZ + 1),
+                                   lookupCount, lookupRecord,
+                                   lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
+    struct ContextApplyLookupContext lookup_context = {
+      {match_coverage},
+      this
+    };
+    return_trace (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverageZ[0];
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
+    struct ContextApplyLookupContext lookup_context = {
+      {match_coverage},
+      this
+    };
+    return_trace (context_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!c->check_struct (this)) return_trace (false);
+    unsigned int count = glyphCount;
+    if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
+    if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return_trace (false);
+    for (unsigned int i = 0; i < count; i++)
+      if (!coverageZ[i].sanitize (c, this)) return_trace (false);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
+    return_trace (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 3 */
+  USHORT        glyphCount;             /* Number of glyphs in the input glyph
+                                         * sequence */
+  USHORT        lookupCount;            /* Number of LookupRecords */
+  OffsetTo<Coverage>
+                coverageZ[VAR];         /* Array of offsets to Coverage
+                                         * table in glyph sequence order */
+  LookupRecord  lookupRecordX[VAR];     /* Array of LookupRecords--in
+                                         * design order */
+  public:
+  DEFINE_SIZE_ARRAY2 (6, coverageZ, lookupRecordX);
+};
+
+struct Context
+{
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1));
+    case 2: return_trace (c->dispatch (u.format2));
+    case 3: return_trace (c->dispatch (u.format3));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  USHORT                format;         /* Format identifier */
+  ContextFormat1        format1;
+  ContextFormat2        format2;
+  ContextFormat3        format3;
+  } u;
+};
+
+
+/* Chaining Contextual lookups */
+
+struct ChainContextClosureLookupContext
+{
+  ContextClosureFuncs funcs;
+  const void *intersects_data[3];
+};
+
+struct ChainContextCollectGlyphsLookupContext
+{
+  ContextCollectGlyphsFuncs funcs;
+  const void *collect_data[3];
+};
+
+struct ChainContextApplyLookupContext
+{
+  ContextApplyFuncs funcs;
+  const void *match_data[3];
+};
+
+static inline void chain_context_closure_lookup (hb_closure_context_t *c,
+                                                 unsigned int backtrackCount,
+                                                 const USHORT backtrack[],
+                                                 unsigned int inputCount, /* Including the first glyph (not matched) */
+                                                 const USHORT input[], /* Array of input values--start with second glyph */
+                                                 unsigned int lookaheadCount,
+                                                 const USHORT lookahead[],
+                                                 unsigned int lookupCount,
+                                                 const LookupRecord lookupRecord[],
+                                                 ChainContextClosureLookupContext &lookup_context)
+{
+  if (intersects_array (c,
+                        backtrackCount, backtrack,
+                        lookup_context.funcs.intersects, lookup_context.intersects_data[0])
+   && intersects_array (c,
+                        inputCount ? inputCount - 1 : 0, input,
+                        lookup_context.funcs.intersects, lookup_context.intersects_data[1])
+   && intersects_array (c,
+                       lookaheadCount, lookahead,
+                       lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
+    recurse_lookups (c,
+                     lookupCount, lookupRecord);
+}
+
+static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
+                                                        unsigned int backtrackCount,
+                                                        const USHORT backtrack[],
+                                                        unsigned int inputCount, /* Including the first glyph (not matched) */
+                                                        const USHORT input[], /* Array of input values--start with second glyph */
+                                                        unsigned int lookaheadCount,
+                                                        const USHORT lookahead[],
+                                                        unsigned int lookupCount,
+                                                        const LookupRecord lookupRecord[],
+                                                        ChainContextCollectGlyphsLookupContext &lookup_context)
+{
+  collect_array (c, c->before,
+                 backtrackCount, backtrack,
+                 lookup_context.funcs.collect, lookup_context.collect_data[0]);
+  collect_array (c, c->input,
+                 inputCount ? inputCount - 1 : 0, input,
+                 lookup_context.funcs.collect, lookup_context.collect_data[1]);
+  collect_array (c, c->after,
+                 lookaheadCount, lookahead,
+                 lookup_context.funcs.collect, lookup_context.collect_data[2]);
+  recurse_lookups (c,
+                   lookupCount, lookupRecord);
+}
+
+static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
+                                                     unsigned int backtrackCount,
+                                                     const USHORT backtrack[] HB_UNUSED,
+                                                     unsigned int inputCount, /* Including the first glyph (not matched) */
+                                                     const USHORT input[], /* Array of input values--start with second glyph */
+                                                     unsigned int lookaheadCount,
+                                                     const USHORT lookahead[] HB_UNUSED,
+                                                     unsigned int lookupCount HB_UNUSED,
+                                                     const LookupRecord lookupRecord[] HB_UNUSED,
+                                                     ChainContextApplyLookupContext &lookup_context)
+{
+  return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
+      && would_match_input (c,
+                            inputCount, input,
+                            lookup_context.funcs.match, lookup_context.match_data[1]);
+}
+
+static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
+                                               unsigned int backtrackCount,
+                                               const USHORT backtrack[],
+                                               unsigned int inputCount, /* Including the first glyph (not matched) */
+                                               const USHORT input[], /* Array of input values--start with second glyph */
+                                               unsigned int lookaheadCount,
+                                               const USHORT lookahead[],
+                                               unsigned int lookupCount,
+                                               const LookupRecord lookupRecord[],
+                                               ChainContextApplyLookupContext &lookup_context)
+{
+  unsigned int match_length = 0;
+  unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
+  return match_input (c,
+                      inputCount, input,
+                      lookup_context.funcs.match, lookup_context.match_data[1],
+                      &match_length, match_positions)
+      && match_backtrack (c,
+                          backtrackCount, backtrack,
+                          lookup_context.funcs.match, lookup_context.match_data[0])
+      && match_lookahead (c,
+                          lookaheadCount, lookahead,
+                          lookup_context.funcs.match, lookup_context.match_data[2],
+                          match_length)
+      && apply_lookup (c,
+                       inputCount, match_positions,
+                       lookupCount, lookupRecord,
+                       match_length);
+}
+
+struct ChainRule
+{
+  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
+  {
+    TRACE_CLOSURE (this);
+    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    chain_context_closure_lookup (c,
+                                  backtrack.len, backtrack.array,
+                                  input.len, input.array,
+                                  lookahead.len, lookahead.array,
+                                  lookup.len, lookup.array,
+                                  lookup_context);
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    chain_context_collect_glyphs_lookup (c,
+                                         backtrack.len, backtrack.array,
+                                         input.len, input.array,
+                                         lookahead.len, lookahead.array,
+                                         lookup.len, lookup.array,
+                                         lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+  {
+    TRACE_WOULD_APPLY (this);
+    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    return_trace (chain_context_would_apply_lookup (c,
+                                                    backtrack.len, backtrack.array,
+                                                    input.len, input.array,
+                                                    lookahead.len, lookahead.array, lookup.len,
+                                                    lookup.array, lookup_context));
+  }
+
+  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+  {
+    TRACE_APPLY (this);
+    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    return_trace (chain_context_apply_lookup (c,
+                                              backtrack.len, backtrack.array,
+                                              input.len, input.array,
+                                              lookahead.len, lookahead.array, lookup.len,
+                                              lookup.array, lookup_context));
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!backtrack.sanitize (c)) return_trace (false);
+    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+    if (!input.sanitize (c)) return_trace (false);
+    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    if (!lookahead.sanitize (c)) return_trace (false);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    return_trace (lookup.sanitize (c));
+  }
+
+  protected:
+  ArrayOf<USHORT>
+                backtrack;              /* Array of backtracking values
+                                         * (to be matched before the input
+                                         * sequence) */
+  HeadlessArrayOf<USHORT>
+                inputX;                 /* Array of input values (start with
+                                         * second glyph) */
+  ArrayOf<USHORT>
+                lookaheadX;             /* Array of lookahead values's (to be
+                                         * matched after the input sequence) */
+  ArrayOf<LookupRecord>
+                lookupX;                /* Array of LookupRecords--in
+                                         * design order) */
+  public:
+  DEFINE_SIZE_MIN (8);
+};
+
+struct ChainRuleSet
+{
+  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
+  {
+    TRACE_CLOSURE (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      (this+rule[i]).closure (c, lookup_context);
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      (this+rule[i]).collect_glyphs (c, lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+  {
+    TRACE_WOULD_APPLY (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      if ((this+rule[i]).would_apply (c, lookup_context))
+        return_trace (true);
+
+    return_trace (false);
+  }
+
+  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+  {
+    TRACE_APPLY (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      if ((this+rule[i]).apply (c, lookup_context))
+        return_trace (true);
+
+    return_trace (false);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (rule.sanitize (c, this));
+  }
+
+  protected:
+  OffsetArrayOf<ChainRule>
+                rule;                   /* Array of ChainRule tables
+                                         * ordered by preference */
+  public:
+  DEFINE_SIZE_ARRAY (2, rule);
+};
+
+struct ChainContextFormat1
+{
+  inline void closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    const Coverage &cov = (this+coverage);
+
+    struct ChainContextClosureLookupContext lookup_context = {
+      {intersects_glyph},
+      {NULL, NULL, NULL}
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (cov.intersects_coverage (c->glyphs, i)) {
+        const ChainRuleSet &rule_set = this+ruleSet[i];
+        rule_set.closure (c, lookup_context);
+      }
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+
+    struct ChainContextCollectGlyphsLookupContext lookup_context = {
+      {collect_glyph},
+      {NULL, NULL, NULL}
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+
+    const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
+    struct ChainContextApplyLookupContext lookup_context = {
+      {match_glyph},
+      {NULL, NULL, NULL}
+    };
+    return_trace (rule_set.would_apply (c, lookup_context));
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    const ChainRuleSet &rule_set = this+ruleSet[index];
+    struct ChainContextApplyLookupContext lookup_context = {
+      {match_glyph},
+      {NULL, NULL, NULL}
+    };
+    return_trace (rule_set.apply (c, lookup_context));
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 1 */
+  OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of table */
+  OffsetArrayOf<ChainRuleSet>
+                ruleSet;                /* Array of ChainRuleSet tables
+                                         * ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_ARRAY (6, ruleSet);
+};
+
+struct ChainContextFormat2
+{
+  inline void closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    if (!(this+coverage).intersects (c->glyphs))
+      return;
+
+    const ClassDef &backtrack_class_def = this+backtrackClassDef;
+    const ClassDef &input_class_def = this+inputClassDef;
+    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+
+    struct ChainContextClosureLookupContext lookup_context = {
+      {intersects_class},
+      {&backtrack_class_def,
+       &input_class_def,
+       &lookahead_class_def}
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (input_class_def.intersects_class (c->glyphs, i)) {
+        const ChainRuleSet &rule_set = this+ruleSet[i];
+        rule_set.closure (c, lookup_context);
+      }
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+
+    const ClassDef &backtrack_class_def = this+backtrackClassDef;
+    const ClassDef &input_class_def = this+inputClassDef;
+    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+
+    struct ChainContextCollectGlyphsLookupContext lookup_context = {
+      {collect_class},
+      {&backtrack_class_def,
+       &input_class_def,
+       &lookahead_class_def}
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+
+    const ClassDef &backtrack_class_def = this+backtrackClassDef;
+    const ClassDef &input_class_def = this+inputClassDef;
+    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+
+    unsigned int index = input_class_def.get_class (c->glyphs[0]);
+    const ChainRuleSet &rule_set = this+ruleSet[index];
+    struct ChainContextApplyLookupContext lookup_context = {
+      {match_class},
+      {&backtrack_class_def,
+       &input_class_def,
+       &lookahead_class_def}
+    };
+    return_trace (rule_set.would_apply (c, lookup_context));
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    const ClassDef &backtrack_class_def = this+backtrackClassDef;
+    const ClassDef &input_class_def = this+inputClassDef;
+    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+
+    index = input_class_def.get_class (c->buffer->cur().codepoint);
+    const ChainRuleSet &rule_set = this+ruleSet[index];
+    struct ChainContextApplyLookupContext lookup_context = {
+      {match_class},
+      {&backtrack_class_def,
+       &input_class_def,
+       &lookahead_class_def}
+    };
+    return_trace (rule_set.apply (c, lookup_context));
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) &&
+                  backtrackClassDef.sanitize (c, this) &&
+                  inputClassDef.sanitize (c, this) &&
+                  lookaheadClassDef.sanitize (c, this) &&
+                  ruleSet.sanitize (c, this));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 2 */
+  OffsetTo<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of table */
+  OffsetTo<ClassDef>
+                backtrackClassDef;      /* Offset to glyph ClassDef table
+                                         * containing backtrack sequence
+                                         * data--from beginning of table */
+  OffsetTo<ClassDef>
+                inputClassDef;          /* Offset to glyph ClassDef
+                                         * table containing input sequence
+                                         * data--from beginning of table */
+  OffsetTo<ClassDef>
+                lookaheadClassDef;      /* Offset to glyph ClassDef table
+                                         * containing lookahead sequence
+                                         * data--from beginning of table */
+  OffsetArrayOf<ChainRuleSet>
+                ruleSet;                /* Array of ChainRuleSet tables
+                                         * ordered by class */
+  public:
+  DEFINE_SIZE_ARRAY (12, ruleSet);
+};
+
+struct ChainContextFormat3
+{
+  inline void closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+    if (!(this+input[0]).intersects (c->glyphs))
+      return;
+
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    struct ChainContextClosureLookupContext lookup_context = {
+      {intersects_coverage},
+      {this, this, this}
+    };
+    chain_context_closure_lookup (c,
+                                  backtrack.len, (const USHORT *) backtrack.array,
+                                  input.len, (const USHORT *) input.array + 1,
+                                  lookahead.len, (const USHORT *) lookahead.array,
+                                  lookup.len, lookup.array,
+                                  lookup_context);
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+    (this+input[0]).add_coverage (c->input);
+
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    struct ChainContextCollectGlyphsLookupContext lookup_context = {
+      {collect_coverage},
+      {this, this, this}
+    };
+    chain_context_collect_glyphs_lookup (c,
+                                         backtrack.len, (const USHORT *) backtrack.array,
+                                         input.len, (const USHORT *) input.array + 1,
+                                         lookahead.len, (const USHORT *) lookahead.array,
+                                         lookup.len, lookup.array,
+                                         lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    struct ChainContextApplyLookupContext lookup_context = {
+      {match_coverage},
+      {this, this, this}
+    };
+    return_trace (chain_context_would_apply_lookup (c,
+                                                    backtrack.len, (const USHORT *) backtrack.array,
+                                                    input.len, (const USHORT *) input.array + 1,
+                                                    lookahead.len, (const USHORT *) lookahead.array,
+                                                    lookup.len, lookup.array, lookup_context));
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    return this+input[0];
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+    unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    struct ChainContextApplyLookupContext lookup_context = {
+      {match_coverage},
+      {this, this, this}
+    };
+    return_trace (chain_context_apply_lookup (c,
+                                              backtrack.len, (const USHORT *) backtrack.array,
+                                              input.len, (const USHORT *) input.array + 1,
+                                              lookahead.len, (const USHORT *) lookahead.array,
+                                              lookup.len, lookup.array, lookup_context));
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!backtrack.sanitize (c, this)) return_trace (false);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    if (!input.sanitize (c, this)) return_trace (false);
+    if (!input.len) return_trace (false); /* To be consistent with Context. */
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    if (!lookahead.sanitize (c, this)) return_trace (false);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    return_trace (lookup.sanitize (c));
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier--format = 3 */
+  OffsetArrayOf<Coverage>
+                backtrack;              /* Array of coverage tables
+                                         * in backtracking sequence, in  glyph
+                                         * sequence order */
+  OffsetArrayOf<Coverage>
+                inputX          ;       /* Array of coverage
+                                         * tables in input sequence, in glyph
+                                         * sequence order */
+  OffsetArrayOf<Coverage>
+                lookaheadX;             /* Array of coverage tables
+                                         * in lookahead sequence, in glyph
+                                         * sequence order */
+  ArrayOf<LookupRecord>
+                lookupX;                /* Array of LookupRecords--in
+                                         * design order) */
+  public:
+  DEFINE_SIZE_MIN (10);
+};
+
+struct ChainContext
+{
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1));
+    case 2: return_trace (c->dispatch (u.format2));
+    case 3: return_trace (c->dispatch (u.format3));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  USHORT                format; /* Format identifier */
+  ChainContextFormat1   format1;
+  ChainContextFormat2   format2;
+  ChainContextFormat3   format3;
+  } u;
+};
+
+
+template <typename T>
+struct ExtensionFormat1
+{
+  inline unsigned int get_type (void) const { return extensionLookupType; }
+
+  template <typename X>
+  inline const X& get_subtable (void) const
+  {
+    unsigned int offset = extensionOffset;
+    if (unlikely (!offset)) return Null(typename T::LookupSubTable);
+    return StructAtOffset<typename T::LookupSubTable> (this, offset);
+  }
+
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, format);
+    if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
+    return_trace (get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ()));
+  }
+
+  /* This is called from may_dispatch() above with hb_sanitize_context_t. */
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && extensionOffset != 0);
+  }
+
+  protected:
+  USHORT        format;                 /* Format identifier. Set to 1. */
+  USHORT        extensionLookupType;    /* Lookup type of subtable referenced
+                                         * by ExtensionOffset (i.e. the
+                                         * extension subtable). */
+  ULONG         extensionOffset;        /* Offset to the extension subtable,
+                                         * of lookup type subtable. */
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+template <typename T>
+struct Extension
+{
+  inline unsigned int get_type (void) const
+  {
+    switch (u.format) {
+    case 1: return u.format1.get_type ();
+    default:return 0;
+    }
+  }
+  template <typename X>
+  inline const X& get_subtable (void) const
+  {
+    switch (u.format) {
+    case 1: return u.format1.template get_subtable<typename T::LookupSubTable> ();
+    default:return Null(typename T::LookupSubTable);
+    }
+  }
+
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (u.format1.dispatch (c));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  USHORT                format;         /* Format identifier */
+  ExtensionFormat1<T>   format1;
+  } u;
+};
+
+
+/*
+ * GSUB/GPOS Common
+ */
+
+struct GSUBGPOS
+{
+  static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB;
+  static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS;
+
+  inline unsigned int get_script_count (void) const
+  { return (this+scriptList).len; }
+  inline const Tag& get_script_tag (unsigned int i) const
+  { return (this+scriptList).get_tag (i); }
+  inline unsigned int get_script_tags (unsigned int start_offset,
+                                       unsigned int *script_count /* IN/OUT */,
+                                       hb_tag_t     *script_tags /* OUT */) const
+  { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
+  inline const Script& get_script (unsigned int i) const
+  { return (this+scriptList)[i]; }
+  inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
+  { return (this+scriptList).find_index (tag, index); }
+
+  inline unsigned int get_feature_count (void) const
+  { return (this+featureList).len; }
+  inline hb_tag_t get_feature_tag (unsigned int i) const
+  { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
+  inline unsigned int get_feature_tags (unsigned int start_offset,
+                                        unsigned int *feature_count /* IN/OUT */,
+                                        hb_tag_t     *feature_tags /* OUT */) const
+  { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
+  inline const Feature& get_feature (unsigned int i) const
+  { return (this+featureList)[i]; }
+  inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
+  { return (this+featureList).find_index (tag, index); }
+
+  inline unsigned int get_lookup_count (void) const
+  { return (this+lookupList).len; }
+  inline const Lookup& get_lookup (unsigned int i) const
+  { return (this+lookupList)[i]; }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (version.sanitize (c) &&
+                  likely (version.major == 1) &&
+                  scriptList.sanitize (c, this) &&
+                  featureList.sanitize (c, this) &&
+                  lookupList.sanitize (c, this));
+  }
+
+  protected:
+  FixedVersion<>version;        /* Version of the GSUB/GPOS table--initially set
+                                 * to 0x00010000u */
+  OffsetTo<ScriptList>
+                scriptList;     /* ScriptList table */
+  OffsetTo<FeatureList>
+                featureList;    /* FeatureList table */
+  OffsetTo<LookupList>
+                lookupList;     /* LookupList table */
+  public:
+  DEFINE_SIZE_STATIC (10);
+};
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-layout-jstf-table.hh b/src/share/native/sun/font/harfbuzz/hb-ot-layout-jstf-table.hh
new file mode 100644
index 0000000..be61722
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-layout-jstf-table.hh
@@ -0,0 +1,234 @@
+/*
+ * 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_OT_LAYOUT_JSTF_TABLE_HH
+#define HB_OT_LAYOUT_JSTF_TABLE_HH
+
+#include "hb-open-type-private.hh"
+#include "hb-ot-layout-gpos-table.hh"
+
+
+namespace OT {
+
+
+/*
+ * JstfModList -- Justification Modification List Tables
+ */
+
+typedef IndexArray JstfModList;
+
+
+/*
+ * JstfMax -- Justification Maximum Table
+ */
+
+typedef OffsetListOf<PosLookup> JstfMax;
+
+
+/*
+ * JstfPriority -- Justification Priority Table
+ */
+
+struct JstfPriority
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  shrinkageEnableGSUB.sanitize (c, this) &&
+                  shrinkageDisableGSUB.sanitize (c, this) &&
+                  shrinkageEnableGPOS.sanitize (c, this) &&
+                  shrinkageDisableGPOS.sanitize (c, this) &&
+                  shrinkageJstfMax.sanitize (c, this) &&
+                  extensionEnableGSUB.sanitize (c, this) &&
+                  extensionDisableGSUB.sanitize (c, this) &&
+                  extensionEnableGPOS.sanitize (c, this) &&
+                  extensionDisableGPOS.sanitize (c, this) &&
+                  extensionJstfMax.sanitize (c, this));
+  }
+
+  protected:
+  OffsetTo<JstfModList>
+                shrinkageEnableGSUB;    /* Offset to Shrinkage Enable GSUB
+                                         * JstfModList table--from beginning of
+                                         * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+                shrinkageDisableGSUB;   /* Offset to Shrinkage Disable GSUB
+                                         * JstfModList table--from beginning of
+                                         * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+                shrinkageEnableGPOS;    /* Offset to Shrinkage Enable GPOS
+                                         * JstfModList table--from beginning of
+                                         * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+                shrinkageDisableGPOS;   /* Offset to Shrinkage Disable GPOS
+                                         * JstfModList table--from beginning of
+                                         * JstfPriority table--may be NULL */
+  OffsetTo<JstfMax>
+                shrinkageJstfMax;       /* Offset to Shrinkage JstfMax table--
+                                         * from beginning of JstfPriority table
+                                         * --may be NULL */
+  OffsetTo<JstfModList>
+                extensionEnableGSUB;    /* Offset to Extension Enable GSUB
+                                         * JstfModList table--from beginning of
+                                         * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+                extensionDisableGSUB;   /* Offset to Extension Disable GSUB
+                                         * JstfModList table--from beginning of
+                                         * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+                extensionEnableGPOS;    /* Offset to Extension Enable GPOS
+                                         * JstfModList table--from beginning of
+                                         * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+                extensionDisableGPOS;   /* Offset to Extension Disable GPOS
+                                         * JstfModList table--from beginning of
+                                         * JstfPriority table--may be NULL */
+  OffsetTo<JstfMax>
+                extensionJstfMax;       /* Offset to Extension JstfMax table--
+                                         * from beginning of JstfPriority table
+                                         * --may be NULL */
+
+  public:
+  DEFINE_SIZE_STATIC (20);
+};
+
+
+/*
+ * JstfLangSys -- Justification Language System Table
+ */
+
+struct JstfLangSys : OffsetListOf<JstfPriority>
+{
+  inline bool sanitize (hb_sanitize_context_t *c,
+                        const Record<JstfLangSys>::sanitize_closure_t * = NULL) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (OffsetListOf<JstfPriority>::sanitize (c));
+  }
+};
+
+
+/*
+ * ExtenderGlyphs -- Extender Glyph Table
+ */
+
+typedef SortedArrayOf<GlyphID> ExtenderGlyphs;
+
+
+/*
+ * JstfScript -- The Justification Table
+ */
+
+struct JstfScript
+{
+  inline unsigned int get_lang_sys_count (void) const
+  { return langSys.len; }
+  inline const Tag& get_lang_sys_tag (unsigned int i) const
+  { return langSys.get_tag (i); }
+  inline unsigned int get_lang_sys_tags (unsigned int start_offset,
+                                         unsigned int *lang_sys_count /* IN/OUT */,
+                                         hb_tag_t     *lang_sys_tags /* OUT */) const
+  { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
+  inline const JstfLangSys& get_lang_sys (unsigned int i) const
+  {
+    if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
+    return this+langSys[i].offset;
+  }
+  inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
+  { return langSys.find_index (tag, index); }
+
+  inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
+  inline const JstfLangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
+
+  inline bool sanitize (hb_sanitize_context_t *c,
+                        const Record<JstfScript>::sanitize_closure_t * = NULL) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (extenderGlyphs.sanitize (c, this) &&
+                  defaultLangSys.sanitize (c, this) &&
+                  langSys.sanitize (c, this));
+  }
+
+  protected:
+  OffsetTo<ExtenderGlyphs>
+                extenderGlyphs; /* Offset to ExtenderGlyph table--from beginning
+                                 * of JstfScript table-may be NULL */
+  OffsetTo<JstfLangSys>
+                defaultLangSys; /* Offset to DefaultJstfLangSys table--from
+                                 * beginning of JstfScript table--may be Null */
+  RecordArrayOf<JstfLangSys>
+                langSys;        /* Array of JstfLangSysRecords--listed
+                                 * alphabetically by LangSysTag */
+  public:
+  DEFINE_SIZE_ARRAY (6, langSys);
+};
+
+
+/*
+ * JSTF -- The Justification Table
+ */
+
+struct JSTF
+{
+  static const hb_tag_t tableTag        = HB_OT_TAG_JSTF;
+
+  inline unsigned int get_script_count (void) const
+  { return scriptList.len; }
+  inline const Tag& get_script_tag (unsigned int i) const
+  { return scriptList.get_tag (i); }
+  inline unsigned int get_script_tags (unsigned int start_offset,
+                                       unsigned int *script_count /* IN/OUT */,
+                                       hb_tag_t     *script_tags /* OUT */) const
+  { return scriptList.get_tags (start_offset, script_count, script_tags); }
+  inline const JstfScript& get_script (unsigned int i) const
+  { return this+scriptList[i].offset; }
+  inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
+  { return scriptList.find_index (tag, index); }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (version.sanitize (c) &&
+                  likely (version.major == 1) &&
+                  scriptList.sanitize (c, this));
+  }
+
+  protected:
+  FixedVersion<>version;        /* Version of the JSTF table--initially set
+                                 * to 0x00010000u */
+  RecordArrayOf<JstfScript>
+                scriptList;     /* Array of JstfScripts--listed
+                                 * alphabetically by ScriptTag */
+  public:
+  DEFINE_SIZE_ARRAY (6, scriptList);
+};
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_LAYOUT_JSTF_TABLE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-layout-private.hh b/src/share/native/sun/font/harfbuzz/hb-ot-layout-private.hh
new file mode 100644
index 0000000..2081949
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-layout-private.hh
@@ -0,0 +1,618 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * 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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_LAYOUT_PRIVATE_HH
+#define HB_OT_LAYOUT_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-font-private.hh"
+#include "hb-buffer-private.hh"
+#include "hb-set-private.hh"
+
+
+/* Private API corresponding to hb-ot-layout.h: */
+
+HB_INTERNAL hb_bool_t
+hb_ot_layout_table_find_feature (hb_face_t    *face,
+                                 hb_tag_t      table_tag,
+                                 hb_tag_t      feature_tag,
+                                 unsigned int *feature_index);
+
+
+/*
+ * GDEF
+ */
+
+enum hb_ot_layout_glyph_props_flags_t
+{
+  /* The following three match LookupFlags::Ignore* numbers. */
+  HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH   = 0x02u,
+  HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE     = 0x04u,
+  HB_OT_LAYOUT_GLYPH_PROPS_MARK         = 0x08u,
+
+  /* The following are used internally; not derived from GDEF. */
+  HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED  = 0x10u,
+  HB_OT_LAYOUT_GLYPH_PROPS_LIGATED      = 0x20u,
+  HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED   = 0x40u,
+
+  HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE     = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
+                                          HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
+                                          HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED
+};
+HB_MARK_AS_FLAG_T (hb_ot_layout_glyph_props_flags_t);
+
+
+/*
+ * GSUB/GPOS
+ */
+
+HB_INTERNAL hb_bool_t
+hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
+                                           unsigned int          lookup_index,
+                                           const hb_codepoint_t *glyphs,
+                                           unsigned int          glyphs_length,
+                                           hb_bool_t             zero_context);
+
+
+/* Should be called before all the substitute_lookup's are done. */
+HB_INTERNAL void
+hb_ot_layout_substitute_start (hb_font_t    *font,
+                               hb_buffer_t  *buffer);
+
+
+struct hb_ot_layout_lookup_accelerator_t;
+
+namespace OT {
+  struct hb_apply_context_t;
+  struct SubstLookup;
+}
+
+HB_INTERNAL void
+hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
+                                const OT::SubstLookup &lookup,
+                                const hb_ot_layout_lookup_accelerator_t &accel);
+
+
+/* Should be called before all the position_lookup's are done. */
+HB_INTERNAL void
+hb_ot_layout_position_start (hb_font_t    *font,
+                             hb_buffer_t  *buffer);
+
+/* Should be called after all the position_lookup's are done, to finish advances. */
+HB_INTERNAL void
+hb_ot_layout_position_finish_advances (hb_font_t    *font,
+                                       hb_buffer_t  *buffer);
+
+/* Should be called after hb_ot_layout_position_finish_advances, to finish offsets. */
+HB_INTERNAL void
+hb_ot_layout_position_finish_offsets (hb_font_t    *font,
+                                      hb_buffer_t  *buffer);
+
+
+
+/*
+ * hb_ot_layout_t
+ */
+
+namespace OT {
+  struct GDEF;
+  struct GSUB;
+  struct GPOS;
+}
+
+struct hb_ot_layout_lookup_accelerator_t
+{
+  template <typename TLookup>
+  inline void init (const TLookup &lookup)
+  {
+    digest.init ();
+    lookup.add_coverage (&digest);
+  }
+
+  inline void fini (void)
+  {
+  }
+
+  inline bool may_have (hb_codepoint_t g) const {
+    return digest.may_have (g);
+  }
+
+  private:
+  hb_set_digest_t digest;
+};
+
+struct hb_ot_layout_t
+{
+  hb_blob_t *gdef_blob;
+  hb_blob_t *gsub_blob;
+  hb_blob_t *gpos_blob;
+
+  const struct OT::GDEF *gdef;
+  const struct OT::GSUB *gsub;
+  const struct OT::GPOS *gpos;
+
+  unsigned int gsub_lookup_count;
+  unsigned int gpos_lookup_count;
+
+  hb_ot_layout_lookup_accelerator_t *gsub_accels;
+  hb_ot_layout_lookup_accelerator_t *gpos_accels;
+};
+
+
+HB_INTERNAL hb_ot_layout_t *
+_hb_ot_layout_create (hb_face_t *face);
+
+HB_INTERNAL void
+_hb_ot_layout_destroy (hb_ot_layout_t *layout);
+
+
+#define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
+
+
+/*
+ * Buffer var routines.
+ */
+
+/* buffer var allocations, used during the entire shaping process */
+#define unicode_props()         var2.u16[0]
+
+/* buffer var allocations, used during the GSUB/GPOS processing */
+#define glyph_props()           var1.u16[0] /* GDEF glyph properties */
+#define lig_props()             var1.u8[2] /* GSUB/GPOS ligature tracking */
+#define syllable()              var1.u8[3] /* GSUB/GPOS shaping boundaries */
+
+
+/* loop over syllables */
+
+#define foreach_syllable(buffer, start, end) \
+  for (unsigned int \
+       _count = buffer->len, \
+       start = 0, end = _count ? _next_syllable (buffer, 0) : 0; \
+       start < _count; \
+       start = end, end = _next_syllable (buffer, start))
+
+static inline unsigned int
+_next_syllable (hb_buffer_t *buffer, unsigned int start)
+{
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+
+  unsigned int syllable = info[start].syllable();
+  while (++start < count && syllable == info[start].syllable())
+    ;
+
+  return start;
+}
+
+
+/* unicode_props */
+
+/* Design:
+ * unicode_props() is a two-byte number.  The low byte includes:
+ * - General_Category: 5 bits.
+ * - A bit each for:
+ *   * Is it Default_Ignorable(); we have a modified Default_Ignorable().
+ *   * Whether it's one of the three Mongolian Free Variation Selectors.
+ *   * One free bit right now.
+ *
+ * The high-byte has different meanings, switched by the Gen-Cat:
+ * - For Mn,Mc,Me: the modified Combining_Class.
+ * - For Cf: whether it's ZWJ, ZWNJ, or something else.
+ * - For Ws: index of which space character this is, if space fallback
+ *   is needed, ie. we don't set this by default, only if asked to.
+ */
+
+enum hb_unicode_props_flags_t {
+  UPROPS_MASK_GEN_CAT   = 0x001Fu,
+  UPROPS_MASK_IGNORABLE = 0x0020u,
+  UPROPS_MASK_FVS       = 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3 */
+
+  /* If GEN_CAT=FORMAT, top byte masks: */
+  UPROPS_MASK_Cf_ZWJ    = 0x0100u,
+  UPROPS_MASK_Cf_ZWNJ   = 0x0200u
+};
+HB_MARK_AS_FLAG_T (hb_unicode_props_flags_t);
+
+static inline void
+_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
+{
+  hb_unicode_funcs_t *unicode = buffer->unicode;
+  unsigned int u = info->codepoint;
+  unsigned int gen_cat = (unsigned int) unicode->general_category (u);
+  unsigned int props = gen_cat;
+
+  if (u >= 0x80)
+  {
+    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
+    if (unlikely (unicode->is_default_ignorable (u)))
+    {
+      buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
+      props |=  UPROPS_MASK_IGNORABLE;
+      if (u == 0x200Cu) props |= UPROPS_MASK_Cf_ZWNJ;
+      if (u == 0x200Du) props |= UPROPS_MASK_Cf_ZWJ;
+      /* Mongolian Free Variation Selectors need to be remembered
+       * because although we need to hide them like default-ignorables,
+       * they need to non-ignorable during shaping.  This is similar to
+       * what we do for joiners in Indic-like shapers, but since the
+       * FVSes are GC=Mn, we have use a separate bit to remember them.
+       * Fixes:
+       * https://github.com/behdad/harfbuzz/issues/234
+       */
+      if (unlikely (hb_in_range (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_FVS;
+    }
+    else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL (gen_cat)))
+    {
+      /* The above check is just an optimization to let in only things we need further
+       * processing on. */
+
+      /* Only Mn and Mc can have non-zero ccc:
+       * http://www.unicode.org/policies/stability_policy.html#Property_Value
+       * """
+       * Canonical_Combining_Class, General_Category
+       * All characters other than those with General_Category property values
+       * Spacing_Mark (Mc) and Nonspacing_Mark (Mn) have the Canonical_Combining_Class
+       * property value 0.
+       * 1.1.5+
+       * """
+       *
+       * Also, all Mn's that are Default_Ignorable, have ccc=0, hence
+       * the "else if".
+       */
+      props |= unicode->modified_combining_class (info->codepoint)<<8;
+
+      /* Recategorize emoji skin-tone modifiers as Unicode mark, so they
+       * behave correctly in non-native directionality.  They originally
+       * are MODIFIER_SYMBOL.  Fixes:
+       * https://github.com/behdad/harfbuzz/issues/169
+       */
+      if (unlikely (hb_in_range (u, 0x1F3FBu, 0x1F3FFu)))
+      {
+        props = gen_cat = HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
+      }
+    }
+  }
+
+  info->unicode_props() = props;
+}
+
+static inline void
+_hb_glyph_info_set_general_category (hb_glyph_info_t *info,
+                                     hb_unicode_general_category_t gen_cat)
+{
+  /* Clears top-byte. */
+  info->unicode_props() = (unsigned int) gen_cat | (info->unicode_props() & (0xFF & ~UPROPS_MASK_GEN_CAT));
+}
+
+static inline hb_unicode_general_category_t
+_hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
+{
+  return (hb_unicode_general_category_t) (info->unicode_props() & UPROPS_MASK_GEN_CAT);
+}
+
+static inline bool
+_hb_glyph_info_is_unicode_mark (const hb_glyph_info_t *info)
+{
+  return HB_UNICODE_GENERAL_CATEGORY_IS_MARK (info->unicode_props() & UPROPS_MASK_GEN_CAT);
+}
+static inline void
+_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info,
+                                             unsigned int modified_class)
+{
+  if (unlikely (!_hb_glyph_info_is_unicode_mark (info)))
+    return;
+  info->unicode_props() = (modified_class<<8) | (info->unicode_props() & 0xFF);
+}
+static inline unsigned int
+_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
+{
+  return _hb_glyph_info_is_unicode_mark (info) ? info->unicode_props()>>8 : 0;
+}
+
+static inline bool
+_hb_glyph_info_is_unicode_space (const hb_glyph_info_t *info)
+{
+  return _hb_glyph_info_get_general_category (info) ==
+         HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
+}
+static inline void
+_hb_glyph_info_set_unicode_space_fallback_type (hb_glyph_info_t *info, hb_unicode_funcs_t::space_t s)
+{
+  if (unlikely (!_hb_glyph_info_is_unicode_space (info)))
+    return;
+  info->unicode_props() = (((unsigned int) s)<<8) | (info->unicode_props() & 0xFF);
+}
+static inline hb_unicode_funcs_t::space_t
+_hb_glyph_info_get_unicode_space_fallback_type (const hb_glyph_info_t *info)
+{
+  return _hb_glyph_info_is_unicode_space (info) ?
+         (hb_unicode_funcs_t::space_t) (info->unicode_props()>>8) :
+         hb_unicode_funcs_t::NOT_SPACE;
+}
+
+static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
+
+static inline hb_bool_t
+_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
+{
+  return (info->unicode_props() & UPROPS_MASK_IGNORABLE) &&
+         !_hb_glyph_info_ligated (info);
+}
+static inline hb_bool_t
+_hb_glyph_info_is_default_ignorable_and_not_fvs (const hb_glyph_info_t *info)
+{
+  return ((info->unicode_props() & (UPROPS_MASK_IGNORABLE|UPROPS_MASK_FVS))
+          == UPROPS_MASK_IGNORABLE) &&
+         !_hb_glyph_info_ligated (info);
+}
+
+static inline bool
+_hb_glyph_info_is_unicode_format (const hb_glyph_info_t *info)
+{
+  return _hb_glyph_info_get_general_category (info) ==
+         HB_UNICODE_GENERAL_CATEGORY_FORMAT;
+}
+static inline hb_bool_t
+_hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
+{
+  return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWNJ);
+}
+static inline hb_bool_t
+_hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
+{
+  return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWJ);
+}
+static inline hb_bool_t
+_hb_glyph_info_is_joiner (const hb_glyph_info_t *info)
+{
+  return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & (UPROPS_MASK_Cf_ZWNJ|UPROPS_MASK_Cf_ZWJ));
+}
+static inline void
+_hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
+{
+  if (!_hb_glyph_info_is_unicode_format (info))
+    return;
+  info->unicode_props() ^= UPROPS_MASK_Cf_ZWNJ | UPROPS_MASK_Cf_ZWJ;
+}
+
+/* lig_props: aka lig_id / lig_comp
+ *
+ * When a ligature is formed:
+ *
+ *   - The ligature glyph and any marks in between all the same newly allocated
+ *     lig_id,
+ *   - The ligature glyph will get lig_num_comps set to the number of components
+ *   - The marks get lig_comp > 0, reflecting which component of the ligature
+ *     they were applied to.
+ *   - This is used in GPOS to attach marks to the right component of a ligature
+ *     in MarkLigPos,
+ *   - Note that when marks are ligated together, much of the above is skipped
+ *     and the current lig_id reused.
+ *
+ * When a multiple-substitution is done:
+ *
+ *   - All resulting glyphs will have lig_id = 0,
+ *   - The resulting glyphs will have lig_comp = 0, 1, 2, ... respectively.
+ *   - This is used in GPOS to attach marks to the first component of a
+ *     multiple substitution in MarkBasePos.
+ *
+ * The numbers are also used in GPOS to do mark-to-mark positioning only
+ * to marks that belong to the same component of the same ligature.
+ */
+
+static inline void
+_hb_glyph_info_clear_lig_props (hb_glyph_info_t *info)
+{
+  info->lig_props() = 0;
+}
+
+#define IS_LIG_BASE 0x10
+
+static inline void
+_hb_glyph_info_set_lig_props_for_ligature (hb_glyph_info_t *info,
+                                           unsigned int lig_id,
+                                           unsigned int lig_num_comps)
+{
+  info->lig_props() = (lig_id << 5) | IS_LIG_BASE | (lig_num_comps & 0x0F);
+}
+
+static inline void
+_hb_glyph_info_set_lig_props_for_mark (hb_glyph_info_t *info,
+                                       unsigned int lig_id,
+                                       unsigned int lig_comp)
+{
+  info->lig_props() = (lig_id << 5) | (lig_comp & 0x0F);
+}
+
+static inline void
+_hb_glyph_info_set_lig_props_for_component (hb_glyph_info_t *info, unsigned int comp)
+{
+  _hb_glyph_info_set_lig_props_for_mark (info, 0, comp);
+}
+
+static inline unsigned int
+_hb_glyph_info_get_lig_id (const hb_glyph_info_t *info)
+{
+  return info->lig_props() >> 5;
+}
+
+static inline bool
+_hb_glyph_info_ligated_internal (const hb_glyph_info_t *info)
+{
+  return !!(info->lig_props() & IS_LIG_BASE);
+}
+
+static inline unsigned int
+_hb_glyph_info_get_lig_comp (const hb_glyph_info_t *info)
+{
+  if (_hb_glyph_info_ligated_internal (info))
+    return 0;
+  else
+    return info->lig_props() & 0x0F;
+}
+
+static inline unsigned int
+_hb_glyph_info_get_lig_num_comps (const hb_glyph_info_t *info)
+{
+  if ((info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE) &&
+      _hb_glyph_info_ligated_internal (info))
+    return info->lig_props() & 0x0F;
+  else
+    return 1;
+}
+
+static inline uint8_t
+_hb_allocate_lig_id (hb_buffer_t *buffer) {
+  uint8_t lig_id = buffer->next_serial () & 0x07;
+  if (unlikely (!lig_id))
+    lig_id = _hb_allocate_lig_id (buffer); /* in case of overflow */
+  return lig_id;
+}
+
+/* glyph_props: */
+
+static inline void
+_hb_glyph_info_set_glyph_props (hb_glyph_info_t *info, unsigned int props)
+{
+  info->glyph_props() = props;
+}
+
+static inline unsigned int
+_hb_glyph_info_get_glyph_props (const hb_glyph_info_t *info)
+{
+  return info->glyph_props();
+}
+
+static inline bool
+_hb_glyph_info_is_base_glyph (const hb_glyph_info_t *info)
+{
+  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
+}
+
+static inline bool
+_hb_glyph_info_is_ligature (const hb_glyph_info_t *info)
+{
+  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE);
+}
+
+static inline bool
+_hb_glyph_info_is_mark (const hb_glyph_info_t *info)
+{
+  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
+}
+
+static inline bool
+_hb_glyph_info_substituted (const hb_glyph_info_t *info)
+{
+  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
+}
+
+static inline bool
+_hb_glyph_info_ligated (const hb_glyph_info_t *info)
+{
+  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED);
+}
+
+static inline bool
+_hb_glyph_info_multiplied (const hb_glyph_info_t *info)
+{
+  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
+}
+
+static inline bool
+_hb_glyph_info_ligated_and_didnt_multiply (const hb_glyph_info_t *info)
+{
+  return _hb_glyph_info_ligated (info) && !_hb_glyph_info_multiplied (info);
+}
+
+static inline void
+_hb_glyph_info_clear_ligated_and_multiplied (hb_glyph_info_t *info)
+{
+  info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
+                           HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
+}
+
+static inline void
+_hb_glyph_info_clear_substituted (hb_glyph_info_t *info)
+{
+  info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
+}
+
+
+/* Allocation / deallocation. */
+
+static inline void
+_hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
+{
+  HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props);
+}
+
+static inline void
+_hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
+{
+  HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props);
+}
+
+static inline void
+_hb_buffer_assert_unicode_vars (hb_buffer_t *buffer)
+{
+  HB_BUFFER_ASSERT_VAR (buffer, unicode_props);
+}
+
+static inline void
+_hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer)
+{
+  HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
+  HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
+  HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
+}
+
+static inline void
+_hb_buffer_deallocate_gsubgpos_vars (hb_buffer_t *buffer)
+{
+  HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
+  HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
+  HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
+}
+
+static inline void
+_hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer)
+{
+  HB_BUFFER_ASSERT_VAR (buffer, glyph_props);
+  HB_BUFFER_ASSERT_VAR (buffer, lig_props);
+  HB_BUFFER_ASSERT_VAR (buffer, syllable);
+}
+
+/* Make sure no one directly touches our props... */
+#undef unicode_props0
+#undef unicode_props1
+#undef lig_props
+#undef glyph_props
+
+
+#endif /* HB_OT_LAYOUT_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-layout.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-layout.cpp
new file mode 100644
index 0000000..74f6113
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-layout.cpp
@@ -0,0 +1,1184 @@
+/*
+ * Copyright © 1998-2004  David Turner and Werner Lemberg
+ * Copyright © 2006  Behdad Esfahbod
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * 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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-open-type-private.hh"
+#include "hb-ot-layout-private.hh"
+
+#include "hb-ot-layout-gdef-table.hh"
+#include "hb-ot-layout-gsub-table.hh"
+#include "hb-ot-layout-gpos-table.hh"
+#include "hb-ot-layout-jstf-table.hh"
+
+#include "hb-ot-map-private.hh"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
+
+hb_ot_layout_t *
+_hb_ot_layout_create (hb_face_t *face)
+{
+  hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
+  if (unlikely (!layout))
+    return NULL;
+
+  layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
+  layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
+
+  layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
+  layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
+
+  layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
+  layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
+
+  {
+    /*
+     * The ugly business of blacklisting individual fonts' tables happen here!
+     * See this thread for why we finally had to bend in and do this:
+     * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html
+     */
+    unsigned int gdef_len = hb_blob_get_length (layout->gdef_blob);
+    unsigned int gsub_len = hb_blob_get_length (layout->gsub_blob);
+    unsigned int gpos_len = hb_blob_get_length (layout->gpos_blob);
+    if (0
+      /* sha1sum:c5ee92f0bca4bfb7d06c4d03e8cf9f9cf75d2e8a Windows 7? timesi.ttf */
+      || (442 == gdef_len && 42038 == gpos_len && 2874 == gsub_len)
+      /* sha1sum:37fc8c16a0894ab7b749e35579856c73c840867b Windows 7? timesbi.ttf */
+      || (430 == gdef_len && 40662 == gpos_len && 2874 == gsub_len)
+      /* sha1sum:19fc45110ea6cd3cdd0a5faca256a3797a069a80 Windows 7 timesi.ttf */
+      || (442 == gdef_len && 39116 == gpos_len && 2874 == gsub_len)
+      /* sha1sum:6d2d3c9ed5b7de87bc84eae0df95ee5232ecde26 Windows 7 timesbi.ttf */
+      || (430 == gdef_len && 39374 == gpos_len && 2874 == gsub_len)
+      /* sha1sum:8583225a8b49667c077b3525333f84af08c6bcd8 OS X 10.11.3 Times New Roman Italic.ttf */
+      || (490 == gdef_len && 41638 == gpos_len && 3046 == gsub_len)
+      /* sha1sum:ec0f5a8751845355b7c3271d11f9918a966cb8c9 OS X 10.11.3 Times New Roman Bold Italic.ttf */
+      || (478 == gdef_len && 41902 == gpos_len && 3046 == gsub_len)
+    )
+    {
+      /* In certain versions of Times New Roman Italic and Bold Italic,
+       * ASCII double quotation mark U+0022, mapped to glyph 5, has wrong
+       * glyph class 3 (mark) in GDEF.  Nuke the GDEF to avoid zero-width
+       * double-quote.  See:
+       * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html
+       */
+     if (3 == layout->gdef->get_glyph_class (5))
+       layout->gdef = &OT::Null(OT::GDEF);
+    }
+    else if (0
+      /* sha1sum:96eda93f7d33e79962451c6c39a6b51ee893ce8c  tahoma.ttf from Windows 8 */
+      || (898 == gdef_len && 46470 == gpos_len && 12554 == gsub_len)
+      /* sha1sum:20928dc06014e0cd120b6fc942d0c3b1a46ac2bc  tahomabd.ttf from Windows 8 */
+      || (910 == gdef_len && 47732 == gpos_len && 12566 == gsub_len)
+      /* sha1sum:4f95b7e4878f60fa3a39ca269618dfde9721a79e  tahoma.ttf from Windows 8.1 */
+      || (928 == gdef_len && 59332 == gpos_len && 23298 == gsub_len)
+      /* sha1sum:6d400781948517c3c0441ba42acb309584b73033  tahomabd.ttf from Windows 8.1 */
+      || (940 == gdef_len && 60732 == gpos_len && 23310 == gsub_len)
+      /* sha1sum:e55fa2dfe957a9f7ec26be516a0e30b0c925f846  tahoma.ttf from Windows 10 */
+      || (994 == gdef_len && 60336 == gpos_len && 24474 == gsub_len)
+      /* sha1sum:7199385abb4c2cc81c83a151a7599b6368e92343  tahomabd.ttf from Windows 10 */
+      || (1006 == gdef_len && 61740 == gpos_len && 24470 == gsub_len)
+      /* sha1sum:b0d36cf5a2fbe746a3dd277bffc6756a820807a7  Tahoma.ttf from Mac OS X 10.9 */
+      || (832 == gdef_len && 47162 == gpos_len && 7324 == gsub_len)
+      /* sha1sum:12fc4538e84d461771b30c18b5eb6bd434e30fba  Tahoma Bold.ttf from Mac OS X 10.9 */
+      || (844 == gdef_len && 45474 == gpos_len && 7302 == gsub_len)
+      /* sha1sum:73da7f025b238a3f737aa1fde22577a6370f77b0  himalaya.ttf from Windows 8 */
+      || (192 == gdef_len && 7254 == gpos_len && 12638 == gsub_len)
+      /* sha1sum:6e80fd1c0b059bbee49272401583160dc1e6a427  himalaya.ttf from Windows 8.1 */
+      || (192 == gdef_len && 7254 == gpos_len && 12690 == gsub_len)
+      /* 8d9267aea9cd2c852ecfb9f12a6e834bfaeafe44  cantarell-fonts-0.0.21/otf/Cantarell-Regular.otf */
+      /* 983988ff7b47439ab79aeaf9a45bd4a2c5b9d371  cantarell-fonts-0.0.21/otf/Cantarell-Oblique.otf */
+      || (188 == gdef_len && 3852 == gpos_len && 248 == gsub_len)
+      /* 2c0c90c6f6087ffbfea76589c93113a9cbb0e75f  cantarell-fonts-0.0.21/otf/Cantarell-Bold.otf */
+      /* 55461f5b853c6da88069ffcdf7f4dd3f8d7e3e6b  cantarell-fonts-0.0.21/otf/Cantarell-Bold-Oblique.otf */
+      || (188 == gdef_len && 3426 == gpos_len && 264 == gsub_len)
+    )
+    {
+      /* Many versions of Tahoma have bad GDEF tables that incorrectly classify some spacing marks
+       * such as certain IPA symbols as glyph class 3. So do older versions of Microsoft Himalaya,
+       * and the version of Cantarell shipped by Ubuntu 16.04.
+       * Nuke the GDEF tables of these fonts to avoid unwanted width-zeroing.
+       * See https://bugzilla.mozilla.org/show_bug.cgi?id=1279925
+       *     https://bugzilla.mozilla.org/show_bug.cgi?id=1279693
+       *     https://bugzilla.mozilla.org/show_bug.cgi?id=1279875
+       */
+      layout->gdef = &OT::Null(OT::GDEF);
+    }
+  }
+
+  layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
+  layout->gpos_lookup_count = layout->gpos->get_lookup_count ();
+
+  layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
+  layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
+
+  if (unlikely ((layout->gsub_lookup_count && !layout->gsub_accels) ||
+                (layout->gpos_lookup_count && !layout->gpos_accels)))
+  {
+    _hb_ot_layout_destroy (layout);
+    return NULL;
+  }
+
+  for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
+    layout->gsub_accels[i].init (layout->gsub->get_lookup (i));
+  for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
+    layout->gpos_accels[i].init (layout->gpos->get_lookup (i));
+
+  return layout;
+}
+
+void
+_hb_ot_layout_destroy (hb_ot_layout_t *layout)
+{
+  for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
+    layout->gsub_accels[i].fini ();
+  for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
+    layout->gpos_accels[i].fini ();
+
+  free (layout->gsub_accels);
+  free (layout->gpos_accels);
+
+  hb_blob_destroy (layout->gdef_blob);
+  hb_blob_destroy (layout->gsub_blob);
+  hb_blob_destroy (layout->gpos_blob);
+
+  free (layout);
+}
+
+static inline const OT::GDEF&
+_get_gdef (hb_face_t *face)
+{
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GDEF);
+  return *hb_ot_layout_from_face (face)->gdef;
+}
+static inline const OT::GSUB&
+_get_gsub (hb_face_t *face)
+{
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GSUB);
+  return *hb_ot_layout_from_face (face)->gsub;
+}
+static inline const OT::GPOS&
+_get_gpos (hb_face_t *face)
+{
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GPOS);
+  return *hb_ot_layout_from_face (face)->gpos;
+}
+
+
+/*
+ * GDEF
+ */
+
+hb_bool_t
+hb_ot_layout_has_glyph_classes (hb_face_t *face)
+{
+  return _get_gdef (face).has_glyph_classes ();
+}
+
+/**
+ * hb_ot_layout_get_glyph_class:
+ *
+ * Since: 0.9.7
+ **/
+hb_ot_layout_glyph_class_t
+hb_ot_layout_get_glyph_class (hb_face_t      *face,
+                              hb_codepoint_t  glyph)
+{
+  return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph);
+}
+
+/**
+ * hb_ot_layout_get_glyphs_in_class:
+ *
+ * Since: 0.9.7
+ **/
+void
+hb_ot_layout_get_glyphs_in_class (hb_face_t                  *face,
+                                  hb_ot_layout_glyph_class_t  klass,
+                                  hb_set_t                   *glyphs /* OUT */)
+{
+  return _get_gdef (face).get_glyphs_in_class (klass, glyphs);
+}
+
+unsigned int
+hb_ot_layout_get_attach_points (hb_face_t      *face,
+                                hb_codepoint_t  glyph,
+                                unsigned int    start_offset,
+                                unsigned int   *point_count /* IN/OUT */,
+                                unsigned int   *point_array /* OUT */)
+{
+  return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
+}
+
+unsigned int
+hb_ot_layout_get_ligature_carets (hb_font_t      *font,
+                                  hb_direction_t  direction,
+                                  hb_codepoint_t  glyph,
+                                  unsigned int    start_offset,
+                                  unsigned int   *caret_count /* IN/OUT */,
+                                  int            *caret_array /* OUT */)
+{
+  return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
+}
+
+
+/*
+ * GSUB/GPOS
+ */
+
+static const OT::GSUBGPOS&
+get_gsubgpos_table (hb_face_t *face,
+                    hb_tag_t   table_tag)
+{
+  switch (table_tag) {
+    case HB_OT_TAG_GSUB: return _get_gsub (face);
+    case HB_OT_TAG_GPOS: return _get_gpos (face);
+    default:             return OT::Null(OT::GSUBGPOS);
+  }
+}
+
+
+unsigned int
+hb_ot_layout_table_get_script_tags (hb_face_t    *face,
+                                    hb_tag_t      table_tag,
+                                    unsigned int  start_offset,
+                                    unsigned int *script_count /* IN/OUT */,
+                                    hb_tag_t     *script_tags /* OUT */)
+{
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+
+  return g.get_script_tags (start_offset, script_count, script_tags);
+}
+
+#define HB_OT_TAG_LATIN_SCRIPT          HB_TAG ('l', 'a', 't', 'n')
+
+hb_bool_t
+hb_ot_layout_table_find_script (hb_face_t    *face,
+                                hb_tag_t      table_tag,
+                                hb_tag_t      script_tag,
+                                unsigned int *script_index)
+{
+  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+
+  if (g.find_script_index (script_tag, script_index))
+    return true;
+
+  /* try finding 'DFLT' */
+  if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
+    return false;
+
+  /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
+   * including many versions of DejaVu Sans Mono! */
+  if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
+    return false;
+
+  /* try with 'latn'; some old fonts put their features there even though
+     they're really trying to support Thai, for example :( */
+  if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index))
+    return false;
+
+  if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
+  return false;
+}
+
+hb_bool_t
+hb_ot_layout_table_choose_script (hb_face_t      *face,
+                                  hb_tag_t        table_tag,
+                                  const hb_tag_t *script_tags,
+                                  unsigned int   *script_index,
+                                  hb_tag_t       *chosen_script)
+{
+  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+
+  while (*script_tags)
+  {
+    if (g.find_script_index (*script_tags, script_index)) {
+      if (chosen_script)
+        *chosen_script = *script_tags;
+      return true;
+    }
+    script_tags++;
+  }
+
+  /* try finding 'DFLT' */
+  if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) {
+    if (chosen_script)
+      *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT;
+    return false;
+  }
+
+  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
+  if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) {
+    if (chosen_script)
+      *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE;
+    return false;
+  }
+
+  /* try with 'latn'; some old fonts put their features there even though
+     they're really trying to support Thai, for example :( */
+  if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) {
+    if (chosen_script)
+      *chosen_script = HB_OT_TAG_LATIN_SCRIPT;
+    return false;
+  }
+
+  if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
+  if (chosen_script)
+    *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
+  return false;
+}
+
+unsigned int
+hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
+                                     hb_tag_t      table_tag,
+                                     unsigned int  start_offset,
+                                     unsigned int *feature_count /* IN/OUT */,
+                                     hb_tag_t     *feature_tags /* OUT */)
+{
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+
+  return g.get_feature_tags (start_offset, feature_count, feature_tags);
+}
+
+hb_bool_t
+hb_ot_layout_table_find_feature (hb_face_t    *face,
+                                 hb_tag_t      table_tag,
+                                 hb_tag_t      feature_tag,
+                                 unsigned int *feature_index)
+{
+  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+
+  unsigned int num_features = g.get_feature_count ();
+  for (unsigned int i = 0; i < num_features; i++)
+  {
+    if (feature_tag == g.get_feature_tag (i)) {
+      if (feature_index) *feature_index = i;
+      return true;
+    }
+  }
+
+  if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
+  return false;
+}
+
+
+unsigned int
+hb_ot_layout_script_get_language_tags (hb_face_t    *face,
+                                       hb_tag_t      table_tag,
+                                       unsigned int  script_index,
+                                       unsigned int  start_offset,
+                                       unsigned int *language_count /* IN/OUT */,
+                                       hb_tag_t     *language_tags /* OUT */)
+{
+  const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
+
+  return s.get_lang_sys_tags (start_offset, language_count, language_tags);
+}
+
+hb_bool_t
+hb_ot_layout_script_find_language (hb_face_t    *face,
+                                   hb_tag_t      table_tag,
+                                   unsigned int  script_index,
+                                   hb_tag_t      language_tag,
+                                   unsigned int *language_index)
+{
+  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
+  const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
+
+  if (s.find_lang_sys_index (language_tag, language_index))
+    return true;
+
+  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
+  if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
+    return false;
+
+  if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
+  return false;
+}
+
+hb_bool_t
+hb_ot_layout_language_get_required_feature_index (hb_face_t    *face,
+                                                  hb_tag_t      table_tag,
+                                                  unsigned int  script_index,
+                                                  unsigned int  language_index,
+                                                  unsigned int *feature_index)
+{
+  return hb_ot_layout_language_get_required_feature (face,
+                                                     table_tag,
+                                                     script_index,
+                                                     language_index,
+                                                     feature_index,
+                                                     NULL);
+}
+
+/**
+ * hb_ot_layout_language_get_required_feature:
+ *
+ * Since: 0.9.30
+ **/
+hb_bool_t
+hb_ot_layout_language_get_required_feature (hb_face_t    *face,
+                                            hb_tag_t      table_tag,
+                                            unsigned int  script_index,
+                                            unsigned int  language_index,
+                                            unsigned int *feature_index,
+                                            hb_tag_t     *feature_tag)
+{
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+  const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+
+  unsigned int index = l.get_required_feature_index ();
+  if (feature_index) *feature_index = index;
+  if (feature_tag) *feature_tag = g.get_feature_tag (index);
+
+  return l.has_required_feature ();
+}
+
+unsigned int
+hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
+                                           hb_tag_t      table_tag,
+                                           unsigned int  script_index,
+                                           unsigned int  language_index,
+                                           unsigned int  start_offset,
+                                           unsigned int *feature_count /* IN/OUT */,
+                                           unsigned int *feature_indexes /* OUT */)
+{
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+  const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+
+  return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
+}
+
+unsigned int
+hb_ot_layout_language_get_feature_tags (hb_face_t    *face,
+                                        hb_tag_t      table_tag,
+                                        unsigned int  script_index,
+                                        unsigned int  language_index,
+                                        unsigned int  start_offset,
+                                        unsigned int *feature_count /* IN/OUT */,
+                                        hb_tag_t     *feature_tags /* OUT */)
+{
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+  const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+
+  ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
+  unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
+
+  if (feature_tags) {
+    unsigned int count = *feature_count;
+    for (unsigned int i = 0; i < count; i++)
+      feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
+  }
+
+  return ret;
+}
+
+
+hb_bool_t
+hb_ot_layout_language_find_feature (hb_face_t    *face,
+                                    hb_tag_t      table_tag,
+                                    unsigned int  script_index,
+                                    unsigned int  language_index,
+                                    hb_tag_t      feature_tag,
+                                    unsigned int *feature_index)
+{
+  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+  const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+
+  unsigned int num_features = l.get_feature_count ();
+  for (unsigned int i = 0; i < num_features; i++) {
+    unsigned int f_index = l.get_feature_index (i);
+
+    if (feature_tag == g.get_feature_tag (f_index)) {
+      if (feature_index) *feature_index = f_index;
+      return true;
+    }
+  }
+
+  if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
+  return false;
+}
+
+/**
+ * hb_ot_layout_feature_get_lookups:
+ *
+ * Since: 0.9.7
+ **/
+unsigned int
+hb_ot_layout_feature_get_lookups (hb_face_t    *face,
+                                  hb_tag_t      table_tag,
+                                  unsigned int  feature_index,
+                                  unsigned int  start_offset,
+                                  unsigned int *lookup_count /* IN/OUT */,
+                                  unsigned int *lookup_indexes /* OUT */)
+{
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+  const OT::Feature &f = g.get_feature (feature_index);
+
+  return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
+}
+
+/**
+ * hb_ot_layout_table_get_lookup_count:
+ *
+ * Since: 0.9.22
+ **/
+unsigned int
+hb_ot_layout_table_get_lookup_count (hb_face_t    *face,
+                                     hb_tag_t      table_tag)
+{
+  switch (table_tag)
+  {
+    case HB_OT_TAG_GSUB:
+    {
+      return hb_ot_layout_from_face (face)->gsub_lookup_count;
+    }
+    case HB_OT_TAG_GPOS:
+    {
+      return hb_ot_layout_from_face (face)->gpos_lookup_count;
+    }
+  }
+  return 0;
+}
+
+static void
+_hb_ot_layout_collect_lookups_lookups (hb_face_t      *face,
+                                       hb_tag_t        table_tag,
+                                       unsigned int    feature_index,
+                                       hb_set_t       *lookup_indexes /* OUT */)
+{
+  unsigned int lookup_indices[32];
+  unsigned int offset, len;
+
+  offset = 0;
+  do {
+    len = ARRAY_LENGTH (lookup_indices);
+    hb_ot_layout_feature_get_lookups (face,
+                                      table_tag,
+                                      feature_index,
+                                      offset, &len,
+                                      lookup_indices);
+
+    for (unsigned int i = 0; i < len; i++)
+      lookup_indexes->add (lookup_indices[i]);
+
+    offset += len;
+  } while (len == ARRAY_LENGTH (lookup_indices));
+}
+
+static void
+_hb_ot_layout_collect_lookups_features (hb_face_t      *face,
+                                        hb_tag_t        table_tag,
+                                        unsigned int    script_index,
+                                        unsigned int    language_index,
+                                        const hb_tag_t *features,
+                                        hb_set_t       *lookup_indexes /* OUT */)
+{
+  if (!features)
+  {
+    unsigned int required_feature_index;
+    if (hb_ot_layout_language_get_required_feature (face,
+                                                    table_tag,
+                                                    script_index,
+                                                    language_index,
+                                                    &required_feature_index,
+                                                    NULL))
+      _hb_ot_layout_collect_lookups_lookups (face,
+                                             table_tag,
+                                             required_feature_index,
+                                             lookup_indexes);
+
+    /* All features */
+    unsigned int feature_indices[32];
+    unsigned int offset, len;
+
+    offset = 0;
+    do {
+      len = ARRAY_LENGTH (feature_indices);
+      hb_ot_layout_language_get_feature_indexes (face,
+                                                 table_tag,
+                                                 script_index,
+                                                 language_index,
+                                                 offset, &len,
+                                                 feature_indices);
+
+      for (unsigned int i = 0; i < len; i++)
+        _hb_ot_layout_collect_lookups_lookups (face,
+                                               table_tag,
+                                               feature_indices[i],
+                                               lookup_indexes);
+
+      offset += len;
+    } while (len == ARRAY_LENGTH (feature_indices));
+  }
+  else
+  {
+    for (; *features; features++)
+    {
+      unsigned int feature_index;
+      if (hb_ot_layout_language_find_feature (face,
+                                              table_tag,
+                                              script_index,
+                                              language_index,
+                                              *features,
+                                              &feature_index))
+        _hb_ot_layout_collect_lookups_lookups (face,
+                                               table_tag,
+                                               feature_index,
+                                               lookup_indexes);
+    }
+  }
+}
+
+static void
+_hb_ot_layout_collect_lookups_languages (hb_face_t      *face,
+                                         hb_tag_t        table_tag,
+                                         unsigned int    script_index,
+                                         const hb_tag_t *languages,
+                                         const hb_tag_t *features,
+                                         hb_set_t       *lookup_indexes /* OUT */)
+{
+  _hb_ot_layout_collect_lookups_features (face,
+                                          table_tag,
+                                          script_index,
+                                          HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
+                                          features,
+                                          lookup_indexes);
+
+  if (!languages)
+  {
+    /* All languages */
+    unsigned int count = hb_ot_layout_script_get_language_tags (face,
+                                                                table_tag,
+                                                                script_index,
+                                                                0, NULL, NULL);
+    for (unsigned int language_index = 0; language_index < count; language_index++)
+      _hb_ot_layout_collect_lookups_features (face,
+                                              table_tag,
+                                              script_index,
+                                              language_index,
+                                              features,
+                                              lookup_indexes);
+  }
+  else
+  {
+    for (; *languages; languages++)
+    {
+      unsigned int language_index;
+      if (hb_ot_layout_script_find_language (face,
+                                             table_tag,
+                                             script_index,
+                                             *languages,
+                                             &language_index))
+        _hb_ot_layout_collect_lookups_features (face,
+                                                table_tag,
+                                                script_index,
+                                                language_index,
+                                                features,
+                                                lookup_indexes);
+    }
+  }
+}
+
+/**
+ * hb_ot_layout_collect_lookups:
+ *
+ * Since: 0.9.8
+ **/
+void
+hb_ot_layout_collect_lookups (hb_face_t      *face,
+                              hb_tag_t        table_tag,
+                              const hb_tag_t *scripts,
+                              const hb_tag_t *languages,
+                              const hb_tag_t *features,
+                              hb_set_t       *lookup_indexes /* OUT */)
+{
+  if (!scripts)
+  {
+    /* All scripts */
+    unsigned int count = hb_ot_layout_table_get_script_tags (face,
+                                                             table_tag,
+                                                             0, NULL, NULL);
+    for (unsigned int script_index = 0; script_index < count; script_index++)
+      _hb_ot_layout_collect_lookups_languages (face,
+                                               table_tag,
+                                               script_index,
+                                               languages,
+                                               features,
+                                               lookup_indexes);
+  }
+  else
+  {
+    for (; *scripts; scripts++)
+    {
+      unsigned int script_index;
+      if (hb_ot_layout_table_find_script (face,
+                                          table_tag,
+                                          *scripts,
+                                          &script_index))
+        _hb_ot_layout_collect_lookups_languages (face,
+                                                 table_tag,
+                                                 script_index,
+                                                 languages,
+                                                 features,
+                                                 lookup_indexes);
+    }
+  }
+}
+
+/**
+ * hb_ot_layout_lookup_collect_glyphs:
+ *
+ * Since: 0.9.7
+ **/
+void
+hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
+                                    hb_tag_t      table_tag,
+                                    unsigned int  lookup_index,
+                                    hb_set_t     *glyphs_before, /* OUT. May be NULL */
+                                    hb_set_t     *glyphs_input,  /* OUT. May be NULL */
+                                    hb_set_t     *glyphs_after,  /* OUT. May be NULL */
+                                    hb_set_t     *glyphs_output  /* OUT. May be NULL */)
+{
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
+
+  OT::hb_collect_glyphs_context_t c (face,
+                                     glyphs_before,
+                                     glyphs_input,
+                                     glyphs_after,
+                                     glyphs_output);
+
+  switch (table_tag)
+  {
+    case HB_OT_TAG_GSUB:
+    {
+      const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
+      l.collect_glyphs (&c);
+      return;
+    }
+    case HB_OT_TAG_GPOS:
+    {
+      const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
+      l.collect_glyphs (&c);
+      return;
+    }
+  }
+}
+
+
+/*
+ * OT::GSUB
+ */
+
+hb_bool_t
+hb_ot_layout_has_substitution (hb_face_t *face)
+{
+  return &_get_gsub (face) != &OT::Null(OT::GSUB);
+}
+
+/**
+ * hb_ot_layout_lookup_would_substitute:
+ *
+ * Since: 0.9.7
+ **/
+hb_bool_t
+hb_ot_layout_lookup_would_substitute (hb_face_t            *face,
+                                      unsigned int          lookup_index,
+                                      const hb_codepoint_t *glyphs,
+                                      unsigned int          glyphs_length,
+                                      hb_bool_t             zero_context)
+{
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
+  return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
+}
+
+hb_bool_t
+hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
+                                           unsigned int          lookup_index,
+                                           const hb_codepoint_t *glyphs,
+                                           unsigned int          glyphs_length,
+                                           hb_bool_t             zero_context)
+{
+  if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
+  OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context);
+
+  const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
+
+  return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index]);
+}
+
+void
+hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
+{
+  OT::GSUB::substitute_start (font, buffer);
+}
+
+/**
+ * hb_ot_layout_lookup_substitute_closure:
+ *
+ * Since: 0.9.7
+ **/
+void
+hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
+                                        unsigned int  lookup_index,
+                                        hb_set_t     *glyphs)
+{
+  OT::hb_closure_context_t c (face, glyphs);
+
+  const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index);
+
+  l.closure (&c);
+}
+
+/*
+ * OT::GPOS
+ */
+
+hb_bool_t
+hb_ot_layout_has_positioning (hb_face_t *face)
+{
+  return &_get_gpos (face) != &OT::Null(OT::GPOS);
+}
+
+void
+hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
+{
+  OT::GPOS::position_start (font, buffer);
+}
+
+void
+hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer)
+{
+  OT::GPOS::position_finish_advances (font, buffer);
+}
+
+void
+hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
+{
+  OT::GPOS::position_finish_offsets (font, buffer);
+}
+
+/**
+ * hb_ot_layout_get_size_params:
+ *
+ * Since: 0.9.10
+ **/
+hb_bool_t
+hb_ot_layout_get_size_params (hb_face_t    *face,
+                              unsigned int *design_size,       /* OUT.  May be NULL */
+                              unsigned int *subfamily_id,      /* OUT.  May be NULL */
+                              unsigned int *subfamily_name_id, /* OUT.  May be NULL */
+                              unsigned int *range_start,       /* OUT.  May be NULL */
+                              unsigned int *range_end          /* OUT.  May be NULL */)
+{
+  const OT::GPOS &gpos = _get_gpos (face);
+  const hb_tag_t tag = HB_TAG ('s','i','z','e');
+
+  unsigned int num_features = gpos.get_feature_count ();
+  for (unsigned int i = 0; i < num_features; i++)
+  {
+    if (tag == gpos.get_feature_tag (i))
+    {
+      const OT::Feature &f = gpos.get_feature (i);
+      const OT::FeatureParamsSize &params = f.get_feature_params ().get_size_params (tag);
+
+      if (params.designSize)
+      {
+#define PARAM(a, A) if (a) *a = params.A
+        PARAM (design_size, designSize);
+        PARAM (subfamily_id, subfamilyID);
+        PARAM (subfamily_name_id, subfamilyNameID);
+        PARAM (range_start, rangeStart);
+        PARAM (range_end, rangeEnd);
+#undef PARAM
+
+        return true;
+      }
+    }
+  }
+
+#define PARAM(a, A) if (a) *a = 0
+  PARAM (design_size, designSize);
+  PARAM (subfamily_id, subfamilyID);
+  PARAM (subfamily_name_id, subfamilyNameID);
+  PARAM (range_start, rangeStart);
+  PARAM (range_end, rangeEnd);
+#undef PARAM
+
+  return false;
+}
+
+
+/*
+ * Parts of different types are implemented here such that they have direct
+ * access to GSUB/GPOS lookups.
+ */
+
+
+struct GSUBProxy
+{
+  static const unsigned int table_index = 0;
+  static const bool inplace = false;
+  typedef OT::SubstLookup Lookup;
+
+  GSUBProxy (hb_face_t *face) :
+    table (*hb_ot_layout_from_face (face)->gsub),
+    accels (hb_ot_layout_from_face (face)->gsub_accels) {}
+
+  const OT::GSUB &table;
+  const hb_ot_layout_lookup_accelerator_t *accels;
+};
+
+struct GPOSProxy
+{
+  static const unsigned int table_index = 1;
+  static const bool inplace = true;
+  typedef OT::PosLookup Lookup;
+
+  GPOSProxy (hb_face_t *face) :
+    table (*hb_ot_layout_from_face (face)->gpos),
+    accels (hb_ot_layout_from_face (face)->gpos_accels) {}
+
+  const OT::GPOS &table;
+  const hb_ot_layout_lookup_accelerator_t *accels;
+};
+
+
+struct hb_get_subtables_context_t :
+       OT::hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
+{
+  template <typename Type>
+  static inline bool apply_to (const void *obj, OT::hb_apply_context_t *c)
+  {
+    const Type *typed_obj = (const Type *) obj;
+    return typed_obj->apply (c);
+  }
+
+  typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_apply_context_t *c);
+
+  struct hb_applicable_t
+  {
+    inline void init (const void *obj_, hb_apply_func_t apply_func_)
+    {
+      obj = obj_;
+      apply_func = apply_func_;
+    }
+
+    inline bool apply (OT::hb_apply_context_t *c) const { return apply_func (obj, c); }
+
+    private:
+    const void *obj;
+    hb_apply_func_t apply_func;
+  };
+
+  typedef hb_auto_array_t<hb_applicable_t> array_t;
+
+  /* Dispatch interface. */
+  inline const char *get_name (void) { return "GET_SUBTABLES"; }
+  template <typename T>
+  inline return_t dispatch (const T &obj)
+  {
+    hb_applicable_t *entry = array.push();
+    if (likely (entry))
+      entry->init (&obj, apply_to<T>);
+    return HB_VOID;
+  }
+  static return_t default_return_value (void) { return HB_VOID; }
+  bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
+
+  hb_get_subtables_context_t (array_t &array_) :
+                              array (array_),
+                              debug_depth (0) {}
+
+  array_t &array;
+  unsigned int debug_depth;
+};
+
+static inline bool
+apply_forward (OT::hb_apply_context_t *c,
+               const hb_ot_layout_lookup_accelerator_t &accel,
+               const hb_get_subtables_context_t::array_t &subtables)
+{
+  bool ret = false;
+  hb_buffer_t *buffer = c->buffer;
+  while (buffer->idx < buffer->len && !buffer->in_error)
+  {
+    bool applied = false;
+    if (accel.may_have (buffer->cur().codepoint) &&
+        (buffer->cur().mask & c->lookup_mask) &&
+        c->check_glyph_property (&buffer->cur(), c->lookup_props))
+     {
+       for (unsigned int i = 0; i < subtables.len; i++)
+         if (subtables[i].apply (c))
+         {
+           applied = true;
+           break;
+         }
+     }
+
+    if (applied)
+      ret = true;
+    else
+      buffer->next_glyph ();
+  }
+  return ret;
+}
+
+static inline bool
+apply_backward (OT::hb_apply_context_t *c,
+               const hb_ot_layout_lookup_accelerator_t &accel,
+               const hb_get_subtables_context_t::array_t &subtables)
+{
+  bool ret = false;
+  hb_buffer_t *buffer = c->buffer;
+  do
+  {
+    if (accel.may_have (buffer->cur().codepoint) &&
+        (buffer->cur().mask & c->lookup_mask) &&
+        c->check_glyph_property (&buffer->cur(), c->lookup_props))
+    {
+     for (unsigned int i = 0; i < subtables.len; i++)
+       if (subtables[i].apply (c))
+       {
+         ret = true;
+         break;
+       }
+    }
+    /* The reverse lookup doesn't "advance" cursor (for good reason). */
+    buffer->idx--;
+
+  }
+  while ((int) buffer->idx >= 0);
+  return ret;
+}
+
+template <typename Proxy>
+static inline void
+apply_string (OT::hb_apply_context_t *c,
+              const typename Proxy::Lookup &lookup,
+              const hb_ot_layout_lookup_accelerator_t &accel)
+{
+  hb_buffer_t *buffer = c->buffer;
+
+  if (unlikely (!buffer->len || !c->lookup_mask))
+    return;
+
+  c->set_lookup_props (lookup.get_props ());
+
+  hb_get_subtables_context_t::array_t subtables;
+  hb_get_subtables_context_t c_get_subtables (subtables);
+  lookup.dispatch (&c_get_subtables);
+
+  if (likely (!lookup.is_reverse ()))
+  {
+    /* in/out forward substitution/positioning */
+    if (Proxy::table_index == 0)
+      buffer->clear_output ();
+    buffer->idx = 0;
+
+    bool ret;
+    ret = apply_forward (c, accel, subtables);
+    if (ret)
+    {
+      if (!Proxy::inplace)
+        buffer->swap_buffers ();
+      else
+        assert (!buffer->has_separate_output ());
+    }
+  }
+  else
+  {
+    /* in-place backward substitution/positioning */
+    if (Proxy::table_index == 0)
+      buffer->remove_output ();
+    buffer->idx = buffer->len - 1;
+
+    apply_backward (c, accel, subtables);
+  }
+}
+
+template <typename Proxy>
+inline void hb_ot_map_t::apply (const Proxy &proxy,
+                                const hb_ot_shape_plan_t *plan,
+                                hb_font_t *font,
+                                hb_buffer_t *buffer) const
+{
+  const unsigned int table_index = proxy.table_index;
+  unsigned int i = 0;
+  OT::hb_apply_context_t c (table_index, font, buffer);
+  c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
+
+  for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) {
+    const stage_map_t *stage = &stages[table_index][stage_index];
+    for (; i < stage->last_lookup; i++)
+    {
+      unsigned int lookup_index = lookups[table_index][i].index;
+      if (!buffer->message (font, "start lookup %d", lookup_index)) continue;
+      c.set_lookup_index (lookup_index);
+      c.set_lookup_mask (lookups[table_index][i].mask);
+      c.set_auto_zwj (lookups[table_index][i].auto_zwj);
+      apply_string<Proxy> (&c,
+                           proxy.table.get_lookup (lookup_index),
+                           proxy.accels[lookup_index]);
+      (void) buffer->message (font, "end lookup %d", lookup_index);
+    }
+
+    if (stage->pause_func)
+    {
+      buffer->clear_output ();
+      stage->pause_func (plan, font, buffer);
+    }
+  }
+}
+
+void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
+{
+  GSUBProxy proxy (font->face);
+  apply (proxy, plan, font, buffer);
+}
+
+void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
+{
+  GPOSProxy proxy (font->face);
+  apply (proxy, plan, font, buffer);
+}
+
+HB_INTERNAL void
+hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
+                                const OT::SubstLookup &lookup,
+                                const hb_ot_layout_lookup_accelerator_t &accel)
+{
+  apply_string<GSUBProxy> (c, lookup, accel);
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-layout.h b/src/share/native/sun/font/harfbuzz/hb-ot-layout.h
new file mode 100644
index 0000000..2c455a9
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-layout.h
@@ -0,0 +1,302 @@
+/*
+ * Copyright © 2007,2008,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_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
+#ifndef HB_OT_LAYOUT_H
+#define HB_OT_LAYOUT_H
+
+#include "hb.h"
+
+#include "hb-ot-tag.h"
+
+HB_BEGIN_DECLS
+
+
+#define HB_OT_TAG_GDEF HB_TAG('G','D','E','F')
+#define HB_OT_TAG_GSUB HB_TAG('G','S','U','B')
+#define HB_OT_TAG_GPOS HB_TAG('G','P','O','S')
+#define HB_OT_TAG_JSTF HB_TAG('J','S','T','F')
+
+
+/*
+ * GDEF
+ */
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_has_glyph_classes (hb_face_t *face);
+
+typedef enum {
+  HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED = 0,
+  HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH   = 1,
+  HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE     = 2,
+  HB_OT_LAYOUT_GLYPH_CLASS_MARK         = 3,
+  HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT    = 4
+} hb_ot_layout_glyph_class_t;
+
+HB_EXTERN hb_ot_layout_glyph_class_t
+hb_ot_layout_get_glyph_class (hb_face_t      *face,
+                              hb_codepoint_t  glyph);
+
+HB_EXTERN void
+hb_ot_layout_get_glyphs_in_class (hb_face_t                  *face,
+                                  hb_ot_layout_glyph_class_t  klass,
+                                  hb_set_t                   *glyphs /* OUT */);
+
+
+/* Not that useful.  Provides list of attach points for a glyph that a
+ * client may want to cache */
+HB_EXTERN unsigned int
+hb_ot_layout_get_attach_points (hb_face_t      *face,
+                                hb_codepoint_t  glyph,
+                                unsigned int    start_offset,
+                                unsigned int   *point_count /* IN/OUT */,
+                                unsigned int   *point_array /* OUT */);
+
+/* Ligature caret positions */
+HB_EXTERN unsigned int
+hb_ot_layout_get_ligature_carets (hb_font_t      *font,
+                                  hb_direction_t  direction,
+                                  hb_codepoint_t  glyph,
+                                  unsigned int    start_offset,
+                                  unsigned int   *caret_count /* IN/OUT */,
+                                  hb_position_t  *caret_array /* OUT */);
+
+
+/*
+ * GSUB/GPOS feature query and enumeration interface
+ */
+
+#define HB_OT_LAYOUT_NO_SCRIPT_INDEX            0xFFFFu
+#define HB_OT_LAYOUT_NO_FEATURE_INDEX           0xFFFFu
+#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX     0xFFFFu
+
+HB_EXTERN unsigned int
+hb_ot_layout_table_get_script_tags (hb_face_t    *face,
+                                    hb_tag_t      table_tag,
+                                    unsigned int  start_offset,
+                                    unsigned int *script_count /* IN/OUT */,
+                                    hb_tag_t     *script_tags /* OUT */);
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_table_find_script (hb_face_t    *face,
+                                hb_tag_t      table_tag,
+                                hb_tag_t      script_tag,
+                                unsigned int *script_index);
+
+/* Like find_script, but takes zero-terminated array of scripts to test */
+HB_EXTERN hb_bool_t
+hb_ot_layout_table_choose_script (hb_face_t      *face,
+                                  hb_tag_t        table_tag,
+                                  const hb_tag_t *script_tags,
+                                  unsigned int   *script_index,
+                                  hb_tag_t       *chosen_script);
+
+HB_EXTERN unsigned int
+hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
+                                     hb_tag_t      table_tag,
+                                     unsigned int  start_offset,
+                                     unsigned int *feature_count /* IN/OUT */,
+                                     hb_tag_t     *feature_tags /* OUT */);
+
+HB_EXTERN unsigned int
+hb_ot_layout_script_get_language_tags (hb_face_t    *face,
+                                       hb_tag_t      table_tag,
+                                       unsigned int  script_index,
+                                       unsigned int  start_offset,
+                                       unsigned int *language_count /* IN/OUT */,
+                                       hb_tag_t     *language_tags /* OUT */);
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_script_find_language (hb_face_t    *face,
+                                   hb_tag_t      table_tag,
+                                   unsigned int  script_index,
+                                   hb_tag_t      language_tag,
+                                   unsigned int *language_index);
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_language_get_required_feature_index (hb_face_t    *face,
+                                                  hb_tag_t      table_tag,
+                                                  unsigned int  script_index,
+                                                  unsigned int  language_index,
+                                                  unsigned int *feature_index);
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_language_get_required_feature (hb_face_t    *face,
+                                            hb_tag_t      table_tag,
+                                            unsigned int  script_index,
+                                            unsigned int  language_index,
+                                            unsigned int *feature_index,
+                                            hb_tag_t     *feature_tag);
+
+HB_EXTERN unsigned int
+hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
+                                           hb_tag_t      table_tag,
+                                           unsigned int  script_index,
+                                           unsigned int  language_index,
+                                           unsigned int  start_offset,
+                                           unsigned int *feature_count /* IN/OUT */,
+                                           unsigned int *feature_indexes /* OUT */);
+
+HB_EXTERN unsigned int
+hb_ot_layout_language_get_feature_tags (hb_face_t    *face,
+                                        hb_tag_t      table_tag,
+                                        unsigned int  script_index,
+                                        unsigned int  language_index,
+                                        unsigned int  start_offset,
+                                        unsigned int *feature_count /* IN/OUT */,
+                                        hb_tag_t     *feature_tags /* OUT */);
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_language_find_feature (hb_face_t    *face,
+                                    hb_tag_t      table_tag,
+                                    unsigned int  script_index,
+                                    unsigned int  language_index,
+                                    hb_tag_t      feature_tag,
+                                    unsigned int *feature_index);
+
+HB_EXTERN unsigned int
+hb_ot_layout_feature_get_lookups (hb_face_t    *face,
+                                  hb_tag_t      table_tag,
+                                  unsigned int  feature_index,
+                                  unsigned int  start_offset,
+                                  unsigned int *lookup_count /* IN/OUT */,
+                                  unsigned int *lookup_indexes /* OUT */);
+
+HB_EXTERN unsigned int
+hb_ot_layout_table_get_lookup_count (hb_face_t    *face,
+                                     hb_tag_t      table_tag);
+
+
+HB_EXTERN void
+hb_ot_layout_collect_lookups (hb_face_t      *face,
+                              hb_tag_t        table_tag,
+                              const hb_tag_t *scripts,
+                              const hb_tag_t *languages,
+                              const hb_tag_t *features,
+                              hb_set_t       *lookup_indexes /* OUT */);
+
+HB_EXTERN void
+hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
+                                    hb_tag_t      table_tag,
+                                    unsigned int  lookup_index,
+                                    hb_set_t     *glyphs_before, /* OUT. May be NULL */
+                                    hb_set_t     *glyphs_input,  /* OUT. May be NULL */
+                                    hb_set_t     *glyphs_after,  /* OUT. May be NULL */
+                                    hb_set_t     *glyphs_output  /* OUT. May be NULL */);
+
+#ifdef HB_NOT_IMPLEMENTED
+typedef struct
+{
+  const hb_codepoint_t *before,
+  unsigned int          before_length,
+  const hb_codepoint_t *input,
+  unsigned int          input_length,
+  const hb_codepoint_t *after,
+  unsigned int          after_length,
+} hb_ot_layout_glyph_sequence_t;
+
+typedef hb_bool_t
+(*hb_ot_layout_glyph_sequence_func_t) (hb_font_t    *font,
+                                       hb_tag_t      table_tag,
+                                       unsigned int  lookup_index,
+                                       const hb_ot_layout_glyph_sequence_t *sequence,
+                                       void         *user_data);
+
+HB_EXTERN void
+Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t    *face,
+                                         hb_tag_t      table_tag,
+                                         unsigned int  lookup_index,
+                                         hb_ot_layout_glyph_sequence_func_t callback,
+                                         void         *user_data);
+#endif
+
+
+/*
+ * GSUB
+ */
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_has_substitution (hb_face_t *face);
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_lookup_would_substitute (hb_face_t            *face,
+                                      unsigned int          lookup_index,
+                                      const hb_codepoint_t *glyphs,
+                                      unsigned int          glyphs_length,
+                                      hb_bool_t             zero_context);
+
+HB_EXTERN void
+hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
+                                        unsigned int  lookup_index,
+                                        hb_set_t     *glyphs
+                                        /*TODO , hb_bool_t  inclusive */);
+
+#ifdef HB_NOT_IMPLEMENTED
+/* Note: You better have GDEF when using this API, or marks won't do much. */
+HB_EXTERN hb_bool_t
+Xhb_ot_layout_lookup_substitute (hb_font_t            *font,
+                                unsigned int          lookup_index,
+                                const hb_ot_layout_glyph_sequence_t *sequence,
+                                unsigned int          out_size,
+                                hb_codepoint_t       *glyphs_out,   /* OUT */
+                                unsigned int         *clusters_out, /* OUT */
+                                unsigned int         *out_length    /* OUT */);
+#endif
+
+
+/*
+ * GPOS
+ */
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_has_positioning (hb_face_t *face);
+
+#ifdef HB_NOT_IMPLEMENTED
+/* Note: You better have GDEF when using this API, or marks won't do much. */
+HB_EXTERN hb_bool_t
+Xhb_ot_layout_lookup_position (hb_font_t            *font,
+                              unsigned int          lookup_index,
+                              const hb_ot_layout_glyph_sequence_t *sequence,
+                              hb_glyph_position_t  *positions /* IN / OUT */);
+#endif
+
+/* Optical 'size' feature info.  Returns true if found.
+ * http://www.microsoft.com/typography/otspec/features_pt.htm#size */
+HB_EXTERN hb_bool_t
+hb_ot_layout_get_size_params (hb_face_t    *face,
+                              unsigned int *design_size,       /* OUT.  May be NULL */
+                              unsigned int *subfamily_id,      /* OUT.  May be NULL */
+                              unsigned int *subfamily_name_id, /* OUT.  May be NULL */
+                              unsigned int *range_start,       /* OUT.  May be NULL */
+                              unsigned int *range_end          /* OUT.  May be NULL */);
+
+
+HB_END_DECLS
+
+#endif /* HB_OT_LAYOUT_H */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-map-private.hh b/src/share/native/sun/font/harfbuzz/hb-ot-map-private.hh
new file mode 100644
index 0000000..6d9cf96
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-map-private.hh
@@ -0,0 +1,235 @@
+/*
+ * Copyright © 2009,2010  Red Hat, Inc.
+ * Copyright © 2010,2011,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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_MAP_PRIVATE_HH
+#define HB_OT_MAP_PRIVATE_HH
+
+#include "hb-buffer-private.hh"
+
+
+struct hb_ot_shape_plan_t;
+
+static const hb_tag_t table_tags[2] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS};
+
+struct hb_ot_map_t
+{
+  friend struct hb_ot_map_builder_t;
+
+  public:
+
+  struct feature_map_t {
+    hb_tag_t tag; /* should be first for our bsearch to work */
+    unsigned int index[2]; /* GSUB/GPOS */
+    unsigned int stage[2]; /* GSUB/GPOS */
+    unsigned int shift;
+    hb_mask_t mask;
+    hb_mask_t _1_mask; /* mask for value=1, for quick access */
+    unsigned int needs_fallback : 1;
+    unsigned int auto_zwj : 1;
+
+    static int cmp (const feature_map_t *a, const feature_map_t *b)
+    { return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0; }
+  };
+
+  struct lookup_map_t {
+    unsigned short index;
+    unsigned short auto_zwj : 1;
+    hb_mask_t mask;
+
+    static int cmp (const lookup_map_t *a, const lookup_map_t *b)
+    { return a->index < b->index ? -1 : a->index > b->index ? 1 : 0; }
+  };
+
+  typedef void (*pause_func_t) (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
+
+  struct stage_map_t {
+    unsigned int last_lookup; /* Cumulative */
+    pause_func_t pause_func;
+  };
+
+
+  hb_ot_map_t (void) { memset (this, 0, sizeof (*this)); }
+
+  inline hb_mask_t get_global_mask (void) const { return global_mask; }
+
+  inline hb_mask_t get_mask (hb_tag_t feature_tag, unsigned int *shift = NULL) const {
+    const feature_map_t *map = features.bsearch (&feature_tag);
+    if (shift) *shift = map ? map->shift : 0;
+    return map ? map->mask : 0;
+  }
+
+  inline bool needs_fallback (hb_tag_t feature_tag) const {
+    const feature_map_t *map = features.bsearch (&feature_tag);
+    return map ? map->needs_fallback : false;
+  }
+
+  inline hb_mask_t get_1_mask (hb_tag_t feature_tag) const {
+    const feature_map_t *map = features.bsearch (&feature_tag);
+    return map ? map->_1_mask : 0;
+  }
+
+  inline unsigned int get_feature_index (unsigned int table_index, hb_tag_t feature_tag) const {
+    const feature_map_t *map = features.bsearch (&feature_tag);
+    return map ? map->index[table_index] : HB_OT_LAYOUT_NO_FEATURE_INDEX;
+  }
+
+  inline unsigned int get_feature_stage (unsigned int table_index, hb_tag_t feature_tag) const {
+    const feature_map_t *map = features.bsearch (&feature_tag);
+    return map ? map->stage[table_index] : (unsigned int) -1;
+  }
+
+  inline void get_stage_lookups (unsigned int table_index, unsigned int stage,
+                                 const struct lookup_map_t **plookups, unsigned int *lookup_count) const {
+    if (unlikely (stage == (unsigned int) -1)) {
+      *plookups = NULL;
+      *lookup_count = 0;
+      return;
+    }
+    assert (stage <= stages[table_index].len);
+    unsigned int start = stage ? stages[table_index][stage - 1].last_lookup : 0;
+    unsigned int end   = stage < stages[table_index].len ? stages[table_index][stage].last_lookup : lookups[table_index].len;
+    *plookups = &lookups[table_index][start];
+    *lookup_count = end - start;
+  }
+
+  HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const;
+  template <typename Proxy>
+  HB_INTERNAL inline void apply (const Proxy &proxy,
+                                 const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
+  HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
+  HB_INTERNAL void position (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
+
+  inline void finish (void) {
+    features.finish ();
+    for (unsigned int table_index = 0; table_index < 2; table_index++)
+    {
+      lookups[table_index].finish ();
+      stages[table_index].finish ();
+    }
+  }
+
+  public:
+  hb_tag_t chosen_script[2];
+  bool found_script[2];
+
+  private:
+
+  HB_INTERNAL void add_lookups (hb_face_t    *face,
+                                unsigned int  table_index,
+                                unsigned int  feature_index,
+                                hb_mask_t     mask,
+                                bool          auto_zwj);
+
+  hb_mask_t global_mask;
+
+  hb_prealloced_array_t<feature_map_t, 8> features;
+  hb_prealloced_array_t<lookup_map_t, 32> lookups[2]; /* GSUB/GPOS */
+  hb_prealloced_array_t<stage_map_t, 4> stages[2]; /* GSUB/GPOS */
+};
+
+enum hb_ot_map_feature_flags_t {
+  F_NONE                = 0x0000u,
+  F_GLOBAL              = 0x0001u, /* Feature applies to all characters; results in no mask allocated for it. */
+  F_HAS_FALLBACK        = 0x0002u, /* Has fallback implementation, so include mask bit even if feature not found. */
+  F_MANUAL_ZWJ          = 0x0004u, /* Don't skip over ZWJ when matching. */
+  F_GLOBAL_SEARCH       = 0x0008u  /* If feature not found in LangSys, look for it in global feature list and pick one. */
+};
+HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t);
+/* Macro version for where const is desired. */
+#define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r)))
+
+
+struct hb_ot_map_builder_t
+{
+  public:
+
+  HB_INTERNAL hb_ot_map_builder_t (hb_face_t *face_,
+                                   const hb_segment_properties_t *props_);
+
+  HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value,
+                                hb_ot_map_feature_flags_t flags);
+
+  inline void add_global_bool_feature (hb_tag_t tag)
+  { add_feature (tag, 1, F_GLOBAL); }
+
+  inline void add_gsub_pause (hb_ot_map_t::pause_func_t pause_func)
+  { add_pause (0, pause_func); }
+  inline void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func)
+  { add_pause (1, pause_func); }
+
+  HB_INTERNAL void compile (struct hb_ot_map_t &m);
+
+  inline void finish (void) {
+    feature_infos.finish ();
+    for (unsigned int table_index = 0; table_index < 2; table_index++)
+    {
+      stages[table_index].finish ();
+    }
+  }
+
+  private:
+
+  struct feature_info_t {
+    hb_tag_t tag;
+    unsigned int seq; /* sequence#, used for stable sorting only */
+    unsigned int max_value;
+    hb_ot_map_feature_flags_t flags;
+    unsigned int default_value; /* for non-global features, what should the unset glyphs take */
+    unsigned int stage[2]; /* GSUB/GPOS */
+
+    static int cmp (const feature_info_t *a, const feature_info_t *b)
+    { return (a->tag != b->tag) ?  (a->tag < b->tag ? -1 : 1) :
+             (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0); }
+  };
+
+  struct stage_info_t {
+    unsigned int index;
+    hb_ot_map_t::pause_func_t pause_func;
+  };
+
+  HB_INTERNAL void add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func);
+
+  public:
+
+  hb_face_t *face;
+  hb_segment_properties_t props;
+
+  hb_tag_t chosen_script[2];
+  bool found_script[2];
+  unsigned int script_index[2], language_index[2];
+
+  private:
+
+  unsigned int current_stage[2]; /* GSUB/GPOS */
+  hb_prealloced_array_t<feature_info_t, 32> feature_infos;
+  hb_prealloced_array_t<stage_info_t, 8> stages[2]; /* GSUB/GPOS */
+};
+
+
+
+#endif /* HB_OT_MAP_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-map.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-map.cpp
new file mode 100644
index 0000000..0f9f608
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-map.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright © 2009,2010  Red Hat, Inc.
+ * Copyright © 2010,2011,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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-map-private.hh"
+
+#include "hb-ot-layout-private.hh"
+
+
+void
+hb_ot_map_t::add_lookups (hb_face_t    *face,
+                          unsigned int  table_index,
+                          unsigned int  feature_index,
+                          hb_mask_t     mask,
+                          bool          auto_zwj)
+{
+  unsigned int lookup_indices[32];
+  unsigned int offset, len;
+  unsigned int table_lookup_count;
+
+  table_lookup_count = hb_ot_layout_table_get_lookup_count (face, table_tags[table_index]);
+
+  offset = 0;
+  do {
+    len = ARRAY_LENGTH (lookup_indices);
+    hb_ot_layout_feature_get_lookups (face,
+                                      table_tags[table_index],
+                                      feature_index,
+                                      offset, &len,
+                                      lookup_indices);
+
+    for (unsigned int i = 0; i < len; i++)
+    {
+      if (lookup_indices[i] >= table_lookup_count)
+        continue;
+      hb_ot_map_t::lookup_map_t *lookup = lookups[table_index].push ();
+      if (unlikely (!lookup))
+        return;
+      lookup->mask = mask;
+      lookup->index = lookup_indices[i];
+      lookup->auto_zwj = auto_zwj;
+    }
+
+    offset += len;
+  } while (len == ARRAY_LENGTH (lookup_indices));
+}
+
+hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
+                                          const hb_segment_properties_t *props_)
+{
+  memset (this, 0, sizeof (*this));
+
+  face = face_;
+  props = *props_;
+
+
+  /* Fetch script/language indices for GSUB/GPOS.  We need these later to skip
+   * features not available in either table and not waste precious bits for them. */
+
+  hb_tag_t script_tags[3] = {HB_TAG_NONE, HB_TAG_NONE, HB_TAG_NONE};
+  hb_tag_t language_tag;
+
+  hb_ot_tags_from_script (props.script, &script_tags[0], &script_tags[1]);
+  language_tag = hb_ot_tag_from_language (props.language);
+
+  for (unsigned int table_index = 0; table_index < 2; table_index++) {
+    hb_tag_t table_tag = table_tags[table_index];
+    found_script[table_index] = (bool) hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &chosen_script[table_index]);
+    hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
+  }
+}
+
+void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value,
+                                       hb_ot_map_feature_flags_t flags)
+{
+  feature_info_t *info = feature_infos.push();
+  if (unlikely (!info)) return;
+  if (unlikely (!tag)) return;
+  info->tag = tag;
+  info->seq = feature_infos.len;
+  info->max_value = value;
+  info->flags = flags;
+  info->default_value = (flags & F_GLOBAL) ? value : 0;
+  info->stage[0] = current_stage[0];
+  info->stage[1] = current_stage[1];
+}
+
+
+void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
+{
+  for (unsigned int i = 0; i < lookups[table_index].len; i++)
+    hb_set_add (lookups_out, lookups[table_index][i].index);
+}
+
+void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func)
+{
+  stage_info_t *s = stages[table_index].push ();
+  if (likely (s)) {
+    s->index = current_stage[table_index];
+    s->pause_func = pause_func;
+  }
+
+  current_stage[table_index]++;
+}
+
+void
+hb_ot_map_builder_t::compile (hb_ot_map_t &m)
+{
+  m.global_mask = 1;
+
+  unsigned int required_feature_index[2];
+  hb_tag_t required_feature_tag[2];
+  /* We default to applying required feature in stage 0.  If the required
+   * feature has a tag that is known to the shaper, we apply required feature
+   * in the stage for that tag.
+   */
+  unsigned int required_feature_stage[2] = {0, 0};
+
+  for (unsigned int table_index = 0; table_index < 2; table_index++)
+  {
+    m.chosen_script[table_index] = chosen_script[table_index];
+    m.found_script[table_index] = found_script[table_index];
+
+    hb_ot_layout_language_get_required_feature (face,
+                                                table_tags[table_index],
+                                                script_index[table_index],
+                                                language_index[table_index],
+                                                &required_feature_index[table_index],
+                                                &required_feature_tag[table_index]);
+  }
+
+  if (!feature_infos.len)
+    return;
+
+  /* Sort features and merge duplicates */
+  {
+    feature_infos.qsort ();
+    unsigned int j = 0;
+    for (unsigned int i = 1; i < feature_infos.len; i++)
+      if (feature_infos[i].tag != feature_infos[j].tag)
+        feature_infos[++j] = feature_infos[i];
+      else {
+        if (feature_infos[i].flags & F_GLOBAL) {
+          feature_infos[j].flags |= F_GLOBAL;
+          feature_infos[j].max_value = feature_infos[i].max_value;
+          feature_infos[j].default_value = feature_infos[i].default_value;
+        } else {
+          feature_infos[j].flags &= ~F_GLOBAL;
+          feature_infos[j].max_value = MAX (feature_infos[j].max_value, feature_infos[i].max_value);
+          /* Inherit default_value from j */
+        }
+        feature_infos[j].flags |= (feature_infos[i].flags & F_HAS_FALLBACK);
+        feature_infos[j].stage[0] = MIN (feature_infos[j].stage[0], feature_infos[i].stage[0]);
+        feature_infos[j].stage[1] = MIN (feature_infos[j].stage[1], feature_infos[i].stage[1]);
+      }
+    feature_infos.shrink (j + 1);
+  }
+
+
+  /* Allocate bits now */
+  unsigned int next_bit = 1;
+  for (unsigned int i = 0; i < feature_infos.len; i++)
+  {
+    const feature_info_t *info = &feature_infos[i];
+
+    unsigned int bits_needed;
+
+    if ((info->flags & F_GLOBAL) && info->max_value == 1)
+      /* Uses the global bit */
+      bits_needed = 0;
+    else
+      bits_needed = _hb_bit_storage (info->max_value);
+
+    if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
+      continue; /* Feature disabled, or not enough bits. */
+
+
+    hb_bool_t found = false;
+    unsigned int feature_index[2];
+    for (unsigned int table_index = 0; table_index < 2; table_index++)
+    {
+      if (required_feature_tag[table_index] == info->tag)
+        required_feature_stage[table_index] = info->stage[table_index];
+
+      found |= hb_ot_layout_language_find_feature (face,
+                                                   table_tags[table_index],
+                                                   script_index[table_index],
+                                                   language_index[table_index],
+                                                   info->tag,
+                                                   &feature_index[table_index]);
+    }
+    if (!found && (info->flags & F_GLOBAL_SEARCH))
+    {
+      for (unsigned int table_index = 0; table_index < 2; table_index++)
+      {
+        found |= hb_ot_layout_table_find_feature (face,
+                                                  table_tags[table_index],
+                                                  info->tag,
+                                                  &feature_index[table_index]);
+      }
+    }
+    if (!found && !(info->flags & F_HAS_FALLBACK))
+      continue;
+
+
+    hb_ot_map_t::feature_map_t *map = m.features.push ();
+    if (unlikely (!map))
+      break;
+
+    map->tag = info->tag;
+    map->index[0] = feature_index[0];
+    map->index[1] = feature_index[1];
+    map->stage[0] = info->stage[0];
+    map->stage[1] = info->stage[1];
+    map->auto_zwj = !(info->flags & F_MANUAL_ZWJ);
+    if ((info->flags & F_GLOBAL) && info->max_value == 1) {
+      /* Uses the global bit */
+      map->shift = 0;
+      map->mask = 1;
+    } else {
+      map->shift = next_bit;
+      map->mask = (1 << (next_bit + bits_needed)) - (1 << next_bit);
+      next_bit += bits_needed;
+      m.global_mask |= (info->default_value << map->shift) & map->mask;
+    }
+    map->_1_mask = (1 << map->shift) & map->mask;
+    map->needs_fallback = !found;
+
+  }
+  feature_infos.shrink (0); /* Done with these */
+
+
+  add_gsub_pause (NULL);
+  add_gpos_pause (NULL);
+
+  for (unsigned int table_index = 0; table_index < 2; table_index++)
+  {
+    /* Collect lookup indices for features */
+
+    unsigned int stage_index = 0;
+    unsigned int last_num_lookups = 0;
+    for (unsigned stage = 0; stage < current_stage[table_index]; stage++)
+    {
+      if (required_feature_index[table_index] != HB_OT_LAYOUT_NO_FEATURE_INDEX &&
+          required_feature_stage[table_index] == stage)
+        m.add_lookups (face, table_index,
+                       required_feature_index[table_index],
+                       1 /* mask */,
+                       true /* auto_zwj */);
+
+      for (unsigned i = 0; i < m.features.len; i++)
+        if (m.features[i].stage[table_index] == stage)
+          m.add_lookups (face, table_index,
+                         m.features[i].index[table_index],
+                         m.features[i].mask,
+                         m.features[i].auto_zwj);
+
+      /* Sort lookups and merge duplicates */
+      if (last_num_lookups < m.lookups[table_index].len)
+      {
+        m.lookups[table_index].qsort (last_num_lookups, m.lookups[table_index].len);
+
+        unsigned int j = last_num_lookups;
+        for (unsigned int i = j + 1; i < m.lookups[table_index].len; i++)
+          if (m.lookups[table_index][i].index != m.lookups[table_index][j].index)
+            m.lookups[table_index][++j] = m.lookups[table_index][i];
+          else
+          {
+            m.lookups[table_index][j].mask |= m.lookups[table_index][i].mask;
+            m.lookups[table_index][j].auto_zwj &= m.lookups[table_index][i].auto_zwj;
+          }
+        m.lookups[table_index].shrink (j + 1);
+      }
+
+      last_num_lookups = m.lookups[table_index].len;
+
+      if (stage_index < stages[table_index].len && stages[table_index][stage_index].index == stage) {
+        hb_ot_map_t::stage_map_t *stage_map = m.stages[table_index].push ();
+        if (likely (stage_map)) {
+          stage_map->last_lookup = last_num_lookups;
+          stage_map->pause_func = stages[table_index][stage_index].pause_func;
+        }
+
+        stage_index++;
+      }
+    }
+  }
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-maxp-table.hh b/src/share/native/sun/font/harfbuzz/hb-ot-maxp-table.hh
new file mode 100644
index 0000000..5b9ed91
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-maxp-table.hh
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_MAXP_TABLE_HH
+#define HB_OT_MAXP_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+
+namespace OT {
+
+
+/*
+ * maxp -- The Maximum Profile Table
+ */
+
+#define HB_OT_TAG_maxp HB_TAG('m','a','x','p')
+
+struct maxp
+{
+  static const hb_tag_t tableTag        = HB_OT_TAG_maxp;
+
+  inline unsigned int get_num_glyphs (void) const
+  {
+    return numGlyphs;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  likely (version.major == 1 ||
+                          (version.major == 0 && version.minor == 0x5000u)));
+  }
+
+  /* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */
+  protected:
+  FixedVersion<>version;                /* Version of the maxp table (0.5 or 1.0),
+                                         * 0x00005000u or 0x00010000u. */
+  USHORT        numGlyphs;              /* The number of glyphs in the font. */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_MAXP_TABLE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-name-table.hh b/src/share/native/sun/font/harfbuzz/hb-ot-name-table.hh
new file mode 100644
index 0000000..83529ed
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-name-table.hh
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_NAME_TABLE_HH
+#define HB_OT_NAME_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+
+namespace OT {
+
+
+/*
+ * name -- The Naming Table
+ */
+
+#define HB_OT_TAG_name HB_TAG('n','a','m','e')
+
+
+struct NameRecord
+{
+  static int cmp (const NameRecord *a, const NameRecord *b)
+  {
+    int ret;
+    ret = b->platformID.cmp (a->platformID);
+    if (ret) return ret;
+    ret = b->encodingID.cmp (a->encodingID);
+    if (ret) return ret;
+    ret = b->languageID.cmp (a->languageID);
+    if (ret) return ret;
+    ret = b->nameID.cmp (a->nameID);
+    if (ret) return ret;
+    return 0;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    /* We can check from base all the way up to the end of string... */
+    return_trace (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset));
+  }
+
+  USHORT        platformID;     /* Platform ID. */
+  USHORT        encodingID;     /* Platform-specific encoding ID. */
+  USHORT        languageID;     /* Language ID. */
+  USHORT        nameID;         /* Name ID. */
+  USHORT        length;         /* String length (in bytes). */
+  USHORT        offset;         /* String offset from start of storage area (in bytes). */
+  public:
+  DEFINE_SIZE_STATIC (12);
+};
+
+struct name
+{
+  static const hb_tag_t tableTag        = HB_OT_TAG_name;
+
+  inline unsigned int get_name (unsigned int platform_id,
+                                unsigned int encoding_id,
+                                unsigned int language_id,
+                                unsigned int name_id,
+                                void *buffer,
+                                unsigned int buffer_length) const
+  {
+    NameRecord key;
+    key.platformID.set (platform_id);
+    key.encodingID.set (encoding_id);
+    key.languageID.set (language_id);
+    key.nameID.set (name_id);
+    NameRecord *match = (NameRecord *) bsearch (&key, nameRecord, count, sizeof (nameRecord[0]), (hb_compare_func_t) NameRecord::cmp);
+
+    if (!match)
+      return 0;
+
+    unsigned int length = MIN (buffer_length, (unsigned int) match->length);
+    memcpy (buffer, (char *) this + stringOffset + match->offset, length);
+    return length;
+  }
+
+  inline unsigned int get_size (void) const
+  { return min_size + count * nameRecord[0].min_size; }
+
+  inline bool sanitize_records (hb_sanitize_context_t *c) const {
+    TRACE_SANITIZE (this);
+    char *string_pool = (char *) this + stringOffset;
+    unsigned int _count = count;
+    for (unsigned int i = 0; i < _count; i++)
+      if (!nameRecord[i].sanitize (c, string_pool)) return_trace (false);
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  likely (format == 0 || format == 1) &&
+                  c->check_array (nameRecord, nameRecord[0].static_size, count) &&
+                  sanitize_records (c));
+  }
+
+  /* We only implement format 0 for now. */
+  USHORT        format;                 /* Format selector (=0/1). */
+  USHORT        count;                  /* Number of name records. */
+  Offset<>      stringOffset;           /* Offset to start of string storage (from start of table). */
+  NameRecord    nameRecord[VAR];        /* The name records where count is the number of records. */
+  public:
+  DEFINE_SIZE_ARRAY (6, nameRecord);
+};
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_NAME_TABLE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-os2-table.hh b/src/share/native/sun/font/harfbuzz/hb-ot-os2-table.hh
new file mode 100644
index 0000000..9d3df8d
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-os2-table.hh
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_OS2_TABLE_HH
+#define HB_OT_OS2_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+
+namespace OT {
+
+/*
+ * OS/2 and Windows Metrics
+ * http://www.microsoft.com/typography/otspec/os2.htm
+ */
+
+#define HB_OT_TAG_os2 HB_TAG('O','S','/','2')
+
+struct os2
+{
+  static const hb_tag_t tableTag = HB_OT_TAG_os2;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  public:
+  USHORT        version;
+
+  /* Version 0 */
+  SHORT         xAvgCharWidth;
+  USHORT        usWeightClass;
+  USHORT        usWidthClass;
+  USHORT        fsType;
+  SHORT         ySubscriptXSize;
+  SHORT         ySubscriptYSize;
+  SHORT         ySubscriptXOffset;
+  SHORT         ySubscriptYOffset;
+  SHORT         ySuperscriptXSize;
+  SHORT         ySuperscriptYSize;
+  SHORT         ySuperscriptXOffset;
+  SHORT         ySuperscriptYOffset;
+  SHORT         yStrikeoutSize;
+  SHORT         yStrikeoutPosition;
+  SHORT         sFamilyClass;
+  BYTE          panose[10];
+  ULONG         ulUnicodeRange[4];
+  Tag           achVendID;
+  USHORT        fsSelection;
+  USHORT        usFirstCharIndex;
+  USHORT        usLastCharIndex;
+  SHORT         sTypoAscender;
+  SHORT         sTypoDescender;
+  SHORT         sTypoLineGap;
+  USHORT        usWinAscent;
+  USHORT        usWinDescent;
+
+  /* Version 1 */
+  //ULONG ulCodePageRange1;
+  //ULONG ulCodePageRange2;
+
+  /* Version 2 */
+  //SHORT sxHeight;
+  //SHORT sCapHeight;
+  //USHORT  usDefaultChar;
+  //USHORT  usBreakChar;
+  //USHORT  usMaxContext;
+
+  /* Version 5 */
+  //USHORT  usLowerOpticalPointSize;
+  //USHORT  usUpperOpticalPointSize;
+
+  public:
+  DEFINE_SIZE_STATIC (78);
+};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_OS2_TABLE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-fallback.hh b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-fallback.hh
new file mode 100644
index 0000000..62d0b25
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-fallback.hh
@@ -0,0 +1,354 @@
+/*
+ * 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_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH
+#define HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH
+
+#include "hb-private.hh"
+
+#include "hb-ot-shape-private.hh"
+#include "hb-ot-layout-gsub-table.hh"
+
+
+/* Features ordered the same as the entries in shaping_table rows,
+ * followed by rlig.  Don't change. */
+static const hb_tag_t arabic_fallback_features[] =
+{
+  HB_TAG('i','n','i','t'),
+  HB_TAG('m','e','d','i'),
+  HB_TAG('f','i','n','a'),
+  HB_TAG('i','s','o','l'),
+  HB_TAG('r','l','i','g'),
+};
+
+static OT::SubstLookup *
+arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                                          hb_font_t *font,
+                                          unsigned int feature_index)
+{
+  OT::GlyphID glyphs[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
+  OT::GlyphID substitutes[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
+  unsigned int num_glyphs = 0;
+
+  /* Populate arrays */
+  for (hb_codepoint_t u = SHAPING_TABLE_FIRST; u < SHAPING_TABLE_LAST + 1; u++)
+  {
+    hb_codepoint_t s = shaping_table[u - SHAPING_TABLE_FIRST][feature_index];
+    hb_codepoint_t u_glyph, s_glyph;
+
+    if (!s ||
+        !hb_font_get_glyph (font, u, 0, &u_glyph) ||
+        !hb_font_get_glyph (font, s, 0, &s_glyph) ||
+        u_glyph == s_glyph ||
+        u_glyph > 0xFFFFu || s_glyph > 0xFFFFu)
+      continue;
+
+    glyphs[num_glyphs].set (u_glyph);
+    substitutes[num_glyphs].set (s_glyph);
+
+    num_glyphs++;
+  }
+
+  if (!num_glyphs)
+    return NULL;
+
+  /* Bubble-sort or something equally good!
+   * May not be good-enough for presidential candidate interviews, but good-enough for us... */
+  hb_stable_sort (&glyphs[0], num_glyphs, OT::GlyphID::cmp, &substitutes[0]);
+
+  OT::Supplier<OT::GlyphID> glyphs_supplier      (glyphs, num_glyphs);
+  OT::Supplier<OT::GlyphID> substitutes_supplier (substitutes, num_glyphs);
+
+  /* Each glyph takes four bytes max, and there's some overhead. */
+  char buf[(SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1) * 4 + 128];
+  OT::hb_serialize_context_t c (buf, sizeof (buf));
+  OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
+  bool ret = lookup->serialize_single (&c,
+                                       OT::LookupFlag::IgnoreMarks,
+                                       glyphs_supplier,
+                                       substitutes_supplier,
+                                       num_glyphs);
+  c.end_serialize ();
+  /* TODO sanitize the results? */
+
+  return ret ? c.copy<OT::SubstLookup> () : NULL;
+}
+
+static OT::SubstLookup *
+arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                                            hb_font_t *font)
+{
+  OT::GlyphID first_glyphs[ARRAY_LENGTH_CONST (ligature_table)];
+  unsigned int first_glyphs_indirection[ARRAY_LENGTH_CONST (ligature_table)];
+  unsigned int ligature_per_first_glyph_count_list[ARRAY_LENGTH_CONST (first_glyphs)];
+  unsigned int num_first_glyphs = 0;
+
+  /* We know that all our ligatures are 2-component */
+  OT::GlyphID ligature_list[ARRAY_LENGTH_CONST (first_glyphs) * ARRAY_LENGTH_CONST(ligature_table[0].ligatures)];
+  unsigned int component_count_list[ARRAY_LENGTH_CONST (ligature_list)];
+  OT::GlyphID component_list[ARRAY_LENGTH_CONST (ligature_list) * 1/* One extra component per ligature */];
+  unsigned int num_ligatures = 0;
+
+  /* Populate arrays */
+
+  /* Sort out the first-glyphs */
+  for (unsigned int first_glyph_idx = 0; first_glyph_idx < ARRAY_LENGTH (first_glyphs); first_glyph_idx++)
+  {
+    hb_codepoint_t first_u = ligature_table[first_glyph_idx].first;
+    hb_codepoint_t first_glyph;
+    if (!hb_font_get_glyph (font, first_u, 0, &first_glyph))
+      continue;
+    first_glyphs[num_first_glyphs].set (first_glyph);
+    ligature_per_first_glyph_count_list[num_first_glyphs] = 0;
+    first_glyphs_indirection[num_first_glyphs] = first_glyph_idx;
+    num_first_glyphs++;
+  }
+  hb_stable_sort (&first_glyphs[0], num_first_glyphs, OT::GlyphID::cmp, &first_glyphs_indirection[0]);
+
+  /* Now that the first-glyphs are sorted, walk again, populate ligatures. */
+  for (unsigned int i = 0; i < num_first_glyphs; i++)
+  {
+    unsigned int first_glyph_idx = first_glyphs_indirection[i];
+
+    for (unsigned int second_glyph_idx = 0; second_glyph_idx < ARRAY_LENGTH (ligature_table[0].ligatures); second_glyph_idx++)
+    {
+      hb_codepoint_t second_u   = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].second;
+      hb_codepoint_t ligature_u = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].ligature;
+      hb_codepoint_t second_glyph, ligature_glyph;
+      if (!second_u ||
+          !hb_font_get_glyph (font, second_u,   0, &second_glyph) ||
+          !hb_font_get_glyph (font, ligature_u, 0, &ligature_glyph))
+        continue;
+
+      ligature_per_first_glyph_count_list[i]++;
+
+      ligature_list[num_ligatures].set (ligature_glyph);
+      component_count_list[num_ligatures] = 2;
+      component_list[num_ligatures].set (second_glyph);
+      num_ligatures++;
+    }
+  }
+
+  if (!num_ligatures)
+    return NULL;
+
+  OT::Supplier<OT::GlyphID>   first_glyphs_supplier                      (first_glyphs, num_first_glyphs);
+  OT::Supplier<unsigned int > ligature_per_first_glyph_count_supplier    (ligature_per_first_glyph_count_list, num_first_glyphs);
+  OT::Supplier<OT::GlyphID>   ligatures_supplier                         (ligature_list, num_ligatures);
+  OT::Supplier<unsigned int > component_count_supplier                   (component_count_list, num_ligatures);
+  OT::Supplier<OT::GlyphID>   component_supplier                         (component_list, num_ligatures);
+
+  /* 16 bytes per ligature ought to be enough... */
+  char buf[ARRAY_LENGTH_CONST (ligature_list) * 16 + 128];
+  OT::hb_serialize_context_t c (buf, sizeof (buf));
+  OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
+  bool ret = lookup->serialize_ligature (&c,
+                                         OT::LookupFlag::IgnoreMarks,
+                                         first_glyphs_supplier,
+                                         ligature_per_first_glyph_count_supplier,
+                                         num_first_glyphs,
+                                         ligatures_supplier,
+                                         component_count_supplier,
+                                         component_supplier);
+
+  c.end_serialize ();
+  /* TODO sanitize the results? */
+
+  return ret ? c.copy<OT::SubstLookup> () : NULL;
+}
+
+static OT::SubstLookup *
+arabic_fallback_synthesize_lookup (const hb_ot_shape_plan_t *plan,
+                                   hb_font_t *font,
+                                   unsigned int feature_index)
+{
+  if (feature_index < 4)
+    return arabic_fallback_synthesize_lookup_single (plan, font, feature_index);
+  else
+    return arabic_fallback_synthesize_lookup_ligature (plan, font);
+}
+
+#define ARABIC_FALLBACK_MAX_LOOKUPS 5
+
+struct arabic_fallback_plan_t
+{
+  ASSERT_POD ();
+
+  unsigned int num_lookups;
+  bool free_lookups;
+
+  hb_mask_t mask_array[ARABIC_FALLBACK_MAX_LOOKUPS];
+  OT::SubstLookup *lookup_array[ARABIC_FALLBACK_MAX_LOOKUPS];
+  hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS];
+};
+
+static const arabic_fallback_plan_t arabic_fallback_plan_nil = {};
+
+#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_WIN1256)
+#define HB_WITH_WIN1256
+#endif
+
+#ifdef HB_WITH_WIN1256
+#include "hb-ot-shape-complex-arabic-win1256.hh"
+#endif
+
+struct ManifestLookup {
+  OT::Tag tag;
+  OT::OffsetTo<OT::SubstLookup> lookupOffset;
+};
+typedef OT::ArrayOf<ManifestLookup> Manifest;
+
+static bool
+arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan,
+                                   const hb_ot_shape_plan_t *plan,
+                                   hb_font_t *font)
+{
+#ifdef HB_WITH_WIN1256
+  /* Does this font look like it's Windows-1256-encoded? */
+  hb_codepoint_t g;
+  if (!(hb_font_get_glyph (font, 0x0627u, 0, &g) && g == 199 /* ALEF */ &&
+        hb_font_get_glyph (font, 0x0644u, 0, &g) && g == 225 /* LAM */ &&
+        hb_font_get_glyph (font, 0x0649u, 0, &g) && g == 236 /* ALEF MAKSURA */ &&
+        hb_font_get_glyph (font, 0x064Au, 0, &g) && g == 237 /* YEH */ &&
+        hb_font_get_glyph (font, 0x0652u, 0, &g) && g == 250 /* SUKUN */))
+    return false;
+
+  const Manifest &manifest = reinterpret_cast<const Manifest&> (arabic_win1256_gsub_lookups.manifest);
+  ASSERT_STATIC (sizeof (arabic_win1256_gsub_lookups.manifestData) / sizeof (ManifestLookup)
+                 <= ARABIC_FALLBACK_MAX_LOOKUPS);
+  /* TODO sanitize the table? */
+
+  unsigned j = 0;
+  unsigned int count = manifest.len;
+  for (unsigned int i = 0; i < count; i++)
+  {
+    fallback_plan->mask_array[j] = plan->map.get_1_mask (manifest[i].tag);
+    if (fallback_plan->mask_array[j])
+    {
+      fallback_plan->lookup_array[j] = const_cast<OT::SubstLookup*> (&(&manifest+manifest[i].lookupOffset));
+      if (fallback_plan->lookup_array[j])
+      {
+        fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]);
+        j++;
+      }
+    }
+  }
+
+  fallback_plan->num_lookups = j;
+  fallback_plan->free_lookups = false;
+
+  return j > 0;
+#else
+  return false;
+#endif
+}
+
+static bool
+arabic_fallback_plan_init_unicode (arabic_fallback_plan_t *fallback_plan,
+                                   const hb_ot_shape_plan_t *plan,
+                                   hb_font_t *font)
+{
+  ASSERT_STATIC (ARRAY_LENGTH_CONST(arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS);
+  unsigned int j = 0;
+  for (unsigned int i = 0; i < ARRAY_LENGTH(arabic_fallback_features) ; i++)
+  {
+    fallback_plan->mask_array[j] = plan->map.get_1_mask (arabic_fallback_features[i]);
+    if (fallback_plan->mask_array[j])
+    {
+      fallback_plan->lookup_array[j] = arabic_fallback_synthesize_lookup (plan, font, i);
+      if (fallback_plan->lookup_array[j])
+      {
+        fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]);
+        j++;
+      }
+    }
+  }
+
+  fallback_plan->num_lookups = j;
+  fallback_plan->free_lookups = true;
+
+  return j > 0;
+}
+
+static arabic_fallback_plan_t *
+arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
+                             hb_font_t *font)
+{
+  arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) calloc (1, sizeof (arabic_fallback_plan_t));
+  if (unlikely (!fallback_plan))
+    return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
+
+  fallback_plan->num_lookups = 0;
+  fallback_plan->free_lookups = false;
+
+  /* Try synthesizing GSUB table using Unicode Arabic Presentation Forms,
+   * in case the font has cmap entries for the presentation-forms characters. */
+  if (arabic_fallback_plan_init_unicode (fallback_plan, plan, font))
+    return fallback_plan;
+
+  /* See if this looks like a Windows-1256-encoded font.  If it does, use a
+   * hand-coded GSUB table. */
+  if (arabic_fallback_plan_init_win1256 (fallback_plan, plan, font))
+    return fallback_plan;
+
+  free (fallback_plan);
+  return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
+}
+
+static void
+arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan)
+{
+  if (!fallback_plan || fallback_plan == &arabic_fallback_plan_nil)
+    return;
+
+  for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
+    if (fallback_plan->lookup_array[i])
+    {
+      fallback_plan->accel_array[i].fini ();
+      if (fallback_plan->free_lookups)
+        free (fallback_plan->lookup_array[i]);
+    }
+
+  free (fallback_plan);
+}
+
+static void
+arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan,
+                            hb_font_t *font,
+                            hb_buffer_t *buffer)
+{
+  OT::hb_apply_context_t c (0, font, buffer);
+  for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
+    if (fallback_plan->lookup_array[i]) {
+      c.set_lookup_mask (fallback_plan->mask_array[i]);
+      hb_ot_layout_substitute_lookup (&c,
+                                      *fallback_plan->lookup_array[i],
+                                      fallback_plan->accel_array[i]);
+    }
+}
+
+
+#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-private.hh b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-private.hh
new file mode 100644
index 0000000..a234ab4
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-private.hh
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2015  Mozilla Foundation.
+ * Copyright © 2015  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
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH
+#define HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+struct arabic_shape_plan_t;
+
+HB_INTERNAL void *
+data_create_arabic (const hb_ot_shape_plan_t *plan);
+
+HB_INTERNAL void
+data_destroy_arabic (void *data);
+
+HB_INTERNAL void
+setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan,
+                         hb_buffer_t               *buffer,
+                         hb_script_t                script);
+
+#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-table.hh b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-table.hh
new file mode 100644
index 0000000..2198f76
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-table.hh
@@ -0,0 +1,395 @@
+/* == Start of generated table == */
+/*
+ * The following table is generated by running:
+ *
+ *   ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
+ *
+ * on files with these headers:
+ *
+ * # ArabicShaping-9.0.0.txt
+ * # Date: 2016-02-24, 22:25:00 GMT [RP]
+ * # Blocks-9.0.0.txt
+ * # Date: 2016-02-05, 23:48:00 GMT [KW]
+ * UnicodeData.txt does not have a header.
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH
+#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH
+
+
+#define X       JOINING_TYPE_X
+#define R       JOINING_TYPE_R
+#define T       JOINING_TYPE_T
+#define U       JOINING_TYPE_U
+#define A       JOINING_GROUP_ALAPH
+#define DR      JOINING_GROUP_DALATH_RISH
+#define L       JOINING_TYPE_L
+#define C       JOINING_TYPE_C
+#define D       JOINING_TYPE_D
+
+static const uint8_t joining_table[] =
+{
+
+#define joining_offset_0x0600u 0
+
+  /* Arabic */
+
+  /* 0600 */ U,U,U,U,U,U,X,X,U,X,X,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 0620 */ D,U,R,R,R,R,D,R,D,R,D,D,D,D,D,R,R,R,R,D,D,D,D,D,D,D,D,D,D,D,D,D,
+  /* 0640 */ C,D,D,D,D,D,D,D,R,D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 0660 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,D,D,X,R,R,R,U,R,R,R,D,D,D,D,D,D,D,D,
+  /* 0680 */ D,D,D,D,D,D,D,D,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,D,D,D,D,D,D,
+  /* 06A0 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+  /* 06C0 */ R,D,D,R,R,R,R,R,R,R,R,R,D,R,D,R,D,D,R,R,X,R,X,X,X,X,X,X,X,U,X,X,
+  /* 06E0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,R,R,X,X,X,X,X,X,X,X,X,X,D,D,D,X,X,D,
+
+  /* Syriac */
+
+  /* 0700 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,A,X,D,D,D,DR,DR,R,R,R,D,D,D,D,R,D,
+  /* 0720 */ D,D,D,D,D,D,D,D,R,D,DR,D,R,D,D,DR,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 0740 */ X,X,X,X,X,X,X,X,X,X,X,X,X,R,D,D,
+
+  /* Arabic Supplement */
+
+  /* 0740 */                                 D,D,D,D,D,D,D,D,D,R,R,R,D,D,D,D,
+  /* 0760 */ D,D,D,D,D,D,D,D,D,D,D,R,R,D,D,D,D,R,D,R,R,D,D,D,R,R,D,D,D,D,D,D,
+
+  /* FILLER */
+
+  /* 0780 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 07A0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+
+  /* NKo */
+
+  /* 07C0 */ X,X,X,X,X,X,X,X,X,X,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+  /* 07E0 */ D,D,D,D,D,D,D,D,D,D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,C,X,X,X,X,X,
+
+  /* FILLER */
+
+  /* 0800 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 0820 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+
+  /* Mandaic */
+
+  /* 0840 */ R,D,D,D,D,D,R,R,D,R,D,D,D,D,D,D,D,D,D,D,R,D,U,U,U,X,X,X,X,X,X,X,
+  /* 0860 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 0880 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+
+  /* Arabic Extended-A */
+
+  /* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,D,D,X,D,D,D,R,D,D,D,D,X,X,
+  /* 08C0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 08E0 */ X,X,U,
+
+#define joining_offset_0x1806u 739
+
+  /* Mongolian */
+
+  /* 1800 */             U,D,X,X,C,X,X,X,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 1820 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+  /* 1840 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+  /* 1860 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,X,X,X,X,X,X,X,X,
+  /* 1880 */ U,U,U,U,U,T,T,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+  /* 18A0 */ D,D,D,D,D,D,D,D,D,X,D,
+
+#define joining_offset_0x200cu 904
+
+  /* General Punctuation */
+
+  /* 2000 */                         U,C,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 2020 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 2040 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 2060 */ X,X,X,X,X,X,U,U,U,U,
+
+#define joining_offset_0xa840u 998
+
+  /* Phags-pa */
+
+  /* A840 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+  /* A860 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,L,U,
+
+#define joining_offset_0x10ac0u 1050
+
+  /* Manichaean */
+
+  /* 10AC0 */ D,D,D,D,D,R,U,R,U,R,R,U,U,L,R,R,R,R,R,D,D,D,D,L,D,D,D,D,D,R,D,D,
+  /* 10AE0 */ D,R,U,U,R,X,X,X,X,X,X,D,D,D,D,R,
+
+#define joining_offset_0x10b80u 1098
+
+  /* Psalter Pahlavi */
+
+  /* 10B80 */ D,R,D,R,R,R,D,D,D,R,D,D,R,D,R,R,D,R,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 10BA0 */ X,X,X,X,X,X,X,X,X,R,R,R,R,D,D,U,
+
+#define joining_offset_0x1e900u 1146
+
+  /* Adlam */
+
+  /* 1E900 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+  /* 1E920 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+  /* 1E940 */ D,D,D,D,
+
+}; /* Table items: 1214; occupancy: 54% */
+
+
+static unsigned int
+joining_type (hb_codepoint_t u)
+{
+  switch (u >> 12)
+  {
+    case 0x0u:
+      if (hb_in_range (u, 0x0600u, 0x08E2u)) return joining_table[u - 0x0600u + joining_offset_0x0600u];
+      break;
+
+    case 0x1u:
+      if (hb_in_range (u, 0x1806u, 0x18AAu)) return joining_table[u - 0x1806u + joining_offset_0x1806u];
+      break;
+
+    case 0x2u:
+      if (hb_in_range (u, 0x200Cu, 0x2069u)) return joining_table[u - 0x200Cu + joining_offset_0x200cu];
+      break;
+
+    case 0xAu:
+      if (hb_in_range (u, 0xA840u, 0xA873u)) return joining_table[u - 0xA840u + joining_offset_0xa840u];
+      break;
+
+    case 0x10u:
+      if (hb_in_range (u, 0x10AC0u, 0x10AEFu)) return joining_table[u - 0x10AC0u + joining_offset_0x10ac0u];
+      if (hb_in_range (u, 0x10B80u, 0x10BAFu)) return joining_table[u - 0x10B80u + joining_offset_0x10b80u];
+      break;
+
+    case 0x1Eu:
+      if (hb_in_range (u, 0x1E900u, 0x1E943u)) return joining_table[u - 0x1E900u + joining_offset_0x1e900u];
+      break;
+
+    default:
+      break;
+  }
+  return X;
+}
+
+#undef X
+#undef R
+#undef T
+#undef U
+#undef A
+#undef DR
+#undef L
+#undef C
+#undef D
+
+
+static const uint16_t shaping_table[][4] =
+{
+  {0x0000u, 0x0000u, 0x0000u, 0xFE80u}, /* U+0621 ARABIC LETTER HAMZA ISOLATED FORM */
+  {0x0000u, 0x0000u, 0xFE82u, 0xFE81u}, /* U+0622 ARABIC LETTER ALEF WITH MADDA ABOVE */
+  {0x0000u, 0x0000u, 0xFE84u, 0xFE83u}, /* U+0623 ARABIC LETTER ALEF WITH HAMZA ABOVE */
+  {0x0000u, 0x0000u, 0xFE86u, 0xFE85u}, /* U+0624 ARABIC LETTER WAW WITH HAMZA ABOVE */
+  {0x0000u, 0x0000u, 0xFE88u, 0xFE87u}, /* U+0625 ARABIC LETTER ALEF WITH HAMZA BELOW */
+  {0xFE8Bu, 0xFE8Cu, 0xFE8Au, 0xFE89u}, /* U+0626 ARABIC LETTER YEH WITH HAMZA ABOVE */
+  {0x0000u, 0x0000u, 0xFE8Eu, 0xFE8Du}, /* U+0627 ARABIC LETTER ALEF */
+  {0xFE91u, 0xFE92u, 0xFE90u, 0xFE8Fu}, /* U+0628 ARABIC LETTER BEH */
+  {0x0000u, 0x0000u, 0xFE94u, 0xFE93u}, /* U+0629 ARABIC LETTER TEH MARBUTA */
+  {0xFE97u, 0xFE98u, 0xFE96u, 0xFE95u}, /* U+062A ARABIC LETTER TEH */
+  {0xFE9Bu, 0xFE9Cu, 0xFE9Au, 0xFE99u}, /* U+062B ARABIC LETTER THEH */
+  {0xFE9Fu, 0xFEA0u, 0xFE9Eu, 0xFE9Du}, /* U+062C ARABIC LETTER JEEM */
+  {0xFEA3u, 0xFEA4u, 0xFEA2u, 0xFEA1u}, /* U+062D ARABIC LETTER HAH */
+  {0xFEA7u, 0xFEA8u, 0xFEA6u, 0xFEA5u}, /* U+062E ARABIC LETTER KHAH */
+  {0x0000u, 0x0000u, 0xFEAAu, 0xFEA9u}, /* U+062F ARABIC LETTER DAL */
+  {0x0000u, 0x0000u, 0xFEACu, 0xFEABu}, /* U+0630 ARABIC LETTER THAL */
+  {0x0000u, 0x0000u, 0xFEAEu, 0xFEADu}, /* U+0631 ARABIC LETTER REH */
+  {0x0000u, 0x0000u, 0xFEB0u, 0xFEAFu}, /* U+0632 ARABIC LETTER ZAIN */
+  {0xFEB3u, 0xFEB4u, 0xFEB2u, 0xFEB1u}, /* U+0633 ARABIC LETTER SEEN */
+  {0xFEB7u, 0xFEB8u, 0xFEB6u, 0xFEB5u}, /* U+0634 ARABIC LETTER SHEEN */
+  {0xFEBBu, 0xFEBCu, 0xFEBAu, 0xFEB9u}, /* U+0635 ARABIC LETTER SAD */
+  {0xFEBFu, 0xFEC0u, 0xFEBEu, 0xFEBDu}, /* U+0636 ARABIC LETTER DAD */
+  {0xFEC3u, 0xFEC4u, 0xFEC2u, 0xFEC1u}, /* U+0637 ARABIC LETTER TAH */
+  {0xFEC7u, 0xFEC8u, 0xFEC6u, 0xFEC5u}, /* U+0638 ARABIC LETTER ZAH */
+  {0xFECBu, 0xFECCu, 0xFECAu, 0xFEC9u}, /* U+0639 ARABIC LETTER AIN */
+  {0xFECFu, 0xFED0u, 0xFECEu, 0xFECDu}, /* U+063A ARABIC LETTER GHAIN */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+063B  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+063C  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+063D  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+063E  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+063F  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0640  */
+  {0xFED3u, 0xFED4u, 0xFED2u, 0xFED1u}, /* U+0641 ARABIC LETTER FEH */
+  {0xFED7u, 0xFED8u, 0xFED6u, 0xFED5u}, /* U+0642 ARABIC LETTER QAF */
+  {0xFEDBu, 0xFEDCu, 0xFEDAu, 0xFED9u}, /* U+0643 ARABIC LETTER KAF */
+  {0xFEDFu, 0xFEE0u, 0xFEDEu, 0xFEDDu}, /* U+0644 ARABIC LETTER LAM */
+  {0xFEE3u, 0xFEE4u, 0xFEE2u, 0xFEE1u}, /* U+0645 ARABIC LETTER MEEM */
+  {0xFEE7u, 0xFEE8u, 0xFEE6u, 0xFEE5u}, /* U+0646 ARABIC LETTER NOON */
+  {0xFEEBu, 0xFEECu, 0xFEEAu, 0xFEE9u}, /* U+0647 ARABIC LETTER HEH */
+  {0x0000u, 0x0000u, 0xFEEEu, 0xFEEDu}, /* U+0648 ARABIC LETTER WAW */
+  {0xFBE8u, 0xFBE9u, 0xFEF0u, 0xFEEFu}, /* U+0649 ARABIC LETTER */
+  {0xFEF3u, 0xFEF4u, 0xFEF2u, 0xFEF1u}, /* U+064A ARABIC LETTER YEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+064B  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+064C  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+064D  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+064E  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+064F  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0650  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0651  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0652  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0653  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0654  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0655  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0656  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0657  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0658  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0659  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065A  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065B  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065C  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065D  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065E  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065F  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0660  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0661  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0662  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0663  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0664  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0665  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0666  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0667  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0668  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0669  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066A  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066B  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066C  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066D  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066E  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066F  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0670  */
+  {0x0000u, 0x0000u, 0xFB51u, 0xFB50u}, /* U+0671 ARABIC LETTER ALEF WASLA */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0672  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0673  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0674  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0675  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0676  */
+  {0x0000u, 0x0000u, 0x0000u, 0xFBDDu}, /* U+0677 ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0678  */
+  {0xFB68u, 0xFB69u, 0xFB67u, 0xFB66u}, /* U+0679 ARABIC LETTER TTEH */
+  {0xFB60u, 0xFB61u, 0xFB5Fu, 0xFB5Eu}, /* U+067A ARABIC LETTER TTEHEH */
+  {0xFB54u, 0xFB55u, 0xFB53u, 0xFB52u}, /* U+067B ARABIC LETTER BEEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+067C  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+067D  */
+  {0xFB58u, 0xFB59u, 0xFB57u, 0xFB56u}, /* U+067E ARABIC LETTER PEH */
+  {0xFB64u, 0xFB65u, 0xFB63u, 0xFB62u}, /* U+067F ARABIC LETTER TEHEH */
+  {0xFB5Cu, 0xFB5Du, 0xFB5Bu, 0xFB5Au}, /* U+0680 ARABIC LETTER BEHEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0681  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0682  */
+  {0xFB78u, 0xFB79u, 0xFB77u, 0xFB76u}, /* U+0683 ARABIC LETTER NYEH */
+  {0xFB74u, 0xFB75u, 0xFB73u, 0xFB72u}, /* U+0684 ARABIC LETTER DYEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0685  */
+  {0xFB7Cu, 0xFB7Du, 0xFB7Bu, 0xFB7Au}, /* U+0686 ARABIC LETTER TCHEH */
+  {0xFB80u, 0xFB81u, 0xFB7Fu, 0xFB7Eu}, /* U+0687 ARABIC LETTER TCHEHEH */
+  {0x0000u, 0x0000u, 0xFB89u, 0xFB88u}, /* U+0688 ARABIC LETTER DDAL */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0689  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+068A  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+068B  */
+  {0x0000u, 0x0000u, 0xFB85u, 0xFB84u}, /* U+068C ARABIC LETTER DAHAL */
+  {0x0000u, 0x0000u, 0xFB83u, 0xFB82u}, /* U+068D ARABIC LETTER DDAHAL */
+  {0x0000u, 0x0000u, 0xFB87u, 0xFB86u}, /* U+068E ARABIC LETTER DUL */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+068F  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0690  */
+  {0x0000u, 0x0000u, 0xFB8Du, 0xFB8Cu}, /* U+0691 ARABIC LETTER RREH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0692  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0693  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0694  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0695  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0696  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0697  */
+  {0x0000u, 0x0000u, 0xFB8Bu, 0xFB8Au}, /* U+0698 ARABIC LETTER JEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0699  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069A  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069B  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069C  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069D  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069E  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069F  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A0  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A1  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A2  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A3  */
+  {0xFB6Cu, 0xFB6Du, 0xFB6Bu, 0xFB6Au}, /* U+06A4 ARABIC LETTER VEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A5  */
+  {0xFB70u, 0xFB71u, 0xFB6Fu, 0xFB6Eu}, /* U+06A6 ARABIC LETTER PEHEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A7  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A8  */
+  {0xFB90u, 0xFB91u, 0xFB8Fu, 0xFB8Eu}, /* U+06A9 ARABIC LETTER KEHEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06AA  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06AB  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06AC  */
+  {0xFBD5u, 0xFBD6u, 0xFBD4u, 0xFBD3u}, /* U+06AD ARABIC LETTER NG */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06AE  */
+  {0xFB94u, 0xFB95u, 0xFB93u, 0xFB92u}, /* U+06AF ARABIC LETTER GAF */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B0  */
+  {0xFB9Cu, 0xFB9Du, 0xFB9Bu, 0xFB9Au}, /* U+06B1 ARABIC LETTER NGOEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B2  */
+  {0xFB98u, 0xFB99u, 0xFB97u, 0xFB96u}, /* U+06B3 ARABIC LETTER GUEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B4  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B5  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B6  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B7  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B8  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B9  */
+  {0x0000u, 0x0000u, 0xFB9Fu, 0xFB9Eu}, /* U+06BA ARABIC LETTER NOON GHUNNA */
+  {0xFBA2u, 0xFBA3u, 0xFBA1u, 0xFBA0u}, /* U+06BB ARABIC LETTER RNOON */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06BC  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06BD  */
+  {0xFBACu, 0xFBADu, 0xFBABu, 0xFBAAu}, /* U+06BE ARABIC LETTER HEH DOACHASHMEE */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06BF  */
+  {0x0000u, 0x0000u, 0xFBA5u, 0xFBA4u}, /* U+06C0 ARABIC LETTER HEH WITH YEH ABOVE */
+  {0xFBA8u, 0xFBA9u, 0xFBA7u, 0xFBA6u}, /* U+06C1 ARABIC LETTER HEH GOAL */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06C2  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06C3  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06C4  */
+  {0x0000u, 0x0000u, 0xFBE1u, 0xFBE0u}, /* U+06C5 ARABIC LETTER KIRGHIZ OE */
+  {0x0000u, 0x0000u, 0xFBDAu, 0xFBD9u}, /* U+06C6 ARABIC LETTER OE */
+  {0x0000u, 0x0000u, 0xFBD8u, 0xFBD7u}, /* U+06C7 ARABIC LETTER U */
+  {0x0000u, 0x0000u, 0xFBDCu, 0xFBDBu}, /* U+06C8 ARABIC LETTER YU */
+  {0x0000u, 0x0000u, 0xFBE3u, 0xFBE2u}, /* U+06C9 ARABIC LETTER KIRGHIZ YU */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06CA  */
+  {0x0000u, 0x0000u, 0xFBDFu, 0xFBDEu}, /* U+06CB ARABIC LETTER VE */
+  {0xFBFEu, 0xFBFFu, 0xFBFDu, 0xFBFCu}, /* U+06CC ARABIC LETTER FARSI YEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06CD  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06CE  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06CF  */
+  {0xFBE6u, 0xFBE7u, 0xFBE5u, 0xFBE4u}, /* U+06D0 ARABIC LETTER E */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06D1  */
+  {0x0000u, 0x0000u, 0xFBAFu, 0xFBAEu}, /* U+06D2 ARABIC LETTER YEH BARREE */
+  {0x0000u, 0x0000u, 0xFBB1u, 0xFBB0u}, /* U+06D3 ARABIC LETTER YEH BARREE WITH HAMZA ABOVE */
+};
+
+#define SHAPING_TABLE_FIRST     0x0621u
+#define SHAPING_TABLE_LAST      0x06D3u
+
+
+static const struct ligature_set_t {
+ uint16_t first;
+ struct ligature_pairs_t {
+   uint16_t second;
+   uint16_t ligature;
+ } ligatures[4];
+} ligature_table[] =
+{
+  { 0xFEDFu, {
+    { 0xFE88u, 0xFEF9u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */
+    { 0xFE82u, 0xFEF5u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM */
+    { 0xFE8Eu, 0xFEFBu }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */
+    { 0xFE84u, 0xFEF7u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM */
+  }},
+  { 0xFEE0u, {
+    { 0xFE88u, 0xFEFAu }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */
+    { 0xFE82u, 0xFEF6u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM */
+    { 0xFE8Eu, 0xFEFCu }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */
+    { 0xFE84u, 0xFEF8u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM */
+  }},
+};
+
+
+#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH */
+
+/* == End of generated table == */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-win1256.hh b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-win1256.hh
new file mode 100644
index 0000000..5d0268c
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-win1256.hh
@@ -0,0 +1,323 @@
+/*
+ * Copyright © 2014  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_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH
+
+
+/*
+ * The macros in the first part of this file are generic macros that can
+ * be used to define the bytes for OpenType table data in code in a
+ * readable manner.  We can move the macros to reside with their respective
+ * struct types, but since we only use these to define one data table, the
+ * Windows-1256 Arabic shaping table in this file, we keep them here.
+ */
+
+
+/* First we measure, then we cut. */
+#ifndef OT_MEASURE
+#define OT_MEASURE
+#define OT_TABLE_START                  static const struct TABLE_NAME {
+#define OT_TABLE_END                    }
+#define OT_LABEL_START(Name)            unsigned char Name[
+#define OT_LABEL_END                    ];
+#define OT_BYTE(u8)                     +1/*byte*/
+#define OT_USHORT(u16)                  +2/*bytes*/
+#else
+#undef  OT_MEASURE
+#define OT_TABLE_START                  TABLE_NAME = {
+#define OT_TABLE_END                    };
+#define OT_LABEL_START(Name)            {
+#define OT_LABEL_END                    },
+#define OT_BYTE(u8)                     (u8),
+#define OT_USHORT(u16)                  (unsigned char)((u16)>>8), (unsigned char)((u16)&0xFFu),
+#define OT_COUNT(Name, ItemSize)        ((unsigned int) sizeof(((struct TABLE_NAME*)0)->Name) \
+                                         / (unsigned int)(ItemSize) \
+                                         /* OT_ASSERT it's divisible (and positive). */)
+#define OT_DISTANCE(From,To)            ((unsigned int) \
+                                         ((char*)(&((struct TABLE_NAME*)0)->To) - \
+                                          (char*)(&((struct TABLE_NAME*)0)->From)) \
+                                         /* OT_ASSERT it's positive. */)
+#endif
+
+
+#define OT_LABEL(Name) \
+        OT_LABEL_END \
+        OT_LABEL_START(Name)
+
+/* Whenever we receive an argument that is a list, it will expand to
+ * contain commas.  That cannot be passed to another macro because the
+ * commas will throw off the preprocessor.  The solution is to wrap
+ * the passed-in argument in OT_LIST() before passing to the next macro.
+ * Unfortunately this trick requires vararg macros. */
+#define OT_LIST(...) __VA_ARGS__
+
+
+/*
+ * Basic Types
+ */
+
+#define OT_TAG(a,b,c,d) \
+        OT_BYTE(a) OT_BYTE(b) OT_BYTE(c) OT_BYTE(d)
+
+#define OT_OFFSET(From, To) /* Offset from From to To in bytes */ \
+        OT_USHORT(OT_DISTANCE(From, To))
+
+#define OT_GLYPHID /* GlyphID */ \
+        OT_USHORT
+
+#define OT_UARRAY(Name, Items) \
+        OT_LABEL_START(Name) \
+        OT_USHORT(OT_COUNT(Name##Data, 2)) \
+        OT_LABEL(Name##Data) \
+        Items \
+        OT_LABEL_END
+
+#define OT_UHEADLESSARRAY(Name, Items) \
+        OT_LABEL_START(Name) \
+        OT_USHORT(OT_COUNT(Name##Data, 2) + 1) \
+        OT_LABEL(Name##Data) \
+        Items \
+        OT_LABEL_END
+
+
+/*
+ * Common Types
+ */
+
+#define OT_LOOKUP_FLAG_IGNORE_MARKS     0x08u
+
+#define OT_LOOKUP(Name, LookupType, LookupFlag, SubLookupOffsets) \
+        OT_LABEL_START(Name) \
+        OT_USHORT(LookupType) \
+        OT_USHORT(LookupFlag) \
+        OT_LABEL_END \
+        OT_UARRAY(Name##SubLookupOffsetsArray, OT_LIST(SubLookupOffsets))
+
+#define OT_SUBLOOKUP(Name, SubFormat, Items) \
+        OT_LABEL_START(Name) \
+        OT_USHORT(SubFormat) \
+        Items
+
+#define OT_COVERAGE1(Name, Items) \
+        OT_LABEL_START(Name) \
+        OT_USHORT(1) \
+        OT_LABEL_END \
+        OT_UARRAY(Name##Glyphs, OT_LIST(Items))
+
+
+/*
+ * GSUB
+ */
+
+#define OT_LOOKUP_TYPE_SUBST_SINGLE     1u
+#define OT_LOOKUP_TYPE_SUBST_LIGATURE   4u
+
+#define OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(Name, FromGlyphs, ToGlyphs) \
+        OT_SUBLOOKUP(Name, 2, \
+                OT_OFFSET(Name, Name##Coverage) \
+                OT_LABEL_END \
+                OT_UARRAY(Name##Substitute, OT_LIST(ToGlyphs)) \
+        ) \
+        OT_COVERAGE1(Name##Coverage, OT_LIST(FromGlyphs)) \
+        /* ASSERT_STATIC_EXPR_ZERO (len(FromGlyphs) == len(ToGlyphs)) */
+
+#define OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(Name, FirstGlyphs, LigatureSetOffsets) \
+        OT_SUBLOOKUP(Name, 1, \
+                OT_OFFSET(Name, Name##Coverage) \
+                OT_LABEL_END \
+                OT_UARRAY(Name##LigatureSetOffsetsArray, OT_LIST(LigatureSetOffsets)) \
+        ) \
+        OT_COVERAGE1(Name##Coverage, OT_LIST(FirstGlyphs)) \
+        /* ASSERT_STATIC_EXPR_ZERO (len(FirstGlyphs) == len(LigatureSetOffsets)) */
+
+#define OT_LIGATURE_SET(Name, LigatureSetOffsets) \
+        OT_UARRAY(Name, OT_LIST(LigatureSetOffsets))
+
+#define OT_LIGATURE(Name, Components, LigGlyph) \
+        OT_LABEL_START(Name) \
+        LigGlyph \
+        OT_LABEL_END \
+        OT_UHEADLESSARRAY(Name##ComponentsArray, OT_LIST(Components))
+
+/*
+ *
+ * Start of Windows-1256 shaping table.
+ *
+ */
+
+/* Table name. */
+#define TABLE_NAME arabic_win1256_gsub_lookups
+
+/* Table manifest. */
+#define MANIFEST(Items) \
+        OT_LABEL_START(manifest) \
+        OT_USHORT(OT_COUNT(manifestData, 6)) \
+        OT_LABEL(manifestData) \
+        Items \
+        OT_LABEL_END
+
+#define MANIFEST_LOOKUP(Tag, Name) \
+        Tag \
+        OT_OFFSET(manifest, Name)
+
+/* Shorthand. */
+#define G       OT_GLYPHID
+
+/*
+ * Table Start
+ */
+OT_TABLE_START
+
+
+/*
+ * Manifest
+ */
+MANIFEST(
+        MANIFEST_LOOKUP(OT_TAG('r','l','i','g'), rligLookup)
+        MANIFEST_LOOKUP(OT_TAG('i','n','i','t'), initLookup)
+        MANIFEST_LOOKUP(OT_TAG('m','e','d','i'), mediLookup)
+        MANIFEST_LOOKUP(OT_TAG('f','i','n','a'), finaLookup)
+        MANIFEST_LOOKUP(OT_TAG('r','l','i','g'), rligMarksLookup)
+)
+
+/*
+ * Lookups
+ */
+OT_LOOKUP(initLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
+        OT_OFFSET(initLookup, initmediSubLookup)
+        OT_OFFSET(initLookup, initSubLookup)
+)
+OT_LOOKUP(mediLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
+        OT_OFFSET(mediLookup, initmediSubLookup)
+        OT_OFFSET(mediLookup, mediSubLookup)
+        OT_OFFSET(mediLookup, medifinaLamAlefSubLookup)
+)
+OT_LOOKUP(finaLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
+        OT_OFFSET(finaLookup, finaSubLookup)
+        /* We don't need this one currently as the sequence inherits masks
+         * from the first item.  Just in case we change that in the future
+         * to be smart about Arabic masks when ligating... */
+        OT_OFFSET(finaLookup, medifinaLamAlefSubLookup)
+)
+OT_LOOKUP(rligLookup, OT_LOOKUP_TYPE_SUBST_LIGATURE, OT_LOOKUP_FLAG_IGNORE_MARKS,
+        OT_OFFSET(rligLookup, lamAlefLigaturesSubLookup)
+)
+OT_LOOKUP(rligMarksLookup, OT_LOOKUP_TYPE_SUBST_LIGATURE, 0,
+        OT_OFFSET(rligMarksLookup, shaddaLigaturesSubLookup)
+)
+
+/*
+ * init/medi/fina forms
+ */
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(initmediSubLookup,
+        G(198)  G(200)  G(201)  G(202)  G(203)  G(204)  G(205)  G(206)  G(211)
+        G(212)  G(213)  G(214)  G(223)  G(225)  G(227)  G(228)  G(236)  G(237),
+        G(162)  G(4)    G(5)    G(5)    G(6)    G(7)    G(9)    G(11)   G(13)
+        G(14)   G(15)   G(26)   G(140)  G(141)  G(142)  G(143)  G(154)  G(154)
+)
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(initSubLookup,
+        G(218)  G(219)  G(221)  G(222)  G(229),
+        G(27)   G(30)   G(128)  G(131)  G(144)
+)
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(mediSubLookup,
+        G(218)  G(219)  G(221)  G(222)  G(229),
+        G(28)   G(31)   G(129)  G(138)  G(149)
+)
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(finaSubLookup,
+        G(194)  G(195)  G(197)  G(198)  G(199)  G(201)  G(204)  G(205)  G(206)
+        G(218)  G(219)  G(229)  G(236)  G(237),
+        G(2)    G(1)    G(3)    G(181)  G(0)    G(159)  G(8)    G(10)   G(12)
+        G(29)   G(127)  G(152) G(160)   G(156)
+)
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(medifinaLamAlefSubLookup,
+        G(165)  G(178)  G(180)  G(252),
+        G(170)  G(179)  G(185)  G(255)
+)
+
+/*
+ * Lam+Alef ligatures
+ */
+OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(lamAlefLigaturesSubLookup,
+        G(225),
+        OT_OFFSET(lamAlefLigaturesSubLookup, lamLigatureSet)
+)
+OT_LIGATURE_SET(lamLigatureSet,
+        OT_OFFSET(lamLigatureSet, lamInitLigature1)
+        OT_OFFSET(lamLigatureSet, lamInitLigature2)
+        OT_OFFSET(lamLigatureSet, lamInitLigature3)
+        OT_OFFSET(lamLigatureSet, lamInitLigature4)
+)
+OT_LIGATURE(lamInitLigature1, G(199), G(165))
+OT_LIGATURE(lamInitLigature2, G(195), G(178))
+OT_LIGATURE(lamInitLigature3, G(194), G(180))
+OT_LIGATURE(lamInitLigature4, G(197), G(252))
+
+/*
+ * Shadda ligatures
+ */
+OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(shaddaLigaturesSubLookup,
+        G(248),
+        OT_OFFSET(shaddaLigaturesSubLookup, shaddaLigatureSet)
+)
+OT_LIGATURE_SET(shaddaLigatureSet,
+        OT_OFFSET(shaddaLigatureSet, shaddaLigature1)
+        OT_OFFSET(shaddaLigatureSet, shaddaLigature2)
+        OT_OFFSET(shaddaLigatureSet, shaddaLigature3)
+)
+OT_LIGATURE(shaddaLigature1, G(243), G(172))
+OT_LIGATURE(shaddaLigature2, G(245), G(173))
+OT_LIGATURE(shaddaLigature3, G(246), G(175))
+
+/*
+ * Table end
+ */
+OT_TABLE_END
+
+
+/*
+ * Clean up
+ */
+#undef OT_TABLE_START
+#undef OT_TABLE_END
+#undef OT_LABEL_START
+#undef OT_LABEL_END
+#undef OT_BYTE
+#undef OT_USHORT
+#undef OT_DISTANCE
+#undef OT_COUNT
+
+/*
+ * Include a second time to get the table data...
+ */
+#if 0
+#include "hb-private.hh" /* Make check-includes.sh happy. */
+#endif
+#ifdef OT_MEASURE
+#include "hb-ot-shape-complex-arabic-win1256.hh"
+#endif
+
+#define HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH
+#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic.cpp
new file mode 100644
index 0000000..80accde
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic.cpp
@@ -0,0 +1,623 @@
+/*
+ * Copyright © 2010,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
+ */
+
+#include "hb-ot-shape-complex-arabic-private.hh"
+#include "hb-ot-shape-private.hh"
+
+
+#ifndef HB_DEBUG_ARABIC
+#define HB_DEBUG_ARABIC (HB_DEBUG+0)
+#endif
+
+
+/* buffer var allocations */
+#define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
+
+#define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_COMPLEX0
+
+/* See:
+ * https://github.com/behdad/harfbuzz/commit/6e6f82b6f3dde0fc6c3c7d991d9ec6cfff57823d#commitcomment-14248516 */
+#define HB_ARABIC_GENERAL_CATEGORY_IS_WORD(gen_cat) \
+        (FLAG_SAFE (gen_cat) & \
+         (FLAG (HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED) | \
+          FLAG (HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE) | \
+          /*FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |*/ \
+          FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER) | \
+          FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) | \
+          /*FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) |*/ \
+          /*FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER) |*/ \
+          FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
+          FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
+          FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | \
+          FLAG (HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) | \
+          FLAG (HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER) | \
+          FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER) | \
+          FLAG (HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL) | \
+          FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL) | \
+          FLAG (HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL) | \
+          FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL)))
+
+
+/*
+ * Joining types:
+ */
+
+/*
+ * Bits used in the joining tables
+ */
+enum hb_arabic_joining_type_t {
+  JOINING_TYPE_U                = 0,
+  JOINING_TYPE_L                = 1,
+  JOINING_TYPE_R                = 2,
+  JOINING_TYPE_D                = 3,
+  JOINING_TYPE_C                = JOINING_TYPE_D,
+  JOINING_GROUP_ALAPH           = 4,
+  JOINING_GROUP_DALATH_RISH     = 5,
+  NUM_STATE_MACHINE_COLS        = 6,
+
+  JOINING_TYPE_T = 7,
+  JOINING_TYPE_X = 8  /* means: use general-category to choose between U or T. */
+};
+
+#include "hb-ot-shape-complex-arabic-table.hh"
+
+static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat)
+{
+  unsigned int j_type = joining_type(u);
+  if (likely (j_type != JOINING_TYPE_X))
+    return j_type;
+
+  return (FLAG_SAFE(gen_cat) &
+          (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
+           FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
+           FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))
+         ) ?  JOINING_TYPE_T : JOINING_TYPE_U;
+}
+
+#define FEATURE_IS_SYRIAC(tag) hb_in_range<unsigned char> ((unsigned char) (tag), '2', '3')
+
+static const hb_tag_t arabic_features[] =
+{
+  HB_TAG('i','s','o','l'),
+  HB_TAG('f','i','n','a'),
+  HB_TAG('f','i','n','2'),
+  HB_TAG('f','i','n','3'),
+  HB_TAG('m','e','d','i'),
+  HB_TAG('m','e','d','2'),
+  HB_TAG('i','n','i','t'),
+  HB_TAG_NONE
+};
+
+
+/* Same order as the feature array */
+enum arabic_action_t {
+  ISOL,
+  FINA,
+  FIN2,
+  FIN3,
+  MEDI,
+  MED2,
+  INIT,
+
+  NONE,
+
+  ARABIC_NUM_FEATURES = NONE,
+
+  /* We abuse the same byte for other things... */
+  STCH_FIXED,
+  STCH_REPEATING,
+};
+
+static const struct arabic_state_table_entry {
+        uint8_t prev_action;
+        uint8_t curr_action;
+        uint16_t next_state;
+} arabic_state_table[][NUM_STATE_MACHINE_COLS] =
+{
+  /*   jt_U,          jt_L,          jt_R,          jt_D,          jg_ALAPH,      jg_DALATH_RISH */
+
+  /* State 0: prev was U, not willing to join. */
+  { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, },
+
+  /* State 1: prev was R or ISOL/ALAPH, not willing to join. */
+  { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, },
+
+  /* State 2: prev was D/L in ISOL form, willing to join. */
+  { {NONE,NONE,0}, {NONE,ISOL,2}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, },
+
+  /* State 3: prev was D in FINA form, willing to join. */
+  { {NONE,NONE,0}, {NONE,ISOL,2}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, },
+
+  /* State 4: prev was FINA ALAPH, not willing to join. */
+  { {NONE,NONE,0}, {NONE,ISOL,2}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, },
+
+  /* State 5: prev was FIN2/FIN3 ALAPH, not willing to join. */
+  { {NONE,NONE,0}, {NONE,ISOL,2}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, },
+
+  /* State 6: prev was DALATH/RISH, not willing to join. */
+  { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, }
+};
+
+
+static void
+nuke_joiners (const hb_ot_shape_plan_t *plan,
+              hb_font_t *font,
+              hb_buffer_t *buffer);
+
+static void
+arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
+                       hb_font_t *font,
+                       hb_buffer_t *buffer);
+
+static void
+record_stch (const hb_ot_shape_plan_t *plan,
+             hb_font_t *font,
+             hb_buffer_t *buffer);
+
+static void
+collect_features_arabic (hb_ot_shape_planner_t *plan)
+{
+  hb_ot_map_builder_t *map = &plan->map;
+
+  /* We apply features according to the Arabic spec, with pauses
+   * in between most.
+   *
+   * The pause between init/medi/... and rlig is required.  See eg:
+   * https://bugzilla.mozilla.org/show_bug.cgi?id=644184
+   *
+   * The pauses between init/medi/... themselves are not necessarily
+   * needed as only one of those features is applied to any character.
+   * The only difference it makes is when fonts have contextual
+   * substitutions.  We now follow the order of the spec, which makes
+   * for better experience if that's what Uniscribe is doing.
+   *
+   * At least for Arabic, looks like Uniscribe has a pause between
+   * rlig and calt.  Otherwise the IranNastaliq's ALLAH ligature won't
+   * work.  However, testing shows that rlig and calt are applied
+   * together for Mongolian in Uniscribe.  As such, we only add a
+   * pause for Arabic, not other scripts.
+   */
+
+  map->add_gsub_pause (nuke_joiners);
+
+  map->add_global_bool_feature (HB_TAG('s','t','c','h'));
+  map->add_gsub_pause (record_stch);
+
+  map->add_global_bool_feature (HB_TAG('c','c','m','p'));
+  map->add_global_bool_feature (HB_TAG('l','o','c','l'));
+
+  map->add_gsub_pause (NULL);
+
+  for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
+  {
+    bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]);
+    map->add_feature (arabic_features[i], 1, has_fallback ? F_HAS_FALLBACK : F_NONE);
+    map->add_gsub_pause (NULL);
+  }
+
+  map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK);
+  if (plan->props.script == HB_SCRIPT_ARABIC)
+    map->add_gsub_pause (arabic_fallback_shape);
+
+  map->add_global_bool_feature (HB_TAG('c','a','l','t'));
+
+  /* The spec includes 'cswh'.  Earlier versions of Windows
+   * used to enable this by default, but testing suggests
+   * that Windows 8 and later do not enable it by default,
+   * and spec now says 'Off by default'.
+   * We disabled this in ae23c24c32.
+   * Note that IranNastaliq uses this feature extensively
+   * to fixup broken glyph sequences.  Oh well...
+   * Test case: U+0643,U+0640,U+0631. */
+  //map->add_gsub_pause (NULL);
+  //map->add_global_bool_feature (HB_TAG('c','s','w','h'));
+  map->add_global_bool_feature (HB_TAG('m','s','e','t'));
+}
+
+#include "hb-ot-shape-complex-arabic-fallback.hh"
+
+struct arabic_shape_plan_t
+{
+  ASSERT_POD ();
+
+  /* The "+ 1" in the next array is to accommodate for the "NONE" command,
+   * which is not an OpenType feature, but this simplifies the code by not
+   * having to do a "if (... < NONE) ..." and just rely on the fact that
+   * mask_array[NONE] == 0. */
+  hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1];
+
+  arabic_fallback_plan_t *fallback_plan;
+
+  unsigned int do_fallback : 1;
+  unsigned int has_stch : 1;
+};
+
+void *
+data_create_arabic (const hb_ot_shape_plan_t *plan)
+{
+  arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t));
+  if (unlikely (!arabic_plan))
+    return NULL;
+
+  arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC;
+  arabic_plan->has_stch = !!plan->map.get_1_mask (HB_TAG ('s','t','c','h'));
+  for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
+    arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
+    arabic_plan->do_fallback = arabic_plan->do_fallback &&
+                               (FEATURE_IS_SYRIAC (arabic_features[i]) ||
+                                plan->map.needs_fallback (arabic_features[i]));
+  }
+
+  return arabic_plan;
+}
+
+void
+data_destroy_arabic (void *data)
+{
+  arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) data;
+
+  arabic_fallback_plan_destroy (arabic_plan->fallback_plan);
+
+  free (data);
+}
+
+static void
+arabic_joining (hb_buffer_t *buffer)
+{
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int prev = (unsigned int) -1, state = 0;
+
+  /* Check pre-context */
+  for (unsigned int i = 0; i < buffer->context_len[0]; i++)
+  {
+    unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i]));
+
+    if (unlikely (this_type == JOINING_TYPE_T))
+      continue;
+
+    const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
+    state = entry->next_state;
+    break;
+  }
+
+  for (unsigned int i = 0; i < count; i++)
+  {
+    unsigned int this_type = get_joining_type (info[i].codepoint, _hb_glyph_info_get_general_category (&info[i]));
+
+    if (unlikely (this_type == JOINING_TYPE_T)) {
+      info[i].arabic_shaping_action() = NONE;
+      continue;
+    }
+
+    const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
+
+    if (entry->prev_action != NONE && prev != (unsigned int) -1)
+      info[prev].arabic_shaping_action() = entry->prev_action;
+
+    info[i].arabic_shaping_action() = entry->curr_action;
+
+    prev = i;
+    state = entry->next_state;
+  }
+
+  for (unsigned int i = 0; i < buffer->context_len[1]; i++)
+  {
+    unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[1][i]));
+
+    if (unlikely (this_type == JOINING_TYPE_T))
+      continue;
+
+    const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
+    if (entry->prev_action != NONE && prev != (unsigned int) -1)
+      info[prev].arabic_shaping_action() = entry->prev_action;
+    break;
+  }
+}
+
+static void
+mongolian_variation_selectors (hb_buffer_t *buffer)
+{
+  /* Copy arabic_shaping_action() from base to Mongolian variation selectors. */
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 1; i < count; i++)
+    if (unlikely (hb_in_range (info[i].codepoint, 0x180Bu, 0x180Du)))
+      info[i].arabic_shaping_action() = info[i - 1].arabic_shaping_action();
+}
+
+void
+setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan,
+                         hb_buffer_t               *buffer,
+                         hb_script_t                script)
+{
+  HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action);
+
+  arabic_joining (buffer);
+  if (script == HB_SCRIPT_MONGOLIAN)
+    mongolian_variation_selectors (buffer);
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    info[i].mask |= arabic_plan->mask_array[info[i].arabic_shaping_action()];
+}
+
+static void
+setup_masks_arabic (const hb_ot_shape_plan_t *plan,
+                    hb_buffer_t              *buffer,
+                    hb_font_t                *font HB_UNUSED)
+{
+  const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
+  setup_masks_arabic_plan (arabic_plan, buffer, plan->props.script);
+}
+
+
+static void
+nuke_joiners (const hb_ot_shape_plan_t *plan HB_UNUSED,
+              hb_font_t *font HB_UNUSED,
+              hb_buffer_t *buffer)
+{
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    if (_hb_glyph_info_is_zwj (&info[i]))
+      _hb_glyph_info_flip_joiners (&info[i]);
+}
+
+static void
+arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
+                       hb_font_t *font,
+                       hb_buffer_t *buffer)
+{
+  const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
+
+  if (!arabic_plan->do_fallback)
+    return;
+
+retry:
+  arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) hb_atomic_ptr_get (&arabic_plan->fallback_plan);
+  if (unlikely (!fallback_plan))
+  {
+    /* This sucks.  We need a font to build the fallback plan... */
+    fallback_plan = arabic_fallback_plan_create (plan, font);
+    if (unlikely (!hb_atomic_ptr_cmpexch (&(const_cast<arabic_shape_plan_t *> (arabic_plan))->fallback_plan, NULL, fallback_plan))) {
+      arabic_fallback_plan_destroy (fallback_plan);
+      goto retry;
+    }
+  }
+
+  arabic_fallback_plan_shape (fallback_plan, font, buffer);
+}
+
+/*
+ * Stretch feature: "stch".
+ * See example here:
+ * https://www.microsoft.com/typography/OpenTypeDev/syriac/intro.htm
+ * We implement this in a generic way, such that the Arabic subtending
+ * marks can use it as well.
+ */
+
+static void
+record_stch (const hb_ot_shape_plan_t *plan,
+             hb_font_t *font,
+             hb_buffer_t *buffer)
+{
+  const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
+  if (!arabic_plan->has_stch)
+    return;
+
+  /* 'stch' feature was just applied.  Look for anything that multiplied,
+   * and record it for stch treatment later.  Note that rtlm, frac, etc
+   * are applied before stch, but we assume that they didn't result in
+   * anything multiplying into 5 pieces, so it's safe-ish... */
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    if (unlikely (_hb_glyph_info_multiplied (&info[i])))
+    {
+      unsigned int comp = _hb_glyph_info_get_lig_comp (&info[i]);
+      info[i].arabic_shaping_action() = comp % 2 ? STCH_REPEATING : STCH_FIXED;
+      buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH;
+    }
+}
+
+static void
+apply_stch (const hb_ot_shape_plan_t *plan,
+            hb_buffer_t              *buffer,
+            hb_font_t                *font)
+{
+  if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH)))
+    return;
+
+  /* The Arabic shaper currently always processes in RTL mode, so we should
+   * stretch / position the stretched pieces to the left / preceding glyphs. */
+
+  /* We do a two pass implementation:
+   * First pass calculates the exact number of extra glyphs we need,
+   * We then enlarge buffer to have that much room,
+   * Second pass applies the stretch, copying things to the end of buffer.
+   */
+
+  int sign = font->x_scale < 0 ? -1 : +1;
+  unsigned int extra_glyphs_needed = 0; // Set during MEASURE, used during CUT
+  typedef enum { MEASURE, CUT } step_t;
+
+  for (step_t step = MEASURE; step <= CUT; step = (step_t) (step + 1))
+  {
+    unsigned int count = buffer->len;
+    hb_glyph_info_t *info = buffer->info;
+    hb_glyph_position_t *pos = buffer->pos;
+    unsigned int new_len = count + extra_glyphs_needed; // write head during CUT
+    unsigned int j = new_len;
+    for (unsigned int i = count; i; i--)
+    {
+      if (!hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
+      {
+        if (step == CUT)
+        {
+          --j;
+          info[j] = info[i - 1];
+          pos[j] = pos[i - 1];
+        }
+        continue;
+      }
+
+      /* Yay, justification! */
+
+      hb_position_t w_total = 0; // Total to be filled
+      hb_position_t w_fixed = 0; // Sum of fixed tiles
+      hb_position_t w_repeating = 0; // Sum of repeating tiles
+      int n_fixed = 0;
+      int n_repeating = 0;
+
+      unsigned int end = i;
+      while (i &&
+             hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
+      {
+        i--;
+        hb_position_t width = font->get_glyph_h_advance (info[i].codepoint);
+        if (info[i].arabic_shaping_action() == STCH_FIXED)
+        {
+          w_fixed += width;
+          n_fixed++;
+        }
+        else
+        {
+          w_repeating += width;
+          n_repeating++;
+        }
+      }
+      unsigned int start = i;
+      unsigned int context = i;
+      while (context &&
+             !hb_in_range<unsigned> (info[context - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING) &&
+             (_hb_glyph_info_is_default_ignorable (&info[context - 1]) ||
+              HB_ARABIC_GENERAL_CATEGORY_IS_WORD (_hb_glyph_info_get_general_category (&info[context - 1]))))
+      {
+        context--;
+        w_total += pos[context].x_advance;
+      }
+      i++; // Don't touch i again.
+
+      DEBUG_MSG (ARABIC, NULL, "%s stretch at (%d,%d,%d)",
+                 step == MEASURE ? "measuring" : "cutting", context, start, end);
+      DEBUG_MSG (ARABIC, NULL, "rest of word:    count=%d width %d", start - context, w_total);
+      DEBUG_MSG (ARABIC, NULL, "fixed tiles:     count=%d width=%d", n_fixed, w_fixed);
+      DEBUG_MSG (ARABIC, NULL, "repeating tiles: count=%d width=%d", n_repeating, w_repeating);
+
+      /* Number of additional times to repeat each repeating tile. */
+      int n_copies = 0;
+
+      hb_position_t w_remaining = w_total - w_fixed;
+      if (sign * w_remaining > sign * w_repeating && sign * w_repeating > 0)
+        n_copies = (sign * w_remaining) / (sign * w_repeating) - 1;
+
+      /* See if we can improve the fit by adding an extra repeat and squeezing them together a bit. */
+      hb_position_t extra_repeat_overlap = 0;
+      hb_position_t shortfall = sign * w_remaining - sign * w_repeating * (n_copies + 1);
+      if (shortfall > 0)
+      {
+        ++n_copies;
+        hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining;
+        if (excess > 0)
+          extra_repeat_overlap = excess / (n_copies * n_repeating);
+      }
+
+      if (step == MEASURE)
+      {
+        extra_glyphs_needed += n_copies * n_repeating;
+        DEBUG_MSG (ARABIC, NULL, "will add extra %d copies of repeating tiles", n_copies);
+      }
+      else
+      {
+        hb_position_t x_offset = 0;
+        for (unsigned int k = end; k > start; k--)
+        {
+          hb_position_t width = font->get_glyph_h_advance (info[k - 1].codepoint);
+
+          unsigned int repeat = 1;
+          if (info[k - 1].arabic_shaping_action() == STCH_REPEATING)
+            repeat += n_copies;
+
+          DEBUG_MSG (ARABIC, NULL, "appending %d copies of glyph %d; j=%d",
+                     repeat, info[k - 1].codepoint, j);
+          for (unsigned int n = 0; n < repeat; n++)
+          {
+            x_offset -= width;
+            if (n > 0)
+              x_offset += extra_repeat_overlap;
+            pos[k - 1].x_offset = x_offset;
+            /* Append copy. */
+            --j;
+            info[j] = info[k - 1];
+            pos[j] = pos[k - 1];
+          }
+        }
+      }
+    }
+
+    if (step == MEASURE)
+    {
+      if (unlikely (!buffer->ensure (count + extra_glyphs_needed)))
+        break;
+    }
+    else
+    {
+      assert (j == 0);
+      buffer->len = new_len;
+    }
+  }
+}
+
+
+static void
+postprocess_glyphs_arabic (const hb_ot_shape_plan_t *plan,
+                           hb_buffer_t              *buffer,
+                           hb_font_t                *font)
+{
+  apply_stch (plan, buffer, font);
+
+  HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
+}
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
+{
+  "arabic",
+  collect_features_arabic,
+  NULL, /* override_features */
+  data_create_arabic,
+  data_destroy_arabic,
+  NULL, /* preprocess_text */
+  postprocess_glyphs_arabic,
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+  NULL, /* decompose */
+  NULL, /* compose */
+  setup_masks_arabic,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
+  true, /* fallback_position */
+};
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-default.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-default.cpp
new file mode 100644
index 0000000..be60e56
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-default.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2010,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
+ */
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
+{
+  "default",
+  NULL, /* collect_features */
+  NULL, /* override_features */
+  NULL, /* data_create */
+  NULL, /* data_destroy */
+  NULL, /* preprocess_text */
+  NULL, /* postprocess_glyphs */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+  NULL, /* decompose */
+  NULL, /* compose */
+  NULL, /* setup_masks */
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
+  true, /* fallback_position */
+};
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-hangul.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-hangul.cpp
new file mode 100644
index 0000000..aa90739
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-hangul.cpp
@@ -0,0 +1,424 @@
+/*
+ * 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
+ */
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+/* Hangul shaper */
+
+
+/* Same order as the feature array below */
+enum {
+  NONE,
+
+  LJMO,
+  VJMO,
+  TJMO,
+
+  FIRST_HANGUL_FEATURE = LJMO,
+  HANGUL_FEATURE_COUNT = TJMO + 1
+};
+
+static const hb_tag_t hangul_features[HANGUL_FEATURE_COUNT] =
+{
+  HB_TAG_NONE,
+  HB_TAG('l','j','m','o'),
+  HB_TAG('v','j','m','o'),
+  HB_TAG('t','j','m','o')
+};
+
+static void
+collect_features_hangul (hb_ot_shape_planner_t *plan)
+{
+  hb_ot_map_builder_t *map = &plan->map;
+
+  for (unsigned int i = FIRST_HANGUL_FEATURE; i < HANGUL_FEATURE_COUNT; i++)
+    map->add_feature (hangul_features[i], 1, F_NONE);
+}
+
+static void
+override_features_hangul (hb_ot_shape_planner_t *plan)
+{
+  /* Uniscribe does not apply 'calt' for Hangul, and certain fonts
+   * (Noto Sans CJK, Source Sans Han, etc) apply all of jamo lookups
+   * in calt, which is not desirable. */
+  plan->map.add_feature (HB_TAG('c','a','l','t'), 0, F_GLOBAL);
+}
+
+struct hangul_shape_plan_t
+{
+  ASSERT_POD ();
+
+  hb_mask_t mask_array[HANGUL_FEATURE_COUNT];
+};
+
+static void *
+data_create_hangul (const hb_ot_shape_plan_t *plan)
+{
+  hangul_shape_plan_t *hangul_plan = (hangul_shape_plan_t *) calloc (1, sizeof (hangul_shape_plan_t));
+  if (unlikely (!hangul_plan))
+    return NULL;
+
+  for (unsigned int i = 0; i < HANGUL_FEATURE_COUNT; i++)
+    hangul_plan->mask_array[i] = plan->map.get_1_mask (hangul_features[i]);
+
+  return hangul_plan;
+}
+
+static void
+data_destroy_hangul (void *data)
+{
+  free (data);
+}
+
+/* Constants for algorithmic hangul syllable [de]composition. */
+#define LBase 0x1100u
+#define VBase 0x1161u
+#define TBase 0x11A7u
+#define LCount 19u
+#define VCount 21u
+#define TCount 28u
+#define SBase 0xAC00u
+#define NCount (VCount * TCount)
+#define SCount (LCount * NCount)
+
+#define isCombiningL(u) (hb_in_range ((u), LBase, LBase+LCount-1))
+#define isCombiningV(u) (hb_in_range ((u), VBase, VBase+VCount-1))
+#define isCombiningT(u) (hb_in_range ((u), TBase+1, TBase+TCount-1))
+#define isCombinedS(u) (hb_in_range ((u), SBase, SBase+SCount-1))
+
+#define isL(u) (hb_in_ranges ((u), 0x1100u, 0x115Fu, 0xA960u, 0xA97Cu))
+#define isV(u) (hb_in_ranges ((u), 0x1160u, 0x11A7u, 0xD7B0u, 0xD7C6u))
+#define isT(u) (hb_in_ranges ((u), 0x11A8u, 0x11FFu, 0xD7CBu, 0xD7FBu))
+
+#define isHangulTone(u) (hb_in_range ((u), 0x302Eu, 0x302Fu))
+
+/* buffer var allocations */
+#define hangul_shaping_feature() complex_var_u8_0() /* hangul jamo shaping feature */
+
+static bool
+is_zero_width_char (hb_font_t *font,
+                    hb_codepoint_t unicode)
+{
+  hb_codepoint_t glyph;
+  return hb_font_get_glyph (font, unicode, 0, &glyph) && hb_font_get_glyph_h_advance (font, glyph) == 0;
+}
+
+static void
+preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
+                        hb_buffer_t              *buffer,
+                        hb_font_t                *font)
+{
+  HB_BUFFER_ALLOCATE_VAR (buffer, hangul_shaping_feature);
+
+  /* Hangul syllables come in two shapes: LV, and LVT.  Of those:
+   *
+   *   - LV can be precomposed, or decomposed.  Lets call those
+   *     <LV> and <L,V>,
+   *   - LVT can be fully precomposed, partically precomposed, or
+   *     fully decomposed.  Ie. <LVT>, <LV,T>, or <L,V,T>.
+   *
+   * The composition / decomposition is mechanical.  However, not
+   * all <L,V> sequences compose, and not all <LV,T> sequences
+   * compose.
+   *
+   * Here are the specifics:
+   *
+   *   - <L>: U+1100..115F, U+A960..A97F
+   *   - <V>: U+1160..11A7, U+D7B0..D7C7
+   *   - <T>: U+11A8..11FF, U+D7CB..D7FB
+   *
+   *   - Only the <L,V> sequences for the 11xx ranges combine.
+   *   - Only <LV,T> sequences for T in U+11A8..11C3 combine.
+   *
+   * Here is what we want to accomplish in this shaper:
+   *
+   *   - If the whole syllable can be precomposed, do that,
+   *   - Otherwise, fully decompose and apply ljmo/vjmo/tjmo features.
+   *   - If a valid syllable is followed by a Hangul tone mark, reorder the tone
+   *     mark to precede the whole syllable - unless it is a zero-width glyph, in
+   *     which case we leave it untouched, assuming it's designed to overstrike.
+   *
+   * That is, of the different possible syllables:
+   *
+   *   <L>
+   *   <L,V>
+   *   <L,V,T>
+   *   <LV>
+   *   <LVT>
+   *   <LV, T>
+   *
+   * - <L> needs no work.
+   *
+   * - <LV> and <LVT> can stay the way they are if the font supports them, otherwise we
+   *   should fully decompose them if font supports.
+   *
+   * - <L,V> and <L,V,T> we should compose if the whole thing can be composed.
+   *
+   * - <LV,T> we should compose if the whole thing can be composed, otherwise we should
+   *   decompose.
+   */
+
+  buffer->clear_output ();
+  unsigned int start = 0, end = 0; /* Extent of most recently seen syllable;
+                                    * valid only if start < end
+                                    */
+  unsigned int count = buffer->len;
+
+  for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
+  {
+    hb_codepoint_t u = buffer->cur().codepoint;
+
+    if (isHangulTone (u))
+    {
+      /*
+       * We could cache the width of the tone marks and the existence of dotted-circle,
+       * but the use of the Hangul tone mark characters seems to be rare enough that
+       * I didn't bother for now.
+       */
+      if (start < end && end == buffer->out_len)
+      {
+        /* Tone mark follows a valid syllable; move it in front, unless it's zero width. */
+        buffer->next_glyph ();
+        if (!is_zero_width_char (font, u))
+        {
+          buffer->merge_out_clusters (start, end + 1);
+          hb_glyph_info_t *info = buffer->out_info;
+          hb_glyph_info_t tone = info[end];
+          memmove (&info[start + 1], &info[start], (end - start) * sizeof (hb_glyph_info_t));
+          info[start] = tone;
+        }
+      }
+      else
+      {
+        /* No valid syllable as base for tone mark; try to insert dotted circle. */
+        if (font->has_glyph (0x25CCu))
+        {
+          hb_codepoint_t chars[2];
+          if (!is_zero_width_char (font, u)) {
+            chars[0] = u;
+            chars[1] = 0x25CCu;
+          } else {
+            chars[0] = 0x25CCu;
+            chars[1] = u;
+          }
+          buffer->replace_glyphs (1, 2, chars);
+        }
+        else
+        {
+          /* No dotted circle available in the font; just leave tone mark untouched. */
+          buffer->next_glyph ();
+        }
+      }
+      start = end = buffer->out_len;
+      continue;
+    }
+
+    start = buffer->out_len; /* Remember current position as a potential syllable start;
+                              * will only be used if we set end to a later position.
+                              */
+
+    if (isL (u) && buffer->idx + 1 < count)
+    {
+      hb_codepoint_t l = u;
+      hb_codepoint_t v = buffer->cur(+1).codepoint;
+      if (isV (v))
+      {
+        /* Have <L,V> or <L,V,T>. */
+        hb_codepoint_t t = 0;
+        unsigned int tindex = 0;
+        if (buffer->idx + 2 < count)
+        {
+          t = buffer->cur(+2).codepoint;
+          if (isT (t))
+            tindex = t - TBase; /* Only used if isCombiningT (t); otherwise invalid. */
+          else
+            t = 0; /* The next character was not a trailing jamo. */
+        }
+
+        /* We've got a syllable <L,V,T?>; see if it can potentially be composed. */
+        if (isCombiningL (l) && isCombiningV (v) && (t == 0 || isCombiningT (t)))
+        {
+          /* Try to compose; if this succeeds, end is set to start+1. */
+          hb_codepoint_t s = SBase + (l - LBase) * NCount + (v - VBase) * TCount + tindex;
+          if (font->has_glyph (s))
+          {
+            buffer->replace_glyphs (t ? 3 : 2, 1, &s);
+            if (unlikely (buffer->in_error))
+              return;
+            end = start + 1;
+            continue;
+          }
+        }
+
+        /* We didn't compose, either because it's an Old Hangul syllable without a
+         * precomposed character in Unicode, or because the font didn't support the
+         * necessary precomposed glyph.
+         * Set jamo features on the individual glyphs, and advance past them.
+         */
+        buffer->cur().hangul_shaping_feature() = LJMO;
+        buffer->next_glyph ();
+        buffer->cur().hangul_shaping_feature() = VJMO;
+        buffer->next_glyph ();
+        if (t)
+        {
+          buffer->cur().hangul_shaping_feature() = TJMO;
+          buffer->next_glyph ();
+          end = start + 3;
+        }
+        else
+          end = start + 2;
+        if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+          buffer->merge_out_clusters (start, end);
+        continue;
+      }
+    }
+
+    else if (isCombinedS (u))
+    {
+      /* Have <LV>, <LVT>, or <LV,T> */
+      hb_codepoint_t s = u;
+      bool has_glyph = font->has_glyph (s);
+      unsigned int lindex = (s - SBase) / NCount;
+      unsigned int nindex = (s - SBase) % NCount;
+      unsigned int vindex = nindex / TCount;
+      unsigned int tindex = nindex % TCount;
+
+      if (!tindex &&
+          buffer->idx + 1 < count &&
+          isCombiningT (buffer->cur(+1).codepoint))
+      {
+        /* <LV,T>, try to combine. */
+        unsigned int new_tindex = buffer->cur(+1).codepoint - TBase;
+        hb_codepoint_t new_s = s + new_tindex;
+        if (font->has_glyph (new_s))
+        {
+          buffer->replace_glyphs (2, 1, &new_s);
+          if (unlikely (buffer->in_error))
+            return;
+          end = start + 1;
+          continue;
+        }
+      }
+
+      /* Otherwise, decompose if font doesn't support <LV> or <LVT>,
+       * or if having non-combining <LV,T>.  Note that we already handled
+       * combining <LV,T> above. */
+      if (!has_glyph ||
+          (!tindex &&
+           buffer->idx + 1 < count &&
+           isT (buffer->cur(+1).codepoint)))
+      {
+        hb_codepoint_t decomposed[3] = {LBase + lindex,
+                                        VBase + vindex,
+                                        TBase + tindex};
+        if (font->has_glyph (decomposed[0]) &&
+            font->has_glyph (decomposed[1]) &&
+            (!tindex || font->has_glyph (decomposed[2])))
+        {
+          unsigned int s_len = tindex ? 3 : 2;
+          buffer->replace_glyphs (1, s_len, decomposed);
+          if (unlikely (buffer->in_error))
+            return;
+
+          /* We decomposed S: apply jamo features to the individual glyphs
+           * that are now in buffer->out_info.
+           */
+          hb_glyph_info_t *info = buffer->out_info;
+
+          /* If we decomposed an LV because of a non-combining T following,
+           * we want to include this T in the syllable.
+           */
+          if (has_glyph && !tindex)
+          {
+            buffer->next_glyph ();
+            s_len++;
+          }
+          end = start + s_len;
+
+          unsigned int i = start;
+          info[i++].hangul_shaping_feature() = LJMO;
+          info[i++].hangul_shaping_feature() = VJMO;
+          if (i < end)
+            info[i++].hangul_shaping_feature() = TJMO;
+          if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+            buffer->merge_out_clusters (start, end);
+          continue;
+        }
+      }
+
+      if (has_glyph)
+      {
+        /* We didn't decompose the S, so just advance past it. */
+        end = start + 1;
+        buffer->next_glyph ();
+        continue;
+      }
+    }
+
+    /* Didn't find a recognizable syllable, so we leave end <= start;
+     * this will prevent tone-mark reordering happening.
+     */
+    buffer->next_glyph ();
+  }
+  buffer->swap_buffers ();
+}
+
+static void
+setup_masks_hangul (const hb_ot_shape_plan_t *plan,
+                    hb_buffer_t              *buffer,
+                    hb_font_t                *font HB_UNUSED)
+{
+  const hangul_shape_plan_t *hangul_plan = (const hangul_shape_plan_t *) plan->data;
+
+  if (likely (hangul_plan))
+  {
+    unsigned int count = buffer->len;
+    hb_glyph_info_t *info = buffer->info;
+    for (unsigned int i = 0; i < count; i++, info++)
+      info->mask |= hangul_plan->mask_array[info->hangul_shaping_feature()];
+  }
+
+  HB_BUFFER_DEALLOCATE_VAR (buffer, hangul_shaping_feature);
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
+{
+  "hangul",
+  collect_features_hangul,
+  override_features_hangul,
+  data_create_hangul,
+  data_destroy_hangul,
+  preprocess_text_hangul,
+  NULL, /* postprocess_glyphs */
+  HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
+  NULL, /* decompose */
+  NULL, /* compose */
+  setup_masks_hangul,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+  false, /* fallback_position */
+};
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-hebrew.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-hebrew.cpp
new file mode 100644
index 0000000..e6fde14
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-hebrew.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright © 2010,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
+ */
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+static bool
+compose_hebrew (const hb_ot_shape_normalize_context_t *c,
+                hb_codepoint_t  a,
+                hb_codepoint_t  b,
+                hb_codepoint_t *ab)
+{
+  /* Hebrew presentation-form shaping.
+   * https://bugzilla.mozilla.org/show_bug.cgi?id=728866
+   * Hebrew presentation forms with dagesh, for characters U+05D0..05EA;
+   * Note that some letters do not have a dagesh presForm encoded.
+   */
+  static const hb_codepoint_t sDageshForms[0x05EAu - 0x05D0u + 1] = {
+    0xFB30u, /* ALEF */
+    0xFB31u, /* BET */
+    0xFB32u, /* GIMEL */
+    0xFB33u, /* DALET */
+    0xFB34u, /* HE */
+    0xFB35u, /* VAV */
+    0xFB36u, /* ZAYIN */
+    0x0000u, /* HET */
+    0xFB38u, /* TET */
+    0xFB39u, /* YOD */
+    0xFB3Au, /* FINAL KAF */
+    0xFB3Bu, /* KAF */
+    0xFB3Cu, /* LAMED */
+    0x0000u, /* FINAL MEM */
+    0xFB3Eu, /* MEM */
+    0x0000u, /* FINAL NUN */
+    0xFB40u, /* NUN */
+    0xFB41u, /* SAMEKH */
+    0x0000u, /* AYIN */
+    0xFB43u, /* FINAL PE */
+    0xFB44u, /* PE */
+    0x0000u, /* FINAL TSADI */
+    0xFB46u, /* TSADI */
+    0xFB47u, /* QOF */
+    0xFB48u, /* RESH */
+    0xFB49u, /* SHIN */
+    0xFB4Au /* TAV */
+  };
+
+  bool found = (bool) c->unicode->compose (a, b, ab);
+
+  if (!found && !c->plan->has_mark)
+  {
+      /* Special-case Hebrew presentation forms that are excluded from
+       * standard normalization, but wanted for old fonts. */
+      switch (b) {
+      case 0x05B4u: /* HIRIQ */
+          if (a == 0x05D9u) { /* YOD */
+              *ab = 0xFB1Du;
+              found = true;
+          }
+          break;
+      case 0x05B7u: /* patah */
+          if (a == 0x05F2u) { /* YIDDISH YOD YOD */
+              *ab = 0xFB1Fu;
+              found = true;
+          } else if (a == 0x05D0u) { /* ALEF */
+              *ab = 0xFB2Eu;
+              found = true;
+          }
+          break;
+      case 0x05B8u: /* QAMATS */
+          if (a == 0x05D0u) { /* ALEF */
+              *ab = 0xFB2Fu;
+              found = true;
+          }
+          break;
+      case 0x05B9u: /* HOLAM */
+          if (a == 0x05D5u) { /* VAV */
+              *ab = 0xFB4Bu;
+              found = true;
+          }
+          break;
+      case 0x05BCu: /* DAGESH */
+          if (a >= 0x05D0u && a <= 0x05EAu) {
+              *ab = sDageshForms[a - 0x05D0u];
+              found = (*ab != 0);
+          } else if (a == 0xFB2Au) { /* SHIN WITH SHIN DOT */
+              *ab = 0xFB2Cu;
+              found = true;
+          } else if (a == 0xFB2Bu) { /* SHIN WITH SIN DOT */
+              *ab = 0xFB2Du;
+              found = true;
+          }
+          break;
+      case 0x05BFu: /* RAFE */
+          switch (a) {
+          case 0x05D1u: /* BET */
+              *ab = 0xFB4Cu;
+              found = true;
+              break;
+          case 0x05DBu: /* KAF */
+              *ab = 0xFB4Du;
+              found = true;
+              break;
+          case 0x05E4u: /* PE */
+              *ab = 0xFB4Eu;
+              found = true;
+              break;
+          }
+          break;
+      case 0x05C1u: /* SHIN DOT */
+          if (a == 0x05E9u) { /* SHIN */
+              *ab = 0xFB2Au;
+              found = true;
+          } else if (a == 0xFB49u) { /* SHIN WITH DAGESH */
+              *ab = 0xFB2Cu;
+              found = true;
+          }
+          break;
+      case 0x05C2u: /* SIN DOT */
+          if (a == 0x05E9u) { /* SHIN */
+              *ab = 0xFB2Bu;
+              found = true;
+          } else if (a == 0xFB49u) { /* SHIN WITH DAGESH */
+              *ab = 0xFB2Du;
+              found = true;
+          }
+          break;
+      }
+  }
+
+  return found;
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
+{
+  "hebrew",
+  NULL, /* collect_features */
+  NULL, /* override_features */
+  NULL, /* data_create */
+  NULL, /* data_destroy */
+  NULL, /* preprocess_text */
+  NULL, /* postprocess_glyphs */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+  NULL, /* decompose */
+  compose_hebrew,
+  NULL, /* setup_masks */
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
+  true, /* fallback_position */
+};
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic-machine.hh b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic-machine.hh
new file mode 100644
index 0000000..d3f0bee
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic-machine.hh
@@ -0,0 +1,1564 @@
+
+#line 1 "hb-ot-shape-complex-indic-machine.rl"
+/*
+ * 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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
+#define HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
+
+#include "hb-private.hh"
+
+
+#line 36 "hb-ot-shape-complex-indic-machine.hh"
+static const unsigned char _indic_syllable_machine_trans_keys[] = {
+        8u, 8u, 1u, 16u, 8u, 13u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u,
+        7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u,
+        6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u,
+        4u, 8u, 6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u,
+        4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 8u, 8u, 1u, 16u, 8u, 13u,
+        5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u,
+        7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u,
+        6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u,
+        4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u,
+        4u, 14u, 4u, 14u, 8u, 8u, 1u, 16u, 8u, 13u, 5u, 8u, 5u, 7u, 7u, 7u,
+        5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u,
+        7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u,
+        6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u,
+        4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 8u, 8u, 1u, 16u,
+        8u, 13u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u,
+        5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u,
+        4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u,
+        16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u,
+        4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 5u, 8u, 4u, 14u, 4u, 14u, 5u, 8u,
+        5u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u,
+        5u, 7u, 7u, 7u, 8u, 8u, 1u, 16u, 8u, 13u, 4u, 8u, 6u, 6u, 16u, 16u,
+        4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u,
+        16u, 16u, 8u, 8u, 1u, 18u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u,
+        3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u,
+        3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 5u, 14u, 5u, 14u,
+        5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u,
+        3u, 10u, 5u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
+        3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u,
+        5u, 14u, 3u, 14u, 1u, 16u, 4u, 14u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u,
+        1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u,
+        1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
+        1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
+        3u, 17u, 3u, 17u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u,
+        4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u,
+        4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 5u, 14u, 5u, 14u, 5u, 10u,
+        9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u, 3u, 10u,
+        5u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u,
+        4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
+        3u, 14u, 1u, 16u, 4u, 14u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u,
+        1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
+        1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
+        3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 4u, 14u, 1u, 16u,
+        3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u,
+        3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u,
+        3u, 17u, 3u, 17u, 4u, 17u, 5u, 14u, 5u, 14u, 5u, 10u, 9u, 10u, 9u, 9u,
+        9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u, 3u, 10u, 5u, 10u, 3u, 10u,
+        3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
+        3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 1u, 16u,
+        4u, 14u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
+        3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u,
+        3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u,
+        1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 4u, 14u, 3u, 17u, 4u, 14u,
+        3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u,
+        3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u,
+        3u, 17u, 3u, 17u, 4u, 17u, 5u, 14u, 5u, 14u, 5u, 10u, 9u, 10u, 9u, 9u,
+        9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u, 3u, 10u, 5u, 10u, 3u, 10u,
+        3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
+        3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 1u, 16u,
+        4u, 14u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
+        3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u,
+        3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u,
+        1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 1u, 17u, 3u, 17u,
+        1u, 17u, 4u, 14u, 5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u,
+        5u, 10u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 3u, 17u, 3u, 17u, 1u, 16u,
+        3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u,
+        5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 13u, 3u, 10u, 5u, 10u, 3u, 10u,
+        3u, 13u, 1u, 16u, 3u, 10u, 5u, 10u, 5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u,
+        9u, 10u, 9u, 9u, 5u, 10u, 0
+};
+
+static const char _indic_syllable_machine_key_spans[] = {
+        1, 16, 6, 4, 3, 1, 4, 3,
+        1, 4, 3, 1, 4, 3, 1, 5,
+        1, 1, 5, 1, 1, 5, 1, 1,
+        5, 1, 1, 11, 11, 11, 11, 11,
+        11, 11, 11, 11, 11, 1, 16, 6,
+        4, 3, 1, 4, 3, 1, 4, 3,
+        1, 4, 3, 1, 5, 1, 1, 5,
+        1, 1, 5, 1, 1, 5, 1, 1,
+        11, 11, 11, 11, 11, 11, 11, 11,
+        11, 11, 1, 16, 6, 4, 3, 1,
+        4, 3, 1, 4, 3, 1, 4, 3,
+        1, 5, 1, 1, 5, 1, 1, 5,
+        1, 1, 5, 1, 1, 11, 11, 11,
+        11, 11, 11, 11, 11, 11, 1, 16,
+        6, 4, 3, 1, 4, 3, 1, 4,
+        3, 1, 4, 3, 1, 5, 1, 1,
+        5, 1, 1, 5, 1, 1, 5, 1,
+        1, 11, 11, 11, 11, 11, 11, 11,
+        11, 11, 11, 11, 4, 11, 11, 4,
+        3, 4, 3, 1, 4, 3, 1, 4,
+        3, 1, 1, 16, 6, 5, 1, 1,
+        5, 1, 1, 5, 1, 1, 5, 1,
+        1, 1, 18, 15, 15, 14, 16, 15,
+        15, 14, 16, 15, 15, 14, 16, 15,
+        15, 14, 16, 15, 15, 14, 10, 10,
+        6, 2, 1, 2, 2, 1, 6, 11,
+        8, 6, 8, 11, 12, 12, 11, 10,
+        12, 11, 10, 12, 11, 10, 12, 11,
+        10, 12, 16, 11, 15, 15, 16, 16,
+        16, 16, 16, 15, 15, 16, 16, 16,
+        16, 16, 15, 15, 16, 16, 16, 16,
+        16, 15, 15, 16, 16, 16, 16, 16,
+        15, 15, 15, 15, 14, 16, 15, 15,
+        14, 16, 15, 15, 14, 16, 15, 15,
+        14, 16, 15, 15, 14, 10, 10, 6,
+        2, 1, 2, 2, 1, 6, 11, 8,
+        6, 8, 11, 12, 12, 11, 10, 12,
+        11, 10, 12, 11, 10, 12, 11, 10,
+        12, 16, 11, 15, 15, 16, 16, 16,
+        16, 16, 15, 15, 16, 16, 16, 16,
+        16, 15, 15, 16, 16, 16, 16, 16,
+        15, 15, 16, 16, 16, 16, 11, 16,
+        15, 15, 14, 16, 15, 15, 14, 16,
+        15, 15, 14, 16, 15, 15, 14, 16,
+        15, 15, 14, 10, 10, 6, 2, 1,
+        2, 2, 1, 6, 11, 8, 6, 8,
+        11, 12, 12, 11, 10, 12, 11, 10,
+        12, 11, 10, 12, 11, 10, 12, 16,
+        11, 15, 15, 16, 16, 16, 16, 16,
+        15, 15, 16, 16, 16, 16, 16, 15,
+        15, 16, 16, 16, 16, 16, 15, 15,
+        16, 16, 16, 16, 16, 11, 15, 11,
+        15, 15, 14, 16, 15, 15, 14, 16,
+        15, 15, 14, 16, 15, 15, 14, 16,
+        15, 15, 14, 10, 10, 6, 2, 1,
+        2, 2, 1, 6, 11, 8, 6, 8,
+        11, 12, 12, 11, 10, 12, 11, 10,
+        12, 11, 10, 12, 11, 10, 12, 16,
+        11, 15, 15, 16, 16, 16, 16, 16,
+        15, 15, 16, 16, 16, 16, 16, 15,
+        15, 16, 16, 16, 16, 16, 15, 15,
+        16, 16, 16, 16, 16, 15, 17, 15,
+        17, 11, 6, 2, 1, 2, 2, 1,
+        6, 16, 15, 15, 14, 15, 15, 16,
+        12, 11, 10, 12, 11, 10, 12, 11,
+        10, 12, 11, 10, 11, 8, 6, 8,
+        11, 16, 8, 6, 6, 2, 1, 2,
+        2, 1, 6
+};
+
+static const short _indic_syllable_machine_index_offsets[] = {
+        0, 2, 19, 26, 31, 35, 37, 42,
+        46, 48, 53, 57, 59, 64, 68, 70,
+        76, 78, 80, 86, 88, 90, 96, 98,
+        100, 106, 108, 110, 122, 134, 146, 158,
+        170, 182, 194, 206, 218, 230, 232, 249,
+        256, 261, 265, 267, 272, 276, 278, 283,
+        287, 289, 294, 298, 300, 306, 308, 310,
+        316, 318, 320, 326, 328, 330, 336, 338,
+        340, 352, 364, 376, 388, 400, 412, 424,
+        436, 448, 460, 462, 479, 486, 491, 495,
+        497, 502, 506, 508, 513, 517, 519, 524,
+        528, 530, 536, 538, 540, 546, 548, 550,
+        556, 558, 560, 566, 568, 570, 582, 594,
+        606, 618, 630, 642, 654, 666, 678, 680,
+        697, 704, 709, 713, 715, 720, 724, 726,
+        731, 735, 737, 742, 746, 748, 754, 756,
+        758, 764, 766, 768, 774, 776, 778, 784,
+        786, 788, 800, 812, 824, 836, 848, 860,
+        872, 884, 896, 908, 920, 925, 937, 949,
+        954, 958, 963, 967, 969, 974, 978, 980,
+        985, 989, 991, 993, 1010, 1017, 1023, 1025,
+        1027, 1033, 1035, 1037, 1043, 1045, 1047, 1053,
+        1055, 1057, 1059, 1078, 1094, 1110, 1125, 1142,
+        1158, 1174, 1189, 1206, 1222, 1238, 1253, 1270,
+        1286, 1302, 1317, 1334, 1350, 1366, 1381, 1392,
+        1403, 1410, 1413, 1415, 1418, 1421, 1423, 1430,
+        1442, 1451, 1458, 1467, 1479, 1492, 1505, 1517,
+        1528, 1541, 1553, 1564, 1577, 1589, 1600, 1613,
+        1625, 1636, 1649, 1666, 1678, 1694, 1710, 1727,
+        1744, 1761, 1778, 1795, 1811, 1827, 1844, 1861,
+        1878, 1895, 1912, 1928, 1944, 1961, 1978, 1995,
+        2012, 2029, 2045, 2061, 2078, 2095, 2112, 2129,
+        2146, 2162, 2178, 2194, 2210, 2225, 2242, 2258,
+        2274, 2289, 2306, 2322, 2338, 2353, 2370, 2386,
+        2402, 2417, 2434, 2450, 2466, 2481, 2492, 2503,
+        2510, 2513, 2515, 2518, 2521, 2523, 2530, 2542,
+        2551, 2558, 2567, 2579, 2592, 2605, 2617, 2628,
+        2641, 2653, 2664, 2677, 2689, 2700, 2713, 2725,
+        2736, 2749, 2766, 2778, 2794, 2810, 2827, 2844,
+        2861, 2878, 2895, 2911, 2927, 2944, 2961, 2978,
+        2995, 3012, 3028, 3044, 3061, 3078, 3095, 3112,
+        3129, 3145, 3161, 3178, 3195, 3212, 3229, 3241,
+        3258, 3274, 3290, 3305, 3322, 3338, 3354, 3369,
+        3386, 3402, 3418, 3433, 3450, 3466, 3482, 3497,
+        3514, 3530, 3546, 3561, 3572, 3583, 3590, 3593,
+        3595, 3598, 3601, 3603, 3610, 3622, 3631, 3638,
+        3647, 3659, 3672, 3685, 3697, 3708, 3721, 3733,
+        3744, 3757, 3769, 3780, 3793, 3805, 3816, 3829,
+        3846, 3858, 3874, 3890, 3907, 3924, 3941, 3958,
+        3975, 3991, 4007, 4024, 4041, 4058, 4075, 4092,
+        4108, 4124, 4141, 4158, 4175, 4192, 4209, 4225,
+        4241, 4258, 4275, 4292, 4309, 4326, 4338, 4354,
+        4366, 4382, 4398, 4413, 4430, 4446, 4462, 4477,
+        4494, 4510, 4526, 4541, 4558, 4574, 4590, 4605,
+        4622, 4638, 4654, 4669, 4680, 4691, 4698, 4701,
+        4703, 4706, 4709, 4711, 4718, 4730, 4739, 4746,
+        4755, 4767, 4780, 4793, 4805, 4816, 4829, 4841,
+        4852, 4865, 4877, 4888, 4901, 4913, 4924, 4937,
+        4954, 4966, 4982, 4998, 5015, 5032, 5049, 5066,
+        5083, 5099, 5115, 5132, 5149, 5166, 5183, 5200,
+        5216, 5232, 5249, 5266, 5283, 5300, 5317, 5333,
+        5349, 5366, 5383, 5400, 5417, 5434, 5450, 5468,
+        5484, 5502, 5514, 5521, 5524, 5526, 5529, 5532,
+        5534, 5541, 5558, 5574, 5590, 5605, 5621, 5637,
+        5654, 5667, 5679, 5690, 5703, 5715, 5726, 5739,
+        5751, 5762, 5775, 5787, 5798, 5810, 5819, 5826,
+        5835, 5847, 5864, 5873, 5880, 5887, 5890, 5892,
+        5895, 5898, 5900
+};
+
+static const short _indic_syllable_machine_indicies[] = {
+        1, 0, 2, 3, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 2, 0, 1, 0, 0, 0, 0,
+        4, 0, 5, 5, 6, 1, 0, 7,
+        7, 6, 0, 6, 0, 8, 8, 9,
+        1, 0, 10, 10, 9, 0, 9, 0,
+        11, 11, 12, 1, 0, 13, 13, 12,
+        0, 12, 0, 14, 14, 15, 1, 0,
+        16, 16, 15, 0, 15, 0, 17, 0,
+        0, 0, 1, 0, 18, 0, 19, 0,
+        20, 14, 14, 15, 1, 0, 21, 0,
+        22, 0, 23, 11, 11, 12, 1, 0,
+        24, 0, 25, 0, 26, 8, 8, 9,
+        1, 0, 27, 0, 28, 0, 29, 5,
+        5, 6, 1, 0, 0, 0, 0, 0,
+        29, 0, 29, 5, 5, 6, 1, 0,
+        0, 0, 0, 30, 29, 0, 31, 5,
+        5, 6, 1, 0, 0, 0, 0, 0,
+        31, 0, 31, 5, 5, 6, 1, 0,
+        0, 0, 0, 32, 31, 0, 33, 5,
+        5, 6, 1, 0, 0, 0, 0, 0,
+        33, 0, 33, 5, 5, 6, 1, 0,
+        0, 0, 0, 34, 33, 0, 35, 5,
+        5, 6, 1, 0, 0, 0, 0, 0,
+        35, 0, 35, 5, 5, 6, 1, 0,
+        0, 0, 0, 36, 35, 0, 37, 5,
+        5, 6, 1, 0, 0, 0, 0, 0,
+        37, 0, 37, 5, 5, 6, 1, 0,
+        0, 0, 0, 38, 37, 0, 40, 39,
+        41, 42, 39, 39, 39, 39, 39, 39,
+        39, 39, 39, 39, 39, 39, 39, 41,
+        39, 40, 39, 39, 39, 39, 43, 39,
+        44, 44, 45, 40, 39, 46, 46, 45,
+        39, 45, 39, 47, 47, 48, 40, 39,
+        49, 49, 48, 39, 48, 39, 50, 50,
+        51, 40, 39, 52, 52, 51, 39, 51,
+        39, 53, 53, 54, 40, 39, 55, 55,
+        54, 39, 54, 39, 56, 39, 39, 39,
+        40, 39, 57, 39, 58, 39, 59, 53,
+        53, 54, 40, 39, 60, 39, 61, 39,
+        62, 50, 50, 51, 40, 39, 63, 39,
+        64, 39, 65, 47, 47, 48, 40, 39,
+        66, 39, 67, 39, 68, 44, 44, 45,
+        40, 39, 39, 39, 39, 39, 68, 39,
+        68, 44, 44, 45, 40, 39, 39, 39,
+        39, 69, 68, 39, 70, 44, 44, 45,
+        40, 39, 39, 39, 39, 39, 70, 39,
+        70, 44, 44, 45, 40, 39, 39, 39,
+        39, 71, 70, 39, 72, 44, 44, 45,
+        40, 39, 39, 39, 39, 39, 72, 39,
+        72, 44, 44, 45, 40, 39, 39, 39,
+        39, 73, 72, 39, 74, 44, 44, 45,
+        40, 39, 39, 39, 39, 39, 74, 39,
+        74, 44, 44, 45, 40, 39, 39, 39,
+        39, 75, 74, 39, 76, 44, 44, 45,
+        40, 39, 39, 39, 39, 39, 76, 39,
+        76, 44, 44, 45, 40, 39, 39, 39,
+        39, 77, 76, 39, 79, 78, 80, 81,
+        78, 78, 78, 78, 78, 78, 78, 78,
+        78, 78, 78, 78, 78, 80, 78, 79,
+        78, 78, 78, 78, 82, 78, 83, 83,
+        84, 79, 78, 86, 86, 84, 85, 84,
+        85, 87, 87, 88, 79, 78, 89, 89,
+        88, 78, 88, 78, 90, 90, 91, 79,
+        78, 92, 92, 91, 78, 91, 78, 93,
+        93, 94, 79, 78, 95, 95, 94, 78,
+        94, 78, 96, 78, 78, 78, 79, 78,
+        97, 78, 98, 78, 99, 93, 93, 94,
+        79, 78, 100, 78, 101, 78, 102, 90,
+        90, 91, 79, 78, 103, 78, 104, 78,
+        105, 87, 87, 88, 79, 78, 106, 78,
+        107, 78, 108, 83, 83, 84, 79, 78,
+        78, 78, 78, 78, 108, 78, 108, 83,
+        83, 84, 79, 78, 78, 78, 78, 109,
+        108, 78, 110, 83, 83, 84, 79, 78,
+        78, 78, 78, 78, 110, 78, 110, 83,
+        83, 84, 79, 78, 78, 78, 78, 111,
+        110, 78, 112, 83, 83, 84, 79, 78,
+        78, 78, 78, 78, 112, 78, 112, 83,
+        83, 84, 79, 78, 78, 78, 78, 113,
+        112, 78, 114, 83, 83, 84, 79, 78,
+        78, 78, 78, 78, 114, 78, 114, 83,
+        83, 84, 79, 78, 78, 78, 78, 115,
+        114, 78, 116, 83, 83, 84, 79, 78,
+        78, 78, 78, 78, 116, 78, 118, 117,
+        119, 120, 117, 117, 117, 117, 117, 117,
+        117, 117, 117, 117, 117, 117, 117, 119,
+        117, 118, 117, 117, 117, 117, 121, 117,
+        122, 122, 123, 118, 117, 124, 124, 123,
+        117, 123, 117, 125, 125, 126, 118, 117,
+        127, 127, 126, 117, 126, 117, 128, 128,
+        129, 118, 117, 130, 130, 129, 117, 129,
+        117, 131, 131, 132, 118, 117, 133, 133,
+        132, 117, 132, 117, 134, 117, 117, 117,
+        118, 117, 135, 117, 136, 117, 137, 131,
+        131, 132, 118, 117, 138, 117, 139, 117,
+        140, 128, 128, 129, 118, 117, 141, 117,
+        142, 117, 143, 125, 125, 126, 118, 117,
+        144, 117, 145, 117, 146, 122, 122, 123,
+        118, 117, 117, 117, 117, 117, 146, 117,
+        146, 122, 122, 123, 118, 117, 117, 117,
+        117, 147, 146, 117, 148, 122, 122, 123,
+        118, 117, 117, 117, 117, 117, 148, 117,
+        148, 122, 122, 123, 118, 117, 117, 117,
+        117, 149, 148, 117, 150, 122, 122, 123,
+        118, 117, 117, 117, 117, 117, 150, 117,
+        150, 122, 122, 123, 118, 117, 117, 117,
+        117, 151, 150, 117, 152, 122, 122, 123,
+        118, 117, 117, 117, 117, 117, 152, 117,
+        152, 122, 122, 123, 118, 117, 117, 117,
+        117, 153, 152, 117, 154, 122, 122, 123,
+        118, 117, 117, 117, 117, 117, 154, 117,
+        154, 122, 122, 123, 118, 117, 117, 117,
+        117, 155, 154, 117, 116, 83, 83, 84,
+        79, 78, 78, 78, 78, 156, 116, 78,
+        86, 86, 84, 1, 0, 114, 83, 83,
+        84, 157, 0, 0, 0, 0, 0, 114,
+        0, 114, 83, 83, 84, 157, 0, 0,
+        0, 0, 158, 114, 0, 159, 159, 160,
+        1, 0, 7, 7, 160, 0, 161, 161,
+        162, 157, 0, 163, 163, 162, 0, 162,
+        0, 164, 164, 165, 157, 0, 166, 166,
+        165, 0, 165, 0, 167, 167, 168, 157,
+        0, 169, 169, 168, 0, 168, 0, 157,
+        0, 170, 171, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        170, 0, 157, 0, 0, 0, 0, 172,
+        0, 173, 0, 0, 0, 157, 0, 174,
+        0, 175, 0, 176, 167, 167, 168, 157,
+        0, 177, 0, 178, 0, 179, 164, 164,
+        165, 157, 0, 180, 0, 181, 0, 182,
+        161, 161, 162, 157, 0, 183, 0, 184,
+        0, 186, 185, 188, 189, 190, 191, 192,
+        193, 84, 79, 194, 195, 196, 196, 156,
+        197, 198, 199, 200, 201, 187, 203, 204,
+        205, 206, 6, 1, 207, 208, 202, 202,
+        38, 209, 202, 202, 210, 202, 211, 204,
+        212, 212, 6, 1, 207, 208, 202, 202,
+        202, 209, 202, 202, 210, 202, 204, 212,
+        212, 6, 1, 207, 208, 202, 202, 202,
+        209, 202, 202, 210, 202, 213, 202, 202,
+        202, 19, 214, 202, 1, 207, 208, 202,
+        202, 202, 215, 202, 213, 202, 216, 217,
+        218, 219, 6, 1, 207, 208, 202, 202,
+        36, 220, 202, 202, 210, 202, 221, 217,
+        222, 222, 6, 1, 207, 208, 202, 202,
+        202, 220, 202, 202, 210, 202, 217, 222,
+        222, 6, 1, 207, 208, 202, 202, 202,
+        220, 202, 202, 210, 202, 223, 202, 202,
+        202, 19, 224, 202, 1, 207, 208, 202,
+        202, 202, 215, 202, 223, 202, 225, 226,
+        227, 228, 6, 1, 207, 208, 202, 202,
+        34, 229, 202, 202, 210, 202, 230, 226,
+        231, 231, 6, 1, 207, 208, 202, 202,
+        202, 229, 202, 202, 210, 202, 226, 231,
+        231, 6, 1, 207, 208, 202, 202, 202,
+        229, 202, 202, 210, 202, 232, 202, 202,
+        202, 19, 233, 202, 1, 207, 208, 202,
+        202, 202, 215, 202, 232, 202, 234, 235,
+        236, 237, 6, 1, 207, 208, 202, 202,
+        32, 238, 202, 202, 210, 202, 239, 235,
+        240, 240, 6, 1, 207, 208, 202, 202,
+        202, 238, 202, 202, 210, 202, 235, 240,
+        240, 6, 1, 207, 208, 202, 202, 202,
+        238, 202, 202, 210, 202, 241, 202, 202,
+        202, 19, 242, 202, 1, 207, 208, 202,
+        202, 202, 215, 202, 241, 202, 243, 244,
+        245, 246, 6, 1, 207, 208, 202, 202,
+        30, 247, 202, 202, 210, 202, 248, 244,
+        249, 249, 6, 1, 207, 208, 202, 202,
+        202, 247, 202, 202, 210, 202, 244, 249,
+        249, 6, 1, 207, 208, 202, 202, 202,
+        247, 202, 202, 210, 202, 19, 250, 202,
+        1, 207, 208, 202, 202, 202, 215, 202,
+        251, 251, 202, 1, 207, 208, 202, 202,
+        202, 215, 202, 252, 202, 202, 253, 207,
+        208, 202, 207, 208, 202, 254, 202, 207,
+        255, 202, 207, 256, 202, 207, 202, 252,
+        202, 202, 202, 207, 208, 202, 257, 202,
+        258, 259, 202, 1, 207, 208, 202, 202,
+        4, 202, 3, 202, 251, 251, 202, 1,
+        207, 208, 202, 251, 251, 202, 1, 207,
+        208, 202, 257, 202, 251, 251, 202, 1,
+        207, 208, 202, 257, 202, 258, 251, 202,
+        1, 207, 208, 202, 202, 4, 202, 19,
+        202, 260, 260, 6, 1, 207, 208, 202,
+        202, 202, 215, 202, 261, 28, 262, 263,
+        9, 1, 207, 208, 202, 202, 202, 215,
+        202, 28, 262, 263, 9, 1, 207, 208,
+        202, 202, 202, 215, 202, 262, 262, 9,
+        1, 207, 208, 202, 202, 202, 215, 202,
+        264, 25, 265, 266, 12, 1, 207, 208,
+        202, 202, 202, 215, 202, 25, 265, 266,
+        12, 1, 207, 208, 202, 202, 202, 215,
+        202, 265, 265, 12, 1, 207, 208, 202,
+        202, 202, 215, 202, 267, 22, 268, 269,
+        15, 1, 207, 208, 202, 202, 202, 215,
+        202, 22, 268, 269, 15, 1, 207, 208,
+        202, 202, 202, 215, 202, 268, 268, 15,
+        1, 207, 208, 202, 202, 202, 215, 202,
+        270, 19, 251, 271, 202, 1, 207, 208,
+        202, 202, 202, 215, 202, 19, 251, 271,
+        202, 1, 207, 208, 202, 202, 202, 215,
+        202, 251, 272, 202, 1, 207, 208, 202,
+        202, 202, 215, 202, 19, 202, 251, 251,
+        202, 1, 207, 208, 202, 202, 202, 215,
+        202, 2, 3, 202, 202, 19, 250, 202,
+        1, 207, 208, 202, 202, 202, 215, 202,
+        2, 202, 244, 249, 249, 6, 1, 207,
+        208, 202, 202, 202, 247, 202, 243, 244,
+        249, 249, 6, 1, 207, 208, 202, 202,
+        202, 247, 202, 202, 210, 202, 243, 244,
+        245, 249, 6, 1, 207, 208, 202, 202,
+        30, 247, 202, 202, 210, 202, 241, 202,
+        273, 202, 260, 260, 6, 1, 207, 208,
+        202, 202, 202, 215, 202, 241, 202, 241,
+        202, 202, 202, 251, 251, 202, 1, 207,
+        208, 202, 202, 202, 215, 202, 241, 202,
+        241, 202, 202, 202, 251, 274, 202, 1,
+        207, 208, 202, 202, 202, 215, 202, 241,
+        202, 241, 202, 273, 202, 251, 251, 202,
+        1, 207, 208, 202, 202, 202, 215, 202,
+        241, 202, 241, 3, 202, 202, 19, 242,
+        202, 1, 207, 208, 202, 202, 202, 215,
+        202, 241, 202, 234, 235, 240, 240, 6,
+        1, 207, 208, 202, 202, 202, 238, 202,
+        202, 210, 202, 234, 235, 236, 240, 6,
+        1, 207, 208, 202, 202, 32, 238, 202,
+        202, 210, 202, 232, 202, 275, 202, 260,
+        260, 6, 1, 207, 208, 202, 202, 202,
+        215, 202, 232, 202, 232, 202, 202, 202,
+        251, 251, 202, 1, 207, 208, 202, 202,
+        202, 215, 202, 232, 202, 232, 202, 202,
+        202, 251, 276, 202, 1, 207, 208, 202,
+        202, 202, 215, 202, 232, 202, 232, 202,
+        275, 202, 251, 251, 202, 1, 207, 208,
+        202, 202, 202, 215, 202, 232, 202, 232,
+        3, 202, 202, 19, 233, 202, 1, 207,
+        208, 202, 202, 202, 215, 202, 232, 202,
+        225, 226, 231, 231, 6, 1, 207, 208,
+        202, 202, 202, 229, 202, 202, 210, 202,
+        225, 226, 227, 231, 6, 1, 207, 208,
+        202, 202, 34, 229, 202, 202, 210, 202,
+        223, 202, 277, 202, 260, 260, 6, 1,
+        207, 208, 202, 202, 202, 215, 202, 223,
+        202, 223, 202, 202, 202, 251, 251, 202,
+        1, 207, 208, 202, 202, 202, 215, 202,
+        223, 202, 223, 202, 202, 202, 251, 278,
+        202, 1, 207, 208, 202, 202, 202, 215,
+        202, 223, 202, 223, 202, 277, 202, 251,
+        251, 202, 1, 207, 208, 202, 202, 202,
+        215, 202, 223, 202, 223, 3, 202, 202,
+        19, 224, 202, 1, 207, 208, 202, 202,
+        202, 215, 202, 223, 202, 216, 217, 222,
+        222, 6, 1, 207, 208, 202, 202, 202,
+        220, 202, 202, 210, 202, 216, 217, 218,
+        222, 6, 1, 207, 208, 202, 202, 36,
+        220, 202, 202, 210, 202, 213, 202, 279,
+        202, 260, 260, 6, 1, 207, 208, 202,
+        202, 202, 215, 202, 213, 202, 213, 202,
+        202, 202, 251, 251, 202, 1, 207, 208,
+        202, 202, 202, 215, 202, 213, 202, 213,
+        202, 202, 202, 251, 280, 202, 1, 207,
+        208, 202, 202, 202, 215, 202, 213, 202,
+        213, 202, 279, 202, 251, 251, 202, 1,
+        207, 208, 202, 202, 202, 215, 202, 213,
+        202, 213, 3, 202, 202, 19, 214, 202,
+        1, 207, 208, 202, 202, 202, 215, 202,
+        213, 202, 203, 204, 212, 212, 6, 1,
+        207, 208, 202, 202, 202, 209, 202, 202,
+        210, 202, 203, 204, 205, 212, 6, 1,
+        207, 208, 202, 202, 38, 209, 202, 202,
+        210, 202, 282, 283, 284, 285, 45, 40,
+        286, 287, 281, 281, 77, 288, 281, 281,
+        289, 281, 290, 283, 291, 285, 45, 40,
+        286, 287, 281, 281, 281, 288, 281, 281,
+        289, 281, 283, 291, 285, 45, 40, 286,
+        287, 281, 281, 281, 288, 281, 281, 289,
+        281, 292, 281, 281, 281, 58, 293, 281,
+        40, 286, 287, 281, 281, 281, 294, 281,
+        292, 281, 295, 296, 297, 298, 45, 40,
+        286, 287, 281, 281, 75, 299, 281, 281,
+        289, 281, 300, 296, 301, 301, 45, 40,
+        286, 287, 281, 281, 281, 299, 281, 281,
+        289, 281, 296, 301, 301, 45, 40, 286,
+        287, 281, 281, 281, 299, 281, 281, 289,
+        281, 302, 281, 281, 281, 58, 303, 281,
+        40, 286, 287, 281, 281, 281, 294, 281,
+        302, 281, 304, 305, 306, 307, 45, 40,
+        286, 287, 281, 281, 73, 308, 281, 281,
+        289, 281, 309, 305, 310, 310, 45, 40,
+        286, 287, 281, 281, 281, 308, 281, 281,
+        289, 281, 305, 310, 310, 45, 40, 286,
+        287, 281, 281, 281, 308, 281, 281, 289,
+        281, 311, 281, 281, 281, 58, 312, 281,
+        40, 286, 287, 281, 281, 281, 294, 281,
+        311, 281, 313, 314, 315, 316, 45, 40,
+        286, 287, 281, 281, 71, 317, 281, 281,
+        289, 281, 318, 314, 319, 319, 45, 40,
+        286, 287, 281, 281, 281, 317, 281, 281,
+        289, 281, 314, 319, 319, 45, 40, 286,
+        287, 281, 281, 281, 317, 281, 281, 289,
+        281, 320, 281, 281, 281, 58, 321, 281,
+        40, 286, 287, 281, 281, 281, 294, 281,
+        320, 281, 322, 323, 324, 325, 45, 40,
+        286, 287, 281, 281, 69, 326, 281, 281,
+        289, 281, 327, 323, 328, 328, 45, 40,
+        286, 287, 281, 281, 281, 326, 281, 281,
+        289, 281, 323, 328, 328, 45, 40, 286,
+        287, 281, 281, 281, 326, 281, 281, 289,
+        281, 58, 329, 281, 40, 286, 287, 281,
+        281, 281, 294, 281, 330, 330, 281, 40,
+        286, 287, 281, 281, 281, 294, 281, 331,
+        281, 281, 332, 286, 287, 281, 286, 287,
+        281, 333, 281, 286, 334, 281, 286, 335,
+        281, 286, 281, 331, 281, 281, 281, 286,
+        287, 281, 336, 281, 337, 338, 281, 40,
+        286, 287, 281, 281, 43, 281, 42, 281,
+        330, 330, 281, 40, 286, 287, 281, 330,
+        330, 281, 40, 286, 287, 281, 336, 281,
+        330, 330, 281, 40, 286, 287, 281, 336,
+        281, 337, 330, 281, 40, 286, 287, 281,
+        281, 43, 281, 58, 281, 339, 339, 45,
+        40, 286, 287, 281, 281, 281, 294, 281,
+        340, 67, 341, 342, 48, 40, 286, 287,
+        281, 281, 281, 294, 281, 67, 341, 342,
+        48, 40, 286, 287, 281, 281, 281, 294,
+        281, 341, 341, 48, 40, 286, 287, 281,
+        281, 281, 294, 281, 343, 64, 344, 345,
+        51, 40, 286, 287, 281, 281, 281, 294,
+        281, 64, 344, 345, 51, 40, 286, 287,
+        281, 281, 281, 294, 281, 344, 344, 51,
+        40, 286, 287, 281, 281, 281, 294, 281,
+        346, 61, 347, 348, 54, 40, 286, 287,
+        281, 281, 281, 294, 281, 61, 347, 348,
+        54, 40, 286, 287, 281, 281, 281, 294,
+        281, 347, 347, 54, 40, 286, 287, 281,
+        281, 281, 294, 281, 349, 58, 330, 350,
+        281, 40, 286, 287, 281, 281, 281, 294,
+        281, 58, 330, 350, 281, 40, 286, 287,
+        281, 281, 281, 294, 281, 330, 351, 281,
+        40, 286, 287, 281, 281, 281, 294, 281,
+        58, 281, 330, 330, 281, 40, 286, 287,
+        281, 281, 281, 294, 281, 41, 42, 281,
+        281, 58, 329, 281, 40, 286, 287, 281,
+        281, 281, 294, 281, 41, 281, 323, 328,
+        328, 45, 40, 286, 287, 281, 281, 281,
+        326, 281, 322, 323, 328, 328, 45, 40,
+        286, 287, 281, 281, 281, 326, 281, 281,
+        289, 281, 322, 323, 324, 328, 45, 40,
+        286, 287, 281, 281, 69, 326, 281, 281,
+        289, 281, 320, 281, 352, 281, 339, 339,
+        45, 40, 286, 287, 281, 281, 281, 294,
+        281, 320, 281, 320, 281, 281, 281, 330,
+        330, 281, 40, 286, 287, 281, 281, 281,
+        294, 281, 320, 281, 320, 281, 281, 281,
+        330, 353, 281, 40, 286, 287, 281, 281,
+        281, 294, 281, 320, 281, 320, 281, 352,
+        281, 330, 330, 281, 40, 286, 287, 281,
+        281, 281, 294, 281, 320, 281, 320, 42,
+        281, 281, 58, 321, 281, 40, 286, 287,
+        281, 281, 281, 294, 281, 320, 281, 313,
+        314, 319, 319, 45, 40, 286, 287, 281,
+        281, 281, 317, 281, 281, 289, 281, 313,
+        314, 315, 319, 45, 40, 286, 287, 281,
+        281, 71, 317, 281, 281, 289, 281, 311,
+        281, 354, 281, 339, 339, 45, 40, 286,
+        287, 281, 281, 281, 294, 281, 311, 281,
+        311, 281, 281, 281, 330, 330, 281, 40,
+        286, 287, 281, 281, 281, 294, 281, 311,
+        281, 311, 281, 281, 281, 330, 355, 281,
+        40, 286, 287, 281, 281, 281, 294, 281,
+        311, 281, 311, 281, 354, 281, 330, 330,
+        281, 40, 286, 287, 281, 281, 281, 294,
+        281, 311, 281, 311, 42, 281, 281, 58,
+        312, 281, 40, 286, 287, 281, 281, 281,
+        294, 281, 311, 281, 304, 305, 310, 310,
+        45, 40, 286, 287, 281, 281, 281, 308,
+        281, 281, 289, 281, 304, 305, 306, 310,
+        45, 40, 286, 287, 281, 281, 73, 308,
+        281, 281, 289, 281, 302, 281, 356, 281,
+        339, 339, 45, 40, 286, 287, 281, 281,
+        281, 294, 281, 302, 281, 302, 281, 281,
+        281, 330, 330, 281, 40, 286, 287, 281,
+        281, 281, 294, 281, 302, 281, 302, 281,
+        281, 281, 330, 357, 281, 40, 286, 287,
+        281, 281, 281, 294, 281, 302, 281, 302,
+        281, 356, 281, 330, 330, 281, 40, 286,
+        287, 281, 281, 281, 294, 281, 302, 281,
+        302, 42, 281, 281, 58, 303, 281, 40,
+        286, 287, 281, 281, 281, 294, 281, 302,
+        281, 295, 296, 301, 301, 45, 40, 286,
+        287, 281, 281, 281, 299, 281, 281, 289,
+        281, 295, 296, 297, 301, 45, 40, 286,
+        287, 281, 281, 75, 299, 281, 281, 289,
+        281, 292, 281, 358, 281, 339, 339, 45,
+        40, 286, 287, 281, 281, 281, 294, 281,
+        292, 281, 292, 281, 281, 281, 330, 330,
+        281, 40, 286, 287, 281, 281, 281, 294,
+        281, 292, 281, 292, 281, 281, 281, 330,
+        359, 281, 40, 286, 287, 281, 281, 281,
+        294, 281, 292, 281, 292, 281, 358, 281,
+        330, 330, 281, 40, 286, 287, 281, 281,
+        281, 294, 281, 292, 281, 76, 44, 44,
+        45, 40, 281, 281, 281, 281, 281, 76,
+        281, 292, 42, 281, 281, 58, 293, 281,
+        40, 286, 287, 281, 281, 281, 294, 281,
+        292, 281, 282, 283, 291, 285, 45, 40,
+        286, 287, 281, 281, 281, 288, 281, 281,
+        289, 281, 361, 191, 362, 362, 84, 79,
+        194, 195, 360, 360, 360, 197, 360, 360,
+        200, 360, 191, 362, 362, 84, 79, 194,
+        195, 360, 360, 360, 197, 360, 360, 200,
+        360, 363, 360, 360, 360, 98, 364, 360,
+        79, 194, 195, 360, 360, 360, 365, 360,
+        363, 360, 366, 367, 368, 369, 84, 79,
+        194, 195, 360, 360, 115, 370, 360, 360,
+        200, 360, 371, 367, 372, 372, 84, 79,
+        194, 195, 360, 360, 360, 370, 360, 360,
+        200, 360, 367, 372, 372, 84, 79, 194,
+        195, 360, 360, 360, 370, 360, 360, 200,
+        360, 373, 360, 360, 360, 98, 374, 360,
+        79, 194, 195, 360, 360, 360, 365, 360,
+        373, 360, 375, 376, 377, 378, 84, 79,
+        194, 195, 360, 360, 113, 379, 360, 360,
+        200, 360, 380, 376, 381, 381, 84, 79,
+        194, 195, 360, 360, 360, 379, 360, 360,
+        200, 360, 376, 381, 381, 84, 79, 194,
+        195, 360, 360, 360, 379, 360, 360, 200,
+        360, 382, 360, 360, 360, 98, 383, 360,
+        79, 194, 195, 360, 360, 360, 365, 360,
+        382, 360, 384, 385, 386, 387, 84, 79,
+        194, 195, 360, 360, 111, 388, 360, 360,
+        200, 360, 389, 385, 390, 390, 84, 79,
+        194, 195, 360, 360, 360, 388, 360, 360,
+        200, 360, 385, 390, 390, 84, 79, 194,
+        195, 360, 360, 360, 388, 360, 360, 200,
+        360, 391, 360, 360, 360, 98, 392, 360,
+        79, 194, 195, 360, 360, 360, 365, 360,
+        391, 360, 393, 394, 395, 396, 84, 79,
+        194, 195, 360, 360, 109, 397, 360, 360,
+        200, 360, 398, 394, 399, 399, 84, 79,
+        194, 195, 360, 360, 360, 397, 360, 360,
+        200, 360, 394, 399, 399, 84, 79, 194,
+        195, 360, 360, 360, 397, 360, 360, 200,
+        360, 98, 400, 360, 79, 194, 195, 360,
+        360, 360, 365, 360, 401, 401, 360, 79,
+        194, 195, 360, 360, 360, 365, 360, 402,
+        360, 360, 403, 194, 195, 360, 194, 195,
+        360, 404, 360, 194, 405, 360, 194, 406,
+        360, 194, 360, 402, 360, 360, 360, 194,
+        195, 360, 407, 360, 408, 409, 360, 79,
+        194, 195, 360, 360, 82, 360, 81, 360,
+        401, 401, 360, 79, 194, 195, 360, 401,
+        401, 360, 79, 194, 195, 360, 407, 360,
+        401, 401, 360, 79, 194, 195, 360, 407,
+        360, 408, 401, 360, 79, 194, 195, 360,
+        360, 82, 360, 98, 360, 410, 410, 84,
+        79, 194, 195, 360, 360, 360, 365, 360,
+        411, 107, 412, 413, 88, 79, 194, 195,
+        360, 360, 360, 365, 360, 107, 412, 413,
+        88, 79, 194, 195, 360, 360, 360, 365,
+        360, 412, 412, 88, 79, 194, 195, 360,
+        360, 360, 365, 360, 414, 104, 415, 416,
+        91, 79, 194, 195, 360, 360, 360, 365,
+        360, 104, 415, 416, 91, 79, 194, 195,
+        360, 360, 360, 365, 360, 415, 415, 91,
+        79, 194, 195, 360, 360, 360, 365, 360,
+        417, 101, 418, 419, 94, 79, 194, 195,
+        360, 360, 360, 365, 360, 101, 418, 419,
+        94, 79, 194, 195, 360, 360, 360, 365,
+        360, 418, 418, 94, 79, 194, 195, 360,
+        360, 360, 365, 360, 420, 98, 401, 421,
+        360, 79, 194, 195, 360, 360, 360, 365,
+        360, 98, 401, 421, 360, 79, 194, 195,
+        360, 360, 360, 365, 360, 401, 422, 360,
+        79, 194, 195, 360, 360, 360, 365, 360,
+        98, 360, 401, 401, 360, 79, 194, 195,
+        360, 360, 360, 365, 360, 80, 81, 360,
+        360, 98, 400, 360, 79, 194, 195, 360,
+        360, 360, 365, 360, 80, 360, 394, 399,
+        399, 84, 79, 194, 195, 360, 360, 360,
+        397, 360, 393, 394, 399, 399, 84, 79,
+        194, 195, 360, 360, 360, 397, 360, 360,
+        200, 360, 393, 394, 395, 399, 84, 79,
+        194, 195, 360, 360, 109, 397, 360, 360,
+        200, 360, 391, 360, 423, 360, 410, 410,
+        84, 79, 194, 195, 360, 360, 360, 365,
+        360, 391, 360, 391, 360, 360, 360, 401,
+        401, 360, 79, 194, 195, 360, 360, 360,
+        365, 360, 391, 360, 391, 360, 360, 360,
+        401, 424, 360, 79, 194, 195, 360, 360,
+        360, 365, 360, 391, 360, 391, 360, 423,
+        360, 401, 401, 360, 79, 194, 195, 360,
+        360, 360, 365, 360, 391, 360, 391, 81,
+        360, 360, 98, 392, 360, 79, 194, 195,
+        360, 360, 360, 365, 360, 391, 360, 384,
+        385, 390, 390, 84, 79, 194, 195, 360,
+        360, 360, 388, 360, 360, 200, 360, 384,
+        385, 386, 390, 84, 79, 194, 195, 360,
+        360, 111, 388, 360, 360, 200, 360, 382,
+        360, 425, 360, 410, 410, 84, 79, 194,
+        195, 360, 360, 360, 365, 360, 382, 360,
+        382, 360, 360, 360, 401, 401, 360, 79,
+        194, 195, 360, 360, 360, 365, 360, 382,
+        360, 382, 360, 360, 360, 401, 426, 360,
+        79, 194, 195, 360, 360, 360, 365, 360,
+        382, 360, 382, 360, 425, 360, 401, 401,
+        360, 79, 194, 195, 360, 360, 360, 365,
+        360, 382, 360, 382, 81, 360, 360, 98,
+        383, 360, 79, 194, 195, 360, 360, 360,
+        365, 360, 382, 360, 375, 376, 381, 381,
+        84, 79, 194, 195, 360, 360, 360, 379,
+        360, 360, 200, 360, 375, 376, 377, 381,
+        84, 79, 194, 195, 360, 360, 113, 379,
+        360, 360, 200, 360, 373, 360, 427, 360,
+        410, 410, 84, 79, 194, 195, 360, 360,
+        360, 365, 360, 373, 360, 373, 360, 360,
+        360, 401, 401, 360, 79, 194, 195, 360,
+        360, 360, 365, 360, 373, 360, 373, 360,
+        360, 360, 401, 428, 360, 79, 194, 195,
+        360, 360, 360, 365, 360, 373, 360, 373,
+        360, 427, 360, 401, 401, 360, 79, 194,
+        195, 360, 360, 360, 365, 360, 373, 360,
+        373, 81, 360, 360, 98, 374, 360, 79,
+        194, 195, 360, 360, 360, 365, 360, 373,
+        360, 366, 367, 372, 372, 84, 79, 194,
+        195, 360, 360, 360, 370, 360, 360, 200,
+        360, 366, 367, 368, 372, 84, 79, 194,
+        195, 360, 360, 115, 370, 360, 360, 200,
+        360, 363, 360, 429, 360, 410, 410, 84,
+        79, 194, 195, 360, 360, 360, 365, 360,
+        363, 360, 363, 360, 360, 360, 401, 401,
+        360, 79, 194, 195, 360, 360, 360, 365,
+        360, 363, 360, 363, 360, 360, 360, 401,
+        430, 360, 79, 194, 195, 360, 360, 360,
+        365, 360, 363, 360, 363, 360, 429, 360,
+        401, 401, 360, 79, 194, 195, 360, 360,
+        360, 365, 360, 363, 360, 363, 81, 360,
+        360, 98, 364, 360, 79, 194, 195, 360,
+        360, 360, 365, 360, 363, 360, 116, 83,
+        83, 84, 79, 431, 431, 431, 431, 156,
+        116, 431, 190, 191, 362, 362, 84, 79,
+        194, 195, 360, 360, 360, 197, 360, 360,
+        200, 360, 116, 83, 83, 84, 79, 431,
+        431, 431, 431, 431, 116, 431, 433, 434,
+        435, 436, 123, 118, 437, 438, 432, 432,
+        155, 439, 432, 432, 440, 432, 441, 434,
+        436, 436, 123, 118, 437, 438, 432, 432,
+        432, 439, 432, 432, 440, 432, 434, 436,
+        436, 123, 118, 437, 438, 432, 432, 432,
+        439, 432, 432, 440, 432, 442, 432, 432,
+        432, 136, 443, 432, 118, 437, 438, 432,
+        432, 432, 444, 432, 442, 432, 445, 446,
+        447, 448, 123, 118, 437, 438, 432, 432,
+        153, 449, 432, 432, 440, 432, 450, 446,
+        451, 451, 123, 118, 437, 438, 432, 432,
+        432, 449, 432, 432, 440, 432, 446, 451,
+        451, 123, 118, 437, 438, 432, 432, 432,
+        449, 432, 432, 440, 432, 452, 432, 432,
+        432, 136, 453, 432, 118, 437, 438, 432,
+        432, 432, 444, 432, 452, 432, 454, 455,
+        456, 457, 123, 118, 437, 438, 432, 432,
+        151, 458, 432, 432, 440, 432, 459, 455,
+        460, 460, 123, 118, 437, 438, 432, 432,
+        432, 458, 432, 432, 440, 432, 455, 460,
+        460, 123, 118, 437, 438, 432, 432, 432,
+        458, 432, 432, 440, 432, 461, 432, 432,
+        432, 136, 462, 432, 118, 437, 438, 432,
+        432, 432, 444, 432, 461, 432, 463, 464,
+        465, 466, 123, 118, 437, 438, 432, 432,
+        149, 467, 432, 432, 440, 432, 468, 464,
+        469, 469, 123, 118, 437, 438, 432, 432,
+        432, 467, 432, 432, 440, 432, 464, 469,
+        469, 123, 118, 437, 438, 432, 432, 432,
+        467, 432, 432, 440, 432, 470, 432, 432,
+        432, 136, 471, 432, 118, 437, 438, 432,
+        432, 432, 444, 432, 470, 432, 472, 473,
+        474, 475, 123, 118, 437, 438, 432, 432,
+        147, 476, 432, 432, 440, 432, 477, 473,
+        478, 478, 123, 118, 437, 438, 432, 432,
+        432, 476, 432, 432, 440, 432, 473, 478,
+        478, 123, 118, 437, 438, 432, 432, 432,
+        476, 432, 432, 440, 432, 136, 479, 432,
+        118, 437, 438, 432, 432, 432, 444, 432,
+        480, 480, 432, 118, 437, 438, 432, 432,
+        432, 444, 432, 481, 432, 432, 482, 437,
+        438, 432, 437, 438, 432, 483, 432, 437,
+        484, 432, 437, 485, 432, 437, 432, 481,
+        432, 432, 432, 437, 438, 432, 486, 432,
+        487, 488, 432, 118, 437, 438, 432, 432,
+        121, 432, 120, 432, 480, 480, 432, 118,
+        437, 438, 432, 480, 480, 432, 118, 437,
+        438, 432, 486, 432, 480, 480, 432, 118,
+        437, 438, 432, 486, 432, 487, 480, 432,
+        118, 437, 438, 432, 432, 121, 432, 136,
+        432, 489, 489, 123, 118, 437, 438, 432,
+        432, 432, 444, 432, 490, 145, 491, 492,
+        126, 118, 437, 438, 432, 432, 432, 444,
+        432, 145, 491, 492, 126, 118, 437, 438,
+        432, 432, 432, 444, 432, 491, 491, 126,
+        118, 437, 438, 432, 432, 432, 444, 432,
+        493, 142, 494, 495, 129, 118, 437, 438,
+        432, 432, 432, 444, 432, 142, 494, 495,
+        129, 118, 437, 438, 432, 432, 432, 444,
+        432, 494, 494, 129, 118, 437, 438, 432,
+        432, 432, 444, 432, 496, 139, 497, 498,
+        132, 118, 437, 438, 432, 432, 432, 444,
+        432, 139, 497, 498, 132, 118, 437, 438,
+        432, 432, 432, 444, 432, 497, 497, 132,
+        118, 437, 438, 432, 432, 432, 444, 432,
+        499, 136, 480, 500, 432, 118, 437, 438,
+        432, 432, 432, 444, 432, 136, 480, 500,
+        432, 118, 437, 438, 432, 432, 432, 444,
+        432, 480, 501, 432, 118, 437, 438, 432,
+        432, 432, 444, 432, 136, 432, 480, 480,
+        432, 118, 437, 438, 432, 432, 432, 444,
+        432, 119, 120, 432, 432, 136, 479, 432,
+        118, 437, 438, 432, 432, 432, 444, 432,
+        119, 432, 473, 478, 478, 123, 118, 437,
+        438, 432, 432, 432, 476, 432, 472, 473,
+        478, 478, 123, 118, 437, 438, 432, 432,
+        432, 476, 432, 432, 440, 432, 472, 473,
+        474, 478, 123, 118, 437, 438, 432, 432,
+        147, 476, 432, 432, 440, 432, 470, 432,
+        502, 432, 489, 489, 123, 118, 437, 438,
+        432, 432, 432, 444, 432, 470, 432, 470,
+        432, 432, 432, 480, 480, 432, 118, 437,
+        438, 432, 432, 432, 444, 432, 470, 432,
+        470, 432, 432, 432, 480, 503, 432, 118,
+        437, 438, 432, 432, 432, 444, 432, 470,
+        432, 470, 432, 502, 432, 480, 480, 432,
+        118, 437, 438, 432, 432, 432, 444, 432,
+        470, 432, 470, 120, 432, 432, 136, 471,
+        432, 118, 437, 438, 432, 432, 432, 444,
+        432, 470, 432, 463, 464, 469, 469, 123,
+        118, 437, 438, 432, 432, 432, 467, 432,
+        432, 440, 432, 463, 464, 465, 469, 123,
+        118, 437, 438, 432, 432, 149, 467, 432,
+        432, 440, 432, 461, 432, 504, 432, 489,
+        489, 123, 118, 437, 438, 432, 432, 432,
+        444, 432, 461, 432, 461, 432, 432, 432,
+        480, 480, 432, 118, 437, 438, 432, 432,
+        432, 444, 432, 461, 432, 461, 432, 432,
+        432, 480, 505, 432, 118, 437, 438, 432,
+        432, 432, 444, 432, 461, 432, 461, 432,
+        504, 432, 480, 480, 432, 118, 437, 438,
+        432, 432, 432, 444, 432, 461, 432, 461,
+        120, 432, 432, 136, 462, 432, 118, 437,
+        438, 432, 432, 432, 444, 432, 461, 432,
+        454, 455, 460, 460, 123, 118, 437, 438,
+        432, 432, 432, 458, 432, 432, 440, 432,
+        454, 455, 456, 460, 123, 118, 437, 438,
+        432, 432, 151, 458, 432, 432, 440, 432,
+        452, 432, 506, 432, 489, 489, 123, 118,
+        437, 438, 432, 432, 432, 444, 432, 452,
+        432, 452, 432, 432, 432, 480, 480, 432,
+        118, 437, 438, 432, 432, 432, 444, 432,
+        452, 432, 452, 432, 432, 432, 480, 507,
+        432, 118, 437, 438, 432, 432, 432, 444,
+        432, 452, 432, 452, 432, 506, 432, 480,
+        480, 432, 118, 437, 438, 432, 432, 432,
+        444, 432, 452, 432, 452, 120, 432, 432,
+        136, 453, 432, 118, 437, 438, 432, 432,
+        432, 444, 432, 452, 432, 445, 446, 451,
+        451, 123, 118, 437, 438, 432, 432, 432,
+        449, 432, 432, 440, 432, 445, 446, 447,
+        451, 123, 118, 437, 438, 432, 432, 153,
+        449, 432, 432, 440, 432, 442, 432, 508,
+        432, 489, 489, 123, 118, 437, 438, 432,
+        432, 432, 444, 432, 442, 432, 442, 432,
+        432, 432, 480, 480, 432, 118, 437, 438,
+        432, 432, 432, 444, 432, 442, 432, 442,
+        432, 432, 432, 480, 509, 432, 118, 437,
+        438, 432, 432, 432, 444, 432, 442, 432,
+        442, 432, 508, 432, 480, 480, 432, 118,
+        437, 438, 432, 432, 432, 444, 432, 442,
+        432, 442, 120, 432, 432, 136, 443, 432,
+        118, 437, 438, 432, 432, 432, 444, 432,
+        442, 432, 433, 434, 436, 436, 123, 118,
+        437, 438, 432, 432, 432, 439, 432, 432,
+        440, 432, 188, 189, 190, 191, 510, 362,
+        84, 79, 194, 195, 196, 196, 156, 197,
+        360, 188, 200, 360, 203, 511, 205, 206,
+        6, 1, 207, 208, 202, 202, 38, 209,
+        202, 202, 210, 202, 213, 189, 190, 191,
+        512, 513, 84, 157, 514, 515, 202, 196,
+        156, 516, 202, 213, 200, 202, 116, 517,
+        517, 84, 157, 207, 208, 202, 202, 156,
+        518, 202, 519, 202, 202, 520, 514, 515,
+        202, 514, 515, 202, 254, 202, 514, 521,
+        202, 514, 522, 202, 514, 202, 519, 202,
+        202, 202, 514, 515, 202, 523, 3, 360,
+        360, 401, 430, 360, 79, 194, 195, 360,
+        360, 360, 365, 360, 523, 360, 524, 367,
+        525, 526, 84, 157, 514, 515, 202, 202,
+        158, 370, 202, 202, 200, 202, 527, 367,
+        528, 528, 84, 157, 514, 515, 202, 202,
+        202, 370, 202, 202, 200, 202, 367, 528,
+        528, 84, 157, 514, 515, 202, 202, 202,
+        370, 202, 202, 200, 202, 524, 367, 528,
+        528, 84, 157, 514, 515, 202, 202, 202,
+        370, 202, 202, 200, 202, 524, 367, 525,
+        528, 84, 157, 514, 515, 202, 202, 158,
+        370, 202, 202, 200, 202, 213, 202, 279,
+        116, 529, 529, 160, 157, 207, 208, 202,
+        202, 202, 518, 202, 213, 202, 530, 184,
+        531, 532, 162, 157, 514, 515, 202, 202,
+        202, 533, 202, 184, 531, 532, 162, 157,
+        514, 515, 202, 202, 202, 533, 202, 531,
+        531, 162, 157, 514, 515, 202, 202, 202,
+        533, 202, 534, 181, 535, 536, 165, 157,
+        514, 515, 202, 202, 202, 533, 202, 181,
+        535, 536, 165, 157, 514, 515, 202, 202,
+        202, 533, 202, 535, 535, 165, 157, 514,
+        515, 202, 202, 202, 533, 202, 537, 178,
+        538, 539, 168, 157, 514, 515, 202, 202,
+        202, 533, 202, 178, 538, 539, 168, 157,
+        514, 515, 202, 202, 202, 533, 202, 538,
+        538, 168, 157, 514, 515, 202, 202, 202,
+        533, 202, 540, 175, 541, 542, 202, 157,
+        514, 515, 202, 202, 202, 533, 202, 175,
+        541, 542, 202, 157, 514, 515, 202, 202,
+        202, 533, 202, 541, 541, 202, 157, 514,
+        515, 202, 202, 202, 533, 202, 543, 202,
+        544, 545, 202, 157, 514, 515, 202, 202,
+        172, 202, 171, 202, 541, 541, 202, 157,
+        514, 515, 202, 541, 541, 202, 157, 514,
+        515, 202, 543, 202, 541, 541, 202, 157,
+        514, 515, 202, 543, 202, 544, 541, 202,
+        157, 514, 515, 202, 202, 172, 202, 523,
+        171, 360, 360, 98, 364, 360, 79, 194,
+        195, 360, 360, 360, 365, 360, 523, 360,
+        547, 546, 548, 548, 546, 186, 549, 550,
+        546, 548, 548, 546, 186, 549, 550, 546,
+        551, 546, 546, 552, 549, 550, 546, 549,
+        550, 546, 553, 546, 549, 554, 546, 549,
+        555, 546, 549, 546, 551, 546, 546, 546,
+        549, 550, 546, 0
+};
+
+static const short _indic_syllable_machine_trans_targs[] = {
+        178, 200, 207, 209, 210, 4, 213, 5,
+        7, 216, 8, 10, 219, 11, 13, 222,
+        14, 16, 17, 199, 19, 20, 221, 22,
+        23, 218, 25, 26, 215, 224, 228, 232,
+        235, 239, 242, 246, 249, 253, 256, 178,
+        279, 286, 288, 289, 41, 292, 42, 44,
+        295, 45, 47, 298, 48, 50, 301, 51,
+        53, 54, 278, 56, 57, 300, 59, 60,
+        297, 62, 63, 294, 303, 307, 311, 314,
+        318, 321, 325, 328, 332, 336, 178, 357,
+        364, 366, 367, 78, 370, 178, 79, 81,
+        373, 82, 84, 376, 85, 87, 379, 88,
+        90, 91, 356, 93, 94, 378, 96, 97,
+        375, 99, 100, 372, 381, 385, 389, 392,
+        396, 399, 403, 406, 410, 178, 437, 444,
+        446, 447, 114, 450, 115, 117, 453, 118,
+        120, 456, 121, 123, 459, 124, 126, 127,
+        436, 129, 130, 458, 132, 133, 455, 135,
+        136, 452, 461, 465, 469, 472, 476, 479,
+        483, 486, 490, 493, 414, 498, 509, 152,
+        512, 154, 515, 155, 157, 518, 158, 160,
+        521, 161, 524, 526, 527, 166, 167, 523,
+        169, 170, 520, 172, 173, 517, 175, 176,
+        514, 178, 532, 178, 179, 258, 337, 339,
+        413, 415, 359, 360, 416, 412, 494, 495,
+        384, 530, 178, 180, 182, 36, 257, 202,
+        203, 255, 227, 181, 35, 183, 251, 1,
+        184, 186, 34, 250, 248, 185, 33, 187,
+        244, 188, 190, 32, 243, 241, 189, 31,
+        191, 237, 192, 194, 30, 236, 234, 193,
+        29, 195, 230, 196, 198, 28, 229, 226,
+        197, 27, 212, 0, 201, 206, 178, 204,
+        205, 208, 2, 211, 3, 214, 6, 24,
+        217, 9, 21, 220, 12, 18, 223, 15,
+        225, 231, 233, 238, 240, 245, 247, 252,
+        254, 178, 259, 261, 73, 334, 281, 282,
+        335, 306, 260, 72, 262, 330, 38, 263,
+        265, 71, 329, 327, 264, 70, 266, 323,
+        267, 269, 69, 322, 320, 268, 68, 270,
+        316, 271, 273, 67, 315, 313, 272, 66,
+        274, 309, 275, 277, 65, 308, 305, 276,
+        64, 291, 37, 280, 285, 178, 283, 284,
+        287, 39, 290, 40, 293, 43, 61, 296,
+        46, 58, 299, 49, 55, 302, 52, 304,
+        310, 312, 317, 319, 324, 326, 331, 333,
+        178, 338, 109, 340, 408, 75, 341, 343,
+        108, 407, 405, 342, 107, 344, 401, 345,
+        347, 106, 400, 398, 346, 105, 348, 394,
+        349, 351, 104, 393, 391, 350, 103, 352,
+        387, 353, 355, 102, 386, 383, 354, 101,
+        369, 74, 358, 363, 178, 361, 362, 365,
+        76, 368, 77, 371, 80, 98, 374, 83,
+        95, 377, 86, 92, 380, 89, 382, 388,
+        390, 395, 397, 402, 404, 409, 411, 178,
+        178, 417, 419, 146, 145, 439, 440, 492,
+        464, 418, 420, 488, 111, 421, 423, 144,
+        487, 485, 422, 143, 424, 481, 425, 427,
+        142, 480, 478, 426, 141, 428, 474, 429,
+        431, 140, 473, 471, 430, 139, 432, 467,
+        433, 435, 138, 466, 463, 434, 137, 449,
+        110, 438, 443, 178, 441, 442, 445, 112,
+        448, 113, 451, 116, 134, 454, 119, 131,
+        457, 122, 128, 460, 125, 462, 468, 470,
+        475, 477, 482, 484, 489, 491, 147, 496,
+        497, 511, 500, 501, 529, 148, 505, 499,
+        504, 502, 503, 506, 507, 150, 510, 508,
+        149, 151, 513, 153, 174, 163, 516, 156,
+        171, 519, 159, 168, 522, 162, 165, 525,
+        164, 528, 178, 531, 177, 534, 535, 533,
+        538, 178, 536, 537
+};
+
+static const char _indic_syllable_machine_trans_actions[] = {
+        1, 0, 2, 2, 2, 0, 2, 0,
+        0, 2, 0, 0, 2, 0, 0, 2,
+        0, 0, 0, 2, 0, 0, 2, 0,
+        0, 2, 0, 0, 2, 2, 2, 2,
+        2, 2, 2, 2, 2, 2, 2, 3,
+        0, 2, 2, 2, 0, 2, 0, 0,
+        2, 0, 0, 2, 0, 0, 2, 0,
+        0, 0, 2, 0, 0, 2, 0, 0,
+        2, 0, 0, 2, 2, 2, 2, 2,
+        2, 2, 2, 2, 2, 2, 4, 0,
+        2, 2, 2, 0, 2, 5, 0, 0,
+        2, 0, 0, 2, 0, 0, 2, 0,
+        0, 0, 2, 0, 0, 2, 0, 0,
+        2, 0, 0, 2, 2, 6, 2, 6,
+        2, 6, 2, 6, 2, 7, 0, 2,
+        2, 2, 0, 2, 0, 0, 2, 0,
+        0, 2, 0, 0, 2, 0, 0, 0,
+        2, 0, 0, 2, 0, 0, 2, 0,
+        0, 2, 2, 2, 2, 2, 2, 2,
+        2, 2, 2, 2, 6, 0, 8, 0,
+        2, 0, 2, 0, 0, 2, 0, 0,
+        2, 0, 2, 2, 2, 0, 0, 2,
+        0, 0, 2, 0, 0, 2, 0, 0,
+        2, 9, 0, 12, 2, 2, 6, 2,
+        13, 13, 0, 0, 2, 2, 6, 2,
+        6, 2, 14, 2, 2, 0, 2, 0,
+        0, 2, 2, 2, 0, 2, 2, 0,
+        2, 2, 0, 2, 2, 2, 0, 2,
+        2, 2, 2, 0, 2, 2, 2, 0,
+        2, 2, 2, 2, 0, 2, 2, 2,
+        0, 2, 2, 2, 2, 0, 2, 2,
+        2, 0, 2, 0, 0, 0, 15, 0,
+        0, 2, 0, 2, 0, 2, 0, 0,
+        2, 0, 0, 2, 0, 0, 2, 0,
+        2, 2, 2, 2, 2, 2, 2, 2,
+        2, 16, 2, 2, 0, 2, 0, 0,
+        2, 2, 2, 0, 2, 2, 0, 2,
+        2, 0, 2, 2, 2, 0, 2, 2,
+        2, 2, 0, 2, 2, 2, 0, 2,
+        2, 2, 2, 0, 2, 2, 2, 0,
+        2, 2, 2, 2, 0, 2, 2, 2,
+        0, 2, 0, 0, 0, 17, 0, 0,
+        2, 0, 2, 0, 2, 0, 0, 2,
+        0, 0, 2, 0, 0, 2, 0, 2,
+        2, 2, 2, 2, 2, 2, 2, 2,
+        18, 6, 0, 6, 6, 0, 6, 2,
+        0, 6, 2, 6, 0, 6, 6, 6,
+        2, 0, 6, 2, 6, 0, 6, 6,
+        6, 2, 0, 6, 2, 6, 0, 6,
+        6, 6, 2, 0, 6, 2, 6, 0,
+        6, 0, 0, 0, 19, 0, 0, 2,
+        0, 2, 0, 2, 0, 0, 2, 0,
+        0, 2, 0, 0, 2, 0, 2, 2,
+        2, 2, 2, 2, 2, 2, 2, 20,
+        21, 2, 2, 0, 0, 0, 0, 2,
+        2, 2, 2, 2, 0, 2, 2, 0,
+        2, 2, 2, 0, 2, 2, 2, 2,
+        0, 2, 2, 2, 0, 2, 2, 2,
+        2, 0, 2, 2, 2, 0, 2, 2,
+        2, 2, 0, 2, 2, 2, 0, 2,
+        0, 0, 0, 22, 0, 0, 2, 0,
+        2, 0, 2, 0, 0, 2, 0, 0,
+        2, 0, 0, 2, 0, 2, 2, 2,
+        2, 2, 2, 2, 2, 2, 0, 0,
+        8, 2, 0, 0, 2, 0, 2, 0,
+        0, 0, 0, 8, 8, 0, 8, 8,
+        0, 0, 2, 0, 0, 0, 2, 0,
+        0, 2, 0, 0, 2, 0, 0, 2,
+        0, 2, 23, 2, 0, 0, 0, 0,
+        0, 24, 0, 0
+};
+
+static const char _indic_syllable_machine_to_state_actions[] = {
+        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,
+        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,
+        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,
+        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, 10, 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, 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, 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, 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, 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, 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, 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, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0
+};
+
+static const char _indic_syllable_machine_from_state_actions[] = {
+        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,
+        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,
+        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,
+        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, 11, 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, 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, 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, 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, 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, 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, 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, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0
+};
+
+static const short _indic_syllable_machine_eof_trans[] = {
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 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, 40, 40,
+        40, 40, 40, 40, 40, 40, 40, 40,
+        40, 40, 40, 40, 40, 40, 40, 40,
+        40, 40, 40, 40, 40, 40, 40, 40,
+        40, 40, 40, 40, 40, 40, 40, 40,
+        40, 40, 79, 79, 79, 79, 86, 86,
+        79, 79, 79, 79, 79, 79, 79, 79,
+        79, 79, 79, 79, 79, 79, 79, 79,
+        79, 79, 79, 79, 79, 79, 79, 79,
+        79, 79, 79, 79, 79, 79, 118, 118,
+        118, 118, 118, 118, 118, 118, 118, 118,
+        118, 118, 118, 118, 118, 118, 118, 118,
+        118, 118, 118, 118, 118, 118, 118, 118,
+        118, 118, 118, 118, 118, 118, 118, 118,
+        118, 118, 118, 79, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 186, 0, 203, 203, 203, 203, 203,
+        203, 203, 203, 203, 203, 203, 203, 203,
+        203, 203, 203, 203, 203, 203, 203, 203,
+        203, 203, 203, 203, 203, 203, 203, 203,
+        203, 203, 203, 203, 203, 203, 203, 203,
+        203, 203, 203, 203, 203, 203, 203, 203,
+        203, 203, 203, 203, 203, 203, 203, 203,
+        203, 203, 203, 203, 203, 203, 203, 203,
+        203, 203, 203, 203, 203, 203, 203, 203,
+        203, 203, 203, 203, 203, 203, 203, 203,
+        203, 203, 282, 282, 282, 282, 282, 282,
+        282, 282, 282, 282, 282, 282, 282, 282,
+        282, 282, 282, 282, 282, 282, 282, 282,
+        282, 282, 282, 282, 282, 282, 282, 282,
+        282, 282, 282, 282, 282, 282, 282, 282,
+        282, 282, 282, 282, 282, 282, 282, 282,
+        282, 282, 282, 282, 282, 282, 282, 282,
+        282, 282, 282, 282, 282, 282, 282, 282,
+        282, 282, 282, 282, 282, 282, 282, 282,
+        282, 282, 282, 282, 282, 282, 282, 282,
+        282, 361, 361, 361, 361, 361, 361, 361,
+        361, 361, 361, 361, 361, 361, 361, 361,
+        361, 361, 361, 361, 361, 361, 361, 361,
+        361, 361, 361, 361, 361, 361, 361, 361,
+        361, 361, 361, 361, 361, 361, 361, 361,
+        361, 361, 361, 361, 361, 361, 361, 361,
+        361, 361, 361, 361, 361, 361, 361, 361,
+        361, 361, 361, 361, 361, 361, 361, 361,
+        361, 361, 361, 361, 361, 361, 361, 361,
+        361, 361, 361, 361, 361, 432, 361, 432,
+        433, 433, 433, 433, 433, 433, 433, 433,
+        433, 433, 433, 433, 433, 433, 433, 433,
+        433, 433, 433, 433, 433, 433, 433, 433,
+        433, 433, 433, 433, 433, 433, 433, 433,
+        433, 433, 433, 433, 433, 433, 433, 433,
+        433, 433, 433, 433, 433, 433, 433, 433,
+        433, 433, 433, 433, 433, 433, 433, 433,
+        433, 433, 433, 433, 433, 433, 433, 433,
+        433, 433, 433, 433, 433, 433, 433, 433,
+        433, 433, 433, 433, 433, 433, 361, 203,
+        203, 203, 203, 203, 203, 203, 203, 203,
+        203, 361, 203, 203, 203, 203, 203, 203,
+        203, 203, 203, 203, 203, 203, 203, 203,
+        203, 203, 203, 203, 203, 203, 203, 203,
+        203, 361, 547, 547, 547, 547, 547, 547,
+        547, 547, 547
+};
+
+static const int indic_syllable_machine_start = 178;
+static const int indic_syllable_machine_first_final = 178;
+static const int indic_syllable_machine_error = -1;
+
+static const int indic_syllable_machine_en_main = 178;
+
+
+#line 36 "hb-ot-shape-complex-indic-machine.rl"
+
+
+
+#line 96 "hb-ot-shape-complex-indic-machine.rl"
+
+
+#define found_syllable(syllable_type) \
+  HB_STMT_START { \
+    if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
+    for (unsigned int i = last; i < p+1; i++) \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+    last = p+1; \
+    syllable_serial++; \
+    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+  } HB_STMT_END
+
+static void
+find_syllables (hb_buffer_t *buffer)
+{
+  unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
+  int cs;
+  hb_glyph_info_t *info = buffer->info;
+
+#line 1382 "hb-ot-shape-complex-indic-machine.hh"
+        {
+        cs = indic_syllable_machine_start;
+        ts = 0;
+        te = 0;
+        act = 0;
+        }
+
+#line 117 "hb-ot-shape-complex-indic-machine.rl"
+
+
+  p = 0;
+  pe = eof = buffer->len;
+
+  unsigned int last = 0;
+  unsigned int syllable_serial = 1;
+
+#line 1399 "hb-ot-shape-complex-indic-machine.hh"
+        {
+        int _slen;
+        int _trans;
+        const unsigned char *_keys;
+        const short *_inds;
+        if ( p == pe )
+                goto _test_eof;
+_resume:
+        switch ( _indic_syllable_machine_from_state_actions[cs] ) {
+        case 11:
+#line 1 "NONE"
+        {ts = p;}
+        break;
+#line 1413 "hb-ot-shape-complex-indic-machine.hh"
+        }
+
+        _keys = _indic_syllable_machine_trans_keys + (cs<<1);
+        _inds = _indic_syllable_machine_indicies + _indic_syllable_machine_index_offsets[cs];
+
+        _slen = _indic_syllable_machine_key_spans[cs];
+        _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].indic_category()) &&
+                ( info[p].indic_category()) <= _keys[1] ?
+                ( info[p].indic_category()) - _keys[0] : _slen ];
+
+_eof_trans:
+        cs = _indic_syllable_machine_trans_targs[_trans];
+
+        if ( _indic_syllable_machine_trans_actions[_trans] == 0 )
+                goto _again;
+
+        switch ( _indic_syllable_machine_trans_actions[_trans] ) {
+        case 2:
+#line 1 "NONE"
+        {te = p+1;}
+        break;
+        case 15:
+#line 87 "hb-ot-shape-complex-indic-machine.rl"
+        {te = p+1;{ found_syllable (consonant_syllable); }}
+        break;
+        case 17:
+#line 88 "hb-ot-shape-complex-indic-machine.rl"
+        {te = p+1;{ found_syllable (vowel_syllable); }}
+        break;
+        case 22:
+#line 89 "hb-ot-shape-complex-indic-machine.rl"
+        {te = p+1;{ found_syllable (standalone_cluster); }}
+        break;
+        case 24:
+#line 90 "hb-ot-shape-complex-indic-machine.rl"
+        {te = p+1;{ found_syllable (symbol_cluster); }}
+        break;
+        case 19:
+#line 91 "hb-ot-shape-complex-indic-machine.rl"
+        {te = p+1;{ found_syllable (broken_cluster); }}
+        break;
+        case 12:
+#line 92 "hb-ot-shape-complex-indic-machine.rl"
+        {te = p+1;{ found_syllable (non_indic_cluster); }}
+        break;
+        case 14:
+#line 87 "hb-ot-shape-complex-indic-machine.rl"
+        {te = p;p--;{ found_syllable (consonant_syllable); }}
+        break;
+        case 16:
+#line 88 "hb-ot-shape-complex-indic-machine.rl"
+        {te = p;p--;{ found_syllable (vowel_syllable); }}
+        break;
+        case 21:
+#line 89 "hb-ot-shape-complex-indic-machine.rl"
+        {te = p;p--;{ found_syllable (standalone_cluster); }}
+        break;
+        case 23:
+#line 90 "hb-ot-shape-complex-indic-machine.rl"
+        {te = p;p--;{ found_syllable (symbol_cluster); }}
+        break;
+        case 18:
+#line 91 "hb-ot-shape-complex-indic-machine.rl"
+        {te = p;p--;{ found_syllable (broken_cluster); }}
+        break;
+        case 20:
+#line 92 "hb-ot-shape-complex-indic-machine.rl"
+        {te = p;p--;{ found_syllable (non_indic_cluster); }}
+        break;
+        case 1:
+#line 87 "hb-ot-shape-complex-indic-machine.rl"
+        {{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
+        break;
+        case 3:
+#line 88 "hb-ot-shape-complex-indic-machine.rl"
+        {{p = ((te))-1;}{ found_syllable (vowel_syllable); }}
+        break;
+        case 7:
+#line 89 "hb-ot-shape-complex-indic-machine.rl"
+        {{p = ((te))-1;}{ found_syllable (standalone_cluster); }}
+        break;
+        case 9:
+#line 90 "hb-ot-shape-complex-indic-machine.rl"
+        {{p = ((te))-1;}{ found_syllable (symbol_cluster); }}
+        break;
+        case 4:
+#line 91 "hb-ot-shape-complex-indic-machine.rl"
+        {{p = ((te))-1;}{ found_syllable (broken_cluster); }}
+        break;
+        case 5:
+#line 1 "NONE"
+        {       switch( act ) {
+        case 1:
+        {{p = ((te))-1;} found_syllable (consonant_syllable); }
+        break;
+        case 5:
+        {{p = ((te))-1;} found_syllable (broken_cluster); }
+        break;
+        case 6:
+        {{p = ((te))-1;} found_syllable (non_indic_cluster); }
+        break;
+        }
+        }
+        break;
+        case 8:
+#line 1 "NONE"
+        {te = p+1;}
+#line 87 "hb-ot-shape-complex-indic-machine.rl"
+        {act = 1;}
+        break;
+        case 6:
+#line 1 "NONE"
+        {te = p+1;}
+#line 91 "hb-ot-shape-complex-indic-machine.rl"
+        {act = 5;}
+        break;
+        case 13:
+#line 1 "NONE"
+        {te = p+1;}
+#line 92 "hb-ot-shape-complex-indic-machine.rl"
+        {act = 6;}
+        break;
+#line 1536 "hb-ot-shape-complex-indic-machine.hh"
+        }
+
+_again:
+        switch ( _indic_syllable_machine_to_state_actions[cs] ) {
+        case 10:
+#line 1 "NONE"
+        {ts = 0;}
+        break;
+#line 1545 "hb-ot-shape-complex-indic-machine.hh"
+        }
+
+        if ( ++p != pe )
+                goto _resume;
+        _test_eof: {}
+        if ( p == eof )
+        {
+        if ( _indic_syllable_machine_eof_trans[cs] > 0 ) {
+                _trans = _indic_syllable_machine_eof_trans[cs] - 1;
+                goto _eof_trans;
+        }
+        }
+
+        }
+
+#line 126 "hb-ot-shape-complex-indic-machine.rl"
+
+}
+
+#endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic-private.hh b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic-private.hh
new file mode 100644
index 0000000..4fdc2f8
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic-private.hh
@@ -0,0 +1,189 @@
+/*
+ * 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_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH
+#define HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH
+
+#include "hb-private.hh"
+
+
+#include "hb-ot-shape-complex-private.hh"
+#include "hb-ot-shape-private.hh" /* XXX Remove */
+
+
+#define INDIC_TABLE_ELEMENT_TYPE uint16_t
+
+/* Cateories used in the OpenType spec:
+ * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx
+ */
+/* Note: This enum is duplicated in the -machine.rl source file.
+ * Not sure how to avoid duplication. */
+enum indic_category_t {
+  OT_X = 0,
+  OT_C = 1,
+  OT_V = 2,
+  OT_N = 3,
+  OT_H = 4,
+  OT_ZWNJ = 5,
+  OT_ZWJ = 6,
+  OT_M = 7,
+  OT_SM = 8,
+  OT_VD = 9,
+  OT_A = 10,
+  OT_PLACEHOLDER = 11,
+  OT_DOTTEDCIRCLE = 12,
+  OT_RS = 13, /* Register Shifter, used in Khmer OT spec. */
+  OT_Coeng = 14, /* Khmer-style Virama. */
+  OT_Repha = 15, /* Atomically-encoded logical or visual repha. */
+  OT_Ra = 16,
+  OT_CM = 17,  /* Consonant-Medial. */
+  OT_Symbol = 18 /* Avagraha, etc that take marks (SM,A,VD). */
+};
+
+#define MEDIAL_FLAGS (FLAG (OT_CM))
+
+/* Note:
+ *
+ * We treat Vowels and placeholders as if they were consonants.  This is safe because Vowels
+ * cannot happen in a consonant syllable.  The plus side however is, we can call the
+ * consonant syllable logic from the vowel syllable function and get it all right! */
+#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_Ra) | MEDIAL_FLAGS | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE))
+#define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ))
+#define HALANT_OR_COENG_FLAGS (FLAG (OT_H) | FLAG (OT_Coeng))
+
+
+/* Visual positions in a syllable from left to right. */
+enum indic_position_t {
+  POS_START,
+
+  POS_RA_TO_BECOME_REPH,
+  POS_PRE_M,
+  POS_PRE_C,
+
+  POS_BASE_C,
+  POS_AFTER_MAIN,
+
+  POS_ABOVE_C,
+
+  POS_BEFORE_SUB,
+  POS_BELOW_C,
+  POS_AFTER_SUB,
+
+  POS_BEFORE_POST,
+  POS_POST_C,
+  POS_AFTER_POST,
+
+  POS_FINAL_C,
+  POS_SMVD,
+
+  POS_END
+};
+
+/* Categories used in IndicSyllabicCategory.txt from UCD. */
+enum indic_syllabic_category_t {
+  INDIC_SYLLABIC_CATEGORY_OTHER                         = OT_X,
+
+  INDIC_SYLLABIC_CATEGORY_AVAGRAHA                      = OT_Symbol,
+  INDIC_SYLLABIC_CATEGORY_BINDU                         = OT_SM,
+  INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER         = OT_PLACEHOLDER, /* Don't care. */
+  INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK             = OT_A,
+  INDIC_SYLLABIC_CATEGORY_CONSONANT                     = OT_C,
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD                = OT_C,
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL               = OT_CM,
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER         = OT_C,
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER              = OT_M, /* U+17CD only. */
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL              = OT_CM,
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER         = OT_PLACEHOLDER,
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA     = OT_Repha,
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED            = OT_X, /* Don't care. */
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED           = OT_CM,
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA    = OT_N,
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER        = OT_Repha, /* TODO */
+  INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK               = OT_SM,
+  INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER             = OT_Coeng,
+  INDIC_SYLLABIC_CATEGORY_JOINER                        = OT_ZWJ,
+  INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER              = OT_X,
+  INDIC_SYLLABIC_CATEGORY_NON_JOINER                    = OT_ZWNJ,
+  INDIC_SYLLABIC_CATEGORY_NUKTA                         = OT_N,
+  INDIC_SYLLABIC_CATEGORY_NUMBER                        = OT_PLACEHOLDER,
+  INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER                 = OT_PLACEHOLDER, /* Don't care. */
+  INDIC_SYLLABIC_CATEGORY_PURE_KILLER                   = OT_M, /* Is like a vowel matra. */
+  INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER              = OT_RS,
+  INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER             = OT_M, /* Misc Khmer signs. */
+  INDIC_SYLLABIC_CATEGORY_TONE_LETTER                   = OT_X,
+  INDIC_SYLLABIC_CATEGORY_TONE_MARK                     = OT_N,
+  INDIC_SYLLABIC_CATEGORY_VIRAMA                        = OT_H,
+  INDIC_SYLLABIC_CATEGORY_VISARGA                       = OT_SM,
+  INDIC_SYLLABIC_CATEGORY_VOWEL                         = OT_V,
+  INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT               = OT_M,
+  INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT             = OT_V
+};
+
+/* Categories used in IndicSMatraCategory.txt from UCD */
+enum indic_matra_category_t {
+  INDIC_MATRA_CATEGORY_NOT_APPLICABLE                   = POS_END,
+
+  INDIC_MATRA_CATEGORY_LEFT                             = POS_PRE_C,
+  INDIC_MATRA_CATEGORY_TOP                              = POS_ABOVE_C,
+  INDIC_MATRA_CATEGORY_BOTTOM                           = POS_BELOW_C,
+  INDIC_MATRA_CATEGORY_RIGHT                            = POS_POST_C,
+
+  /* These should resolve to the position of the last part of the split sequence. */
+  INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT                 = INDIC_MATRA_CATEGORY_RIGHT,
+  INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT                   = INDIC_MATRA_CATEGORY_RIGHT,
+  INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM                   = INDIC_MATRA_CATEGORY_BOTTOM,
+  INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT         = INDIC_MATRA_CATEGORY_RIGHT,
+  INDIC_MATRA_CATEGORY_TOP_AND_LEFT                     = INDIC_MATRA_CATEGORY_TOP,
+  INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT           = INDIC_MATRA_CATEGORY_RIGHT,
+  INDIC_MATRA_CATEGORY_TOP_AND_RIGHT                    = INDIC_MATRA_CATEGORY_RIGHT,
+
+  INDIC_MATRA_CATEGORY_OVERSTRUCK                       = POS_AFTER_MAIN,
+  INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT                = POS_PRE_M
+};
+
+#define INDIC_COMBINE_CATEGORIES(S,M) \
+  ( \
+    ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
+    ( S | \
+     ( \
+      ( \
+       S == INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL || \
+       S == INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK || \
+       S == INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER || \
+       S == INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA || \
+       S == INDIC_SYLLABIC_CATEGORY_VIRAMA || \
+       S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT || \
+       false \
+       ? M : INDIC_MATRA_CATEGORY_NOT_APPLICABLE \
+      ) << 8 \
+     ) \
+    ) \
+   )
+
+HB_INTERNAL INDIC_TABLE_ELEMENT_TYPE
+hb_indic_get_categories (hb_codepoint_t u);
+
+#endif /* HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic-table.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic-table.cpp
new file mode 100644
index 0000000..b43e347
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic-table.cpp
@@ -0,0 +1,484 @@
+/* == Start of generated table == */
+/*
+ * The following table is generated by running:
+ *
+ *   ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
+ *
+ * on files with these headers:
+ *
+ * # IndicSyllabicCategory-9.0.0.txt
+ * # Date: 2016-05-21, 02:46:00 GMT [RP]
+ * # IndicPositionalCategory-9.0.0.txt
+ * # Date: 2016-02-25, 00:48:00 GMT [RP]
+ * # Blocks-9.0.0.txt
+ * # Date: 2016-02-05, 23:48:00 GMT [KW]
+ */
+
+#include "hb-ot-shape-complex-indic-private.hh"
+
+
+#define ISC_A   INDIC_SYLLABIC_CATEGORY_AVAGRAHA                /*  15 chars; Avagraha */
+#define ISC_Bi  INDIC_SYLLABIC_CATEGORY_BINDU                   /*  67 chars; Bindu */
+#define ISC_BJN INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER   /*  20 chars; Brahmi_Joining_Number */
+#define ISC_Ca  INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK       /*  53 chars; Cantillation_Mark */
+#define ISC_C   INDIC_SYLLABIC_CATEGORY_CONSONANT               /* 1907 chars; Consonant */
+#define ISC_CD  INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD          /*  10 chars; Consonant_Dead */
+#define ISC_CF  INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL         /*  62 chars; Consonant_Final */
+#define ISC_CHL INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER   /*   5 chars; Consonant_Head_Letter */
+#define ISC_CK  INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER        /*   2 chars; Consonant_Killer */
+#define ISC_CM  INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL        /*  22 chars; Consonant_Medial */
+#define ISC_CP  INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER   /*  16 chars; Consonant_Placeholder */
+#define ISC_CPR INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA       /*   1 chars; Consonant_Preceding_Repha */
+#define ISC_CPrf        INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED      /*   2 chars; Consonant_Prefixed */
+#define ISC_CS  INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED     /*  90 chars; Consonant_Subjoined */
+#define ISC_CSR INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA      /*   4 chars; Consonant_Succeeding_Repha */
+#define ISC_CWS INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER  /*   4 chars; Consonant_With_Stacker */
+#define ISC_GM  INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK         /*   2 chars; Gemination_Mark */
+#define ISC_IS  INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER       /*   7 chars; Invisible_Stacker */
+#define ISC_ZWJ INDIC_SYLLABIC_CATEGORY_JOINER                  /*   1 chars; Joiner */
+#define ISC_ML  INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER        /*   1 chars; Modifying_Letter */
+#define ISC_ZWNJ        INDIC_SYLLABIC_CATEGORY_NON_JOINER              /*   1 chars; Non_Joiner */
+#define ISC_N   INDIC_SYLLABIC_CATEGORY_NUKTA                   /*  24 chars; Nukta */
+#define ISC_Nd  INDIC_SYLLABIC_CATEGORY_NUMBER                  /* 459 chars; Number */
+#define ISC_NJ  INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER           /*   1 chars; Number_Joiner */
+#define ISC_x   INDIC_SYLLABIC_CATEGORY_OTHER                   /*   1 chars; Other */
+#define ISC_PK  INDIC_SYLLABIC_CATEGORY_PURE_KILLER             /*  16 chars; Pure_Killer */
+#define ISC_RS  INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER        /*   2 chars; Register_Shifter */
+#define ISC_SM  INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER       /*  22 chars; Syllable_Modifier */
+#define ISC_TL  INDIC_SYLLABIC_CATEGORY_TONE_LETTER             /*   7 chars; Tone_Letter */
+#define ISC_TM  INDIC_SYLLABIC_CATEGORY_TONE_MARK               /*  42 chars; Tone_Mark */
+#define ISC_V   INDIC_SYLLABIC_CATEGORY_VIRAMA                  /*  24 chars; Virama */
+#define ISC_Vs  INDIC_SYLLABIC_CATEGORY_VISARGA                 /*  31 chars; Visarga */
+#define ISC_Vo  INDIC_SYLLABIC_CATEGORY_VOWEL                   /*  30 chars; Vowel */
+#define ISC_M   INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT         /* 602 chars; Vowel_Dependent */
+#define ISC_VI  INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT       /* 431 chars; Vowel_Independent */
+
+#define IMC_B   INDIC_MATRA_CATEGORY_BOTTOM                     /* 300 chars; Bottom */
+#define IMC_BR  INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT           /*   2 chars; Bottom_And_Right */
+#define IMC_L   INDIC_MATRA_CATEGORY_LEFT                       /*  57 chars; Left */
+#define IMC_LR  INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT             /*  21 chars; Left_And_Right */
+#define IMC_x   INDIC_MATRA_CATEGORY_NOT_APPLICABLE             /*   1 chars; Not_Applicable */
+#define IMC_O   INDIC_MATRA_CATEGORY_OVERSTRUCK                 /*  10 chars; Overstruck */
+#define IMC_R   INDIC_MATRA_CATEGORY_RIGHT                      /* 258 chars; Right */
+#define IMC_T   INDIC_MATRA_CATEGORY_TOP                        /* 342 chars; Top */
+#define IMC_TB  INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM             /*  10 chars; Top_And_Bottom */
+#define IMC_TBR INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT   /*   1 chars; Top_And_Bottom_And_Right */
+#define IMC_TL  INDIC_MATRA_CATEGORY_TOP_AND_LEFT               /*   6 chars; Top_And_Left */
+#define IMC_TLR INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT     /*   4 chars; Top_And_Left_And_Right */
+#define IMC_TR  INDIC_MATRA_CATEGORY_TOP_AND_RIGHT              /*  13 chars; Top_And_Right */
+#define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT          /*  19 chars; Visual_Order_Left */
+
+#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)
+
+
+static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
+
+
+#define indic_offset_0x0028u 0
+
+
+  /* Basic Latin */
+
+  /* 0028 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(CP,x),  _(x,x),  _(x,x),
+  /* 0030 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 0038 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+#define indic_offset_0x00b0u 24
+
+
+  /* Latin-1 Supplement */
+
+  /* 00B0 */  _(x,x),  _(x,x), _(SM,x), _(SM,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 00B8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 00C0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 00C8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 00D0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(CP,x),
+
+#define indic_offset_0x0900u 64
+
+
+  /* Devanagari */
+
+  /* 0900 */ _(Bi,T), _(Bi,T), _(Bi,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0908 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0910 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0918 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0920 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0928 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0930 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0938 */  _(C,x),  _(C,x),  _(M,T),  _(M,R),  _(N,B),  _(A,x),  _(M,R),  _(M,L),
+  /* 0940 */  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(M,T),  _(M,T),  _(M,T),
+  /* 0948 */  _(M,T),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(V,B),  _(M,L),  _(M,R),
+  /* 0950 */  _(x,x), _(Ca,T), _(Ca,B),  _(x,T),  _(x,T),  _(M,T),  _(M,B),  _(M,B),
+  /* 0958 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0960 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
+  /* 0968 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 0970 */  _(x,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0978 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+
+  /* Bengali */
+
+  /* 0980 */  _(x,x), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0988 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x),  _(x,x), _(VI,x),
+  /* 0990 */ _(VI,x),  _(x,x),  _(x,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0998 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 09A0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 09A8 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 09B0 */  _(C,x),  _(x,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),
+  /* 09B8 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(A,x),  _(M,R),  _(M,L),
+  /* 09C0 */  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(x,x),  _(x,x),  _(M,L),
+  /* 09C8 */  _(M,L),  _(x,x),  _(x,x), _(M,LR), _(M,LR),  _(V,B), _(CD,x),  _(x,x),
+  /* 09D0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),
+  /* 09D8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),
+  /* 09E0 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
+  /* 09E8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 09F0 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 09F8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+  /* Gurmukhi */
+
+  /* 0A00 */  _(x,x), _(Bi,T), _(Bi,T), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0A08 */ _(VI,x), _(VI,x), _(VI,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(VI,x),
+  /* 0A10 */ _(VI,x),  _(x,x),  _(x,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0A18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0A20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0A28 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0A30 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),
+  /* 0A38 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(x,x),  _(M,R),  _(M,L),
+  /* 0A40 */  _(M,R),  _(M,B),  _(M,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,T),
+  /* 0A48 */  _(M,T),  _(x,x),  _(x,x),  _(M,T),  _(M,T),  _(V,B),  _(x,x),  _(x,x),
+  /* 0A50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0A58 */  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(x,x),
+  /* 0A60 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
+  /* 0A68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 0A70 */ _(Bi,T), _(GM,T), _(CP,x), _(CP,x),  _(x,x), _(CM,B),  _(x,x),  _(x,x),
+  /* 0A78 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+  /* Gujarati */
+
+  /* 0A80 */  _(x,x), _(Bi,T), _(Bi,T), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0A88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x), _(VI,x),
+  /* 0A90 */ _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0A98 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0AA0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0AA8 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0AB0 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0AB8 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(A,x),  _(M,R),  _(M,L),
+  /* 0AC0 */  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(M,T),  _(x,x),  _(M,T),
+  /* 0AC8 */  _(M,T), _(M,TR),  _(x,x),  _(M,R),  _(M,R),  _(V,B),  _(x,x),  _(x,x),
+  /* 0AD0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0AD8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0AE0 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
+  /* 0AE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 0AF0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0AF8 */  _(x,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+  /* Oriya */
+
+  /* 0B00 */  _(x,x), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x),  _(x,x), _(VI,x),
+  /* 0B10 */ _(VI,x),  _(x,x),  _(x,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0B18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0B20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0B28 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0B30 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0B38 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(A,x),  _(M,R),  _(M,T),
+  /* 0B40 */  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(x,x),  _(x,x),  _(M,L),
+  /* 0B48 */ _(M,TL),  _(x,x),  _(x,x), _(M,LR),_(M,TLR),  _(V,B),  _(x,x),  _(x,x),
+  /* 0B50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,T), _(M,TR),
+  /* 0B58 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),
+  /* 0B60 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
+  /* 0B68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 0B70 */  _(x,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0B78 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+  /* Tamil */
+
+  /* 0B80 */  _(x,x),  _(x,x), _(Bi,T), _(ML,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0B88 */ _(VI,x), _(VI,x), _(VI,x),  _(x,x),  _(x,x),  _(x,x), _(VI,x), _(VI,x),
+  /* 0B90 */ _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(x,x),  _(x,x),
+  /* 0B98 */  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),
+  /* 0BA0 */  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0BA8 */  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),
+  /* 0BB0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0BB8 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),  _(M,R),
+  /* 0BC0 */  _(M,T),  _(M,R),  _(M,R),  _(x,x),  _(x,x),  _(x,x),  _(M,L),  _(M,L),
+  /* 0BC8 */  _(M,L),  _(x,x), _(M,LR), _(M,LR), _(M,LR),  _(V,T),  _(x,x),  _(x,x),
+  /* 0BD0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),
+  /* 0BD8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0BE0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
+  /* 0BE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 0BF0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0BF8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+  /* Telugu */
+
+  /* 0C00 */ _(Bi,T), _(Bi,R), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0C08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x),
+  /* 0C10 */ _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0C18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0C20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0C28 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0C30 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0C38 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(A,x),  _(M,T),  _(M,T),
+  /* 0C40 */  _(M,T),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(x,x),  _(M,T),  _(M,T),
+  /* 0C48 */ _(M,TB),  _(x,x),  _(M,T),  _(M,T),  _(M,T),  _(V,T),  _(x,x),  _(x,x),
+  /* 0C50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,T),  _(M,B),  _(x,x),
+  /* 0C58 */  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0C60 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
+  /* 0C68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 0C70 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0C78 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+  /* Kannada */
+
+  /* 0C80 */  _(x,x), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0C88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x),
+  /* 0C90 */ _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0C98 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0CA0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0CA8 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0CB0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0CB8 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(A,x),  _(M,R),  _(M,T),
+  /* 0CC0 */ _(M,TR),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(x,x),  _(M,T), _(M,TR),
+  /* 0CC8 */ _(M,TR),  _(x,x), _(M,TR), _(M,TR),  _(M,T),  _(V,T),  _(x,x),  _(x,x),
+  /* 0CD0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),  _(M,R),  _(x,x),
+  /* 0CD8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(x,x),
+  /* 0CE0 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
+  /* 0CE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 0CF0 */  _(x,x),_(CWS,x),_(CWS,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0CF8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+  /* Malayalam */
+
+  /* 0D00 */  _(x,x), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0D08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x),
+  /* 0D10 */ _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0D18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0D20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0D28 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0D30 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0D38 */  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(A,x),  _(M,R),  _(M,R),
+  /* 0D40 */  _(M,R),  _(M,R),  _(M,R),  _(M,B),  _(M,B),  _(x,x),  _(M,L),  _(M,L),
+  /* 0D48 */  _(M,L),  _(x,x), _(M,LR), _(M,LR), _(M,LR),  _(V,T),_(CPR,x),  _(x,x),
+  /* 0D50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(CD,x), _(CD,x), _(CD,x),  _(M,R),
+  /* 0D58 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(VI,x),
+  /* 0D60 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
+  /* 0D68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 0D70 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0D78 */  _(x,x),  _(x,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x),
+
+  /* Sinhala */
+
+  /* 0D80 */  _(x,x),  _(x,x), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0D88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0D90 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x),
+  /* 0D98 */  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0DA0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0DA8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0DB0 */  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0DB8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(x,x),  _(x,x),
+  /* 0DC0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),
+  /* 0DC8 */  _(x,x),  _(x,x),  _(V,T),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),
+  /* 0DD0 */  _(M,R),  _(M,R),  _(M,T),  _(M,T),  _(M,B),  _(x,x),  _(M,B),  _(x,x),
+  /* 0DD8 */  _(M,R),  _(M,L), _(M,TL),  _(M,L), _(M,LR),_(M,TLR), _(M,LR),  _(M,R),
+  /* 0DE0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
+  /* 0DE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 0DF0 */  _(x,x),  _(x,x),  _(M,R),  _(M,R),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+#define indic_offset_0x1000u 1336
+
+
+  /* Myanmar */
+
+  /* 1000 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 1008 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 1010 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 1018 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 1020 */  _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 1028 */ _(VI,x), _(VI,x), _(VI,x),  _(M,R),  _(M,R),  _(M,T),  _(M,T),  _(M,B),
+  /* 1030 */  _(M,B),  _(M,L),  _(M,T),  _(M,T),  _(M,T),  _(M,T), _(Bi,T), _(TM,B),
+  /* 1038 */ _(Vs,R), _(IS,x), _(PK,T), _(CM,R), _(CM,x), _(CM,B), _(CM,B),  _(C,x),
+  /* 1040 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 1048 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(CP,x),  _(x,x),
+  /* 1050 */  _(C,x),  _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(M,R),  _(M,R),
+  /* 1058 */  _(M,B),  _(M,B),  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(CM,B), _(CM,B),
+  /* 1060 */ _(CM,B),  _(C,x),  _(M,R), _(TM,R), _(TM,R),  _(C,x),  _(C,x),  _(M,R),
+  /* 1068 */  _(M,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R),  _(C,x),  _(C,x),
+  /* 1070 */  _(C,x),  _(M,T),  _(M,T),  _(M,T),  _(M,T),  _(C,x),  _(C,x),  _(C,x),
+  /* 1078 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 1080 */  _(C,x),  _(C,x), _(CM,B),  _(M,R),  _(M,L),  _(M,T),  _(M,T), _(TM,R),
+  /* 1088 */ _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,B),  _(C,x), _(TM,R),
+  /* 1090 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 1098 */ _(Nd,x), _(Nd,x), _(TM,R), _(TM,R),  _(M,R),  _(M,T),  _(x,x),  _(x,x),
+
+#define indic_offset_0x1780u 1496
+
+
+  /* Khmer */
+
+  /* 1780 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 1788 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 1790 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 1798 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 17A0 */  _(C,x),  _(C,x),  _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 17A8 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 17B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x),  _(x,x),  _(M,R),  _(M,T),
+  /* 17B8 */  _(M,T),  _(M,T),  _(M,T),  _(M,B),  _(M,B),  _(M,B), _(M,TL),_(M,TLR),
+  /* 17C0 */ _(M,LR),  _(M,L),  _(M,L),  _(M,L), _(M,LR), _(M,LR), _(Bi,T), _(Vs,R),
+  /* 17C8 */  _(M,R), _(RS,T), _(RS,T), _(SM,T),_(CSR,T), _(CK,T), _(SM,T), _(SM,T),
+  /* 17D0 */ _(SM,T), _(PK,T), _(IS,x), _(SM,T),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 17D8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(A,x), _(SM,T),  _(x,x),  _(x,x),
+  /* 17E0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 17E8 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+#define indic_offset_0x1cd0u 1608
+
+
+  /* Vedic Extensions */
+
+  /* 1CD0 */ _(Ca,T), _(Ca,T), _(Ca,T),  _(x,x), _(Ca,O), _(Ca,B), _(Ca,B), _(Ca,B),
+  /* 1CD8 */ _(Ca,B), _(Ca,B), _(Ca,T), _(Ca,T), _(Ca,B), _(Ca,B), _(Ca,B), _(Ca,B),
+  /* 1CE0 */ _(Ca,T), _(Ca,R),  _(x,O),  _(x,O),  _(x,O),  _(x,O),  _(x,O),  _(x,O),
+  /* 1CE8 */  _(x,O),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,B),  _(x,x),  _(x,x),
+  /* 1CF0 */  _(x,x),  _(x,x), _(Vs,x), _(Vs,x), _(Ca,T),  _(x,x),  _(x,x),  _(x,x),
+  /* 1CF8 */ _(Ca,x), _(Ca,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+#define indic_offset_0x2008u 1656
+
+
+  /* General Punctuation */
+
+  /* 2008 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),_(ZWNJ,x),_(ZWJ,x),  _(x,x),  _(x,x),
+  /* 2010 */ _(CP,x), _(CP,x), _(CP,x), _(CP,x), _(CP,x),  _(x,x),  _(x,x),  _(x,x),
+
+#define indic_offset_0x2070u 1672
+
+
+  /* Superscripts and Subscripts */
+
+  /* 2070 */  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(SM,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 2078 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 2080 */  _(x,x),  _(x,x), _(SM,x), _(SM,x), _(SM,x),  _(x,x),  _(x,x),  _(x,x),
+
+#define indic_offset_0xa8e0u 1696
+
+
+  /* Devanagari Extended */
+
+  /* A8E0 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),
+  /* A8E8 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),
+  /* A8F0 */ _(Ca,T), _(Ca,T),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+#define indic_offset_0xa9e0u 1720
+
+
+  /* Myanmar Extended-B */
+
+  /* A9E0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(M,T),  _(x,x),  _(C,x),
+  /* A9E8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* A9F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* A9F8 */ _(Nd,x), _(Nd,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),
+
+#define indic_offset_0xaa60u 1752
+
+
+  /* Myanmar Extended-A */
+
+  /* AA60 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* AA68 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* AA70 */  _(x,x),  _(C,x),  _(C,x),  _(C,x), _(CP,x), _(CP,x), _(CP,x),  _(x,x),
+  /* AA78 */  _(x,x),  _(x,x),  _(C,x), _(TM,R), _(TM,T), _(TM,R),  _(C,x),  _(C,x),
+
+}; /* Table items: 1784; occupancy: 69% */
+
+INDIC_TABLE_ELEMENT_TYPE
+hb_indic_get_categories (hb_codepoint_t u)
+{
+  switch (u >> 12)
+  {
+    case 0x0u:
+      if (hb_in_range (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
+      if (hb_in_range (u, 0x00B0u, 0x00D7u)) return indic_table[u - 0x00B0u + indic_offset_0x00b0u];
+      if (hb_in_range (u, 0x0900u, 0x0DF7u)) return indic_table[u - 0x0900u + indic_offset_0x0900u];
+      if (unlikely (u == 0x00A0u)) return _(CP,x);
+      break;
+
+    case 0x1u:
+      if (hb_in_range (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u];
+      if (hb_in_range (u, 0x1780u, 0x17EFu)) return indic_table[u - 0x1780u + indic_offset_0x1780u];
+      if (hb_in_range (u, 0x1CD0u, 0x1CFFu)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
+      break;
+
+    case 0x2u:
+      if (hb_in_range (u, 0x2008u, 0x2017u)) return indic_table[u - 0x2008u + indic_offset_0x2008u];
+      if (hb_in_range (u, 0x2070u, 0x2087u)) return indic_table[u - 0x2070u + indic_offset_0x2070u];
+      if (unlikely (u == 0x25CCu)) return _(CP,x);
+      break;
+
+    case 0xAu:
+      if (hb_in_range (u, 0xA8E0u, 0xA8F7u)) return indic_table[u - 0xA8E0u + indic_offset_0xa8e0u];
+      if (hb_in_range (u, 0xA9E0u, 0xA9FFu)) return indic_table[u - 0xA9E0u + indic_offset_0xa9e0u];
+      if (hb_in_range (u, 0xAA60u, 0xAA7Fu)) return indic_table[u - 0xAA60u + indic_offset_0xaa60u];
+      break;
+
+    default:
+      break;
+  }
+  return _(x,x);
+}
+
+#undef _
+
+#undef ISC_A
+#undef ISC_Bi
+#undef ISC_BJN
+#undef ISC_Ca
+#undef ISC_C
+#undef ISC_CD
+#undef ISC_CF
+#undef ISC_CHL
+#undef ISC_CK
+#undef ISC_CM
+#undef ISC_CP
+#undef ISC_CPR
+#undef ISC_CPrf
+#undef ISC_CS
+#undef ISC_CSR
+#undef ISC_CWS
+#undef ISC_GM
+#undef ISC_IS
+#undef ISC_ZWJ
+#undef ISC_ML
+#undef ISC_ZWNJ
+#undef ISC_N
+#undef ISC_Nd
+#undef ISC_NJ
+#undef ISC_x
+#undef ISC_PK
+#undef ISC_RS
+#undef ISC_SM
+#undef ISC_TL
+#undef ISC_TM
+#undef ISC_V
+#undef ISC_Vs
+#undef ISC_Vo
+#undef ISC_M
+#undef ISC_VI
+
+#undef IMC_B
+#undef IMC_BR
+#undef IMC_L
+#undef IMC_LR
+#undef IMC_x
+#undef IMC_O
+#undef IMC_R
+#undef IMC_T
+#undef IMC_TB
+#undef IMC_TBR
+#undef IMC_TL
+#undef IMC_TLR
+#undef IMC_TR
+#undef IMC_VOL
+
+/* == End of generated table == */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic.cpp
new file mode 100644
index 0000000..6486e84
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic.cpp
@@ -0,0 +1,1824 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-shape-complex-indic-private.hh"
+#include "hb-ot-layout-private.hh"
+
+/* buffer var allocations */
+#define indic_category() complex_var_u8_0() /* indic_category_t */
+#define indic_position() complex_var_u8_1() /* indic_position_t */
+
+
+/*
+ * Indic shaper.
+ */
+
+
+#define IN_HALF_BLOCK(u, Base) (((u) & ~0x7Fu) == (Base))
+
+#define IS_DEVA(u) (IN_HALF_BLOCK (u, 0x0900u))
+#define IS_BENG(u) (IN_HALF_BLOCK (u, 0x0980u))
+#define IS_GURU(u) (IN_HALF_BLOCK (u, 0x0A00u))
+#define IS_GUJR(u) (IN_HALF_BLOCK (u, 0x0A80u))
+#define IS_ORYA(u) (IN_HALF_BLOCK (u, 0x0B00u))
+#define IS_TAML(u) (IN_HALF_BLOCK (u, 0x0B80u))
+#define IS_TELU(u) (IN_HALF_BLOCK (u, 0x0C00u))
+#define IS_KNDA(u) (IN_HALF_BLOCK (u, 0x0C80u))
+#define IS_MLYM(u) (IN_HALF_BLOCK (u, 0x0D00u))
+#define IS_SINH(u) (IN_HALF_BLOCK (u, 0x0D80u))
+#define IS_KHMR(u) (IN_HALF_BLOCK (u, 0x1780u))
+
+
+#define MATRA_POS_LEFT(u)       POS_PRE_M
+#define MATRA_POS_RIGHT(u)      ( \
+                                  IS_DEVA(u) ? POS_AFTER_SUB  : \
+                                  IS_BENG(u) ? POS_AFTER_POST : \
+                                  IS_GURU(u) ? POS_AFTER_POST : \
+                                  IS_GUJR(u) ? POS_AFTER_POST : \
+                                  IS_ORYA(u) ? POS_AFTER_POST : \
+                                  IS_TAML(u) ? POS_AFTER_POST : \
+                                  IS_TELU(u) ? (u <= 0x0C42u ? POS_BEFORE_SUB : POS_AFTER_SUB) : \
+                                  IS_KNDA(u) ? (u < 0x0CC3u || u > 0xCD6u ? POS_BEFORE_SUB : POS_AFTER_SUB) : \
+                                  IS_MLYM(u) ? POS_AFTER_POST : \
+                                  IS_SINH(u) ? POS_AFTER_SUB  : \
+                                  IS_KHMR(u) ? POS_AFTER_POST : \
+                                  /*default*/  POS_AFTER_SUB    \
+                                )
+#define MATRA_POS_TOP(u)        ( /* BENG and MLYM don't have top matras. */ \
+                                  IS_DEVA(u) ? POS_AFTER_SUB  : \
+                                  IS_GURU(u) ? POS_AFTER_POST : /* Deviate from spec */ \
+                                  IS_GUJR(u) ? POS_AFTER_SUB  : \
+                                  IS_ORYA(u) ? POS_AFTER_MAIN : \
+                                  IS_TAML(u) ? POS_AFTER_SUB  : \
+                                  IS_TELU(u) ? POS_BEFORE_SUB : \
+                                  IS_KNDA(u) ? POS_BEFORE_SUB : \
+                                  IS_SINH(u) ? POS_AFTER_SUB  : \
+                                  IS_KHMR(u) ? POS_AFTER_POST : \
+                                  /*default*/  POS_AFTER_SUB    \
+                                )
+#define MATRA_POS_BOTTOM(u)     ( \
+                                  IS_DEVA(u) ? POS_AFTER_SUB  : \
+                                  IS_BENG(u) ? POS_AFTER_SUB  : \
+                                  IS_GURU(u) ? POS_AFTER_POST : \
+                                  IS_GUJR(u) ? POS_AFTER_POST : \
+                                  IS_ORYA(u) ? POS_AFTER_SUB  : \
+                                  IS_TAML(u) ? POS_AFTER_POST : \
+                                  IS_TELU(u) ? POS_BEFORE_SUB : \
+                                  IS_KNDA(u) ? POS_BEFORE_SUB : \
+                                  IS_MLYM(u) ? POS_AFTER_POST : \
+                                  IS_SINH(u) ? POS_AFTER_SUB  : \
+                                  IS_KHMR(u) ? POS_AFTER_POST : \
+                                  /*default*/  POS_AFTER_SUB    \
+                                )
+
+static inline indic_position_t
+matra_position (hb_codepoint_t u, indic_position_t side)
+{
+  switch ((int) side)
+  {
+    case POS_PRE_C:     return MATRA_POS_LEFT (u);
+    case POS_POST_C:    return MATRA_POS_RIGHT (u);
+    case POS_ABOVE_C:   return MATRA_POS_TOP (u);
+    case POS_BELOW_C:   return MATRA_POS_BOTTOM (u);
+  };
+  return side;
+}
+
+/* XXX
+ * This is a hack for now.  We should move this data into the main Indic table.
+ * Or completely remove it and just check in the tables.
+ */
+static const hb_codepoint_t ra_chars[] = {
+  0x0930u, /* Devanagari */
+  0x09B0u, /* Bengali */
+  0x09F0u, /* Bengali */
+  0x0A30u, /* Gurmukhi */       /* No Reph */
+  0x0AB0u, /* Gujarati */
+  0x0B30u, /* Oriya */
+  0x0BB0u, /* Tamil */          /* No Reph */
+  0x0C30u, /* Telugu */         /* Reph formed only with ZWJ */
+  0x0CB0u, /* Kannada */
+  0x0D30u, /* Malayalam */      /* No Reph, Logical Repha */
+
+  0x0DBBu, /* Sinhala */                /* Reph formed only with ZWJ */
+
+  0x179Au, /* Khmer */          /* No Reph, Visual Repha */
+};
+
+static inline bool
+is_ra (hb_codepoint_t u)
+{
+  for (unsigned int i = 0; i < ARRAY_LENGTH (ra_chars); i++)
+    if (u == ra_chars[i])
+      return true;
+  return false;
+}
+
+static inline bool
+is_one_of (const hb_glyph_info_t &info, unsigned int flags)
+{
+  /* If it ligated, all bets are off. */
+  if (_hb_glyph_info_ligated (&info)) return false;
+  return !!(FLAG_SAFE (info.indic_category()) & flags);
+}
+
+static inline bool
+is_joiner (const hb_glyph_info_t &info)
+{
+  return is_one_of (info, JOINER_FLAGS);
+}
+
+static inline bool
+is_consonant (const hb_glyph_info_t &info)
+{
+  return is_one_of (info, CONSONANT_FLAGS);
+}
+
+static inline bool
+is_halant_or_coeng (const hb_glyph_info_t &info)
+{
+  return is_one_of (info, HALANT_OR_COENG_FLAGS);
+}
+
+static inline void
+set_indic_properties (hb_glyph_info_t &info)
+{
+  hb_codepoint_t u = info.codepoint;
+  unsigned int type = hb_indic_get_categories (u);
+  indic_category_t cat = (indic_category_t) (type & 0x7Fu);
+  indic_position_t pos = (indic_position_t) (type >> 8);
+
+
+  /*
+   * Re-assign category
+   */
+
+  /* The following act more like the Bindus. */
+  if (unlikely (hb_in_range (u, 0x0953u, 0x0954u)))
+    cat = OT_SM;
+  /* The following act like consonants. */
+  else if (unlikely (hb_in_ranges (u, 0x0A72u, 0x0A73u,
+                                      0x1CF5u, 0x1CF6u)))
+    cat = OT_C;
+  /* TODO: The following should only be allowed after a Visarga.
+   * For now, just treat them like regular tone marks. */
+  else if (unlikely (hb_in_range (u, 0x1CE2u, 0x1CE8u)))
+    cat = OT_A;
+  /* TODO: The following should only be allowed after some of
+   * the nasalization marks, maybe only for U+1CE9..U+1CF1.
+   * For now, just treat them like tone marks. */
+  else if (unlikely (u == 0x1CEDu))
+    cat = OT_A;
+  /* The following take marks in standalone clusters, similar to Avagraha. */
+  else if (unlikely (hb_in_ranges (u, 0xA8F2u, 0xA8F7u,
+                                      0x1CE9u, 0x1CECu,
+                                      0x1CEEu, 0x1CF1u)))
+  {
+    cat = OT_Symbol;
+    ASSERT_STATIC ((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol);
+  }
+  else if (unlikely (u == 0x17C6u)) cat = OT_N; /* Khmer Bindu doesn't like to be repositioned. */
+  else if (unlikely (hb_in_range (u, 0x2010u, 0x2011u)))
+                                    cat = OT_PLACEHOLDER;
+  else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE;
+
+
+  /*
+   * Re-assign position.
+   */
+
+  if ((FLAG_SAFE (cat) & CONSONANT_FLAGS))
+  {
+    pos = POS_BASE_C;
+    if (is_ra (u))
+      cat = OT_Ra;
+  }
+  else if (cat == OT_M)
+  {
+    pos = matra_position (u, pos);
+  }
+  else if ((FLAG_SAFE (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Symbol))))
+  {
+    pos = POS_SMVD;
+  }
+
+  if (unlikely (u == 0x0B01u)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub in the spec. */
+
+
+
+  info.indic_category() = cat;
+  info.indic_position() = pos;
+}
+
+/*
+ * Things above this line should ideally be moved to the Indic table itself.
+ */
+
+
+/*
+ * Indic configurations.  Note that we do not want to keep every single script-specific
+ * behavior in these tables necessarily.  This should mainly be used for per-script
+ * properties that are cheaper keeping here, than in the code.  Ie. if, say, one and
+ * only one script has an exception, that one script can be if'ed directly in the code,
+ * instead of adding a new flag in these structs.
+ */
+
+enum base_position_t {
+  BASE_POS_FIRST,
+  BASE_POS_LAST_SINHALA,
+  BASE_POS_LAST
+};
+enum reph_position_t {
+  REPH_POS_AFTER_MAIN  = POS_AFTER_MAIN,
+  REPH_POS_BEFORE_SUB  = POS_BEFORE_SUB,
+  REPH_POS_AFTER_SUB   = POS_AFTER_SUB,
+  REPH_POS_BEFORE_POST = POS_BEFORE_POST,
+  REPH_POS_AFTER_POST  = POS_AFTER_POST,
+  REPH_POS_DONT_CARE   = POS_RA_TO_BECOME_REPH
+};
+enum reph_mode_t {
+  REPH_MODE_IMPLICIT,  /* Reph formed out of initial Ra,H sequence. */
+  REPH_MODE_EXPLICIT,  /* Reph formed out of initial Ra,H,ZWJ sequence. */
+  REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */
+  REPH_MODE_LOG_REPHA  /* Encoded Repha character, needs reordering. */
+};
+enum blwf_mode_t {
+  BLWF_MODE_PRE_AND_POST, /* Below-forms feature applied to pre-base and post-base. */
+  BLWF_MODE_POST_ONLY     /* Below-forms feature applied to post-base only. */
+};
+struct indic_config_t
+{
+  hb_script_t     script;
+  bool            has_old_spec;
+  hb_codepoint_t  virama;
+  base_position_t base_pos;
+  reph_position_t reph_pos;
+  reph_mode_t     reph_mode;
+  blwf_mode_t     blwf_mode;
+};
+
+static const indic_config_t indic_configs[] =
+{
+  /* Default.  Should be first. */
+  {HB_SCRIPT_INVALID,   false,      0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_DEVANAGARI,true, 0x094Du,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_BENGALI,   true, 0x09CDu,BASE_POS_LAST, REPH_POS_AFTER_SUB,  REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_GURMUKHI,  true, 0x0A4Du,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_GUJARATI,  true, 0x0ACDu,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_ORIYA,     true, 0x0B4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_TAMIL,     true, 0x0BCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_TELUGU,    true, 0x0C4Du,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY},
+  {HB_SCRIPT_KANNADA,   true, 0x0CCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY},
+  {HB_SCRIPT_MALAYALAM, true, 0x0D4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_SINHALA,   false,0x0DCAu,BASE_POS_LAST_SINHALA,
+                                                     REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST},
+  {HB_SCRIPT_KHMER,     false,0x17D2u,BASE_POS_FIRST,REPH_POS_DONT_CARE,  REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST},
+};
+
+
+
+/*
+ * Indic shaper.
+ */
+
+struct feature_list_t {
+  hb_tag_t tag;
+  hb_ot_map_feature_flags_t flags;
+};
+
+static const feature_list_t
+indic_features[] =
+{
+  /*
+   * Basic features.
+   * These features are applied in order, one at a time, after initial_reordering.
+   */
+  {HB_TAG('n','u','k','t'), F_GLOBAL},
+  {HB_TAG('a','k','h','n'), F_GLOBAL},
+  {HB_TAG('r','p','h','f'), F_NONE},
+  {HB_TAG('r','k','r','f'), F_GLOBAL},
+  {HB_TAG('p','r','e','f'), F_NONE},
+  {HB_TAG('b','l','w','f'), F_NONE},
+  {HB_TAG('a','b','v','f'), F_NONE},
+  {HB_TAG('h','a','l','f'), F_NONE},
+  {HB_TAG('p','s','t','f'), F_NONE},
+  {HB_TAG('v','a','t','u'), F_GLOBAL},
+  {HB_TAG('c','j','c','t'), F_GLOBAL},
+  {HB_TAG('c','f','a','r'), F_NONE},
+  /*
+   * Other features.
+   * These features are applied all at once, after final_reordering.
+   * Default Bengali font in Windows for example has intermixed
+   * lookups for init,pres,abvs,blws features.
+   */
+  {HB_TAG('i','n','i','t'), F_NONE},
+  {HB_TAG('p','r','e','s'), F_GLOBAL},
+  {HB_TAG('a','b','v','s'), F_GLOBAL},
+  {HB_TAG('b','l','w','s'), F_GLOBAL},
+  {HB_TAG('p','s','t','s'), F_GLOBAL},
+  {HB_TAG('h','a','l','n'), F_GLOBAL},
+  /* Positioning features, though we don't care about the types. */
+  {HB_TAG('d','i','s','t'), F_GLOBAL},
+  {HB_TAG('a','b','v','m'), F_GLOBAL},
+  {HB_TAG('b','l','w','m'), F_GLOBAL},
+};
+
+/*
+ * Must be in the same order as the indic_features array.
+ */
+enum {
+  _NUKT,
+  _AKHN,
+  RPHF,
+  _RKRF,
+  PREF,
+  BLWF,
+  ABVF,
+  HALF,
+  PSTF,
+  _VATU,
+  _CJCT,
+  CFAR,
+
+  INIT,
+  _PRES,
+  _ABVS,
+  _BLWS,
+  _PSTS,
+  _HALN,
+  _DIST,
+  _ABVM,
+  _BLWM,
+
+  INDIC_NUM_FEATURES,
+  INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */
+};
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan,
+                 hb_font_t *font,
+                 hb_buffer_t *buffer);
+static void
+initial_reordering (const hb_ot_shape_plan_t *plan,
+                    hb_font_t *font,
+                    hb_buffer_t *buffer);
+static void
+final_reordering (const hb_ot_shape_plan_t *plan,
+                  hb_font_t *font,
+                  hb_buffer_t *buffer);
+static void
+clear_syllables (const hb_ot_shape_plan_t *plan,
+                 hb_font_t *font,
+                 hb_buffer_t *buffer);
+
+static void
+collect_features_indic (hb_ot_shape_planner_t *plan)
+{
+  hb_ot_map_builder_t *map = &plan->map;
+
+  /* Do this before any lookups have been applied. */
+  map->add_gsub_pause (setup_syllables);
+
+  map->add_global_bool_feature (HB_TAG('l','o','c','l'));
+  /* The Indic specs do not require ccmp, but we apply it here since if
+   * there is a use of it, it's typically at the beginning. */
+  map->add_global_bool_feature (HB_TAG('c','c','m','p'));
+
+
+  unsigned int i = 0;
+  map->add_gsub_pause (initial_reordering);
+  for (; i < INDIC_BASIC_FEATURES; i++) {
+    map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ);
+    map->add_gsub_pause (NULL);
+  }
+  map->add_gsub_pause (final_reordering);
+  for (; i < INDIC_NUM_FEATURES; i++) {
+    map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ);
+  }
+
+  map->add_global_bool_feature (HB_TAG('c','a','l','t'));
+  map->add_global_bool_feature (HB_TAG('c','l','i','g'));
+
+  map->add_gsub_pause (clear_syllables);
+}
+
+static void
+override_features_indic (hb_ot_shape_planner_t *plan)
+{
+  /* Uniscribe does not apply 'kern' in Khmer. */
+  if (hb_options ().uniscribe_bug_compatible)
+  {
+    switch ((hb_tag_t) plan->props.script)
+    {
+      case HB_SCRIPT_KHMER:
+        plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL);
+        break;
+    }
+  }
+
+  plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
+}
+
+
+struct would_substitute_feature_t
+{
+  inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_)
+  {
+    zero_context = zero_context_;
+    map->get_stage_lookups (0/*GSUB*/,
+                            map->get_feature_stage (0/*GSUB*/, feature_tag),
+                            &lookups, &count);
+  }
+
+  inline bool would_substitute (const hb_codepoint_t *glyphs,
+                                unsigned int          glyphs_count,
+                                hb_face_t            *face) const
+  {
+    for (unsigned int i = 0; i < count; i++)
+      if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context))
+        return true;
+    return false;
+  }
+
+  private:
+  const hb_ot_map_t::lookup_map_t *lookups;
+  unsigned int count;
+  bool zero_context;
+};
+
+struct indic_shape_plan_t
+{
+  ASSERT_POD ();
+
+  inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
+  {
+    hb_codepoint_t glyph = virama_glyph;
+    if (unlikely (virama_glyph == (hb_codepoint_t) -1))
+    {
+      if (!config->virama || !font->get_nominal_glyph (config->virama, &glyph))
+        glyph = 0;
+      /* Technically speaking, the spec says we should apply 'locl' to virama too.
+       * Maybe one day... */
+
+      /* Our get_nominal_glyph() function needs a font, so we can't get the virama glyph
+       * during shape planning...  Instead, overwrite it here.  It's safe.  Don't worry! */
+      (const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph;
+    }
+
+    *pglyph = glyph;
+    return glyph != 0;
+  }
+
+  const indic_config_t *config;
+
+  bool is_old_spec;
+  hb_codepoint_t virama_glyph;
+
+  would_substitute_feature_t rphf;
+  would_substitute_feature_t pref;
+  would_substitute_feature_t blwf;
+  would_substitute_feature_t pstf;
+
+  hb_mask_t mask_array[INDIC_NUM_FEATURES];
+};
+
+static void *
+data_create_indic (const hb_ot_shape_plan_t *plan)
+{
+  indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t));
+  if (unlikely (!indic_plan))
+    return NULL;
+
+  indic_plan->config = &indic_configs[0];
+  for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++)
+    if (plan->props.script == indic_configs[i].script) {
+      indic_plan->config = &indic_configs[i];
+      break;
+    }
+
+  indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FFu) != '2');
+  indic_plan->virama_glyph = (hb_codepoint_t) -1;
+
+  /* Use zero-context would_substitute() matching for new-spec of the main
+   * Indic scripts, and scripts with one spec only, but not for old-specs.
+   * The new-spec for all dual-spec scripts says zero-context matching happens.
+   *
+   * However, testing with Malayalam shows that old and new spec both allow
+   * context.  Testing with Bengali new-spec however shows that it doesn't.
+   * So, the heuristic here is the way it is.  It should *only* be changed,
+   * as we discover more cases of what Windows does.  DON'T TOUCH OTHERWISE.
+   */
+  bool zero_context = !indic_plan->is_old_spec && plan->props.script != HB_SCRIPT_MALAYALAM;
+  indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'), zero_context);
+  indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context);
+  indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context);
+  indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'), zero_context);
+
+  for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++)
+    indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ?
+                                 0 : plan->map.get_1_mask (indic_features[i].tag);
+
+  return indic_plan;
+}
+
+static void
+data_destroy_indic (void *data)
+{
+  free (data);
+}
+
+static indic_position_t
+consonant_position_from_face (const indic_shape_plan_t *indic_plan,
+                              const hb_codepoint_t consonant,
+                              const hb_codepoint_t virama,
+                              hb_face_t *face)
+{
+  /* For old-spec, the order of glyphs is Consonant,Virama,
+   * whereas for new-spec, it's Virama,Consonant.  However,
+   * some broken fonts (like Free Sans) simply copied lookups
+   * from old-spec to new-spec without modification.
+   * And oddly enough, Uniscribe seems to respect those lookups.
+   * Eg. in the sequence U+0924,U+094D,U+0930, Uniscribe finds
+   * base at 0.  The font however, only has lookups matching
+   * 930,94D in 'blwf', not the expected 94D,930 (with new-spec
+   * table).  As such, we simply match both sequences.  Seems
+   * to work. */
+  hb_codepoint_t glyphs[3] = {virama, consonant, virama};
+  if (indic_plan->blwf.would_substitute (glyphs  , 2, face) ||
+      indic_plan->blwf.would_substitute (glyphs+1, 2, face))
+    return POS_BELOW_C;
+  if (indic_plan->pstf.would_substitute (glyphs  , 2, face) ||
+      indic_plan->pstf.would_substitute (glyphs+1, 2, face))
+    return POS_POST_C;
+  if (indic_plan->pref.would_substitute (glyphs  , 2, face) ||
+      indic_plan->pref.would_substitute (glyphs+1, 2, face))
+    return POS_POST_C;
+  return POS_BASE_C;
+}
+
+
+enum syllable_type_t {
+  consonant_syllable,
+  vowel_syllable,
+  standalone_cluster,
+  symbol_cluster,
+  broken_cluster,
+  non_indic_cluster,
+};
+
+#include "hb-ot-shape-complex-indic-machine.hh"
+
+
+static void
+setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                   hb_buffer_t              *buffer,
+                   hb_font_t                *font HB_UNUSED)
+{
+  HB_BUFFER_ALLOCATE_VAR (buffer, indic_category);
+  HB_BUFFER_ALLOCATE_VAR (buffer, indic_position);
+
+  /* We cannot setup masks here.  We save information about characters
+   * and setup masks later on in a pause-callback. */
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    set_indic_properties (info[i]);
+}
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                 hb_font_t *font HB_UNUSED,
+                 hb_buffer_t *buffer)
+{
+  find_syllables (buffer);
+}
+
+static int
+compare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
+{
+  int a = pa->indic_position();
+  int b = pb->indic_position();
+
+  return a < b ? -1 : a == b ? 0 : +1;
+}
+
+
+
+static void
+update_consonant_positions (const hb_ot_shape_plan_t *plan,
+                            hb_font_t         *font,
+                            hb_buffer_t       *buffer)
+{
+  const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
+
+  if (indic_plan->config->base_pos != BASE_POS_LAST)
+    return;
+
+  hb_codepoint_t virama;
+  if (indic_plan->get_virama_glyph (font, &virama))
+  {
+    hb_face_t *face = font->face;
+    unsigned int count = buffer->len;
+    hb_glyph_info_t *info = buffer->info;
+    for (unsigned int i = 0; i < count; i++)
+      if (info[i].indic_position() == POS_BASE_C)
+      {
+        hb_codepoint_t consonant = info[i].codepoint;
+        info[i].indic_position() = consonant_position_from_face (indic_plan, consonant, virama, face);
+      }
+  }
+}
+
+
+/* Rules from:
+ * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */
+
+static void
+initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
+                                       hb_face_t *face,
+                                       hb_buffer_t *buffer,
+                                       unsigned int start, unsigned int end)
+{
+  const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
+  hb_glyph_info_t *info = buffer->info;
+
+
+  /* 1. Find base consonant:
+   *
+   * The shaping engine finds the base consonant of the syllable, using the
+   * following algorithm: starting from the end of the syllable, move backwards
+   * until a consonant is found that does not have a below-base or post-base
+   * form (post-base forms have to follow below-base forms), or that is not a
+   * pre-base reordering Ra, or arrive at the first consonant. The consonant
+   * stopped at will be the base.
+   *
+   *   o If the syllable starts with Ra + Halant (in a script that has Reph)
+   *     and has more than one consonant, Ra is excluded from candidates for
+   *     base consonants.
+   */
+
+  unsigned int base = end;
+  bool has_reph = false;
+
+  {
+    /* -> If the syllable starts with Ra + Halant (in a script that has Reph)
+     *    and has more than one consonant, Ra is excluded from candidates for
+     *    base consonants. */
+    unsigned int limit = start;
+    if (indic_plan->config->reph_pos != REPH_POS_DONT_CARE &&
+        indic_plan->mask_array[RPHF] &&
+        start + 3 <= end &&
+        (
+         (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) ||
+         (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ)
+        ))
+    {
+      /* See if it matches the 'rphf' feature. */
+      hb_codepoint_t glyphs[3] = {info[start].codepoint,
+                                  info[start + 1].codepoint,
+                                  indic_plan->config->reph_mode == REPH_MODE_EXPLICIT ?
+                                    info[start + 2].codepoint : 0};
+      if (indic_plan->rphf.would_substitute (glyphs, 2, face) ||
+          (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT &&
+           indic_plan->rphf.would_substitute (glyphs, 3, face)))
+      {
+        limit += 2;
+        while (limit < end && is_joiner (info[limit]))
+          limit++;
+        base = start;
+        has_reph = true;
+      }
+    } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == OT_Repha)
+    {
+        limit += 1;
+        while (limit < end && is_joiner (info[limit]))
+          limit++;
+        base = start;
+        has_reph = true;
+    }
+
+    switch (indic_plan->config->base_pos)
+    {
+      case BASE_POS_LAST:
+      {
+        /* -> starting from the end of the syllable, move backwards */
+        unsigned int i = end;
+        bool seen_below = false;
+        do {
+          i--;
+          /* -> until a consonant is found */
+          if (is_consonant (info[i]))
+          {
+            /* -> that does not have a below-base or post-base form
+             * (post-base forms have to follow below-base forms), */
+            if (info[i].indic_position() != POS_BELOW_C &&
+                (info[i].indic_position() != POS_POST_C || seen_below))
+            {
+              base = i;
+              break;
+            }
+            if (info[i].indic_position() == POS_BELOW_C)
+              seen_below = true;
+
+            /* -> or that is not a pre-base reordering Ra,
+             *
+             * IMPLEMENTATION NOTES:
+             *
+             * Our pre-base reordering Ra's are marked POS_POST_C, so will be skipped
+             * by the logic above already.
+             */
+
+            /* -> or arrive at the first consonant. The consonant stopped at will
+             * be the base. */
+            base = i;
+          }
+          else
+          {
+            /* A ZWJ after a Halant stops the base search, and requests an explicit
+             * half form.
+             * A ZWJ before a Halant, requests a subjoined form instead, and hence
+             * search continues.  This is particularly important for Bengali
+             * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */
+            if (start < i &&
+                info[i].indic_category() == OT_ZWJ &&
+                info[i - 1].indic_category() == OT_H)
+              break;
+          }
+        } while (i > limit);
+      }
+      break;
+
+      case BASE_POS_LAST_SINHALA:
+      {
+        /* Sinhala base positioning is slightly different from main Indic, in that:
+         * 1. Its ZWJ behavior is different,
+         * 2. We don't need to look into the font for consonant positions.
+         */
+
+        if (!has_reph)
+          base = limit;
+
+        /* Find the last base consonant that is not blocked by ZWJ.  If there is
+         * a ZWJ right before a base consonant, that would request a subjoined form. */
+        for (unsigned int i = limit; i < end; i++)
+          if (is_consonant (info[i]))
+          {
+            if (limit < i && info[i - 1].indic_category() == OT_ZWJ)
+              break;
+            else
+              base = i;
+          }
+
+        /* Mark all subsequent consonants as below. */
+        for (unsigned int i = base + 1; i < end; i++)
+          if (is_consonant (info[i]))
+            info[i].indic_position() = POS_BELOW_C;
+      }
+      break;
+
+      case BASE_POS_FIRST:
+      {
+        /* The first consonant is always the base. */
+
+        assert (indic_plan->config->reph_mode == REPH_MODE_VIS_REPHA);
+        assert (!has_reph);
+
+        base = start;
+
+        /* Mark all subsequent consonants as below. */
+        for (unsigned int i = base + 1; i < end; i++)
+          if (is_consonant (info[i]))
+            info[i].indic_position() = POS_BELOW_C;
+      }
+      break;
+    }
+
+    /* -> If the syllable starts with Ra + Halant (in a script that has Reph)
+     *    and has more than one consonant, Ra is excluded from candidates for
+     *    base consonants.
+     *
+     *  Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */
+    if (has_reph && base == start && limit - base <= 2) {
+      /* Have no other consonant, so Reph is not formed and Ra becomes base. */
+      has_reph = false;
+    }
+  }
+
+
+  /* 2. Decompose and reorder Matras:
+   *
+   * Each matra and any syllable modifier sign in the cluster are moved to the
+   * appropriate position relative to the consonant(s) in the cluster. The
+   * shaping engine decomposes two- or three-part matras into their constituent
+   * parts before any repositioning. Matra characters are classified by which
+   * consonant in a conjunct they have affinity for and are reordered to the
+   * following positions:
+   *
+   *   o Before first half form in the syllable
+   *   o After subjoined consonants
+   *   o After post-form consonant
+   *   o After main consonant (for above marks)
+   *
+   * IMPLEMENTATION NOTES:
+   *
+   * The normalize() routine has already decomposed matras for us, so we don't
+   * need to worry about that.
+   */
+
+
+  /* 3.  Reorder marks to canonical order:
+   *
+   * Adjacent nukta and halant or nukta and vedic sign are always repositioned
+   * if necessary, so that the nukta is first.
+   *
+   * IMPLEMENTATION NOTES:
+   *
+   * We don't need to do this: the normalize() routine already did this for us.
+   */
+
+
+  /* Reorder characters */
+
+  for (unsigned int i = start; i < base; i++)
+    info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position());
+
+  if (base < end)
+    info[base].indic_position() = POS_BASE_C;
+
+  /* Mark final consonants.  A final consonant is one appearing after a matra,
+   * like in Khmer. */
+  for (unsigned int i = base + 1; i < end; i++)
+    if (info[i].indic_category() == OT_M) {
+      for (unsigned int j = i + 1; j < end; j++)
+        if (is_consonant (info[j])) {
+          info[j].indic_position() = POS_FINAL_C;
+          break;
+        }
+      break;
+    }
+
+  /* Handle beginning Ra */
+  if (has_reph)
+    info[start].indic_position() = POS_RA_TO_BECOME_REPH;
+
+  /* For old-style Indic script tags, move the first post-base Halant after
+   * last consonant.
+   *
+   * Reports suggest that in some scripts Uniscribe does this only if there
+   * is *not* a Halant after last consonant already (eg. Kannada), while it
+   * does it unconditionally in other scripts (eg. Malayalam).  We don't
+   * currently know about other scripts, so we single out Malayalam for now.
+   *
+   * Kannada test case:
+   * U+0C9A,U+0CCD,U+0C9A,U+0CCD
+   * With some versions of Lohit Kannada.
+   * https://bugs.freedesktop.org/show_bug.cgi?id=59118
+   *
+   * Malayalam test case:
+   * U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D
+   * With lohit-ttf-20121122/Lohit-Malayalam.ttf
+   */
+  if (indic_plan->is_old_spec)
+  {
+    bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM;
+    for (unsigned int i = base + 1; i < end; i++)
+      if (info[i].indic_category() == OT_H)
+      {
+        unsigned int j;
+        for (j = end - 1; j > i; j--)
+          if (is_consonant (info[j]) ||
+              (disallow_double_halants && info[j].indic_category() == OT_H))
+            break;
+        if (info[j].indic_category() != OT_H && j > i) {
+          /* Move Halant to after last consonant. */
+          hb_glyph_info_t t = info[i];
+          memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0]));
+          info[j] = t;
+        }
+        break;
+      }
+  }
+
+  /* Attach misc marks to previous char to move with them. */
+  {
+    indic_position_t last_pos = POS_START;
+    for (unsigned int i = start; i < end; i++)
+    {
+      if ((FLAG_SAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | HALANT_OR_COENG_FLAGS)))
+      {
+        info[i].indic_position() = last_pos;
+        if (unlikely (info[i].indic_category() == OT_H &&
+                      info[i].indic_position() == POS_PRE_M))
+        {
+          /*
+           * Uniscribe doesn't move the Halant with Left Matra.
+           * TEST: U+092B,U+093F,U+094DE
+           * We follow.  This is important for the Sinhala
+           * U+0DDA split matra since it decomposes to U+0DD9,U+0DCA
+           * where U+0DD9 is a left matra and U+0DCA is the virama.
+           * We don't want to move the virama with the left matra.
+           * TEST: U+0D9A,U+0DDA
+           */
+          for (unsigned int j = i; j > start; j--)
+            if (info[j - 1].indic_position() != POS_PRE_M) {
+              info[i].indic_position() = info[j - 1].indic_position();
+              break;
+            }
+        }
+      } else if (info[i].indic_position() != POS_SMVD) {
+        last_pos = (indic_position_t) info[i].indic_position();
+      }
+    }
+  }
+  /* For post-base consonants let them own anything before them
+   * since the last consonant or matra. */
+  {
+    unsigned int last = base;
+    for (unsigned int i = base + 1; i < end; i++)
+      if (is_consonant (info[i]))
+      {
+        for (unsigned int j = last + 1; j < i; j++)
+          if (info[j].indic_position() < POS_SMVD)
+            info[j].indic_position() = info[i].indic_position();
+        last = i;
+      } else if (info[i].indic_category() == OT_M)
+        last = i;
+  }
+
+
+  {
+    /* Use syllable() for sort accounting temporarily. */
+    unsigned int syllable = info[start].syllable();
+    for (unsigned int i = start; i < end; i++)
+      info[i].syllable() = i - start;
+
+    /* Sit tight, rock 'n roll! */
+    hb_stable_sort (info + start, end - start, compare_indic_order);
+    /* Find base again */
+    base = end;
+    for (unsigned int i = start; i < end; i++)
+      if (info[i].indic_position() == POS_BASE_C)
+      {
+        base = i;
+        break;
+      }
+    /* Things are out-of-control for post base positions, they may shuffle
+     * around like crazy.  In old-spec mode, we move halants around, so in
+     * that case merge all clusters after base.  Otherwise, check the sort
+     * order and merge as needed.
+     * For pre-base stuff, we handle cluster issues in final reordering.
+     *
+     * We could use buffer->sort() for this, if there was no special
+     * reordering of pre-base stuff happening later...
+     */
+    if (indic_plan->is_old_spec || end - base > 127)
+      buffer->merge_clusters (base, end);
+    else
+    {
+      /* Note!  syllable() is a one-byte field. */
+      for (unsigned int i = base; i < end; i++)
+        if (info[i].syllable() != 255)
+        {
+          unsigned int max = i;
+          unsigned int j = start + info[i].syllable();
+          while (j != i)
+          {
+            max = MAX (max, j);
+            unsigned int next = start + info[j].syllable();
+            info[j].syllable() = 255; /* So we don't process j later again. */
+            j = next;
+          }
+          if (i != max)
+            buffer->merge_clusters (i, max + 1);
+        }
+    }
+
+    /* Put syllable back in. */
+    for (unsigned int i = start; i < end; i++)
+      info[i].syllable() = syllable;
+  }
+
+  /* Setup masks now */
+
+  {
+    hb_mask_t mask;
+
+    /* Reph */
+    for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++)
+      info[i].mask |= indic_plan->mask_array[RPHF];
+
+    /* Pre-base */
+    mask = indic_plan->mask_array[HALF];
+    if (!indic_plan->is_old_spec &&
+        indic_plan->config->blwf_mode == BLWF_MODE_PRE_AND_POST)
+      mask |= indic_plan->mask_array[BLWF];
+    for (unsigned int i = start; i < base; i++)
+      info[i].mask  |= mask;
+    /* Base */
+    mask = 0;
+    if (base < end)
+      info[base].mask |= mask;
+    /* Post-base */
+    mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF];
+    for (unsigned int i = base + 1; i < end; i++)
+      info[i].mask  |= mask;
+  }
+
+  if (indic_plan->is_old_spec &&
+      buffer->props.script == HB_SCRIPT_DEVANAGARI)
+  {
+    /* Old-spec eye-lash Ra needs special handling.  From the
+     * spec:
+     *
+     * "The feature 'below-base form' is applied to consonants
+     * having below-base forms and following the base consonant.
+     * The exception is vattu, which may appear below half forms
+     * as well as below the base glyph. The feature 'below-base
+     * form' will be applied to all such occurrences of Ra as well."
+     *
+     * Test case: U+0924,U+094D,U+0930,U+094d,U+0915
+     * with Sanskrit 2003 font.
+     *
+     * However, note that Ra,Halant,ZWJ is the correct way to
+     * request eyelash form of Ra, so we wouldbn't inhibit it
+     * in that sequence.
+     *
+     * Test case: U+0924,U+094D,U+0930,U+094d,U+200D,U+0915
+     */
+    for (unsigned int i = start; i + 1 < base; i++)
+      if (info[i  ].indic_category() == OT_Ra &&
+          info[i+1].indic_category() == OT_H  &&
+          (i + 2 == base ||
+           info[i+2].indic_category() != OT_ZWJ))
+      {
+        info[i  ].mask |= indic_plan->mask_array[BLWF];
+        info[i+1].mask |= indic_plan->mask_array[BLWF];
+      }
+  }
+
+  unsigned int pref_len = 2;
+  if (indic_plan->mask_array[PREF] && base + pref_len < end)
+  {
+    /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */
+    for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) {
+      hb_codepoint_t glyphs[2];
+      for (unsigned int j = 0; j < pref_len; j++)
+        glyphs[j] = info[i + j].codepoint;
+      if (indic_plan->pref.would_substitute (glyphs, pref_len, face))
+      {
+        for (unsigned int j = 0; j < pref_len; j++)
+          info[i++].mask |= indic_plan->mask_array[PREF];
+
+        /* Mark the subsequent stuff with 'cfar'.  Used in Khmer.
+         * Read the feature spec.
+         * This allows distinguishing the following cases with MS Khmer fonts:
+         * U+1784,U+17D2,U+179A,U+17D2,U+1782
+         * U+1784,U+17D2,U+1782,U+17D2,U+179A
+         */
+        if (indic_plan->mask_array[CFAR])
+          for (; i < end; i++)
+            info[i].mask |= indic_plan->mask_array[CFAR];
+
+        break;
+      }
+    }
+  }
+
+  /* Apply ZWJ/ZWNJ effects */
+  for (unsigned int i = start + 1; i < end; i++)
+    if (is_joiner (info[i])) {
+      bool non_joiner = info[i].indic_category() == OT_ZWNJ;
+      unsigned int j = i;
+
+      do {
+        j--;
+
+        /* ZWJ/ZWNJ should disable CJCT.  They do that by simply
+         * being there, since we don't skip them for the CJCT
+         * feature (ie. F_MANUAL_ZWJ) */
+
+        /* A ZWNJ disables HALF. */
+        if (non_joiner)
+          info[j].mask &= ~indic_plan->mask_array[HALF];
+
+      } while (j > start && !is_consonant (info[j]));
+    }
+}
+
+static void
+initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
+                                       hb_face_t *face,
+                                       hb_buffer_t *buffer,
+                                       unsigned int start, unsigned int end)
+{
+  /* We treat placeholder/dotted-circle as if they are consonants, so we
+   * should just chain.  Only if not in compatibility mode that is... */
+
+  if (hb_options ().uniscribe_bug_compatible)
+  {
+    /* For dotted-circle, this is what Uniscribe does:
+     * If dotted-circle is the last glyph, it just does nothing.
+     * Ie. It doesn't form Reph. */
+    if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE)
+      return;
+  }
+
+  initial_reordering_consonant_syllable (plan, face, buffer, start, end);
+}
+
+static void
+initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
+                             hb_face_t *face,
+                             hb_buffer_t *buffer,
+                             unsigned int start, unsigned int end)
+{
+  syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+  switch (syllable_type)
+  {
+    case vowel_syllable: /* We made the vowels look like consonants.  So let's call the consonant logic! */
+    case consonant_syllable:
+     initial_reordering_consonant_syllable (plan, face, buffer, start, end);
+     break;
+
+    case broken_cluster: /* We already inserted dotted-circles, so just call the standalone_cluster. */
+    case standalone_cluster:
+     initial_reordering_standalone_cluster (plan, face, buffer, start, end);
+     break;
+
+    case symbol_cluster:
+    case non_indic_cluster:
+      break;
+  }
+}
+
+static inline void
+insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                       hb_font_t *font,
+                       hb_buffer_t *buffer)
+{
+  /* Note: This loop is extra overhead, but should not be measurable. */
+  bool has_broken_syllables = false;
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    if ((info[i].syllable() & 0x0F) == broken_cluster)
+    {
+      has_broken_syllables = true;
+      break;
+    }
+  if (likely (!has_broken_syllables))
+    return;
+
+
+  hb_codepoint_t dottedcircle_glyph;
+  if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
+    return;
+
+  hb_glyph_info_t dottedcircle = {0};
+  dottedcircle.codepoint = 0x25CCu;
+  set_indic_properties (dottedcircle);
+  dottedcircle.codepoint = dottedcircle_glyph;
+
+  buffer->clear_output ();
+
+  buffer->idx = 0;
+  unsigned int last_syllable = 0;
+  while (buffer->idx < buffer->len && !buffer->in_error)
+  {
+    unsigned int syllable = buffer->cur().syllable();
+    syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
+    if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+    {
+      last_syllable = syllable;
+
+      hb_glyph_info_t ginfo = dottedcircle;
+      ginfo.cluster = buffer->cur().cluster;
+      ginfo.mask = buffer->cur().mask;
+      ginfo.syllable() = buffer->cur().syllable();
+      /* TODO Set glyph_props? */
+
+      /* Insert dottedcircle after possible Repha. */
+      while (buffer->idx < buffer->len && !buffer->in_error &&
+             last_syllable == buffer->cur().syllable() &&
+             buffer->cur().indic_category() == OT_Repha)
+        buffer->next_glyph ();
+
+      buffer->output_info (ginfo);
+    }
+    else
+      buffer->next_glyph ();
+  }
+
+  buffer->swap_buffers ();
+}
+
+static void
+initial_reordering (const hb_ot_shape_plan_t *plan,
+                    hb_font_t *font,
+                    hb_buffer_t *buffer)
+{
+  update_consonant_positions (plan, font, buffer);
+  insert_dotted_circles (plan, font, buffer);
+
+  foreach_syllable (buffer, start, end)
+    initial_reordering_syllable (plan, font->face, buffer, start, end);
+}
+
+static void
+final_reordering_syllable (const hb_ot_shape_plan_t *plan,
+                           hb_buffer_t *buffer,
+                           unsigned int start, unsigned int end)
+{
+  const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
+  hb_glyph_info_t *info = buffer->info;
+
+
+  /* This function relies heavily on halant glyphs.  Lots of ligation
+   * and possibly multiplication substitutions happened prior to this
+   * phase, and that might have messed up our properties.  Recover
+   * from a particular case of that where we're fairly sure that a
+   * class of OT_H is desired but has been lost. */
+  if (indic_plan->virama_glyph)
+  {
+    unsigned int virama_glyph = indic_plan->virama_glyph;
+    for (unsigned int i = start; i < end; i++)
+      if (info[i].codepoint == virama_glyph &&
+          _hb_glyph_info_ligated (&info[i]) &&
+          _hb_glyph_info_multiplied (&info[i]))
+      {
+        /* This will make sure that this glyph passes is_halant_or_coeng() test. */
+        info[i].indic_category() = OT_H;
+        _hb_glyph_info_clear_ligated_and_multiplied (&info[i]);
+      }
+  }
+
+
+  /* 4. Final reordering:
+   *
+   * After the localized forms and basic shaping forms GSUB features have been
+   * applied (see below), the shaping engine performs some final glyph
+   * reordering before applying all the remaining font features to the entire
+   * cluster.
+   */
+
+  bool try_pref = !!indic_plan->mask_array[PREF];
+
+  /* Find base again */
+  unsigned int base;
+  for (base = start; base < end; base++)
+    if (info[base].indic_position() >= POS_BASE_C)
+    {
+      if (try_pref && base + 1 < end)
+      {
+        for (unsigned int i = base + 1; i < end; i++)
+          if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
+          {
+            if (!(_hb_glyph_info_substituted (&info[i]) &&
+                  _hb_glyph_info_ligated_and_didnt_multiply (&info[i])))
+            {
+              /* Ok, this was a 'pref' candidate but didn't form any.
+               * Base is around here... */
+              base = i;
+              while (base < end && is_halant_or_coeng (info[base]))
+                base++;
+              info[base].indic_position() = POS_BASE_C;
+
+              try_pref = false;
+            }
+            break;
+          }
+      }
+      /* For Malayalam, skip over unformed below- (but NOT post-) forms. */
+      if (buffer->props.script == HB_SCRIPT_MALAYALAM)
+      {
+        for (unsigned int i = base + 1; i < end; i++)
+        {
+          while (i < end && is_joiner (info[i]))
+            i++;
+          if (i == end || !is_halant_or_coeng (info[i]))
+            break;
+          i++; /* Skip halant. */
+          while (i < end && is_joiner (info[i]))
+            i++;
+          if (i < end && is_consonant (info[i]) && info[i].indic_position() == POS_BELOW_C)
+          {
+            base = i;
+            info[base].indic_position() = POS_BASE_C;
+          }
+        }
+      }
+
+      if (start < base && info[base].indic_position() > POS_BASE_C)
+        base--;
+      break;
+    }
+  if (base == end && start < base &&
+      is_one_of (info[base - 1], FLAG (OT_ZWJ)))
+    base--;
+  if (base < end)
+    while (start < base &&
+           is_one_of (info[base], (FLAG (OT_N) | HALANT_OR_COENG_FLAGS)))
+      base--;
+
+
+  /*   o Reorder matras:
+   *
+   *     If a pre-base matra character had been reordered before applying basic
+   *     features, the glyph can be moved closer to the main consonant based on
+   *     whether half-forms had been formed. Actual position for the matra is
+   *     defined as “after last standalone halant glyph, after initial matra
+   *     position and before the main consonant”. If ZWJ or ZWNJ follow this
+   *     halant, position is moved after it.
+   */
+
+  if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */
+  {
+    /* If we lost track of base, alas, position before last thingy. */
+    unsigned int new_pos = base == end ? base - 2 : base - 1;
+
+    /* Malayalam / Tamil do not have "half" forms or explicit virama forms.
+     * The glyphs formed by 'half' are Chillus or ligated explicit viramas.
+     * We want to position matra after them.
+     */
+    if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
+    {
+      while (new_pos > start &&
+             !(is_one_of (info[new_pos], (FLAG (OT_M) | HALANT_OR_COENG_FLAGS))))
+        new_pos--;
+
+      /* If we found no Halant we are done.
+       * Otherwise only proceed if the Halant does
+       * not belong to the Matra itself! */
+      if (is_halant_or_coeng (info[new_pos]) &&
+          info[new_pos].indic_position() != POS_PRE_M)
+      {
+        /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
+        if (new_pos + 1 < end && is_joiner (info[new_pos + 1]))
+          new_pos++;
+      }
+      else
+        new_pos = start; /* No move. */
+    }
+
+    if (start < new_pos && info[new_pos].indic_position () != POS_PRE_M)
+    {
+      /* Now go see if there's actually any matras... */
+      for (unsigned int i = new_pos; i > start; i--)
+        if (info[i - 1].indic_position () == POS_PRE_M)
+        {
+          unsigned int old_pos = i - 1;
+          if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. */
+            base--;
+
+          hb_glyph_info_t tmp = info[old_pos];
+          memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0]));
+          info[new_pos] = tmp;
+
+          /* Note: this merge_clusters() is intentionally *after* the reordering.
+           * Indic matra reordering is special and tricky... */
+          buffer->merge_clusters (new_pos, MIN (end, base + 1));
+
+          new_pos--;
+        }
+    } else {
+      for (unsigned int i = start; i < base; i++)
+        if (info[i].indic_position () == POS_PRE_M) {
+          buffer->merge_clusters (i, MIN (end, base + 1));
+          break;
+        }
+    }
+  }
+
+
+  /*   o Reorder reph:
+   *
+   *     Reph’s original position is always at the beginning of the syllable,
+   *     (i.e. it is not reordered at the character reordering stage). However,
+   *     it will be reordered according to the basic-forms shaping results.
+   *     Possible positions for reph, depending on the script, are; after main,
+   *     before post-base consonant forms, and after post-base consonant forms.
+   */
+
+  /* Two cases:
+   *
+   * - If repha is encoded as a sequence of characters (Ra,H or Ra,H,ZWJ), then
+   *   we should only move it if the sequence ligated to the repha form.
+   *
+   * - If repha is encoded separately and in the logical position, we should only
+   *   move it if it did NOT ligate.  If it ligated, it's probably the font trying
+   *   to make it work without the reordering.
+   */
+  if (start + 1 < end &&
+      info[start].indic_position() == POS_RA_TO_BECOME_REPH &&
+      ((info[start].indic_category() == OT_Repha) ^
+       _hb_glyph_info_ligated_and_didnt_multiply (&info[start])))
+  {
+    unsigned int new_reph_pos;
+    reph_position_t reph_pos = indic_plan->config->reph_pos;
+
+    assert (reph_pos != REPH_POS_DONT_CARE);
+
+    /*       1. If reph should be positioned after post-base consonant forms,
+     *          proceed to step 5.
+     */
+    if (reph_pos == REPH_POS_AFTER_POST)
+    {
+      goto reph_step_5;
+    }
+
+    /*       2. If the reph repositioning class is not after post-base: target
+     *          position is after the first explicit halant glyph between the
+     *          first post-reph consonant and last main consonant. If ZWJ or ZWNJ
+     *          are following this halant, position is moved after it. If such
+     *          position is found, this is the target position. Otherwise,
+     *          proceed to the next step.
+     *
+     *          Note: in old-implementation fonts, where classifications were
+     *          fixed in shaping engine, there was no case where reph position
+     *          will be found on this step.
+     */
+    {
+      new_reph_pos = start + 1;
+      while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos]))
+        new_reph_pos++;
+
+      if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos]))
+      {
+        /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */
+        if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1]))
+          new_reph_pos++;
+        goto reph_move;
+      }
+    }
+
+    /*       3. If reph should be repositioned after the main consonant: find the
+     *          first consonant not ligated with main, or find the first
+     *          consonant that is not a potential pre-base reordering Ra.
+     */
+    if (reph_pos == REPH_POS_AFTER_MAIN)
+    {
+      new_reph_pos = base;
+      while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN)
+        new_reph_pos++;
+      if (new_reph_pos < end)
+        goto reph_move;
+    }
+
+    /*       4. If reph should be positioned before post-base consonant, find
+     *          first post-base classified consonant not ligated with main. If no
+     *          consonant is found, the target position should be before the
+     *          first matra, syllable modifier sign or vedic sign.
+     */
+    /* This is our take on what step 4 is trying to say (and failing, BADLY). */
+    if (reph_pos == REPH_POS_AFTER_SUB)
+    {
+      new_reph_pos = base;
+      while (new_reph_pos < end &&
+             !( FLAG_SAFE (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD))))
+        new_reph_pos++;
+      if (new_reph_pos < end)
+        goto reph_move;
+    }
+
+    /*       5. If no consonant is found in steps 3 or 4, move reph to a position
+     *          immediately before the first post-base matra, syllable modifier
+     *          sign or vedic sign that has a reordering class after the intended
+     *          reph position. For example, if the reordering position for reph
+     *          is post-main, it will skip above-base matras that also have a
+     *          post-main position.
+     */
+    reph_step_5:
+    {
+      /* Copied from step 2. */
+      new_reph_pos = start + 1;
+      while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos]))
+        new_reph_pos++;
+
+      if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos]))
+      {
+        /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */
+        if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1]))
+          new_reph_pos++;
+        goto reph_move;
+      }
+    }
+
+    /*       6. Otherwise, reorder reph to the end of the syllable.
+     */
+    {
+      new_reph_pos = end - 1;
+      while (new_reph_pos > start && info[new_reph_pos].indic_position() == POS_SMVD)
+        new_reph_pos--;
+
+      /*
+       * If the Reph is to be ending up after a Matra,Halant sequence,
+       * position it before that Halant so it can interact with the Matra.
+       * However, if it's a plain Consonant,Halant we shouldn't do that.
+       * Uniscribe doesn't do this.
+       * TEST: U+0930,U+094D,U+0915,U+094B,U+094D
+       */
+      if (!hb_options ().uniscribe_bug_compatible &&
+          unlikely (is_halant_or_coeng (info[new_reph_pos]))) {
+        for (unsigned int i = base + 1; i < new_reph_pos; i++)
+          if (info[i].indic_category() == OT_M) {
+            /* Ok, got it. */
+            new_reph_pos--;
+          }
+      }
+      goto reph_move;
+    }
+
+    reph_move:
+    {
+      /* Move */
+      buffer->merge_clusters (start, new_reph_pos + 1);
+      hb_glyph_info_t reph = info[start];
+      memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0]));
+      info[new_reph_pos] = reph;
+
+      if (start < base && base <= new_reph_pos)
+        base--;
+    }
+  }
+
+
+  /*   o Reorder pre-base reordering consonants:
+   *
+   *     If a pre-base reordering consonant is found, reorder it according to
+   *     the following rules:
+   */
+
+  if (try_pref && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */
+  {
+    for (unsigned int i = base + 1; i < end; i++)
+      if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
+      {
+        /*       1. Only reorder a glyph produced by substitution during application
+         *          of the <pref> feature. (Note that a font may shape a Ra consonant with
+         *          the feature generally but block it in certain contexts.)
+         */
+        /* Note: We just check that something got substituted.  We don't check that
+         * the <pref> feature actually did it...
+         *
+         * Reorder pref only if it ligated. */
+        if (_hb_glyph_info_ligated_and_didnt_multiply (&info[i]))
+        {
+          /*
+           *       2. Try to find a target position the same way as for pre-base matra.
+           *          If it is found, reorder pre-base consonant glyph.
+           *
+           *       3. If position is not found, reorder immediately before main
+           *          consonant.
+           */
+
+          unsigned int new_pos = base;
+          /* Malayalam / Tamil do not have "half" forms or explicit virama forms.
+           * The glyphs formed by 'half' are Chillus or ligated explicit viramas.
+           * We want to position matra after them.
+           */
+          if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
+          {
+            while (new_pos > start &&
+                   !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS)))
+              new_pos--;
+
+            /* In Khmer coeng model, a H,Ra can go *after* matras.  If it goes after a
+             * split matra, it should be reordered to *before* the left part of such matra. */
+            if (new_pos > start && info[new_pos - 1].indic_category() == OT_M)
+            {
+              unsigned int old_pos = i;
+              for (unsigned int j = base + 1; j < old_pos; j++)
+                if (info[j].indic_category() == OT_M)
+                {
+                  new_pos--;
+                  break;
+                }
+            }
+          }
+
+          if (new_pos > start && is_halant_or_coeng (info[new_pos - 1]))
+          {
+            /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
+            if (new_pos < end && is_joiner (info[new_pos]))
+              new_pos++;
+          }
+
+          {
+            unsigned int old_pos = i;
+
+            buffer->merge_clusters (new_pos, old_pos + 1);
+            hb_glyph_info_t tmp = info[old_pos];
+            memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0]));
+            info[new_pos] = tmp;
+
+            if (new_pos <= base && base < old_pos)
+              base++;
+          }
+        }
+
+        break;
+      }
+  }
+
+
+  /* Apply 'init' to the Left Matra if it's a word start. */
+  if (info[start].indic_position () == POS_PRE_M &&
+      (!start ||
+       !(FLAG_SAFE (_hb_glyph_info_get_general_category (&info[start - 1])) &
+         FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))))
+    info[start].mask |= indic_plan->mask_array[INIT];
+
+
+  /*
+   * Finish off the clusters and go home!
+   */
+  if (hb_options ().uniscribe_bug_compatible)
+  {
+    switch ((hb_tag_t) plan->props.script)
+    {
+      case HB_SCRIPT_TAMIL:
+      case HB_SCRIPT_SINHALA:
+        break;
+
+      default:
+        /* Uniscribe merges the entire cluster... Except for Tamil & Sinhala.
+         * This means, half forms are submerged into the main consonants cluster.
+         * This is unnecessary, and makes cursor positioning harder, but that's what
+         * Uniscribe does. */
+        buffer->merge_clusters (start, end);
+        break;
+    }
+  }
+}
+
+
+static void
+final_reordering (const hb_ot_shape_plan_t *plan,
+                  hb_font_t *font HB_UNUSED,
+                  hb_buffer_t *buffer)
+{
+  unsigned int count = buffer->len;
+  if (unlikely (!count)) return;
+
+  foreach_syllable (buffer, start, end)
+    final_reordering_syllable (plan, buffer, start, end);
+
+  HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
+  HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
+}
+
+
+static void
+clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                 hb_font_t *font HB_UNUSED,
+                 hb_buffer_t *buffer)
+{
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+    info[i].syllable() = 0;
+}
+
+
+static bool
+decompose_indic (const hb_ot_shape_normalize_context_t *c,
+                 hb_codepoint_t  ab,
+                 hb_codepoint_t *a,
+                 hb_codepoint_t *b)
+{
+  switch (ab)
+  {
+    /* Don't decompose these. */
+    case 0x0931u  : return false;
+    case 0x0B94u  : return false;
+
+
+    /*
+     * Decompose split matras that don't have Unicode decompositions.
+     */
+
+    case 0x0F77u  : *a = 0x0FB2u; *b= 0x0F81u; return true;
+    case 0x0F79u  : *a = 0x0FB3u; *b= 0x0F81u; return true;
+    case 0x17BEu  : *a = 0x17C1u; *b= 0x17BEu; return true;
+    case 0x17BFu  : *a = 0x17C1u; *b= 0x17BFu; return true;
+    case 0x17C0u  : *a = 0x17C1u; *b= 0x17C0u; return true;
+    case 0x17C4u  : *a = 0x17C1u; *b= 0x17C4u; return true;
+    case 0x17C5u  : *a = 0x17C1u; *b= 0x17C5u; return true;
+    case 0x1925u  : *a = 0x1920u; *b= 0x1923u; return true;
+    case 0x1926u  : *a = 0x1920u; *b= 0x1924u; return true;
+    case 0x1B3Cu  : *a = 0x1B42u; *b= 0x1B3Cu; return true;
+    case 0x1112Eu  : *a = 0x11127u; *b= 0x11131u; return true;
+    case 0x1112Fu  : *a = 0x11127u; *b= 0x11132u; return true;
+#if 0
+    /* This one has no decomposition in Unicode, but needs no decomposition either. */
+    /* case 0x0AC9u  : return false; */
+    case 0x0B57u  : *a = no decomp, -> RIGHT; return true;
+    case 0x1C29u  : *a = no decomp, -> LEFT; return true;
+    case 0xA9C0u  : *a = no decomp, -> RIGHT; return true;
+    case 0x111BuF  : *a = no decomp, -> ABOVE; return true;
+#endif
+  }
+
+  if ((ab == 0x0DDAu || hb_in_range (ab, 0x0DDCu, 0x0DDEu)))
+  {
+    /*
+     * Sinhala split matras...  Let the fun begin.
+     *
+     * These four characters have Unicode decompositions.  However, Uniscribe
+     * decomposes them "Khmer-style", that is, it uses the character itself to
+     * get the second half.  The first half of all four decompositions is always
+     * U+0DD9.
+     *
+     * Now, there are buggy fonts, namely, the widely used lklug.ttf, that are
+     * broken with Uniscribe.  But we need to support them.  As such, we only
+     * do the Uniscribe-style decomposition if the character is transformed into
+     * its "sec.half" form by the 'pstf' feature.  Otherwise, we fall back to
+     * Unicode decomposition.
+     *
+     * Note that we can't unconditionally use Unicode decomposition.  That would
+     * break some other fonts, that are designed to work with Uniscribe, and
+     * don't have positioning features for the Unicode-style decomposition.
+     *
+     * Argh...
+     *
+     * The Uniscribe behavior is now documented in the newly published Sinhala
+     * spec in 2012:
+     *
+     *   http://www.microsoft.com/typography/OpenTypeDev/sinhala/intro.htm#shaping
+     */
+
+    const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data;
+
+    hb_codepoint_t glyph;
+
+    if (hb_options ().uniscribe_bug_compatible ||
+        (c->font->get_nominal_glyph (ab, &glyph) &&
+         indic_plan->pstf.would_substitute (&glyph, 1, c->font->face)))
+    {
+      /* Ok, safe to use Uniscribe-style decomposition. */
+      *a = 0x0DD9u;
+      *b = ab;
+      return true;
+    }
+  }
+
+  return (bool) c->unicode->decompose (ab, a, b);
+}
+
+static bool
+compose_indic (const hb_ot_shape_normalize_context_t *c,
+               hb_codepoint_t  a,
+               hb_codepoint_t  b,
+               hb_codepoint_t *ab)
+{
+  /* Avoid recomposing split matras. */
+  if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a)))
+    return false;
+
+  /* Composition-exclusion exceptions that we want to recompose. */
+  if (a == 0x09AFu && b == 0x09BCu) { *ab = 0x09DFu; return true; }
+
+  return (bool) c->unicode->compose (a, b, ab);
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
+{
+  "indic",
+  collect_features_indic,
+  override_features_indic,
+  data_create_indic,
+  data_destroy_indic,
+  NULL, /* preprocess_text */
+  NULL, /* postprocess_glyphs */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
+  decompose_indic,
+  compose_indic,
+  setup_masks_indic,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+  false, /* fallback_position */
+};
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-myanmar-machine.hh b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-myanmar-machine.hh
new file mode 100644
index 0000000..c16b4fd
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-myanmar-machine.hh
@@ -0,0 +1,400 @@
+
+#line 1 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+/*
+ * 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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
+#define HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
+
+#include "hb-private.hh"
+
+
+#line 36 "../../src/hb-ot-shape-complex-myanmar-machine.hh.tmp"
+static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
+        1u, 31u, 3u, 30u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u,
+        3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 1u, 16u, 3u, 29u, 3u, 29u, 3u, 29u,
+        3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 5u, 29u, 5u, 8u,
+        5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u,
+        3u, 30u, 3u, 29u, 1u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u,
+        3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 8u, 8u, 0
+};
+
+static const char _myanmar_syllable_machine_key_spans[] = {
+        31, 28, 25, 4, 25, 23, 21, 21,
+        27, 27, 27, 27, 16, 27, 27, 27,
+        27, 27, 27, 27, 27, 27, 25, 4,
+        25, 23, 21, 21, 27, 27, 27, 27,
+        28, 27, 30, 27, 27, 27, 27, 27,
+        27, 27, 27, 27, 1
+};
+
+static const short _myanmar_syllable_machine_index_offsets[] = {
+        0, 32, 61, 87, 92, 118, 142, 164,
+        186, 214, 242, 270, 298, 315, 343, 371,
+        399, 427, 455, 483, 511, 539, 567, 593,
+        598, 624, 648, 670, 692, 720, 748, 776,
+        804, 833, 861, 892, 920, 948, 976, 1004,
+        1032, 1060, 1088, 1116, 1144
+};
+
+static const char _myanmar_syllable_machine_indicies[] = {
+        1, 1, 2, 3, 4, 4, 0, 5,
+        0, 6, 1, 0, 0, 0, 0, 7,
+        0, 8, 1, 0, 9, 10, 11, 12,
+        13, 14, 15, 16, 17, 18, 19, 0,
+        21, 22, 23, 23, 20, 24, 20, 25,
+        20, 20, 20, 20, 20, 20, 20, 26,
+        20, 20, 27, 28, 29, 30, 31, 32,
+        33, 34, 35, 36, 20, 23, 23, 20,
+        24, 20, 20, 20, 20, 20, 20, 20,
+        20, 20, 37, 20, 20, 20, 20, 20,
+        20, 31, 20, 20, 20, 35, 20, 23,
+        23, 20, 24, 20, 23, 23, 20, 24,
+        20, 20, 20, 20, 20, 20, 20, 20,
+        20, 20, 20, 20, 20, 20, 20, 20,
+        31, 20, 20, 20, 35, 20, 38, 20,
+        23, 23, 20, 24, 20, 31, 20, 20,
+        20, 20, 20, 20, 20, 39, 20, 20,
+        20, 20, 20, 20, 31, 20, 23, 23,
+        20, 24, 20, 20, 20, 20, 20, 20,
+        20, 20, 20, 39, 20, 20, 20, 20,
+        20, 20, 31, 20, 23, 23, 20, 24,
+        20, 20, 20, 20, 20, 20, 20, 20,
+        20, 20, 20, 20, 20, 20, 20, 20,
+        31, 20, 21, 20, 23, 23, 20, 24,
+        20, 25, 20, 20, 20, 20, 20, 20,
+        20, 40, 20, 20, 40, 20, 20, 20,
+        31, 41, 20, 20, 35, 20, 21, 20,
+        23, 23, 20, 24, 20, 25, 20, 20,
+        20, 20, 20, 20, 20, 20, 20, 20,
+        20, 20, 20, 20, 31, 20, 20, 20,
+        35, 20, 21, 20, 23, 23, 20, 24,
+        20, 25, 20, 20, 20, 20, 20, 20,
+        20, 40, 20, 20, 20, 20, 20, 20,
+        31, 41, 20, 20, 35, 20, 21, 20,
+        23, 23, 20, 24, 20, 25, 20, 20,
+        20, 20, 20, 20, 20, 20, 20, 20,
+        20, 20, 20, 20, 31, 41, 20, 20,
+        35, 20, 1, 1, 20, 20, 20, 20,
+        20, 20, 20, 20, 20, 20, 20, 20,
+        20, 1, 20, 21, 20, 23, 23, 20,
+        24, 20, 25, 20, 20, 20, 20, 20,
+        20, 20, 26, 20, 20, 27, 28, 29,
+        30, 31, 32, 33, 34, 35, 20, 21,
+        20, 23, 23, 20, 24, 20, 25, 20,
+        20, 20, 20, 20, 20, 20, 34, 20,
+        20, 20, 20, 20, 20, 31, 32, 33,
+        34, 35, 20, 21, 20, 23, 23, 20,
+        24, 20, 25, 20, 20, 20, 20, 20,
+        20, 20, 20, 20, 20, 20, 20, 20,
+        20, 31, 32, 33, 34, 35, 20, 21,
+        20, 23, 23, 20, 24, 20, 25, 20,
+        20, 20, 20, 20, 20, 20, 20, 20,
+        20, 20, 20, 20, 20, 31, 32, 33,
+        20, 35, 20, 21, 20, 23, 23, 20,
+        24, 20, 25, 20, 20, 20, 20, 20,
+        20, 20, 20, 20, 20, 20, 20, 20,
+        20, 31, 20, 33, 20, 35, 20, 21,
+        20, 23, 23, 20, 24, 20, 25, 20,
+        20, 20, 20, 20, 20, 20, 34, 20,
+        20, 27, 20, 29, 20, 31, 32, 33,
+        34, 35, 20, 21, 20, 23, 23, 20,
+        24, 20, 25, 20, 20, 20, 20, 20,
+        20, 20, 34, 20, 20, 27, 20, 20,
+        20, 31, 32, 33, 34, 35, 20, 21,
+        20, 23, 23, 20, 24, 20, 25, 20,
+        20, 20, 20, 20, 20, 20, 34, 20,
+        20, 27, 28, 29, 20, 31, 32, 33,
+        34, 35, 20, 21, 22, 23, 23, 20,
+        24, 20, 25, 20, 20, 20, 20, 20,
+        20, 20, 26, 20, 20, 27, 28, 29,
+        30, 31, 32, 33, 34, 35, 20, 3,
+        3, 42, 5, 42, 42, 42, 42, 42,
+        42, 42, 42, 42, 43, 42, 42, 42,
+        42, 42, 42, 13, 42, 42, 42, 17,
+        42, 3, 3, 42, 5, 42, 3, 3,
+        42, 5, 42, 42, 42, 42, 42, 42,
+        42, 42, 42, 42, 42, 42, 42, 42,
+        42, 42, 13, 42, 42, 42, 17, 42,
+        44, 42, 3, 3, 42, 5, 42, 13,
+        42, 42, 42, 42, 42, 42, 42, 45,
+        42, 42, 42, 42, 42, 42, 13, 42,
+        3, 3, 42, 5, 42, 42, 42, 42,
+        42, 42, 42, 42, 42, 45, 42, 42,
+        42, 42, 42, 42, 13, 42, 3, 3,
+        42, 5, 42, 42, 42, 42, 42, 42,
+        42, 42, 42, 42, 42, 42, 42, 42,
+        42, 42, 13, 42, 2, 42, 3, 3,
+        42, 5, 42, 6, 42, 42, 42, 42,
+        42, 42, 42, 46, 42, 42, 46, 42,
+        42, 42, 13, 47, 42, 42, 17, 42,
+        2, 42, 3, 3, 42, 5, 42, 6,
+        42, 42, 42, 42, 42, 42, 42, 42,
+        42, 42, 42, 42, 42, 42, 13, 42,
+        42, 42, 17, 42, 2, 42, 3, 3,
+        42, 5, 42, 6, 42, 42, 42, 42,
+        42, 42, 42, 46, 42, 42, 42, 42,
+        42, 42, 13, 47, 42, 42, 17, 42,
+        2, 42, 3, 3, 42, 5, 42, 6,
+        42, 42, 42, 42, 42, 42, 42, 42,
+        42, 42, 42, 42, 42, 42, 13, 47,
+        42, 42, 17, 42, 21, 22, 23, 23,
+        20, 24, 20, 25, 20, 20, 20, 20,
+        20, 20, 20, 48, 20, 20, 27, 28,
+        29, 30, 31, 32, 33, 34, 35, 36,
+        20, 21, 49, 23, 23, 20, 24, 20,
+        25, 20, 20, 20, 20, 20, 20, 20,
+        26, 20, 20, 27, 28, 29, 30, 31,
+        32, 33, 34, 35, 20, 1, 1, 2,
+        3, 3, 3, 42, 5, 42, 6, 1,
+        42, 42, 42, 42, 1, 42, 8, 1,
+        42, 9, 10, 11, 12, 13, 14, 15,
+        16, 17, 18, 42, 2, 42, 3, 3,
+        42, 5, 42, 6, 42, 42, 42, 42,
+        42, 42, 42, 8, 42, 42, 9, 10,
+        11, 12, 13, 14, 15, 16, 17, 42,
+        2, 42, 3, 3, 42, 5, 42, 6,
+        42, 42, 42, 42, 42, 42, 42, 16,
+        42, 42, 42, 42, 42, 42, 13, 14,
+        15, 16, 17, 42, 2, 42, 3, 3,
+        42, 5, 42, 6, 42, 42, 42, 42,
+        42, 42, 42, 42, 42, 42, 42, 42,
+        42, 42, 13, 14, 15, 16, 17, 42,
+        2, 42, 3, 3, 42, 5, 42, 6,
+        42, 42, 42, 42, 42, 42, 42, 42,
+        42, 42, 42, 42, 42, 42, 13, 14,
+        15, 42, 17, 42, 2, 42, 3, 3,
+        42, 5, 42, 6, 42, 42, 42, 42,
+        42, 42, 42, 42, 42, 42, 42, 42,
+        42, 42, 13, 42, 15, 42, 17, 42,
+        2, 42, 3, 3, 42, 5, 42, 6,
+        42, 42, 42, 42, 42, 42, 42, 16,
+        42, 42, 9, 42, 11, 42, 13, 14,
+        15, 16, 17, 42, 2, 42, 3, 3,
+        42, 5, 42, 6, 42, 42, 42, 42,
+        42, 42, 42, 16, 42, 42, 9, 42,
+        42, 42, 13, 14, 15, 16, 17, 42,
+        2, 42, 3, 3, 42, 5, 42, 6,
+        42, 42, 42, 42, 42, 42, 42, 16,
+        42, 42, 9, 10, 11, 42, 13, 14,
+        15, 16, 17, 42, 2, 3, 3, 3,
+        42, 5, 42, 6, 42, 42, 42, 42,
+        42, 42, 42, 8, 42, 42, 9, 10,
+        11, 12, 13, 14, 15, 16, 17, 42,
+        51, 50, 0
+};
+
+static const char _myanmar_syllable_machine_trans_targs[] = {
+        0, 1, 22, 0, 0, 23, 29, 32,
+        35, 36, 40, 41, 42, 25, 38, 39,
+        37, 28, 43, 44, 0, 2, 12, 0,
+        3, 9, 13, 14, 18, 19, 20, 5,
+        16, 17, 15, 8, 21, 4, 6, 7,
+        10, 11, 0, 24, 26, 27, 30, 31,
+        33, 34, 0, 0
+};
+
+static const char _myanmar_syllable_machine_trans_actions[] = {
+        3, 0, 0, 4, 5, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 6, 0, 0, 7,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 8, 0, 0, 0, 0, 0,
+        0, 0, 9, 10
+};
+
+static const char _myanmar_syllable_machine_to_state_actions[] = {
+        1, 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
+};
+
+static const char _myanmar_syllable_machine_from_state_actions[] = {
+        2, 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
+};
+
+static const short _myanmar_syllable_machine_eof_trans[] = {
+        0, 21, 21, 21, 21, 21, 21, 21,
+        21, 21, 21, 21, 21, 21, 21, 21,
+        21, 21, 21, 21, 21, 21, 43, 43,
+        43, 43, 43, 43, 43, 43, 43, 43,
+        21, 21, 43, 43, 43, 43, 43, 43,
+        43, 43, 43, 43, 51
+};
+
+static const int myanmar_syllable_machine_start = 0;
+static const int myanmar_syllable_machine_first_final = 0;
+static const int myanmar_syllable_machine_error = -1;
+
+static const int myanmar_syllable_machine_en_main = 0;
+
+
+#line 36 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+
+
+
+#line 93 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+
+
+#define found_syllable(syllable_type) \
+  HB_STMT_START { \
+    if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
+    for (unsigned int i = last; i < p+1; i++) \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+    last = p+1; \
+    syllable_serial++; \
+    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+  } HB_STMT_END
+
+static void
+find_syllables (hb_buffer_t *buffer)
+{
+  unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
+  int cs;
+  hb_glyph_info_t *info = buffer->info;
+
+#line 289 "../../src/hb-ot-shape-complex-myanmar-machine.hh.tmp"
+        {
+        cs = myanmar_syllable_machine_start;
+        ts = 0;
+        te = 0;
+        act = 0;
+        }
+
+#line 114 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+
+
+  p = 0;
+  pe = eof = buffer->len;
+
+  unsigned int last = 0;
+  unsigned int syllable_serial = 1;
+
+#line 306 "../../src/hb-ot-shape-complex-myanmar-machine.hh.tmp"
+        {
+        int _slen;
+        int _trans;
+        const unsigned char *_keys;
+        const char *_inds;
+        if ( p == pe )
+                goto _test_eof;
+_resume:
+        switch ( _myanmar_syllable_machine_from_state_actions[cs] ) {
+        case 2:
+#line 1 "NONE"
+        {ts = p;}
+        break;
+#line 320 "../../src/hb-ot-shape-complex-myanmar-machine.hh.tmp"
+        }
+
+        _keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
+        _inds = _myanmar_syllable_machine_indicies + _myanmar_syllable_machine_index_offsets[cs];
+
+        _slen = _myanmar_syllable_machine_key_spans[cs];
+        _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].myanmar_category()) &&
+                ( info[p].myanmar_category()) <= _keys[1] ?
+                ( info[p].myanmar_category()) - _keys[0] : _slen ];
+
+_eof_trans:
+        cs = _myanmar_syllable_machine_trans_targs[_trans];
+
+        if ( _myanmar_syllable_machine_trans_actions[_trans] == 0 )
+                goto _again;
+
+        switch ( _myanmar_syllable_machine_trans_actions[_trans] ) {
+        case 7:
+#line 85 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+        {te = p+1;{ found_syllable (consonant_syllable); }}
+        break;
+        case 5:
+#line 86 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+        {te = p+1;{ found_syllable (non_myanmar_cluster); }}
+        break;
+        case 10:
+#line 87 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+        {te = p+1;{ found_syllable (punctuation_cluster); }}
+        break;
+        case 4:
+#line 88 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+        {te = p+1;{ found_syllable (broken_cluster); }}
+        break;
+        case 3:
+#line 89 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+        {te = p+1;{ found_syllable (non_myanmar_cluster); }}
+        break;
+        case 6:
+#line 85 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+        {te = p;p--;{ found_syllable (consonant_syllable); }}
+        break;
+        case 8:
+#line 88 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+        {te = p;p--;{ found_syllable (broken_cluster); }}
+        break;
+        case 9:
+#line 89 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+        {te = p;p--;{ found_syllable (non_myanmar_cluster); }}
+        break;
+#line 370 "../../src/hb-ot-shape-complex-myanmar-machine.hh.tmp"
+        }
+
+_again:
+        switch ( _myanmar_syllable_machine_to_state_actions[cs] ) {
+        case 1:
+#line 1 "NONE"
+        {ts = 0;}
+        break;
+#line 379 "../../src/hb-ot-shape-complex-myanmar-machine.hh.tmp"
+        }
+
+        if ( ++p != pe )
+                goto _resume;
+        _test_eof: {}
+        if ( p == eof )
+        {
+        if ( _myanmar_syllable_machine_eof_trans[cs] > 0 ) {
+                _trans = _myanmar_syllable_machine_eof_trans[cs] - 1;
+                goto _eof_trans;
+        }
+        }
+
+        }
+
+#line 123 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+
+}
+
+#undef found_syllable
+
+#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-myanmar.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-myanmar.cpp
new file mode 100644
index 0000000..6c64662
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-myanmar.cpp
@@ -0,0 +1,543 @@
+/*
+ * Copyright © 2011,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-ot-shape-complex-indic-private.hh"
+
+/* buffer var allocations */
+#define myanmar_category() complex_var_u8_0() /* myanmar_category_t */
+#define myanmar_position() complex_var_u8_1() /* myanmar_position_t */
+
+
+/*
+ * Myanmar shaper.
+ */
+
+static const hb_tag_t
+basic_features[] =
+{
+  /*
+   * Basic features.
+   * These features are applied in order, one at a time, after initial_reordering.
+   */
+  HB_TAG('r','p','h','f'),
+  HB_TAG('p','r','e','f'),
+  HB_TAG('b','l','w','f'),
+  HB_TAG('p','s','t','f'),
+};
+static const hb_tag_t
+other_features[] =
+{
+  /*
+   * Other features.
+   * These features are applied all at once, after final_reordering.
+   */
+  HB_TAG('p','r','e','s'),
+  HB_TAG('a','b','v','s'),
+  HB_TAG('b','l','w','s'),
+  HB_TAG('p','s','t','s'),
+  /* Positioning features, though we don't care about the types. */
+  HB_TAG('d','i','s','t'),
+  /* Pre-release version of Windows 8 Myanmar font had abvm,blwm
+   * features.  The released Windows 8 version of the font (as well
+   * as the released spec) used 'mark' instead.  The Windows 8
+   * shaper however didn't apply 'mark' but did apply 'mkmk'.
+   * Perhaps it applied abvm/blwm.  This was fixed in a Windows 8
+   * update, so now it applies mark/mkmk.  We are guessing that
+   * it still applies abvm/blwm too.
+   */
+  HB_TAG('a','b','v','m'),
+  HB_TAG('b','l','w','m'),
+};
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan,
+                 hb_font_t *font,
+                 hb_buffer_t *buffer);
+static void
+initial_reordering (const hb_ot_shape_plan_t *plan,
+                    hb_font_t *font,
+                    hb_buffer_t *buffer);
+static void
+final_reordering (const hb_ot_shape_plan_t *plan,
+                  hb_font_t *font,
+                  hb_buffer_t *buffer);
+
+static void
+collect_features_myanmar (hb_ot_shape_planner_t *plan)
+{
+  hb_ot_map_builder_t *map = &plan->map;
+
+  /* Do this before any lookups have been applied. */
+  map->add_gsub_pause (setup_syllables);
+
+  map->add_global_bool_feature (HB_TAG('l','o','c','l'));
+  /* The Indic specs do not require ccmp, but we apply it here since if
+   * there is a use of it, it's typically at the beginning. */
+  map->add_global_bool_feature (HB_TAG('c','c','m','p'));
+
+
+  map->add_gsub_pause (initial_reordering);
+  for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
+  {
+    map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
+    map->add_gsub_pause (NULL);
+  }
+  map->add_gsub_pause (final_reordering);
+  for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
+    map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
+}
+
+static void
+override_features_myanmar (hb_ot_shape_planner_t *plan)
+{
+  plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
+}
+
+
+enum syllable_type_t {
+  consonant_syllable,
+  punctuation_cluster,
+  broken_cluster,
+  non_myanmar_cluster,
+};
+
+#include "hb-ot-shape-complex-myanmar-machine.hh"
+
+
+/* Note: This enum is duplicated in the -machine.rl source file.
+ * Not sure how to avoid duplication. */
+enum myanmar_category_t {
+  OT_As  = 18, /* Asat */
+  OT_D   = 19, /* Digits except zero */
+  OT_D0  = 20, /* Digit zero */
+  OT_DB  = OT_N, /* Dot below */
+  OT_GB  = OT_PLACEHOLDER,
+  OT_MH  = 21, /* Various consonant medial types */
+  OT_MR  = 22, /* Various consonant medial types */
+  OT_MW  = 23, /* Various consonant medial types */
+  OT_MY  = 24, /* Various consonant medial types */
+  OT_PT  = 25, /* Pwo and other tones */
+  OT_VAbv = 26,
+  OT_VBlw = 27,
+  OT_VPre = 28,
+  OT_VPst = 29,
+  OT_VS   = 30, /* Variation selectors */
+  OT_P    = 31  /* Punctuation */
+};
+
+
+static inline bool
+is_one_of (const hb_glyph_info_t &info, unsigned int flags)
+{
+  /* If it ligated, all bets are off. */
+  if (_hb_glyph_info_ligated (&info)) return false;
+  return !!(FLAG_SAFE (info.myanmar_category()) & flags);
+}
+
+static inline bool
+is_consonant (const hb_glyph_info_t &info)
+{
+  return is_one_of (info, CONSONANT_FLAGS);
+}
+
+
+static inline void
+set_myanmar_properties (hb_glyph_info_t &info)
+{
+  hb_codepoint_t u = info.codepoint;
+  unsigned int type = hb_indic_get_categories (u);
+  indic_category_t cat = (indic_category_t) (type & 0x7Fu);
+  indic_position_t pos = (indic_position_t) (type >> 8);
+
+  /* Myanmar
+   * http://www.microsoft.com/typography/OpenTypeDev/myanmar/intro.htm#analyze
+   */
+  if (unlikely (hb_in_range (u, 0xFE00u, 0xFE0Fu)))
+    cat = (indic_category_t) OT_VS;
+
+  switch (u)
+  {
+    case 0x104Eu:
+      cat = (indic_category_t) OT_C; /* The spec says C, IndicSyllableCategory doesn't have. */
+      break;
+
+    case 0x002Du: case 0x00A0u: case 0x00D7u: case 0x2012u:
+    case 0x2013u: case 0x2014u: case 0x2015u: case 0x2022u:
+    case 0x25CCu: case 0x25FBu: case 0x25FCu: case 0x25FDu:
+    case 0x25FEu:
+      cat = (indic_category_t) OT_GB;
+      break;
+
+    case 0x1004u: case 0x101Bu: case 0x105Au:
+      cat = (indic_category_t) OT_Ra;
+      break;
+
+    case 0x1032u: case 0x1036u:
+      cat = (indic_category_t) OT_A;
+      break;
+
+    case 0x1039u:
+      cat = (indic_category_t) OT_H;
+      break;
+
+    case 0x103Au:
+      cat = (indic_category_t) OT_As;
+      break;
+
+    case 0x1041u: case 0x1042u: case 0x1043u: case 0x1044u:
+    case 0x1045u: case 0x1046u: case 0x1047u: case 0x1048u:
+    case 0x1049u: case 0x1090u: case 0x1091u: case 0x1092u:
+    case 0x1093u: case 0x1094u: case 0x1095u: case 0x1096u:
+    case 0x1097u: case 0x1098u: case 0x1099u:
+      cat = (indic_category_t) OT_D;
+      break;
+
+    case 0x1040u:
+      cat = (indic_category_t) OT_D; /* XXX The spec says D0, but Uniscribe doesn't seem to do. */
+      break;
+
+    case 0x103Eu: case 0x1060u:
+      cat = (indic_category_t) OT_MH;
+      break;
+
+    case 0x103Cu:
+      cat = (indic_category_t) OT_MR;
+      break;
+
+    case 0x103Du: case 0x1082u:
+      cat = (indic_category_t) OT_MW;
+      break;
+
+    case 0x103Bu: case 0x105Eu: case 0x105Fu:
+      cat = (indic_category_t) OT_MY;
+      break;
+
+    case 0x1063u: case 0x1064u: case 0x1069u: case 0x106Au:
+    case 0x106Bu: case 0x106Cu: case 0x106Du: case 0xAA7Bu:
+      cat = (indic_category_t) OT_PT;
+      break;
+
+    case 0x1038u: case 0x1087u: case 0x1088u: case 0x1089u:
+    case 0x108Au: case 0x108Bu: case 0x108Cu: case 0x108Du:
+    case 0x108Fu: case 0x109Au: case 0x109Bu: case 0x109Cu:
+      cat = (indic_category_t) OT_SM;
+      break;
+
+    case 0x104Au: case 0x104Bu:
+      cat = (indic_category_t) OT_P;
+      break;
+
+    case 0xAA74u: case 0xAA75u: case 0xAA76u:
+      /* https://github.com/roozbehp/unicode-data/issues/3 */
+      cat = (indic_category_t) OT_C;
+      break;
+  }
+
+  if (cat == OT_M)
+  {
+    switch ((int) pos)
+    {
+      case POS_PRE_C:   cat = (indic_category_t) OT_VPre;
+                        pos = POS_PRE_M;                  break;
+      case POS_ABOVE_C: cat = (indic_category_t) OT_VAbv; break;
+      case POS_BELOW_C: cat = (indic_category_t) OT_VBlw; break;
+      case POS_POST_C:  cat = (indic_category_t) OT_VPst; break;
+    }
+  }
+
+  info.myanmar_category() = (myanmar_category_t) cat;
+  info.myanmar_position() = pos;
+}
+
+
+
+static void
+setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                   hb_buffer_t              *buffer,
+                   hb_font_t                *font HB_UNUSED)
+{
+  HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_category);
+  HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_position);
+
+  /* We cannot setup masks here.  We save information about characters
+   * and setup masks later on in a pause-callback. */
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    set_myanmar_properties (info[i]);
+}
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                 hb_font_t *font HB_UNUSED,
+                 hb_buffer_t *buffer)
+{
+  find_syllables (buffer);
+}
+
+static int
+compare_myanmar_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
+{
+  int a = pa->myanmar_position();
+  int b = pb->myanmar_position();
+
+  return a < b ? -1 : a == b ? 0 : +1;
+}
+
+
+/* Rules from:
+ * http://www.microsoft.com/typography/OpenTypeDev/myanmar/intro.htm */
+
+static void
+initial_reordering_consonant_syllable (hb_buffer_t *buffer,
+                                       unsigned int start, unsigned int end)
+{
+  hb_glyph_info_t *info = buffer->info;
+
+  unsigned int base = end;
+  bool has_reph = false;
+
+  {
+    unsigned int limit = start;
+    if (start + 3 <= end &&
+        info[start  ].myanmar_category() == OT_Ra &&
+        info[start+1].myanmar_category() == OT_As &&
+        info[start+2].myanmar_category() == OT_H)
+    {
+      limit += 3;
+      base = start;
+      has_reph = true;
+    }
+
+    {
+      if (!has_reph)
+        base = limit;
+
+      for (unsigned int i = limit; i < end; i++)
+        if (is_consonant (info[i]))
+        {
+          base = i;
+          break;
+        }
+    }
+  }
+
+  /* Reorder! */
+  {
+    unsigned int i = start;
+    for (; i < start + (has_reph ? 3 : 0); i++)
+      info[i].myanmar_position() = POS_AFTER_MAIN;
+    for (; i < base; i++)
+      info[i].myanmar_position() = POS_PRE_C;
+    if (i < end)
+    {
+      info[i].myanmar_position() = POS_BASE_C;
+      i++;
+    }
+    indic_position_t pos = POS_AFTER_MAIN;
+    /* The following loop may be ugly, but it implements all of
+     * Myanmar reordering! */
+    for (; i < end; i++)
+    {
+      if (info[i].myanmar_category() == OT_MR) /* Pre-base reordering */
+      {
+        info[i].myanmar_position() = POS_PRE_C;
+        continue;
+      }
+      if (info[i].myanmar_position() < POS_BASE_C) /* Left matra */
+      {
+        continue;
+      }
+
+      if (pos == POS_AFTER_MAIN && info[i].myanmar_category() == OT_VBlw)
+      {
+        pos = POS_BELOW_C;
+        info[i].myanmar_position() = pos;
+        continue;
+      }
+
+      if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_A)
+      {
+        info[i].myanmar_position() = POS_BEFORE_SUB;
+        continue;
+      }
+      if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_VBlw)
+      {
+        info[i].myanmar_position() = pos;
+        continue;
+      }
+      if (pos == POS_BELOW_C && info[i].myanmar_category() != OT_A)
+      {
+        pos = POS_AFTER_SUB;
+        info[i].myanmar_position() = pos;
+        continue;
+      }
+      info[i].myanmar_position() = pos;
+    }
+  }
+
+  /* Sit tight, rock 'n roll! */
+  buffer->sort (start, end, compare_myanmar_order);
+}
+
+static void
+initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
+                             hb_face_t *face,
+                             hb_buffer_t *buffer,
+                             unsigned int start, unsigned int end)
+{
+  syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+  switch (syllable_type) {
+
+    case broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */
+    case consonant_syllable:
+      initial_reordering_consonant_syllable  (buffer, start, end);
+      break;
+
+    case punctuation_cluster:
+    case non_myanmar_cluster:
+      break;
+  }
+}
+
+static inline void
+insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                       hb_font_t *font,
+                       hb_buffer_t *buffer)
+{
+  /* Note: This loop is extra overhead, but should not be measurable. */
+  bool has_broken_syllables = false;
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    if ((info[i].syllable() & 0x0F) == broken_cluster)
+    {
+      has_broken_syllables = true;
+      break;
+    }
+  if (likely (!has_broken_syllables))
+    return;
+
+
+  hb_codepoint_t dottedcircle_glyph;
+  if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
+    return;
+
+  hb_glyph_info_t dottedcircle = {0};
+  dottedcircle.codepoint = 0x25CCu;
+  set_myanmar_properties (dottedcircle);
+  dottedcircle.codepoint = dottedcircle_glyph;
+
+  buffer->clear_output ();
+
+  buffer->idx = 0;
+  unsigned int last_syllable = 0;
+  while (buffer->idx < buffer->len && !buffer->in_error)
+  {
+    unsigned int syllable = buffer->cur().syllable();
+    syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
+    if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+    {
+      last_syllable = syllable;
+
+      hb_glyph_info_t ginfo = dottedcircle;
+      ginfo.cluster = buffer->cur().cluster;
+      ginfo.mask = buffer->cur().mask;
+      ginfo.syllable() = buffer->cur().syllable();
+
+      buffer->output_info (ginfo);
+    }
+    else
+      buffer->next_glyph ();
+  }
+
+  buffer->swap_buffers ();
+}
+
+static void
+initial_reordering (const hb_ot_shape_plan_t *plan,
+                    hb_font_t *font,
+                    hb_buffer_t *buffer)
+{
+  insert_dotted_circles (plan, font, buffer);
+
+  foreach_syllable (buffer, start, end)
+    initial_reordering_syllable (plan, font->face, buffer, start, end);
+}
+
+static void
+final_reordering (const hb_ot_shape_plan_t *plan,
+                  hb_font_t *font HB_UNUSED,
+                  hb_buffer_t *buffer)
+{
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+
+  /* Zero syllables now... */
+  for (unsigned int i = 0; i < count; i++)
+    info[i].syllable() = 0;
+
+  HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category);
+  HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position);
+}
+
+
+/* Uniscribe seems to have a shaper for 'mymr' that is like the
+ * generic shaper, except that it zeros mark advances GDEF_LATE. */
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_old =
+{
+  "default",
+  NULL, /* collect_features */
+  NULL, /* override_features */
+  NULL, /* data_create */
+  NULL, /* data_destroy */
+  NULL, /* preprocess_text */
+  NULL, /* postprocess_glyphs */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+  NULL, /* decompose */
+  NULL, /* compose */
+  NULL, /* setup_masks */
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
+  true, /* fallback_position */
+};
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
+{
+  "myanmar",
+  collect_features_myanmar,
+  override_features_myanmar,
+  NULL, /* data_create */
+  NULL, /* data_destroy */
+  NULL, /* preprocess_text */
+  NULL, /* postprocess_glyphs */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
+  NULL, /* decompose */
+  NULL, /* compose */
+  setup_masks_myanmar,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
+  false, /* fallback_position */
+};
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-private.hh b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-private.hh
new file mode 100644
index 0000000..c1d08dc
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-private.hh
@@ -0,0 +1,366 @@
+/*
+ * Copyright © 2010,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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_PRIVATE_HH
+#define HB_OT_SHAPE_COMPLEX_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-ot-shape-private.hh"
+#include "hb-ot-shape-normalize-private.hh"
+
+
+
+/* buffer var allocations, used by complex shapers */
+#define complex_var_u8_0()      var2.u8[2]
+#define complex_var_u8_1()      var2.u8[3]
+
+
+enum hb_ot_shape_zero_width_marks_type_t {
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE
+};
+
+
+/* Master OT shaper list */
+#define HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS \
+  HB_COMPLEX_SHAPER_IMPLEMENT (default) /* should be first */ \
+  HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (hebrew) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_old) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (indic) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (thai) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (tibetan) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (use) \
+  /* ^--- Add new shapers here */
+
+
+struct hb_ot_complex_shaper_t
+{
+  char name[8];
+
+  /* collect_features()
+   * Called during shape_plan().
+   * Shapers should use plan->map to add their features and callbacks.
+   * May be NULL.
+   */
+  void (*collect_features) (hb_ot_shape_planner_t *plan);
+
+  /* override_features()
+   * Called during shape_plan().
+   * Shapers should use plan->map to override features and add callbacks after
+   * common features are added.
+   * May be NULL.
+   */
+  void (*override_features) (hb_ot_shape_planner_t *plan);
+
+
+  /* data_create()
+   * Called at the end of shape_plan().
+   * Whatever shapers return will be accessible through plan->data later.
+   * If NULL is returned, means a plan failure.
+   */
+  void *(*data_create) (const hb_ot_shape_plan_t *plan);
+
+  /* data_destroy()
+   * Called when the shape_plan is being destroyed.
+   * plan->data is passed here for destruction.
+   * If NULL is returned, means a plan failure.
+   * May be NULL.
+   */
+  void (*data_destroy) (void *data);
+
+
+  /* preprocess_text()
+   * Called during shape().
+   * Shapers can use to modify text before shaping starts.
+   * May be NULL.
+   */
+  void (*preprocess_text) (const hb_ot_shape_plan_t *plan,
+                           hb_buffer_t              *buffer,
+                           hb_font_t                *font);
+
+  /* postprocess_glyphs()
+   * Called during shape().
+   * Shapers can use to modify glyphs after shaping ends.
+   * May be NULL.
+   */
+  void (*postprocess_glyphs) (const hb_ot_shape_plan_t *plan,
+                              hb_buffer_t              *buffer,
+                              hb_font_t                *font);
+
+
+  hb_ot_shape_normalization_mode_t normalization_preference;
+
+  /* decompose()
+   * Called during shape()'s normalization.
+   * May be NULL.
+   */
+  bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
+                     hb_codepoint_t  ab,
+                     hb_codepoint_t *a,
+                     hb_codepoint_t *b);
+
+  /* compose()
+   * Called during shape()'s normalization.
+   * May be NULL.
+   */
+  bool (*compose) (const hb_ot_shape_normalize_context_t *c,
+                   hb_codepoint_t  a,
+                   hb_codepoint_t  b,
+                   hb_codepoint_t *ab);
+
+  /* setup_masks()
+   * Called during shape().
+   * Shapers should use map to get feature masks and set on buffer.
+   * Shapers may NOT modify characters.
+   * May be NULL.
+   */
+  void (*setup_masks) (const hb_ot_shape_plan_t *plan,
+                       hb_buffer_t              *buffer,
+                       hb_font_t                *font);
+
+  hb_ot_shape_zero_width_marks_type_t zero_width_marks;
+
+  bool fallback_position;
+};
+
+#define HB_COMPLEX_SHAPER_IMPLEMENT(name) extern HB_INTERNAL const hb_ot_complex_shaper_t _hb_ot_complex_shaper_##name;
+HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
+#undef HB_COMPLEX_SHAPER_IMPLEMENT
+
+
+static inline const hb_ot_complex_shaper_t *
+hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
+{
+  switch ((hb_tag_t) planner->props.script)
+  {
+    default:
+      return &_hb_ot_complex_shaper_default;
+
+
+    /* Unicode-1.1 additions */
+    case HB_SCRIPT_ARABIC:
+
+    /* Unicode-3.0 additions */
+    case HB_SCRIPT_MONGOLIAN:
+    case HB_SCRIPT_SYRIAC:
+
+    /* Unicode-5.0 additions */
+    case HB_SCRIPT_NKO:
+    case HB_SCRIPT_PHAGS_PA:
+
+    /* Unicode-6.0 additions */
+    case HB_SCRIPT_MANDAIC:
+
+    /* Unicode-7.0 additions */
+    case HB_SCRIPT_MANICHAEAN:
+    case HB_SCRIPT_PSALTER_PAHLAVI:
+
+      /* For Arabic script, use the Arabic shaper even if no OT script tag was found.
+       * This is because we do fallback shaping for Arabic script (and not others).
+       * But note that Arabic shaping is applicable only to horizontal layout; for
+       * vertical text, just use the generic shaper instead. */
+      if ((planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT ||
+           planner->props.script == HB_SCRIPT_ARABIC) &&
+          HB_DIRECTION_IS_HORIZONTAL(planner->props.direction))
+        return &_hb_ot_complex_shaper_arabic;
+      else
+        return &_hb_ot_complex_shaper_default;
+
+
+    /* Unicode-1.1 additions */
+    case HB_SCRIPT_THAI:
+    case HB_SCRIPT_LAO:
+
+      return &_hb_ot_complex_shaper_thai;
+
+
+    /* Unicode-1.1 additions */
+    case HB_SCRIPT_HANGUL:
+
+      return &_hb_ot_complex_shaper_hangul;
+
+
+    /* Unicode-2.0 additions */
+    case HB_SCRIPT_TIBETAN:
+
+      return &_hb_ot_complex_shaper_tibetan;
+
+
+    /* Unicode-1.1 additions */
+    case HB_SCRIPT_HEBREW:
+
+      return &_hb_ot_complex_shaper_hebrew;
+
+
+    /* ^--- Add new shapers here */
+
+#if 0
+    /* Unicode-4.1 additions */
+    case HB_SCRIPT_NEW_TAI_LUE:
+#endif
+
+    /* Unicode-1.1 additions */
+    case HB_SCRIPT_BENGALI:
+    case HB_SCRIPT_DEVANAGARI:
+    case HB_SCRIPT_GUJARATI:
+    case HB_SCRIPT_GURMUKHI:
+    case HB_SCRIPT_KANNADA:
+    case HB_SCRIPT_MALAYALAM:
+    case HB_SCRIPT_ORIYA:
+    case HB_SCRIPT_TAMIL:
+    case HB_SCRIPT_TELUGU:
+
+    /* Unicode-3.0 additions */
+    case HB_SCRIPT_SINHALA:
+
+      /* If the designer designed the font for the 'DFLT' script,
+       * use the default shaper.  Otherwise, use the specific shaper.
+       * Note that for some simple scripts, there may not be *any*
+       * GSUB/GPOS needed, so there may be no scripts found! */
+      if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T'))
+        return &_hb_ot_complex_shaper_default;
+      else
+        return &_hb_ot_complex_shaper_indic;
+
+    case HB_SCRIPT_KHMER:
+      /* A number of Khmer fonts in the wild don't have a 'pref' feature,
+       * and as such won't shape properly via the Indic shaper;
+       * however, they typically have 'liga' / 'clig' features that implement
+       * the necessary "reordering" by means of ligature substitutions.
+       * So we send such pref-less fonts through the generic shaper instead. */
+      if (planner->map.found_script[0] &&
+          hb_ot_layout_language_find_feature (planner->face, HB_OT_TAG_GSUB,
+                                              planner->map.script_index[0],
+                                              planner->map.language_index[0],
+                                              HB_TAG ('p','r','e','f'),
+                                              NULL))
+        return &_hb_ot_complex_shaper_indic;
+      else
+        return &_hb_ot_complex_shaper_default;
+
+    case HB_SCRIPT_MYANMAR:
+      if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','2'))
+        return &_hb_ot_complex_shaper_myanmar;
+      else if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','r'))
+        return &_hb_ot_complex_shaper_myanmar_old;
+      else
+        return &_hb_ot_complex_shaper_default;
+
+
+    /* Unicode-2.0 additions */
+    //case HB_SCRIPT_TIBETAN:
+
+    /* Unicode-3.0 additions */
+    //case HB_SCRIPT_MONGOLIAN:
+    //case HB_SCRIPT_SINHALA:
+
+    /* Unicode-3.2 additions */
+    case HB_SCRIPT_BUHID:
+    case HB_SCRIPT_HANUNOO:
+    case HB_SCRIPT_TAGALOG:
+    case HB_SCRIPT_TAGBANWA:
+
+    /* Unicode-4.0 additions */
+    case HB_SCRIPT_LIMBU:
+    case HB_SCRIPT_TAI_LE:
+
+    /* Unicode-4.1 additions */
+    case HB_SCRIPT_BUGINESE:
+    case HB_SCRIPT_KHAROSHTHI:
+    case HB_SCRIPT_SYLOTI_NAGRI:
+    case HB_SCRIPT_TIFINAGH:
+
+    /* Unicode-5.0 additions */
+    case HB_SCRIPT_BALINESE:
+    //case HB_SCRIPT_NKO:
+    //case HB_SCRIPT_PHAGS_PA:
+
+    /* Unicode-5.1 additions */
+    case HB_SCRIPT_CHAM:
+    case HB_SCRIPT_KAYAH_LI:
+    case HB_SCRIPT_LEPCHA:
+    case HB_SCRIPT_REJANG:
+    case HB_SCRIPT_SAURASHTRA:
+    case HB_SCRIPT_SUNDANESE:
+
+    /* Unicode-5.2 additions */
+    case HB_SCRIPT_EGYPTIAN_HIEROGLYPHS:
+    case HB_SCRIPT_JAVANESE:
+    case HB_SCRIPT_KAITHI:
+    case HB_SCRIPT_MEETEI_MAYEK:
+    case HB_SCRIPT_TAI_THAM:
+    case HB_SCRIPT_TAI_VIET:
+
+    /* Unicode-6.0 additions */
+    case HB_SCRIPT_BATAK:
+    case HB_SCRIPT_BRAHMI:
+    //case HB_SCRIPT_MANDAIC:
+
+    /* Unicode-6.1 additions */
+    case HB_SCRIPT_CHAKMA:
+    case HB_SCRIPT_SHARADA:
+    case HB_SCRIPT_TAKRI:
+
+    /* Unicode-7.0 additions */
+    case HB_SCRIPT_DUPLOYAN:
+    case HB_SCRIPT_GRANTHA:
+    case HB_SCRIPT_KHOJKI:
+    case HB_SCRIPT_KHUDAWADI:
+    case HB_SCRIPT_MAHAJANI:
+    //case HB_SCRIPT_MANICHAEAN:
+    case HB_SCRIPT_MODI:
+    case HB_SCRIPT_PAHAWH_HMONG:
+    //case HB_SCRIPT_PSALTER_PAHLAVI:
+    case HB_SCRIPT_SIDDHAM:
+    case HB_SCRIPT_TIRHUTA:
+
+    /* Unicode-8.0 additions */
+    case HB_SCRIPT_AHOM:
+    //case HB_SCRIPT_MULTANI:
+
+    /* Unicode-9.0 additions */
+    case HB_SCRIPT_BHAIKSUKI:
+    case HB_SCRIPT_MARCHEN:
+    case HB_SCRIPT_NEWA:
+
+      /* If the designer designed the font for the 'DFLT' script,
+       * use the default shaper.  Otherwise, use the specific shaper.
+       * Note that for some simple scripts, there may not be *any*
+       * GSUB/GPOS needed, so there may be no scripts found! */
+      if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T'))
+        return &_hb_ot_complex_shaper_default;
+      else
+        return &_hb_ot_complex_shaper_use;
+  }
+}
+
+
+#endif /* HB_OT_SHAPE_COMPLEX_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-thai.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-thai.cpp
new file mode 100644
index 0000000..e4889d4
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-thai.cpp
@@ -0,0 +1,381 @@
+/*
+ * Copyright © 2010,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
+ */
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+/* Thai / Lao shaper */
+
+
+/* PUA shaping */
+
+
+enum thai_consonant_type_t
+{
+  NC,
+  AC,
+  RC,
+  DC,
+  NOT_CONSONANT,
+  NUM_CONSONANT_TYPES = NOT_CONSONANT
+};
+
+static thai_consonant_type_t
+get_consonant_type (hb_codepoint_t u)
+{
+  if (u == 0x0E1Bu || u == 0x0E1Du || u == 0x0E1Fu/* || u == 0x0E2Cu*/)
+    return AC;
+  if (u == 0x0E0Du || u == 0x0E10u)
+    return RC;
+  if (u == 0x0E0Eu || u == 0x0E0Fu)
+    return DC;
+  if (hb_in_range (u, 0x0E01u, 0x0E2Eu))
+    return NC;
+  return NOT_CONSONANT;
+}
+
+
+enum thai_mark_type_t
+{
+  AV,
+  BV,
+  T,
+  NOT_MARK,
+  NUM_MARK_TYPES = NOT_MARK
+};
+
+static thai_mark_type_t
+get_mark_type (hb_codepoint_t u)
+{
+  if (u == 0x0E31u || hb_in_range (u, 0x0E34u, 0x0E37u) ||
+      u == 0x0E47u || hb_in_range (u, 0x0E4Du, 0x0E4Eu))
+    return AV;
+  if (hb_in_range (u, 0x0E38u, 0x0E3Au))
+    return BV;
+  if (hb_in_range (u, 0x0E48u, 0x0E4Cu))
+    return T;
+  return NOT_MARK;
+}
+
+
+enum thai_action_t
+{
+  NOP,
+  SD,  /* Shift combining-mark down */
+  SL,  /* Shift combining-mark left */
+  SDL, /* Shift combining-mark down-left */
+  RD   /* Remove descender from base */
+};
+
+static hb_codepoint_t
+thai_pua_shape (hb_codepoint_t u, thai_action_t action, hb_font_t *font)
+{
+  struct thai_pua_mapping_t {
+    hb_codepoint_t u;
+    hb_codepoint_t win_pua;
+    hb_codepoint_t mac_pua;
+  } const *pua_mappings = NULL;
+  static const thai_pua_mapping_t SD_mappings[] = {
+    {0x0E48u, 0xF70Au, 0xF88Bu}, /* MAI EK */
+    {0x0E49u, 0xF70Bu, 0xF88Eu}, /* MAI THO */
+    {0x0E4Au, 0xF70Cu, 0xF891u}, /* MAI TRI */
+    {0x0E4Bu, 0xF70Du, 0xF894u}, /* MAI CHATTAWA */
+    {0x0E4Cu, 0xF70Eu, 0xF897u}, /* THANTHAKHAT */
+    {0x0E38u, 0xF718u, 0xF89Bu}, /* SARA U */
+    {0x0E39u, 0xF719u, 0xF89Cu}, /* SARA UU */
+    {0x0E3Au, 0xF71Au, 0xF89Du}, /* PHINTHU */
+    {0x0000u, 0x0000u, 0x0000u}
+  };
+  static const thai_pua_mapping_t SDL_mappings[] = {
+    {0x0E48u, 0xF705u, 0xF88Cu}, /* MAI EK */
+    {0x0E49u, 0xF706u, 0xF88Fu}, /* MAI THO */
+    {0x0E4Au, 0xF707u, 0xF892u}, /* MAI TRI */
+    {0x0E4Bu, 0xF708u, 0xF895u}, /* MAI CHATTAWA */
+    {0x0E4Cu, 0xF709u, 0xF898u}, /* THANTHAKHAT */
+    {0x0000u, 0x0000u, 0x0000u}
+  };
+  static const thai_pua_mapping_t SL_mappings[] = {
+    {0x0E48u, 0xF713u, 0xF88Au}, /* MAI EK */
+    {0x0E49u, 0xF714u, 0xF88Du}, /* MAI THO */
+    {0x0E4Au, 0xF715u, 0xF890u}, /* MAI TRI */
+    {0x0E4Bu, 0xF716u, 0xF893u}, /* MAI CHATTAWA */
+    {0x0E4Cu, 0xF717u, 0xF896u}, /* THANTHAKHAT */
+    {0x0E31u, 0xF710u, 0xF884u}, /* MAI HAN-AKAT */
+    {0x0E34u, 0xF701u, 0xF885u}, /* SARA I */
+    {0x0E35u, 0xF702u, 0xF886u}, /* SARA II */
+    {0x0E36u, 0xF703u, 0xF887u}, /* SARA UE */
+    {0x0E37u, 0xF704u, 0xF888u}, /* SARA UEE */
+    {0x0E47u, 0xF712u, 0xF889u}, /* MAITAIKHU */
+    {0x0E4Du, 0xF711u, 0xF899u}, /* NIKHAHIT */
+    {0x0000u, 0x0000u, 0x0000u}
+  };
+  static const thai_pua_mapping_t RD_mappings[] = {
+    {0x0E0Du, 0xF70Fu, 0xF89Au}, /* YO YING */
+    {0x0E10u, 0xF700u, 0xF89Eu}, /* THO THAN */
+    {0x0000u, 0x0000u, 0x0000u}
+  };
+
+  switch (action) {
+    case NOP: return u;
+    case SD:  pua_mappings = SD_mappings; break;
+    case SDL: pua_mappings = SDL_mappings; break;
+    case SL:  pua_mappings = SL_mappings; break;
+    case RD:  pua_mappings = RD_mappings; break;
+  }
+  for (; pua_mappings->u; pua_mappings++)
+    if (pua_mappings->u == u)
+    {
+      hb_codepoint_t glyph;
+      if (hb_font_get_glyph (font, pua_mappings->win_pua, 0, &glyph))
+        return pua_mappings->win_pua;
+      if (hb_font_get_glyph (font, pua_mappings->mac_pua, 0, &glyph))
+        return pua_mappings->mac_pua;
+      break;
+    }
+  return u;
+}
+
+
+static enum thai_above_state_t
+{     /* Cluster above looks like: */
+  T0, /*  ⣤                      */
+  T1, /*     ⣼                   */
+  T2, /*        ⣾                */
+  T3, /*           ⣿             */
+  NUM_ABOVE_STATES
+} thai_above_start_state[NUM_CONSONANT_TYPES + 1/* For NOT_CONSONANT */] =
+{
+  T0, /* NC */
+  T1, /* AC */
+  T0, /* RC */
+  T0, /* DC */
+  T3, /* NOT_CONSONANT */
+};
+
+static const struct thai_above_state_machine_edge_t {
+  thai_action_t action;
+  thai_above_state_t next_state;
+} thai_above_state_machine[NUM_ABOVE_STATES][NUM_MARK_TYPES] =
+{        /*AV*/    /*BV*/    /*T*/
+/*T0*/ {{NOP,T3}, {NOP,T0}, {SD, T3}},
+/*T1*/ {{SL, T2}, {NOP,T1}, {SDL,T2}},
+/*T2*/ {{NOP,T3}, {NOP,T2}, {SL, T3}},
+/*T3*/ {{NOP,T3}, {NOP,T3}, {NOP,T3}},
+};
+
+
+static enum thai_below_state_t
+{
+  B0, /* No descender */
+  B1, /* Removable descender */
+  B2, /* Strict descender */
+  NUM_BELOW_STATES
+} thai_below_start_state[NUM_CONSONANT_TYPES + 1/* For NOT_CONSONANT */] =
+{
+  B0, /* NC */
+  B0, /* AC */
+  B1, /* RC */
+  B2, /* DC */
+  B2, /* NOT_CONSONANT */
+};
+
+static const struct thai_below_state_machine_edge_t {
+  thai_action_t action;
+  thai_below_state_t next_state;
+} thai_below_state_machine[NUM_BELOW_STATES][NUM_MARK_TYPES] =
+{        /*AV*/    /*BV*/    /*T*/
+/*B0*/ {{NOP,B0}, {NOP,B2}, {NOP, B0}},
+/*B1*/ {{NOP,B1}, {RD, B2}, {NOP, B1}},
+/*B2*/ {{NOP,B2}, {SD, B2}, {NOP, B2}},
+};
+
+
+static void
+do_thai_pua_shaping (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                     hb_buffer_t              *buffer,
+                     hb_font_t                *font)
+{
+  thai_above_state_t above_state = thai_above_start_state[NOT_CONSONANT];
+  thai_below_state_t below_state = thai_below_start_state[NOT_CONSONANT];
+  unsigned int base = 0;
+
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+  {
+    thai_mark_type_t mt = get_mark_type (info[i].codepoint);
+
+    if (mt == NOT_MARK) {
+      thai_consonant_type_t ct = get_consonant_type (info[i].codepoint);
+      above_state = thai_above_start_state[ct];
+      below_state = thai_below_start_state[ct];
+      base = i;
+      continue;
+    }
+
+    const thai_above_state_machine_edge_t &above_edge = thai_above_state_machine[above_state][mt];
+    const thai_below_state_machine_edge_t &below_edge = thai_below_state_machine[below_state][mt];
+    above_state = above_edge.next_state;
+    below_state = below_edge.next_state;
+
+    /* At least one of the above/below actions is NOP. */
+    thai_action_t action = above_edge.action != NOP ? above_edge.action : below_edge.action;
+
+    if (action == RD)
+      info[base].codepoint = thai_pua_shape (info[base].codepoint, action, font);
+    else
+      info[i].codepoint = thai_pua_shape (info[i].codepoint, action, font);
+  }
+}
+
+
+static void
+preprocess_text_thai (const hb_ot_shape_plan_t *plan,
+                      hb_buffer_t              *buffer,
+                      hb_font_t                *font)
+{
+  /* This function implements the shaping logic documented here:
+   *
+   *   http://linux.thai.net/~thep/th-otf/shaping.html
+   *
+   * The first shaping rule listed there is needed even if the font has Thai
+   * OpenType tables.  The rest do fallback positioning based on PUA codepoints.
+   * We implement that only if there exist no Thai GSUB in the font.
+   */
+
+  /* The following is NOT specified in the MS OT Thai spec, however, it seems
+   * to be what Uniscribe and other engines implement.  According to Eric Muller:
+   *
+   * When you have a SARA AM, decompose it in NIKHAHIT + SARA AA, *and* move the
+   * NIKHAHIT backwards over any tone mark (0E48-0E4B).
+   *
+   * <0E14, 0E4B, 0E33> -> <0E14, 0E4D, 0E4B, 0E32>
+   *
+   * This reordering is legit only when the NIKHAHIT comes from a SARA AM, not
+   * when it's there to start with. The string <0E14, 0E4B, 0E4D> is probably
+   * not what a user wanted, but the rendering is nevertheless nikhahit above
+   * chattawa.
+   *
+   * Same for Lao.
+   *
+   * Note:
+   *
+   * Uniscribe also does some below-marks reordering.  Namely, it positions U+0E3A
+   * after U+0E38 and U+0E39.  We do that by modifying the ccc for U+0E3A.
+   * See unicode->modified_combining_class ().  Lao does NOT have a U+0E3A
+   * equivalent.
+   */
+
+
+  /*
+   * Here are the characters of significance:
+   *
+   *                    Thai    Lao
+   * SARA AM:           U+0E33  U+0EB3
+   * SARA AA:           U+0E32  U+0EB2
+   * Nikhahit:          U+0E4D  U+0ECD
+   *
+   * Testing shows that Uniscribe reorder the following marks:
+   * Thai:      <0E31,0E34..0E37,0E47..0E4E>
+   * Lao:       <0EB1,0EB4..0EB7,0EC7..0ECE>
+   *
+   * Note how the Lao versions are the same as Thai + 0x80.
+   */
+
+  /* We only get one script at a time, so a script-agnostic implementation
+   * is adequate here. */
+#define IS_SARA_AM(x) (((x) & ~0x0080u) == 0x0E33u)
+#define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0x0E33u + 0x0E4Du)
+#define SARA_AA_FROM_SARA_AM(x) ((x) - 1)
+#define IS_TONE_MARK(x) (hb_in_ranges ((x) & ~0x0080u, 0x0E34u, 0x0E37u, 0x0E47u, 0x0E4Eu, 0x0E31u, 0x0E31u))
+
+  buffer->clear_output ();
+  unsigned int count = buffer->len;
+  for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
+  {
+    hb_codepoint_t u = buffer->cur().codepoint;
+    if (likely (!IS_SARA_AM (u))) {
+      buffer->next_glyph ();
+      continue;
+    }
+
+    /* Is SARA AM. Decompose and reorder. */
+    hb_codepoint_t decomposed[2] = {hb_codepoint_t (NIKHAHIT_FROM_SARA_AM (u)),
+                                    hb_codepoint_t (SARA_AA_FROM_SARA_AM (u))};
+    buffer->replace_glyphs (1, 2, decomposed);
+    if (unlikely (buffer->in_error))
+      return;
+
+    /* Make Nikhahit be recognized as a ccc=0 mark when zeroing widths. */
+    unsigned int end = buffer->out_len;
+    _hb_glyph_info_set_general_category (&buffer->out_info[end - 2], HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK);
+
+    /* Ok, let's see... */
+    unsigned int start = end - 2;
+    while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint))
+      start--;
+
+    if (start + 2 < end)
+    {
+      /* Move Nikhahit (end-2) to the beginning */
+      buffer->merge_out_clusters (start, end);
+      hb_glyph_info_t t = buffer->out_info[end - 2];
+      memmove (buffer->out_info + start + 1,
+               buffer->out_info + start,
+               sizeof (buffer->out_info[0]) * (end - start - 2));
+      buffer->out_info[start] = t;
+    }
+    else
+    {
+      /* Since we decomposed, and NIKHAHIT is combining, merge clusters with the
+       * previous cluster. */
+      if (start && buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+        buffer->merge_out_clusters (start - 1, end);
+    }
+  }
+  buffer->swap_buffers ();
+
+  /* If font has Thai GSUB, we are done. */
+  if (plan->props.script == HB_SCRIPT_THAI && !plan->map.found_script[0])
+    do_thai_pua_shaping (plan, buffer, font);
+}
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
+{
+  "thai",
+  NULL, /* collect_features */
+  NULL, /* override_features */
+  NULL, /* data_create */
+  NULL, /* data_destroy */
+  preprocess_text_thai,
+  NULL, /* postprocess_glyphs */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+  NULL, /* decompose */
+  NULL, /* compose */
+  NULL, /* setup_masks */
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
+  false,/* fallback_position */
+};
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-tibetan.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-tibetan.cpp
new file mode 100644
index 0000000..a77b531
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-tibetan.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright © 2010,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
+ */
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+static const hb_tag_t tibetan_features[] =
+{
+  HB_TAG('a','b','v','s'),
+  HB_TAG('b','l','w','s'),
+  HB_TAG('a','b','v','m'),
+  HB_TAG('b','l','w','m'),
+  HB_TAG_NONE
+};
+
+static void
+collect_features_tibetan (hb_ot_shape_planner_t *plan)
+{
+  for (const hb_tag_t *script_features = tibetan_features; script_features && *script_features; script_features++)
+    plan->map.add_global_bool_feature (*script_features);
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_tibetan =
+{
+  "default",
+  collect_features_tibetan,
+  NULL, /* override_features */
+  NULL, /* data_create */
+  NULL, /* data_destroy */
+  NULL, /* preprocess_text */
+  NULL, /* postprocess_glyphs */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+  NULL, /* decompose */
+  NULL, /* compose */
+  NULL, /* setup_masks */
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
+  true, /* fallback_position */
+};
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use-machine.hh b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use-machine.hh
new file mode 100644
index 0000000..97409f1
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use-machine.hh
@@ -0,0 +1,450 @@
+
+#line 1 "hb-ot-shape-complex-use-machine.rl"
+/*
+ * Copyright © 2015  Mozilla Foundation.
+ * Copyright © 2015  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
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
+#define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
+
+#include "hb-private.hh"
+
+
+#line 38 "hb-ot-shape-complex-use-machine.hh"
+static const unsigned char _use_syllable_machine_trans_keys[] = {
+        1u, 1u, 0u, 39u, 21u, 21u, 8u, 39u, 8u, 39u, 1u, 1u, 8u, 39u, 8u, 39u,
+        8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u,
+        8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 13u, 21u,
+        4u, 4u, 13u, 13u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 26u, 8u, 26u,
+        8u, 26u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u,
+        8u, 39u, 8u, 39u, 8u, 39u, 1u, 1u, 1u, 39u, 8u, 39u, 21u, 42u, 41u, 42u,
+        42u, 42u, 0
+};
+
+static const char _use_syllable_machine_key_spans[] = {
+        1, 40, 1, 32, 32, 1, 32, 32,
+        32, 19, 19, 19, 32, 32, 32, 32,
+        32, 32, 32, 32, 32, 32, 32, 9,
+        1, 1, 32, 32, 32, 32, 19, 19,
+        19, 32, 32, 32, 32, 32, 32, 32,
+        32, 32, 32, 1, 39, 32, 22, 2,
+        1
+};
+
+static const short _use_syllable_machine_index_offsets[] = {
+        0, 2, 43, 45, 78, 111, 113, 146,
+        179, 212, 232, 252, 272, 305, 338, 371,
+        404, 437, 470, 503, 536, 569, 602, 635,
+        645, 647, 649, 682, 715, 748, 781, 801,
+        821, 841, 874, 907, 940, 973, 1006, 1039,
+        1072, 1105, 1138, 1171, 1173, 1213, 1246, 1269,
+        1272
+};
+
+static const char _use_syllable_machine_indicies[] = {
+        1, 0, 2, 3, 4, 2, 5, 3,
+        4, 4, 6, 4, 4, 1, 7, 4,
+        4, 4, 2, 2, 8, 9, 4, 4,
+        10, 11, 12, 13, 14, 15, 16, 10,
+        17, 18, 19, 20, 21, 22, 4, 23,
+        24, 25, 4, 27, 26, 29, 28, 28,
+        30, 31, 28, 28, 28, 28, 28, 28,
+        28, 28, 32, 33, 34, 35, 36, 37,
+        38, 39, 33, 40, 32, 41, 42, 43,
+        44, 28, 45, 46, 47, 28, 29, 28,
+        28, 30, 31, 28, 28, 28, 28, 28,
+        28, 28, 28, 48, 33, 34, 35, 36,
+        37, 38, 39, 33, 40, 41, 41, 42,
+        43, 44, 28, 45, 46, 47, 28, 30,
+        49, 29, 28, 28, 30, 31, 28, 28,
+        28, 28, 28, 28, 28, 28, 28, 33,
+        34, 35, 36, 37, 38, 39, 33, 40,
+        41, 41, 42, 43, 44, 28, 45, 46,
+        47, 28, 29, 28, 28, 28, 28, 28,
+        28, 28, 28, 28, 28, 28, 28, 28,
+        33, 34, 35, 36, 37, 28, 28, 28,
+        28, 28, 28, 42, 43, 44, 28, 45,
+        46, 47, 28, 29, 28, 28, 28, 28,
+        28, 28, 28, 28, 28, 28, 28, 28,
+        28, 28, 34, 35, 36, 37, 28, 28,
+        28, 28, 28, 28, 28, 28, 28, 28,
+        45, 46, 47, 28, 29, 28, 28, 28,
+        28, 28, 28, 28, 28, 28, 28, 28,
+        28, 28, 28, 28, 35, 36, 37, 28,
+        29, 28, 28, 28, 28, 28, 28, 28,
+        28, 28, 28, 28, 28, 28, 28, 28,
+        28, 36, 37, 28, 29, 28, 28, 28,
+        28, 28, 28, 28, 28, 28, 28, 28,
+        28, 28, 28, 28, 28, 28, 37, 28,
+        29, 28, 28, 28, 28, 28, 28, 28,
+        28, 28, 28, 28, 28, 28, 28, 28,
+        35, 36, 37, 28, 28, 28, 28, 28,
+        28, 28, 28, 28, 28, 45, 46, 47,
+        28, 29, 28, 28, 28, 28, 28, 28,
+        28, 28, 28, 28, 28, 28, 28, 28,
+        28, 35, 36, 37, 28, 28, 28, 28,
+        28, 28, 28, 28, 28, 28, 28, 46,
+        47, 28, 29, 28, 28, 28, 28, 28,
+        28, 28, 28, 28, 28, 28, 28, 28,
+        28, 28, 35, 36, 37, 28, 28, 28,
+        28, 28, 28, 28, 28, 28, 28, 28,
+        28, 47, 28, 29, 28, 28, 28, 28,
+        28, 28, 28, 28, 28, 28, 28, 28,
+        28, 28, 34, 35, 36, 37, 28, 28,
+        28, 28, 28, 28, 42, 43, 44, 28,
+        45, 46, 47, 28, 29, 28, 28, 28,
+        28, 28, 28, 28, 28, 28, 28, 28,
+        28, 28, 28, 34, 35, 36, 37, 28,
+        28, 28, 28, 28, 28, 28, 43, 44,
+        28, 45, 46, 47, 28, 29, 28, 28,
+        28, 28, 28, 28, 28, 28, 28, 28,
+        28, 28, 28, 28, 34, 35, 36, 37,
+        28, 28, 28, 28, 28, 28, 28, 28,
+        44, 28, 45, 46, 47, 28, 29, 28,
+        28, 28, 28, 28, 28, 28, 28, 28,
+        28, 28, 28, 28, 33, 34, 35, 36,
+        37, 28, 39, 33, 28, 28, 28, 42,
+        43, 44, 28, 45, 46, 47, 28, 29,
+        28, 28, 28, 28, 28, 28, 28, 28,
+        28, 28, 28, 28, 28, 33, 34, 35,
+        36, 37, 28, 28, 33, 28, 28, 28,
+        42, 43, 44, 28, 45, 46, 47, 28,
+        29, 28, 28, 28, 28, 28, 28, 28,
+        28, 28, 28, 28, 28, 28, 33, 34,
+        35, 36, 37, 38, 39, 33, 28, 28,
+        28, 42, 43, 44, 28, 45, 46, 47,
+        28, 29, 28, 28, 30, 31, 28, 28,
+        28, 28, 28, 28, 28, 28, 28, 33,
+        34, 35, 36, 37, 38, 39, 33, 40,
+        28, 41, 42, 43, 44, 28, 45, 46,
+        47, 28, 29, 28, 28, 30, 31, 28,
+        28, 28, 28, 28, 28, 28, 28, 28,
+        33, 34, 35, 36, 37, 38, 39, 33,
+        40, 32, 41, 42, 43, 44, 28, 45,
+        46, 47, 28, 51, 50, 50, 50, 50,
+        50, 50, 50, 52, 50, 5, 53, 51,
+        50, 6, 54, 54, 1, 55, 54, 54,
+        54, 54, 54, 54, 54, 54, 56, 10,
+        11, 12, 13, 14, 15, 16, 10, 17,
+        19, 19, 20, 21, 22, 54, 23, 24,
+        25, 54, 6, 54, 54, 1, 55, 54,
+        54, 54, 54, 54, 54, 54, 54, 54,
+        10, 11, 12, 13, 14, 15, 16, 10,
+        17, 19, 19, 20, 21, 22, 54, 23,
+        24, 25, 54, 6, 54, 54, 54, 54,
+        54, 54, 54, 54, 54, 54, 54, 54,
+        54, 10, 11, 12, 13, 14, 54, 54,
+        54, 54, 54, 54, 20, 21, 22, 54,
+        23, 24, 25, 54, 6, 54, 54, 54,
+        54, 54, 54, 54, 54, 54, 54, 54,
+        54, 54, 54, 11, 12, 13, 14, 54,
+        54, 54, 54, 54, 54, 54, 54, 54,
+        54, 23, 24, 25, 54, 6, 54, 54,
+        54, 54, 54, 54, 54, 54, 54, 54,
+        54, 54, 54, 54, 54, 12, 13, 14,
+        54, 6, 54, 54, 54, 54, 54, 54,
+        54, 54, 54, 54, 54, 54, 54, 54,
+        54, 54, 13, 14, 54, 6, 54, 54,
+        54, 54, 54, 54, 54, 54, 54, 54,
+        54, 54, 54, 54, 54, 54, 54, 14,
+        54, 6, 54, 54, 54, 54, 54, 54,
+        54, 54, 54, 54, 54, 54, 54, 54,
+        54, 12, 13, 14, 54, 54, 54, 54,
+        54, 54, 54, 54, 54, 54, 23, 24,
+        25, 54, 6, 54, 54, 54, 54, 54,
+        54, 54, 54, 54, 54, 54, 54, 54,
+        54, 54, 12, 13, 14, 54, 54, 54,
+        54, 54, 54, 54, 54, 54, 54, 54,
+        24, 25, 54, 6, 54, 54, 54, 54,
+        54, 54, 54, 54, 54, 54, 54, 54,
+        54, 54, 54, 12, 13, 14, 54, 54,
+        54, 54, 54, 54, 54, 54, 54, 54,
+        54, 54, 25, 54, 6, 54, 54, 54,
+        54, 54, 54, 54, 54, 54, 54, 54,
+        54, 54, 54, 11, 12, 13, 14, 54,
+        54, 54, 54, 54, 54, 20, 21, 22,
+        54, 23, 24, 25, 54, 6, 54, 54,
+        54, 54, 54, 54, 54, 54, 54, 54,
+        54, 54, 54, 54, 11, 12, 13, 14,
+        54, 54, 54, 54, 54, 54, 54, 21,
+        22, 54, 23, 24, 25, 54, 6, 54,
+        54, 54, 54, 54, 54, 54, 54, 54,
+        54, 54, 54, 54, 54, 11, 12, 13,
+        14, 54, 54, 54, 54, 54, 54, 54,
+        54, 22, 54, 23, 24, 25, 54, 6,
+        54, 54, 54, 54, 54, 54, 54, 54,
+        54, 54, 54, 54, 54, 10, 11, 12,
+        13, 14, 54, 16, 10, 54, 54, 54,
+        20, 21, 22, 54, 23, 24, 25, 54,
+        6, 54, 54, 54, 54, 54, 54, 54,
+        54, 54, 54, 54, 54, 54, 10, 11,
+        12, 13, 14, 54, 54, 10, 54, 54,
+        54, 20, 21, 22, 54, 23, 24, 25,
+        54, 6, 54, 54, 54, 54, 54, 54,
+        54, 54, 54, 54, 54, 54, 54, 10,
+        11, 12, 13, 14, 15, 16, 10, 54,
+        54, 54, 20, 21, 22, 54, 23, 24,
+        25, 54, 6, 54, 54, 1, 55, 54,
+        54, 54, 54, 54, 54, 54, 54, 54,
+        10, 11, 12, 13, 14, 15, 16, 10,
+        17, 54, 19, 20, 21, 22, 54, 23,
+        24, 25, 54, 1, 57, 3, 54, 54,
+        54, 3, 54, 54, 6, 54, 54, 1,
+        55, 54, 54, 54, 54, 54, 54, 54,
+        54, 54, 10, 11, 12, 13, 14, 15,
+        16, 10, 17, 18, 19, 20, 21, 22,
+        54, 23, 24, 25, 54, 6, 54, 54,
+        1, 55, 54, 54, 54, 54, 54, 54,
+        54, 54, 54, 10, 11, 12, 13, 14,
+        15, 16, 10, 17, 18, 19, 20, 21,
+        22, 54, 23, 24, 25, 54, 59, 58,
+        58, 58, 58, 58, 58, 58, 58, 58,
+        58, 58, 58, 58, 58, 58, 58, 58,
+        58, 58, 59, 60, 58, 59, 60, 58,
+        60, 58, 0
+};
+
+static const char _use_syllable_machine_trans_targs[] = {
+        1, 26, 2, 3, 1, 23, 1, 43,
+        44, 46, 28, 29, 30, 31, 32, 39,
+        40, 41, 45, 42, 36, 37, 38, 33,
+        34, 35, 1, 1, 1, 1, 4, 5,
+        22, 7, 8, 9, 10, 11, 18, 19,
+        20, 21, 15, 16, 17, 12, 13, 14,
+        6, 1, 1, 24, 25, 1, 1, 0,
+        27, 1, 1, 47, 48
+};
+
+static const char _use_syllable_machine_trans_actions[] = {
+        1, 2, 0, 0, 5, 0, 6, 0,
+        2, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 2, 2, 0, 0, 0, 0,
+        0, 0, 7, 8, 9, 10, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 11, 12, 0, 0, 13, 14, 0,
+        2, 15, 16, 0, 0
+};
+
+static const char _use_syllable_machine_to_state_actions[] = {
+        0, 3, 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
+};
+
+static const char _use_syllable_machine_from_state_actions[] = {
+        0, 4, 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
+};
+
+static const short _use_syllable_machine_eof_trans[] = {
+        1, 0, 27, 29, 29, 50, 29, 29,
+        29, 29, 29, 29, 29, 29, 29, 29,
+        29, 29, 29, 29, 29, 29, 29, 51,
+        54, 51, 55, 55, 55, 55, 55, 55,
+        55, 55, 55, 55, 55, 55, 55, 55,
+        55, 55, 55, 58, 55, 55, 59, 59,
+        59
+};
+
+static const int use_syllable_machine_start = 1;
+static const int use_syllable_machine_first_final = 1;
+static const int use_syllable_machine_error = -1;
+
+static const int use_syllable_machine_en_main = 1;
+
+
+#line 38 "hb-ot-shape-complex-use-machine.rl"
+
+
+
+#line 138 "hb-ot-shape-complex-use-machine.rl"
+
+
+#define found_syllable(syllable_type) \
+  HB_STMT_START { \
+    if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
+    for (unsigned int i = last; i < p+1; i++) \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+    last = p+1; \
+    syllable_serial++; \
+    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+  } HB_STMT_END
+
+static void
+find_syllables (hb_buffer_t *buffer)
+{
+  unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
+  int cs;
+  hb_glyph_info_t *info = buffer->info;
+
+#line 315 "hb-ot-shape-complex-use-machine.hh"
+        {
+        cs = use_syllable_machine_start;
+        ts = 0;
+        te = 0;
+        act = 0;
+        }
+
+#line 159 "hb-ot-shape-complex-use-machine.rl"
+
+
+  p = 0;
+  pe = eof = buffer->len;
+
+  unsigned int last = 0;
+  unsigned int syllable_serial = 1;
+
+#line 332 "hb-ot-shape-complex-use-machine.hh"
+        {
+        int _slen;
+        int _trans;
+        const unsigned char *_keys;
+        const char *_inds;
+        if ( p == pe )
+                goto _test_eof;
+_resume:
+        switch ( _use_syllable_machine_from_state_actions[cs] ) {
+        case 4:
+#line 1 "NONE"
+        {ts = p;}
+        break;
+#line 346 "hb-ot-shape-complex-use-machine.hh"
+        }
+
+        _keys = _use_syllable_machine_trans_keys + (cs<<1);
+        _inds = _use_syllable_machine_indicies + _use_syllable_machine_index_offsets[cs];
+
+        _slen = _use_syllable_machine_key_spans[cs];
+        _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].use_category()) &&
+                ( info[p].use_category()) <= _keys[1] ?
+                ( info[p].use_category()) - _keys[0] : _slen ];
+
+_eof_trans:
+        cs = _use_syllable_machine_trans_targs[_trans];
+
+        if ( _use_syllable_machine_trans_actions[_trans] == 0 )
+                goto _again;
+
+        switch ( _use_syllable_machine_trans_actions[_trans] ) {
+        case 2:
+#line 1 "NONE"
+        {te = p+1;}
+        break;
+        case 8:
+#line 127 "hb-ot-shape-complex-use-machine.rl"
+        {te = p+1;{ found_syllable (independent_cluster); }}
+        break;
+        case 10:
+#line 129 "hb-ot-shape-complex-use-machine.rl"
+        {te = p+1;{ found_syllable (standard_cluster); }}
+        break;
+        case 6:
+#line 133 "hb-ot-shape-complex-use-machine.rl"
+        {te = p+1;{ found_syllable (broken_cluster); }}
+        break;
+        case 5:
+#line 134 "hb-ot-shape-complex-use-machine.rl"
+        {te = p+1;{ found_syllable (non_cluster); }}
+        break;
+        case 7:
+#line 127 "hb-ot-shape-complex-use-machine.rl"
+        {te = p;p--;{ found_syllable (independent_cluster); }}
+        break;
+        case 11:
+#line 128 "hb-ot-shape-complex-use-machine.rl"
+        {te = p;p--;{ found_syllable (virama_terminated_cluster); }}
+        break;
+        case 9:
+#line 129 "hb-ot-shape-complex-use-machine.rl"
+        {te = p;p--;{ found_syllable (standard_cluster); }}
+        break;
+        case 13:
+#line 130 "hb-ot-shape-complex-use-machine.rl"
+        {te = p;p--;{ found_syllable (number_joiner_terminated_cluster); }}
+        break;
+        case 12:
+#line 131 "hb-ot-shape-complex-use-machine.rl"
+        {te = p;p--;{ found_syllable (numeral_cluster); }}
+        break;
+        case 16:
+#line 132 "hb-ot-shape-complex-use-machine.rl"
+        {te = p;p--;{ found_syllable (symbol_cluster); }}
+        break;
+        case 14:
+#line 133 "hb-ot-shape-complex-use-machine.rl"
+        {te = p;p--;{ found_syllable (broken_cluster); }}
+        break;
+        case 15:
+#line 134 "hb-ot-shape-complex-use-machine.rl"
+        {te = p;p--;{ found_syllable (non_cluster); }}
+        break;
+        case 1:
+#line 133 "hb-ot-shape-complex-use-machine.rl"
+        {{p = ((te))-1;}{ found_syllable (broken_cluster); }}
+        break;
+#line 420 "hb-ot-shape-complex-use-machine.hh"
+        }
+
+_again:
+        switch ( _use_syllable_machine_to_state_actions[cs] ) {
+        case 3:
+#line 1 "NONE"
+        {ts = 0;}
+        break;
+#line 429 "hb-ot-shape-complex-use-machine.hh"
+        }
+
+        if ( ++p != pe )
+                goto _resume;
+        _test_eof: {}
+        if ( p == eof )
+        {
+        if ( _use_syllable_machine_eof_trans[cs] > 0 ) {
+                _trans = _use_syllable_machine_eof_trans[cs] - 1;
+                goto _eof_trans;
+        }
+        }
+
+        }
+
+#line 168 "hb-ot-shape-complex-use-machine.rl"
+
+}
+
+#undef found_syllable
+
+#endif /* HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use-private.hh b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use-private.hh
new file mode 100644
index 0000000..590fce2
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use-private.hh
@@ -0,0 +1,96 @@
+/*
+ * Copyright © 2015  Mozilla Foundation.
+ * Copyright © 2015  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
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH
+#define HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH
+
+#include "hb-private.hh"
+
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+#define USE_TABLE_ELEMENT_TYPE uint8_t
+
+/* Cateories used in the Universal Shaping Engine spec:
+ * https://www.microsoft.com/typography/OpenTypeDev/USE/intro.htm
+ */
+/* Note: This enum is duplicated in the -machine.rl source file.
+ * Not sure how to avoid duplication. */
+enum use_category_t {
+  USE_O         = 0,    /* OTHER */
+
+  USE_B         = 1,    /* BASE */
+  USE_IND       = 3,    /* BASE_IND */
+  USE_N         = 4,    /* BASE_NUM */
+  USE_GB        = 5,    /* BASE_OTHER */
+  USE_CGJ       = 6,    /* CGJ */
+//  USE_F               = 7,    /* CONS_FINAL */
+  USE_FM        = 8,    /* CONS_FINAL_MOD */
+//  USE_M               = 9,    /* CONS_MED */
+//  USE_CM      = 10,   /* CONS_MOD */
+  USE_SUB       = 11,   /* CONS_SUB */
+  USE_H         = 12,   /* HALANT */
+
+  USE_HN        = 13,   /* HALANT_NUM */
+  USE_ZWNJ      = 14,   /* Zero width non-joiner */
+  USE_ZWJ       = 15,   /* Zero width joiner */
+  USE_WJ        = 16,   /* Word joiner */
+  USE_Rsv       = 17,   /* Reserved characters */
+  USE_R         = 18,   /* REPHA */
+  USE_S         = 19,   /* SYM */
+//  USE_SM      = 20,   /* SYM_MOD */
+  USE_VS        = 21,   /* VARIATION_SELECTOR */
+//  USE_V       = 36,   /* VOWEL */
+//  USE_VM      = 40,   /* VOWEL_MOD */
+
+  USE_FAbv      = 24,   /* CONS_FINAL_ABOVE */
+  USE_FBlw      = 25,   /* CONS_FINAL_BELOW */
+  USE_FPst      = 26,   /* CONS_FINAL_POST */
+  USE_MAbv      = 27,   /* CONS_MED_ABOVE */
+  USE_MBlw      = 28,   /* CONS_MED_BELOW */
+  USE_MPst      = 29,   /* CONS_MED_POST */
+  USE_MPre      = 30,   /* CONS_MED_PRE */
+  USE_CMAbv     = 31,   /* CONS_MOD_ABOVE */
+  USE_CMBlw     = 32,   /* CONS_MOD_BELOW */
+  USE_VAbv      = 33,   /* VOWEL_ABOVE / VOWEL_ABOVE_BELOW / VOWEL_ABOVE_BELOW_POST / VOWEL_ABOVE_POST */
+  USE_VBlw      = 34,   /* VOWEL_BELOW / VOWEL_BELOW_POST */
+  USE_VPst      = 35,   /* VOWEL_POST   UIPC = Right */
+  USE_VPre      = 22,   /* VOWEL_PRE / VOWEL_PRE_ABOVE / VOWEL_PRE_ABOVE_POST / VOWEL_PRE_POST */
+  USE_VMAbv     = 37,   /* VOWEL_MOD_ABOVE */
+  USE_VMBlw     = 38,   /* VOWEL_MOD_BELOW */
+  USE_VMPst     = 39,   /* VOWEL_MOD_POST */
+  USE_VMPre     = 23,   /* VOWEL_MOD_PRE */
+  USE_SMAbv     = 41,   /* SYM_MOD_ABOVE */
+  USE_SMBlw     = 42    /* SYM_MOD_BELOW */
+};
+
+HB_INTERNAL USE_TABLE_ELEMENT_TYPE
+hb_use_get_categories (hb_codepoint_t u);
+
+#endif /* HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use-table.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use-table.cpp
new file mode 100644
index 0000000..645576f
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use-table.cpp
@@ -0,0 +1,734 @@
+/* == Start of generated table == */
+/*
+ * The following table is generated by running:
+ *
+ *   ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt
+ *
+ * on files with these headers:
+ *
+ * # IndicSyllabicCategory-9.0.0.txt
+ * # Date: 2016-05-21, 02:46:00 GMT [RP]
+ * # IndicPositionalCategory-9.0.0.txt
+ * # Date: 2016-02-25, 00:48:00 GMT [RP]
+ * # Blocks-9.0.0.txt
+ * # Date: 2016-02-05, 23:48:00 GMT [KW]
+ * UnicodeData.txt does not have a header.
+ */
+
+#include "hb-ot-shape-complex-use-private.hh"
+
+#define B       USE_B   /* BASE */
+#define CGJ     USE_CGJ /* CGJ */
+#define FM      USE_FM  /* CONS_FINAL_MOD */
+#define GB      USE_GB  /* BASE_OTHER */
+#define H       USE_H   /* HALANT */
+#define HN      USE_HN  /* HALANT_NUM */
+#define IND     USE_IND /* BASE_IND */
+#define N       USE_N   /* BASE_NUM */
+#define O       USE_O   /* OTHER */
+#define R       USE_R   /* REPHA */
+#define Rsv     USE_Rsv /* Reserved */
+#define S       USE_S   /* SYM */
+#define SUB     USE_SUB /* CONS_SUB */
+#define VS      USE_VS  /* VARIATION_SELECTOR */
+#define WJ      USE_WJ  /* Word_Joiner */
+#define ZWJ     USE_ZWJ /* ZWJ */
+#define ZWNJ    USE_ZWNJ        /* ZWNJ */
+#define CMBlw   USE_CMBlw
+#define CMAbv   USE_CMAbv
+#define FBlw    USE_FBlw
+#define FPst    USE_FPst
+#define FAbv    USE_FAbv
+#define MPre    USE_MPre
+#define MBlw    USE_MBlw
+#define MPst    USE_MPst
+#define MAbv    USE_MAbv
+#define SMBlw   USE_SMBlw
+#define SMAbv   USE_SMAbv
+#define VPre    USE_VPre
+#define VBlw    USE_VBlw
+#define VPst    USE_VPst
+#define VAbv    USE_VAbv
+#define VMPre   USE_VMPre
+#define VMBlw   USE_VMBlw
+#define VMPst   USE_VMPst
+#define VMAbv   USE_VMAbv
+
+static const USE_TABLE_ELEMENT_TYPE use_table[] = {
+
+
+#define use_offset_0x0028u 0
+
+
+  /* Basic Latin */
+                                                                         O,     O,     O,     O,     O,    GB,     O,     O,
+  /* 0030 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+
+#define use_offset_0x00a0u 24
+
+
+  /* Latin-1 Supplement */
+
+  /* 00A0 */    GB,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 00B0 */     O,     O,    FM,    FM,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 00C0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 00D0 */     O,     O,     O,     O,     O,     O,     O,    GB,
+
+#define use_offset_0x0900u 80
+
+
+  /* Devanagari */
+
+  /* 0900 */ VMAbv, VMAbv, VMAbv, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0910 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0920 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0930 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VAbv,  VPst, CMBlw,     B,  VPst,  VPre,
+  /* 0940 */  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,  VPst,  VPst,  VPst,  VPst,     H,  VPre,  VPst,
+  /* 0950 */     O, VMAbv, VMBlw,     O,     O,  VAbv,  VBlw,  VBlw,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0960 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0970 */     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+
+  /* Bengali */
+
+  /* 0980 */     O, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     B,
+  /* 0990 */     B,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 09A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
+  /* 09B0 */     B,     O,     B,     O,     O,     O,     B,     B,     B,     B,     O,     O, CMBlw,     B,  VPst,  VPre,
+  /* 09C0 */  VPst,  VBlw,  VBlw,  VBlw,  VBlw,     O,     O,  VPre,  VPre,     O,     O,  VPre,  VPre,     H,   IND,     O,
+  /* 09D0 */     O,     O,     O,     O,     O,     O,     O,  VPst,     O,     O,     O,     O,     B,     B,     O,     B,
+  /* 09E0 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 09F0 */     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Gurmukhi */
+
+  /* 0A00 */     O, VMAbv, VMAbv, VMPst,     O,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     B,
+  /* 0A10 */     B,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
+  /* 0A30 */     B,     O,     B,     B,     O,     B,     B,     O,     B,     B,     O,     O, CMBlw,     O,  VPst,  VPre,
+  /* 0A40 */  VPst,  VBlw,  VBlw,     O,     O,     O,     O,  VAbv,  VAbv,     O,     O,  VAbv,  VAbv,     H,     O,     O,
+  /* 0A50 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     O,     B,     O,
+  /* 0A60 */     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0A70 */ VMAbv, CMAbv,    GB,    GB,     O,  MBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Gujarati */
+
+  /* 0A80 */     O, VMAbv, VMAbv, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,
+  /* 0A90 */     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0AA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
+  /* 0AB0 */     B,     O,     B,     B,     O,     B,     B,     B,     B,     B,     O,     O, CMBlw,     B,  VPst,  VPre,
+  /* 0AC0 */  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,     O,  VAbv,  VAbv,  VAbv,     O,  VPst,  VPst,     H,     O,     O,
+  /* 0AD0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 0AE0 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0AF0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     B,     O,     O,     O,     O,     O,     O,
+
+  /* Oriya */
+
+  /* 0B00 */     O, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     B,
+  /* 0B10 */     B,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0B20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
+  /* 0B30 */     B,     O,     B,     B,     O,     B,     B,     B,     B,     B,     O,     O, CMBlw,     B,  VPst,  VAbv,
+  /* 0B40 */  VPst,  VBlw,  VBlw,  VBlw,  VBlw,     O,     O,  VPre,  VPre,     O,     O,  VPre,  VPre,     H,     O,     O,
+  /* 0B50 */     O,     O,     O,     O,     O,     O,  VAbv,  VAbv,     O,     O,     O,     O,     B,     B,     O,     B,
+  /* 0B60 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0B70 */     O,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Tamil */
+
+  /* 0B80 */     O,     O, VMAbv,   IND,     O,     B,     B,     B,     B,     B,     B,     O,     O,     O,     B,     B,
+  /* 0B90 */     B,     O,     B,     B,     B,     B,     O,     O,     O,     B,     B,     O,     B,     O,     B,     B,
+  /* 0BA0 */     O,     O,     O,     B,     B,     O,     O,     O,     B,     B,     B,     O,     O,     O,     B,     B,
+  /* 0BB0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,  VPst,  VPst,
+  /* 0BC0 */  VAbv,  VPst,  VPst,     O,     O,     O,  VPre,  VPre,  VPre,     O,  VPre,  VPre,  VPre,     H,     O,     O,
+  /* 0BD0 */     O,     O,     O,     O,     O,     O,     O,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 0BE0 */     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0BF0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Telugu */
+
+  /* 0C00 */ VMAbv, VMPst, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
+  /* 0C10 */     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0C20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
+  /* 0C30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     B,  VAbv,  VAbv,
+  /* 0C40 */  VAbv,  VPst,  VPst,  VPst,  VPst,     O,  VAbv,  VAbv,  VAbv,     O,  VAbv,  VAbv,  VAbv,     H,     O,     O,
+  /* 0C50 */     O,     O,     O,     O,     O,  VAbv,  VBlw,     O,     B,     B,     B,     O,     O,     O,     O,     O,
+  /* 0C60 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0C70 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Kannada */
+
+  /* 0C80 */     O, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
+  /* 0C90 */     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0CA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
+  /* 0CB0 */     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     O,     O, CMBlw,     B,  VPst,  VAbv,
+  /* 0CC0 */  VAbv,  VPst,  VPst,  VPst,  VPst,     O,  VAbv,  VAbv,  VAbv,     O,  VAbv,  VAbv,  VAbv,     H,     O,     O,
+  /* 0CD0 */     O,     O,     O,     O,     O,  VPst,  VPst,     O,     O,     O,     O,     O,     O,     O,     B,     O,
+  /* 0CE0 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0CF0 */     O,     R,     R,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Malayalam */
+
+  /* 0D00 */     O, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
+  /* 0D10 */     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0D20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0D30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     B,  VPst,  VPst,
+  /* 0D40 */  VPst,  VPst,  VPst,  VBlw,  VBlw,     O,  VPre,  VPre,  VPre,     O,  VPre,  VPre,  VPre,     H,     R,     O,
+  /* 0D50 */     O,     O,     O,     O,   IND,   IND,   IND,  VPst,     O,     O,     O,     O,     O,     O,     O,     B,
+  /* 0D60 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0D70 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,   IND,   IND,   IND,   IND,   IND,   IND,
+
+  /* Sinhala */
+
+  /* 0D80 */     O,     O, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0D90 */     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     B,     B,     B,     B,     B,     B,
+  /* 0DA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0DB0 */     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     O,     O,
+  /* 0DC0 */     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     H,     O,     O,     O,     O,  VPst,
+  /* 0DD0 */  VPst,  VPst,  VAbv,  VAbv,  VBlw,     O,  VBlw,     O,  VPst,  VPre,  VPre,  VPre,  VPre,  VPre,  VPre,  VPst,
+  /* 0DE0 */     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0DF0 */     O,     O,  VPst,  VPst,     O,     O,     O,     O,
+
+#define use_offset_0x1000u 1352
+
+
+  /* Myanmar */
+
+  /* 1000 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1010 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1020 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPst,  VPst,  VAbv,  VAbv,  VBlw,
+  /* 1030 */  VBlw,  VPre,  VAbv,  VAbv,  VAbv,  VAbv, VMAbv, VMBlw, VMPst,     H,  VAbv,  MPst,  MPre,  MBlw,  MBlw,     B,
+  /* 1040 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,    GB,     O,
+  /* 1050 */     B,     B,     B,     B,     B,     B,  VPst,  VPst,  VBlw,  VBlw,     B,     B,     B,     B,  MBlw,  MBlw,
+  /* 1060 */  MBlw,     B,  VPst, VMPst, VMPst,     B,     B,  VPst,  VPst, VMPst, VMPst, VMPst, VMPst, VMPst,     B,     B,
+  /* 1070 */     B,  VAbv,  VAbv,  VAbv,  VAbv,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1080 */     B,     B,  MBlw,  VPst,  VPre,  VAbv,  VAbv, VMPst, VMPst, VMPst, VMPst, VMPst, VMPst, VMBlw,     B, VMPst,
+  /* 1090 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B, VMPst, VMPst,  VPst,  VAbv,     O,     O,
+
+#define use_offset_0x1700u 1512
+
+
+  /* Tagalog */
+
+  /* 1700 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
+  /* 1710 */     B,     B,  VAbv,  VBlw,  VBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Hanunoo */
+
+  /* 1720 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1730 */     B,     B,  VAbv,  VBlw,  VBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Buhid */
+
+  /* 1740 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1750 */     B,     B,  VAbv,  VBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Tagbanwa */
+
+  /* 1760 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
+  /* 1770 */     B,     O,  VAbv,  VBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Khmer */
+
+  /* 1780 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1790 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 17A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 17B0 */     B,     B,     B,     B,     O,     O,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VPre,  VPre,
+  /* 17C0 */  VPre,  VPre,  VPre,  VPre,  VPre,  VPre, VMAbv, VMPst,  VPst, VMAbv, VMAbv,    FM,  FAbv, CMAbv,    FM,    FM,
+  /* 17D0 */    FM,  VAbv,     H,    FM,     O,     O,     O,     O,     O,     O,     O,     O,     B,  VAbv,     O,     O,
+  /* 17E0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+
+#define use_offset_0x1900u 1752
+
+
+  /* Limbu */
+
+  /* 1900 */    GB,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1910 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,
+  /* 1920 */  VAbv,  VAbv,  VBlw,  VPst,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,   SUB,   SUB,   SUB,     O,     O,     O,     O,
+  /* 1930 */  FPst,  FPst, VMBlw,  FPst,  FPst,  FPst,  FPst,  FPst,  FPst,  FBlw,  VAbv,    FM,     O,     O,     O,     O,
+  /* 1940 */     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+
+  /* Tai Le */
+
+  /* 1950 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1960 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,
+  /* 1970 */     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* New Tai Lue */
+
+  /* 1980 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1990 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 19A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,
+  /* 19B0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 19C0 */     B,     B,     B,     B,     B,     B,     B,     B, VMPst, VMPst,     O,     O,     O,     O,     O,     O,
+  /* 19D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+  /* 19E0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 19F0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Buginese */
+
+  /* 1A00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1A10 */     B,     B,     B,     B,     B,     B,     B,  VAbv,  VBlw,  VPre,  VPst,  VAbv,     O,     O,     O,     O,
+
+  /* Tai Tham */
+
+  /* 1A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1A30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1A40 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1A50 */     B,     B,     B,     B,     B,  MPre,  MBlw,  FPst,  FAbv,  FAbv,  FAbv,  FBlw,  FBlw,  FBlw,  FBlw,     O,
+  /* 1A60 */     H,  VPst,  VAbv,  VPst,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VAbv,  VBlw,  VPst,  VPre,  VPre,
+  /* 1A70 */  VPre,  VPre,  VPre,  VAbv,  VAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,    FM,    FM,    FM,     O,     O,    FM,
+  /* 1A80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+  /* 1A90 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+
+#define use_offset_0x1b00u 2168
+
+
+  /* Balinese */
+
+  /* 1B00 */ VMAbv, VMAbv, VMAbv,  FAbv, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1B10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1B20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1B30 */     B,     B,     B,     B, CMAbv,  VPst,  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VPre,  VPre,
+  /* 1B40 */  VPre,  VPre,  VAbv,  VAbv,     H,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,
+  /* 1B50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+  /* 1B60 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv,
+  /* 1B70 */ SMAbv, SMAbv, SMAbv, SMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Sundanese */
+
+  /* 1B80 */ VMAbv,  FAbv, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1B90 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1BA0 */     B,   SUB,   SUB,   SUB,  VAbv,  VBlw,  VPre,  VPst,  VAbv,  VAbv,  VPst,     H,   SUB,   SUB,     B,     B,
+  /* 1BB0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+
+  /* Batak */
+
+  /* 1BC0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1BD0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1BE0 */     B,     B,     B,     B,     B,     B, CMAbv,  VPst,  VAbv,  VAbv,  VPst,  VPst,  VPst,  VAbv,  VPst,  VAbv,
+  /* 1BF0 */  FAbv,  FAbv,  VPst,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Lepcha */
+
+  /* 1C00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1C10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1C20 */     B,     B,     B,     B,   SUB,   SUB,  VPst,  VPre,  VPre,  VPre,  VPst,  VPst,  VBlw,  FAbv,  FAbv,  FAbv,
+  /* 1C30 */  FAbv,  FAbv,  FAbv,  FAbv, VMPre, VMPre,    FM, CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 1C40 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     B,     B,     B,
+
+#define use_offset_0x1cd0u 2504
+
+
+  /* Vedic Extensions */
+
+  /* 1CD0 */ VMAbv, VMAbv, VMAbv,     O, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMAbv, VMAbv, VMBlw, VMBlw, VMBlw, VMBlw,
+  /* 1CE0 */ VMAbv, VMPst, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw,     O,     O,     O,     O, VMBlw,     O,     O,
+  /* 1CF0 */     O,     O, VMPst, VMPst, VMAbv,     O,     O,     O, VMAbv, VMAbv,     O,     O,     O,     O,     O,     O,
+
+#define use_offset_0x1df8u 2552
+
+
+  /* Combining Diacritical Marks Supplement */
+                                                                         O,     O,     O,    FM,     O,     O,     O,     O,
+
+#define use_offset_0x2008u 2560
+
+
+  /* General Punctuation */
+                                                                         O,     O,     O,     O,  ZWNJ,   ZWJ,     O,     O,
+  /* 2010 */    GB,    GB,    GB,    GB,    GB,     O,     O,     O,
+
+#define use_offset_0x2060u 2576
+
+  /* 2060 */    WJ,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Superscripts and Subscripts */
+
+  /* 2070 */     O,     O,     O,     O,    FM,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 2080 */     O,     O,    FM,    FM,    FM,     O,     O,     O,
+
+#define use_offset_0xa800u 2616
+
+
+  /* Syloti Nagri */
+
+  /* A800 */     B,     B,     O,     B,     B,     B,  VAbv,     B,     B,     B,     B, VMAbv,     B,     B,     B,     B,
+  /* A810 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A820 */     B,     B,     B,  VPst,  VPst,  VBlw,  VAbv,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* A830 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Phags-pa */
+
+  /* A840 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A850 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A860 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A870 */     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Saurashtra */
+
+  /* A880 */ VMPst, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A890 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A8A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A8B0 */     B,     B,     B,     B,  FPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,
+  /* A8C0 */  VPst,  VPst,  VPst,  VPst,     H, VMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* A8D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+
+  /* Devanagari Extended */
+
+  /* A8E0 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,
+  /* A8F0 */ VMAbv, VMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Kayah Li */
+
+  /* A900 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A910 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A920 */     B,     B,     B,     B,     B,     B,  VAbv,  VAbv,  VAbv,  VAbv,  VAbv, VMBlw, VMBlw, VMBlw,     O,     O,
+
+  /* Rejang */
+
+  /* A930 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A940 */     B,     B,     B,     B,     B,     B,     B,  VBlw,  VBlw,  VBlw,  VAbv,  VBlw,  VBlw,  VBlw,  VBlw,  FAbv,
+  /* A950 */  FAbv,  FAbv,  FPst,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* A960 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* A970 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Javanese */
+
+  /* A980 */ VMAbv, VMAbv,  FAbv, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A990 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A9A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A9B0 */     B,     B,     B, CMAbv,  VPst,  VPst,  VAbv,  VAbv,  VBlw,  VBlw,  VPre,  VPre,  VAbv,   SUB,  MPst,  MPst,
+  /* A9C0 */     H,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* A9D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+
+  /* Myanmar Extended-B */
+
+  /* A9E0 */     B,     B,     B,     B,     B,  VAbv,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A9F0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,
+
+  /* Cham */
+
+  /* AA00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* AA10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* AA20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VAbv,  VPre,
+  /* AA30 */  VPre,  VAbv,  VBlw,  MPst,  MPre,  MBlw,  MBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* AA40 */     B,     B,     B,  FAbv,     B,     B,     B,     B,     B,     B,     B,     B,  FAbv,  FPst,     O,     O,
+  /* AA50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+
+  /* Myanmar Extended-A */
+
+  /* AA60 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* AA70 */     O,     B,     B,     B,    GB,    GB,    GB,     O,     O,     O,     B, VMPst, VMAbv, VMPst,     B,     B,
+
+  /* Tai Viet */
+
+  /* AA80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* AA90 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* AAA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* AAB0 */  VAbv,     B,  VAbv,  VAbv,  VBlw,     B,     B,  VAbv,  VAbv,     B,     B,     B,     B,     B,  VAbv, VMAbv,
+  /* AAC0 */     B, VMAbv,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* AAD0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Meetei Mayek Extensions */
+
+  /* AAE0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPre,  VBlw,  VAbv,  VPre,  VPst,
+  /* AAF0 */     O,     O,     O,     O,     O, VMPst,     H,     O,
+
+#define use_offset_0xabc0u 3376
+
+
+  /* Meetei Mayek */
+
+  /* ABC0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* ABD0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* ABE0 */     B,     B,     B,  VPst,  VPst,  VAbv,  VPst,  VPst,  VBlw,  VPst,  VPst,     O, VMPst,  VBlw,     O,     O,
+  /* ABF0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+
+#define use_offset_0xfe00u 3440
+
+
+  /* Variation Selectors */
+
+  /* FE00 */    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,
+
+#define use_offset_0x10a00u 3456
+
+
+  /* Kharoshthi */
+
+  /* 10A00 */     B,  VBlw,  VBlw,  VBlw,     O,  VAbv,  VBlw,     O,     O,     O,     O,     O,  VBlw,  VBlw, VMBlw, VMAbv,
+  /* 10A10 */     B,     B,     B,     B,     O,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,
+  /* 10A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 10A30 */     B,     B,     B,     B,     O,     O,     O,     O, CMAbv, CMBlw, CMBlw,     O,     O,     O,     O,     H,
+  /* 10A40 */     B,     B,     B,     B,     B,     B,     B,     B,
+
+#define use_offset_0x11000u 3528
+
+
+  /* Brahmi */
+
+  /* 11000 */ VMPst, VMAbv, VMPst,     R,     R,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11010 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11020 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11030 */     B,     B,     B,     B,     B,     B,     B,     B,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VBlw,
+  /* 11040 */  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,     H,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 11050 */     O,     O,     N,     N,     N,     N,     N,     N,     N,     N,     N,     N,     N,     N,     N,     N,
+  /* 11060 */     N,     N,     N,     N,     N,     N,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11070 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Kaithi */
+
+  /* 11080 */ VMAbv, VMAbv, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11090 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 110A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 110B0 */  VPst,  VPre,  VPst,  VBlw,  VBlw,  VAbv,  VAbv,  VPst,  VPst,     H, CMBlw,     O,     O,     O,     O,     O,
+
+#define use_offset_0x11100u 3720
+
+
+  /* Chakma */
+
+  /* 11100 */ VMAbv, VMAbv, VMAbv,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11110 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11120 */     B,     B,     B,     B,     B,     B,     B,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VPre,  VAbv,  VAbv,  VAbv,
+  /* 11130 */  VAbv,  VBlw,  VBlw,     H,  VAbv,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11140 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Mahajani */
+
+  /* 11150 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11160 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11170 */     B,     B,     B, CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Sharada */
+
+  /* 11180 */ VMAbv, VMAbv, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11190 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 111A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 111B0 */     B,     B,     B,  VPst,  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,
+  /* 111C0 */     H,     B,     R,     R,     O,     O,     O,     O,     O,     O, CMBlw,  VAbv,  VBlw,     O,     O,     O,
+  /* 111D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+
+  /* Sinhala Archaic Numbers */
+
+  /* 111E0 */     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 111F0 */     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Khojki */
+
+  /* 11200 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11210 */     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11220 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPst,  VPst,  VPst,  VBlw,
+  /* 11230 */  VAbv,  VAbv,  VAbv,  VAbv, VMAbv,     H, CMAbv, CMAbv,     O,     O,     O,     O,     O,     O, VMAbv,     O,
+
+#define use_offset_0x11280u 4040
+
+
+  /* Multani */
+
+  /* 11280 */     B,     B,     B,     B,     B,     B,     B,     O,     B,     O,     B,     B,     B,     B,     O,     B,
+  /* 11290 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,
+  /* 112A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Khudawadi */
+
+  /* 112B0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 112C0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 112D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B, VMAbv,
+  /* 112E0 */  VPst,  VPre,  VPst,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv, CMBlw,  VBlw,     O,     O,     O,     O,     O,
+  /* 112F0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+
+  /* Grantha */
+
+  /* 11300 */ VMAbv, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     B,
+  /* 11310 */     B,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11320 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
+  /* 11330 */     B,     O,     B,     B,     O,     B,     B,     B,     B,     B,     O,     O, CMBlw,     B,  VPst,  VPst,
+  /* 11340 */  VAbv,  VPst,  VPst,  VPst,  VPst,     O,     O,  VPre,  VPre,     O,     O,  VPre,  VPre,     H,     O,     O,
+  /* 11350 */     O,     O,     O,     O,     O,     O,     O,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 11360 */     B,     B,  VPst,  VPst,     O,     O, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,     O,     O,     O,
+  /* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,     O,     O,     O,
+
+#define use_offset_0x11400u 4288
+
+
+  /* Newa */
+
+  /* 11400 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11410 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11420 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11430 */     B,     B,     B,     B,     B,  VPst,  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,
+  /* 11440 */  VPst,  VPst,     H, VMAbv, VMAbv, VMPst, CMBlw,     B,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 11450 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+  /* 11460 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 11470 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Tirhuta */
+
+  /* 11480 */     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11490 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 114A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 114B0 */  VPst,  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VPre,  VAbv,  VPre,  VPre,  VPst,  VPre, VMAbv,
+  /* 114C0 */ VMAbv, VMPst,     H, CMBlw,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 114D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+
+#define use_offset_0x11580u 4512
+
+
+  /* Siddham */
+
+  /* 11580 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11590 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 115A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPst,
+  /* 115B0 */  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,     O,     O,  VPre,  VPre,  VPre,  VPre, VMAbv, VMAbv, VMPst,     H,
+  /* 115C0 */ CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 115D0 */     O,     O,     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,  VBlw,  VBlw,     O,     O,
+  /* 115E0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 115F0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Modi */
+
+  /* 11600 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11610 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11620 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11630 */  VPst,  VPst,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VPst,  VPst, VMAbv, VMPst,     H,
+  /* 11640 */  VAbv,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 11650 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+  /* 11660 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 11670 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Takri */
+
+  /* 11680 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11690 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 116A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B, VMAbv, VMPst,  VAbv,  VPre,  VPst,
+  /* 116B0 */  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,     H, CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 116C0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+  /* 116D0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 116E0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 116F0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Ahom */
+
+  /* 11700 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11710 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,  MBlw,  MPre,  MAbv,
+  /* 11720 */  VPst,  VPst,  VAbv,  VAbv,  VBlw,  VBlw,  VPre,  VAbv,  VBlw,  VAbv,  VAbv,  VAbv,     O,     O,     O,     O,
+  /* 11730 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,
+
+#define use_offset_0x11c00u 4960
+
+
+  /* Bhaiksuki */
+
+  /* 11C00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
+  /* 11C10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11C20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPst,
+  /* 11C30 */  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,     O,  VAbv,  VAbv,  VAbv,  VAbv, VMAbv, VMAbv, VMPst,     H,
+  /* 11C40 */     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 11C50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11C60 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,
+
+  /* Marchen */
+
+  /* 11C70 */     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11C80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11C90 */     O,     O,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,
+  /* 11CA0 */   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,     O,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,
+  /* 11CB0 */  VBlw,  VPre,  VBlw,  VAbv,  VPst, VMAbv, VMAbv,     O,
+
+}; /* Table items: 5144; occupancy: 72% */
+
+USE_TABLE_ELEMENT_TYPE
+hb_use_get_categories (hb_codepoint_t u)
+{
+  switch (u >> 12)
+  {
+    case 0x0u:
+      if (hb_in_range (u, 0x0028u, 0x003Fu)) return use_table[u - 0x0028u + use_offset_0x0028u];
+      if (hb_in_range (u, 0x00A0u, 0x00D7u)) return use_table[u - 0x00A0u + use_offset_0x00a0u];
+      if (hb_in_range (u, 0x0900u, 0x0DF7u)) return use_table[u - 0x0900u + use_offset_0x0900u];
+      if (unlikely (u == 0x034Fu)) return CGJ;
+      break;
+
+    case 0x1u:
+      if (hb_in_range (u, 0x1000u, 0x109Fu)) return use_table[u - 0x1000u + use_offset_0x1000u];
+      if (hb_in_range (u, 0x1700u, 0x17EFu)) return use_table[u - 0x1700u + use_offset_0x1700u];
+      if (hb_in_range (u, 0x1900u, 0x1A9Fu)) return use_table[u - 0x1900u + use_offset_0x1900u];
+      if (hb_in_range (u, 0x1B00u, 0x1C4Fu)) return use_table[u - 0x1B00u + use_offset_0x1b00u];
+      if (hb_in_range (u, 0x1CD0u, 0x1CFFu)) return use_table[u - 0x1CD0u + use_offset_0x1cd0u];
+      if (hb_in_range (u, 0x1DF8u, 0x1DFFu)) return use_table[u - 0x1DF8u + use_offset_0x1df8u];
+      break;
+
+    case 0x2u:
+      if (hb_in_range (u, 0x2008u, 0x2017u)) return use_table[u - 0x2008u + use_offset_0x2008u];
+      if (hb_in_range (u, 0x2060u, 0x2087u)) return use_table[u - 0x2060u + use_offset_0x2060u];
+      if (unlikely (u == 0x25CCu)) return GB;
+      break;
+
+    case 0xAu:
+      if (hb_in_range (u, 0xA800u, 0xAAF7u)) return use_table[u - 0xA800u + use_offset_0xa800u];
+      if (hb_in_range (u, 0xABC0u, 0xABFFu)) return use_table[u - 0xABC0u + use_offset_0xabc0u];
+      break;
+
+    case 0xFu:
+      if (hb_in_range (u, 0xFE00u, 0xFE0Fu)) return use_table[u - 0xFE00u + use_offset_0xfe00u];
+      break;
+
+    case 0x10u:
+      if (hb_in_range (u, 0x10A00u, 0x10A47u)) return use_table[u - 0x10A00u + use_offset_0x10a00u];
+      break;
+
+    case 0x11u:
+      if (hb_in_range (u, 0x11000u, 0x110BFu)) return use_table[u - 0x11000u + use_offset_0x11000u];
+      if (hb_in_range (u, 0x11100u, 0x1123Fu)) return use_table[u - 0x11100u + use_offset_0x11100u];
+      if (hb_in_range (u, 0x11280u, 0x11377u)) return use_table[u - 0x11280u + use_offset_0x11280u];
+      if (hb_in_range (u, 0x11400u, 0x114DFu)) return use_table[u - 0x11400u + use_offset_0x11400u];
+      if (hb_in_range (u, 0x11580u, 0x1173Fu)) return use_table[u - 0x11580u + use_offset_0x11580u];
+      if (hb_in_range (u, 0x11C00u, 0x11CB7u)) return use_table[u - 0x11C00u + use_offset_0x11c00u];
+      if (unlikely (u == 0x1107Fu)) return HN;
+      break;
+
+    default:
+      break;
+  }
+  return USE_O;
+}
+
+#undef B
+#undef CGJ
+#undef FM
+#undef GB
+#undef H
+#undef HN
+#undef IND
+#undef N
+#undef O
+#undef R
+#undef Rsv
+#undef S
+#undef SUB
+#undef VS
+#undef WJ
+#undef ZWJ
+#undef ZWNJ
+#undef CMBlw
+#undef CMAbv
+#undef FBlw
+#undef FPst
+#undef FAbv
+#undef MPre
+#undef MBlw
+#undef MPst
+#undef MAbv
+#undef SMBlw
+#undef SMAbv
+#undef VPre
+#undef VBlw
+#undef VPst
+#undef VAbv
+#undef VMPre
+#undef VMBlw
+#undef VMPst
+#undef VMAbv
+
+/* == End of generated table == */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use.cpp
new file mode 100644
index 0000000..eeca79a
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use.cpp
@@ -0,0 +1,590 @@
+/*
+ * Copyright © 2015  Mozilla Foundation.
+ * Copyright © 2015  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
+ */
+
+#include "hb-ot-shape-complex-use-private.hh"
+#include "hb-ot-shape-complex-arabic-private.hh"
+
+/* buffer var allocations */
+#define use_category() complex_var_u8_0()
+
+
+/*
+ * Universal Shaping Engine.
+ * https://www.microsoft.com/typography/OpenTypeDev/USE/intro.htm
+ */
+
+static const hb_tag_t
+basic_features[] =
+{
+  /*
+   * Basic features.
+   * These features are applied all at once, before reordering.
+   */
+  HB_TAG('r','k','r','f'),
+  HB_TAG('a','b','v','f'),
+  HB_TAG('b','l','w','f'),
+  HB_TAG('h','a','l','f'),
+  HB_TAG('p','s','t','f'),
+  HB_TAG('v','a','t','u'),
+  HB_TAG('c','j','c','t'),
+};
+static const hb_tag_t
+arabic_features[] =
+{
+  HB_TAG('i','s','o','l'),
+  HB_TAG('i','n','i','t'),
+  HB_TAG('m','e','d','i'),
+  HB_TAG('f','i','n','a'),
+  /* The spec doesn't specify these but we apply anyway, since our Arabic shaper
+   * does.  These are only used in Syriac spec. */
+  HB_TAG('m','e','d','2'),
+  HB_TAG('f','i','n','2'),
+  HB_TAG('f','i','n','3'),
+};
+/* Same order as arabic_features.  Don't need Syriac stuff.*/
+enum joining_form_t {
+  ISOL,
+  INIT,
+  MEDI,
+  FINA,
+  _NONE
+};
+static const hb_tag_t
+other_features[] =
+{
+  /*
+   * Other features.
+   * These features are applied all at once, after reordering.
+   */
+  HB_TAG('a','b','v','s'),
+  HB_TAG('b','l','w','s'),
+  HB_TAG('h','a','l','n'),
+  HB_TAG('p','r','e','s'),
+  HB_TAG('p','s','t','s'),
+  /* Positioning features, though we don't care about the types. */
+  HB_TAG('d','i','s','t'),
+  HB_TAG('a','b','v','m'),
+  HB_TAG('b','l','w','m'),
+};
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan,
+                 hb_font_t *font,
+                 hb_buffer_t *buffer);
+static void
+clear_substitution_flags (const hb_ot_shape_plan_t *plan,
+                          hb_font_t *font,
+                          hb_buffer_t *buffer);
+static void
+record_rphf (const hb_ot_shape_plan_t *plan,
+             hb_font_t *font,
+             hb_buffer_t *buffer);
+static void
+record_pref (const hb_ot_shape_plan_t *plan,
+             hb_font_t *font,
+             hb_buffer_t *buffer);
+static void
+reorder (const hb_ot_shape_plan_t *plan,
+         hb_font_t *font,
+         hb_buffer_t *buffer);
+
+static void
+collect_features_use (hb_ot_shape_planner_t *plan)
+{
+  hb_ot_map_builder_t *map = &plan->map;
+
+  /* Do this before any lookups have been applied. */
+  map->add_gsub_pause (setup_syllables);
+
+  /* "Default glyph pre-processing group" */
+  map->add_global_bool_feature (HB_TAG('l','o','c','l'));
+  map->add_global_bool_feature (HB_TAG('c','c','m','p'));
+  map->add_global_bool_feature (HB_TAG('n','u','k','t'));
+  map->add_global_bool_feature (HB_TAG('a','k','h','n'));
+
+  /* "Reordering group" */
+  map->add_gsub_pause (clear_substitution_flags);
+  map->add_feature (HB_TAG('r','p','h','f'), 1, F_MANUAL_ZWJ);
+  map->add_gsub_pause (record_rphf);
+  map->add_gsub_pause (clear_substitution_flags);
+  map->add_feature (HB_TAG('p','r','e','f'), 1, F_GLOBAL | F_MANUAL_ZWJ);
+  map->add_gsub_pause (record_pref);
+
+  /* "Orthographic unit shaping group" */
+  for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
+    map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
+
+  map->add_gsub_pause (reorder);
+
+  /* "Topographical features" */
+  for (unsigned int i = 0; i < ARRAY_LENGTH (arabic_features); i++)
+    map->add_feature (arabic_features[i], 1, F_NONE);
+  map->add_gsub_pause (NULL);
+
+  /* "Standard typographic presentation" and "Positional feature application" */
+  for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
+    map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
+}
+
+struct use_shape_plan_t
+{
+  ASSERT_POD ();
+
+  hb_mask_t rphf_mask;
+
+  arabic_shape_plan_t *arabic_plan;
+};
+
+static bool
+has_arabic_joining (hb_script_t script)
+{
+  /* List of scripts that have data in arabic-table. */
+  switch ((int) script)
+  {
+    /* Unicode-1.1 additions */
+    case HB_SCRIPT_ARABIC:
+
+    /* Unicode-3.0 additions */
+    case HB_SCRIPT_MONGOLIAN:
+    case HB_SCRIPT_SYRIAC:
+
+    /* Unicode-5.0 additions */
+    case HB_SCRIPT_NKO:
+    case HB_SCRIPT_PHAGS_PA:
+
+    /* Unicode-6.0 additions */
+    case HB_SCRIPT_MANDAIC:
+
+    /* Unicode-7.0 additions */
+    case HB_SCRIPT_MANICHAEAN:
+    case HB_SCRIPT_PSALTER_PAHLAVI:
+
+    /* Unicode-9.0 additions */
+    case HB_SCRIPT_ADLAM:
+
+      return true;
+
+    default:
+      return false;
+  }
+}
+
+static void *
+data_create_use (const hb_ot_shape_plan_t *plan)
+{
+  use_shape_plan_t *use_plan = (use_shape_plan_t *) calloc (1, sizeof (use_shape_plan_t));
+  if (unlikely (!use_plan))
+    return NULL;
+
+  use_plan->rphf_mask = plan->map.get_1_mask (HB_TAG('r','p','h','f'));
+
+  if (has_arabic_joining (plan->props.script))
+  {
+    use_plan->arabic_plan = (arabic_shape_plan_t *) data_create_arabic (plan);
+    if (unlikely (!use_plan->arabic_plan))
+    {
+      free (use_plan);
+      return NULL;
+    }
+  }
+
+  return use_plan;
+}
+
+static void
+data_destroy_use (void *data)
+{
+  use_shape_plan_t *use_plan = (use_shape_plan_t *) data;
+
+  if (use_plan->arabic_plan)
+    data_destroy_arabic (use_plan->arabic_plan);
+
+  free (data);
+}
+
+enum syllable_type_t {
+  independent_cluster,
+  virama_terminated_cluster,
+  standard_cluster,
+  number_joiner_terminated_cluster,
+  numeral_cluster,
+  symbol_cluster,
+  broken_cluster,
+  non_cluster,
+};
+
+#include "hb-ot-shape-complex-use-machine.hh"
+
+
+static void
+setup_masks_use (const hb_ot_shape_plan_t *plan,
+                 hb_buffer_t              *buffer,
+                 hb_font_t                *font HB_UNUSED)
+{
+  const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
+
+  /* Do this before allocating use_category(). */
+  if (use_plan->arabic_plan)
+  {
+    setup_masks_arabic_plan (use_plan->arabic_plan, buffer, plan->props.script);
+  }
+
+  HB_BUFFER_ALLOCATE_VAR (buffer, use_category);
+
+  /* We cannot setup masks here.  We save information about characters
+   * and setup masks later on in a pause-callback. */
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    info[i].use_category() = hb_use_get_categories (info[i].codepoint);
+}
+
+static void
+setup_rphf_mask (const hb_ot_shape_plan_t *plan,
+                 hb_buffer_t *buffer)
+{
+  const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
+
+  hb_mask_t mask = use_plan->rphf_mask;
+  if (!mask) return;
+
+  hb_glyph_info_t *info = buffer->info;
+
+  foreach_syllable (buffer, start, end)
+  {
+    unsigned int limit = info[start].use_category() == USE_R ? 1 : MIN (3u, end - start);
+    for (unsigned int i = start; i < start + limit; i++)
+      info[i].mask |= mask;
+  }
+}
+
+static void
+setup_topographical_masks (const hb_ot_shape_plan_t *plan,
+                           hb_buffer_t *buffer)
+{
+  const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
+  if (use_plan->arabic_plan)
+    return;
+
+  ASSERT_STATIC (INIT < 4 && ISOL < 4 && MEDI < 4 && FINA < 4);
+  hb_mask_t masks[4], all_masks = 0;
+  for (unsigned int i = 0; i < 4; i++)
+  {
+    masks[i] = plan->map.get_1_mask (arabic_features[i]);
+    if (masks[i] == plan->map.get_global_mask ())
+      masks[i] = 0;
+    all_masks |= masks[i];
+  }
+  if (!all_masks)
+    return;
+  hb_mask_t other_masks = ~all_masks;
+
+  unsigned int last_start = 0;
+  joining_form_t last_form = _NONE;
+  hb_glyph_info_t *info = buffer->info;
+  foreach_syllable (buffer, start, end)
+  {
+    syllable_type_t syllable_type = (syllable_type_t) (info[start].syllable() & 0x0F);
+    switch (syllable_type)
+    {
+      case independent_cluster:
+      case symbol_cluster:
+      case non_cluster:
+        /* These don't join.  Nothing to do. */
+        last_form = _NONE;
+        break;
+
+      case virama_terminated_cluster:
+      case standard_cluster:
+      case number_joiner_terminated_cluster:
+      case numeral_cluster:
+      case broken_cluster:
+
+        bool join = last_form == FINA || last_form == ISOL;
+
+        if (join)
+        {
+          /* Fixup previous syllable's form. */
+          last_form = last_form == FINA ? MEDI : INIT;
+          for (unsigned int i = last_start; i < start; i++)
+            info[i].mask = (info[i].mask & other_masks) | masks[last_form];
+        }
+
+        /* Form for this syllable. */
+        last_form = join ? FINA : ISOL;
+        for (unsigned int i = start; i < end; i++)
+          info[i].mask = (info[i].mask & other_masks) | masks[last_form];
+
+        break;
+    }
+
+    last_start = start;
+  }
+}
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan,
+                 hb_font_t *font HB_UNUSED,
+                 hb_buffer_t *buffer)
+{
+  find_syllables (buffer);
+  setup_rphf_mask (plan, buffer);
+  setup_topographical_masks (plan, buffer);
+}
+
+static void
+clear_substitution_flags (const hb_ot_shape_plan_t *plan,
+                          hb_font_t *font HB_UNUSED,
+                          hb_buffer_t *buffer)
+{
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+    _hb_glyph_info_clear_substituted (&info[i]);
+}
+
+static void
+record_rphf (const hb_ot_shape_plan_t *plan,
+             hb_font_t *font,
+             hb_buffer_t *buffer)
+{
+  const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
+
+  hb_mask_t mask = use_plan->rphf_mask;
+  if (!mask) return;
+  hb_glyph_info_t *info = buffer->info;
+
+  foreach_syllable (buffer, start, end)
+  {
+    /* Mark a substituted repha as USE_R. */
+    for (unsigned int i = start; i < end && (info[i].mask & mask); i++)
+      if (_hb_glyph_info_substituted (&info[i]))
+      {
+        info[i].use_category() = USE_R;
+        break;
+      }
+  }
+}
+
+static void
+record_pref (const hb_ot_shape_plan_t *plan,
+             hb_font_t *font,
+             hb_buffer_t *buffer)
+{
+  hb_glyph_info_t *info = buffer->info;
+
+  foreach_syllable (buffer, start, end)
+  {
+    /* Mark a substituted pref as VPre, as they behave the same way. */
+    for (unsigned int i = start; i < end; i++)
+      if (_hb_glyph_info_substituted (&info[i]))
+      {
+        info[i].use_category() = USE_VPre;
+        break;
+      }
+  }
+}
+
+static inline bool
+is_halant (const hb_glyph_info_t &info)
+{
+  return info.use_category() == USE_H && !_hb_glyph_info_ligated (&info);
+}
+
+static void
+reorder_syllable (hb_buffer_t *buffer, unsigned int start, unsigned int end)
+{
+  syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+  /* Only a few syllable types need reordering. */
+  if (unlikely (!(FLAG_SAFE (syllable_type) &
+                  (FLAG (virama_terminated_cluster) |
+                   FLAG (standard_cluster) |
+                   FLAG (broken_cluster) |
+                   0))))
+    return;
+
+  hb_glyph_info_t *info = buffer->info;
+
+#define BASE_FLAGS (FLAG (USE_B) | FLAG (USE_GB))
+
+  /* Move things forward. */
+  if (info[start].use_category() == USE_R && end - start > 1)
+  {
+    /* Got a repha.  Reorder it to after first base, before first halant. */
+    for (unsigned int i = start + 1; i < end; i++)
+      if ((FLAG_UNSAFE (info[i].use_category()) & (BASE_FLAGS)) || is_halant (info[i]))
+      {
+        /* If we hit a halant, move before it; otherwise it's a base: move to it's
+         * place, and shift things in between backward. */
+
+        if (is_halant (info[i]))
+          i--;
+
+        buffer->merge_clusters (start, i + 1);
+        hb_glyph_info_t t = info[start];
+        memmove (&info[start], &info[start + 1], (i - start) * sizeof (info[0]));
+        info[i] = t;
+
+        break;
+      }
+  }
+
+  /* Move things back. */
+  unsigned int j = end;
+  for (unsigned int i = start; i < end; i++)
+  {
+    uint32_t flag = FLAG_UNSAFE (info[i].use_category());
+    if ((flag & (BASE_FLAGS)) || is_halant (info[i]))
+    {
+      /* If we hit a halant, move after it; otherwise it's a base: move to it's
+       * place, and shift things in between backward. */
+      if (is_halant (info[i]))
+        j = i + 1;
+      else
+        j = i;
+    }
+    else if (((flag) & (FLAG (USE_VPre) | FLAG (USE_VMPre))) &&
+             /* Only move the first component of a MultipleSubst. */
+             0 == _hb_glyph_info_get_lig_comp (&info[i]) &&
+             j < i)
+    {
+      buffer->merge_clusters (j, i + 1);
+      hb_glyph_info_t t = info[i];
+      memmove (&info[j + 1], &info[j], (i - j) * sizeof (info[0]));
+      info[j] = t;
+    }
+  }
+}
+
+static inline void
+insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                       hb_font_t *font,
+                       hb_buffer_t *buffer)
+{
+  /* Note: This loop is extra overhead, but should not be measurable. */
+  bool has_broken_syllables = false;
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    if ((info[i].syllable() & 0x0F) == broken_cluster)
+    {
+      has_broken_syllables = true;
+      break;
+    }
+  if (likely (!has_broken_syllables))
+    return;
+
+  hb_glyph_info_t dottedcircle = {0};
+  if (!font->get_nominal_glyph (0x25CCu, &dottedcircle.codepoint))
+    return;
+  dottedcircle.use_category() = hb_use_get_categories (0x25CC);
+
+  buffer->clear_output ();
+
+  buffer->idx = 0;
+  unsigned int last_syllable = 0;
+  while (buffer->idx < buffer->len && !buffer->in_error)
+  {
+    unsigned int syllable = buffer->cur().syllable();
+    syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
+    if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+    {
+      last_syllable = syllable;
+
+      hb_glyph_info_t ginfo = dottedcircle;
+      ginfo.cluster = buffer->cur().cluster;
+      ginfo.mask = buffer->cur().mask;
+      ginfo.syllable() = buffer->cur().syllable();
+      /* TODO Set glyph_props? */
+
+      /* Insert dottedcircle after possible Repha. */
+      while (buffer->idx < buffer->len && !buffer->in_error &&
+             last_syllable == buffer->cur().syllable() &&
+             buffer->cur().use_category() == USE_R)
+        buffer->next_glyph ();
+
+      buffer->output_info (ginfo);
+    }
+    else
+      buffer->next_glyph ();
+  }
+
+  buffer->swap_buffers ();
+}
+
+static void
+reorder (const hb_ot_shape_plan_t *plan,
+         hb_font_t *font,
+         hb_buffer_t *buffer)
+{
+  insert_dotted_circles (plan, font, buffer);
+
+  hb_glyph_info_t *info = buffer->info;
+
+  foreach_syllable (buffer, start, end)
+    reorder_syllable (buffer, start, end);
+
+  /* Zero syllables now... */
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+    info[i].syllable() = 0;
+
+  HB_BUFFER_DEALLOCATE_VAR (buffer, use_category);
+}
+
+static bool
+compose_use (const hb_ot_shape_normalize_context_t *c,
+             hb_codepoint_t  a,
+             hb_codepoint_t  b,
+             hb_codepoint_t *ab)
+{
+  /* Avoid recomposing split matras. */
+  if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a)))
+    return false;
+
+  return (bool)c->unicode->compose (a, b, ab);
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
+{
+  "use",
+  collect_features_use,
+  NULL, /* override_features */
+  data_create_use,
+  data_destroy_use,
+  NULL, /* preprocess_text */
+  NULL, /* postprocess_glyphs */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
+  NULL, /* decompose */
+  compose_use,
+  setup_masks_use,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
+  false, /* fallback_position */
+};
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-fallback-private.hh b/src/share/native/sun/font/harfbuzz/hb-ot-shape-fallback-private.hh
new file mode 100644
index 0000000..f9fe504
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-fallback-private.hh
@@ -0,0 +1,53 @@
+/*
+ * 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_OT_SHAPE_FALLBACK_PRIVATE_HH
+#define HB_OT_SHAPE_FALLBACK_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-ot-shape-private.hh"
+
+
+HB_INTERNAL void _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
+                                                 hb_font_t *font,
+                                                 hb_buffer_t  *buffer);
+
+HB_INTERNAL void _hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan,
+                                                                    hb_font_t *font,
+                                                                    hb_buffer_t  *buffer);
+
+
+HB_INTERNAL void _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
+                                             hb_font_t *font,
+                                             hb_buffer_t  *buffer);
+
+HB_INTERNAL void _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
+                                               hb_font_t *font,
+                                               hb_buffer_t  *buffer);
+
+
+#endif /* HB_OT_SHAPE_FALLBACK_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-fallback.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-shape-fallback.cpp
new file mode 100644
index 0000000..baa3835
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-fallback.cpp
@@ -0,0 +1,553 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-shape-fallback-private.hh"
+#include "hb-ot-layout-gsubgpos-private.hh"
+
+static unsigned int
+recategorize_combining_class (hb_codepoint_t u,
+                              unsigned int klass)
+{
+  if (klass >= 200)
+    return klass;
+
+  /* Thai / Lao need some per-character work. */
+  if ((u & ~0xFF) == 0x0E00u)
+  {
+    if (unlikely (klass == 0))
+    {
+      switch (u)
+      {
+        case 0x0E31u:
+        case 0x0E34u:
+        case 0x0E35u:
+        case 0x0E36u:
+        case 0x0E37u:
+        case 0x0E47u:
+        case 0x0E4Cu:
+        case 0x0E4Du:
+        case 0x0E4Eu:
+          klass = HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
+          break;
+
+        case 0x0EB1u:
+        case 0x0EB4u:
+        case 0x0EB5u:
+        case 0x0EB6u:
+        case 0x0EB7u:
+        case 0x0EBBu:
+        case 0x0ECCu:
+        case 0x0ECDu:
+          klass = HB_UNICODE_COMBINING_CLASS_ABOVE;
+          break;
+
+        case 0x0EBCu:
+          klass = HB_UNICODE_COMBINING_CLASS_BELOW;
+          break;
+      }
+    } else {
+      /* Thai virama is below-right */
+      if (u == 0x0E3Au)
+        klass = HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
+    }
+  }
+
+  switch (klass)
+  {
+
+    /* Hebrew */
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC10: /* sheva */
+    case HB_MODIFIED_COMBINING_CLASS_CCC11: /* hataf segol */
+    case HB_MODIFIED_COMBINING_CLASS_CCC12: /* hataf patah */
+    case HB_MODIFIED_COMBINING_CLASS_CCC13: /* hataf qamats */
+    case HB_MODIFIED_COMBINING_CLASS_CCC14: /* hiriq */
+    case HB_MODIFIED_COMBINING_CLASS_CCC15: /* tsere */
+    case HB_MODIFIED_COMBINING_CLASS_CCC16: /* segol */
+    case HB_MODIFIED_COMBINING_CLASS_CCC17: /* patah */
+    case HB_MODIFIED_COMBINING_CLASS_CCC18: /* qamats */
+    case HB_MODIFIED_COMBINING_CLASS_CCC20: /* qubuts */
+    case HB_MODIFIED_COMBINING_CLASS_CCC22: /* meteg */
+      return HB_UNICODE_COMBINING_CLASS_BELOW;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC23: /* rafe */
+      return HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC24: /* shin dot */
+      return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC25: /* sin dot */
+    case HB_MODIFIED_COMBINING_CLASS_CCC19: /* holam */
+      return HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC26: /* point varika */
+      return HB_UNICODE_COMBINING_CLASS_ABOVE;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC21: /* dagesh */
+      break;
+
+
+    /* Arabic and Syriac */
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC27: /* fathatan */
+    case HB_MODIFIED_COMBINING_CLASS_CCC28: /* dammatan */
+    case HB_MODIFIED_COMBINING_CLASS_CCC30: /* fatha */
+    case HB_MODIFIED_COMBINING_CLASS_CCC31: /* damma */
+    case HB_MODIFIED_COMBINING_CLASS_CCC33: /* shadda */
+    case HB_MODIFIED_COMBINING_CLASS_CCC34: /* sukun */
+    case HB_MODIFIED_COMBINING_CLASS_CCC35: /* superscript alef */
+    case HB_MODIFIED_COMBINING_CLASS_CCC36: /* superscript alaph */
+      return HB_UNICODE_COMBINING_CLASS_ABOVE;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC29: /* kasratan */
+    case HB_MODIFIED_COMBINING_CLASS_CCC32: /* kasra */
+      return HB_UNICODE_COMBINING_CLASS_BELOW;
+
+
+    /* Thai */
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC103: /* sara u / sara uu */
+      return HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC107: /* mai */
+      return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
+
+
+    /* Lao */
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC118: /* sign u / sign uu */
+      return HB_UNICODE_COMBINING_CLASS_BELOW;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC122: /* mai */
+      return HB_UNICODE_COMBINING_CLASS_ABOVE;
+
+
+    /* Tibetan */
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC129: /* sign aa */
+      return HB_UNICODE_COMBINING_CLASS_BELOW;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC130: /* sign i*/
+      return HB_UNICODE_COMBINING_CLASS_ABOVE;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC132: /* sign u */
+      return HB_UNICODE_COMBINING_CLASS_BELOW;
+
+  }
+
+  return klass;
+}
+
+void
+_hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                                                   hb_font_t *font HB_UNUSED,
+                                                   hb_buffer_t  *buffer)
+{
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
+      unsigned int combining_class = _hb_glyph_info_get_modified_combining_class (&info[i]);
+      combining_class = recategorize_combining_class (info[i].codepoint, combining_class);
+      _hb_glyph_info_set_modified_combining_class (&info[i], combining_class);
+    }
+}
+
+
+static void
+zero_mark_advances (hb_buffer_t *buffer,
+                    unsigned int start,
+                    unsigned int end)
+{
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = start; i < end; i++)
+    if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
+    {
+      buffer->pos[i].x_advance = 0;
+      buffer->pos[i].y_advance = 0;
+    }
+}
+
+static inline void
+position_mark (const hb_ot_shape_plan_t *plan,
+               hb_font_t *font,
+               hb_buffer_t  *buffer,
+               hb_glyph_extents_t &base_extents,
+               unsigned int i,
+               unsigned int combining_class)
+{
+  hb_glyph_extents_t mark_extents;
+  if (!font->get_glyph_extents (buffer->info[i].codepoint,
+                                &mark_extents))
+    return;
+
+  hb_position_t y_gap = font->y_scale / 16;
+
+  hb_glyph_position_t &pos = buffer->pos[i];
+  pos.x_offset = pos.y_offset = 0;
+
+
+  /* We dont position LEFT and RIGHT marks. */
+
+  /* X positioning */
+  switch (combining_class)
+  {
+    case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW:
+    case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
+      if (buffer->props.direction == HB_DIRECTION_LTR) {
+        pos.x_offset += base_extents.x_bearing - mark_extents.width / 2 - mark_extents.x_bearing;
+        break;
+      } else if (buffer->props.direction == HB_DIRECTION_RTL) {
+        pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing;
+        break;
+      }
+      HB_FALLTHROUGH;
+
+    default:
+    case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
+    case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
+    case HB_UNICODE_COMBINING_CLASS_BELOW:
+    case HB_UNICODE_COMBINING_CLASS_ABOVE:
+      /* Center align. */
+      pos.x_offset += base_extents.x_bearing + (base_extents.width - mark_extents.width) / 2 - mark_extents.x_bearing;
+      break;
+
+    case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
+    case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT:
+    case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
+      /* Left align. */
+      pos.x_offset += base_extents.x_bearing - mark_extents.x_bearing;
+      break;
+
+    case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
+    case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
+    case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
+      /* Right align. */
+      pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width - mark_extents.x_bearing;
+      break;
+  }
+
+  /* Y positioning */
+  switch (combining_class)
+  {
+    case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW:
+    case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT:
+    case HB_UNICODE_COMBINING_CLASS_BELOW:
+    case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
+      /* Add gap, fall-through. */
+      base_extents.height -= y_gap;
+      HB_FALLTHROUGH;
+
+    case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
+    case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
+      pos.y_offset = base_extents.y_bearing + base_extents.height - mark_extents.y_bearing;
+      /* Never shift up "below" marks. */
+      if ((y_gap > 0) == (pos.y_offset > 0))
+      {
+        base_extents.height -= pos.y_offset;
+        pos.y_offset = 0;
+      }
+      base_extents.height += mark_extents.height;
+      break;
+
+    case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
+    case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
+    case HB_UNICODE_COMBINING_CLASS_ABOVE:
+    case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
+      /* Add gap, fall-through. */
+      base_extents.y_bearing += y_gap;
+      base_extents.height -= y_gap;
+      HB_FALLTHROUGH;
+
+    case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
+    case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
+      pos.y_offset = base_extents.y_bearing - (mark_extents.y_bearing + mark_extents.height);
+      /* Don't shift down "above" marks too much. */
+      if ((y_gap > 0) != (pos.y_offset > 0))
+      {
+        unsigned int correction = -pos.y_offset / 2;
+        base_extents.y_bearing += correction;
+        base_extents.height -= correction;
+        pos.y_offset += correction;
+      }
+      base_extents.y_bearing -= mark_extents.height;
+      base_extents.height += mark_extents.height;
+      break;
+  }
+}
+
+static inline void
+position_around_base (const hb_ot_shape_plan_t *plan,
+                      hb_font_t *font,
+                      hb_buffer_t  *buffer,
+                      unsigned int base,
+                      unsigned int end)
+{
+  hb_direction_t horiz_dir = HB_DIRECTION_INVALID;
+  hb_glyph_extents_t base_extents;
+  if (!font->get_glyph_extents (buffer->info[base].codepoint,
+                                &base_extents))
+  {
+    /* If extents don't work, zero marks and go home. */
+    zero_mark_advances (buffer, base + 1, end);
+    return;
+  }
+  base_extents.x_bearing += buffer->pos[base].x_offset;
+  base_extents.y_bearing += buffer->pos[base].y_offset;
+
+  unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[base]);
+  unsigned int num_lig_components = _hb_glyph_info_get_lig_num_comps (&buffer->info[base]);
+
+  hb_position_t x_offset = 0, y_offset = 0;
+  if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
+    x_offset -= buffer->pos[base].x_advance;
+    y_offset -= buffer->pos[base].y_advance;
+  }
+
+  hb_glyph_extents_t component_extents = base_extents;
+  unsigned int last_lig_component = (unsigned int) -1;
+  unsigned int last_combining_class = 255;
+  hb_glyph_extents_t cluster_extents = base_extents; /* Initialization is just to shut gcc up. */
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = base + 1; i < end; i++)
+    if (_hb_glyph_info_get_modified_combining_class (&info[i]))
+    {
+      if (num_lig_components > 1) {
+        unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&info[i]);
+        unsigned int this_lig_component = _hb_glyph_info_get_lig_comp (&info[i]) - 1;
+        /* Conditions for attaching to the last component. */
+        if (!lig_id || lig_id != this_lig_id || this_lig_component >= num_lig_components)
+          this_lig_component = num_lig_components - 1;
+        if (last_lig_component != this_lig_component)
+        {
+          last_lig_component = this_lig_component;
+          last_combining_class = 255;
+          component_extents = base_extents;
+          if (unlikely (horiz_dir == HB_DIRECTION_INVALID)) {
+            if (HB_DIRECTION_IS_HORIZONTAL (plan->props.direction))
+              horiz_dir = plan->props.direction;
+            else
+              horiz_dir = hb_script_get_horizontal_direction (plan->props.script);
+          }
+          if (horiz_dir == HB_DIRECTION_LTR)
+            component_extents.x_bearing += (this_lig_component * component_extents.width) / num_lig_components;
+          else
+            component_extents.x_bearing += ((num_lig_components - 1 - this_lig_component) * component_extents.width) / num_lig_components;
+          component_extents.width /= num_lig_components;
+        }
+      }
+
+      unsigned int this_combining_class = _hb_glyph_info_get_modified_combining_class (&info[i]);
+      if (last_combining_class != this_combining_class)
+      {
+        last_combining_class = this_combining_class;
+        cluster_extents = component_extents;
+      }
+
+      position_mark (plan, font, buffer, cluster_extents, i, this_combining_class);
+
+      buffer->pos[i].x_advance = 0;
+      buffer->pos[i].y_advance = 0;
+      buffer->pos[i].x_offset += x_offset;
+      buffer->pos[i].y_offset += y_offset;
+
+    } else {
+      if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
+        x_offset -= buffer->pos[i].x_advance;
+        y_offset -= buffer->pos[i].y_advance;
+      } else {
+        x_offset += buffer->pos[i].x_advance;
+        y_offset += buffer->pos[i].y_advance;
+      }
+    }
+}
+
+static inline void
+position_cluster (const hb_ot_shape_plan_t *plan,
+                  hb_font_t *font,
+                  hb_buffer_t  *buffer,
+                  unsigned int start,
+                  unsigned int end)
+{
+  if (end - start < 2)
+    return;
+
+  /* Find the base glyph */
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = start; i < end; i++)
+    if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))
+    {
+      /* Find mark glyphs */
+      unsigned int j;
+      for (j = i + 1; j < end; j++)
+        if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[j])))
+          break;
+
+      position_around_base (plan, font, buffer, i, j);
+
+      i = j - 1;
+    }
+}
+
+void
+_hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
+                                hb_font_t *font,
+                                hb_buffer_t  *buffer)
+{
+  _hb_buffer_assert_gsubgpos_vars (buffer);
+
+  unsigned int start = 0;
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 1; i < count; i++)
+    if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) {
+      position_cluster (plan, font, buffer, start, i);
+      start = i;
+    }
+  position_cluster (plan, font, buffer, start, count);
+}
+
+
+/* Performs old-style TrueType kerning. */
+void
+_hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
+                            hb_font_t *font,
+                            hb_buffer_t  *buffer)
+{
+  if (!plan->has_kern) return;
+
+  OT::hb_apply_context_t c (1, font, buffer);
+  c.set_lookup_mask (plan->kern_mask);
+  c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
+  OT::hb_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input;
+  skippy_iter.init (&c);
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  hb_glyph_position_t *pos = buffer->pos;
+  for (unsigned int idx = 0; idx < count;)
+  {
+    skippy_iter.reset (idx, 1);
+    if (!skippy_iter.next ())
+    {
+      idx++;
+      continue;
+    }
+
+    hb_position_t x_kern, y_kern;
+    font->get_glyph_kerning_for_direction (info[idx].codepoint,
+                                           info[skippy_iter.idx].codepoint,
+                                           buffer->props.direction,
+                                           &x_kern, &y_kern);
+
+    if (x_kern)
+    {
+      hb_position_t kern1 = x_kern >> 1;
+      hb_position_t kern2 = x_kern - kern1;
+      pos[idx].x_advance += kern1;
+      pos[skippy_iter.idx].x_advance += kern2;
+      pos[skippy_iter.idx].x_offset += kern2;
+    }
+
+    if (y_kern)
+    {
+      hb_position_t kern1 = y_kern >> 1;
+      hb_position_t kern2 = y_kern - kern1;
+      pos[idx].y_advance += kern1;
+      pos[skippy_iter.idx].y_advance += kern2;
+      pos[skippy_iter.idx].y_offset += kern2;
+    }
+
+    idx = skippy_iter.idx;
+  }
+}
+
+
+/* Adjusts width of various spaces. */
+void
+_hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
+                              hb_font_t *font,
+                              hb_buffer_t  *buffer)
+{
+  if (!HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+    return;
+
+  hb_glyph_info_t *info = buffer->info;
+  hb_glyph_position_t *pos = buffer->pos;
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+    if (_hb_glyph_info_is_unicode_space (&info[i]) && !_hb_glyph_info_ligated (&info[i]))
+    {
+      hb_unicode_funcs_t::space_t space_type = _hb_glyph_info_get_unicode_space_fallback_type (&info[i]);
+      hb_codepoint_t glyph;
+      typedef hb_unicode_funcs_t t;
+      switch (space_type)
+      {
+        case t::NOT_SPACE: /* Shouldn't happen. */
+        case t::SPACE:
+          break;
+
+        case t::SPACE_EM:
+        case t::SPACE_EM_2:
+        case t::SPACE_EM_3:
+        case t::SPACE_EM_4:
+        case t::SPACE_EM_5:
+        case t::SPACE_EM_6:
+        case t::SPACE_EM_16:
+          pos[i].x_advance = (font->x_scale + ((int) space_type)/2) / (int) space_type;
+          break;
+
+        case t::SPACE_4_EM_18:
+          pos[i].x_advance = font->x_scale * 4 / 18;
+          break;
+
+        case t::SPACE_FIGURE:
+          for (char u = '0'; u <= '9'; u++)
+            if (font->get_nominal_glyph (u, &glyph))
+            {
+              pos[i].x_advance = font->get_glyph_h_advance (glyph);
+              break;
+            }
+          break;
+
+        case t::SPACE_PUNCTUATION:
+          if (font->get_nominal_glyph ('.', &glyph))
+            pos[i].x_advance = font->get_glyph_h_advance (glyph);
+          else if (font->get_nominal_glyph (',', &glyph))
+            pos[i].x_advance = font->get_glyph_h_advance (glyph);
+          break;
+
+        case t::SPACE_NARROW:
+          /* Half-space?
+           * Unicode doc http://www.unicode.org/charts/PDF/U2000.pdf says ~1/4 or 1/5 of EM.
+           * However, in my testing, many fonts have their regular space being about that
+           * size.  To me, a percentage of the space width makes more sense.  Half is as
+           * good as any. */
+          pos[i].x_advance /= 2;
+          break;
+      }
+    }
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-normalize-private.hh b/src/share/native/sun/font/harfbuzz/hb-ot-shape-normalize-private.hh
new file mode 100644
index 0000000..94fd49a
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-normalize-private.hh
@@ -0,0 +1,69 @@
+/*
+ * 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_OT_SHAPE_NORMALIZE_PRIVATE_HH
+#define HB_OT_SHAPE_NORMALIZE_PRIVATE_HH
+
+#include "hb-private.hh"
+
+
+/* buffer var allocations, used during the normalization process */
+#define glyph_index()   var1.u32
+
+struct hb_ot_shape_plan_t;
+
+enum hb_ot_shape_normalization_mode_t {
+  HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
+  HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED,
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS, /* never composes base-to-base */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, /* always fully decomposes and then recompose back */
+
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS
+};
+
+HB_INTERNAL void _hb_ot_shape_normalize (const hb_ot_shape_plan_t *shaper,
+                                         hb_buffer_t *buffer,
+                                         hb_font_t *font);
+
+
+struct hb_ot_shape_normalize_context_t
+{
+  const hb_ot_shape_plan_t *plan;
+  hb_buffer_t *buffer;
+  hb_font_t *font;
+  hb_unicode_funcs_t *unicode;
+  bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
+                     hb_codepoint_t  ab,
+                     hb_codepoint_t *a,
+                     hb_codepoint_t *b);
+  bool (*compose) (const hb_ot_shape_normalize_context_t *c,
+                   hb_codepoint_t  a,
+                   hb_codepoint_t  b,
+                   hb_codepoint_t *ab);
+};
+
+
+#endif /* HB_OT_SHAPE_NORMALIZE_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-normalize.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-shape-normalize.cpp
new file mode 100644
index 0000000..6bba43b
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-normalize.cpp
@@ -0,0 +1,415 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-shape-normalize-private.hh"
+#include "hb-ot-shape-complex-private.hh"
+#include "hb-ot-shape-private.hh"
+
+
+/*
+ * HIGHLEVEL DESIGN:
+ *
+ * This file exports one main function: _hb_ot_shape_normalize().
+ *
+ * This function closely reflects the Unicode Normalization Algorithm,
+ * yet it's different.
+ *
+ * Each shaper specifies whether it prefers decomposed (NFD) or composed (NFC).
+ * The logic however tries to use whatever the font can support.
+ *
+ * In general what happens is that: each grapheme is decomposed in a chain
+ * of 1:2 decompositions, marks reordered, and then recomposed if desired,
+ * so far it's like Unicode Normalization.  However, the decomposition and
+ * recomposition only happens if the font supports the resulting characters.
+ *
+ * The goals are:
+ *
+ *   - Try to render all canonically equivalent strings similarly.  To really
+ *     achieve this we have to always do the full decomposition and then
+ *     selectively recompose from there.  It's kinda too expensive though, so
+ *     we skip some cases.  For example, if composed is desired, we simply
+ *     don't touch 1-character clusters that are supported by the font, even
+ *     though their NFC may be different.
+ *
+ *   - When a font has a precomposed character for a sequence but the 'ccmp'
+ *     feature in the font is not adequate, use the precomposed character
+ *     which typically has better mark positioning.
+ *
+ *   - When a font does not support a combining mark, but supports it precomposed
+ *     with previous base, use that.  This needs the itemizer to have this
+ *     knowledge too.  We need to provide assistance to the itemizer.
+ *
+ *   - When a font does not support a character but supports its canonical
+ *     decomposition, well, use the decomposition.
+ *
+ *   - The complex shapers can customize the compose and decompose functions to
+ *     offload some of their requirements to the normalizer.  For example, the
+ *     Indic shaper may want to disallow recomposing of two matras.
+ */
+
+static bool
+decompose_unicode (const hb_ot_shape_normalize_context_t *c,
+                   hb_codepoint_t  ab,
+                   hb_codepoint_t *a,
+                   hb_codepoint_t *b)
+{
+  return (bool) c->unicode->decompose (ab, a, b);
+}
+
+static bool
+compose_unicode (const hb_ot_shape_normalize_context_t *c,
+                 hb_codepoint_t  a,
+                 hb_codepoint_t  b,
+                 hb_codepoint_t *ab)
+{
+  return (bool) c->unicode->compose (a, b, ab);
+}
+
+static inline void
+set_glyph (hb_glyph_info_t &info, hb_font_t *font)
+{
+  font->get_nominal_glyph (info.codepoint, &info.glyph_index());
+}
+
+static inline void
+output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
+{
+  buffer->cur().glyph_index() = glyph;
+  buffer->output_glyph (unichar); /* This is very confusing indeed. */
+  _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer);
+}
+
+static inline void
+next_char (hb_buffer_t *buffer, hb_codepoint_t glyph)
+{
+  buffer->cur().glyph_index() = glyph;
+  buffer->next_glyph ();
+}
+
+static inline void
+skip_char (hb_buffer_t *buffer)
+{
+  buffer->skip_glyph ();
+}
+
+/* Returns 0 if didn't decompose, number of resulting characters otherwise. */
+static inline unsigned int
+decompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint_t ab)
+{
+  hb_codepoint_t a, b, a_glyph, b_glyph;
+  hb_buffer_t * const buffer = c->buffer;
+  hb_font_t * const font = c->font;
+
+  if (!c->decompose (c, ab, &a, &b) ||
+      (b && !font->get_nominal_glyph (b, &b_glyph)))
+    return 0;
+
+  bool has_a = (bool) font->get_nominal_glyph (a, &a_glyph);
+  if (shortest && has_a) {
+    /* Output a and b */
+    output_char (buffer, a, a_glyph);
+    if (likely (b)) {
+      output_char (buffer, b, b_glyph);
+      return 2;
+    }
+    return 1;
+  }
+
+  unsigned int ret;
+  if ((ret = decompose (c, shortest, a))) {
+    if (b) {
+      output_char (buffer, b, b_glyph);
+      return ret + 1;
+    }
+    return ret;
+  }
+
+  if (has_a) {
+    output_char (buffer, a, a_glyph);
+    if (likely (b)) {
+      output_char (buffer, b, b_glyph);
+      return 2;
+    }
+    return 1;
+  }
+
+  return 0;
+}
+
+static inline void
+decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shortest)
+{
+  hb_buffer_t * const buffer = c->buffer;
+  hb_codepoint_t u = buffer->cur().codepoint;
+  hb_codepoint_t glyph;
+
+  if (shortest && c->font->get_nominal_glyph (u, &glyph))
+  {
+    next_char (buffer, glyph);
+    return;
+  }
+
+  if (decompose (c, shortest, u))
+  {
+    skip_char (buffer);
+    return;
+  }
+
+  if (!shortest && c->font->get_nominal_glyph (u, &glyph))
+  {
+    next_char (buffer, glyph);
+    return;
+  }
+
+  if (_hb_glyph_info_is_unicode_space (&buffer->cur()))
+  {
+    hb_codepoint_t space_glyph;
+    hb_unicode_funcs_t::space_t space_type = buffer->unicode->space_fallback_type (u);
+    if (space_type != hb_unicode_funcs_t::NOT_SPACE && c->font->get_nominal_glyph (0x0020u, &space_glyph))
+    {
+      _hb_glyph_info_set_unicode_space_fallback_type (&buffer->cur(), space_type);
+      next_char (buffer, space_glyph);
+      buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK;
+      return;
+    }
+  }
+
+  if (u == 0x2011u)
+  {
+    /* U+2011 is the only sensible character that is a no-break version of another character
+     * and not a space.  The space ones are handled already.  Handle this lone one. */
+    hb_codepoint_t other_glyph;
+    if (c->font->get_nominal_glyph (0x2010u, &other_glyph))
+    {
+      next_char (buffer, other_glyph);
+      return;
+    }
+  }
+
+  next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
+}
+
+static inline void
+handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
+{
+  /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
+  hb_buffer_t * const buffer = c->buffer;
+  hb_font_t * const font = c->font;
+  for (; buffer->idx < end - 1 && !buffer->in_error;) {
+    if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
+      /* The next two lines are some ugly lines... But work. */
+      if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
+      {
+        buffer->replace_glyphs (2, 1, &buffer->cur().codepoint);
+      }
+      else
+      {
+        /* Just pass on the two characters separately, let GSUB do its magic. */
+        set_glyph (buffer->cur(), font);
+        buffer->next_glyph ();
+        set_glyph (buffer->cur(), font);
+        buffer->next_glyph ();
+      }
+      /* Skip any further variation selectors. */
+      while (buffer->idx < end && unlikely (buffer->unicode->is_variation_selector (buffer->cur().codepoint)))
+      {
+        set_glyph (buffer->cur(), font);
+        buffer->next_glyph ();
+      }
+    } else {
+      set_glyph (buffer->cur(), font);
+      buffer->next_glyph ();
+    }
+  }
+  if (likely (buffer->idx < end)) {
+    set_glyph (buffer->cur(), font);
+    buffer->next_glyph ();
+  }
+}
+
+static inline void
+decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
+{
+  hb_buffer_t * const buffer = c->buffer;
+  for (unsigned int i = buffer->idx; i < end && !buffer->in_error; i++)
+    if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) {
+      handle_variation_selector_cluster (c, end, short_circuit);
+      return;
+    }
+
+  while (buffer->idx < end && !buffer->in_error)
+    decompose_current_character (c, short_circuit);
+}
+
+static inline void
+decompose_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool might_short_circuit, bool always_short_circuit)
+{
+  if (likely (c->buffer->idx + 1 == end))
+    decompose_current_character (c, might_short_circuit);
+  else
+    decompose_multi_char_cluster (c, end, always_short_circuit);
+}
+
+
+static int
+compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
+{
+  unsigned int a = _hb_glyph_info_get_modified_combining_class (pa);
+  unsigned int b = _hb_glyph_info_get_modified_combining_class (pb);
+
+  return a < b ? -1 : a == b ? 0 : +1;
+}
+
+
+void
+_hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
+                        hb_buffer_t *buffer,
+                        hb_font_t *font)
+{
+  if (unlikely (!buffer->len)) return;
+
+  _hb_buffer_assert_unicode_vars (buffer);
+
+  hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference;
+  const hb_ot_shape_normalize_context_t c = {
+    plan,
+    buffer,
+    font,
+    buffer->unicode,
+    plan->shaper->decompose ? plan->shaper->decompose : decompose_unicode,
+    plan->shaper->compose   ? plan->shaper->compose   : compose_unicode
+  };
+
+  bool always_short_circuit = mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE;
+  bool might_short_circuit = always_short_circuit ||
+                             (mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED &&
+                              mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT);
+  unsigned int count;
+
+  /* We do a fairly straightforward yet custom normalization process in three
+   * separate rounds: decompose, reorder, recompose (if desired).  Currently
+   * this makes two buffer swaps.  We can make it faster by moving the last
+   * two rounds into the inner loop for the first round, but it's more readable
+   * this way. */
+
+
+  /* First round, decompose */
+
+  buffer->clear_output ();
+  count = buffer->len;
+  for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
+  {
+    unsigned int end;
+    for (end = buffer->idx + 1; end < count; end++)
+      if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end]))))
+        break;
+
+    decompose_cluster (&c, end, might_short_circuit, always_short_circuit);
+  }
+  buffer->swap_buffers ();
+
+
+  /* Second round, reorder (inplace) */
+
+  count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+  {
+    if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]) == 0)
+      continue;
+
+    unsigned int end;
+    for (end = i + 1; end < count; end++)
+      if (_hb_glyph_info_get_modified_combining_class (&buffer->info[end]) == 0)
+        break;
+
+    /* We are going to do a O(n^2).  Only do this if the sequence is short. */
+    if (end - i > 10) {
+      i = end;
+      continue;
+    }
+
+    buffer->sort (i, end, compare_combining_class);
+
+    i = end;
+  }
+
+
+  if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE ||
+      mode == HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED)
+    return;
+
+  /* Third round, recompose */
+
+  /* As noted in the comment earlier, we don't try to combine
+   * ccc=0 chars with their previous Starter. */
+
+  buffer->clear_output ();
+  count = buffer->len;
+  unsigned int starter = 0;
+  buffer->next_glyph ();
+  while (buffer->idx < count && !buffer->in_error)
+  {
+    hb_codepoint_t composed, glyph;
+    if (/* We don't try to compose a non-mark character with it's preceding starter.
+         * This is both an optimization to avoid trying to compose every two neighboring
+         * glyphs in most scripts AND a desired feature for Hangul.  Apparently Hangul
+         * fonts are not designed to mix-and-match pre-composed syllables and Jamo. */
+        HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur())) &&
+        /* If there's anything between the starter and this char, they should have CCC
+         * smaller than this character's. */
+        (starter == buffer->out_len - 1 ||
+         _hb_glyph_info_get_modified_combining_class (&buffer->prev()) < _hb_glyph_info_get_modified_combining_class (&buffer->cur())) &&
+        /* And compose. */
+        c.compose (&c,
+                   buffer->out_info[starter].codepoint,
+                   buffer->cur().codepoint,
+                   &composed) &&
+        /* And the font has glyph for the composite. */
+        font->get_nominal_glyph (composed, &glyph))
+    {
+      /* Composes. */
+      buffer->next_glyph (); /* Copy to out-buffer. */
+      if (unlikely (buffer->in_error))
+        return;
+      buffer->merge_out_clusters (starter, buffer->out_len);
+      buffer->out_len--; /* Remove the second composable. */
+      /* Modify starter and carry on. */
+      buffer->out_info[starter].codepoint = composed;
+      buffer->out_info[starter].glyph_index() = glyph;
+      _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer);
+
+      continue;
+    }
+
+    /* Blocked, or doesn't compose. */
+    buffer->next_glyph ();
+
+    if (_hb_glyph_info_get_modified_combining_class (&buffer->prev()) == 0)
+      starter = buffer->out_len - 1;
+  }
+  buffer->swap_buffers ();
+
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape-private.hh b/src/share/native/sun/font/harfbuzz/hb-ot-shape-private.hh
new file mode 100644
index 0000000..3734827
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape-private.hh
@@ -0,0 +1,104 @@
+/*
+ * Copyright © 2010  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_OT_SHAPE_PRIVATE_HH
+#define HB_OT_SHAPE_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-ot-map-private.hh"
+#include "hb-ot-layout-private.hh"
+
+
+
+struct hb_ot_shape_plan_t
+{
+  hb_segment_properties_t props;
+  const struct hb_ot_complex_shaper_t *shaper;
+  hb_ot_map_t map;
+  const void *data;
+  hb_mask_t rtlm_mask, frac_mask, numr_mask, dnom_mask;
+  hb_mask_t kern_mask;
+  unsigned int has_frac : 1;
+  unsigned int has_kern : 1;
+  unsigned int has_mark : 1;
+
+  inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
+  {
+    unsigned int table_index;
+    switch (table_tag) {
+      case HB_OT_TAG_GSUB: table_index = 0; break;
+      case HB_OT_TAG_GPOS: table_index = 1; break;
+      default: return;
+    }
+    map.collect_lookups (table_index, lookups);
+  }
+  inline void substitute (hb_font_t *font, hb_buffer_t *buffer) const { map.substitute (this, font, buffer); }
+  inline void position (hb_font_t *font, hb_buffer_t *buffer) const { map.position (this, font, buffer); }
+
+  void finish (void) { map.finish (); }
+};
+
+struct hb_ot_shape_planner_t
+{
+  /* In the order that they are filled in. */
+  hb_face_t *face;
+  hb_segment_properties_t props;
+  const struct hb_ot_complex_shaper_t *shaper;
+  hb_ot_map_builder_t map;
+
+  hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan) :
+                         face (master_plan->face_unsafe),
+                         props (master_plan->props),
+                         shaper (NULL),
+                         map (face, &props) {}
+  ~hb_ot_shape_planner_t (void) { map.finish (); }
+
+  inline void compile (hb_ot_shape_plan_t &plan)
+  {
+    plan.props = props;
+    plan.shaper = shaper;
+    map.compile (plan.map);
+
+    plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m'));
+    plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c'));
+    plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r'));
+    plan.dnom_mask = plan.map.get_1_mask (HB_TAG ('d','n','o','m'));
+
+    plan.kern_mask = plan.map.get_mask (HB_DIRECTION_IS_HORIZONTAL (plan.props.direction) ?
+                                        HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n'));
+
+    plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask);
+    plan.has_kern = !!plan.kern_mask;
+    plan.has_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k'));
+  }
+
+  private:
+  NO_COPY (hb_ot_shape_planner_t);
+};
+
+
+#endif /* HB_OT_SHAPE_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-shape.cpp
new file mode 100644
index 0000000..35f2097
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape.cpp
@@ -0,0 +1,872 @@
+/*
+ * Copyright © 2009,2010  Red Hat, Inc.
+ * Copyright © 2010,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
+ */
+
+#define HB_SHAPER ot
+#define hb_ot_shaper_face_data_t hb_ot_layout_t
+#define hb_ot_shaper_shape_plan_data_t hb_ot_shape_plan_t
+#include "hb-shaper-impl-private.hh"
+
+#include "hb-ot-shape-private.hh"
+#include "hb-ot-shape-complex-private.hh"
+#include "hb-ot-shape-fallback-private.hh"
+#include "hb-ot-shape-normalize-private.hh"
+
+#include "hb-ot-layout-private.hh"
+#include "hb-unicode-private.hh"
+#include "hb-set-private.hh"
+
+
+static hb_tag_t common_features[] = {
+  HB_TAG('c','c','m','p'),
+  HB_TAG('l','o','c','l'),
+  HB_TAG('m','a','r','k'),
+  HB_TAG('m','k','m','k'),
+  HB_TAG('r','l','i','g'),
+};
+
+
+static hb_tag_t horizontal_features[] = {
+  HB_TAG('c','a','l','t'),
+  HB_TAG('c','l','i','g'),
+  HB_TAG('c','u','r','s'),
+  HB_TAG('k','e','r','n'),
+  HB_TAG('l','i','g','a'),
+  HB_TAG('r','c','l','t'),
+};
+
+
+
+static void
+hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
+                              const hb_segment_properties_t  *props,
+                              const hb_feature_t             *user_features,
+                              unsigned int                    num_user_features)
+{
+  hb_ot_map_builder_t *map = &planner->map;
+
+  switch (props->direction) {
+    case HB_DIRECTION_LTR:
+      map->add_global_bool_feature (HB_TAG ('l','t','r','a'));
+      map->add_global_bool_feature (HB_TAG ('l','t','r','m'));
+      break;
+    case HB_DIRECTION_RTL:
+      map->add_global_bool_feature (HB_TAG ('r','t','l','a'));
+      map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE);
+      break;
+    case HB_DIRECTION_TTB:
+    case HB_DIRECTION_BTT:
+    case HB_DIRECTION_INVALID:
+    default:
+      break;
+  }
+
+  map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE);
+  map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE);
+  map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE);
+
+  if (planner->shaper->collect_features)
+    planner->shaper->collect_features (planner);
+
+  for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++)
+    map->add_global_bool_feature (common_features[i]);
+
+  if (HB_DIRECTION_IS_HORIZONTAL (props->direction))
+    for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++)
+      map->add_feature (horizontal_features[i], 1, F_GLOBAL |
+                        (horizontal_features[i] == HB_TAG('k','e','r','n') ?
+                         F_HAS_FALLBACK : F_NONE));
+  else
+  {
+    /* We really want to find a 'vert' feature if there's any in the font, no
+     * matter which script/langsys it is listed (or not) under.
+     * See various bugs referenced from:
+     * https://github.com/behdad/harfbuzz/issues/63 */
+    map->add_feature (HB_TAG ('v','e','r','t'), 1, F_GLOBAL | F_GLOBAL_SEARCH);
+  }
+
+  if (planner->shaper->override_features)
+    planner->shaper->override_features (planner);
+
+  for (unsigned int i = 0; i < num_user_features; i++) {
+    const hb_feature_t *feature = &user_features[i];
+    map->add_feature (feature->tag, feature->value,
+                      (feature->start == 0 && feature->end == (unsigned int) -1) ?
+                       F_GLOBAL : F_NONE);
+  }
+}
+
+
+/*
+ * shaper face data
+ */
+
+hb_ot_shaper_face_data_t *
+_hb_ot_shaper_face_data_create (hb_face_t *face)
+{
+  return _hb_ot_layout_create (face);
+}
+
+void
+_hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data)
+{
+  _hb_ot_layout_destroy (data);
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_ot_shaper_font_data_t {};
+
+hb_ot_shaper_font_data_t *
+_hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED)
+{
+  return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data)
+{
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+hb_ot_shaper_shape_plan_data_t *
+_hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
+                                      const hb_feature_t *user_features,
+                                      unsigned int        num_user_features)
+{
+  hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
+  if (unlikely (!plan))
+    return NULL;
+
+  hb_ot_shape_planner_t planner (shape_plan);
+
+  planner.shaper = hb_ot_shape_complex_categorize (&planner);
+
+  hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features);
+
+  planner.compile (*plan);
+
+  if (plan->shaper->data_create) {
+    plan->data = plan->shaper->data_create (plan);
+    if (unlikely (!plan->data))
+      return NULL;
+  }
+
+  return plan;
+}
+
+void
+_hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan)
+{
+  if (plan->shaper->data_destroy)
+    plan->shaper->data_destroy (const_cast<void *> (plan->data));
+
+  plan->finish ();
+
+  free (plan);
+}
+
+
+/*
+ * shaper
+ */
+
+struct hb_ot_shape_context_t
+{
+  hb_ot_shape_plan_t *plan;
+  hb_font_t *font;
+  hb_face_t *face;
+  hb_buffer_t  *buffer;
+  const hb_feature_t *user_features;
+  unsigned int        num_user_features;
+
+  /* Transient stuff */
+  hb_direction_t target_direction;
+};
+
+
+
+/* Main shaper */
+
+
+/* Prepare */
+
+static void
+hb_set_unicode_props (hb_buffer_t *buffer)
+{
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    _hb_glyph_info_set_unicode_props (&info[i], buffer);
+}
+
+static void
+hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
+{
+  if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
+      buffer->context_len[0] ||
+      _hb_glyph_info_get_general_category (&buffer->info[0]) !=
+      HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
+    return;
+
+  if (!font->has_glyph (0x25CCu))
+    return;
+
+  hb_glyph_info_t dottedcircle = {0};
+  dottedcircle.codepoint = 0x25CCu;
+  _hb_glyph_info_set_unicode_props (&dottedcircle, buffer);
+
+  buffer->clear_output ();
+
+  buffer->idx = 0;
+  hb_glyph_info_t info = dottedcircle;
+  info.cluster = buffer->cur().cluster;
+  info.mask = buffer->cur().mask;
+  buffer->output_info (info);
+  while (buffer->idx < buffer->len && !buffer->in_error)
+    buffer->next_glyph ();
+
+  buffer->swap_buffers ();
+}
+
+static void
+hb_form_clusters (hb_buffer_t *buffer)
+{
+  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
+      buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+    return;
+
+  /* Loop duplicated in hb_ensure_native_direction(), and in _hb-coretext.cc */
+  unsigned int base = 0;
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 1; i < count; i++)
+  {
+    if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])) &&
+                !_hb_glyph_info_is_joiner (&info[i])))
+    {
+      buffer->merge_clusters (base, i);
+      base = i;
+    }
+  }
+  buffer->merge_clusters (base, count);
+}
+
+static void
+hb_ensure_native_direction (hb_buffer_t *buffer)
+{
+  hb_direction_t direction = buffer->props.direction;
+
+  /* TODO vertical:
+   * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
+   * Ogham fonts are supposed to be implemented BTT or not.  Need to research that
+   * first. */
+  if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_horizontal_direction (buffer->props.script)) ||
+      (HB_DIRECTION_IS_VERTICAL   (direction) && direction != HB_DIRECTION_TTB))
+  {
+    /* Same loop as hb_form_clusters().
+     * Since form_clusters() merged clusters already, we don't merge. */
+    unsigned int base = 0;
+    unsigned int count = buffer->len;
+    hb_glyph_info_t *info = buffer->info;
+    for (unsigned int i = 1; i < count; i++)
+    {
+      if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i]))))
+      {
+        if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+          buffer->merge_clusters (base, i);
+        buffer->reverse_range (base, i);
+
+        base = i;
+      }
+    }
+    if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+      buffer->merge_clusters (base, count);
+    buffer->reverse_range (base, count);
+
+    buffer->reverse ();
+
+    buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
+  }
+}
+
+
+/* Substitute */
+
+static inline void
+hb_ot_mirror_chars (hb_ot_shape_context_t *c)
+{
+  if (HB_DIRECTION_IS_FORWARD (c->target_direction))
+    return;
+
+  hb_buffer_t *buffer = c->buffer;
+  hb_unicode_funcs_t *unicode = buffer->unicode;
+  hb_mask_t rtlm_mask = c->plan->rtlm_mask;
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++) {
+    hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
+    if (likely (codepoint == info[i].codepoint || !c->font->has_glyph (codepoint)))
+      info[i].mask |= rtlm_mask;
+    else
+      info[i].codepoint = codepoint;
+  }
+}
+
+static inline void
+hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
+{
+  if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
+      !c->plan->has_frac)
+    return;
+
+  hb_buffer_t *buffer = c->buffer;
+
+  /* TODO look in pre/post context text also. */
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+  {
+    if (info[i].codepoint == 0x2044u) /* FRACTION SLASH */
+    {
+      unsigned int start = i, end = i + 1;
+      while (start &&
+             _hb_glyph_info_get_general_category (&info[start - 1]) ==
+             HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
+        start--;
+      while (end < count &&
+             _hb_glyph_info_get_general_category (&info[end]) ==
+             HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
+        end++;
+
+      for (unsigned int j = start; j < i; j++)
+        info[j].mask |= c->plan->numr_mask | c->plan->frac_mask;
+      info[i].mask |= c->plan->frac_mask;
+      for (unsigned int j = i + 1; j < end; j++)
+        info[j].mask |= c->plan->frac_mask | c->plan->dnom_mask;
+
+      i = end - 1;
+    }
+  }
+}
+
+static inline void
+hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c)
+{
+  hb_ot_map_t *map = &c->plan->map;
+  hb_buffer_t *buffer = c->buffer;
+
+  hb_mask_t global_mask = map->get_global_mask ();
+  buffer->reset_masks (global_mask);
+}
+
+static inline void
+hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
+{
+  hb_ot_map_t *map = &c->plan->map;
+  hb_buffer_t *buffer = c->buffer;
+
+  hb_ot_shape_setup_masks_fraction (c);
+
+  if (c->plan->shaper->setup_masks)
+    c->plan->shaper->setup_masks (c->plan, buffer, c->font);
+
+  for (unsigned int i = 0; i < c->num_user_features; i++)
+  {
+    const hb_feature_t *feature = &c->user_features[i];
+    if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
+      unsigned int shift;
+      hb_mask_t mask = map->get_mask (feature->tag, &shift);
+      buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
+    }
+  }
+}
+
+static void
+hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c)
+{
+  hb_buffer_t *buffer = c->buffer;
+
+  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
+      (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
+    return;
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  hb_glyph_position_t *pos = buffer->pos;
+  unsigned int i = 0;
+  for (i = 0; i < count; i++)
+    if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
+      pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
+}
+
+static void
+hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
+{
+  hb_buffer_t *buffer = c->buffer;
+
+  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
+      (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
+    return;
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  hb_glyph_position_t *pos = buffer->pos;
+  unsigned int i = 0;
+  for (i = 0; i < count; i++)
+  {
+    if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
+      break;
+  }
+
+  /* No default-ignorables found; return. */
+  if (i == count)
+    return;
+
+  hb_codepoint_t space;
+  if (c->font->get_nominal_glyph (' ', &space))
+  {
+    /* Replace default-ignorables with a zero-advance space glyph. */
+    for (/*continue*/; i < count; i++)
+    {
+      if (_hb_glyph_info_is_default_ignorable (&info[i]))
+        info[i].codepoint = space;
+    }
+  }
+  else
+  {
+    /* Merge clusters and delete default-ignorables.
+     * NOTE! We can't use out-buffer as we have positioning data. */
+    unsigned int j = i;
+    for (; i < count; i++)
+    {
+      if (_hb_glyph_info_is_default_ignorable (&info[i]))
+      {
+        /* Merge clusters.
+         * Same logic as buffer->delete_glyph(), but for in-place removal. */
+
+        unsigned int cluster = info[i].cluster;
+        if (i + 1 < count && cluster == info[i + 1].cluster)
+          continue; /* Cluster survives; do nothing. */
+
+        if (j)
+        {
+          /* Merge cluster backward. */
+          if (cluster < info[j - 1].cluster)
+          {
+            unsigned int old_cluster = info[j - 1].cluster;
+            for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
+              info[k - 1].cluster = cluster;
+          }
+          continue;
+        }
+
+        if (i + 1 < count)
+          buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */
+
+        continue;
+      }
+
+      if (j != i)
+      {
+        info[j] = info[i];
+        pos[j] = pos[i];
+      }
+      j++;
+    }
+    buffer->len = j;
+  }
+}
+
+
+static inline void
+hb_ot_map_glyphs_fast (hb_buffer_t  *buffer)
+{
+  /* Normalization process sets up glyph_index(), we just copy it. */
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    info[i].codepoint = info[i].glyph_index();
+
+  buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
+}
+
+static inline void
+hb_ot_substitute_default (hb_ot_shape_context_t *c)
+{
+  hb_buffer_t *buffer = c->buffer;
+
+  hb_ot_shape_initialize_masks (c);
+
+  hb_ot_mirror_chars (c);
+
+  HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
+
+  _hb_ot_shape_normalize (c->plan, buffer, c->font);
+
+  hb_ot_shape_setup_masks (c);
+
+  /* This is unfortunate to go here, but necessary... */
+  if (!hb_ot_layout_has_positioning (c->face))
+    _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer);
+
+  hb_ot_map_glyphs_fast (buffer);
+
+  HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index);
+}
+
+static inline void
+hb_ot_substitute_complex (hb_ot_shape_context_t *c)
+{
+  hb_buffer_t *buffer = c->buffer;
+
+  hb_ot_layout_substitute_start (c->font, buffer);
+
+  c->plan->substitute (c->font, buffer);
+
+  return;
+}
+
+static inline void
+hb_ot_substitute (hb_ot_shape_context_t *c)
+{
+  hb_ot_substitute_default (c);
+
+  _hb_buffer_allocate_gsubgpos_vars (c->buffer);
+
+  hb_ot_substitute_complex (c);
+}
+
+/* Position */
+
+static inline void
+adjust_mark_offsets (hb_glyph_position_t *pos)
+{
+  pos->x_offset -= pos->x_advance;
+  pos->y_offset -= pos->y_advance;
+}
+
+static inline void
+zero_mark_width (hb_glyph_position_t *pos)
+{
+  pos->x_advance = 0;
+  pos->y_advance = 0;
+}
+
+static inline void
+zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
+{
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    if (_hb_glyph_info_is_mark (&info[i]))
+    {
+      if (adjust_offsets)
+        adjust_mark_offsets (&buffer->pos[i]);
+      zero_mark_width (&buffer->pos[i]);
+    }
+}
+
+static inline void
+hb_ot_position_default (hb_ot_shape_context_t *c)
+{
+  hb_direction_t direction = c->buffer->props.direction;
+  unsigned int count = c->buffer->len;
+  hb_glyph_info_t *info = c->buffer->info;
+  hb_glyph_position_t *pos = c->buffer->pos;
+
+  if (HB_DIRECTION_IS_HORIZONTAL (direction))
+  {
+    for (unsigned int i = 0; i < count; i++)
+      pos[i].x_advance = c->font->get_glyph_h_advance (info[i].codepoint);
+    /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
+    if (c->font->has_glyph_h_origin_func ())
+      for (unsigned int i = 0; i < count; i++)
+        c->font->subtract_glyph_h_origin (info[i].codepoint,
+                                          &pos[i].x_offset,
+                                          &pos[i].y_offset);
+  }
+  else
+  {
+    for (unsigned int i = 0; i < count; i++)
+    {
+      pos[i].y_advance = c->font->get_glyph_v_advance (info[i].codepoint);
+      c->font->subtract_glyph_v_origin (info[i].codepoint,
+                                        &pos[i].x_offset,
+                                        &pos[i].y_offset);
+    }
+  }
+  if (c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK)
+    _hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer);
+}
+
+static inline bool
+hb_ot_position_complex (hb_ot_shape_context_t *c)
+{
+  hb_ot_layout_position_start (c->font, c->buffer);
+
+  bool ret = false;
+  unsigned int count = c->buffer->len;
+  bool has_positioning = (bool) hb_ot_layout_has_positioning (c->face);
+
+  /* If the font has no GPOS, AND, no fallback positioning will
+   * happen, AND, direction is forward, then when zeroing mark
+   * widths, we shift the mark with it, such that the mark
+   * is positioned hanging over the previous glyph.  When
+   * direction is backward we don't shift and it will end up
+   * hanging over the next glyph after the final reordering.
+   * If fallback positinoing happens or GPOS is present, we don't
+   * care.
+   */
+  bool adjust_offsets_when_zeroing = !(has_positioning || c->plan->shaper->fallback_position ||
+                                       HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction));
+
+  switch (c->plan->shaper->zero_width_marks)
+  {
+    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
+      zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
+      break;
+
+    default:
+    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
+    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
+      break;
+  }
+
+  if (has_positioning)
+  {
+    hb_glyph_info_t *info = c->buffer->info;
+    hb_glyph_position_t *pos = c->buffer->pos;
+
+    /* Change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */
+
+    /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
+    if (c->font->has_glyph_h_origin_func ())
+      for (unsigned int i = 0; i < count; i++)
+        c->font->add_glyph_h_origin (info[i].codepoint,
+                                     &pos[i].x_offset,
+                                     &pos[i].y_offset);
+
+    c->plan->position (c->font, c->buffer);
+
+    /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
+    if (c->font->has_glyph_h_origin_func ())
+      for (unsigned int i = 0; i < count; i++)
+        c->font->subtract_glyph_h_origin (info[i].codepoint,
+                                          &pos[i].x_offset,
+                                          &pos[i].y_offset);
+
+    ret = true;
+  }
+
+  switch (c->plan->shaper->zero_width_marks)
+  {
+    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
+      zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
+      break;
+
+    default:
+    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
+    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
+      break;
+  }
+
+  /* Finishing off GPOS has to follow a certain order. */
+  hb_ot_layout_position_finish_advances (c->font, c->buffer);
+  hb_ot_zero_width_default_ignorables (c);
+  hb_ot_layout_position_finish_offsets (c->font, c->buffer);
+
+  return ret;
+}
+
+static inline void
+hb_ot_position (hb_ot_shape_context_t *c)
+{
+  c->buffer->clear_positions ();
+
+  hb_ot_position_default (c);
+
+  hb_bool_t fallback = !hb_ot_position_complex (c);
+
+  if (fallback && c->plan->shaper->fallback_position)
+    _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
+
+  if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
+    hb_buffer_reverse (c->buffer);
+
+  /* Visual fallback goes here. */
+
+  if (fallback)
+    _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer);
+
+  _hb_buffer_deallocate_gsubgpos_vars (c->buffer);
+}
+
+
+/* Pull it all together! */
+
+static void
+hb_ot_shape_internal (hb_ot_shape_context_t *c)
+{
+  c->buffer->deallocate_var_all ();
+  c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
+  if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_EXPANSION_FACTOR)))
+  {
+    c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_EXPANSION_FACTOR,
+                              (unsigned) HB_BUFFER_MAX_LEN_MIN);
+  }
+
+  /* Save the original direction, we use it later. */
+  c->target_direction = c->buffer->props.direction;
+
+  _hb_buffer_allocate_unicode_vars (c->buffer);
+
+  c->buffer->clear_output ();
+
+  hb_set_unicode_props (c->buffer);
+  hb_insert_dotted_circle (c->buffer, c->font);
+  hb_form_clusters (c->buffer);
+
+  hb_ensure_native_direction (c->buffer);
+
+  if (c->plan->shaper->preprocess_text)
+    c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
+
+  hb_ot_substitute (c);
+  hb_ot_position (c);
+
+  hb_ot_hide_default_ignorables (c);
+
+  if (c->plan->shaper->postprocess_glyphs)
+    c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
+
+  _hb_buffer_deallocate_unicode_vars (c->buffer);
+
+  c->buffer->props.direction = c->target_direction;
+
+  c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
+  c->buffer->deallocate_var_all ();
+}
+
+
+hb_bool_t
+_hb_ot_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_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features};
+  hb_ot_shape_internal (&c);
+
+  return true;
+}
+
+
+/**
+ * hb_ot_shape_plan_collect_lookups:
+ *
+ * Since: 0.9.7
+ **/
+void
+hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
+                                  hb_tag_t         table_tag,
+                                  hb_set_t        *lookup_indexes /* OUT */)
+{
+  /* XXX Does the first part always succeed? */
+  HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes);
+}
+
+
+/* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
+static void
+add_char (hb_font_t          *font,
+          hb_unicode_funcs_t *unicode,
+          hb_bool_t           mirror,
+          hb_codepoint_t      u,
+          hb_set_t           *glyphs)
+{
+  hb_codepoint_t glyph;
+  if (font->get_nominal_glyph (u, &glyph))
+    glyphs->add (glyph);
+  if (mirror)
+  {
+    hb_codepoint_t m = unicode->mirroring (u);
+    if (m != u && font->get_nominal_glyph (m, &glyph))
+      glyphs->add (glyph);
+  }
+}
+
+
+/**
+ * hb_ot_shape_glyphs_closure:
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_ot_shape_glyphs_closure (hb_font_t          *font,
+                            hb_buffer_t        *buffer,
+                            const hb_feature_t *features,
+                            unsigned int        num_features,
+                            hb_set_t           *glyphs)
+{
+  hb_ot_shape_plan_t plan;
+
+  const char *shapers[] = {"ot", NULL};
+  hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
+                                                             features, num_features, shapers);
+
+  bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL;
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs);
+
+  hb_set_t lookups;
+  lookups.init ();
+  hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups);
+
+  /* And find transitive closure. */
+  hb_set_t copy;
+  copy.init ();
+  do {
+    copy.set (glyphs);
+    for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);)
+      hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs);
+  } while (!copy.is_equal (glyphs));
+
+  hb_shape_plan_destroy (shape_plan);
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-shape.h b/src/share/native/sun/font/harfbuzz/hb-ot-shape.h
new file mode 100644
index 0000000..0f38b55
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-shape.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2013  Red Hat, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
+#ifndef HB_OT_SHAPE_H
+#define HB_OT_SHAPE_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+/* TODO port to shape-plan / set. */
+HB_EXTERN void
+hb_ot_shape_glyphs_closure (hb_font_t          *font,
+                            hb_buffer_t        *buffer,
+                            const hb_feature_t *features,
+                            unsigned int        num_features,
+                            hb_set_t           *glyphs);
+
+HB_EXTERN void
+hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
+                                  hb_tag_t         table_tag,
+                                  hb_set_t        *lookup_indexes /* OUT */);
+
+HB_END_DECLS
+
+#endif /* HB_OT_SHAPE_H */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-tag.cpp b/src/share/native/sun/font/harfbuzz/hb-ot-tag.cpp
new file mode 100644
index 0000000..c790888
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-tag.cpp
@@ -0,0 +1,1011 @@
+/*
+ * 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, Roozbeh Pournader
+ */
+
+#include "hb-private.hh"
+
+#include <string.h>
+
+
+
+/* hb_script_t */
+
+static hb_tag_t
+hb_ot_old_tag_from_script (hb_script_t script)
+{
+  /* This seems to be accurate as of end of 2012. */
+
+  switch ((hb_tag_t) script) {
+    case HB_SCRIPT_INVALID:             return HB_OT_TAG_DEFAULT_SCRIPT;
+
+    /* KATAKANA and HIRAGANA both map to 'kana' */
+    case HB_SCRIPT_HIRAGANA:            return HB_TAG('k','a','n','a');
+
+    /* Spaces at the end are preserved, unlike ISO 15924 */
+    case HB_SCRIPT_LAO:                 return HB_TAG('l','a','o',' ');
+    case HB_SCRIPT_YI:                  return HB_TAG('y','i',' ',' ');
+    /* Unicode-5.0 additions */
+    case HB_SCRIPT_NKO:                 return HB_TAG('n','k','o',' ');
+    /* Unicode-5.1 additions */
+    case HB_SCRIPT_VAI:                 return HB_TAG('v','a','i',' ');
+    /* Unicode-5.2 additions */
+    /* Unicode-6.0 additions */
+  }
+
+  /* Else, just change first char to lowercase and return */
+  return ((hb_tag_t) script) | 0x20000000u;
+}
+
+static hb_script_t
+hb_ot_old_tag_to_script (hb_tag_t tag)
+{
+  if (unlikely (tag == HB_OT_TAG_DEFAULT_SCRIPT))
+    return HB_SCRIPT_INVALID;
+
+  /* This side of the conversion is fully algorithmic. */
+
+  /* Any spaces at the end of the tag are replaced by repeating the last
+   * letter.  Eg 'nko ' -> 'Nkoo' */
+  if (unlikely ((tag & 0x0000FF00u) == 0x00002000u))
+    tag |= (tag >> 8) & 0x0000FF00u; /* Copy second letter to third */
+  if (unlikely ((tag & 0x000000FFu) == 0x00000020u))
+    tag |= (tag >> 8) & 0x000000FFu; /* Copy third letter to fourth */
+
+  /* Change first char to uppercase and return */
+  return (hb_script_t) (tag & ~0x20000000u);
+}
+
+static hb_tag_t
+hb_ot_new_tag_from_script (hb_script_t script)
+{
+  switch ((hb_tag_t) script) {
+    case HB_SCRIPT_BENGALI:             return HB_TAG('b','n','g','2');
+    case HB_SCRIPT_DEVANAGARI:          return HB_TAG('d','e','v','2');
+    case HB_SCRIPT_GUJARATI:            return HB_TAG('g','j','r','2');
+    case HB_SCRIPT_GURMUKHI:            return HB_TAG('g','u','r','2');
+    case HB_SCRIPT_KANNADA:             return HB_TAG('k','n','d','2');
+    case HB_SCRIPT_MALAYALAM:           return HB_TAG('m','l','m','2');
+    case HB_SCRIPT_ORIYA:               return HB_TAG('o','r','y','2');
+    case HB_SCRIPT_TAMIL:               return HB_TAG('t','m','l','2');
+    case HB_SCRIPT_TELUGU:              return HB_TAG('t','e','l','2');
+    case HB_SCRIPT_MYANMAR:             return HB_TAG('m','y','m','2');
+  }
+
+  return HB_OT_TAG_DEFAULT_SCRIPT;
+}
+
+static hb_script_t
+hb_ot_new_tag_to_script (hb_tag_t tag)
+{
+  switch (tag) {
+    case HB_TAG('b','n','g','2'):       return HB_SCRIPT_BENGALI;
+    case HB_TAG('d','e','v','2'):       return HB_SCRIPT_DEVANAGARI;
+    case HB_TAG('g','j','r','2'):       return HB_SCRIPT_GUJARATI;
+    case HB_TAG('g','u','r','2'):       return HB_SCRIPT_GURMUKHI;
+    case HB_TAG('k','n','d','2'):       return HB_SCRIPT_KANNADA;
+    case HB_TAG('m','l','m','2'):       return HB_SCRIPT_MALAYALAM;
+    case HB_TAG('o','r','y','2'):       return HB_SCRIPT_ORIYA;
+    case HB_TAG('t','m','l','2'):       return HB_SCRIPT_TAMIL;
+    case HB_TAG('t','e','l','2'):       return HB_SCRIPT_TELUGU;
+    case HB_TAG('m','y','m','2'):       return HB_SCRIPT_MYANMAR;
+  }
+
+  return HB_SCRIPT_UNKNOWN;
+}
+
+/*
+ * Complete list at:
+ * https://www.microsoft.com/typography/otspec/scripttags.htm
+ * https://www.microsoft.com/typography/otspec160/scripttagsProposed.htm
+ *
+ * Most of the script tags are the same as the ISO 15924 tag but lowercased.
+ * So we just do that, and handle the exceptional cases in a switch.
+ */
+
+void
+hb_ot_tags_from_script (hb_script_t  script,
+                        hb_tag_t    *script_tag_1,
+                        hb_tag_t    *script_tag_2)
+{
+  hb_tag_t new_tag;
+
+  *script_tag_2 = HB_OT_TAG_DEFAULT_SCRIPT;
+  *script_tag_1 = hb_ot_old_tag_from_script (script);
+
+  new_tag = hb_ot_new_tag_from_script (script);
+  if (unlikely (new_tag != HB_OT_TAG_DEFAULT_SCRIPT)) {
+    *script_tag_2 = *script_tag_1;
+    *script_tag_1 = new_tag;
+  }
+}
+
+hb_script_t
+hb_ot_tag_to_script (hb_tag_t tag)
+{
+  if (unlikely ((tag & 0x000000FFu) == '2'))
+    return hb_ot_new_tag_to_script (tag);
+
+  return hb_ot_old_tag_to_script (tag);
+}
+
+
+/* hb_language_t */
+
+typedef struct {
+  char language[4];
+  hb_tag_t tag;
+} LangTag;
+
+/*
+ * Complete list at:
+ * http://www.microsoft.com/typography/otspec/languagetags.htm
+ *
+ * Generated by intersecting the OpenType language tag list from
+ * Draft OpenType 1.5 spec, with with the ISO 639-3 codes from
+ * 2008-08-04, matching on name, and finally adjusted manually.
+ *
+ * Updated on 2012-12-07 with more research into remaining codes.
+ *
+ * Updated on 2013-11-23 based on usage in SIL and Microsoft fonts,
+ * the new proposal from Microsoft, and latest ISO 639-3 names.
+ *
+ * Some items still missing.  Those are commented out at the end.
+ * Keep sorted for bsearch.
+ *
+ * Updated as of 2015-05-06: OT1.7 on MS website has some newer
+ * items that we don't have here, eg. Zazaki.  This is the new
+ * items in OpenType 1.7 (red items), most of which we have:
+ * http://www.microsoft.com/typography/otspec170/languagetags.htm
+ */
+
+static const LangTag ot_languages[] = {
+  {"aa",        HB_TAG('A','F','R',' ')},       /* Afar */
+  {"ab",        HB_TAG('A','B','K',' ')},       /* Abkhazian */
+  {"abq",       HB_TAG('A','B','A',' ')},       /* Abaza */
+  {"acf",       HB_TAG('F','A','N',' ')},       /* French Antillean */
+  {"ach",       HB_TAG('A','C','H',' ')},       /* Acoli */
+  {"acr",       HB_TAG('A','C','R',' ')},       /* Achi */
+  {"ada",       HB_TAG('D','N','G',' ')},       /* Dangme */
+  {"ady",       HB_TAG('A','D','Y',' ')},       /* Adyghe */
+  {"af",        HB_TAG('A','F','K',' ')},       /* Afrikaans */
+  {"ahg",       HB_TAG('A','G','W',' ')},       /* Agaw */
+  {"aii",       HB_TAG('S','W','A',' ')},       /* Swadaya Aramaic */
+  {"aio",       HB_TAG('A','I','O',' ')},       /* Aiton */
+  {"aiw",       HB_TAG('A','R','I',' ')},       /* Aari */
+  {"ak",        HB_TAG('T','W','I',' ')},       /* Akan [macrolanguage] */
+  {"aka",       HB_TAG('A','K','A',' ')},       /* Akan */
+  {"alt",       HB_TAG('A','L','T',' ')},       /* [Southern] Altai */
+  {"am",        HB_TAG('A','M','H',' ')},       /* Amharic */
+  {"amf",       HB_TAG('H','B','N',' ')},       /* Hammer-Banna */
+  {"an",        HB_TAG('A','R','G',' ')},       /* Aragonese */
+  {"ang",       HB_TAG('A','N','G',' ')},       /* Old English (ca. 450-1100) */
+  {"ar",        HB_TAG('A','R','A',' ')},       /* Arabic [macrolanguage] */
+  {"arb",       HB_TAG('A','R','A',' ')},       /* Standard Arabic */
+  {"arn",       HB_TAG('M','A','P',' ')},       /* Mapudungun */
+  {"ary",       HB_TAG('M','O','R',' ')},       /* Moroccan Arabic */
+  {"as",        HB_TAG('A','S','M',' ')},       /* Assamese */
+  {"ast",       HB_TAG('A','S','T',' ')},       /* Asturian/Asturleonese/Bable/Leonese */
+  {"ath",       HB_TAG('A','T','H',' ')},       /* Athapaskan [family] */
+  {"atj",       HB_TAG('R','C','R',' ')},       /* R-Cree */
+  {"atv",       HB_TAG('A','L','T',' ')},       /* [Northern] Altai */
+  {"av",        HB_TAG('A','V','R',' ')},       /* Avaric */
+  {"awa",       HB_TAG('A','W','A',' ')},       /* Awadhi */
+  {"ay",        HB_TAG('A','Y','M',' ')},       /* Aymara [macrolanguage] */
+  {"az",        HB_TAG('A','Z','E',' ')},       /* Azerbaijani [macrolanguage] */
+  {"azb",       HB_TAG('A','Z','B',' ')},       /* South Azerbaijani */
+  {"azj",       HB_TAG('A','Z','E',' ')},       /* North Azerbaijani */
+  {"ba",        HB_TAG('B','S','H',' ')},       /* Bashkir */
+  {"bad",       HB_TAG('B','A','D','0')},       /* Banda */
+  {"bai",       HB_TAG('B','M','L',' ')},       /* Bamileke [family] */
+  {"bal",       HB_TAG('B','L','I',' ')},       /* Baluchi [macrolangauge] */
+  {"ban",       HB_TAG('B','A','N',' ')},       /* Balinese */
+  {"bar",       HB_TAG('B','A','R',' ')},       /* Bavarian */
+  {"bbc",       HB_TAG('B','B','C',' ')},       /* Batak Toba */
+  {"bci",       HB_TAG('B','A','U',' ')},       /* Baoulé */
+  {"bcl",       HB_TAG('B','I','K',' ')},       /* Central Bikol */
+  {"bcq",       HB_TAG('B','C','H',' ')},       /* Bench */
+  {"bdy",       HB_TAG('B','D','Y',' ')},       /* Bandjalang */
+  {"be",        HB_TAG('B','E','L',' ')},       /* Belarusian */
+  {"bem",       HB_TAG('B','E','M',' ')},       /* Bemba (Zambia) */
+  {"ber",       HB_TAG('B','E','R',' ')},       /* Berber [family] */
+  {"bfq",       HB_TAG('B','A','D',' ')},       /* Badaga */
+  {"bft",       HB_TAG('B','L','T',' ')},       /* Balti */
+  {"bfu",       HB_TAG('L','A','H',' ')},       /* Lahuli */
+  {"bfy",       HB_TAG('B','A','G',' ')},       /* Baghelkhandi */
+  {"bg",        HB_TAG('B','G','R',' ')},       /* Bulgarian */
+  {"bgc",       HB_TAG('B','G','C',' ')},       /* Haryanvi */
+  {"bgq",       HB_TAG('B','G','Q',' ')},       /* Bagri */
+  {"bhb",       HB_TAG('B','H','I',' ')},       /* Bhili */
+  {"bhk",       HB_TAG('B','I','K',' ')},       /* Albay Bicolano (retired code) */
+  {"bho",       HB_TAG('B','H','O',' ')},       /* Bhojpuri */
+  {"bi",        HB_TAG('B','I','S',' ')},       /* Bislama */
+  {"bik",       HB_TAG('B','I','K',' ')},       /* Bikol [macrolanguage] */
+  {"bin",       HB_TAG('E','D','O',' ')},       /* Bini */
+  {"bjj",       HB_TAG('B','J','J',' ')},       /* Kanauji */
+  {"bjt",       HB_TAG('B','L','N',' ')},       /* Balanta-Ganja */
+  {"bla",       HB_TAG('B','K','F',' ')},       /* Blackfoot */
+  {"ble",       HB_TAG('B','L','N',' ')},       /* Balanta-Kentohe */
+  {"blk",       HB_TAG('B','L','K',' ')},       /* Pa'O/Pa'o Karen */
+  {"bln",       HB_TAG('B','I','K',' ')},       /* Southern Catanduanes Bikol */
+  {"bm",        HB_TAG('B','M','B',' ')},       /* Bambara */
+  {"bn",        HB_TAG('B','E','N',' ')},       /* Bengali */
+  {"bo",        HB_TAG('T','I','B',' ')},       /* Tibetan */
+  {"bpy",       HB_TAG('B','P','Y',' ')},       /* Bishnupriya */
+  {"bqi",       HB_TAG('L','R','C',' ')},       /* Bakhtiari */
+  {"br",        HB_TAG('B','R','E',' ')},       /* Breton */
+  {"bra",       HB_TAG('B','R','I',' ')},       /* Braj Bhasha */
+  {"brh",       HB_TAG('B','R','H',' ')},       /* Brahui */
+  {"brx",       HB_TAG('B','R','X',' ')},       /* Bodo (India) */
+  {"bs",        HB_TAG('B','O','S',' ')},       /* Bosnian */
+  {"btb",       HB_TAG('B','T','I',' ')},       /* Beti (Cameroon) */
+  {"bto",       HB_TAG('B','I','K',' ')},       /* Rinconada Bikol */
+  {"bts",       HB_TAG('B','T','S',' ')},       /* Batak Simalungun */
+  {"bug",       HB_TAG('B','U','G',' ')},       /* Buginese */
+  {"bxr",       HB_TAG('R','B','U',' ')},       /* Russian Buriat */
+  {"byn",       HB_TAG('B','I','L',' ')},       /* Bilen */
+  {"ca",        HB_TAG('C','A','T',' ')},       /* Catalan */
+  {"cak",       HB_TAG('C','A','K',' ')},       /* Kaqchikel */
+  {"cbk",       HB_TAG('C','B','K',' ')},       /* Chavacano */
+  {"ce",        HB_TAG('C','H','E',' ')},       /* Chechen */
+  {"ceb",       HB_TAG('C','E','B',' ')},       /* Cebuano */
+  {"cgg",       HB_TAG('C','G','G',' ')},       /* Chiga */
+  {"ch",        HB_TAG('C','H','A',' ')},       /* Chamorro */
+  {"chk",       HB_TAG('C','H','K','0')},       /* Chuukese */
+  {"cho",       HB_TAG('C','H','O',' ')},       /* Choctaw */
+  {"chp",       HB_TAG('C','H','P',' ')},       /* Chipewyan */
+  {"chr",       HB_TAG('C','H','R',' ')},       /* Cherokee */
+  {"chy",       HB_TAG('C','H','Y',' ')},       /* Cheyenne */
+  {"ckb",       HB_TAG('K','U','R',' ')},       /* Central Kurdish (Sorani) */
+  {"ckt",       HB_TAG('C','H','K',' ')},       /* Chukchi */
+  {"cop",       HB_TAG('C','O','P',' ')},       /* Coptic */
+  {"cpp",       HB_TAG('C','P','P',' ')},       /* Creoles */
+  {"cr",        HB_TAG('C','R','E',' ')},       /* Cree */
+  {"cre",       HB_TAG('Y','C','R',' ')},       /* Y-Cree */
+  {"crh",       HB_TAG('C','R','T',' ')},       /* Crimean Tatar */
+  {"crj",       HB_TAG('E','C','R',' ')},       /* [Southern] East Cree */
+  {"crk",       HB_TAG('W','C','R',' ')},       /* West-Cree */
+  {"crl",       HB_TAG('E','C','R',' ')},       /* [Northern] East Cree */
+  {"crm",       HB_TAG('M','C','R',' ')},       /* Moose Cree */
+  {"crx",       HB_TAG('C','R','R',' ')},       /* Carrier */
+  {"cs",        HB_TAG('C','S','Y',' ')},       /* Czech */
+  {"csb",       HB_TAG('C','S','B',' ')},       /* Kashubian */
+  {"ctg",       HB_TAG('C','T','G',' ')},       /* Chittagonian */
+  {"cts",       HB_TAG('B','I','K',' ')},       /* Northern Catanduanes Bikol */
+  {"cu",        HB_TAG('C','S','L',' ')},       /* Church Slavic */
+  {"cuk",       HB_TAG('C','U','K',' ')},       /* San Blas Kuna */
+  {"cv",        HB_TAG('C','H','U',' ')},       /* Chuvash */
+  {"cwd",       HB_TAG('D','C','R',' ')},       /* Woods Cree */
+  {"cy",        HB_TAG('W','E','L',' ')},       /* Welsh */
+  {"da",        HB_TAG('D','A','N',' ')},       /* Danish */
+  {"dap",       HB_TAG('N','I','S',' ')},       /* Nisi (India) */
+  {"dar",       HB_TAG('D','A','R',' ')},       /* Dargwa */
+  {"dax",       HB_TAG('D','A','X',' ')},       /* Dayi */
+  {"de",        HB_TAG('D','E','U',' ')},       /* German */
+  {"dgo",       HB_TAG('D','G','O',' ')},       /* Dogri */
+  {"dhd",       HB_TAG('M','A','W',' ')},       /* Dhundari */
+  {"dhg",       HB_TAG('D','H','G',' ')},       /* Dhangu */
+  {"din",       HB_TAG('D','N','K',' ')},       /* Dinka [macrolanguage] */
+  {"diq",       HB_TAG('D','I','Q',' ')},       /* Dimli */
+  {"dje",       HB_TAG('D','J','R',' ')},       /* Zarma */
+  {"djr",       HB_TAG('D','J','R','0')},       /* Djambarrpuyngu */
+  {"dng",       HB_TAG('D','U','N',' ')},       /* Dungan */
+  {"dnj",       HB_TAG('D','N','J',' ')},       /* Dan */
+  {"doi",       HB_TAG('D','G','R',' ')},       /* Dogri [macrolanguage] */
+  {"dsb",       HB_TAG('L','S','B',' ')},       /* Lower Sorbian */
+  {"duj",       HB_TAG('D','U','J',' ')},       /* Dhuwal */
+  {"dv",        HB_TAG('D','I','V',' ')},       /* Dhivehi/Divehi/Maldivian */
+  {"dyu",       HB_TAG('J','U','L',' ')},       /* Jula */
+  {"dz",        HB_TAG('D','Z','N',' ')},       /* Dzongkha */
+  {"ee",        HB_TAG('E','W','E',' ')},       /* Ewe */
+  {"efi",       HB_TAG('E','F','I',' ')},       /* Efik */
+  {"ekk",       HB_TAG('E','T','I',' ')},       /* Standard Estonian */
+  {"el",        HB_TAG('E','L','L',' ')},       /* Modern Greek (1453-) */
+  {"emk",       HB_TAG('M','N','K',' ')},       /* Eastern Maninkakan */
+  {"en",        HB_TAG('E','N','G',' ')},       /* English */
+  {"enf",       HB_TAG('F','N','E',' ')},       /* Forest Nenets */
+  {"enh",       HB_TAG('T','N','E',' ')},       /* Tundra Nenets */
+  {"eo",        HB_TAG('N','T','O',' ')},       /* Esperanto */
+  {"eot",       HB_TAG('B','T','I',' ')},       /* Beti (Côte d'Ivoire) */
+  {"es",        HB_TAG('E','S','P',' ')},       /* Spanish */
+  {"esu",       HB_TAG('E','S','U',' ')},       /* Central Yupik */
+  {"et",        HB_TAG('E','T','I',' ')},       /* Estonian [macrolanguage] */
+  {"eu",        HB_TAG('E','U','Q',' ')},       /* Basque */
+  {"eve",       HB_TAG('E','V','N',' ')},       /* Even */
+  {"evn",       HB_TAG('E','V','K',' ')},       /* Evenki */
+  {"fa",        HB_TAG('F','A','R',' ')},       /* Persian [macrolanguage] */
+  {"fan",       HB_TAG('F','A','N','0')},       /* Fang */
+  {"fat",       HB_TAG('F','A','T',' ')},       /* Fanti */
+  {"ff",        HB_TAG('F','U','L',' ')},       /* Fulah [macrolanguage] */
+  {"fi",        HB_TAG('F','I','N',' ')},       /* Finnish */
+  {"fil",       HB_TAG('P','I','L',' ')},       /* Filipino */
+  {"fj",        HB_TAG('F','J','I',' ')},       /* Fijian */
+  {"flm",       HB_TAG('H','A','L',' ')},       /* Halam */
+  {"fo",        HB_TAG('F','O','S',' ')},       /* Faroese */
+  {"fon",       HB_TAG('F','O','N',' ')},       /* Fon */
+  {"fr",        HB_TAG('F','R','A',' ')},       /* French */
+  {"frc",       HB_TAG('F','R','C',' ')},       /* Cajun French */
+  {"frp",       HB_TAG('F','R','P',' ')},       /* Arpitan/Francoprovençal */
+  {"fuf",       HB_TAG('F','T','A',' ')},       /* Futa */
+  {"fur",       HB_TAG('F','R','L',' ')},       /* Friulian */
+  {"fuv",       HB_TAG('F','U','V',' ')},       /* Nigerian Fulfulde */
+  {"fy",        HB_TAG('F','R','I',' ')},       /* Western Frisian */
+  {"ga",        HB_TAG('I','R','I',' ')},       /* Irish */
+  {"gaa",       HB_TAG('G','A','D',' ')},       /* Ga */
+  {"gag",       HB_TAG('G','A','G',' ')},       /* Gagauz */
+  {"gbm",       HB_TAG('G','A','W',' ')},       /* Garhwali */
+  {"gd",        HB_TAG('G','A','E',' ')},       /* Scottish Gaelic */
+  {"gez",       HB_TAG('G','E','Z',' ')},       /* Ge'ez */
+  {"ggo",       HB_TAG('G','O','N',' ')},       /* Southern Gondi */
+  {"gih",       HB_TAG('G','I','H',' ')},       /* Githabul */
+  {"gil",       HB_TAG('G','I','L','0')},       /* Kiribati (Gilbertese) */
+  {"gkp",       HB_TAG('G','K','P',' ')},       /* Kpelle (Guinea) */
+  {"gl",        HB_TAG('G','A','L',' ')},       /* Galician */
+  {"gld",       HB_TAG('N','A','N',' ')},       /* Nanai */
+  {"gle",       HB_TAG('I','R','T',' ')},       /* Irish Traditional */
+  {"glk",       HB_TAG('G','L','K',' ')},       /* Gilaki */
+  {"gn",        HB_TAG('G','U','A',' ')},       /* Guarani [macrolanguage] */
+  {"gnn",       HB_TAG('G','N','N',' ')},       /* Gumatj */
+  {"gno",       HB_TAG('G','O','N',' ')},       /* Northern Gondi */
+  {"gog",       HB_TAG('G','O','G',' ')},       /* Gogo */
+  {"gon",       HB_TAG('G','O','N',' ')},       /* Gondi [macrolanguage] */
+  {"grt",       HB_TAG('G','R','O',' ')},       /* Garo */
+  {"gru",       HB_TAG('S','O','G',' ')},       /* Sodo Gurage */
+  {"gsw",       HB_TAG('A','L','S',' ')},       /* Alsatian */
+  {"gu",        HB_TAG('G','U','J',' ')},       /* Gujarati */
+  {"guc",       HB_TAG('G','U','C',' ')},       /* Wayuu */
+  {"guf",       HB_TAG('G','U','F',' ')},       /* Gupapuyngu */
+  {"guk",       HB_TAG('G','M','Z',' ')},       /* Gumuz */
+/*{"guk",       HB_TAG('G','U','K',' ')},*/     /* Gumuz (in SIL fonts) */
+  {"guz",       HB_TAG('G','U','Z',' ')},       /* Ekegusii/Gusii */
+  {"gv",        HB_TAG('M','N','X',' ')},       /* Manx */
+  {"ha",        HB_TAG('H','A','U',' ')},       /* Hausa */
+  {"har",       HB_TAG('H','R','I',' ')},       /* Harari */
+  {"haw",       HB_TAG('H','A','W',' ')},       /* Hawaiian */
+  {"hay",       HB_TAG('H','A','Y',' ')},       /* Haya */
+  {"haz",       HB_TAG('H','A','Z',' ')},       /* Hazaragi */
+  {"he",        HB_TAG('I','W','R',' ')},       /* Hebrew */
+  {"hi",        HB_TAG('H','I','N',' ')},       /* Hindi */
+  {"hil",       HB_TAG('H','I','L',' ')},       /* Hiligaynon */
+  {"hmn",       HB_TAG('H','M','N',' ')},       /* Hmong */
+  {"hnd",       HB_TAG('H','N','D',' ')},       /* [Southern] Hindko */
+  {"hne",       HB_TAG('C','H','H',' ')},       /* Chattisgarhi */
+  {"hno",       HB_TAG('H','N','D',' ')},       /* [Northern] Hindko */
+  {"ho",        HB_TAG('H','M','O',' ')},       /* Hiri Motu */
+  {"hoc",       HB_TAG('H','O',' ',' ')},       /* Ho */
+  {"hoj",       HB_TAG('H','A','R',' ')},       /* Harauti */
+  {"hr",        HB_TAG('H','R','V',' ')},       /* Croatian */
+  {"hsb",       HB_TAG('U','S','B',' ')},       /* Upper Sorbian */
+  {"ht",        HB_TAG('H','A','I',' ')},       /* Haitian/Haitian Creole */
+  {"hu",        HB_TAG('H','U','N',' ')},       /* Hungarian */
+  {"hy",        HB_TAG('H','Y','E',' ')},       /* Armenian */
+  {"hz",        HB_TAG('H','E','R',' ')},       /* Herero */
+  {"ia",        HB_TAG('I','N','A',' ')},       /* Interlingua (International Auxiliary Language Association) */
+  {"iba",       HB_TAG('I','B','A',' ')},       /* Iban */
+  {"ibb",       HB_TAG('I','B','B',' ')},       /* Ibibio */
+  {"id",        HB_TAG('I','N','D',' ')},       /* Indonesian */
+  {"ie",        HB_TAG('I','L','E',' ')},       /* Interlingue/Occidental */
+  {"ig",        HB_TAG('I','B','O',' ')},       /* Igbo */
+  {"igb",       HB_TAG('E','B','I',' ')},       /* Ebira */
+  {"ii",        HB_TAG('Y','I','M',' ')},       /* Yi Modern */
+  {"ijc",       HB_TAG('I','J','O',' ')},       /* Izon */
+  {"ijo",       HB_TAG('I','J','O',' ')},       /* Ijo [family] */
+  {"ik",        HB_TAG('I','P','K',' ')},       /* Inupiaq [macrolanguage] */
+  {"ilo",       HB_TAG('I','L','O',' ')},       /* Ilokano */
+  {"inh",       HB_TAG('I','N','G',' ')},       /* Ingush */
+  {"io",        HB_TAG('I','D','O',' ')},       /* Ido */
+  {"is",        HB_TAG('I','S','L',' ')},       /* Icelandic */
+  {"it",        HB_TAG('I','T','A',' ')},       /* Italian */
+  {"iu",        HB_TAG('I','N','U',' ')},       /* Inuktitut [macrolanguage] */
+  {"ja",        HB_TAG('J','A','N',' ')},       /* Japanese */
+  {"jam",       HB_TAG('J','A','M',' ')},       /* Jamaican Creole English */
+  {"jbo",       HB_TAG('J','B','O',' ')},       /* Lojban */
+  {"jv",        HB_TAG('J','A','V',' ')},       /* Javanese */
+  {"ka",        HB_TAG('K','A','T',' ')},       /* Georgian */
+  {"kaa",       HB_TAG('K','R','K',' ')},       /* Karakalpak */
+  {"kab",       HB_TAG('K','A','B','0')},       /* Kabyle */
+  {"kam",       HB_TAG('K','M','B',' ')},       /* Kamba (Kenya) */
+  {"kar",       HB_TAG('K','R','N',' ')},       /* Karen [family] */
+  {"kat",       HB_TAG('K','G','E',' ')},       /* Khutsuri Georgian */
+  {"kbd",       HB_TAG('K','A','B',' ')},       /* Kabardian */
+  {"kde",       HB_TAG('K','D','E',' ')},       /* Makonde */
+  {"kdr",       HB_TAG('K','R','M',' ')},       /* Karaim */
+  {"kdt",       HB_TAG('K','U','Y',' ')},       /* Kuy */
+  {"kea",       HB_TAG('K','E','A',' ')},       /* Kabuverdianu (Crioulo) */
+  {"kek",       HB_TAG('K','E','K',' ')},       /* Kekchi */
+  {"kex",       HB_TAG('K','K','N',' ')},       /* Kokni */
+  {"kfa",       HB_TAG('K','O','D',' ')},       /* Kodagu */
+  {"kfr",       HB_TAG('K','A','C',' ')},       /* Kachchi */
+  {"kfx",       HB_TAG('K','U','L',' ')},       /* Kulvi */
+  {"kfy",       HB_TAG('K','M','N',' ')},       /* Kumaoni */
+  {"kg",        HB_TAG('K','O','N',' ')},       /* Kongo [macrolanguage] */
+  {"kha",       HB_TAG('K','S','I',' ')},       /* Khasi */
+  {"khb",       HB_TAG('X','B','D',' ')},       /* Lü */
+  {"kht",       HB_TAG('K','H','N',' ')},       /* Khamti (Microsoft fonts) */
+/*{"kht",       HB_TAG('K','H','T',' ')},*/     /* Khamti (OpenType spec and SIL fonts) */
+  {"khw",       HB_TAG('K','H','W',' ')},       /* Khowar */
+  {"ki",        HB_TAG('K','I','K',' ')},       /* Gikuyu/Kikuyu */
+  {"kiu",       HB_TAG('K','I','U',' ')},       /* Kirmanjki */
+  {"kj",        HB_TAG('K','U','A',' ')},       /* Kuanyama/Kwanyama */
+  {"kjd",       HB_TAG('K','J','D',' ')},       /* Southern Kiwai */
+  {"kjh",       HB_TAG('K','H','A',' ')},       /* Khakass */
+  {"kjp",       HB_TAG('K','J','P',' ')},       /* Pwo Eastern Karen */
+  {"kk",        HB_TAG('K','A','Z',' ')},       /* Kazakh */
+  {"kl",        HB_TAG('G','R','N',' ')},       /* Kalaallisut */
+  {"kln",       HB_TAG('K','A','L',' ')},       /* Kalenjin */
+  {"km",        HB_TAG('K','H','M',' ')},       /* Central Khmer */
+  {"kmb",       HB_TAG('M','B','N',' ')},       /* Kimbundu */
+  {"kmw",       HB_TAG('K','M','O',' ')},       /* Komo (Democratic Republic of Congo) */
+  {"kn",        HB_TAG('K','A','N',' ')},       /* Kannada */
+  {"knn",       HB_TAG('K','O','K',' ')},       /* Konkani */
+  {"ko",        HB_TAG('K','O','R',' ')},       /* Korean */
+  {"koi",       HB_TAG('K','O','P',' ')},       /* Komi-Permyak */
+  {"kok",       HB_TAG('K','O','K',' ')},       /* Konkani [macrolanguage] */
+  {"kon",       HB_TAG('K','O','N','0')},       /* Kongo */
+  {"kos",       HB_TAG('K','O','S',' ')},       /* Kosraean */
+  {"kpe",       HB_TAG('K','P','L',' ')},       /* Kpelle [macrolanguage] */
+  {"kpv",       HB_TAG('K','O','Z',' ')},       /* Komi-Zyrian */
+  {"kpy",       HB_TAG('K','Y','K',' ')},       /* Koryak */
+  {"kqy",       HB_TAG('K','R','T',' ')},       /* Koorete */
+  {"kr",        HB_TAG('K','N','R',' ')},       /* Kanuri [macrolanguage] */
+  {"kri",       HB_TAG('K','R','I',' ')},       /* Krio */
+  {"krl",       HB_TAG('K','R','L',' ')},       /* Karelian */
+  {"kru",       HB_TAG('K','U','U',' ')},       /* Kurukh */
+  {"ks",        HB_TAG('K','S','H',' ')},       /* Kashmiri */
+  {"ksh",       HB_TAG('K','S','H','0')},       /* Ripuarian, Kölsch */
+/*{"ksw",       HB_TAG('K','R','N',' ')},*/     /* S'gaw Karen (Microsoft fonts?) */
+  {"ksw",       HB_TAG('K','S','W',' ')},       /* S'gaw Karen (OpenType spec and SIL fonts) */
+  {"ktb",       HB_TAG('K','E','B',' ')},       /* Kebena */
+  {"ktu",       HB_TAG('K','O','N',' ')},       /* Kikongo */
+  {"ku",        HB_TAG('K','U','R',' ')},       /* Kurdish [macrolanguage] */
+  {"kum",       HB_TAG('K','U','M',' ')},       /* Kumyk */
+  {"kv",        HB_TAG('K','O','M',' ')},       /* Komi [macrolanguage] */
+  {"kvd",       HB_TAG('K','U','I',' ')},       /* Kui (Indonesia) */
+  {"kw",        HB_TAG('C','O','R',' ')},       /* Cornish */
+  {"kxc",       HB_TAG('K','M','S',' ')},       /* Komso */
+  {"kxu",       HB_TAG('K','U','I',' ')},       /* Kui (India) */
+  {"ky",        HB_TAG('K','I','R',' ')},       /* Kirghiz/Kyrgyz */
+  {"kyu",       HB_TAG('K','Y','U',' ')},       /* Western Kayah */
+  {"la",        HB_TAG('L','A','T',' ')},       /* Latin */
+  {"lad",       HB_TAG('J','U','D',' ')},       /* Ladino */
+  {"lb",        HB_TAG('L','T','Z',' ')},       /* Luxembourgish */
+  {"lbe",       HB_TAG('L','A','K',' ')},       /* Lak */
+  {"lbj",       HB_TAG('L','D','K',' ')},       /* Ladakhi */
+  {"lez",       HB_TAG('L','E','Z',' ')},       /* Lezgi */
+  {"lg",        HB_TAG('L','U','G',' ')},       /* Ganda */
+  {"li",        HB_TAG('L','I','M',' ')},       /* Limburgan/Limburger/Limburgish */
+  {"lif",       HB_TAG('L','M','B',' ')},       /* Limbu */
+  {"lij",       HB_TAG('L','I','J',' ')},       /* Ligurian */
+  {"lis",       HB_TAG('L','I','S',' ')},       /* Lisu */
+  {"ljp",       HB_TAG('L','J','P',' ')},       /* Lampung Api */
+  {"lki",       HB_TAG('L','K','I',' ')},       /* Laki */
+  {"lld",       HB_TAG('L','A','D',' ')},       /* Ladin */
+  {"lmn",       HB_TAG('L','A','M',' ')},       /* Lambani */
+  {"lmo",       HB_TAG('L','M','O',' ')},       /* Lombard */
+  {"ln",        HB_TAG('L','I','N',' ')},       /* Lingala */
+  {"lo",        HB_TAG('L','A','O',' ')},       /* Lao */
+  {"lom",       HB_TAG('L','O','M',' ')},       /* Loma */
+  {"lrc",       HB_TAG('L','R','C',' ')},       /* Northern Luri */
+  {"lt",        HB_TAG('L','T','H',' ')},       /* Lithuanian */
+  {"lu",        HB_TAG('L','U','B',' ')},       /* Luba-Katanga */
+  {"lua",       HB_TAG('L','U','B',' ')},       /* Luba-Kasai */
+  {"luo",       HB_TAG('L','U','O',' ')},       /* Luo (Kenya and Tanzania) */
+  {"lus",       HB_TAG('M','I','Z',' ')},       /* Mizo */
+  {"luy",       HB_TAG('L','U','H',' ')},       /* Luyia/Oluluyia [macrolanguage] */
+  {"luz",       HB_TAG('L','R','C',' ')},       /* Southern Luri */
+  {"lv",        HB_TAG('L','V','I',' ')},       /* Latvian */
+  {"lzz",       HB_TAG('L','A','Z',' ')},       /* Laz */
+  {"mad",       HB_TAG('M','A','D',' ')},       /* Madurese */
+  {"mag",       HB_TAG('M','A','G',' ')},       /* Magahi */
+  {"mai",       HB_TAG('M','T','H',' ')},       /* Maithili */
+  {"mak",       HB_TAG('M','K','R',' ')},       /* Makasar */
+  {"mal",       HB_TAG('M','A','L',' ')},       /* Malayalam */
+  {"mam",       HB_TAG('M','A','M',' ')},       /* Mam */
+  {"man",       HB_TAG('M','N','K',' ')},       /* Manding/Mandingo [macrolanguage] */
+  {"mdc",       HB_TAG('M','L','E',' ')},       /* Male (Papua New Guinea) */
+  {"mdf",       HB_TAG('M','O','K',' ')},       /* Moksha */
+  {"mdr",       HB_TAG('M','D','R',' ')},       /* Mandar */
+  {"mdy",       HB_TAG('M','L','E',' ')},       /* Male (Ethiopia) */
+  {"men",       HB_TAG('M','D','E',' ')},       /* Mende (Sierra Leone) */
+  {"mer",       HB_TAG('M','E','R',' ')},       /* Meru */
+  {"mfe",       HB_TAG('M','F','E',' ')},       /* Morisyen */
+  {"mg",        HB_TAG('M','L','G',' ')},       /* Malagasy [macrolanguage] */
+  {"mh",        HB_TAG('M','A','H',' ')},       /* Marshallese */
+  {"mhr",       HB_TAG('L','M','A',' ')},       /* Low Mari */
+  {"mi",        HB_TAG('M','R','I',' ')},       /* Maori */
+  {"min",       HB_TAG('M','I','N',' ')},       /* Minangkabau */
+  {"mk",        HB_TAG('M','K','D',' ')},       /* Macedonian */
+  {"mku",       HB_TAG('M','N','K',' ')},       /* Konyanka Maninka */
+  {"mkw",       HB_TAG('M','K','W',' ')},       /* Kituba (Congo) */
+  {"ml",        HB_TAG('M','L','R',' ')},       /* Malayalam */
+  {"mlq",       HB_TAG('M','N','K',' ')},       /* Western Maninkakan */
+  {"mn",        HB_TAG('M','N','G',' ')},       /* Mongolian [macrolanguage] */
+  {"mnc",       HB_TAG('M','C','H',' ')},       /* Manchu */
+  {"mni",       HB_TAG('M','N','I',' ')},       /* Manipuri */
+  {"mnk",       HB_TAG('M','N','D',' ')},       /* Mandinka */
+  {"mns",       HB_TAG('M','A','N',' ')},       /* Mansi */
+  {"mnw",       HB_TAG('M','O','N',' ')},       /* Mon */
+  {"mo",        HB_TAG('M','O','L',' ')},       /* Moldavian */
+  {"moh",       HB_TAG('M','O','H',' ')},       /* Mohawk */
+  {"mos",       HB_TAG('M','O','S',' ')},       /* Mossi */
+  {"mpe",       HB_TAG('M','A','J',' ')},       /* Majang */
+  {"mr",        HB_TAG('M','A','R',' ')},       /* Marathi */
+  {"mrj",       HB_TAG('H','M','A',' ')},       /* High Mari */
+  {"ms",        HB_TAG('M','L','Y',' ')},       /* Malay [macrolanguage] */
+  {"msc",       HB_TAG('M','N','K',' ')},       /* Sankaran Maninka */
+  {"mt",        HB_TAG('M','T','S',' ')},       /* Maltese */
+  {"mtr",       HB_TAG('M','A','W',' ')},       /* Mewari */
+  {"mus",       HB_TAG('M','U','S',' ')},       /* Creek */
+  {"mve",       HB_TAG('M','A','W',' ')},       /* Marwari (Pakistan) */
+  {"mwk",       HB_TAG('M','N','K',' ')},       /* Kita Maninkakan */
+  {"mwl",       HB_TAG('M','W','L',' ')},       /* Mirandese */
+  {"mwr",       HB_TAG('M','A','W',' ')},       /* Marwari [macrolanguage] */
+  {"mww",       HB_TAG('M','W','W',' ')},       /* Hmong Daw */
+  {"my",        HB_TAG('B','R','M',' ')},       /* Burmese */
+  {"mym",       HB_TAG('M','E','N',' ')},       /* Me'en */
+  {"myn",       HB_TAG('M','Y','N',' ')},       /* Mayan */
+  {"myq",       HB_TAG('M','N','K',' ')},       /* Forest Maninka (retired code) */
+  {"myv",       HB_TAG('E','R','Z',' ')},       /* Erzya */
+  {"mzn",       HB_TAG('M','Z','N',' ')},       /* Mazanderani */
+  {"na",        HB_TAG('N','A','U',' ')},       /* Nauru */
+  {"nag",       HB_TAG('N','A','G',' ')},       /* Naga-Assamese */
+  {"nah",       HB_TAG('N','A','H',' ')},       /* Nahuatl [family] */
+  {"nap",       HB_TAG('N','A','P',' ')},       /* Neapolitan */
+  {"nb",        HB_TAG('N','O','R',' ')},       /* Norwegian Bokmål */
+  {"nco",       HB_TAG('S','I','B',' ')},       /* Sibe */
+  {"nd",        HB_TAG('N','D','B',' ')},       /* [North] Ndebele */
+  {"ndc",       HB_TAG('N','D','C',' ')},       /* Ndau */
+  {"nds",       HB_TAG('N','D','S',' ')},       /* Low German/Low Saxon */
+  {"ne",        HB_TAG('N','E','P',' ')},       /* Nepali */
+  {"new",       HB_TAG('N','E','W',' ')},       /* Newari */
+  {"ng",        HB_TAG('N','D','G',' ')},       /* Ndonga */
+  {"nga",       HB_TAG('N','G','A',' ')},       /* Ngabaka */
+  {"ngl",       HB_TAG('L','M','W',' ')},       /* Lomwe */
+  {"ngo",       HB_TAG('S','X','T',' ')},       /* Sutu */
+  {"niu",       HB_TAG('N','I','U',' ')},       /* Niuean */
+  {"niv",       HB_TAG('G','I','L',' ')},       /* Gilyak */
+  {"nl",        HB_TAG('N','L','D',' ')},       /* Dutch */
+  {"nn",        HB_TAG('N','Y','N',' ')},       /* Norwegian Nynorsk */
+  {"no",        HB_TAG('N','O','R',' ')},       /* Norwegian [macrolanguage] */
+  {"nod",       HB_TAG('N','T','A',' ')},       /* Northern Thai */
+  {"noe",       HB_TAG('N','O','E',' ')},       /* Nimadi */
+  {"nog",       HB_TAG('N','O','G',' ')},       /* Nogai */
+  {"nov",       HB_TAG('N','O','V',' ')},       /* Novial */
+  {"nqo",       HB_TAG('N','K','O',' ')},       /* N'Ko */
+  {"nr",        HB_TAG('N','D','B',' ')},       /* [South] Ndebele */
+  {"nsk",       HB_TAG('N','A','S',' ')},       /* Naskapi */
+  {"nso",       HB_TAG('S','O','T',' ')},       /* [Northern] Sotho */
+  {"nv",        HB_TAG('N','A','V',' ')},       /* Navajo */
+  {"ny",        HB_TAG('C','H','I',' ')},       /* Chewa/Chichwa/Nyanja */
+  {"nym",       HB_TAG('N','Y','M',' ')},       /* Nyamwezi */
+  {"nyn",       HB_TAG('N','K','L',' ')},       /* Nyankole */
+  {"oc",        HB_TAG('O','C','I',' ')},       /* Occitan (post 1500) */
+  {"oj",        HB_TAG('O','J','B',' ')},       /* Ojibwa [macrolanguage] */
+  {"ojs",       HB_TAG('O','C','R',' ')},       /* Oji-Cree */
+  {"okm",       HB_TAG('K','O','H',' ')},       /* Korean Old Hangul */
+  {"om",        HB_TAG('O','R','O',' ')},       /* Oromo [macrolanguage] */
+  {"or",        HB_TAG('O','R','I',' ')},       /* Oriya */
+  {"os",        HB_TAG('O','S','S',' ')},       /* Ossetian */
+  {"pa",        HB_TAG('P','A','N',' ')},       /* Panjabi */
+  {"pag",       HB_TAG('P','A','G',' ')},       /* Pangasinan */
+  {"pam",       HB_TAG('P','A','M',' ')},       /* Kapampangan/Pampanga */
+  {"pap",       HB_TAG('P','A','P','0')},       /* Papiamento */
+  {"pau",       HB_TAG('P','A','U',' ')},       /* Palauan */
+  {"pcc",       HB_TAG('P','C','C',' ')},       /* Bouyei */
+  {"pcd",       HB_TAG('P','C','D',' ')},       /* Picard */
+  {"pce",       HB_TAG('P','L','G',' ')},       /* [Ruching] Palaung */
+  {"pdc",       HB_TAG('P','D','C',' ')},       /* Pennsylvania German */
+  {"pes",       HB_TAG('F','A','R',' ')},       /* Iranian Persian */
+  {"phk",       HB_TAG('P','H','K',' ')},       /* Phake */
+  {"pi",        HB_TAG('P','A','L',' ')},       /* Pali */
+  {"pih",       HB_TAG('P','I','H',' ')},       /* Pitcairn-Norfolk */
+  {"pl",        HB_TAG('P','L','K',' ')},       /* Polish */
+  {"pll",       HB_TAG('P','L','G',' ')},       /* [Shwe] Palaung */
+  {"plp",       HB_TAG('P','A','P',' ')},       /* Palpa */
+  {"pms",       HB_TAG('P','M','S',' ')},       /* Piemontese */
+  {"pnb",       HB_TAG('P','N','B',' ')},       /* Western Panjabi */
+  {"poh",       HB_TAG('P','O','H',' ')},       /* Pocomchi */
+  {"pon",       HB_TAG('P','O','N',' ')},       /* Pohnpeian */
+  {"prs",       HB_TAG('D','R','I',' ')},       /* Afghan Persian/Dari */
+  {"ps",        HB_TAG('P','A','S',' ')},       /* Pashto/Pushto [macrolanguage] */
+  {"pt",        HB_TAG('P','T','G',' ')},       /* Portuguese */
+  {"pwo",       HB_TAG('P','W','O',' ')},       /* Pwo Western Karen */
+  {"qu",        HB_TAG('Q','U','Z',' ')},       /* Quechua [macrolanguage] */
+  {"quc",       HB_TAG('Q','U','C',' ')},       /* K'iche'/Quiché */
+  {"quh",       HB_TAG('Q','U','H',' ')},       /* Quechua (Bolivia) */
+  {"quz",       HB_TAG('Q','U','Z',' ')},       /* Cusco Quechua */
+  {"qvi",       HB_TAG('Q','V','I',' ')},       /* Quechua (Ecuador) */
+  {"qwh",       HB_TAG('Q','W','H',' ')},       /* Quechua (Peru) */
+  {"raj",       HB_TAG('R','A','J',' ')},       /* Rajasthani [macrolanguage] */
+  {"rar",       HB_TAG('R','A','R',' ')},       /* Rarotongan */
+  {"rbb",       HB_TAG('P','L','G',' ')},       /* Rumai Palaung */
+  {"rej",       HB_TAG('R','E','J',' ')},       /* Rejang */
+  {"ria",       HB_TAG('R','I','A',' ')},       /* Riang (India) */
+  {"rif",       HB_TAG('R','I','F',' ')},       /* Tarifit */
+  {"ril",       HB_TAG('R','I','A',' ')},       /* Riang (Myanmar) */
+  {"rit",       HB_TAG('R','I','T',' ')},       /* Ritarungo */
+  {"rki",       HB_TAG('A','R','K',' ')},       /* Rakhine */
+  {"rkw",       HB_TAG('R','K','W',' ')},       /* Arakwal */
+  {"rm",        HB_TAG('R','M','S',' ')},       /* Romansh */
+  {"rmy",       HB_TAG('R','M','Y',' ')},       /* Vlax Romani */
+  {"rn",        HB_TAG('R','U','N',' ')},       /* Rundi */
+  {"ro",        HB_TAG('R','O','M',' ')},       /* Romanian */
+  {"rom",       HB_TAG('R','O','Y',' ')},       /* Romany [macrolanguage] */
+  {"rtm",       HB_TAG('R','T','M',' ')},       /* Rotuman */
+  {"ru",        HB_TAG('R','U','S',' ')},       /* Russian */
+  {"rue",       HB_TAG('R','S','Y',' ')},       /* Rusyn */
+  {"rup",       HB_TAG('R','U','P',' ')},       /* Aromanian/Arumanian/Macedo-Romanian */
+  {"rw",        HB_TAG('R','U','A',' ')},       /* Kinyarwanda */
+  {"rwr",       HB_TAG('M','A','W',' ')},       /* Marwari (India) */
+  {"sa",        HB_TAG('S','A','N',' ')},       /* Sanskrit */
+  {"sah",       HB_TAG('Y','A','K',' ')},       /* Yakut */
+  {"sam",       HB_TAG('P','A','A',' ')},       /* Palestinian Aramaic */
+  {"sas",       HB_TAG('S','A','S',' ')},       /* Sasak */
+  {"sat",       HB_TAG('S','A','T',' ')},       /* Santali */
+  {"sc",        HB_TAG('S','R','D',' ')},       /* Sardinian [macrolanguage] */
+  {"sck",       HB_TAG('S','A','D',' ')},       /* Sadri */
+  {"scn",       HB_TAG('S','C','N',' ')},       /* Sicilian */
+  {"sco",       HB_TAG('S','C','O',' ')},       /* Scots */
+  {"scs",       HB_TAG('S','L','A',' ')},       /* [North] Slavey */
+  {"sd",        HB_TAG('S','N','D',' ')},       /* Sindhi */
+  {"se",        HB_TAG('N','S','M',' ')},       /* Northern Sami */
+  {"seh",       HB_TAG('S','N','A',' ')},       /* Sena */
+  {"sel",       HB_TAG('S','E','L',' ')},       /* Selkup */
+  {"sg",        HB_TAG('S','G','O',' ')},       /* Sango */
+  {"sga",       HB_TAG('S','G','A',' ')},       /* Old Irish (to 900) */
+  {"sgs",       HB_TAG('S','G','S',' ')},       /* Samogitian */
+  {"sgw",       HB_TAG('C','H','G',' ')},       /* Sebat Bet Gurage */
+/*{"sgw",       HB_TAG('S','G','W',' ')},*/     /* Sebat Bet Gurage (in SIL fonts) */
+  {"shi",       HB_TAG('S','H','I',' ')},       /* Tachelhit */
+  {"shn",       HB_TAG('S','H','N',' ')},       /* Shan */
+  {"si",        HB_TAG('S','N','H',' ')},       /* Sinhala */
+  {"sid",       HB_TAG('S','I','D',' ')},       /* Sidamo */
+  {"sjd",       HB_TAG('K','S','M',' ')},       /* Kildin Sami */
+  {"sk",        HB_TAG('S','K','Y',' ')},       /* Slovak */
+  {"skr",       HB_TAG('S','R','K',' ')},       /* Seraiki */
+  {"sl",        HB_TAG('S','L','V',' ')},       /* Slovenian */
+  {"sm",        HB_TAG('S','M','O',' ')},       /* Samoan */
+  {"sma",       HB_TAG('S','S','M',' ')},       /* Southern Sami */
+  {"smj",       HB_TAG('L','S','M',' ')},       /* Lule Sami */
+  {"smn",       HB_TAG('I','S','M',' ')},       /* Inari Sami */
+  {"sms",       HB_TAG('S','K','S',' ')},       /* Skolt Sami */
+  {"sn",        HB_TAG('S','N','A','0')},       /* Shona */
+  {"snk",       HB_TAG('S','N','K',' ')},       /* Soninke */
+  {"so",        HB_TAG('S','M','L',' ')},       /* Somali */
+  {"sop",       HB_TAG('S','O','P',' ')},       /* Songe */
+  {"sq",        HB_TAG('S','Q','I',' ')},       /* Albanian [macrolanguage] */
+  {"sr",        HB_TAG('S','R','B',' ')},       /* Serbian */
+  {"srr",       HB_TAG('S','R','R',' ')},       /* Serer */
+  {"ss",        HB_TAG('S','W','Z',' ')},       /* Swati */
+  {"st",        HB_TAG('S','O','T',' ')},       /* [Southern] Sotho */
+  {"stq",       HB_TAG('S','T','Q',' ')},       /* Saterfriesisch */
+  {"stv",       HB_TAG('S','I','G',' ')},       /* Silt'e */
+  {"su",        HB_TAG('S','U','N',' ')},       /* Sundanese */
+  {"suk",       HB_TAG('S','U','K',' ')},       /* Sukama */
+  {"suq",       HB_TAG('S','U','R',' ')},       /* Suri */
+  {"sv",        HB_TAG('S','V','E',' ')},       /* Swedish */
+  {"sva",       HB_TAG('S','V','A',' ')},       /* Svan */
+  {"sw",        HB_TAG('S','W','K',' ')},       /* Swahili [macrolanguage] */
+  {"swb",       HB_TAG('C','M','R',' ')},       /* Comorian */
+  {"swh",       HB_TAG('S','W','K',' ')},       /* Kiswahili/Swahili */
+  {"swv",       HB_TAG('M','A','W',' ')},       /* Shekhawati */
+  {"sxu",       HB_TAG('S','X','U',' ')},       /* Upper Saxon */
+  {"syl",       HB_TAG('S','Y','L',' ')},       /* Sylheti */
+  {"syr",       HB_TAG('S','Y','R',' ')},       /* Syriac [macrolanguage] */
+  {"szl",       HB_TAG('S','Z','L',' ')},       /* Silesian */
+  {"ta",        HB_TAG('T','A','M',' ')},       /* Tamil */
+  {"tab",       HB_TAG('T','A','B',' ')},       /* Tabasaran */
+  {"tcy",       HB_TAG('T','U','L',' ')},       /* Tulu */
+  {"tdd",       HB_TAG('T','D','D',' ')},       /* Tai Nüa */
+  {"te",        HB_TAG('T','E','L',' ')},       /* Telugu */
+  {"tem",       HB_TAG('T','M','N',' ')},       /* Temne */
+  {"tet",       HB_TAG('T','E','T',' ')},       /* Tetum */
+  {"tg",        HB_TAG('T','A','J',' ')},       /* Tajik */
+  {"th",        HB_TAG('T','H','A',' ')},       /* Thai */
+  {"ti",        HB_TAG('T','G','Y',' ')},       /* Tigrinya */
+  {"tig",       HB_TAG('T','G','R',' ')},       /* Tigre */
+  {"tiv",       HB_TAG('T','I','V',' ')},       /* Tiv */
+  {"tk",        HB_TAG('T','K','M',' ')},       /* Turkmen */
+  {"tl",        HB_TAG('T','G','L',' ')},       /* Tagalog */
+  {"tmh",       HB_TAG('T','M','H',' ')},       /* Tamashek */
+  {"tn",        HB_TAG('T','N','A',' ')},       /* Tswana */
+  {"to",        HB_TAG('T','G','N',' ')},       /* Tonga (Tonga Islands) */
+  {"tod",       HB_TAG('T','O','D','0')},       /* Toma */
+  {"toi",       HB_TAG('T','N','G',' ')},       /* Tonga */
+  {"tpi",       HB_TAG('T','P','I',' ')},       /* Tok Pisin */
+  {"tr",        HB_TAG('T','R','K',' ')},       /* Turkish */
+  {"tru",       HB_TAG('T','U','A',' ')},       /* Turoyo Aramaic */
+  {"ts",        HB_TAG('T','S','G',' ')},       /* Tsonga */
+  {"tt",        HB_TAG('T','A','T',' ')},       /* Tatar */
+  {"tum",       HB_TAG('T','U','M',' ')},       /* Tumbuka */
+  {"tvl",       HB_TAG('T','V','L',' ')},       /* Tuvalu */
+  {"tw",        HB_TAG('T','W','I',' ')},       /* Twi */
+  {"ty",        HB_TAG('T','H','T',' ')},       /* Tahitian */
+  {"tyv",       HB_TAG('T','U','V',' ')},       /* Tuvin */
+  {"tyz",       HB_TAG('T','Y','Z',' ')},       /* Tày */
+  {"tzm",       HB_TAG('T','Z','M',' ')},       /* Central Atlas Tamazight */
+  {"tzo",       HB_TAG('T','Z','O',' ')},       /* Tzotzil */
+  {"udm",       HB_TAG('U','D','M',' ')},       /* Udmurt */
+  {"ug",        HB_TAG('U','Y','G',' ')},       /* Uighur */
+  {"uk",        HB_TAG('U','K','R',' ')},       /* Ukrainian */
+  {"umb",       HB_TAG('U','M','B',' ')},       /* Umbundu */
+  {"unr",       HB_TAG('M','U','N',' ')},       /* Mundari */
+  {"ur",        HB_TAG('U','R','D',' ')},       /* Urdu */
+  {"uz",        HB_TAG('U','Z','B',' ')},       /* Uzbek [macrolanguage] */
+  {"uzn",       HB_TAG('U','Z','B',' ')},       /* Northern Uzbek */
+  {"uzs",       HB_TAG('U','Z','B',' ')},       /* Southern Uzbek */
+  {"ve",        HB_TAG('V','E','N',' ')},       /* Venda */
+  {"vec",       HB_TAG('V','E','C',' ')},       /* Venetian */
+  {"vi",        HB_TAG('V','I','T',' ')},       /* Vietnamese */
+  {"vls",       HB_TAG('F','L','E',' ')},       /* Vlaams */
+  {"vmw",       HB_TAG('M','A','K',' ')},       /* Makhuwa */
+  {"vo",        HB_TAG('V','O','L',' ')},       /* Volapük */
+  {"vro",       HB_TAG('V','R','O',' ')},       /* Võro */
+  {"wa",        HB_TAG('W','L','N',' ')},       /* Walloon */
+  {"war",       HB_TAG('W','A','R',' ')},       /* Waray (Philippines) */
+  {"wbm",       HB_TAG('W','A',' ',' ')},       /* Wa */
+  {"wbr",       HB_TAG('W','A','G',' ')},       /* Wagdi */
+  {"wle",       HB_TAG('S','I','G',' ')},       /* Wolane */
+  {"wo",        HB_TAG('W','L','F',' ')},       /* Wolof */
+  {"wry",       HB_TAG('M','A','W',' ')},       /* Merwari */
+  {"wtm",       HB_TAG('W','T','M',' ')},       /* Mewati */
+  {"xal",       HB_TAG('K','L','M',' ')},       /* Kalmyk */
+  {"xan",       HB_TAG('S','E','K',' ')},       /* Sekota */
+  {"xh",        HB_TAG('X','H','S',' ')},       /* Xhosa */
+  {"xjb",       HB_TAG('X','J','B',' ')},       /* Minjangbal */
+  {"xog",       HB_TAG('X','O','G',' ')},       /* Soga */
+  {"xom",       HB_TAG('K','M','O',' ')},       /* Komo (Sudan) */
+  {"xpe",       HB_TAG('X','P','E',' ')},       /* Kpelle (Liberia) */
+  {"xsl",       HB_TAG('S','S','L',' ')},       /* South Slavey */
+  {"xst",       HB_TAG('S','I','G',' ')},       /* Silt'e (retired code) */
+  {"xwo",       HB_TAG('T','O','D',' ')},       /* Written Oirat (Todo) */
+  {"yao",       HB_TAG('Y','A','O',' ')},       /* Yao */
+  {"yap",       HB_TAG('Y','A','P',' ')},       /* Yapese */
+  {"yi",        HB_TAG('J','I','I',' ')},       /* Yiddish [macrolanguage] */
+  {"yo",        HB_TAG('Y','B','A',' ')},       /* Yoruba */
+  {"yso",       HB_TAG('N','I','S',' ')},       /* Nisi (China) */
+  {"za",        HB_TAG('Z','H','A',' ')},       /* Chuang/Zhuang [macrolanguage] */
+  {"zea",       HB_TAG('Z','E','A',' ')},       /* Zeeuws */
+  {"zgh",       HB_TAG('Z','G','H',' ')},       /* Standard Morrocan Tamazigh */
+  {"zne",       HB_TAG('Z','N','D',' ')},       /* Zande */
+  {"zu",        HB_TAG('Z','U','L',' ')},       /* Zulu */
+  {"zum",       HB_TAG('L','R','C',' ')},       /* Kumzari */
+  {"zza",       HB_TAG('Z','Z','A',' ')},       /* Zazaki */
+
+  /* The corresponding languages IDs for the following IDs are unclear,
+   * overlap, or are architecturally weird. Needs more research. */
+
+/*{"chp",       HB_TAG('S','A','Y',' ')},*/     /* Sayisi */
+/*{"cwd",       HB_TAG('T','C','R',' ')},*/     /* TH-Cree */
+/*{"emk",       HB_TAG('E','M','K',' ')},*/     /* Eastern Maninkakan */
+/*{"krc",       HB_TAG('B','A','L',' ')},*/     /* Balkar */
+/*{"??",        HB_TAG('B','C','R',' ')},*/     /* Bible Cree */
+/*{"zh?",       HB_TAG('C','H','N',' ')},*/     /* Chinese (seen in Microsoft fonts) */
+/*{"ar-Syrc?",  HB_TAG('G','A','R',' ')},*/     /* Garshuni */
+/*{"hy?",       HB_TAG('H','Y','E','0')},*/     /* Armenian East (ISO 639-3 hye according to Microsoft, but that’s equivalent to ISO 639-1 hy) */
+/*{"ga-Latg?/"  HB_TAG('I','R','T',' ')},*/     /* Irish Traditional */
+/*{"krc",       HB_TAG('K','A','R',' ')},*/     /* Karachay */
+/*{"ka-Geok?",  HB_TAG('K','G','E',' ')},*/     /* Khutsuri Georgian */
+/*{"kca",       HB_TAG('K','H','K',' ')},*/     /* Khanty-Kazim */
+/*{"kca",       HB_TAG('K','H','S',' ')},*/     /* Khanty-Shurishkar */
+/*{"kca",       HB_TAG('K','H','V',' ')},*/     /* Khanty-Vakhi */
+/*{"kqs, kss",  HB_TAG('K','I','S',' ')},*/     /* Kisii */
+/*{"lua",       HB_TAG('L','U','A',' ')},*/     /* Luba-Lulua */
+/*{"mlq",       HB_TAG('M','L','N',' ')},*/     /* Malinke */
+/*{"nso",       HB_TAG('N','S','O',' ')},*/     /* Sotho, Northern */
+/*{"??",        HB_TAG('M','A','L',' ')},*/     /* Malayalam Traditional */
+/*{"csw",       HB_TAG('N','C','R',' ')},*/     /* N-Cree */
+/*{"csw",       HB_TAG('N','H','C',' ')},*/     /* Norway House Cree */
+/*{"el-polyton",        HB_TAG('P','G','R',' ')},*/     /* Polytonic Greek */
+/*{"bgr, cnh, cnw, czt, sez, tcp, csy, ctd, flm, pck, tcz, zom, cmr, dao, hlt, cka, cnk, mrh, mwg, cbl, cnb, csh",      HB_TAG('Q','I','N',' ')},*/     /* Chin */
+/*{"??",        HB_TAG('Y','I','C',' ')},*/     /* Yi Classic */
+/*{"zh-Latn-pinyin",    HB_TAG('Z','H','P',' ')},*/     /* Chinese Phonetic */
+};
+
+typedef struct {
+  char language[8];
+  hb_tag_t tag;
+} LangTagLong;
+static const LangTagLong ot_languages_zh[] = {
+  {"zh-cn",     HB_TAG('Z','H','S',' ')},       /* Chinese (China) */
+  {"zh-hk",     HB_TAG('Z','H','H',' ')},       /* Chinese (Hong Kong) */
+  {"zh-mo",     HB_TAG('Z','H','T',' ')},       /* Chinese (Macao) */
+  {"zh-sg",     HB_TAG('Z','H','S',' ')},       /* Chinese (Singapore) */
+  {"zh-tw",     HB_TAG('Z','H','T',' ')},       /* Chinese (Taiwan) */
+  {"zh-hans",   HB_TAG('Z','H','S',' ')},       /* Chinese (Simplified) */
+  {"zh-hant",   HB_TAG('Z','H','T',' ')},       /* Chinese (Traditional) */
+};
+
+static int
+lang_compare_first_component (const char *a,
+                              const char *b)
+{
+  unsigned int da, db;
+  const char *p;
+
+  p = strchr (a, '-');
+  da = p ? (unsigned int) (p - a) : strlen (a);
+
+  p = strchr (b, '-');
+  db = p ? (unsigned int) (p - b) : strlen (b);
+
+  return strncmp (a, b, MAX (da, db));
+}
+
+static hb_bool_t
+lang_matches (const char *lang_str, const char *spec)
+{
+  unsigned int len = strlen (spec);
+
+  return strncmp (lang_str, spec, len) == 0 &&
+         (lang_str[len] == '\0' || lang_str[len] == '-');
+}
+
+hb_tag_t
+hb_ot_tag_from_language (hb_language_t language)
+{
+  const char *lang_str, *s;
+
+  if (language == HB_LANGUAGE_INVALID)
+    return HB_OT_TAG_DEFAULT_LANGUAGE;
+
+  lang_str = hb_language_to_string (language);
+
+  s = strstr (lang_str, "x-hbot");
+  if (s) {
+    char tag[4];
+    int i;
+    s += 6;
+    for (i = 0; i < 4 && ISALPHA (s[i]); i++)
+      tag[i] = TOUPPER (s[i]);
+    if (i) {
+      for (; i < 4; i++)
+        tag[i] = ' ';
+      return HB_TAG_CHAR4 (tag);
+    }
+  }
+
+  /*
+   * The International Phonetic Alphabet is a variant tag in BCP-47,
+   * which can be applied to any language.
+   */
+  if (strstr (lang_str, "-fonipa")) {
+    return HB_TAG('I','P','P','H');  /* Phonetic transcription—IPA conventions */
+  }
+
+  /* Find a language matching in the first component */
+  {
+    const LangTag *lang_tag;
+    lang_tag = (LangTag *) bsearch (lang_str, ot_languages,
+                                    ARRAY_LENGTH (ot_languages), sizeof (LangTag),
+                                    (hb_compare_func_t) lang_compare_first_component);
+    if (lang_tag)
+      return lang_tag->tag;
+  }
+
+  /* Otherwise, check the Chinese ones */
+  if (0 == lang_compare_first_component (lang_str, "zh"))
+  {
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_LENGTH (ot_languages_zh); i++)
+    {
+      const LangTagLong *lang_tag;
+      lang_tag = &ot_languages_zh[i];
+      if (lang_matches (lang_str, lang_tag->language))
+        return lang_tag->tag;
+    }
+
+    /* Otherwise just return 'ZHS ' */
+    return HB_TAG('Z','H','S',' ');
+  }
+
+  s = strchr (lang_str, '-');
+  if (!s)
+    s = lang_str + strlen (lang_str);
+  if (s - lang_str == 3) {
+    /* Assume it's ISO-639-3 and upper-case and use it. */
+    return hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000u;
+  }
+
+  return HB_OT_TAG_DEFAULT_LANGUAGE;
+}
+
+/**
+ * hb_ot_tag_to_language:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.2
+ **/
+hb_language_t
+hb_ot_tag_to_language (hb_tag_t tag)
+{
+  unsigned int i;
+
+  if (tag == HB_OT_TAG_DEFAULT_LANGUAGE)
+    return NULL;
+
+  for (i = 0; i < ARRAY_LENGTH (ot_languages); i++)
+    if (ot_languages[i].tag == tag)
+      return hb_language_from_string (ot_languages[i].language, -1);
+
+  /* If tag starts with ZH, it's Chinese */
+  if ((tag & 0xFFFF0000u)  == 0x5A480000u) {
+    switch (tag) {
+      case HB_TAG('Z','H','H',' '): return hb_language_from_string ("zh-hk", -1); /* Hong Kong */
+      case HB_TAG('Z','H','S',' '): return hb_language_from_string ("zh-Hans", -1); /* Simplified */
+      case HB_TAG('Z','H','T',' '): return hb_language_from_string ("zh-Hant", -1); /* Traditional */
+      default: break; /* Fall through */
+    }
+  }
+
+  /* struct LangTag has only room for 3-letter language tags. */
+  switch (tag) {
+  case HB_TAG('I','P','P','H'):  /* Phonetic transcription—IPA conventions */
+    return hb_language_from_string ("und-fonipa", -1);
+  }
+
+  /* Else return a custom language in the form of "x-hbotABCD" */
+  {
+    unsigned char buf[11] = "x-hbot";
+    buf[6] = tag >> 24;
+    buf[7] = (tag >> 16) & 0xFF;
+    buf[8] = (tag >> 8) & 0xFF;
+    buf[9] = tag & 0xFF;
+    if (buf[9] == 0x20)
+      buf[9] = '\0';
+    buf[10] = '\0';
+    return hb_language_from_string ((char *) buf, -1);
+  }
+}
+
+#ifdef MAIN
+static inline void
+test_langs_sorted (void)
+{
+  for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages); i++)
+  {
+    int c = lang_compare_first_component (ot_languages[i-1].language, ot_languages[i].language);
+    if (c >= 0)
+    {
+      fprintf (stderr, "ot_languages not sorted at index %d: %s %d %s\n",
+               i, ot_languages[i-1].language, c, ot_languages[i].language);
+      abort();
+    }
+  }
+}
+
+int
+main (void)
+{
+  test_langs_sorted ();
+  return 0;
+}
+
+#endif
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot-tag.h b/src/share/native/sun/font/harfbuzz/hb-ot-tag.h
new file mode 100644
index 0000000..10cf397
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot-tag.h
@@ -0,0 +1,59 @@
+/*
+ * 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_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
+#ifndef HB_OT_TAG_H
+#define HB_OT_TAG_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+
+#define HB_OT_TAG_DEFAULT_SCRIPT        HB_TAG ('D', 'F', 'L', 'T')
+#define HB_OT_TAG_DEFAULT_LANGUAGE      HB_TAG ('d', 'f', 'l', 't')
+
+HB_EXTERN void
+hb_ot_tags_from_script (hb_script_t  script,
+                        hb_tag_t    *script_tag_1,
+                        hb_tag_t    *script_tag_2);
+
+HB_EXTERN hb_script_t
+hb_ot_tag_to_script (hb_tag_t tag);
+
+HB_EXTERN hb_tag_t
+hb_ot_tag_from_language (hb_language_t language);
+
+HB_EXTERN hb_language_t
+hb_ot_tag_to_language (hb_tag_t tag);
+
+
+HB_END_DECLS
+
+#endif /* HB_OT_TAG_H */
diff --git a/src/share/native/sun/font/harfbuzz/hb-ot.h b/src/share/native/sun/font/harfbuzz/hb-ot.h
new file mode 100644
index 0000000..47c92a5
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ot.h
@@ -0,0 +1,43 @@
+/*
+ * 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_OT_H
+#define HB_OT_H
+#define HB_OT_H_IN
+
+#include "hb.h"
+
+#include "hb-ot-font.h"
+#include "hb-ot-layout.h"
+#include "hb-ot-tag.h"
+#include "hb-ot-shape.h"
+
+HB_BEGIN_DECLS
+
+HB_END_DECLS
+
+#undef HB_OT_H_IN
+#endif /* HB_OT_H */
diff --git a/src/share/native/sun/font/harfbuzz/hb-private.hh b/src/share/native/sun/font/harfbuzz/hb-private.hh
new file mode 100644
index 0000000..1f270ee
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-private.hh
@@ -0,0 +1,1021 @@
+/*
+ * 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_PRIVATE_HH
+#define HB_PRIVATE_HH
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb.h"
+#define HB_H_IN
+#ifdef HAVE_OT
+#include "hb-ot.h"
+#define HB_OT_H_IN
+#endif
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+
+/* We only use these two for debug output.  However, the debug code is
+ * always seen by the compiler (and optimized out in non-debug builds.
+ * If including these becomes a problem, we can start thinking about
+ * someway around that. */
+#include <stdio.h>
+#include <errno.h>
+#include <stdarg.h>
+
+
+/* Compile-time custom allocator support. */
+
+#if defined(hb_malloc_impl) \
+ && defined(hb_calloc_impl) \
+ && defined(hb_realloc_impl) \
+ && defined(hb_free_impl)
+extern "C" void* hb_malloc_impl(size_t size);
+extern "C" void* hb_calloc_impl(size_t nmemb, size_t size);
+extern "C" void* hb_realloc_impl(void *ptr, size_t size);
+extern "C" void  hb_free_impl(void *ptr);
+#define malloc hb_malloc_impl
+#define calloc hb_calloc_impl
+#define realloc hb_realloc_impl
+#define free hb_free_impl
+#endif
+
+
+/* Compiler attributes */
+
+
+#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
+#define _HB_BOOLEAN_EXPR(expr) ((expr) ? 1 : 0)
+#define likely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 1))
+#define unlikely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 0))
+#else
+#define likely(expr) (expr)
+#define unlikely(expr) (expr)
+#endif
+
+#if !defined(__GNUC__) && !defined(__clang__)
+#undef __attribute__
+#define __attribute__(x)
+#endif
+
+#if __GNUC__ >= 3
+#define HB_PURE_FUNC    __attribute__((pure))
+#define HB_CONST_FUNC   __attribute__((const))
+#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
+#else
+#define HB_PURE_FUNC
+#define HB_CONST_FUNC
+#define HB_PRINTF_FUNC(format_idx, arg_idx)
+#endif
+#if __GNUC__ >= 4
+#define HB_UNUSED       __attribute__((unused))
+#else
+#define HB_UNUSED
+#endif
+
+#ifndef HB_INTERNAL
+# if !defined(__MINGW32__) && !defined(__CYGWIN__)
+#  define HB_INTERNAL __attribute__((__visibility__("hidden")))
+# else
+#  define HB_INTERNAL
+# endif
+#endif
+
+#if __GNUC__ >= 3
+#define HB_FUNC __PRETTY_FUNCTION__
+#elif defined(_MSC_VER)
+#define HB_FUNC __FUNCSIG__
+#else
+#define HB_FUNC __func__
+#endif
+
+/*
+ * Borrowed from https://bugzilla.mozilla.org/show_bug.cgi?id=1215411
+ * HB_FALLTHROUGH is an annotation to suppress compiler warnings about switch
+ * cases that fall through without a break or return statement. HB_FALLTHROUGH
+ * is only needed on cases that have code:
+ *
+ * switch (foo) {
+ *   case 1: // These cases have no code. No fallthrough annotations are needed.
+ *   case 2:
+ *   case 3:
+ *     foo = 4; // This case has code, so a fallthrough annotation is needed:
+ *     HB_FALLTHROUGH;
+ *   default:
+ *     return foo;
+ * }
+ */
+#if defined(__clang__) && __cplusplus >= 201103L
+   /* clang's fallthrough annotations are only available starting in C++11. */
+#  define HB_FALLTHROUGH [[clang::fallthrough]]
+#elif defined(_MSC_VER)
+   /*
+    * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis):
+    * https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx
+    */
+#  include <sal.h>
+#  define HB_FALLTHROUGH __fallthrough
+#else
+#  define HB_FALLTHROUGH /* FALLTHROUGH */
+#endif
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+   /* We need Windows Vista for both Uniscribe backend and for
+    * MemoryBarrier.  We don't support compiling on Windows XP,
+    * though we run on it fine. */
+#  if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600
+#    undef _WIN32_WINNT
+#  endif
+#  ifndef _WIN32_WINNT
+#    define _WIN32_WINNT 0x0600
+#  endif
+#  ifndef WIN32_LEAN_AND_MEAN
+#    define WIN32_LEAN_AND_MEAN 1
+#  endif
+#  ifndef STRICT
+#    define STRICT 1
+#  endif
+
+#  if defined(_WIN32_WCE)
+     /* Some things not defined on Windows CE. */
+#    define strdup _strdup
+#    define vsnprintf _vsnprintf
+#    define getenv(Name) NULL
+#    if _WIN32_WCE < 0x800
+#      define setlocale(Category, Locale) "C"
+static int errno = 0; /* Use something better? */
+#    endif
+#  elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#    define getenv(Name) NULL
+#  endif
+#  if defined(_MSC_VER) && _MSC_VER < 1900
+#    define snprintf _snprintf
+#  elif defined(_MSC_VER) && _MSC_VER >= 1900
+#    /* Covers VC++ Error for strdup being a deprecated POSIX name and to instead use _strdup instead */
+#    define strdup _strdup
+#  endif
+#endif
+
+#if HAVE_ATEXIT
+/* atexit() is only safe to be called from shared libraries on certain
+ * platforms.  Whitelist.
+ * https://bugs.freedesktop.org/show_bug.cgi?id=82246 */
+#  if defined(__linux) && defined(__GLIBC_PREREQ)
+#    if __GLIBC_PREREQ(2,3)
+/* From atexit() manpage, it's safe with glibc 2.2.3 on Linux. */
+#      define HB_USE_ATEXIT 1
+#    endif
+#  elif defined(_MSC_VER) || defined(__MINGW32__)
+/* For MSVC:
+ * http://msdn.microsoft.com/en-ca/library/tze57ck3.aspx
+ * http://msdn.microsoft.com/en-ca/library/zk17ww08.aspx
+ * mingw32 headers say atexit is safe to use in shared libraries.
+ */
+#    define HB_USE_ATEXIT 1
+#  elif defined(__ANDROID__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+/* This was fixed in Android NKD r8 or r8b:
+ * https://code.google.com/p/android/issues/detail?id=6455
+ * which introduced GCC 4.6:
+ * https://developer.android.com/tools/sdk/ndk/index.html
+ */
+#    define HB_USE_ATEXIT 1
+#  endif
+#endif
+
+/* Basics */
+
+
+#ifndef NULL
+# define NULL ((void *) 0)
+#endif
+
+#undef MIN
+template <typename Type>
+static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
+
+#undef MAX
+template <typename Type>
+static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
+
+static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
+{ return (a + (b - 1)) / b; }
+
+
+#undef  ARRAY_LENGTH
+template <typename Type, unsigned int n>
+static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
+/* A const version, but does not detect erratically being called on pointers. */
+#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
+
+#define HB_STMT_START do
+#define HB_STMT_END   while (0)
+
+#define _ASSERT_STATIC1(_line, _cond)   HB_UNUSED typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
+#define _ASSERT_STATIC0(_line, _cond)   _ASSERT_STATIC1 (_line, (_cond))
+#define ASSERT_STATIC(_cond)            _ASSERT_STATIC0 (__LINE__, (_cond))
+
+template <unsigned int cond> class hb_assert_constant_t {};
+
+#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * (unsigned int) sizeof (hb_assert_constant_t<_cond>))
+
+#define _PASTE1(a,b) a##b
+#define PASTE(a,b) _PASTE1(a,b)
+
+/* Lets assert int types.  Saves trouble down the road. */
+
+ASSERT_STATIC (sizeof (int8_t) == 1);
+ASSERT_STATIC (sizeof (uint8_t) == 1);
+ASSERT_STATIC (sizeof (int16_t) == 2);
+ASSERT_STATIC (sizeof (uint16_t) == 2);
+ASSERT_STATIC (sizeof (int32_t) == 4);
+ASSERT_STATIC (sizeof (uint32_t) == 4);
+ASSERT_STATIC (sizeof (int64_t) == 8);
+ASSERT_STATIC (sizeof (uint64_t) == 8);
+
+ASSERT_STATIC (sizeof (hb_codepoint_t) == 4);
+ASSERT_STATIC (sizeof (hb_position_t) == 4);
+ASSERT_STATIC (sizeof (hb_mask_t) == 4);
+ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
+
+
+/* We like our types POD */
+
+#define _ASSERT_TYPE_POD1(_line, _type) union _type_##_type##_on_line_##_line##_is_not_POD { _type instance; }
+#define _ASSERT_TYPE_POD0(_line, _type) _ASSERT_TYPE_POD1 (_line, _type)
+#define ASSERT_TYPE_POD(_type)          _ASSERT_TYPE_POD0 (__LINE__, _type)
+
+#ifdef __GNUC__
+# define _ASSERT_INSTANCE_POD1(_line, _instance) \
+        HB_STMT_START { \
+                typedef __typeof__(_instance) _type_##_line; \
+                _ASSERT_TYPE_POD1 (_line, _type_##_line); \
+        } HB_STMT_END
+#else
+# define _ASSERT_INSTANCE_POD1(_line, _instance)        typedef int _assertion_on_line_##_line##_not_tested
+#endif
+# define _ASSERT_INSTANCE_POD0(_line, _instance)        _ASSERT_INSTANCE_POD1 (_line, _instance)
+# define ASSERT_INSTANCE_POD(_instance)                 _ASSERT_INSTANCE_POD0 (__LINE__, _instance)
+
+/* Check _assertion in a method environment */
+#define _ASSERT_POD1(_line) \
+        HB_UNUSED inline void _static_assertion_on_line_##_line (void) const \
+        { _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ }
+# define _ASSERT_POD0(_line)    _ASSERT_POD1 (_line)
+# define ASSERT_POD()           _ASSERT_POD0 (__LINE__)
+
+
+
+/* Misc */
+
+/* Void! */
+struct _hb_void_t {};
+typedef const _hb_void_t *hb_void_t;
+#define HB_VOID ((const _hb_void_t *) NULL)
+
+/* Return the number of 1 bits in mask. */
+static inline HB_CONST_FUNC unsigned int
+_hb_popcount32 (uint32_t mask)
+{
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+  return __builtin_popcount (mask);
+#else
+  /* "HACKMEM 169" */
+  uint32_t y;
+  y = (mask >> 1) &033333333333;
+  y = mask - y - ((y >>1) & 033333333333);
+  return (((y + (y >> 3)) & 030707070707) % 077);
+#endif
+}
+
+/* Returns the number of bits needed to store number */
+static inline HB_CONST_FUNC unsigned int
+_hb_bit_storage (unsigned int number)
+{
+#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
+  return likely (number) ? (sizeof (unsigned int) * 8 - __builtin_clz (number)) : 0;
+#else
+  unsigned int n_bits = 0;
+  while (number) {
+    n_bits++;
+    number >>= 1;
+  }
+  return n_bits;
+#endif
+}
+
+/* Returns the number of zero bits in the least significant side of number */
+static inline HB_CONST_FUNC unsigned int
+_hb_ctz (unsigned int number)
+{
+#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
+  return likely (number) ? __builtin_ctz (number) : 0;
+#else
+  unsigned int n_bits = 0;
+  if (unlikely (!number)) return 0;
+  while (!(number & 1)) {
+    n_bits++;
+    number >>= 1;
+  }
+  return n_bits;
+#endif
+}
+
+static inline bool
+_hb_unsigned_int_mul_overflows (unsigned int count, unsigned int size)
+{
+  return (size > 0) && (count >= ((unsigned int) -1) / size);
+}
+
+
+/* Type of bsearch() / qsort() compare function */
+typedef int (*hb_compare_func_t) (const void *, const void *);
+
+
+
+
+/* arrays and maps */
+
+
+#define HB_PREALLOCED_ARRAY_INIT {0, 0, NULL}
+template <typename Type, unsigned int StaticSize=16>
+struct hb_prealloced_array_t
+{
+  unsigned int len;
+  unsigned int allocated;
+  Type *array;
+  Type static_array[StaticSize];
+
+  void init (void) { memset (this, 0, sizeof (*this)); }
+
+  inline Type& operator [] (unsigned int i) { return array[i]; }
+  inline const Type& operator [] (unsigned int i) const { return array[i]; }
+
+  inline Type *push (void)
+  {
+    if (!array) {
+      array = static_array;
+      allocated = ARRAY_LENGTH (static_array);
+    }
+    if (likely (len < allocated))
+      return &array[len++];
+
+    /* Need to reallocate */
+    unsigned int new_allocated = allocated + (allocated >> 1) + 8;
+    Type *new_array = NULL;
+
+    if (array == static_array) {
+      new_array = (Type *) calloc (new_allocated, sizeof (Type));
+      if (new_array)
+        memcpy (new_array, array, len * sizeof (Type));
+    } else {
+      bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
+      if (likely (!overflows)) {
+        new_array = (Type *) realloc (array, new_allocated * sizeof (Type));
+      }
+    }
+
+    if (unlikely (!new_array))
+      return NULL;
+
+    array = new_array;
+    allocated = new_allocated;
+    return &array[len++];
+  }
+
+  inline void pop (void)
+  {
+    len--;
+  }
+
+  inline void remove (unsigned int i)
+  {
+     if (unlikely (i >= len))
+       return;
+     memmove (static_cast<void *> (&array[i]),
+              static_cast<void *> (&array[i + 1]),
+              (len - i - 1) * sizeof (Type));
+     len--;
+  }
+
+  inline void shrink (unsigned int l)
+  {
+     if (l < len)
+       len = l;
+  }
+
+  template <typename T>
+  inline Type *find (T v) {
+    for (unsigned int i = 0; i < len; i++)
+      if (array[i] == v)
+        return &array[i];
+    return NULL;
+  }
+  template <typename T>
+  inline const Type *find (T v) const {
+    for (unsigned int i = 0; i < len; i++)
+      if (array[i] == v)
+        return &array[i];
+    return NULL;
+  }
+
+  inline void qsort (void)
+  {
+    ::qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
+  }
+
+  inline void qsort (unsigned int start, unsigned int end)
+  {
+    ::qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
+  }
+
+  template <typename T>
+  inline Type *bsearch (T *key)
+  {
+    return (Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
+  }
+  template <typename T>
+  inline const Type *bsearch (T *key) const
+  {
+    return (const Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
+  }
+
+  inline void finish (void)
+  {
+    if (array != static_array)
+      free (array);
+    array = NULL;
+    allocated = len = 0;
+  }
+};
+
+template <typename Type>
+struct hb_auto_array_t : hb_prealloced_array_t <Type>
+{
+  hb_auto_array_t (void) { hb_prealloced_array_t<Type>::init (); }
+  ~hb_auto_array_t (void) { hb_prealloced_array_t<Type>::finish (); }
+};
+
+
+#define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT}
+template <typename item_t, typename lock_t>
+struct hb_lockable_set_t
+{
+  hb_prealloced_array_t <item_t, 2> items;
+
+  inline void init (void) { items.init (); }
+
+  template <typename T>
+  inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
+  {
+    l.lock ();
+    item_t *item = items.find (v);
+    if (item) {
+      if (replace) {
+        item_t old = *item;
+        *item = v;
+        l.unlock ();
+        old.finish ();
+      }
+      else {
+        item = NULL;
+        l.unlock ();
+      }
+    } else {
+      item = items.push ();
+      if (likely (item))
+        *item = v;
+      l.unlock ();
+    }
+    return item;
+  }
+
+  template <typename T>
+  inline void remove (T v, lock_t &l)
+  {
+    l.lock ();
+    item_t *item = items.find (v);
+    if (item) {
+      item_t old = *item;
+      *item = items[items.len - 1];
+      items.pop ();
+      l.unlock ();
+      old.finish ();
+    } else {
+      l.unlock ();
+    }
+  }
+
+  template <typename T>
+  inline bool find (T v, item_t *i, lock_t &l)
+  {
+    l.lock ();
+    item_t *item = items.find (v);
+    if (item)
+      *i = *item;
+    l.unlock ();
+    return !!item;
+  }
+
+  template <typename T>
+  inline item_t *find_or_insert (T v, lock_t &l)
+  {
+    l.lock ();
+    item_t *item = items.find (v);
+    if (!item) {
+      item = items.push ();
+      if (likely (item))
+        *item = v;
+    }
+    l.unlock ();
+    return item;
+  }
+
+  inline void finish (lock_t &l)
+  {
+    if (!items.len) {
+      /* No need for locking. */
+      items.finish ();
+      return;
+    }
+    l.lock ();
+    while (items.len) {
+      item_t old = items[items.len - 1];
+        items.pop ();
+        l.unlock ();
+        old.finish ();
+        l.lock ();
+    }
+    items.finish ();
+    l.unlock ();
+  }
+
+};
+
+
+/* ASCII tag/character handling */
+
+static inline bool ISALPHA (unsigned char c)
+{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
+static inline bool ISALNUM (unsigned char c)
+{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
+static inline bool ISSPACE (unsigned char c)
+{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
+static inline unsigned char TOUPPER (unsigned char c)
+{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
+static inline unsigned char TOLOWER (unsigned char c)
+{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
+
+#define HB_TAG_CHAR4(s)   (HB_TAG(((const char *) s)[0], \
+                                  ((const char *) s)[1], \
+                                  ((const char *) s)[2], \
+                                  ((const char *) s)[3]))
+
+
+/* C++ helpers */
+
+/* Makes class uncopyable.  Use in private: section. */
+#define NO_COPY(T) \
+  T (const T &o); \
+  T &operator = (const T &o)
+
+
+/* Debug */
+
+
+/* HB_NDEBUG disables some sanity checks that are very safe to disable and
+ * should be disabled in production systems.  If NDEBUG is defined, enable
+ * HB_NDEBUG; but if it's desirable that normal assert()s (which are very
+ * light-weight) to be enabled, then HB_DEBUG can be defined to disable
+ * the costlier checks. */
+#ifdef NDEBUG
+#define HB_NDEBUG
+#endif
+
+#ifndef HB_DEBUG
+#define HB_DEBUG 0
+#endif
+
+static inline bool
+_hb_debug (unsigned int level,
+           unsigned int max_level)
+{
+  return level < max_level;
+}
+
+#define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
+#define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0))
+
+static inline void
+_hb_print_func (const char *func)
+{
+  if (func)
+  {
+    unsigned int func_len = strlen (func);
+    /* Skip "static" */
+    if (0 == strncmp (func, "static ", 7))
+      func += 7;
+    /* Skip "typename" */
+    if (0 == strncmp (func, "typename ", 9))
+      func += 9;
+    /* Skip return type */
+    const char *space = strchr (func, ' ');
+    if (space)
+      func = space + 1;
+    /* Skip parameter list */
+    const char *paren = strchr (func, '(');
+    if (paren)
+      func_len = paren - func;
+    fprintf (stderr, "%.*s", func_len, func);
+  }
+}
+
+template <int max_level> static inline void
+_hb_debug_msg_va (const char *what,
+                  const void *obj,
+                  const char *func,
+                  bool indented,
+                  unsigned int level,
+                  int level_dir,
+                  const char *message,
+                  va_list ap) HB_PRINTF_FUNC(7, 0);
+template <int max_level> static inline void
+_hb_debug_msg_va (const char *what,
+                  const void *obj,
+                  const char *func,
+                  bool indented,
+                  unsigned int level,
+                  int level_dir,
+                  const char *message,
+                  va_list ap)
+{
+  if (!_hb_debug (level, max_level))
+    return;
+
+  fprintf (stderr, "%-10s", what ? what : "");
+
+  if (obj)
+    fprintf (stderr, "(%0*lx) ", (unsigned int) (2 * sizeof (void *)), (unsigned long) obj);
+  else
+    fprintf (stderr, " %*s  ", (unsigned int) (2 * sizeof (void *)), "");
+
+  if (indented) {
+/* One may want to add ASCII version of these.  See:
+ * https://bugs.freedesktop.org/show_bug.cgi?id=50970 */
+#define VBAR    "\342\224\202"  /* U+2502 BOX DRAWINGS LIGHT VERTICAL */
+#define VRBAR   "\342\224\234"  /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
+#define DLBAR   "\342\225\256"  /* U+256E BOX DRAWINGS LIGHT ARC DOWN AND LEFT */
+#define ULBAR   "\342\225\257"  /* U+256F BOX DRAWINGS LIGHT ARC UP AND LEFT */
+#define LBAR    "\342\225\264"  /* U+2574 BOX DRAWINGS LIGHT LEFT */
+    static const char bars[] = VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
+    fprintf (stderr, "%2u %s" VRBAR "%s",
+             level,
+             bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars), (unsigned int) (sizeof (VBAR) - 1) * level),
+             level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
+  } else
+    fprintf (stderr, "   " VRBAR LBAR);
+
+  _hb_print_func (func);
+
+  if (message)
+  {
+    fprintf (stderr, ": ");
+    vfprintf (stderr, message, ap);
+  }
+
+  fprintf (stderr, "\n");
+}
+template <> inline void
+_hb_debug_msg_va<0> (const char *what HB_UNUSED,
+                     const void *obj HB_UNUSED,
+                     const char *func HB_UNUSED,
+                     bool indented HB_UNUSED,
+                     unsigned int level HB_UNUSED,
+                     int level_dir HB_UNUSED,
+                     const char *message HB_UNUSED,
+                     va_list ap HB_UNUSED) {}
+
+template <int max_level> static inline void
+_hb_debug_msg (const char *what,
+               const void *obj,
+               const char *func,
+               bool indented,
+               unsigned int level,
+               int level_dir,
+               const char *message,
+               ...) HB_PRINTF_FUNC(7, 8);
+template <int max_level> static inline void
+_hb_debug_msg (const char *what,
+               const void *obj,
+               const char *func,
+               bool indented,
+               unsigned int level,
+               int level_dir,
+               const char *message,
+               ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  _hb_debug_msg_va<max_level> (what, obj, func, indented, level, level_dir, message, ap);
+  va_end (ap);
+}
+template <> inline void
+_hb_debug_msg<0> (const char *what HB_UNUSED,
+                  const void *obj HB_UNUSED,
+                  const char *func HB_UNUSED,
+                  bool indented HB_UNUSED,
+                  unsigned int level HB_UNUSED,
+                  int level_dir HB_UNUSED,
+                  const char *message HB_UNUSED,
+                  ...) HB_PRINTF_FUNC(7, 8);
+template <> inline void
+_hb_debug_msg<0> (const char *what HB_UNUSED,
+                  const void *obj HB_UNUSED,
+                  const char *func HB_UNUSED,
+                  bool indented HB_UNUSED,
+                  unsigned int level HB_UNUSED,
+                  int level_dir HB_UNUSED,
+                  const char *message HB_UNUSED,
+                  ...) {}
+
+#define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...)       _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL,    true, (LEVEL), (LEVEL_DIR), __VA_ARGS__)
+#define DEBUG_MSG(WHAT, OBJ, ...)                               _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL,    false, 0, 0, __VA_ARGS__)
+#define DEBUG_MSG_FUNC(WHAT, OBJ, ...)                          _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, false, 0, 0, __VA_ARGS__)
+
+
+/*
+ * Printer
+ */
+
+template <typename T>
+struct hb_printer_t {
+  const char *print (const T&) { return "something"; }
+};
+
+template <>
+struct hb_printer_t<bool> {
+  const char *print (bool v) { return v ? "true" : "false"; }
+};
+
+template <>
+struct hb_printer_t<hb_void_t> {
+  const char *print (hb_void_t) { return ""; }
+};
+
+
+/*
+ * Trace
+ */
+
+template <typename T>
+static inline void _hb_warn_no_return (bool returned)
+{
+  if (unlikely (!returned)) {
+    fprintf (stderr, "OUCH, returned with no call to return_trace().  This is a bug, please report.\n");
+  }
+}
+template <>
+/*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
+{}
+
+template <int max_level, typename ret_t>
+struct hb_auto_trace_t {
+  explicit inline hb_auto_trace_t (unsigned int *plevel_,
+                                   const char *what_,
+                                   const void *obj_,
+                                   const char *func,
+                                   const char *message,
+                                   ...) : plevel (plevel_), what (what_), obj (obj_), returned (false)
+  {
+    if (plevel) ++*plevel;
+
+    va_list ap;
+    va_start (ap, message);
+    _hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap);
+    va_end (ap);
+  }
+  inline ~hb_auto_trace_t (void)
+  {
+    _hb_warn_no_return<ret_t> (returned);
+    if (!returned) {
+      _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, " ");
+    }
+    if (plevel) --*plevel;
+  }
+
+  inline ret_t ret (ret_t v, unsigned int line = 0)
+  {
+    if (unlikely (returned)) {
+      fprintf (stderr, "OUCH, double calls to return_trace().  This is a bug, please report.\n");
+      return v;
+    }
+
+    _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1,
+                              "return %s (line %d)",
+                              hb_printer_t<ret_t>().print (v), line);
+    if (plevel) --*plevel;
+    plevel = NULL;
+    returned = true;
+    return v;
+  }
+
+  private:
+  unsigned int *plevel;
+  const char *what;
+  const void *obj;
+  bool returned;
+};
+template <typename ret_t> /* Optimize when tracing is disabled */
+struct hb_auto_trace_t<0, ret_t> {
+  explicit inline hb_auto_trace_t (unsigned int *plevel_ HB_UNUSED,
+                                   const char *what HB_UNUSED,
+                                   const void *obj HB_UNUSED,
+                                   const char *func HB_UNUSED,
+                                   const char *message HB_UNUSED,
+                                   ...) {}
+
+  inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
+};
+
+#define return_trace(RET) return trace.ret (RET, __LINE__)
+
+/* Misc */
+
+template <typename T> class hb_assert_unsigned_t;
+template <> class hb_assert_unsigned_t<unsigned char> {};
+template <> class hb_assert_unsigned_t<unsigned short> {};
+template <> class hb_assert_unsigned_t<unsigned int> {};
+template <> class hb_assert_unsigned_t<unsigned long> {};
+
+template <typename T> static inline bool
+hb_in_range (T u, T lo, T hi)
+{
+  /* The sizeof() is here to force template instantiation.
+   * I'm sure there are better ways to do this but can't think of
+   * one right now.  Declaring a variable won't work as HB_UNUSED
+   * is unusable on some platforms and unused types are less likely
+   * to generate a warning than unused variables. */
+  ASSERT_STATIC (sizeof (hb_assert_unsigned_t<T>) >= 0);
+
+  /* The casts below are important as if T is smaller than int,
+   * the subtract results will become a signed int! */
+  return (T)(u - lo) <= (T)(hi - lo);
+}
+
+template <typename T> static inline bool
+hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
+{
+  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
+}
+
+template <typename T> static inline bool
+hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
+{
+  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
+}
+
+
+/* Enable bitwise ops on enums marked as flags_t */
+/* To my surprise, looks like the function resolver is happy to silently cast
+ * one enum to another...  So this doesn't provide the type-checking that I
+ * originally had in mind... :(.
+ *
+ * For MSVC warnings, see: https://github.com/behdad/harfbuzz/pull/163
+ */
+#ifdef _MSC_VER
+# pragma warning(disable:4200)
+# pragma warning(disable:4800)
+#endif
+#define HB_MARK_AS_FLAG_T(T) \
+        extern "C++" { \
+          static inline T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
+          static inline T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
+          static inline T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
+          static inline T operator ~ (T r) { return T (~(unsigned int) r); } \
+          static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
+          static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
+          static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
+        }
+
+
+/* Useful for set-operations on small enums.
+ * For example, for testing "x ∈ {x1, x2, x3}" use:
+ * (FLAG_SAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
+ */
+#define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((x) < 32) + (1U << (x)))
+#define FLAG_SAFE(x) (1U << (x))
+#define FLAG_UNSAFE(x) ((x) < 32 ? FLAG_SAFE(x) : 0)
+#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
+
+
+template <typename T, typename T2> static inline void
+hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
+{
+  for (unsigned int i = 1; i < len; i++)
+  {
+    unsigned int j = i;
+    while (j && compar (&array[j - 1], &array[i]) > 0)
+      j--;
+    if (i == j)
+      continue;
+    /* Move item i to occupy place for item j, shift what's in between. */
+    {
+      T t = array[i];
+      memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
+      array[j] = t;
+    }
+    if (array2)
+    {
+      T2 t = array2[i];
+      memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
+      array2[j] = t;
+    }
+  }
+}
+
+template <typename T> static inline void
+hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
+{
+  hb_stable_sort (array, len, compar, (int *) NULL);
+}
+
+static inline hb_bool_t
+hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
+{
+  /* Pain because we don't know whether s is nul-terminated. */
+  char buf[64];
+  len = MIN (ARRAY_LENGTH (buf) - 1, len);
+  strncpy (buf, s, len);
+  buf[len] = '\0';
+
+  char *end;
+  errno = 0;
+  unsigned long v = strtoul (buf, &end, base);
+  if (errno) return false;
+  if (*end) return false;
+  *out = v;
+  return true;
+}
+
+
+/* Global runtime options. */
+
+struct hb_options_t
+{
+  unsigned int initialized : 1;
+  unsigned int uniscribe_bug_compatible : 1;
+};
+
+union hb_options_union_t {
+  unsigned int i;
+  hb_options_t opts;
+};
+ASSERT_STATIC (sizeof (int) == sizeof (hb_options_union_t));
+
+HB_INTERNAL void
+_hb_options_init (void);
+
+extern HB_INTERNAL hb_options_union_t _hb_options;
+
+static inline hb_options_t
+hb_options (void)
+{
+  if (unlikely (!_hb_options.i))
+    _hb_options_init ();
+
+  return _hb_options.opts;
+}
+
+/* Size signifying variable-sized array */
+#define VAR 1
+
+#endif /* HB_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-set-private.hh b/src/share/native/sun/font/harfbuzz/hb-set-private.hh
new file mode 100644
index 0000000..6c0199c
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-set-private.hh
@@ -0,0 +1,402 @@
+/*
+ * 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_SET_PRIVATE_HH
+#define HB_SET_PRIVATE_HH
+
+#include "hb-private.hh"
+#include "hb-object-private.hh"
+
+
+/*
+ * The set digests here implement various "filters" that support
+ * "approximate member query".  Conceptually these are like Bloom
+ * Filter and Quotient Filter, however, much smaller, faster, and
+ * designed to fit the requirements of our uses for glyph coverage
+ * queries.
+ *
+ * Our filters are highly accurate if the lookup covers fairly local
+ * set of glyphs, but fully flooded and ineffective if coverage is
+ * all over the place.
+ *
+ * The frozen-set can be used instead of a digest, to trade more
+ * memory for 100% accuracy, but in practice, that doesn't look like
+ * an attractive trade-off.
+ */
+
+template <typename mask_t, unsigned int shift>
+struct hb_set_digest_lowest_bits_t
+{
+  ASSERT_POD ();
+
+  static const unsigned int mask_bytes = sizeof (mask_t);
+  static const unsigned int mask_bits = sizeof (mask_t) * 8;
+  static const unsigned int num_bits = 0
+                                     + (mask_bytes >= 1 ? 3 : 0)
+                                     + (mask_bytes >= 2 ? 1 : 0)
+                                     + (mask_bytes >= 4 ? 1 : 0)
+                                     + (mask_bytes >= 8 ? 1 : 0)
+                                     + (mask_bytes >= 16? 1 : 0)
+                                     + 0;
+
+  ASSERT_STATIC (shift < sizeof (hb_codepoint_t) * 8);
+  ASSERT_STATIC (shift + num_bits <= sizeof (hb_codepoint_t) * 8);
+
+  inline void init (void) {
+    mask = 0;
+  }
+
+  inline void add (hb_codepoint_t g) {
+    mask |= mask_for (g);
+  }
+
+  inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
+    if ((b >> shift) - (a >> shift) >= mask_bits - 1)
+      mask = (mask_t) -1;
+    else {
+      mask_t ma = mask_for (a);
+      mask_t mb = mask_for (b);
+      mask |= mb + (mb - ma) - (mb < ma);
+    }
+  }
+
+  inline bool may_have (hb_codepoint_t g) const {
+    return !!(mask & mask_for (g));
+  }
+
+  private:
+
+  static inline mask_t mask_for (hb_codepoint_t g) {
+    return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1));
+  }
+  mask_t mask;
+};
+
+template <typename head_t, typename tail_t>
+struct hb_set_digest_combiner_t
+{
+  ASSERT_POD ();
+
+  inline void init (void) {
+    head.init ();
+    tail.init ();
+  }
+
+  inline void add (hb_codepoint_t g) {
+    head.add (g);
+    tail.add (g);
+  }
+
+  inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
+    head.add_range (a, b);
+    tail.add_range (a, b);
+  }
+
+  inline bool may_have (hb_codepoint_t g) const {
+    return head.may_have (g) && tail.may_have (g);
+  }
+
+  private:
+  head_t head;
+  tail_t tail;
+};
+
+
+/*
+ * hb_set_digest_t
+ *
+ * This is a combination of digests that performs "best".
+ * There is not much science to this: it's a result of intuition
+ * and testing.
+ */
+typedef hb_set_digest_combiner_t
+<
+  hb_set_digest_lowest_bits_t<unsigned long, 4>,
+  hb_set_digest_combiner_t
+  <
+    hb_set_digest_lowest_bits_t<unsigned long, 0>,
+    hb_set_digest_lowest_bits_t<unsigned long, 9>
+  >
+> hb_set_digest_t;
+
+
+
+/*
+ * hb_set_t
+ */
+
+
+/* TODO Make this faster and memmory efficient. */
+
+struct hb_set_t
+{
+  friend struct hb_frozen_set_t;
+
+  hb_object_header_t header;
+  ASSERT_POD ();
+  bool in_error;
+
+  inline void init (void) {
+    hb_object_init (this);
+    clear ();
+  }
+  inline void fini (void) {
+  }
+  inline void clear (void) {
+    if (unlikely (hb_object_is_inert (this)))
+      return;
+    in_error = false;
+    memset (elts, 0, sizeof elts);
+  }
+  inline bool is_empty (void) const {
+    for (unsigned int i = 0; i < ARRAY_LENGTH (elts); i++)
+      if (elts[i])
+        return false;
+    return true;
+  }
+  inline void add (hb_codepoint_t g)
+  {
+    if (unlikely (in_error)) return;
+    if (unlikely (g == INVALID)) return;
+    if (unlikely (g > MAX_G)) return;
+    elt (g) |= mask (g);
+  }
+  inline void add_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    if (unlikely (in_error)) return;
+    /* TODO Speedup */
+    for (unsigned int i = a; i < b + 1; i++)
+      add (i);
+  }
+  inline void del (hb_codepoint_t g)
+  {
+    if (unlikely (in_error)) return;
+    if (unlikely (g > MAX_G)) return;
+    elt (g) &= ~mask (g);
+  }
+  inline void del_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    if (unlikely (in_error)) return;
+    /* TODO Speedup */
+    for (unsigned int i = a; i < b + 1; i++)
+      del (i);
+  }
+  inline bool has (hb_codepoint_t g) const
+  {
+    if (unlikely (g > MAX_G)) return false;
+    return !!(elt (g) & mask (g));
+  }
+  inline bool intersects (hb_codepoint_t first,
+                          hb_codepoint_t last) const
+  {
+    if (unlikely (first > MAX_G)) return false;
+    if (unlikely (last  > MAX_G)) last = MAX_G;
+    unsigned int end = last + 1;
+    for (hb_codepoint_t i = first; i < end; i++)
+      if (has (i))
+        return true;
+    return false;
+  }
+  inline bool is_equal (const hb_set_t *other) const
+  {
+    for (unsigned int i = 0; i < ELTS; i++)
+      if (elts[i] != other->elts[i])
+        return false;
+    return true;
+  }
+  inline void set (const hb_set_t *other)
+  {
+    if (unlikely (in_error)) return;
+    for (unsigned int i = 0; i < ELTS; i++)
+      elts[i] = other->elts[i];
+  }
+  inline void union_ (const hb_set_t *other)
+  {
+    if (unlikely (in_error)) return;
+    for (unsigned int i = 0; i < ELTS; i++)
+      elts[i] |= other->elts[i];
+  }
+  inline void intersect (const hb_set_t *other)
+  {
+    if (unlikely (in_error)) return;
+    for (unsigned int i = 0; i < ELTS; i++)
+      elts[i] &= other->elts[i];
+  }
+  inline void subtract (const hb_set_t *other)
+  {
+    if (unlikely (in_error)) return;
+    for (unsigned int i = 0; i < ELTS; i++)
+      elts[i] &= ~other->elts[i];
+  }
+  inline void symmetric_difference (const hb_set_t *other)
+  {
+    if (unlikely (in_error)) return;
+    for (unsigned int i = 0; i < ELTS; i++)
+      elts[i] ^= other->elts[i];
+  }
+  inline void invert (void)
+  {
+    if (unlikely (in_error)) return;
+    for (unsigned int i = 0; i < ELTS; i++)
+      elts[i] = ~elts[i];
+  }
+  inline bool next (hb_codepoint_t *codepoint) const
+  {
+    if (unlikely (*codepoint == INVALID)) {
+      hb_codepoint_t i = get_min ();
+      if (i != INVALID) {
+        *codepoint = i;
+        return true;
+      } else {
+        *codepoint = INVALID;
+        return false;
+      }
+    }
+    for (hb_codepoint_t i = *codepoint + 1; i < MAX_G + 1; i++)
+      if (has (i)) {
+        *codepoint = i;
+        return true;
+      }
+    *codepoint = INVALID;
+    return false;
+  }
+  inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
+  {
+    hb_codepoint_t i;
+
+    i = *last;
+    if (!next (&i))
+    {
+      *last = *first = INVALID;
+      return false;
+    }
+
+    *last = *first = i;
+    while (next (&i) && i == *last + 1)
+      (*last)++;
+
+    return true;
+  }
+
+  inline unsigned int get_population (void) const
+  {
+    unsigned int count = 0;
+    for (unsigned int i = 0; i < ELTS; i++)
+      count += _hb_popcount32 (elts[i]);
+    return count;
+  }
+  inline hb_codepoint_t get_min (void) const
+  {
+    for (unsigned int i = 0; i < ELTS; i++)
+      if (elts[i])
+        for (unsigned int j = 0; j < BITS; j++)
+          if (elts[i] & (1 << j))
+            return i * BITS + j;
+    return INVALID;
+  }
+  inline hb_codepoint_t get_max (void) const
+  {
+    for (unsigned int i = ELTS; i; i--)
+      if (elts[i - 1])
+        for (unsigned int j = BITS; j; j--)
+          if (elts[i - 1] & (1 << (j - 1)))
+            return (i - 1) * BITS + (j - 1);
+    return INVALID;
+  }
+
+  typedef uint32_t elt_t;
+  static const unsigned int MAX_G = 65536 - 1; /* XXX Fix this... */
+  static const unsigned int SHIFT = 5;
+  static const unsigned int BITS = (1 << SHIFT);
+  static const unsigned int MASK = BITS - 1;
+  static const unsigned int ELTS = (MAX_G + 1 + (BITS - 1)) / BITS;
+  static  const hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
+
+  elt_t &elt (hb_codepoint_t g) { return elts[g >> SHIFT]; }
+  elt_t const &elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
+  elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); }
+
+  elt_t elts[ELTS]; /* XXX 8kb */
+
+  ASSERT_STATIC (sizeof (elt_t) * 8 == BITS);
+  ASSERT_STATIC (sizeof (elt_t) * 8 * ELTS > MAX_G);
+};
+
+struct hb_frozen_set_t
+{
+  static const unsigned int SHIFT = hb_set_t::SHIFT;
+  static const unsigned int BITS = hb_set_t::BITS;
+  static const unsigned int MASK = hb_set_t::MASK;
+  typedef hb_set_t::elt_t elt_t;
+
+  inline void init (const hb_set_t &set)
+  {
+    start = count = 0;
+    elts = NULL;
+
+    unsigned int max = set.get_max ();
+    if (max == set.INVALID)
+      return;
+    unsigned int min = set.get_min ();
+    const elt_t &min_elt = set.elt (min);
+
+    start = min & ~MASK;
+    count = max - start + 1;
+    unsigned int num_elts = (count + BITS - 1) / BITS;
+    unsigned int elts_size = num_elts * sizeof (elt_t);
+    elts = (elt_t *) malloc (elts_size);
+    if (unlikely (!elts))
+    {
+      start = count = 0;
+      return;
+    }
+    memcpy (elts, &min_elt, elts_size);
+  }
+
+  inline void fini (void)
+  {
+    if (elts)
+      free (elts);
+  }
+
+  inline bool has (hb_codepoint_t g) const
+  {
+    /* hb_codepoint_t is unsigned. */
+    g -= start;
+    if (unlikely (g > count)) return false;
+    return !!(elt (g) & mask (g));
+  }
+
+  elt_t const &elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
+  elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); }
+
+  private:
+  hb_codepoint_t start, count;
+  elt_t *elts;
+};
+
+
+#endif /* HB_SET_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-set.cpp b/src/share/native/sun/font/harfbuzz/hb-set.cpp
new file mode 100644
index 0000000..beb2910
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-set.cpp
@@ -0,0 +1,471 @@
+/*
+ * 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
+ */
+
+#include "hb-set-private.hh"
+
+
+/* Public API */
+
+
+/**
+ * hb_set_create: (Xconstructor)
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.2
+ **/
+hb_set_t *
+hb_set_create (void)
+{
+  hb_set_t *set;
+
+  if (!(set = hb_object_create<hb_set_t> ()))
+    return hb_set_get_empty ();
+
+  set->clear ();
+
+  return set;
+}
+
+/**
+ * hb_set_get_empty:
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.2
+ **/
+hb_set_t *
+hb_set_get_empty (void)
+{
+  static const hb_set_t _hb_set_nil = {
+    HB_OBJECT_HEADER_STATIC,
+    true, /* in_error */
+
+    {0} /* elts */
+  };
+
+  return const_cast<hb_set_t *> (&_hb_set_nil);
+}
+
+/**
+ * hb_set_reference: (skip)
+ * @set: a set.
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.2
+ **/
+hb_set_t *
+hb_set_reference (hb_set_t *set)
+{
+  return hb_object_reference (set);
+}
+
+/**
+ * hb_set_destroy: (skip)
+ * @set: a set.
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_set_destroy (hb_set_t *set)
+{
+  if (!hb_object_destroy (set)) return;
+
+  set->fini ();
+
+  free (set);
+}
+
+/**
+ * hb_set_set_user_data: (skip)
+ * @set: a set.
+ * @key:
+ * @data:
+ * @destroy (closure data):
+ * @replace:
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_set_set_user_data (hb_set_t           *set,
+                      hb_user_data_key_t *key,
+                      void *              data,
+                      hb_destroy_func_t   destroy,
+                      hb_bool_t           replace)
+{
+  return hb_object_set_user_data (set, key, data, destroy, replace);
+}
+
+/**
+ * hb_set_get_user_data: (skip)
+ * @set: a set.
+ * @key:
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.2
+ **/
+void *
+hb_set_get_user_data (hb_set_t           *set,
+                      hb_user_data_key_t *key)
+{
+  return hb_object_get_user_data (set, key);
+}
+
+
+/**
+ * hb_set_allocation_successful:
+ * @set: a set.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_set_allocation_successful (const hb_set_t  *set HB_UNUSED)
+{
+  return !set->in_error;
+}
+
+/**
+ * hb_set_clear:
+ * @set: a set.
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_set_clear (hb_set_t *set)
+{
+  set->clear ();
+}
+
+/**
+ * hb_set_is_empty:
+ * @set: a set.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.7
+ **/
+hb_bool_t
+hb_set_is_empty (const hb_set_t *set)
+{
+  return set->is_empty ();
+}
+
+/**
+ * hb_set_has:
+ * @set: a set.
+ * @codepoint:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_set_has (const hb_set_t *set,
+            hb_codepoint_t  codepoint)
+{
+  return set->has (codepoint);
+}
+
+/**
+ * hb_set_add:
+ * @set: a set.
+ * @codepoint:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_set_add (hb_set_t       *set,
+            hb_codepoint_t  codepoint)
+{
+  set->add (codepoint);
+}
+
+/**
+ * hb_set_add_range:
+ * @set: a set.
+ * @first:
+ * @last:
+ *
+ *
+ *
+ * Since: 0.9.7
+ **/
+void
+hb_set_add_range (hb_set_t       *set,
+                  hb_codepoint_t  first,
+                  hb_codepoint_t  last)
+{
+  set->add_range (first, last);
+}
+
+/**
+ * hb_set_del:
+ * @set: a set.
+ * @codepoint:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_set_del (hb_set_t       *set,
+            hb_codepoint_t  codepoint)
+{
+  set->del (codepoint);
+}
+
+/**
+ * hb_set_del_range:
+ * @set: a set.
+ * @first:
+ * @last:
+ *
+ *
+ *
+ * Since: 0.9.7
+ **/
+void
+hb_set_del_range (hb_set_t       *set,
+                  hb_codepoint_t  first,
+                  hb_codepoint_t  last)
+{
+  set->del_range (first, last);
+}
+
+/**
+ * hb_set_is_equal:
+ * @set: a set.
+ * @other:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.7
+ **/
+hb_bool_t
+hb_set_is_equal (const hb_set_t *set,
+                 const hb_set_t *other)
+{
+  return set->is_equal (other);
+}
+
+/**
+ * hb_set_set:
+ * @set: a set.
+ * @other:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_set_set (hb_set_t       *set,
+            const hb_set_t *other)
+{
+  set->set (other);
+}
+
+/**
+ * hb_set_union:
+ * @set: a set.
+ * @other:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_set_union (hb_set_t       *set,
+              const hb_set_t *other)
+{
+  set->union_ (other);
+}
+
+/**
+ * hb_set_intersect:
+ * @set: a set.
+ * @other:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_set_intersect (hb_set_t       *set,
+                  const hb_set_t *other)
+{
+  set->intersect (other);
+}
+
+/**
+ * hb_set_subtract:
+ * @set: a set.
+ * @other:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_set_subtract (hb_set_t       *set,
+                 const hb_set_t *other)
+{
+  set->subtract (other);
+}
+
+/**
+ * hb_set_symmetric_difference:
+ * @set: a set.
+ * @other:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_set_symmetric_difference (hb_set_t       *set,
+                             const hb_set_t *other)
+{
+  set->symmetric_difference (other);
+}
+
+/**
+ * hb_set_invert:
+ * @set: a set.
+ *
+ *
+ *
+ * Since: 0.9.10
+ **/
+void
+hb_set_invert (hb_set_t *set)
+{
+  set->invert ();
+}
+
+/**
+ * hb_set_get_population:
+ * @set: a set.
+ *
+ * Returns the number of numbers in the set.
+ *
+ * Return value: set population.
+ *
+ * Since: 0.9.7
+ **/
+unsigned int
+hb_set_get_population (const hb_set_t *set)
+{
+  return set->get_population ();
+}
+
+/**
+ * hb_set_get_min:
+ * @set: a set.
+ *
+ * Finds the minimum number in the set.
+ *
+ * Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty.
+ *
+ * Since: 0.9.7
+ **/
+hb_codepoint_t
+hb_set_get_min (const hb_set_t *set)
+{
+  return set->get_min ();
+}
+
+/**
+ * hb_set_get_max:
+ * @set: a set.
+ *
+ * Finds the maximum number in the set.
+ *
+ * Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty.
+ *
+ * Since: 0.9.7
+ **/
+hb_codepoint_t
+hb_set_get_max (const hb_set_t *set)
+{
+  return set->get_max ();
+}
+
+/**
+ * hb_set_next:
+ * @set: a set.
+ * @codepoint: (inout):
+ *
+ *
+ *
+ * Return value: whether there was a next value.
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_set_next (const hb_set_t *set,
+             hb_codepoint_t *codepoint)
+{
+  return set->next (codepoint);
+}
+
+/**
+ * hb_set_next_range:
+ * @set: a set.
+ * @first: (out): output first codepoint in the range.
+ * @last: (inout): input current last and output last codepoint in the range.
+ *
+ * Gets the next consecutive range of numbers in @set that
+ * are greater than current value of @last.
+ *
+ * Return value: whether there was a next range.
+ *
+ * Since: 0.9.7
+ **/
+hb_bool_t
+hb_set_next_range (const hb_set_t *set,
+                   hb_codepoint_t *first,
+                   hb_codepoint_t *last)
+{
+  return set->next_range (first, last);
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-set.h b/src/share/native/sun/font/harfbuzz/hb-set.h
new file mode 100644
index 0000000..f7a544f
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-set.h
@@ -0,0 +1,157 @@
+/*
+ * 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_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_SET_H
+#define HB_SET_H
+
+#include "hb-common.h"
+
+HB_BEGIN_DECLS
+
+
+/*
+ * Since: 0.9.21
+ */
+#define HB_SET_VALUE_INVALID ((hb_codepoint_t) -1)
+
+typedef struct hb_set_t hb_set_t;
+
+
+HB_EXTERN hb_set_t *
+hb_set_create (void);
+
+HB_EXTERN hb_set_t *
+hb_set_get_empty (void);
+
+HB_EXTERN hb_set_t *
+hb_set_reference (hb_set_t *set);
+
+HB_EXTERN void
+hb_set_destroy (hb_set_t *set);
+
+HB_EXTERN hb_bool_t
+hb_set_set_user_data (hb_set_t           *set,
+                      hb_user_data_key_t *key,
+                      void *              data,
+                      hb_destroy_func_t   destroy,
+                      hb_bool_t           replace);
+
+HB_EXTERN void *
+hb_set_get_user_data (hb_set_t           *set,
+                      hb_user_data_key_t *key);
+
+
+/* Returns false if allocation has failed before */
+HB_EXTERN hb_bool_t
+hb_set_allocation_successful (const hb_set_t *set);
+
+HB_EXTERN void
+hb_set_clear (hb_set_t *set);
+
+HB_EXTERN hb_bool_t
+hb_set_is_empty (const hb_set_t *set);
+
+HB_EXTERN hb_bool_t
+hb_set_has (const hb_set_t *set,
+            hb_codepoint_t  codepoint);
+
+/* Right now limited to 16-bit integers.  Eventually will do full codepoint range, sans -1
+ * which we will use as a sentinel. */
+HB_EXTERN void
+hb_set_add (hb_set_t       *set,
+            hb_codepoint_t  codepoint);
+
+HB_EXTERN void
+hb_set_add_range (hb_set_t       *set,
+                  hb_codepoint_t  first,
+                  hb_codepoint_t  last);
+
+HB_EXTERN void
+hb_set_del (hb_set_t       *set,
+            hb_codepoint_t  codepoint);
+
+HB_EXTERN void
+hb_set_del_range (hb_set_t       *set,
+                  hb_codepoint_t  first,
+                  hb_codepoint_t  last);
+
+HB_EXTERN hb_bool_t
+hb_set_is_equal (const hb_set_t *set,
+                 const hb_set_t *other);
+
+HB_EXTERN void
+hb_set_set (hb_set_t       *set,
+            const hb_set_t *other);
+
+HB_EXTERN void
+hb_set_union (hb_set_t       *set,
+              const hb_set_t *other);
+
+HB_EXTERN void
+hb_set_intersect (hb_set_t       *set,
+                  const hb_set_t *other);
+
+HB_EXTERN void
+hb_set_subtract (hb_set_t       *set,
+                 const hb_set_t *other);
+
+HB_EXTERN void
+hb_set_symmetric_difference (hb_set_t       *set,
+                             const hb_set_t *other);
+
+HB_EXTERN void
+hb_set_invert (hb_set_t *set);
+
+HB_EXTERN unsigned int
+hb_set_get_population (const hb_set_t *set);
+
+/* Returns -1 if set empty. */
+HB_EXTERN hb_codepoint_t
+hb_set_get_min (const hb_set_t *set);
+
+/* Returns -1 if set empty. */
+HB_EXTERN hb_codepoint_t
+hb_set_get_max (const hb_set_t *set);
+
+/* Pass -1 in to get started. */
+HB_EXTERN hb_bool_t
+hb_set_next (const hb_set_t *set,
+             hb_codepoint_t *codepoint);
+
+/* Pass -1 for first and last to get started. */
+HB_EXTERN hb_bool_t
+hb_set_next_range (const hb_set_t *set,
+                   hb_codepoint_t *first,
+                   hb_codepoint_t *last);
+
+
+HB_END_DECLS
+
+#endif /* HB_SET_H */
diff --git a/src/share/native/sun/font/harfbuzz/hb-shape-plan-private.hh b/src/share/native/sun/font/harfbuzz/hb-shape-plan-private.hh
new file mode 100644
index 0000000..5ecc96c
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-shape-plan-private.hh
@@ -0,0 +1,62 @@
+/*
+ * 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_SHAPE_PLAN_PRIVATE_HH
+#define HB_SHAPE_PLAN_PRIVATE_HH
+
+#include "hb-private.hh"
+#include "hb-object-private.hh"
+#include "hb-shaper-private.hh"
+
+
+struct hb_shape_plan_t
+{
+  hb_object_header_t header;
+  ASSERT_POD ();
+
+  hb_bool_t default_shaper_list;
+  hb_face_t *face_unsafe; /* We don't carry a reference to face. */
+  hb_segment_properties_t props;
+
+  hb_shape_func_t *shaper_func;
+  const char *shaper_name;
+
+  hb_feature_t *user_features;
+  unsigned int num_user_features;
+
+  struct hb_shaper_data_t shaper_data;
+};
+
+#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS \
+        , const hb_feature_t            *user_features \
+        , unsigned int                   num_user_features
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, shape_plan);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
+
+
+#endif /* HB_SHAPE_PLAN_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-shape-plan.cpp b/src/share/native/sun/font/harfbuzz/hb-shape-plan.cpp
new file mode 100644
index 0000000..d20912e
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-shape-plan.cpp
@@ -0,0 +1,500 @@
+/*
+ * 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
+ */
+
+#include "hb-shape-plan-private.hh"
+#include "hb-shaper-private.hh"
+#include "hb-font-private.hh"
+#include "hb-buffer-private.hh"
+
+
+#ifndef HB_DEBUG_SHAPE_PLAN
+#define HB_DEBUG_SHAPE_PLAN (HB_DEBUG+0)
+#endif
+
+
+#define HB_SHAPER_IMPLEMENT(shaper) \
+        HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face) \
+        HB_SHAPER_DATA_ENSURE_DECLARE(shaper, font)
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+
+static void
+hb_shape_plan_plan (hb_shape_plan_t    *shape_plan,
+                    const hb_feature_t *user_features,
+                    unsigned int        num_user_features,
+                    const char * const *shaper_list)
+{
+  DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
+                  "num_features=%d shaper_list=%p",
+                  num_user_features,
+                  shaper_list);
+
+  const hb_shaper_pair_t *shapers = _hb_shapers_get ();
+
+#define HB_SHAPER_PLAN(shaper) \
+        HB_STMT_START { \
+          if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) { \
+            HB_SHAPER_DATA (shaper, shape_plan) = \
+              HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \
+            shape_plan->shaper_func = _hb_##shaper##_shape; \
+            shape_plan->shaper_name = #shaper; \
+            return; \
+          } \
+        } HB_STMT_END
+
+  if (likely (!shaper_list)) {
+    for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
+      if (0)
+        ;
+#define HB_SHAPER_IMPLEMENT(shaper) \
+      else if (shapers[i].func == _hb_##shaper##_shape) \
+        HB_SHAPER_PLAN (shaper);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+  } else {
+    for (; *shaper_list; shaper_list++)
+      if (0)
+        ;
+#define HB_SHAPER_IMPLEMENT(shaper) \
+      else if (0 == strcmp (*shaper_list, #shaper)) \
+        HB_SHAPER_PLAN (shaper);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+  }
+
+#undef HB_SHAPER_PLAN
+}
+
+
+/*
+ * hb_shape_plan_t
+ */
+
+/**
+ * hb_shape_plan_create: (Xconstructor)
+ * @face:
+ * @props:
+ * @user_features: (array length=num_user_features):
+ * @num_user_features:
+ * @shaper_list: (array zero-terminated=1):
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.7
+ **/
+hb_shape_plan_t *
+hb_shape_plan_create (hb_face_t                     *face,
+                      const hb_segment_properties_t *props,
+                      const hb_feature_t            *user_features,
+                      unsigned int                   num_user_features,
+                      const char * const            *shaper_list)
+{
+  DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
+                  "face=%p num_features=%d shaper_list=%p",
+                  face,
+                  num_user_features,
+                  shaper_list);
+
+  hb_shape_plan_t *shape_plan;
+  hb_feature_t *features = NULL;
+
+  if (unlikely (!face))
+    face = hb_face_get_empty ();
+  if (unlikely (!props))
+    return hb_shape_plan_get_empty ();
+  if (num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
+    return hb_shape_plan_get_empty ();
+  if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) {
+    free (features);
+    return hb_shape_plan_get_empty ();
+  }
+
+  assert (props->direction != HB_DIRECTION_INVALID);
+
+  hb_face_make_immutable (face);
+  shape_plan->default_shaper_list = shaper_list == NULL;
+  shape_plan->face_unsafe = face;
+  shape_plan->props = *props;
+  shape_plan->num_user_features = num_user_features;
+  shape_plan->user_features = features;
+  if (num_user_features)
+    memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
+
+  hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list);
+
+  return shape_plan;
+}
+
+/**
+ * hb_shape_plan_get_empty:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.7
+ **/
+hb_shape_plan_t *
+hb_shape_plan_get_empty (void)
+{
+  static const hb_shape_plan_t _hb_shape_plan_nil = {
+    HB_OBJECT_HEADER_STATIC,
+
+    true, /* default_shaper_list */
+    NULL, /* face */
+    HB_SEGMENT_PROPERTIES_DEFAULT, /* props */
+
+    NULL, /* shaper_func */
+    NULL, /* shaper_name */
+
+    NULL, /* user_features */
+    0,    /* num_user_featurs */
+
+    {
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+    }
+  };
+
+  return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil);
+}
+
+/**
+ * hb_shape_plan_reference: (skip)
+ * @shape_plan: a shape plan.
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.7
+ **/
+hb_shape_plan_t *
+hb_shape_plan_reference (hb_shape_plan_t *shape_plan)
+{
+  return hb_object_reference (shape_plan);
+}
+
+/**
+ * hb_shape_plan_destroy: (skip)
+ * @shape_plan: a shape plan.
+ *
+ *
+ *
+ * Since: 0.9.7
+ **/
+void
+hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
+{
+  if (!hb_object_destroy (shape_plan)) return;
+
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, shape_plan);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+  free (shape_plan->user_features);
+
+  free (shape_plan);
+}
+
+/**
+ * hb_shape_plan_set_user_data: (skip)
+ * @shape_plan: a shape plan.
+ * @key:
+ * @data:
+ * @destroy:
+ * @replace:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.7
+ **/
+hb_bool_t
+hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
+                             hb_user_data_key_t *key,
+                             void *              data,
+                             hb_destroy_func_t   destroy,
+                             hb_bool_t           replace)
+{
+  return hb_object_set_user_data (shape_plan, key, data, destroy, replace);
+}
+
+/**
+ * hb_shape_plan_get_user_data: (skip)
+ * @shape_plan: a shape plan.
+ * @key:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.7
+ **/
+void *
+hb_shape_plan_get_user_data (hb_shape_plan_t    *shape_plan,
+                             hb_user_data_key_t *key)
+{
+  return hb_object_get_user_data (shape_plan, key);
+}
+
+
+/**
+ * hb_shape_plan_execute:
+ * @shape_plan: a shape plan.
+ * @font: a font.
+ * @buffer: a buffer.
+ * @features: (array length=num_features):
+ * @num_features:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.7
+ **/
+hb_bool_t
+hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
+                       hb_font_t          *font,
+                       hb_buffer_t        *buffer,
+                       const hb_feature_t *features,
+                       unsigned int        num_features)
+{
+  DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
+                  "num_features=%d shaper_func=%p",
+                  num_features,
+                  shape_plan->shaper_func);
+
+  if (unlikely (!buffer->len))
+    return true;
+
+  assert (!hb_object_is_inert (buffer));
+  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
+
+  if (unlikely (hb_object_is_inert (shape_plan)))
+    return false;
+
+  assert (shape_plan->face_unsafe == font->face);
+  assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props));
+
+#define HB_SHAPER_EXECUTE(shaper) \
+        HB_STMT_START { \
+          return HB_SHAPER_DATA (shaper, shape_plan) && \
+                 hb_##shaper##_shaper_font_data_ensure (font) && \
+                 _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \
+        } HB_STMT_END
+
+  if (0)
+    ;
+#define HB_SHAPER_IMPLEMENT(shaper) \
+  else if (shape_plan->shaper_func == _hb_##shaper##_shape) \
+    HB_SHAPER_EXECUTE (shaper);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+#undef HB_SHAPER_EXECUTE
+
+  return false;
+}
+
+
+/*
+ * caching
+ */
+
+#if 0
+static unsigned int
+hb_shape_plan_hash (const hb_shape_plan_t *shape_plan)
+{
+  return hb_segment_properties_hash (&shape_plan->props) +
+         shape_plan->default_shaper_list ? 0 : (intptr_t) shape_plan->shaper_func;
+}
+#endif
+
+/* User-feature caching is currently somewhat dumb:
+ * it only finds matches where the feature array is identical,
+ * not cases where the feature lists would be compatible for plan purposes
+ * but have different ranges, for example.
+ */
+struct hb_shape_plan_proposal_t
+{
+  const hb_segment_properties_t  props;
+  const char * const            *shaper_list;
+  const hb_feature_t            *user_features;
+  unsigned int                   num_user_features;
+  hb_shape_func_t               *shaper_func;
+};
+
+static inline hb_bool_t
+hb_shape_plan_user_features_match (const hb_shape_plan_t          *shape_plan,
+                                   const hb_shape_plan_proposal_t *proposal)
+{
+  if (proposal->num_user_features != shape_plan->num_user_features) return false;
+  for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++)
+    if (proposal->user_features[i].tag   != shape_plan->user_features[i].tag   ||
+        proposal->user_features[i].value != shape_plan->user_features[i].value ||
+        proposal->user_features[i].start != shape_plan->user_features[i].start ||
+        proposal->user_features[i].end   != shape_plan->user_features[i].end) return false;
+  return true;
+}
+
+static hb_bool_t
+hb_shape_plan_matches (const hb_shape_plan_t          *shape_plan,
+                       const hb_shape_plan_proposal_t *proposal)
+{
+  return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
+         hb_shape_plan_user_features_match (shape_plan, proposal) &&
+         ((shape_plan->default_shaper_list && proposal->shaper_list == NULL) ||
+          (shape_plan->shaper_func == proposal->shaper_func));
+}
+
+static inline hb_bool_t
+hb_non_global_user_features_present (const hb_feature_t *user_features,
+                                     unsigned int        num_user_features)
+{
+  while (num_user_features)
+    if (user_features->start != 0 || user_features->end != (unsigned int) -1)
+      return true;
+    else
+      num_user_features--, user_features++;
+  return false;
+}
+
+/**
+ * hb_shape_plan_create_cached:
+ * @face:
+ * @props:
+ * @user_features: (array length=num_user_features):
+ * @num_user_features:
+ * @shaper_list: (array zero-terminated=1):
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.7
+ **/
+hb_shape_plan_t *
+hb_shape_plan_create_cached (hb_face_t                     *face,
+                             const hb_segment_properties_t *props,
+                             const hb_feature_t            *user_features,
+                             unsigned int                   num_user_features,
+                             const char * const            *shaper_list)
+{
+  DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
+                  "face=%p num_features=%d shaper_list=%p",
+                  face,
+                  num_user_features,
+                  shaper_list);
+
+  hb_shape_plan_proposal_t proposal = {
+    *props,
+    shaper_list,
+    user_features,
+    num_user_features,
+    NULL
+  };
+
+  if (shaper_list) {
+    /* Choose shaper.  Adapted from hb_shape_plan_plan().
+     * Must choose shaper exactly the same way as that function. */
+    for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++)
+      if (0)
+        ;
+#define HB_SHAPER_IMPLEMENT(shaper) \
+      else if (0 == strcmp (*shaper_item, #shaper) && \
+               hb_##shaper##_shaper_face_data_ensure (face)) \
+      { \
+        proposal.shaper_func = _hb_##shaper##_shape; \
+        break; \
+      }
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+    if (unlikely (!proposal.shaper_func))
+      return hb_shape_plan_get_empty ();
+  }
+
+
+retry:
+  hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans);
+  for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
+    if (hb_shape_plan_matches (node->shape_plan, &proposal))
+    {
+      DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
+      return hb_shape_plan_reference (node->shape_plan);
+    }
+
+  /* Not found. */
+
+  hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
+
+  /* Don't add to the cache if face is inert. */
+  if (unlikely (hb_object_is_inert (face)))
+    return shape_plan;
+
+  /* Don't add the plan to the cache if there were user features with non-global ranges */
+
+  if (hb_non_global_user_features_present (user_features, num_user_features))
+    return shape_plan;
+
+  hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
+  if (unlikely (!node))
+    return shape_plan;
+
+  node->shape_plan = shape_plan;
+  node->next = cached_plan_nodes;
+
+  if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) {
+    hb_shape_plan_destroy (shape_plan);
+    free (node);
+    goto retry;
+  }
+  DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "inserted into cache");
+
+  return hb_shape_plan_reference (shape_plan);
+}
+
+/**
+ * hb_shape_plan_get_shaper:
+ * @shape_plan: a shape plan.
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.7
+ **/
+const char *
+hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan)
+{
+  return shape_plan->shaper_name;
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-shape-plan.h b/src/share/native/sun/font/harfbuzz/hb-shape-plan.h
new file mode 100644
index 0000000..a86d468
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-shape-plan.h
@@ -0,0 +1,89 @@
+/*
+ * 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_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_SHAPE_PLAN_H
+#define HB_SHAPE_PLAN_H
+
+#include "hb-common.h"
+#include "hb-font.h"
+
+HB_BEGIN_DECLS
+
+typedef struct hb_shape_plan_t hb_shape_plan_t;
+
+HB_EXTERN hb_shape_plan_t *
+hb_shape_plan_create (hb_face_t                     *face,
+                      const hb_segment_properties_t *props,
+                      const hb_feature_t            *user_features,
+                      unsigned int                   num_user_features,
+                      const char * const            *shaper_list);
+
+HB_EXTERN hb_shape_plan_t *
+hb_shape_plan_create_cached (hb_face_t                     *face,
+                             const hb_segment_properties_t *props,
+                             const hb_feature_t            *user_features,
+                             unsigned int                   num_user_features,
+                             const char * const            *shaper_list);
+
+HB_EXTERN hb_shape_plan_t *
+hb_shape_plan_get_empty (void);
+
+HB_EXTERN hb_shape_plan_t *
+hb_shape_plan_reference (hb_shape_plan_t *shape_plan);
+
+HB_EXTERN void
+hb_shape_plan_destroy (hb_shape_plan_t *shape_plan);
+
+HB_EXTERN hb_bool_t
+hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
+                             hb_user_data_key_t *key,
+                             void *              data,
+                             hb_destroy_func_t   destroy,
+                             hb_bool_t           replace);
+
+HB_EXTERN void *
+hb_shape_plan_get_user_data (hb_shape_plan_t    *shape_plan,
+                             hb_user_data_key_t *key);
+
+
+HB_EXTERN hb_bool_t
+hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
+                       hb_font_t          *font,
+                       hb_buffer_t        *buffer,
+                       const hb_feature_t *features,
+                       unsigned int        num_features);
+
+HB_EXTERN const char *
+hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan);
+
+
+HB_END_DECLS
+
+#endif /* HB_SHAPE_PLAN_H */
diff --git a/src/share/native/sun/font/harfbuzz/hb-shape.cpp b/src/share/native/sun/font/harfbuzz/hb-shape.cpp
new file mode 100644
index 0000000..2fbaf40
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-shape.cpp
@@ -0,0 +1,406 @@
+/*
+ * 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-shaper-private.hh"
+#include "hb-shape-plan-private.hh"
+#include "hb-buffer-private.hh"
+#include "hb-font-private.hh"
+
+/**
+ * SECTION:hb-shape
+ * @title: Shaping
+ * @short_description: Conversion of text strings into positioned glyphs
+ * @include: hb.h
+ *
+ * Shaping is the central operation of HarfBuzz. Shaping operates on buffers,
+ * which are sequences of Unicode characters that use the same font and have
+ * the same text direction, script and language. After shaping the buffer
+ * contains the output glyphs and their positions.
+ **/
+
+static bool
+parse_space (const char **pp, const char *end)
+{
+  while (*pp < end && ISSPACE (**pp))
+    (*pp)++;
+  return true;
+}
+
+static bool
+parse_char (const char **pp, const char *end, char c)
+{
+  parse_space (pp, end);
+
+  if (*pp == end || **pp != c)
+    return false;
+
+  (*pp)++;
+  return true;
+}
+
+static bool
+parse_uint (const char **pp, const char *end, unsigned int *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;
+  unsigned int v;
+
+  /* Intentionally use strtol instead of strtoul, such that
+   * -1 turns into "big number"... */
+  errno = 0;
+  v = strtol (p, &pend, 0);
+  if (errno || p == pend)
+    return false;
+
+  *pv = v;
+  *pp += pend - p;
+  return true;
+}
+
+static bool
+parse_bool (const char **pp, const char *end, unsigned int *pv)
+{
+  parse_space (pp, end);
+
+  const char *p = *pp;
+  while (*pp < end && ISALPHA(**pp))
+    (*pp)++;
+
+  /* CSS allows on/off as aliases 1/0. */
+  if (*pp - p == 2 || 0 == strncmp (p, "on", 2))
+    *pv = 1;
+  else if (*pp - p == 3 || 0 == strncmp (p, "off", 2))
+    *pv = 0;
+  else
+    return false;
+
+  return true;
+}
+
+static bool
+parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
+{
+  if (parse_char (pp, end, '-'))
+    feature->value = 0;
+  else {
+    parse_char (pp, end, '+');
+    feature->value = 1;
+  }
+
+  return true;
+}
+
+static bool
+parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
+{
+  parse_space (pp, end);
+
+  char quote = 0;
+
+  if (*pp < end && (**pp == '\'' || **pp == '"'))
+  {
+    quote = **pp;
+    (*pp)++;
+  }
+
+  const char *p = *pp;
+  while (*pp < end && ISALNUM(**pp))
+    (*pp)++;
+
+  if (p == *pp || *pp - p > 4)
+    return false;
+
+  feature->tag = hb_tag_from_string (p, *pp - p);
+
+  if (quote)
+  {
+    /* CSS expects exactly four bytes.  And we only allow quotations for
+     * CSS compatibility.  So, enforce the length. */
+     if (*pp - p != 4)
+       return false;
+    if (*pp == end || **pp != quote)
+      return false;
+    (*pp)++;
+  }
+
+  return true;
+}
+
+static bool
+parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
+{
+  parse_space (pp, end);
+
+  bool has_start;
+
+  feature->start = 0;
+  feature->end = (unsigned int) -1;
+
+  if (!parse_char (pp, end, '['))
+    return true;
+
+  has_start = parse_uint (pp, end, &feature->start);
+
+  if (parse_char (pp, end, ':')) {
+    parse_uint (pp, end, &feature->end);
+  } else {
+    if (has_start)
+      feature->end = feature->start + 1;
+  }
+
+  return parse_char (pp, end, ']');
+}
+
+static bool
+parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
+{
+  bool had_equal = parse_char (pp, end, '=');
+  bool had_value = parse_uint (pp, end, &feature->value) ||
+                   parse_bool (pp, end, &feature->value);
+  /* CSS doesn't use equal-sign between tag and value.
+   * If there was an equal-sign, then there *must* be a value.
+   * A value without an eqaul-sign is ok, but not required. */
+  return !had_equal || had_value;
+}
+
+
+static bool
+parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
+{
+  return parse_feature_value_prefix (pp, end, feature) &&
+         parse_feature_tag (pp, end, feature) &&
+         parse_feature_indices (pp, end, feature) &&
+         parse_feature_value_postfix (pp, end, feature) &&
+         parse_space (pp, end) &&
+         *pp == end;
+}
+
+/**
+ * hb_feature_from_string:
+ * @str: (array length=len) (element-type uint8_t): a string to parse
+ * @len: length of @str, or -1 if string is %NULL terminated
+ * @feature: (out): the #hb_feature_t to initialize with the parsed values
+ *
+ * Parses a string into a #hb_feature_t.
+ *
+ * TODO: document the syntax here.
+ *
+ * Return value:
+ * %true if @str is successfully parsed, %false otherwise.
+ *
+ * Since: 0.9.5
+ **/
+hb_bool_t
+hb_feature_from_string (const char *str, int len,
+                        hb_feature_t *feature)
+{
+  hb_feature_t feat;
+
+  if (len < 0)
+    len = strlen (str);
+
+  if (likely (parse_one_feature (&str, str + len, &feat)))
+  {
+    if (feature)
+      *feature = feat;
+    return true;
+  }
+
+  if (feature)
+    memset (feature, 0, sizeof (*feature));
+  return false;
+}
+
+/**
+ * hb_feature_to_string:
+ * @feature: an #hb_feature_t to convert
+ * @buf: (array length=size) (out): output string
+ * @size: the allocated size of @buf
+ *
+ * Converts a #hb_feature_t into a %NULL-terminated string in the format
+ * understood by hb_feature_from_string(). The client in responsible for
+ * allocating big enough size for @buf, 128 bytes is more than enough.
+ *
+ * Since: 0.9.5
+ **/
+void
+hb_feature_to_string (hb_feature_t *feature,
+                      char *buf, unsigned int size)
+{
+  if (unlikely (!size)) return;
+
+  char s[128];
+  unsigned int len = 0;
+  if (feature->value == 0)
+    s[len++] = '-';
+  hb_tag_to_string (feature->tag, s + len);
+  len += 4;
+  while (len && s[len - 1] == ' ')
+    len--;
+  if (feature->start != 0 || feature->end != (unsigned int) -1)
+  {
+    s[len++] = '[';
+    if (feature->start)
+      len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
+    if (feature->end != feature->start + 1) {
+      s[len++] = ':';
+      if (feature->end != (unsigned int) -1)
+        len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
+    }
+    s[len++] = ']';
+  }
+  if (feature->value > 1)
+  {
+    s[len++] = '=';
+    len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
+  }
+  assert (len < ARRAY_LENGTH (s));
+  len = MIN (len, size - 1);
+  memcpy (buf, s, len);
+  buf[len] = '\0';
+}
+
+
+static const char **static_shaper_list;
+
+#ifdef HB_USE_ATEXIT
+static
+void free_static_shaper_list (void)
+{
+  free (static_shaper_list);
+}
+#endif
+
+/**
+ * hb_shape_list_shapers:
+ *
+ * Retrieves the list of shapers supported by HarfBuzz.
+ *
+ * Return value: (transfer none) (array zero-terminated=1): an array of
+ *    constant strings
+ *
+ * Since: 0.9.2
+ **/
+const char **
+hb_shape_list_shapers (void)
+{
+retry:
+  const char **shaper_list = (const char **) hb_atomic_ptr_get (&static_shaper_list);
+
+  if (unlikely (!shaper_list))
+  {
+    /* Not found; allocate one. */
+    shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
+    if (unlikely (!shaper_list)) {
+      static const char *nil_shaper_list[] = {NULL};
+      return nil_shaper_list;
+    }
+
+    const hb_shaper_pair_t *shapers = _hb_shapers_get ();
+    unsigned int i;
+    for (i = 0; i < HB_SHAPERS_COUNT; i++)
+      shaper_list[i] = shapers[i].name;
+    shaper_list[i] = NULL;
+
+    if (!hb_atomic_ptr_cmpexch (&static_shaper_list, NULL, shaper_list)) {
+      free (shaper_list);
+      goto retry;
+    }
+
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_shaper_list); /* First person registers atexit() callback. */
+#endif
+  }
+
+  return shaper_list;
+}
+
+
+/**
+ * hb_shape_full:
+ * @font: an #hb_font_t to use for shaping
+ * @buffer: an #hb_buffer_t to shape
+ * @features: (array length=num_features) (allow-none): an array of user
+ *    specified #hb_feature_t or %NULL
+ * @num_features: the length of @features array
+ * @shaper_list: (array zero-terminated=1) (allow-none): a %NULL-terminated
+ *    array of shapers to use or %NULL
+ *
+ * See hb_shape() for details. If @shaper_list is not %NULL, the specified
+ * shapers will be used in the given order, otherwise the default shapers list
+ * will be used.
+ *
+ * Return value: %FALSE if all shapers failed, %TRUE otherwise
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_shape_full (hb_font_t          *font,
+               hb_buffer_t        *buffer,
+               const hb_feature_t *features,
+               unsigned int        num_features,
+               const char * const *shaper_list)
+{
+  hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list);
+  hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
+  hb_shape_plan_destroy (shape_plan);
+
+  if (res)
+    buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
+  return res;
+}
+
+/**
+ * hb_shape:
+ * @font: an #hb_font_t to use for shaping
+ * @buffer: an #hb_buffer_t to shape
+ * @features: (array length=num_features) (allow-none): an array of user
+ *    specified #hb_feature_t or %NULL
+ * @num_features: the length of @features array
+ *
+ * Shapes @buffer using @font turning its Unicode characters content to
+ * positioned glyphs. If @features is not %NULL, it will be used to control the
+ * features applied during shaping.
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_shape (hb_font_t           *font,
+          hb_buffer_t         *buffer,
+          const hb_feature_t  *features,
+          unsigned int         num_features)
+{
+  hb_shape_full (font, buffer, features, num_features, NULL);
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-shape.h b/src/share/native/sun/font/harfbuzz/hb-shape.h
new file mode 100644
index 0000000..460f770
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-shape.h
@@ -0,0 +1,78 @@
+/*
+ * 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
+ */
+
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_SHAPE_H
+#define HB_SHAPE_H
+
+#include "hb-common.h"
+#include "hb-buffer.h"
+#include "hb-font.h"
+
+HB_BEGIN_DECLS
+
+
+typedef struct hb_feature_t {
+  hb_tag_t      tag;
+  uint32_t      value;
+  unsigned int  start;
+  unsigned int  end;
+} hb_feature_t;
+
+HB_EXTERN hb_bool_t
+hb_feature_from_string (const char *str, int len,
+                        hb_feature_t *feature);
+
+HB_EXTERN void
+hb_feature_to_string (hb_feature_t *feature,
+                      char *buf, unsigned int size);
+
+
+HB_EXTERN void
+hb_shape (hb_font_t           *font,
+          hb_buffer_t         *buffer,
+          const hb_feature_t  *features,
+          unsigned int         num_features);
+
+HB_EXTERN hb_bool_t
+hb_shape_full (hb_font_t          *font,
+               hb_buffer_t        *buffer,
+               const hb_feature_t *features,
+               unsigned int        num_features,
+               const char * const *shaper_list);
+
+HB_EXTERN const char **
+hb_shape_list_shapers (void);
+
+
+HB_END_DECLS
+
+#endif /* HB_SHAPE_H */
diff --git a/src/share/native/sun/font/harfbuzz/hb-shaper-impl-private.hh b/src/share/native/sun/font/harfbuzz/hb-shaper-impl-private.hh
new file mode 100644
index 0000000..7844081
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-shaper-impl-private.hh
@@ -0,0 +1,43 @@
+/*
+ * 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_SHAPER_IMPL_PRIVATE_HH
+#define HB_SHAPER_IMPL_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-shaper-private.hh"
+#include "hb-shape-plan-private.hh"
+#include "hb-font-private.hh"
+#include "hb-buffer-private.hh"
+
+
+#ifdef HB_SHAPER
+#define HB_SHAPER_DATA_GET(object) HB_SHAPER_DATA (HB_SHAPER, object)
+#endif
+
+
+#endif /* HB_SHAPER_IMPL_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-shaper-list.hh b/src/share/native/sun/font/harfbuzz/hb-shaper-list.hh
new file mode 100644
index 0000000..b0835d3
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-shaper-list.hh
@@ -0,0 +1,58 @@
+/*
+ * 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_SHAPER_LIST_HH
+#define HB_SHAPER_LIST_HH
+#endif /* HB_SHAPER_LIST_HH */ /* Dummy header guards */
+
+/* v--- Add new shapers in the right place here. */
+
+#ifdef HAVE_GRAPHITE2
+/* Only picks up fonts that have a "Silf" table. */
+HB_SHAPER_IMPLEMENT (graphite2)
+#endif
+#ifdef HAVE_CORETEXT
+/* Only picks up fonts that have a "mort" or "morx" table. */
+HB_SHAPER_IMPLEMENT (coretext_aat)
+#endif
+
+#ifdef HAVE_OT
+HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */
+#endif
+
+#ifdef HAVE_UNISCRIBE
+HB_SHAPER_IMPLEMENT (uniscribe)
+#endif
+#ifdef HAVE_DIRECTWRITE
+HB_SHAPER_IMPLEMENT (directwrite)
+#endif
+#ifdef HAVE_CORETEXT
+HB_SHAPER_IMPLEMENT (coretext)
+#endif
+
+#ifdef HAVE_FALLBACK
+HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */
+#endif
diff --git a/src/share/native/sun/font/harfbuzz/hb-shaper-private.hh b/src/share/native/sun/font/harfbuzz/hb-shaper-private.hh
new file mode 100644
index 0000000..41aa54f
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-shaper-private.hh
@@ -0,0 +1,108 @@
+/*
+ * 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_SHAPER_PRIVATE_HH
+#define HB_SHAPER_PRIVATE_HH
+
+#include "hb-private.hh"
+
+typedef hb_bool_t hb_shape_func_t (hb_shape_plan_t    *shape_plan,
+                                   hb_font_t          *font,
+                                   hb_buffer_t        *buffer,
+                                   const hb_feature_t *features,
+                                   unsigned int        num_features);
+
+#define HB_SHAPER_IMPLEMENT(name) \
+        extern "C" HB_INTERNAL hb_shape_func_t _hb_##name##_shape;
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+struct hb_shaper_pair_t {
+  char name[16];
+  hb_shape_func_t *func;
+};
+
+HB_INTERNAL const hb_shaper_pair_t *
+_hb_shapers_get (void);
+
+
+/* For embedding in face / font / ... */
+struct hb_shaper_data_t {
+#define HB_SHAPER_IMPLEMENT(shaper) void *shaper;
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+};
+
+#define HB_SHAPERS_COUNT (sizeof (hb_shaper_data_t) / sizeof (void *))
+
+/* Means: succeeded, but don't need to keep any data. */
+#define HB_SHAPER_DATA_SUCCEEDED ((void *) +1)
+
+/* Means: tried but failed to create. */
+#define HB_SHAPER_DATA_INVALID ((void *) -1)
+#define HB_SHAPER_DATA_IS_INVALID(data) ((void *) (data) == HB_SHAPER_DATA_INVALID)
+
+#define HB_SHAPER_DATA_TYPE(shaper, object)             struct hb_##shaper##_shaper_##object##_data_t
+#define HB_SHAPER_DATA_INSTANCE(shaper, object, instance)       (* (HB_SHAPER_DATA_TYPE(shaper, object) **) &(instance)->shaper_data.shaper)
+#define HB_SHAPER_DATA(shaper, object)                  HB_SHAPER_DATA_INSTANCE (shaper, object, object)
+#define HB_SHAPER_DATA_CREATE_FUNC(shaper, object)      _hb_##shaper##_shaper_##object##_data_create
+#define HB_SHAPER_DATA_DESTROY_FUNC(shaper, object)     _hb_##shaper##_shaper_##object##_data_destroy
+
+#define HB_SHAPER_DATA_PROTOTYPE(shaper, object) \
+        HB_SHAPER_DATA_TYPE (shaper, object); /* Type forward declaration. */ \
+        extern "C" HB_INTERNAL HB_SHAPER_DATA_TYPE (shaper, object) * \
+        HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (hb_##object##_t *object HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS); \
+        extern "C" HB_INTERNAL void \
+        HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA_TYPE (shaper, object) *data)
+
+#define HB_SHAPER_DATA_DESTROY(shaper, object) \
+    if (HB_SHAPER_DATA_TYPE (shaper, object) *data = HB_SHAPER_DATA (shaper, object)) \
+      if (data != HB_SHAPER_DATA_INVALID && data != HB_SHAPER_DATA_SUCCEEDED) \
+        HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data);
+
+#define HB_SHAPER_DATA_ENSURE_DECLARE(shaper, object) \
+static inline bool \
+hb_##shaper##_shaper_##object##_data_ensure (hb_##object##_t *object) \
+{\
+  retry: \
+  HB_SHAPER_DATA_TYPE (shaper, object) *data = (HB_SHAPER_DATA_TYPE (shaper, object) *) hb_atomic_ptr_get (&HB_SHAPER_DATA (shaper, object)); \
+  if (unlikely (!data)) { \
+    data = HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (object); \
+    if (unlikely (!data)) \
+      data = (HB_SHAPER_DATA_TYPE (shaper, object) *) HB_SHAPER_DATA_INVALID; \
+    if (!hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), NULL, data)) { \
+      if (data && \
+          data != HB_SHAPER_DATA_INVALID && \
+          data != HB_SHAPER_DATA_SUCCEEDED) \
+        HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data); \
+      goto retry; \
+    } \
+  } \
+  return data != NULL && !HB_SHAPER_DATA_IS_INVALID (data); \
+}
+
+
+#endif /* HB_SHAPER_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-shaper.cpp b/src/share/native/sun/font/harfbuzz/hb-shaper.cpp
new file mode 100644
index 0000000..fec7580
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-shaper.cpp
@@ -0,0 +1,111 @@
+/*
+ * 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
+ */
+
+#include "hb-private.hh"
+#include "hb-shaper-private.hh"
+#include "hb-atomic-private.hh"
+
+
+static const hb_shaper_pair_t all_shapers[] = {
+#define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape},
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+};
+
+
+/* Thread-safe, lock-free, shapers */
+
+static const hb_shaper_pair_t *static_shapers;
+
+#ifdef HB_USE_ATEXIT
+static
+void free_static_shapers (void)
+{
+  if (unlikely (static_shapers != all_shapers))
+    free ((void *) static_shapers);
+}
+#endif
+
+const hb_shaper_pair_t *
+_hb_shapers_get (void)
+{
+retry:
+  hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers);
+
+  if (unlikely (!shapers))
+  {
+    char *env = getenv ("HB_SHAPER_LIST");
+    if (!env || !*env) {
+      (void) hb_atomic_ptr_cmpexch (&static_shapers, NULL, &all_shapers[0]);
+      return (const hb_shaper_pair_t *) all_shapers;
+    }
+
+    /* Not found; allocate one. */
+    shapers = (hb_shaper_pair_t *) calloc (1, sizeof (all_shapers));
+    if (unlikely (!shapers)) {
+      (void) hb_atomic_ptr_cmpexch (&static_shapers, NULL, &all_shapers[0]);
+      return (const hb_shaper_pair_t *) all_shapers;
+    }
+
+    memcpy (shapers, all_shapers, sizeof (all_shapers));
+
+     /* Reorder shaper list to prefer requested shapers. */
+    unsigned int i = 0;
+    char *end, *p = env;
+    for (;;) {
+      end = strchr (p, ',');
+      if (!end)
+        end = p + strlen (p);
+
+      for (unsigned int j = i; j < ARRAY_LENGTH (all_shapers); j++)
+        if (end - p == (int) strlen (shapers[j].name) &&
+            0 == strncmp (shapers[j].name, p, end - p))
+        {
+          /* Reorder this shaper to position i */
+         struct hb_shaper_pair_t t = shapers[j];
+         memmove (&shapers[i + 1], &shapers[i], sizeof (shapers[i]) * (j - i));
+         shapers[i] = t;
+         i++;
+        }
+
+      if (!*end)
+        break;
+      else
+        p = end + 1;
+    }
+
+    if (!hb_atomic_ptr_cmpexch (&static_shapers, NULL, shapers)) {
+      free (shapers);
+      goto retry;
+    }
+
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_shapers); /* First person registers atexit() callback. */
+#endif
+  }
+
+  return shapers;
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-ucdn.cpp b/src/share/native/sun/font/harfbuzz/hb-ucdn.cpp
new file mode 100644
index 0000000..5da04ed
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ucdn.cpp
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "hb-private.hh"
+
+#include "hb-unicode-private.hh"
+
+#include "ucdn.h"
+
+static const hb_script_t ucdn_script_translate[] =
+{
+    HB_SCRIPT_COMMON,
+    HB_SCRIPT_LATIN,
+    HB_SCRIPT_GREEK,
+    HB_SCRIPT_CYRILLIC,
+    HB_SCRIPT_ARMENIAN,
+    HB_SCRIPT_HEBREW,
+    HB_SCRIPT_ARABIC,
+    HB_SCRIPT_SYRIAC,
+    HB_SCRIPT_THAANA,
+    HB_SCRIPT_DEVANAGARI,
+    HB_SCRIPT_BENGALI,
+    HB_SCRIPT_GURMUKHI,
+    HB_SCRIPT_GUJARATI,
+    HB_SCRIPT_ORIYA,
+    HB_SCRIPT_TAMIL,
+    HB_SCRIPT_TELUGU,
+    HB_SCRIPT_KANNADA,
+    HB_SCRIPT_MALAYALAM,
+    HB_SCRIPT_SINHALA,
+    HB_SCRIPT_THAI,
+    HB_SCRIPT_LAO,
+    HB_SCRIPT_TIBETAN,
+    HB_SCRIPT_MYANMAR,
+    HB_SCRIPT_GEORGIAN,
+    HB_SCRIPT_HANGUL,
+    HB_SCRIPT_ETHIOPIC,
+    HB_SCRIPT_CHEROKEE,
+    HB_SCRIPT_CANADIAN_SYLLABICS,
+    HB_SCRIPT_OGHAM,
+    HB_SCRIPT_RUNIC,
+    HB_SCRIPT_KHMER,
+    HB_SCRIPT_MONGOLIAN,
+    HB_SCRIPT_HIRAGANA,
+    HB_SCRIPT_KATAKANA,
+    HB_SCRIPT_BOPOMOFO,
+    HB_SCRIPT_HAN,
+    HB_SCRIPT_YI,
+    HB_SCRIPT_OLD_ITALIC,
+    HB_SCRIPT_GOTHIC,
+    HB_SCRIPT_DESERET,
+    HB_SCRIPT_INHERITED,
+    HB_SCRIPT_TAGALOG,
+    HB_SCRIPT_HANUNOO,
+    HB_SCRIPT_BUHID,
+    HB_SCRIPT_TAGBANWA,
+    HB_SCRIPT_LIMBU,
+    HB_SCRIPT_TAI_LE,
+    HB_SCRIPT_LINEAR_B,
+    HB_SCRIPT_UGARITIC,
+    HB_SCRIPT_SHAVIAN,
+    HB_SCRIPT_OSMANYA,
+    HB_SCRIPT_CYPRIOT,
+    HB_SCRIPT_BRAILLE,
+    HB_SCRIPT_BUGINESE,
+    HB_SCRIPT_COPTIC,
+    HB_SCRIPT_NEW_TAI_LUE,
+    HB_SCRIPT_GLAGOLITIC,
+    HB_SCRIPT_TIFINAGH,
+    HB_SCRIPT_SYLOTI_NAGRI,
+    HB_SCRIPT_OLD_PERSIAN,
+    HB_SCRIPT_KHAROSHTHI,
+    HB_SCRIPT_BALINESE,
+    HB_SCRIPT_CUNEIFORM,
+    HB_SCRIPT_PHOENICIAN,
+    HB_SCRIPT_PHAGS_PA,
+    HB_SCRIPT_NKO,
+    HB_SCRIPT_SUNDANESE,
+    HB_SCRIPT_LEPCHA,
+    HB_SCRIPT_OL_CHIKI,
+    HB_SCRIPT_VAI,
+    HB_SCRIPT_SAURASHTRA,
+    HB_SCRIPT_KAYAH_LI,
+    HB_SCRIPT_REJANG,
+    HB_SCRIPT_LYCIAN,
+    HB_SCRIPT_CARIAN,
+    HB_SCRIPT_LYDIAN,
+    HB_SCRIPT_CHAM,
+    HB_SCRIPT_TAI_THAM,
+    HB_SCRIPT_TAI_VIET,
+    HB_SCRIPT_AVESTAN,
+    HB_SCRIPT_EGYPTIAN_HIEROGLYPHS,
+    HB_SCRIPT_SAMARITAN,
+    HB_SCRIPT_LISU,
+    HB_SCRIPT_BAMUM,
+    HB_SCRIPT_JAVANESE,
+    HB_SCRIPT_MEETEI_MAYEK,
+    HB_SCRIPT_IMPERIAL_ARAMAIC,
+    HB_SCRIPT_OLD_SOUTH_ARABIAN,
+    HB_SCRIPT_INSCRIPTIONAL_PARTHIAN,
+    HB_SCRIPT_INSCRIPTIONAL_PAHLAVI,
+    HB_SCRIPT_OLD_TURKIC,
+    HB_SCRIPT_KAITHI,
+    HB_SCRIPT_BATAK,
+    HB_SCRIPT_BRAHMI,
+    HB_SCRIPT_MANDAIC,
+    HB_SCRIPT_CHAKMA,
+    HB_SCRIPT_MEROITIC_CURSIVE,
+    HB_SCRIPT_MEROITIC_HIEROGLYPHS,
+    HB_SCRIPT_MIAO,
+    HB_SCRIPT_SHARADA,
+    HB_SCRIPT_SORA_SOMPENG,
+    HB_SCRIPT_TAKRI,
+    HB_SCRIPT_UNKNOWN,
+    HB_SCRIPT_BASSA_VAH,
+    HB_SCRIPT_CAUCASIAN_ALBANIAN,
+    HB_SCRIPT_DUPLOYAN,
+    HB_SCRIPT_ELBASAN,
+    HB_SCRIPT_GRANTHA,
+    HB_SCRIPT_KHOJKI,
+    HB_SCRIPT_KHUDAWADI,
+    HB_SCRIPT_LINEAR_A,
+    HB_SCRIPT_MAHAJANI,
+    HB_SCRIPT_MANICHAEAN,
+    HB_SCRIPT_MENDE_KIKAKUI,
+    HB_SCRIPT_MODI,
+    HB_SCRIPT_MRO,
+    HB_SCRIPT_NABATAEAN,
+    HB_SCRIPT_OLD_NORTH_ARABIAN,
+    HB_SCRIPT_OLD_PERMIC,
+    HB_SCRIPT_PAHAWH_HMONG,
+    HB_SCRIPT_PALMYRENE,
+    HB_SCRIPT_PAU_CIN_HAU,
+    HB_SCRIPT_PSALTER_PAHLAVI,
+    HB_SCRIPT_SIDDHAM,
+    HB_SCRIPT_TIRHUTA,
+    HB_SCRIPT_WARANG_CITI,
+    HB_SCRIPT_AHOM,
+    HB_SCRIPT_ANATOLIAN_HIEROGLYPHS,
+    HB_SCRIPT_HATRAN,
+    HB_SCRIPT_MULTANI,
+    HB_SCRIPT_OLD_HUNGARIAN,
+    HB_SCRIPT_SIGNWRITING,
+    HB_SCRIPT_ADLAM,
+    HB_SCRIPT_BHAIKSUKI,
+    HB_SCRIPT_MARCHEN,
+    HB_SCRIPT_NEWA,
+    HB_SCRIPT_OSAGE,
+    HB_SCRIPT_TANGUT,
+};
+
+static hb_unicode_combining_class_t
+hb_ucdn_combining_class(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+                        void *user_data HB_UNUSED)
+{
+    return (hb_unicode_combining_class_t) ucdn_get_combining_class(unicode);
+}
+
+static unsigned int
+hb_ucdn_eastasian_width(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+                        void *user_data HB_UNUSED)
+{
+    int w = ucdn_get_east_asian_width(unicode);
+    return (w == UCDN_EAST_ASIAN_F || w == UCDN_EAST_ASIAN_W) ? 2 : 1;
+}
+
+static hb_unicode_general_category_t
+hb_ucdn_general_category(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+                         void *user_data HB_UNUSED)
+{
+    return (hb_unicode_general_category_t)ucdn_get_general_category(unicode);
+}
+
+static hb_codepoint_t
+hb_ucdn_mirroring(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+                  void *user_data HB_UNUSED)
+{
+    return ucdn_mirror(unicode);
+}
+
+static hb_script_t
+hb_ucdn_script(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+               void *user_data HB_UNUSED)
+{
+    return ucdn_script_translate[ucdn_get_script(unicode)];
+}
+
+static hb_bool_t
+hb_ucdn_compose(hb_unicode_funcs_t *ufuncs,
+                hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab,
+                void *user_data HB_UNUSED)
+{
+    return ucdn_compose(ab, a, b);
+}
+
+static hb_bool_t
+hb_ucdn_decompose(hb_unicode_funcs_t *ufuncs,
+                  hb_codepoint_t ab, hb_codepoint_t *a, hb_codepoint_t *b,
+                  void *user_data HB_UNUSED)
+{
+    return ucdn_decompose(ab, a, b);
+}
+
+static unsigned int
+hb_ucdn_decompose_compatibility(hb_unicode_funcs_t *ufuncs,
+                                hb_codepoint_t u, hb_codepoint_t *decomposed,
+                                void *user_data HB_UNUSED)
+{
+    return ucdn_compat_decompose(u, decomposed);
+}
+
+extern "C" HB_INTERNAL
+hb_unicode_funcs_t *
+hb_ucdn_get_unicode_funcs (void)
+{
+  static const hb_unicode_funcs_t _hb_ucdn_unicode_funcs = {
+    HB_OBJECT_HEADER_STATIC,
+
+    NULL, /* parent */
+    true, /* immutable */
+    {
+#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_ucdn_##name,
+      HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_UNICODE_FUNC_IMPLEMENT
+    }
+  };
+
+  return const_cast<hb_unicode_funcs_t *> (&_hb_ucdn_unicode_funcs);
+}
+
diff --git a/src/share/native/sun/font/harfbuzz/hb-ucdn/ucdn.c b/src/share/native/sun/font/harfbuzz/hb-ucdn/ucdn.c
new file mode 100644
index 0000000..f4e9be1
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ucdn/ucdn.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "ucdn.h"
+
+typedef struct {
+    unsigned char category;
+    unsigned char combining;
+    unsigned char bidi_class;
+    unsigned char mirrored;
+    unsigned char east_asian_width;
+    unsigned char script;
+    unsigned char linebreak_class;
+} UCDRecord;
+
+typedef struct {
+    unsigned short from, to;
+} MirrorPair;
+
+typedef struct {
+  unsigned short from, to;
+  unsigned char type;
+} BracketPair;
+
+typedef struct {
+    unsigned int start;
+    short count, index;
+} Reindex;
+
+#include "unicodedata_db.h"
+
+/* constants required for Hangul (de)composition */
+#define SBASE 0xAC00
+#define LBASE 0x1100
+#define VBASE 0x1161
+#define TBASE 0x11A7
+#define SCOUNT 11172
+#define LCOUNT 19
+#define VCOUNT 21
+#define TCOUNT 28
+#define NCOUNT (VCOUNT * TCOUNT)
+
+static const UCDRecord *get_ucd_record(uint32_t code)
+{
+    int index, offset;
+
+    if (code >= 0x110000)
+        index = 0;
+    else {
+        index  = index0[code >> (SHIFT1+SHIFT2)] << SHIFT1;
+        offset = (code >> SHIFT2) & ((1<<SHIFT1) - 1);
+        index  = index1[index + offset] << SHIFT2;
+        offset = code & ((1<<SHIFT2) - 1);
+        index  = index2[index + offset];
+    }
+
+    return &ucd_records[index];
+}
+
+static const unsigned short *get_decomp_record(uint32_t code)
+{
+    int index, offset;
+
+    if (code >= 0x110000)
+        index = 0;
+    else {
+        index  = decomp_index0[code >> (DECOMP_SHIFT1+DECOMP_SHIFT2)]
+            << DECOMP_SHIFT1;
+        offset = (code >> DECOMP_SHIFT2) & ((1<<DECOMP_SHIFT1) - 1);
+        index  = decomp_index1[index + offset] << DECOMP_SHIFT2;
+        offset = code & ((1<<DECOMP_SHIFT2) - 1);
+        index  = decomp_index2[index + offset];
+    }
+
+    return &decomp_data[index];
+}
+
+static int get_comp_index(uint32_t code, const Reindex *idx)
+{
+    int i;
+
+    for (i = 0; idx[i].start; i++) {
+        const Reindex *cur = &idx[i];
+        if (code < cur->start)
+            return -1;
+        if (code <= cur->start + cur->count) {
+            return cur->index + (code - cur->start);
+        }
+    }
+
+    return -1;
+}
+
+static int compare_mp(const void *a, const void *b)
+{
+    MirrorPair *mpa = (MirrorPair *)a;
+    MirrorPair *mpb = (MirrorPair *)b;
+    return mpa->from - mpb->from;
+}
+
+static int compare_bp(const void *a, const void *b)
+{
+    BracketPair *bpa = (BracketPair *)a;
+    BracketPair *bpb = (BracketPair *)b;
+    return bpa->from - bpb->from;
+}
+
+static BracketPair *search_bp(uint32_t code)
+{
+    BracketPair bp = {0,0,2};
+    BracketPair *res;
+
+    bp.from = code;
+    res = bsearch(&bp, bracket_pairs, BIDI_BRACKET_LEN, sizeof(BracketPair),
+            compare_bp);
+    return res;
+}
+
+static int hangul_pair_decompose(uint32_t code, uint32_t *a, uint32_t *b)
+{
+    int si = code - SBASE;
+
+    if (si < 0 || si >= SCOUNT)
+        return 0;
+
+    if (si % TCOUNT) {
+        /* LV,T */
+        *a = SBASE + (si / TCOUNT) * TCOUNT;
+        *b = TBASE + (si % TCOUNT);
+        return 3;
+    } else {
+        /* L,V */
+        *a = LBASE + (si / NCOUNT);
+        *b = VBASE + (si % NCOUNT) / TCOUNT;
+        return 2;
+    }
+}
+
+static int hangul_pair_compose(uint32_t *code, uint32_t a, uint32_t b)
+{
+    if (b < VBASE || b >= (TBASE + TCOUNT))
+        return 0;
+
+    if ((a < LBASE || a >= (LBASE + LCOUNT))
+            && (a < SBASE || a >= (SBASE + SCOUNT)))
+        return 0;
+
+    if (a >= SBASE) {
+        /* LV,T */
+        *code = a + (b - TBASE);
+        return 3;
+    } else {
+        /* L,V */
+        int li = a - LBASE;
+        int vi = b - VBASE;
+        *code = SBASE + li * NCOUNT + vi * TCOUNT;
+        return 2;
+    }
+}
+
+static uint32_t decode_utf16(const unsigned short **code_ptr)
+{
+    const unsigned short *code = *code_ptr;
+
+    if ((code[0] & 0xd800) != 0xd800) {
+        *code_ptr += 1;
+        return (uint32_t)code[0];
+    } else {
+        *code_ptr += 2;
+        return 0x10000 + ((uint32_t)code[1] - 0xdc00) +
+            (((uint32_t)code[0] - 0xd800) << 10);
+    }
+}
+
+const char *ucdn_get_unicode_version(void)
+{
+    return UNIDATA_VERSION;
+}
+
+int ucdn_get_combining_class(uint32_t code)
+{
+    return get_ucd_record(code)->combining;
+}
+
+int ucdn_get_east_asian_width(uint32_t code)
+{
+    return get_ucd_record(code)->east_asian_width;
+}
+
+int ucdn_get_general_category(uint32_t code)
+{
+    return get_ucd_record(code)->category;
+}
+
+int ucdn_get_bidi_class(uint32_t code)
+{
+    return get_ucd_record(code)->bidi_class;
+}
+
+int ucdn_get_mirrored(uint32_t code)
+{
+    return get_ucd_record(code)->mirrored;
+}
+
+int ucdn_get_script(uint32_t code)
+{
+    return get_ucd_record(code)->script;
+}
+
+int ucdn_get_linebreak_class(uint32_t code)
+{
+    return get_ucd_record(code)->linebreak_class;
+}
+
+int ucdn_get_resolved_linebreak_class(uint32_t code)
+{
+    const UCDRecord *record = get_ucd_record(code);
+
+    switch (record->linebreak_class)
+    {
+    case UCDN_LINEBREAK_CLASS_AI:
+    case UCDN_LINEBREAK_CLASS_SG:
+    case UCDN_LINEBREAK_CLASS_XX:
+        return UCDN_LINEBREAK_CLASS_AL;
+
+    case UCDN_LINEBREAK_CLASS_SA:
+        if (record->category == UCDN_GENERAL_CATEGORY_MC ||
+                record->category == UCDN_GENERAL_CATEGORY_MN)
+            return UCDN_LINEBREAK_CLASS_CM;
+        return UCDN_LINEBREAK_CLASS_AL;
+
+    case UCDN_LINEBREAK_CLASS_CJ:
+        return UCDN_LINEBREAK_CLASS_NS;
+
+    case UCDN_LINEBREAK_CLASS_CB:
+        return UCDN_LINEBREAK_CLASS_B2;
+
+    case UCDN_LINEBREAK_CLASS_NL:
+        return UCDN_LINEBREAK_CLASS_BK;
+
+    default:
+        return record->linebreak_class;
+    }
+}
+
+uint32_t ucdn_mirror(uint32_t code)
+{
+    MirrorPair mp = {0};
+    MirrorPair *res;
+
+    if (get_ucd_record(code)->mirrored == 0)
+        return code;
+
+    mp.from = code;
+    res = bsearch(&mp, mirror_pairs, BIDI_MIRROR_LEN, sizeof(MirrorPair),
+            compare_mp);
+
+    if (res == NULL)
+        return code;
+    else
+        return res->to;
+}
+
+uint32_t ucdn_paired_bracket(uint32_t code)
+{
+    BracketPair *res = search_bp(code);
+    if (res == NULL)
+        return code;
+    else
+        return res->to;
+}
+
+int ucdn_paired_bracket_type(uint32_t code)
+{
+    BracketPair *res = search_bp(code);
+    if (res == NULL)
+        return UCDN_BIDI_PAIRED_BRACKET_TYPE_NONE;
+    else
+        return res->type;
+}
+
+int ucdn_decompose(uint32_t code, uint32_t *a, uint32_t *b)
+{
+    const unsigned short *rec;
+    int len;
+
+    if (hangul_pair_decompose(code, a, b))
+        return 1;
+
+    rec = get_decomp_record(code);
+    len = rec[0] >> 8;
+
+    if ((rec[0] & 0xff) != 0 || len == 0)
+        return 0;
+
+    rec++;
+    *a = decode_utf16(&rec);
+    if (len > 1)
+        *b = decode_utf16(&rec);
+    else
+        *b = 0;
+
+    return 1;
+}
+
+int ucdn_compose(uint32_t *code, uint32_t a, uint32_t b)
+{
+    int l, r, index, indexi, offset;
+
+    if (hangul_pair_compose(code, a, b))
+        return 1;
+
+    l = get_comp_index(a, nfc_first);
+    r = get_comp_index(b, nfc_last);
+
+    if (l < 0 || r < 0)
+        return 0;
+
+    indexi = l * TOTAL_LAST + r;
+    index  = comp_index0[indexi >> (COMP_SHIFT1+COMP_SHIFT2)] << COMP_SHIFT1;
+    offset = (indexi >> COMP_SHIFT2) & ((1<<COMP_SHIFT1) - 1);
+    index  = comp_index1[index + offset] << COMP_SHIFT2;
+    offset = indexi & ((1<<COMP_SHIFT2) - 1);
+    *code  = comp_data[index + offset];
+
+    return *code != 0;
+}
+
+int ucdn_compat_decompose(uint32_t code, uint32_t *decomposed)
+{
+    int i, len;
+    const unsigned short *rec = get_decomp_record(code);
+    len = rec[0] >> 8;
+
+    if (len == 0)
+        return 0;
+
+    rec++;
+    for (i = 0; i < len; i++)
+        decomposed[i] = decode_utf16(&rec);
+
+    return len;
+}
diff --git a/src/share/native/sun/font/harfbuzz/hb-ucdn/ucdn.h b/src/share/native/sun/font/harfbuzz/hb-ucdn/ucdn.h
new file mode 100644
index 0000000..f694dc5
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ucdn/ucdn.h
@@ -0,0 +1,460 @@
+/*
+ * Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef UCDN_H
+#define UCDN_H
+
+
+
+#if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__)
+# define HB_BEGIN_VISIBILITY _Pragma ("GCC visibility push(hidden)")
+# define HB_END_VISIBILITY _Pragma ("GCC visibility pop")
+#else
+# define HB_BEGIN_VISIBILITY
+# define HB_END_VISIBILITY
+#endif
+#ifdef __cplusplus
+# define HB_BEGIN_HEADER  extern "C" { HB_BEGIN_VISIBILITY
+# define HB_END_HEADER  HB_END_VISIBILITY }
+#else
+# define HB_BEGIN_HEADER  HB_BEGIN_VISIBILITY
+# define HB_END_HEADER  HB_END_VISIBILITY
+#endif
+
+HB_BEGIN_HEADER
+
+#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
+
+
+#define UCDN_EAST_ASIAN_F 0
+#define UCDN_EAST_ASIAN_H 1
+#define UCDN_EAST_ASIAN_W 2
+#define UCDN_EAST_ASIAN_NA 3
+#define UCDN_EAST_ASIAN_A 4
+#define UCDN_EAST_ASIAN_N 5
+
+#define UCDN_SCRIPT_COMMON 0
+#define UCDN_SCRIPT_LATIN 1
+#define UCDN_SCRIPT_GREEK 2
+#define UCDN_SCRIPT_CYRILLIC 3
+#define UCDN_SCRIPT_ARMENIAN 4
+#define UCDN_SCRIPT_HEBREW 5
+#define UCDN_SCRIPT_ARABIC 6
+#define UCDN_SCRIPT_SYRIAC 7
+#define UCDN_SCRIPT_THAANA 8
+#define UCDN_SCRIPT_DEVANAGARI 9
+#define UCDN_SCRIPT_BENGALI 10
+#define UCDN_SCRIPT_GURMUKHI 11
+#define UCDN_SCRIPT_GUJARATI 12
+#define UCDN_SCRIPT_ORIYA 13
+#define UCDN_SCRIPT_TAMIL 14
+#define UCDN_SCRIPT_TELUGU 15
+#define UCDN_SCRIPT_KANNADA 16
+#define UCDN_SCRIPT_MALAYALAM 17
+#define UCDN_SCRIPT_SINHALA 18
+#define UCDN_SCRIPT_THAI 19
+#define UCDN_SCRIPT_LAO 20
+#define UCDN_SCRIPT_TIBETAN 21
+#define UCDN_SCRIPT_MYANMAR 22
+#define UCDN_SCRIPT_GEORGIAN 23
+#define UCDN_SCRIPT_HANGUL 24
+#define UCDN_SCRIPT_ETHIOPIC 25
+#define UCDN_SCRIPT_CHEROKEE 26
+#define UCDN_SCRIPT_CANADIAN_ABORIGINAL 27
+#define UCDN_SCRIPT_OGHAM 28
+#define UCDN_SCRIPT_RUNIC 29
+#define UCDN_SCRIPT_KHMER 30
+#define UCDN_SCRIPT_MONGOLIAN 31
+#define UCDN_SCRIPT_HIRAGANA 32
+#define UCDN_SCRIPT_KATAKANA 33
+#define UCDN_SCRIPT_BOPOMOFO 34
+#define UCDN_SCRIPT_HAN 35
+#define UCDN_SCRIPT_YI 36
+#define UCDN_SCRIPT_OLD_ITALIC 37
+#define UCDN_SCRIPT_GOTHIC 38
+#define UCDN_SCRIPT_DESERET 39
+#define UCDN_SCRIPT_INHERITED 40
+#define UCDN_SCRIPT_TAGALOG 41
+#define UCDN_SCRIPT_HANUNOO 42
+#define UCDN_SCRIPT_BUHID 43
+#define UCDN_SCRIPT_TAGBANWA 44
+#define UCDN_SCRIPT_LIMBU 45
+#define UCDN_SCRIPT_TAI_LE 46
+#define UCDN_SCRIPT_LINEAR_B 47
+#define UCDN_SCRIPT_UGARITIC 48
+#define UCDN_SCRIPT_SHAVIAN 49
+#define UCDN_SCRIPT_OSMANYA 50
+#define UCDN_SCRIPT_CYPRIOT 51
+#define UCDN_SCRIPT_BRAILLE 52
+#define UCDN_SCRIPT_BUGINESE 53
+#define UCDN_SCRIPT_COPTIC 54
+#define UCDN_SCRIPT_NEW_TAI_LUE 55
+#define UCDN_SCRIPT_GLAGOLITIC 56
+#define UCDN_SCRIPT_TIFINAGH 57
+#define UCDN_SCRIPT_SYLOTI_NAGRI 58
+#define UCDN_SCRIPT_OLD_PERSIAN 59
+#define UCDN_SCRIPT_KHAROSHTHI 60
+#define UCDN_SCRIPT_BALINESE 61
+#define UCDN_SCRIPT_CUNEIFORM 62
+#define UCDN_SCRIPT_PHOENICIAN 63
+#define UCDN_SCRIPT_PHAGS_PA 64
+#define UCDN_SCRIPT_NKO 65
+#define UCDN_SCRIPT_SUNDANESE 66
+#define UCDN_SCRIPT_LEPCHA 67
+#define UCDN_SCRIPT_OL_CHIKI 68
+#define UCDN_SCRIPT_VAI 69
+#define UCDN_SCRIPT_SAURASHTRA 70
+#define UCDN_SCRIPT_KAYAH_LI 71
+#define UCDN_SCRIPT_REJANG 72
+#define UCDN_SCRIPT_LYCIAN 73
+#define UCDN_SCRIPT_CARIAN 74
+#define UCDN_SCRIPT_LYDIAN 75
+#define UCDN_SCRIPT_CHAM 76
+#define UCDN_SCRIPT_TAI_THAM 77
+#define UCDN_SCRIPT_TAI_VIET 78
+#define UCDN_SCRIPT_AVESTAN 79
+#define UCDN_SCRIPT_EGYPTIAN_HIEROGLYPHS 80
+#define UCDN_SCRIPT_SAMARITAN 81
+#define UCDN_SCRIPT_LISU 82
+#define UCDN_SCRIPT_BAMUM 83
+#define UCDN_SCRIPT_JAVANESE 84
+#define UCDN_SCRIPT_MEETEI_MAYEK 85
+#define UCDN_SCRIPT_IMPERIAL_ARAMAIC 86
+#define UCDN_SCRIPT_OLD_SOUTH_ARABIAN 87
+#define UCDN_SCRIPT_INSCRIPTIONAL_PARTHIAN 88
+#define UCDN_SCRIPT_INSCRIPTIONAL_PAHLAVI 89
+#define UCDN_SCRIPT_OLD_TURKIC 90
+#define UCDN_SCRIPT_KAITHI 91
+#define UCDN_SCRIPT_BATAK 92
+#define UCDN_SCRIPT_BRAHMI 93
+#define UCDN_SCRIPT_MANDAIC 94
+#define UCDN_SCRIPT_CHAKMA 95
+#define UCDN_SCRIPT_MEROITIC_CURSIVE 96
+#define UCDN_SCRIPT_MEROITIC_HIEROGLYPHS 97
+#define UCDN_SCRIPT_MIAO 98
+#define UCDN_SCRIPT_SHARADA 99
+#define UCDN_SCRIPT_SORA_SOMPENG 100
+#define UCDN_SCRIPT_TAKRI 101
+#define UCDN_SCRIPT_UNKNOWN 102
+#define UCDN_SCRIPT_BASSA_VAH 103
+#define UCDN_SCRIPT_CAUCASIAN_ALBANIAN 104
+#define UCDN_SCRIPT_DUPLOYAN 105
+#define UCDN_SCRIPT_ELBASAN 106
+#define UCDN_SCRIPT_GRANTHA 107
+#define UCDN_SCRIPT_KHOJKI 108
+#define UCDN_SCRIPT_KHUDAWADI 109
+#define UCDN_SCRIPT_LINEAR_A 110
+#define UCDN_SCRIPT_MAHAJANI 111
+#define UCDN_SCRIPT_MANICHAEAN 112
+#define UCDN_SCRIPT_MENDE_KIKAKUI 113
+#define UCDN_SCRIPT_MODI 114
+#define UCDN_SCRIPT_MRO 115
+#define UCDN_SCRIPT_NABATAEAN 116
+#define UCDN_SCRIPT_OLD_NORTH_ARABIAN 117
+#define UCDN_SCRIPT_OLD_PERMIC 118
+#define UCDN_SCRIPT_PAHAWH_HMONG 119
+#define UCDN_SCRIPT_PALMYRENE 120
+#define UCDN_SCRIPT_PAU_CIN_HAU 121
+#define UCDN_SCRIPT_PSALTER_PAHLAVI 122
+#define UCDN_SCRIPT_SIDDHAM 123
+#define UCDN_SCRIPT_TIRHUTA 124
+#define UCDN_SCRIPT_WARANG_CITI 125
+#define UCDN_SCRIPT_AHOM 126
+#define UCDN_SCRIPT_ANATOLIAN_HIEROGLYPHS 127
+#define UCDN_SCRIPT_HATRAN 128
+#define UCDN_SCRIPT_MULTANI 129
+#define UCDN_SCRIPT_OLD_HUNGARIAN 130
+#define UCDN_SCRIPT_SIGNWRITING 131
+#define UCDN_SCRIPT_ADLAM 132
+#define UCDN_SCRIPT_BHAIKSUKI 133
+#define UCDN_SCRIPT_MARCHEN 134
+#define UCDN_SCRIPT_NEWA 135
+#define UCDN_SCRIPT_OSAGE 136
+#define UCDN_SCRIPT_TANGUT 137
+
+#define UCDN_LINEBREAK_CLASS_OP 0
+#define UCDN_LINEBREAK_CLASS_CL 1
+#define UCDN_LINEBREAK_CLASS_CP 2
+#define UCDN_LINEBREAK_CLASS_QU 3
+#define UCDN_LINEBREAK_CLASS_GL 4
+#define UCDN_LINEBREAK_CLASS_NS 5
+#define UCDN_LINEBREAK_CLASS_EX 6
+#define UCDN_LINEBREAK_CLASS_SY 7
+#define UCDN_LINEBREAK_CLASS_IS 8
+#define UCDN_LINEBREAK_CLASS_PR 9
+#define UCDN_LINEBREAK_CLASS_PO 10
+#define UCDN_LINEBREAK_CLASS_NU 11
+#define UCDN_LINEBREAK_CLASS_AL 12
+#define UCDN_LINEBREAK_CLASS_HL 13
+#define UCDN_LINEBREAK_CLASS_ID 14
+#define UCDN_LINEBREAK_CLASS_IN 15
+#define UCDN_LINEBREAK_CLASS_HY 16
+#define UCDN_LINEBREAK_CLASS_BA 17
+#define UCDN_LINEBREAK_CLASS_BB 18
+#define UCDN_LINEBREAK_CLASS_B2 19
+#define UCDN_LINEBREAK_CLASS_ZW 20
+#define UCDN_LINEBREAK_CLASS_CM 21
+#define UCDN_LINEBREAK_CLASS_WJ 22
+#define UCDN_LINEBREAK_CLASS_H2 23
+#define UCDN_LINEBREAK_CLASS_H3 24
+#define UCDN_LINEBREAK_CLASS_JL 25
+#define UCDN_LINEBREAK_CLASS_JV 26
+#define UCDN_LINEBREAK_CLASS_JT 27
+#define UCDN_LINEBREAK_CLASS_RI 28
+#define UCDN_LINEBREAK_CLASS_AI 29
+#define UCDN_LINEBREAK_CLASS_BK 30
+#define UCDN_LINEBREAK_CLASS_CB 31
+#define UCDN_LINEBREAK_CLASS_CJ 32
+#define UCDN_LINEBREAK_CLASS_CR 33
+#define UCDN_LINEBREAK_CLASS_LF 34
+#define UCDN_LINEBREAK_CLASS_NL 35
+#define UCDN_LINEBREAK_CLASS_SA 36
+#define UCDN_LINEBREAK_CLASS_SG 37
+#define UCDN_LINEBREAK_CLASS_SP 38
+#define UCDN_LINEBREAK_CLASS_XX 39
+
+#define UCDN_GENERAL_CATEGORY_CC 0
+#define UCDN_GENERAL_CATEGORY_CF 1
+#define UCDN_GENERAL_CATEGORY_CN 2
+#define UCDN_GENERAL_CATEGORY_CO 3
+#define UCDN_GENERAL_CATEGORY_CS 4
+#define UCDN_GENERAL_CATEGORY_LL 5
+#define UCDN_GENERAL_CATEGORY_LM 6
+#define UCDN_GENERAL_CATEGORY_LO 7
+#define UCDN_GENERAL_CATEGORY_LT 8
+#define UCDN_GENERAL_CATEGORY_LU 9
+#define UCDN_GENERAL_CATEGORY_MC 10
+#define UCDN_GENERAL_CATEGORY_ME 11
+#define UCDN_GENERAL_CATEGORY_MN 12
+#define UCDN_GENERAL_CATEGORY_ND 13
+#define UCDN_GENERAL_CATEGORY_NL 14
+#define UCDN_GENERAL_CATEGORY_NO 15
+#define UCDN_GENERAL_CATEGORY_PC 16
+#define UCDN_GENERAL_CATEGORY_PD 17
+#define UCDN_GENERAL_CATEGORY_PE 18
+#define UCDN_GENERAL_CATEGORY_PF 19
+#define UCDN_GENERAL_CATEGORY_PI 20
+#define UCDN_GENERAL_CATEGORY_PO 21
+#define UCDN_GENERAL_CATEGORY_PS 22
+#define UCDN_GENERAL_CATEGORY_SC 23
+#define UCDN_GENERAL_CATEGORY_SK 24
+#define UCDN_GENERAL_CATEGORY_SM 25
+#define UCDN_GENERAL_CATEGORY_SO 26
+#define UCDN_GENERAL_CATEGORY_ZL 27
+#define UCDN_GENERAL_CATEGORY_ZP 28
+#define UCDN_GENERAL_CATEGORY_ZS 29
+
+#define UCDN_BIDI_CLASS_L 0
+#define UCDN_BIDI_CLASS_LRE 1
+#define UCDN_BIDI_CLASS_LRO 2
+#define UCDN_BIDI_CLASS_R 3
+#define UCDN_BIDI_CLASS_AL 4
+#define UCDN_BIDI_CLASS_RLE 5
+#define UCDN_BIDI_CLASS_RLO 6
+#define UCDN_BIDI_CLASS_PDF 7
+#define UCDN_BIDI_CLASS_EN 8
+#define UCDN_BIDI_CLASS_ES 9
+#define UCDN_BIDI_CLASS_ET 10
+#define UCDN_BIDI_CLASS_AN 11
+#define UCDN_BIDI_CLASS_CS 12
+#define UCDN_BIDI_CLASS_NSM 13
+#define UCDN_BIDI_CLASS_BN 14
+#define UCDN_BIDI_CLASS_B 15
+#define UCDN_BIDI_CLASS_S 16
+#define UCDN_BIDI_CLASS_WS 17
+#define UCDN_BIDI_CLASS_ON 18
+#define UCDN_BIDI_CLASS_LRI 19
+#define UCDN_BIDI_CLASS_RLI 20
+#define UCDN_BIDI_CLASS_FSI 21
+#define UCDN_BIDI_CLASS_PDI 22
+
+#define UCDN_BIDI_PAIRED_BRACKET_TYPE_OPEN 0
+#define UCDN_BIDI_PAIRED_BRACKET_TYPE_CLOSE 1
+#define UCDN_BIDI_PAIRED_BRACKET_TYPE_NONE 2
+
+/**
+ * Return version of the Unicode database.
+ *
+ * @return Unicode database version
+ */
+const char *ucdn_get_unicode_version(void);
+
+/**
+ * Get combining class of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return combining class value, as defined in UAX#44
+ */
+int ucdn_get_combining_class(uint32_t code);
+
+/**
+ * Get east-asian width of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return value according to UCDN_EAST_ASIAN_* and as defined in UAX#11.
+ */
+int ucdn_get_east_asian_width(uint32_t code);
+
+/**
+ * Get general category of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return value according to UCDN_GENERAL_CATEGORY_* and as defined in
+ * UAX#44.
+ */
+int ucdn_get_general_category(uint32_t code);
+
+/**
+ * Get bidirectional class of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return value according to UCDN_BIDI_CLASS_* and as defined in UAX#44.
+ */
+int ucdn_get_bidi_class(uint32_t code);
+
+/**
+ * Get script of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return value according to UCDN_SCRIPT_* and as defined in UAX#24.
+ */
+int ucdn_get_script(uint32_t code);
+
+/**
+ * Get unresolved linebreak class of a codepoint. This does not take
+ * rule LB1 of UAX#14 into account. See ucdn_get_resolved_linebreak_class()
+ * for resolved linebreak classes.
+ *
+ * @param code Unicode codepoint
+ * @return value according to UCDN_LINEBREAK_* and as defined in UAX#14.
+ */
+int ucdn_get_linebreak_class(uint32_t code);
+
+/**
+ * Get resolved linebreak class of a codepoint. This resolves characters
+ * in the AI, SG, XX, SA and CJ classes according to rule LB1 of UAX#14.
+ * In addition the CB class is resolved as the equivalent B2 class and
+ * the NL class is resolved as the equivalent BK class.
+ *
+ * @param code Unicode codepoint
+ * @return value according to UCDN_LINEBREAK_* and as defined in UAX#14.
+ */
+int ucdn_get_resolved_linebreak_class(uint32_t code);
+
+/**
+ * Check if codepoint can be mirrored.
+ *
+ * @param code Unicode codepoint
+ * @return 1 if mirrored character exists, otherwise 0
+ */
+int ucdn_get_mirrored(uint32_t code);
+
+/**
+ * Mirror a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return mirrored codepoint or the original codepoint if no
+ * mirrored character exists
+ */
+uint32_t ucdn_mirror(uint32_t code);
+
+/**
+ * Get paired bracket for a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return paired bracket codepoint or the original codepoint if no
+ * paired bracket character exists
+ */
+uint32_t ucdn_paired_bracket(uint32_t code);
+
+/**
+ * Get paired bracket type for a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return value according to UCDN_BIDI_PAIRED_BRACKET_TYPE_* and as defined
+ * in UAX#9.
+ *
+ */
+int ucdn_paired_bracket_type(uint32_t code);
+
+/**
+ * Pairwise canonical decomposition of a codepoint. This includes
+ * Hangul Jamo decomposition (see chapter 3.12 of the Unicode core
+ * specification).
+ *
+ * Hangul is decomposed into L and V jamos for LV forms, and an
+ * LV precomposed syllable and a T jamo for LVT forms.
+ *
+ * @param code Unicode codepoint
+ * @param a filled with first codepoint of decomposition
+ * @param b filled with second codepoint of decomposition, or 0
+ * @return success
+ */
+int ucdn_decompose(uint32_t code, uint32_t *a, uint32_t *b);
+
+/**
+ * Compatibility decomposition of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @param decomposed filled with decomposition, must be able to hold 18
+ * characters
+ * @return length of decomposition or 0 in case none exists
+ */
+int ucdn_compat_decompose(uint32_t code, uint32_t *decomposed);
+
+/**
+ * Pairwise canonical composition of two codepoints. This includes
+ * Hangul Jamo composition (see chapter 3.12 of the Unicode core
+ * specification).
+ *
+ * Hangul composition expects either L and V jamos, or an LV
+ * precomposed syllable and a T jamo. This is exactly the inverse
+ * of pairwise Hangul decomposition.
+ *
+ * @param code filled with composition
+ * @param a first codepoint
+ * @param b second codepoint
+ * @return success
+ */
+int ucdn_compose(uint32_t *code, uint32_t a, uint32_t b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/share/native/sun/font/harfbuzz/hb-ucdn/unicodedata_db.h b/src/share/native/sun/font/harfbuzz/hb-ucdn/unicodedata_db.h
new file mode 100644
index 0000000..034511b
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-ucdn/unicodedata_db.h
@@ -0,0 +1,5514 @@
+/* this file was generated by makeunicodedata.py 3.2 */
+
+#define UNIDATA_VERSION "9.0.0"
+/* a list of unique database records */
+static const UCDRecord ucd_records[] = {
+    {2, 0, 18, 0, 5, 102, 41},
+    {0, 0, 14, 0, 5, 0, 21},
+    {0, 0, 16, 0, 5, 0, 17},
+    {0, 0, 15, 0, 5, 0, 35},
+    {0, 0, 16, 0, 5, 0, 30},
+    {0, 0, 17, 0, 5, 0, 30},
+    {0, 0, 15, 0, 5, 0, 33},
+    {0, 0, 15, 0, 5, 0, 21},
+    {0, 0, 16, 0, 5, 0, 21},
+    {29, 0, 17, 0, 3, 0, 40},
+    {21, 0, 18, 0, 3, 0, 6},
+    {21, 0, 18, 0, 3, 0, 3},
+    {21, 0, 10, 0, 3, 0, 12},
+    {23, 0, 10, 0, 3, 0, 9},
+    {21, 0, 10, 0, 3, 0, 10},
+    {21, 0, 18, 0, 3, 0, 12},
+    {22, 0, 18, 1, 3, 0, 0},
+    {18, 0, 18, 1, 3, 0, 2},
+    {25, 0, 9, 0, 3, 0, 9},
+    {21, 0, 12, 0, 3, 0, 8},
+    {17, 0, 9, 0, 3, 0, 16},
+    {21, 0, 12, 0, 3, 0, 7},
+    {13, 0, 8, 0, 3, 0, 11},
+    {21, 0, 18, 0, 3, 0, 8},
+    {25, 0, 18, 1, 3, 0, 12},
+    {25, 0, 18, 0, 3, 0, 12},
+    {9, 0, 0, 0, 3, 1, 12},
+    {21, 0, 18, 0, 3, 0, 9},
+    {24, 0, 18, 0, 3, 0, 12},
+    {16, 0, 18, 0, 3, 0, 12},
+    {5, 0, 0, 0, 3, 1, 12},
+    {25, 0, 18, 0, 3, 0, 17},
+    {18, 0, 18, 1, 3, 0, 1},
+    {0, 0, 15, 0, 5, 0, 36},
+    {29, 0, 12, 0, 5, 0, 4},
+    {21, 0, 18, 0, 4, 0, 0},
+    {23, 0, 10, 0, 3, 0, 10},
+    {23, 0, 10, 0, 4, 0, 9},
+    {26, 0, 18, 0, 3, 0, 12},
+    {21, 0, 18, 0, 4, 0, 29},
+    {24, 0, 18, 0, 4, 0, 29},
+    {26, 0, 18, 0, 5, 0, 12},
+    {7, 0, 0, 0, 4, 1, 29},
+    {20, 0, 18, 1, 5, 0, 3},
+    {1, 0, 14, 0, 4, 0, 17},
+    {26, 0, 18, 0, 4, 0, 12},
+    {26, 0, 10, 0, 4, 0, 10},
+    {25, 0, 10, 0, 4, 0, 9},
+    {15, 0, 8, 0, 4, 0, 29},
+    {24, 0, 18, 0, 4, 0, 18},
+    {5, 0, 0, 0, 5, 0, 12},
+    {19, 0, 18, 1, 5, 0, 3},
+    {15, 0, 18, 0, 4, 0, 29},
+    {9, 0, 0, 0, 5, 1, 12},
+    {9, 0, 0, 0, 4, 1, 12},
+    {25, 0, 18, 0, 4, 0, 29},
+    {5, 0, 0, 0, 4, 1, 12},
+    {5, 0, 0, 0, 5, 1, 12},
+    {7, 0, 0, 0, 5, 1, 12},
+    {8, 0, 0, 0, 5, 1, 12},
+    {6, 0, 0, 0, 5, 1, 12},
+    {6, 0, 18, 0, 5, 0, 12},
+    {6, 0, 0, 0, 5, 0, 12},
+    {24, 0, 18, 0, 5, 0, 12},
+    {24, 0, 18, 0, 4, 0, 12},
+    {6, 0, 18, 0, 4, 0, 29},
+    {6, 0, 18, 0, 5, 0, 18},
+    {6, 0, 0, 0, 4, 0, 29},
+    {24, 0, 18, 0, 5, 34, 12},
+    {12, 230, 13, 0, 4, 40, 21},
+    {12, 232, 13, 0, 4, 40, 21},
+    {12, 220, 13, 0, 4, 40, 21},
+    {12, 216, 13, 0, 4, 40, 21},
+    {12, 202, 13, 0, 4, 40, 21},
+    {12, 1, 13, 0, 4, 40, 21},
+    {12, 240, 13, 0, 4, 40, 21},
+    {12, 0, 13, 0, 4, 40, 4},
+    {12, 233, 13, 0, 4, 40, 4},
+    {12, 234, 13, 0, 4, 40, 4},
+    {9, 0, 0, 0, 5, 2, 12},
+    {5, 0, 0, 0, 5, 2, 12},
+    {24, 0, 18, 0, 5, 2, 12},
+    {2, 0, 18, 0, 5, 102, 41},
+    {6, 0, 0, 0, 5, 2, 12},
+    {21, 0, 18, 0, 5, 0, 8},
+    {21, 0, 18, 0, 5, 0, 12},
+    {9, 0, 0, 0, 4, 2, 12},
+    {5, 0, 0, 0, 4, 2, 12},
+    {9, 0, 0, 0, 5, 54, 12},
+    {5, 0, 0, 0, 5, 54, 12},
+    {25, 0, 18, 0, 5, 2, 12},
+    {9, 0, 0, 0, 5, 3, 12},
+    {9, 0, 0, 0, 4, 3, 12},
+    {5, 0, 0, 0, 4, 3, 12},
+    {5, 0, 0, 0, 5, 3, 12},
+    {26, 0, 0, 0, 5, 3, 12},
+    {12, 230, 13, 0, 5, 3, 21},
+    {12, 230, 13, 0, 5, 40, 21},
+    {11, 0, 13, 0, 5, 3, 21},
+    {9, 0, 0, 0, 5, 4, 12},
+    {6, 0, 0, 0, 5, 4, 12},
+    {21, 0, 0, 0, 5, 4, 12},
+    {5, 0, 0, 0, 5, 4, 12},
+    {21, 0, 0, 0, 5, 0, 8},
+    {17, 0, 18, 0, 5, 4, 17},
+    {26, 0, 18, 0, 5, 4, 12},
+    {23, 0, 10, 0, 5, 4, 9},
+    {12, 220, 13, 0, 5, 5, 21},
+    {12, 230, 13, 0, 5, 5, 21},
+    {12, 222, 13, 0, 5, 5, 21},
+    {12, 228, 13, 0, 5, 5, 21},
+    {12, 10, 13, 0, 5, 5, 21},
+    {12, 11, 13, 0, 5, 5, 21},
+    {12, 12, 13, 0, 5, 5, 21},
+    {12, 13, 13, 0, 5, 5, 21},
+    {12, 14, 13, 0, 5, 5, 21},
+    {12, 15, 13, 0, 5, 5, 21},
+    {12, 16, 13, 0, 5, 5, 21},
+    {12, 17, 13, 0, 5, 5, 21},
+    {12, 18, 13, 0, 5, 5, 21},
+    {12, 19, 13, 0, 5, 5, 21},
+    {12, 20, 13, 0, 5, 5, 21},
+    {12, 21, 13, 0, 5, 5, 21},
+    {12, 22, 13, 0, 5, 5, 21},
+    {17, 0, 3, 0, 5, 5, 17},
+    {12, 23, 13, 0, 5, 5, 21},
+    {21, 0, 3, 0, 5, 5, 12},
+    {12, 24, 13, 0, 5, 5, 21},
+    {12, 25, 13, 0, 5, 5, 21},
+    {21, 0, 3, 0, 5, 5, 6},
+    {7, 0, 3, 0, 5, 5, 13},
+    {1, 0, 11, 0, 5, 6, 12},
+    {1, 0, 11, 0, 5, 0, 12},
+    {25, 0, 18, 0, 5, 6, 12},
+    {25, 0, 4, 0, 5, 6, 12},
+    {21, 0, 10, 0, 5, 6, 10},
+    {23, 0, 4, 0, 5, 6, 10},
+    {21, 0, 12, 0, 5, 0, 8},
+    {21, 0, 4, 0, 5, 6, 8},
+    {26, 0, 18, 0, 5, 6, 12},
+    {12, 230, 13, 0, 5, 6, 21},
+    {12, 30, 13, 0, 5, 6, 21},
+    {12, 31, 13, 0, 5, 6, 21},
+    {12, 32, 13, 0, 5, 6, 21},
+    {21, 0, 4, 0, 5, 0, 6},
+    {1, 0, 4, 0, 5, 0, 21},
+    {21, 0, 4, 0, 5, 6, 6},
+    {7, 0, 4, 0, 5, 6, 12},
+    {6, 0, 4, 0, 5, 0, 12},
+    {12, 27, 13, 0, 5, 40, 21},
+    {12, 28, 13, 0, 5, 40, 21},
+    {12, 29, 13, 0, 5, 40, 21},
+    {12, 30, 13, 0, 5, 40, 21},
+    {12, 31, 13, 0, 5, 40, 21},
+    {12, 32, 13, 0, 5, 40, 21},
+    {12, 33, 13, 0, 5, 40, 21},
+    {12, 34, 13, 0, 5, 40, 21},
+    {12, 220, 13, 0, 5, 40, 21},
+    {12, 220, 13, 0, 5, 6, 21},
+    {13, 0, 11, 0, 5, 6, 11},
+    {21, 0, 11, 0, 5, 6, 11},
+    {21, 0, 4, 0, 5, 6, 12},
+    {12, 35, 13, 0, 5, 40, 21},
+    {6, 0, 4, 0, 5, 6, 12},
+    {13, 0, 8, 0, 5, 6, 11},
+    {26, 0, 4, 0, 5, 6, 12},
+    {21, 0, 4, 0, 5, 7, 12},
+    {1, 0, 4, 0, 5, 7, 12},
+    {7, 0, 4, 0, 5, 7, 12},
+    {12, 36, 13, 0, 5, 7, 21},
+    {12, 230, 13, 0, 5, 7, 21},
+    {12, 220, 13, 0, 5, 7, 21},
+    {7, 0, 4, 0, 5, 8, 12},
+    {12, 0, 13, 0, 5, 8, 21},
+    {13, 0, 3, 0, 5, 65, 11},
+    {7, 0, 3, 0, 5, 65, 12},
+    {12, 230, 13, 0, 5, 65, 21},
+    {12, 220, 13, 0, 5, 65, 21},
+    {6, 0, 3, 0, 5, 65, 12},
+    {26, 0, 18, 0, 5, 65, 12},
+    {21, 0, 18, 0, 5, 65, 12},
+    {21, 0, 18, 0, 5, 65, 8},
+    {21, 0, 18, 0, 5, 65, 6},
+    {7, 0, 3, 0, 5, 81, 12},
+    {12, 230, 13, 0, 5, 81, 21},
+    {6, 0, 3, 0, 5, 81, 12},
+    {21, 0, 3, 0, 5, 81, 12},
+    {7, 0, 3, 0, 5, 94, 12},
+    {12, 220, 13, 0, 5, 94, 21},
+    {21, 0, 3, 0, 5, 94, 12},
+    {12, 27, 13, 0, 5, 6, 21},
+    {12, 28, 13, 0, 5, 6, 21},
+    {12, 29, 13, 0, 5, 6, 21},
+    {12, 0, 13, 0, 5, 9, 21},
+    {10, 0, 0, 0, 5, 9, 21},
+    {7, 0, 0, 0, 5, 9, 12},
+    {12, 7, 13, 0, 5, 9, 21},
+    {12, 9, 13, 0, 5, 9, 21},
+    {12, 230, 13, 0, 5, 9, 21},
+    {21, 0, 0, 0, 5, 0, 17},
+    {13, 0, 0, 0, 5, 9, 11},
+    {21, 0, 0, 0, 5, 9, 12},
+    {6, 0, 0, 0, 5, 9, 12},
+    {7, 0, 0, 0, 5, 10, 12},
+    {12, 0, 13, 0, 5, 10, 21},
+    {10, 0, 0, 0, 5, 10, 21},
+    {12, 7, 13, 0, 5, 10, 21},
+    {12, 9, 13, 0, 5, 10, 21},
+    {13, 0, 0, 0, 5, 10, 11},
+    {23, 0, 10, 0, 5, 10, 10},
+    {15, 0, 0, 0, 5, 10, 12},
+    {15, 0, 0, 0, 5, 10, 10},
+    {26, 0, 0, 0, 5, 10, 12},
+    {23, 0, 10, 0, 5, 10, 9},
+    {12, 0, 13, 0, 5, 11, 21},
+    {10, 0, 0, 0, 5, 11, 21},
+    {7, 0, 0, 0, 5, 11, 12},
+    {12, 7, 13, 0, 5, 11, 21},
+    {12, 9, 13, 0, 5, 11, 21},
+    {13, 0, 0, 0, 5, 11, 11},
+    {12, 0, 13, 0, 5, 12, 21},
+    {10, 0, 0, 0, 5, 12, 21},
+    {7, 0, 0, 0, 5, 12, 12},
+    {12, 7, 13, 0, 5, 12, 21},
+    {12, 9, 13, 0, 5, 12, 21},
+    {13, 0, 0, 0, 5, 12, 11},
+    {21, 0, 0, 0, 5, 12, 12},
+    {23, 0, 10, 0, 5, 12, 9},
+    {12, 0, 13, 0, 5, 13, 21},
+    {10, 0, 0, 0, 5, 13, 21},
+    {7, 0, 0, 0, 5, 13, 12},
+    {12, 7, 13, 0, 5, 13, 21},
+    {12, 9, 13, 0, 5, 13, 21},
+    {13, 0, 0, 0, 5, 13, 11},
+    {26, 0, 0, 0, 5, 13, 12},
+    {15, 0, 0, 0, 5, 13, 12},
+    {12, 0, 13, 0, 5, 14, 21},
+    {7, 0, 0, 0, 5, 14, 12},
+    {10, 0, 0, 0, 5, 14, 21},
+    {12, 9, 13, 0, 5, 14, 21},
+    {13, 0, 0, 0, 5, 14, 11},
+    {15, 0, 0, 0, 5, 14, 12},
+    {26, 0, 18, 0, 5, 14, 12},
+    {23, 0, 10, 0, 5, 14, 9},
+    {12, 0, 13, 0, 5, 15, 21},
+    {10, 0, 0, 0, 5, 15, 21},
+    {7, 0, 0, 0, 5, 15, 12},
+    {12, 9, 13, 0, 5, 15, 21},
+    {12, 84, 13, 0, 5, 15, 21},
+    {12, 91, 13, 0, 5, 15, 21},
+    {13, 0, 0, 0, 5, 15, 11},
+    {15, 0, 18, 0, 5, 15, 12},
+    {26, 0, 0, 0, 5, 15, 12},
+    {7, 0, 0, 0, 5, 16, 12},
+    {12, 0, 13, 0, 5, 16, 21},
+    {10, 0, 0, 0, 5, 16, 21},
+    {12, 7, 13, 0, 5, 16, 21},
+    {12, 0, 0, 0, 5, 16, 21},
+    {12, 9, 13, 0, 5, 16, 21},
+    {13, 0, 0, 0, 5, 16, 11},
+    {12, 0, 13, 0, 5, 17, 21},
+    {10, 0, 0, 0, 5, 17, 21},
+    {7, 0, 0, 0, 5, 17, 12},
+    {12, 9, 13, 0, 5, 17, 21},
+    {26, 0, 0, 0, 5, 17, 12},
+    {15, 0, 0, 0, 5, 17, 12},
+    {13, 0, 0, 0, 5, 17, 11},
+    {26, 0, 0, 0, 5, 17, 10},
+    {10, 0, 0, 0, 5, 18, 21},
+    {7, 0, 0, 0, 5, 18, 12},
+    {12, 9, 13, 0, 5, 18, 21},
+    {12, 0, 13, 0, 5, 18, 21},
+    {13, 0, 0, 0, 5, 18, 11},
+    {21, 0, 0, 0, 5, 18, 12},
+    {7, 0, 0, 0, 5, 19, 38},
+    {12, 0, 13, 0, 5, 19, 38},
+    {12, 103, 13, 0, 5, 19, 38},
+    {12, 9, 13, 0, 5, 19, 38},
+    {23, 0, 10, 0, 5, 0, 9},
+    {6, 0, 0, 0, 5, 19, 38},
+    {12, 107, 13, 0, 5, 19, 38},
+    {21, 0, 0, 0, 5, 19, 12},
+    {13, 0, 0, 0, 5, 19, 11},
+    {21, 0, 0, 0, 5, 19, 17},
+    {7, 0, 0, 0, 5, 20, 38},
+    {12, 0, 13, 0, 5, 20, 38},
+    {12, 118, 13, 0, 5, 20, 38},
+    {6, 0, 0, 0, 5, 20, 38},
+    {12, 122, 13, 0, 5, 20, 38},
+    {13, 0, 0, 0, 5, 20, 11},
+    {7, 0, 0, 0, 5, 21, 12},
+    {26, 0, 0, 0, 5, 21, 18},
+    {21, 0, 0, 0, 5, 21, 18},
+    {21, 0, 0, 0, 5, 21, 12},
+    {21, 0, 0, 0, 5, 21, 4},
+    {21, 0, 0, 0, 5, 21, 17},
+    {21, 0, 0, 0, 5, 21, 6},
+    {26, 0, 0, 0, 5, 21, 12},
+    {12, 220, 13, 0, 5, 21, 21},
+    {13, 0, 0, 0, 5, 21, 11},
+    {15, 0, 0, 0, 5, 21, 12},
+    {26, 0, 0, 0, 5, 21, 17},
+    {12, 216, 13, 0, 5, 21, 21},
+    {22, 0, 18, 1, 5, 21, 0},
+    {18, 0, 18, 1, 5, 21, 1},
+    {10, 0, 0, 0, 5, 21, 21},
+    {12, 129, 13, 0, 5, 21, 21},
+    {12, 130, 13, 0, 5, 21, 21},
+    {12, 0, 13, 0, 5, 21, 21},
+    {12, 132, 13, 0, 5, 21, 21},
+    {10, 0, 0, 0, 5, 21, 17},
+    {12, 230, 13, 0, 5, 21, 21},
+    {12, 9, 13, 0, 5, 21, 21},
+    {26, 0, 0, 0, 5, 0, 12},
+    {7, 0, 0, 0, 5, 22, 38},
+    {10, 0, 0, 0, 5, 22, 38},
+    {12, 0, 13, 0, 5, 22, 38},
+    {12, 7, 13, 0, 5, 22, 38},
+    {12, 9, 13, 0, 5, 22, 38},
+    {13, 0, 0, 0, 5, 22, 11},
+    {21, 0, 0, 0, 5, 22, 17},
+    {21, 0, 0, 0, 5, 22, 12},
+    {12, 220, 13, 0, 5, 22, 38},
+    {26, 0, 0, 0, 5, 22, 38},
+    {9, 0, 0, 0, 5, 23, 12},
+    {7, 0, 0, 0, 5, 23, 12},
+    {21, 0, 0, 0, 5, 0, 12},
+    {6, 0, 0, 0, 5, 23, 12},
+    {7, 0, 0, 0, 2, 24, 25},
+    {7, 0, 0, 0, 5, 24, 26},
+    {7, 0, 0, 0, 5, 24, 27},
+    {7, 0, 0, 0, 5, 25, 12},
+    {12, 230, 13, 0, 5, 25, 21},
+    {21, 0, 0, 0, 5, 25, 12},
+    {21, 0, 0, 0, 5, 25, 17},
+    {15, 0, 0, 0, 5, 25, 12},
+    {26, 0, 18, 0, 5, 25, 12},
+    {9, 0, 0, 0, 5, 26, 12},
+    {5, 0, 0, 0, 5, 26, 12},
+    {17, 0, 18, 0, 5, 27, 17},
+    {7, 0, 0, 0, 5, 27, 12},
+    {21, 0, 0, 0, 5, 27, 12},
+    {29, 0, 17, 0, 5, 28, 17},
+    {7, 0, 0, 0, 5, 28, 12},
+    {22, 0, 18, 1, 5, 28, 0},
+    {18, 0, 18, 1, 5, 28, 1},
+    {7, 0, 0, 0, 5, 29, 12},
+    {14, 0, 0, 0, 5, 29, 12},
+    {7, 0, 0, 0, 5, 41, 12},
+    {12, 0, 13, 0, 5, 41, 21},
+    {12, 9, 13, 0, 5, 41, 21},
+    {7, 0, 0, 0, 5, 42, 12},
+    {12, 0, 13, 0, 5, 42, 21},
+    {12, 9, 13, 0, 5, 42, 21},
+    {7, 0, 0, 0, 5, 43, 12},
+    {12, 0, 13, 0, 5, 43, 21},
+    {7, 0, 0, 0, 5, 44, 12},
+    {12, 0, 13, 0, 5, 44, 21},
+    {7, 0, 0, 0, 5, 30, 38},
+    {12, 0, 13, 0, 5, 30, 38},
+    {10, 0, 0, 0, 5, 30, 38},
+    {12, 9, 13, 0, 5, 30, 38},
+    {21, 0, 0, 0, 5, 30, 17},
+    {21, 0, 0, 0, 5, 30, 5},
+    {6, 0, 0, 0, 5, 30, 38},
+    {21, 0, 0, 0, 5, 30, 12},
+    {23, 0, 10, 0, 5, 30, 9},
+    {12, 230, 13, 0, 5, 30, 38},
+    {13, 0, 0, 0, 5, 30, 11},
+    {15, 0, 18, 0, 5, 30, 12},
+    {21, 0, 18, 0, 5, 31, 12},
+    {21, 0, 18, 0, 5, 0, 6},
+    {21, 0, 18, 0, 5, 31, 17},
+    {21, 0, 18, 0, 5, 0, 17},
+    {17, 0, 18, 0, 5, 31, 18},
+    {21, 0, 18, 0, 5, 31, 6},
+    {12, 0, 13, 0, 5, 31, 21},
+    {1, 0, 14, 0, 5, 31, 4},
+    {13, 0, 0, 0, 5, 31, 11},
+    {7, 0, 0, 0, 5, 31, 12},
+    {6, 0, 0, 0, 5, 31, 12},
+    {12, 228, 13, 0, 5, 31, 21},
+    {7, 0, 0, 0, 5, 45, 12},
+    {12, 0, 13, 0, 5, 45, 21},
+    {10, 0, 0, 0, 5, 45, 21},
+    {12, 222, 13, 0, 5, 45, 21},
+    {12, 230, 13, 0, 5, 45, 21},
+    {12, 220, 13, 0, 5, 45, 21},
+    {26, 0, 18, 0, 5, 45, 12},
+    {21, 0, 18, 0, 5, 45, 6},
+    {13, 0, 0, 0, 5, 45, 11},
+    {7, 0, 0, 0, 5, 46, 38},
+    {7, 0, 0, 0, 5, 55, 38},
+    {13, 0, 0, 0, 5, 55, 11},
+    {15, 0, 0, 0, 5, 55, 38},
+    {26, 0, 18, 0, 5, 55, 38},
+    {26, 0, 18, 0, 5, 30, 12},
+    {7, 0, 0, 0, 5, 53, 12},
+    {12, 230, 13, 0, 5, 53, 21},
+    {12, 220, 13, 0, 5, 53, 21},
+    {10, 0, 0, 0, 5, 53, 21},
+    {12, 0, 13, 0, 5, 53, 21},
+    {21, 0, 0, 0, 5, 53, 12},
+    {7, 0, 0, 0, 5, 77, 38},
+    {10, 0, 0, 0, 5, 77, 38},
+    {12, 0, 13, 0, 5, 77, 38},
+    {12, 9, 13, 0, 5, 77, 38},
+    {12, 230, 13, 0, 5, 77, 38},
+    {12, 220, 13, 0, 5, 77, 21},
+    {13, 0, 0, 0, 5, 77, 11},
+    {21, 0, 0, 0, 5, 77, 38},
+    {6, 0, 0, 0, 5, 77, 38},
+    {11, 0, 13, 0, 5, 40, 21},
+    {12, 0, 13, 0, 5, 61, 21},
+    {10, 0, 0, 0, 5, 61, 21},
+    {7, 0, 0, 0, 5, 61, 12},
+    {12, 7, 13, 0, 5, 61, 21},
+    {10, 9, 0, 0, 5, 61, 21},
+    {13, 0, 0, 0, 5, 61, 11},
+    {21, 0, 0, 0, 5, 61, 17},
+    {21, 0, 0, 0, 5, 61, 12},
+    {26, 0, 0, 0, 5, 61, 12},
+    {12, 230, 13, 0, 5, 61, 21},
+    {12, 220, 13, 0, 5, 61, 21},
+    {12, 0, 13, 0, 5, 66, 21},
+    {10, 0, 0, 0, 5, 66, 21},
+    {7, 0, 0, 0, 5, 66, 12},
+    {10, 9, 0, 0, 5, 66, 21},
+    {12, 9, 13, 0, 5, 66, 21},
+    {13, 0, 0, 0, 5, 66, 11},
+    {7, 0, 0, 0, 5, 92, 12},
+    {12, 7, 13, 0, 5, 92, 21},
+    {10, 0, 0, 0, 5, 92, 21},
+    {12, 0, 13, 0, 5, 92, 21},
+    {10, 9, 0, 0, 5, 92, 21},
+    {21, 0, 0, 0, 5, 92, 12},
+    {7, 0, 0, 0, 5, 67, 12},
+    {10, 0, 0, 0, 5, 67, 21},
+    {12, 0, 13, 0, 5, 67, 21},
+    {12, 7, 13, 0, 5, 67, 21},
+    {21, 0, 0, 0, 5, 67, 17},
+    {13, 0, 0, 0, 5, 67, 11},
+    {13, 0, 0, 0, 5, 68, 11},
+    {7, 0, 0, 0, 5, 68, 12},
+    {6, 0, 0, 0, 5, 68, 12},
+    {21, 0, 0, 0, 5, 68, 17},
+    {21, 0, 0, 0, 5, 66, 12},
+    {12, 1, 13, 0, 5, 40, 21},
+    {10, 0, 0, 0, 5, 0, 21},
+    {7, 0, 0, 0, 5, 0, 12},
+    {6, 0, 0, 0, 5, 3, 12},
+    {12, 234, 13, 0, 5, 40, 21},
+    {12, 214, 13, 0, 5, 40, 21},
+    {12, 202, 13, 0, 5, 40, 21},
+    {12, 233, 13, 0, 5, 40, 21},
+    {8, 0, 0, 0, 5, 2, 12},
+    {24, 0, 18, 0, 5, 2, 18},
+    {29, 0, 17, 0, 5, 0, 17},
+    {29, 0, 17, 0, 5, 0, 4},
+    {1, 0, 14, 0, 5, 0, 20},
+    {1, 0, 14, 0, 5, 40, 21},
+    {1, 0, 14, 0, 5, 40, 41},
+    {1, 0, 0, 0, 5, 0, 21},
+    {1, 0, 3, 0, 5, 0, 21},
+    {17, 0, 18, 0, 4, 0, 17},
+    {17, 0, 18, 0, 5, 0, 4},
+    {17, 0, 18, 0, 5, 0, 17},
+    {17, 0, 18, 0, 4, 0, 19},
+    {17, 0, 18, 0, 4, 0, 29},
+    {20, 0, 18, 0, 4, 0, 3},
+    {19, 0, 18, 0, 4, 0, 3},
+    {22, 0, 18, 0, 5, 0, 0},
+    {20, 0, 18, 0, 5, 0, 3},
+    {21, 0, 18, 0, 4, 0, 12},
+    {21, 0, 18, 0, 4, 0, 15},
+    {21, 0, 18, 0, 4, 0, 17},
+    {27, 0, 17, 0, 5, 0, 30},
+    {28, 0, 15, 0, 5, 0, 30},
+    {1, 0, 1, 0, 5, 0, 21},
+    {1, 0, 5, 0, 5, 0, 21},
+    {1, 0, 7, 0, 5, 0, 21},
+    {1, 0, 2, 0, 5, 0, 21},
+    {1, 0, 6, 0, 5, 0, 21},
+    {21, 0, 10, 0, 4, 0, 10},
+    {21, 0, 10, 0, 5, 0, 10},
+    {21, 0, 18, 0, 4, 0, 10},
+    {21, 0, 18, 0, 5, 0, 10},
+    {21, 0, 18, 0, 5, 0, 5},
+    {16, 0, 18, 0, 5, 0, 12},
+    {25, 0, 12, 0, 5, 0, 8},
+    {22, 0, 18, 1, 5, 0, 0},
+    {18, 0, 18, 1, 5, 0, 1},
+    {25, 0, 18, 0, 5, 0, 12},
+    {1, 0, 14, 0, 5, 0, 22},
+    {1, 0, 14, 0, 5, 0, 12},
+    {1, 0, 19, 0, 5, 0, 21},
+    {1, 0, 20, 0, 5, 0, 21},
+    {1, 0, 21, 0, 5, 0, 21},
+    {1, 0, 22, 0, 5, 0, 21},
+    {1, 0, 14, 0, 5, 0, 21},
+    {15, 0, 8, 0, 5, 0, 12},
+    {25, 0, 9, 0, 5, 0, 12},
+    {6, 0, 0, 0, 4, 1, 29},
+    {23, 0, 10, 0, 5, 0, 10},
+    {23, 0, 10, 0, 1, 0, 9},
+    {2, 0, 18, 0, 5, 102, 9},
+    {9, 0, 0, 0, 5, 0, 12},
+    {26, 0, 18, 0, 4, 0, 10},
+    {26, 0, 18, 0, 4, 0, 29},
+    {5, 0, 0, 0, 4, 0, 29},
+    {26, 0, 18, 0, 4, 0, 9},
+    {9, 0, 0, 0, 4, 1, 29},
+    {26, 0, 10, 0, 5, 0, 12},
+    {25, 0, 18, 1, 5, 0, 12},
+    {15, 0, 18, 0, 5, 0, 12},
+    {15, 0, 18, 0, 4, 0, 12},
+    {15, 0, 18, 0, 5, 0, 29},
+    {14, 0, 0, 0, 4, 1, 29},
+    {14, 0, 0, 0, 5, 1, 12},
+    {25, 0, 18, 1, 4, 0, 29},
+    {25, 0, 9, 0, 5, 0, 9},
+    {25, 0, 10, 0, 5, 0, 9},
+    {25, 0, 18, 0, 5, 0, 15},
+    {26, 0, 18, 0, 2, 0, 14},
+    {22, 0, 18, 1, 2, 0, 0},
+    {18, 0, 18, 1, 2, 0, 1},
+    {26, 0, 18, 0, 2, 0, 12},
+    {26, 0, 18, 0, 5, 0, 14},
+    {26, 0, 0, 0, 4, 0, 29},
+    {26, 0, 18, 0, 5, 0, 29},
+    {25, 0, 18, 0, 2, 0, 12},
+    {26, 0, 18, 0, 4, 0, 14},
+    {26, 0, 18, 0, 5, 0, 41},
+    {26, 0, 18, 0, 4, 0, 41},
+    {26, 0, 18, 0, 2, 0, 41},
+    {26, 0, 18, 0, 2, 0, 29},
+    {26, 0, 18, 0, 5, 0, 3},
+    {26, 0, 18, 0, 5, 0, 6},
+    {26, 0, 0, 0, 5, 52, 12},
+    {9, 0, 0, 0, 5, 56, 12},
+    {5, 0, 0, 0, 5, 56, 12},
+    {26, 0, 18, 0, 5, 54, 12},
+    {12, 230, 13, 0, 5, 54, 21},
+    {21, 0, 18, 0, 5, 54, 6},
+    {21, 0, 18, 0, 5, 54, 17},
+    {15, 0, 18, 0, 5, 54, 12},
+    {5, 0, 0, 0, 5, 23, 12},
+    {7, 0, 0, 0, 5, 57, 12},
+    {6, 0, 0, 0, 5, 57, 12},
+    {21, 0, 0, 0, 5, 57, 17},
+    {12, 9, 13, 0, 5, 57, 21},
+    {21, 0, 18, 0, 5, 0, 3},
+    {21, 0, 18, 0, 5, 0, 0},
+    {17, 0, 18, 0, 5, 0, 12},
+    {17, 0, 18, 0, 5, 0, 19},
+    {26, 0, 18, 0, 2, 35, 14},
+    {29, 0, 17, 0, 0, 0, 17},
+    {21, 0, 18, 0, 2, 0, 1},
+    {21, 0, 18, 0, 2, 0, 14},
+    {6, 0, 0, 0, 2, 35, 5},
+    {7, 0, 0, 0, 2, 0, 14},
+    {14, 0, 0, 0, 2, 35, 14},
+    {17, 0, 18, 0, 2, 0, 5},
+    {22, 0, 18, 0, 2, 0, 0},
+    {18, 0, 18, 0, 2, 0, 1},
+    {12, 218, 13, 0, 2, 40, 21},
+    {12, 228, 13, 0, 2, 40, 21},
+    {12, 232, 13, 0, 2, 40, 21},
+    {12, 222, 13, 0, 2, 40, 21},
+    {10, 224, 0, 0, 2, 24, 21},
+    {17, 0, 18, 0, 2, 0, 14},
+    {6, 0, 0, 0, 2, 0, 14},
+    {6, 0, 0, 0, 2, 0, 21},
+    {7, 0, 0, 0, 2, 0, 5},
+    {7, 0, 0, 0, 2, 32, 32},
+    {7, 0, 0, 0, 2, 32, 14},
+    {12, 8, 13, 0, 2, 40, 21},
+    {24, 0, 18, 0, 2, 0, 5},
+    {6, 0, 0, 0, 2, 32, 5},
+    {7, 0, 0, 0, 2, 33, 32},
+    {7, 0, 0, 0, 2, 33, 14},
+    {21, 0, 18, 0, 2, 0, 5},
+    {6, 0, 0, 0, 2, 0, 32},
+    {6, 0, 0, 0, 2, 33, 5},
+    {7, 0, 0, 0, 2, 34, 14},
+    {7, 0, 0, 0, 2, 24, 14},
+    {26, 0, 0, 0, 2, 0, 14},
+    {15, 0, 0, 0, 2, 0, 14},
+    {26, 0, 0, 0, 2, 24, 14},
+    {26, 0, 18, 0, 2, 24, 14},
+    {15, 0, 0, 0, 4, 0, 29},
+    {15, 0, 18, 0, 2, 0, 14},
+    {26, 0, 0, 0, 2, 33, 14},
+    {7, 0, 0, 0, 2, 35, 14},
+    {2, 0, 18, 0, 2, 102, 14},
+    {7, 0, 0, 0, 2, 36, 14},
+    {6, 0, 0, 0, 2, 36, 5},
+    {26, 0, 18, 0, 2, 36, 14},
+    {7, 0, 0, 0, 5, 82, 12},
+    {6, 0, 0, 0, 5, 82, 12},
+    {21, 0, 0, 0, 5, 82, 17},
+    {7, 0, 0, 0, 5, 69, 12},
+    {6, 0, 0, 0, 5, 69, 12},
+    {21, 0, 18, 0, 5, 69, 17},
+    {21, 0, 18, 0, 5, 69, 6},
+    {13, 0, 0, 0, 5, 69, 11},
+    {7, 0, 0, 0, 5, 3, 12},
+    {21, 0, 18, 0, 5, 3, 12},
+    {6, 0, 18, 0, 5, 3, 12},
+    {7, 0, 0, 0, 5, 83, 12},
+    {14, 0, 0, 0, 5, 83, 12},
+    {12, 230, 13, 0, 5, 83, 21},
+    {21, 0, 0, 0, 5, 83, 12},
+    {21, 0, 0, 0, 5, 83, 17},
+    {24, 0, 0, 0, 5, 0, 12},
+    {7, 0, 0, 0, 5, 58, 12},
+    {12, 0, 13, 0, 5, 58, 21},
+    {12, 9, 13, 0, 5, 58, 21},
+    {10, 0, 0, 0, 5, 58, 21},
+    {26, 0, 18, 0, 5, 58, 12},
+    {15, 0, 0, 0, 5, 0, 12},
+    {7, 0, 0, 0, 5, 64, 12},
+    {21, 0, 18, 0, 5, 64, 18},
+    {21, 0, 18, 0, 5, 64, 6},
+    {10, 0, 0, 0, 5, 70, 21},
+    {7, 0, 0, 0, 5, 70, 12},
+    {12, 9, 13, 0, 5, 70, 21},
+    {12, 0, 13, 0, 5, 70, 21},
+    {21, 0, 0, 0, 5, 70, 17},
+    {13, 0, 0, 0, 5, 70, 11},
+    {21, 0, 0, 0, 5, 9, 18},
+    {13, 0, 0, 0, 5, 71, 11},
+    {7, 0, 0, 0, 5, 71, 12},
+    {12, 0, 13, 0, 5, 71, 21},
+    {12, 220, 13, 0, 5, 71, 21},
+    {21, 0, 0, 0, 5, 71, 17},
+    {7, 0, 0, 0, 5, 72, 12},
+    {12, 0, 13, 0, 5, 72, 21},
+    {10, 0, 0, 0, 5, 72, 21},
+    {10, 9, 0, 0, 5, 72, 21},
+    {21, 0, 0, 0, 5, 72, 12},
+    {12, 0, 13, 0, 5, 84, 21},
+    {10, 0, 0, 0, 5, 84, 21},
+    {7, 0, 0, 0, 5, 84, 12},
+    {12, 7, 13, 0, 5, 84, 21},
+    {10, 9, 0, 0, 5, 84, 21},
+    {21, 0, 0, 0, 5, 84, 12},
+    {21, 0, 0, 0, 5, 84, 17},
+    {13, 0, 0, 0, 5, 84, 11},
+    {6, 0, 0, 0, 5, 22, 38},
+    {7, 0, 0, 0, 5, 76, 12},
+    {12, 0, 13, 0, 5, 76, 21},
+    {10, 0, 0, 0, 5, 76, 21},
+    {13, 0, 0, 0, 5, 76, 11},
+    {21, 0, 0, 0, 5, 76, 12},
+    {21, 0, 0, 0, 5, 76, 17},
+    {7, 0, 0, 0, 5, 78, 38},
+    {12, 230, 13, 0, 5, 78, 38},
+    {12, 220, 13, 0, 5, 78, 38},
+    {6, 0, 0, 0, 5, 78, 38},
+    {21, 0, 0, 0, 5, 78, 38},
+    {7, 0, 0, 0, 5, 85, 12},
+    {10, 0, 0, 0, 5, 85, 21},
+    {12, 0, 13, 0, 5, 85, 21},
+    {21, 0, 0, 0, 5, 85, 17},
+    {6, 0, 0, 0, 5, 85, 12},
+    {12, 9, 13, 0, 5, 85, 21},
+    {13, 0, 0, 0, 5, 85, 11},
+    {7, 0, 0, 0, 2, 24, 23},
+    {7, 0, 0, 0, 2, 24, 24},
+    {4, 0, 0, 0, 5, 102, 39},
+    {3, 0, 0, 0, 4, 102, 41},
+    {12, 26, 13, 0, 5, 5, 21},
+    {25, 0, 9, 0, 5, 5, 12},
+    {24, 0, 4, 0, 5, 6, 12},
+    {18, 0, 18, 0, 5, 0, 1},
+    {12, 0, 13, 0, 4, 40, 21},
+    {21, 0, 18, 0, 2, 0, 8},
+    {21, 0, 18, 0, 2, 0, 6},
+    {21, 0, 18, 0, 2, 0, 15},
+    {16, 0, 18, 0, 2, 0, 14},
+    {21, 0, 12, 0, 2, 0, 1},
+    {21, 0, 12, 0, 2, 0, 5},
+    {21, 0, 10, 0, 2, 0, 14},
+    {25, 0, 9, 0, 2, 0, 14},
+    {17, 0, 9, 0, 2, 0, 14},
+    {25, 0, 18, 1, 2, 0, 14},
+    {25, 0, 18, 0, 2, 0, 14},
+    {23, 0, 10, 0, 2, 0, 9},
+    {21, 0, 10, 0, 2, 0, 10},
+    {21, 0, 18, 0, 0, 0, 6},
+    {21, 0, 18, 0, 0, 0, 14},
+    {21, 0, 10, 0, 0, 0, 14},
+    {23, 0, 10, 0, 0, 0, 9},
+    {21, 0, 10, 0, 0, 0, 10},
+    {22, 0, 18, 1, 0, 0, 0},
+    {18, 0, 18, 1, 0, 0, 1},
+    {25, 0, 9, 0, 0, 0, 14},
+    {21, 0, 12, 0, 0, 0, 1},
+    {17, 0, 9, 0, 0, 0, 14},
+    {21, 0, 12, 0, 0, 0, 14},
+    {13, 0, 8, 0, 0, 0, 14},
+    {21, 0, 12, 0, 0, 0, 5},
+    {21, 0, 18, 0, 0, 0, 5},
+    {25, 0, 18, 1, 0, 0, 14},
+    {25, 0, 18, 0, 0, 0, 14},
+    {9, 0, 0, 0, 0, 1, 14},
+    {24, 0, 18, 0, 0, 0, 14},
+    {16, 0, 18, 0, 0, 0, 14},
+    {5, 0, 0, 0, 0, 1, 14},
+    {21, 0, 18, 0, 1, 0, 1},
+    {22, 0, 18, 1, 1, 0, 0},
+    {18, 0, 18, 1, 1, 0, 1},
+    {21, 0, 18, 0, 1, 0, 5},
+    {7, 0, 0, 0, 1, 33, 14},
+    {7, 0, 0, 0, 1, 33, 32},
+    {6, 0, 0, 0, 1, 0, 32},
+    {6, 0, 0, 0, 1, 0, 5},
+    {7, 0, 0, 0, 1, 24, 14},
+    {23, 0, 10, 0, 0, 0, 10},
+    {26, 0, 18, 0, 0, 0, 14},
+    {26, 0, 18, 0, 1, 0, 12},
+    {25, 0, 18, 0, 1, 0, 12},
+    {1, 0, 18, 0, 5, 0, 21},
+    {26, 0, 18, 0, 5, 0, 31},
+    {7, 0, 0, 0, 5, 47, 12},
+    {14, 0, 18, 0, 5, 2, 12},
+    {15, 0, 18, 0, 5, 2, 12},
+    {26, 0, 18, 0, 5, 2, 12},
+    {26, 0, 0, 0, 5, 2, 12},
+    {7, 0, 0, 0, 5, 73, 12},
+    {7, 0, 0, 0, 5, 74, 12},
+    {7, 0, 0, 0, 5, 37, 12},
+    {15, 0, 0, 0, 5, 37, 12},
+    {7, 0, 0, 0, 5, 38, 12},
+    {14, 0, 0, 0, 5, 38, 12},
+    {7, 0, 0, 0, 5, 118, 12},
+    {12, 230, 13, 0, 5, 118, 21},
+    {7, 0, 0, 0, 5, 48, 12},
+    {21, 0, 0, 0, 5, 48, 17},
+    {7, 0, 0, 0, 5, 59, 12},
+    {21, 0, 0, 0, 5, 59, 17},
+    {14, 0, 0, 0, 5, 59, 12},
+    {9, 0, 0, 0, 5, 39, 12},
+    {5, 0, 0, 0, 5, 39, 12},
+    {7, 0, 0, 0, 5, 49, 12},
+    {7, 0, 0, 0, 5, 50, 12},
+    {13, 0, 0, 0, 5, 50, 11},
+    {9, 0, 0, 0, 5, 136, 12},
+    {5, 0, 0, 0, 5, 136, 12},
+    {7, 0, 0, 0, 5, 106, 12},
+    {7, 0, 0, 0, 5, 104, 12},
+    {21, 0, 0, 0, 5, 104, 12},
+    {7, 0, 0, 0, 5, 110, 12},
+    {7, 0, 3, 0, 5, 51, 12},
+    {7, 0, 3, 0, 5, 86, 12},
+    {21, 0, 3, 0, 5, 86, 17},
+    {15, 0, 3, 0, 5, 86, 12},
+    {7, 0, 3, 0, 5, 120, 12},
+    {26, 0, 3, 0, 5, 120, 12},
+    {15, 0, 3, 0, 5, 120, 12},
+    {7, 0, 3, 0, 5, 116, 12},
+    {15, 0, 3, 0, 5, 116, 12},
+    {7, 0, 3, 0, 5, 128, 12},
+    {15, 0, 3, 0, 5, 128, 12},
+    {7, 0, 3, 0, 5, 63, 12},
+    {15, 0, 3, 0, 5, 63, 12},
+    {21, 0, 18, 0, 5, 63, 17},
+    {7, 0, 3, 0, 5, 75, 12},
+    {21, 0, 3, 0, 5, 75, 12},
+    {7, 0, 3, 0, 5, 97, 12},
+    {7, 0, 3, 0, 5, 96, 12},
+    {15, 0, 3, 0, 5, 96, 12},
+    {7, 0, 3, 0, 5, 60, 12},
+    {12, 0, 13, 0, 5, 60, 21},
+    {12, 220, 13, 0, 5, 60, 21},
+    {12, 230, 13, 0, 5, 60, 21},
+    {12, 1, 13, 0, 5, 60, 21},
+    {12, 9, 13, 0, 5, 60, 21},
+    {15, 0, 3, 0, 5, 60, 12},
+    {21, 0, 3, 0, 5, 60, 17},
+    {21, 0, 3, 0, 5, 60, 12},
+    {7, 0, 3, 0, 5, 87, 12},
+    {15, 0, 3, 0, 5, 87, 12},
+    {21, 0, 3, 0, 5, 87, 12},
+    {7, 0, 3, 0, 5, 117, 12},
+    {15, 0, 3, 0, 5, 117, 12},
+    {7, 0, 3, 0, 5, 112, 12},
+    {26, 0, 3, 0, 5, 112, 12},
+    {12, 230, 13, 0, 5, 112, 21},
+    {12, 220, 13, 0, 5, 112, 21},
+    {15, 0, 3, 0, 5, 112, 12},
+    {21, 0, 3, 0, 5, 112, 17},
+    {21, 0, 3, 0, 5, 112, 15},
+    {7, 0, 3, 0, 5, 79, 12},
+    {21, 0, 18, 0, 5, 79, 17},
+    {7, 0, 3, 0, 5, 88, 12},
+    {15, 0, 3, 0, 5, 88, 12},
+    {7, 0, 3, 0, 5, 89, 12},
+    {15, 0, 3, 0, 5, 89, 12},
+    {7, 0, 3, 0, 5, 122, 12},
+    {21, 0, 3, 0, 5, 122, 12},
+    {15, 0, 3, 0, 5, 122, 12},
+    {7, 0, 3, 0, 5, 90, 12},
+    {9, 0, 3, 0, 5, 130, 12},
+    {5, 0, 3, 0, 5, 130, 12},
+    {15, 0, 3, 0, 5, 130, 12},
+    {15, 0, 11, 0, 5, 6, 12},
+    {10, 0, 0, 0, 5, 93, 21},
+    {12, 0, 13, 0, 5, 93, 21},
+    {7, 0, 0, 0, 5, 93, 12},
+    {12, 9, 13, 0, 5, 93, 21},
+    {21, 0, 0, 0, 5, 93, 17},
+    {21, 0, 0, 0, 5, 93, 12},
+    {15, 0, 18, 0, 5, 93, 12},
+    {13, 0, 0, 0, 5, 93, 11},
+    {12, 0, 13, 0, 5, 91, 21},
+    {10, 0, 0, 0, 5, 91, 21},
+    {7, 0, 0, 0, 5, 91, 12},
+    {12, 9, 13, 0, 5, 91, 21},
+    {12, 7, 13, 0, 5, 91, 21},
+    {21, 0, 0, 0, 5, 91, 12},
+    {1, 0, 0, 0, 5, 91, 12},
+    {21, 0, 0, 0, 5, 91, 17},
+    {7, 0, 0, 0, 5, 100, 12},
+    {13, 0, 0, 0, 5, 100, 11},
+    {12, 230, 13, 0, 5, 95, 21},
+    {7, 0, 0, 0, 5, 95, 12},
+    {12, 0, 13, 0, 5, 95, 21},
+    {10, 0, 0, 0, 5, 95, 21},
+    {12, 9, 13, 0, 5, 95, 21},
+    {13, 0, 0, 0, 5, 95, 11},
+    {21, 0, 0, 0, 5, 95, 17},
+    {7, 0, 0, 0, 5, 111, 12},
+    {12, 7, 13, 0, 5, 111, 21},
+    {21, 0, 0, 0, 5, 111, 12},
+    {21, 0, 0, 0, 5, 111, 18},
+    {12, 0, 13, 0, 5, 99, 21},
+    {10, 0, 0, 0, 5, 99, 21},
+    {7, 0, 0, 0, 5, 99, 12},
+    {10, 9, 0, 0, 5, 99, 21},
+    {21, 0, 0, 0, 5, 99, 17},
+    {21, 0, 0, 0, 5, 99, 12},
+    {12, 7, 13, 0, 5, 99, 21},
+    {13, 0, 0, 0, 5, 99, 11},
+    {21, 0, 0, 0, 5, 99, 18},
+    {15, 0, 0, 0, 5, 18, 12},
+    {7, 0, 0, 0, 5, 108, 12},
+    {10, 0, 0, 0, 5, 108, 21},
+    {12, 0, 13, 0, 5, 108, 21},
+    {10, 9, 0, 0, 5, 108, 21},
+    {12, 7, 13, 0, 5, 108, 21},
+    {21, 0, 0, 0, 5, 108, 17},
+    {21, 0, 0, 0, 5, 108, 12},
+    {7, 0, 0, 0, 5, 129, 12},
+    {21, 0, 0, 0, 5, 129, 17},
+    {7, 0, 0, 0, 5, 109, 12},
+    {12, 0, 13, 0, 5, 109, 21},
+    {10, 0, 0, 0, 5, 109, 21},
+    {12, 7, 13, 0, 5, 109, 21},
+    {12, 9, 13, 0, 5, 109, 21},
+    {13, 0, 0, 0, 5, 109, 11},
+    {12, 0, 13, 0, 5, 107, 21},
+    {10, 0, 0, 0, 5, 107, 21},
+    {7, 0, 0, 0, 5, 107, 12},
+    {12, 7, 13, 0, 5, 107, 21},
+    {10, 9, 0, 0, 5, 107, 21},
+    {12, 230, 13, 0, 5, 107, 21},
+    {7, 0, 0, 0, 5, 135, 12},
+    {10, 0, 0, 0, 5, 135, 21},
+    {12, 0, 13, 0, 5, 135, 21},
+    {12, 9, 13, 0, 5, 135, 21},
+    {12, 7, 13, 0, 5, 135, 21},
+    {21, 0, 0, 0, 5, 135, 17},
+    {21, 0, 0, 0, 5, 135, 12},
+    {13, 0, 0, 0, 5, 135, 11},
+    {7, 0, 0, 0, 5, 124, 12},
+    {10, 0, 0, 0, 5, 124, 21},
+    {12, 0, 13, 0, 5, 124, 21},
+    {12, 9, 13, 0, 5, 124, 21},
+    {12, 7, 13, 0, 5, 124, 21},
+    {21, 0, 0, 0, 5, 124, 12},
+    {13, 0, 0, 0, 5, 124, 11},
+    {7, 0, 0, 0, 5, 123, 12},
+    {10, 0, 0, 0, 5, 123, 21},
+    {12, 0, 13, 0, 5, 123, 21},
+    {12, 9, 13, 0, 5, 123, 21},
+    {12, 7, 13, 0, 5, 123, 21},
+    {21, 0, 0, 0, 5, 123, 18},
+    {21, 0, 0, 0, 5, 123, 17},
+    {21, 0, 0, 0, 5, 123, 6},
+    {21, 0, 0, 0, 5, 123, 12},
+    {7, 0, 0, 0, 5, 114, 12},
+    {10, 0, 0, 0, 5, 114, 21},
+    {12, 0, 13, 0, 5, 114, 21},
+    {12, 9, 13, 0, 5, 114, 21},
+    {21, 0, 0, 0, 5, 114, 17},
+    {21, 0, 0, 0, 5, 114, 12},
+    {13, 0, 0, 0, 5, 114, 11},
+    {21, 0, 18, 0, 5, 31, 18},
+    {7, 0, 0, 0, 5, 101, 12},
+    {12, 0, 13, 0, 5, 101, 21},
+    {10, 0, 0, 0, 5, 101, 21},
+    {10, 9, 0, 0, 5, 101, 21},
+    {12, 7, 13, 0, 5, 101, 21},
+    {13, 0, 0, 0, 5, 101, 11},
+    {7, 0, 0, 0, 5, 126, 38},
+    {12, 0, 13, 0, 5, 126, 38},
+    {10, 0, 0, 0, 5, 126, 38},
+    {12, 9, 13, 0, 5, 126, 38},
+    {13, 0, 0, 0, 5, 126, 11},
+    {15, 0, 0, 0, 5, 126, 38},
+    {21, 0, 0, 0, 5, 126, 17},
+    {26, 0, 0, 0, 5, 126, 38},
+    {9, 0, 0, 0, 5, 125, 12},
+    {5, 0, 0, 0, 5, 125, 12},
+    {13, 0, 0, 0, 5, 125, 11},
+    {15, 0, 0, 0, 5, 125, 12},
+    {7, 0, 0, 0, 5, 125, 12},
+    {7, 0, 0, 0, 5, 121, 12},
+    {7, 0, 0, 0, 5, 133, 12},
+    {10, 0, 0, 0, 5, 133, 21},
+    {12, 0, 13, 0, 5, 133, 21},
+    {12, 9, 0, 0, 5, 133, 21},
+    {21, 0, 0, 0, 5, 133, 17},
+    {13, 0, 0, 0, 5, 133, 11},
+    {15, 0, 0, 0, 5, 133, 12},
+    {21, 0, 0, 0, 5, 134, 18},
+    {21, 0, 0, 0, 5, 134, 6},
+    {7, 0, 0, 0, 5, 134, 12},
+    {12, 0, 13, 0, 5, 134, 21},
+    {10, 0, 0, 0, 5, 134, 21},
+    {7, 0, 0, 0, 5, 62, 12},
+    {14, 0, 0, 0, 5, 62, 12},
+    {21, 0, 0, 0, 5, 62, 17},
+    {7, 0, 0, 0, 5, 80, 12},
+    {7, 0, 0, 0, 5, 80, 0},
+    {7, 0, 0, 0, 5, 80, 1},
+    {7, 0, 0, 0, 5, 127, 12},
+    {7, 0, 0, 0, 5, 127, 0},
+    {7, 0, 0, 0, 5, 127, 1},
+    {7, 0, 0, 0, 5, 115, 12},
+    {13, 0, 0, 0, 5, 115, 11},
+    {21, 0, 0, 0, 5, 115, 17},
+    {7, 0, 0, 0, 5, 103, 12},
+    {12, 1, 13, 0, 5, 103, 21},
+    {21, 0, 0, 0, 5, 103, 17},
+    {7, 0, 0, 0, 5, 119, 12},
+    {12, 230, 13, 0, 5, 119, 21},
+    {21, 0, 0, 0, 5, 119, 17},
+    {21, 0, 0, 0, 5, 119, 12},
+    {26, 0, 0, 0, 5, 119, 12},
+    {6, 0, 0, 0, 5, 119, 12},
+    {13, 0, 0, 0, 5, 119, 11},
+    {15, 0, 0, 0, 5, 119, 12},
+    {7, 0, 0, 0, 5, 98, 12},
+    {10, 0, 0, 0, 5, 98, 21},
+    {12, 0, 13, 0, 5, 98, 21},
+    {6, 0, 0, 0, 5, 98, 12},
+    {6, 0, 0, 0, 2, 137, 5},
+    {7, 0, 0, 0, 2, 137, 14},
+    {7, 0, 0, 0, 5, 105, 12},
+    {26, 0, 0, 0, 5, 105, 12},
+    {12, 0, 13, 0, 5, 105, 21},
+    {12, 1, 13, 0, 5, 105, 21},
+    {21, 0, 0, 0, 5, 105, 17},
+    {10, 216, 0, 0, 5, 0, 21},
+    {10, 226, 0, 0, 5, 0, 21},
+    {12, 230, 13, 0, 5, 2, 21},
+    {25, 0, 0, 0, 5, 0, 12},
+    {13, 0, 8, 0, 5, 0, 11},
+    {26, 0, 0, 0, 5, 131, 12},
+    {12, 0, 13, 0, 5, 131, 21},
+    {21, 0, 0, 0, 5, 131, 17},
+    {21, 0, 0, 0, 5, 131, 12},
+    {12, 230, 13, 0, 5, 56, 21},
+    {7, 0, 3, 0, 5, 113, 12},
+    {15, 0, 3, 0, 5, 113, 12},
+    {12, 220, 13, 0, 5, 113, 21},
+    {9, 0, 3, 0, 5, 132, 12},
+    {5, 0, 3, 0, 5, 132, 12},
+    {12, 230, 13, 0, 5, 132, 21},
+    {12, 7, 13, 0, 5, 132, 21},
+    {13, 0, 3, 0, 5, 132, 11},
+    {21, 0, 3, 0, 5, 132, 0},
+    {2, 0, 18, 0, 5, 102, 14},
+    {26, 0, 0, 0, 2, 0, 29},
+    {26, 0, 0, 0, 5, 0, 28},
+    {26, 0, 0, 0, 2, 32, 14},
+    {24, 0, 18, 0, 2, 0, 41},
+    {26, 0, 18, 0, 5, 0, 5},
+};
+
+#define BIDI_MIRROR_LEN 364
+static const MirrorPair mirror_pairs[] = {
+    {40, 41},
+    {41, 40},
+    {60, 62},
+    {62, 60},
+    {91, 93},
+    {93, 91},
+    {123, 125},
+    {125, 123},
+    {171, 187},
+    {187, 171},
+    {3898, 3899},
+    {3899, 3898},
+    {3900, 3901},
+    {3901, 3900},
+    {5787, 5788},
+    {5788, 5787},
+    {8249, 8250},
+    {8250, 8249},
+    {8261, 8262},
+    {8262, 8261},
+    {8317, 8318},
+    {8318, 8317},
+    {8333, 8334},
+    {8334, 8333},
+    {8712, 8715},
+    {8713, 8716},
+    {8714, 8717},
+    {8715, 8712},
+    {8716, 8713},
+    {8717, 8714},
+    {8725, 10741},
+    {8764, 8765},
+    {8765, 8764},
+    {8771, 8909},
+    {8786, 8787},
+    {8787, 8786},
+    {8788, 8789},
+    {8789, 8788},
+    {8804, 8805},
+    {8805, 8804},
+    {8806, 8807},
+    {8807, 8806},
+    {8808, 8809},
+    {8809, 8808},
+    {8810, 8811},
+    {8811, 8810},
+    {8814, 8815},
+    {8815, 8814},
+    {8816, 8817},
+    {8817, 8816},
+    {8818, 8819},
+    {8819, 8818},
+    {8820, 8821},
+    {8821, 8820},
+    {8822, 8823},
+    {8823, 8822},
+    {8824, 8825},
+    {8825, 8824},
+    {8826, 8827},
+    {8827, 8826},
+    {8828, 8829},
+    {8829, 8828},
+    {8830, 8831},
+    {8831, 8830},
+    {8832, 8833},
+    {8833, 8832},
+    {8834, 8835},
+    {8835, 8834},
+    {8836, 8837},
+    {8837, 8836},
+    {8838, 8839},
+    {8839, 8838},
+    {8840, 8841},
+    {8841, 8840},
+    {8842, 8843},
+    {8843, 8842},
+    {8847, 8848},
+    {8848, 8847},
+    {8849, 8850},
+    {8850, 8849},
+    {8856, 10680},
+    {8866, 8867},
+    {8867, 8866},
+    {8870, 10974},
+    {8872, 10980},
+    {8873, 10979},
+    {8875, 10981},
+    {8880, 8881},
+    {8881, 8880},
+    {8882, 8883},
+    {8883, 8882},
+    {8884, 8885},
+    {8885, 8884},
+    {8886, 8887},
+    {8887, 8886},
+    {8905, 8906},
+    {8906, 8905},
+    {8907, 8908},
+    {8908, 8907},
+    {8909, 8771},
+    {8912, 8913},
+    {8913, 8912},
+    {8918, 8919},
+    {8919, 8918},
+    {8920, 8921},
+    {8921, 8920},
+    {8922, 8923},
+    {8923, 8922},
+    {8924, 8925},
+    {8925, 8924},
+    {8926, 8927},
+    {8927, 8926},
+    {8928, 8929},
+    {8929, 8928},
+    {8930, 8931},
+    {8931, 8930},
+    {8932, 8933},
+    {8933, 8932},
+    {8934, 8935},
+    {8935, 8934},
+    {8936, 8937},
+    {8937, 8936},
+    {8938, 8939},
+    {8939, 8938},
+    {8940, 8941},
+    {8941, 8940},
+    {8944, 8945},
+    {8945, 8944},
+    {8946, 8954},
+    {8947, 8955},
+    {8948, 8956},
+    {8950, 8957},
+    {8951, 8958},
+    {8954, 8946},
+    {8955, 8947},
+    {8956, 8948},
+    {8957, 8950},
+    {8958, 8951},
+    {8968, 8969},
+    {8969, 8968},
+    {8970, 8971},
+    {8971, 8970},
+    {9001, 9002},
+    {9002, 9001},
+    {10088, 10089},
+    {10089, 10088},
+    {10090, 10091},
+    {10091, 10090},
+    {10092, 10093},
+    {10093, 10092},
+    {10094, 10095},
+    {10095, 10094},
+    {10096, 10097},
+    {10097, 10096},
+    {10098, 10099},
+    {10099, 10098},
+    {10100, 10101},
+    {10101, 10100},
+    {10179, 10180},
+    {10180, 10179},
+    {10181, 10182},
+    {10182, 10181},
+    {10184, 10185},
+    {10185, 10184},
+    {10187, 10189},
+    {10189, 10187},
+    {10197, 10198},
+    {10198, 10197},
+    {10205, 10206},
+    {10206, 10205},
+    {10210, 10211},
+    {10211, 10210},
+    {10212, 10213},
+    {10213, 10212},
+    {10214, 10215},
+    {10215, 10214},
+    {10216, 10217},
+    {10217, 10216},
+    {10218, 10219},
+    {10219, 10218},
+    {10220, 10221},
+    {10221, 10220},
+    {10222, 10223},
+    {10223, 10222},
+    {10627, 10628},
+    {10628, 10627},
+    {10629, 10630},
+    {10630, 10629},
+    {10631, 10632},
+    {10632, 10631},
+    {10633, 10634},
+    {10634, 10633},
+    {10635, 10636},
+    {10636, 10635},
+    {10637, 10640},
+    {10638, 10639},
+    {10639, 10638},
+    {10640, 10637},
+    {10641, 10642},
+    {10642, 10641},
+    {10643, 10644},
+    {10644, 10643},
+    {10645, 10646},
+    {10646, 10645},
+    {10647, 10648},
+    {10648, 10647},
+    {10680, 8856},
+    {10688, 10689},
+    {10689, 10688},
+    {10692, 10693},
+    {10693, 10692},
+    {10703, 10704},
+    {10704, 10703},
+    {10705, 10706},
+    {10706, 10705},
+    {10708, 10709},
+    {10709, 10708},
+    {10712, 10713},
+    {10713, 10712},
+    {10714, 10715},
+    {10715, 10714},
+    {10741, 8725},
+    {10744, 10745},
+    {10745, 10744},
+    {10748, 10749},
+    {10749, 10748},
+    {10795, 10796},
+    {10796, 10795},
+    {10797, 10798},
+    {10798, 10797},
+    {10804, 10805},
+    {10805, 10804},
+    {10812, 10813},
+    {10813, 10812},
+    {10852, 10853},
+    {10853, 10852},
+    {10873, 10874},
+    {10874, 10873},
+    {10877, 10878},
+    {10878, 10877},
+    {10879, 10880},
+    {10880, 10879},
+    {10881, 10882},
+    {10882, 10881},
+    {10883, 10884},
+    {10884, 10883},
+    {10891, 10892},
+    {10892, 10891},
+    {10897, 10898},
+    {10898, 10897},
+    {10899, 10900},
+    {10900, 10899},
+    {10901, 10902},
+    {10902, 10901},
+    {10903, 10904},
+    {10904, 10903},
+    {10905, 10906},
+    {10906, 10905},
+    {10907, 10908},
+    {10908, 10907},
+    {10913, 10914},
+    {10914, 10913},
+    {10918, 10919},
+    {10919, 10918},
+    {10920, 10921},
+    {10921, 10920},
+    {10922, 10923},
+    {10923, 10922},
+    {10924, 10925},
+    {10925, 10924},
+    {10927, 10928},
+    {10928, 10927},
+    {10931, 10932},
+    {10932, 10931},
+    {10939, 10940},
+    {10940, 10939},
+    {10941, 10942},
+    {10942, 10941},
+    {10943, 10944},
+    {10944, 10943},
+    {10945, 10946},
+    {10946, 10945},
+    {10947, 10948},
+    {10948, 10947},
+    {10949, 10950},
+    {10950, 10949},
+    {10957, 10958},
+    {10958, 10957},
+    {10959, 10960},
+    {10960, 10959},
+    {10961, 10962},
+    {10962, 10961},
+    {10963, 10964},
+    {10964, 10963},
+    {10965, 10966},
+    {10966, 10965},
+    {10974, 8870},
+    {10979, 8873},
+    {10980, 8872},
+    {10981, 8875},
+    {10988, 10989},
+    {10989, 10988},
+    {10999, 11000},
+    {11000, 10999},
+    {11001, 11002},
+    {11002, 11001},
+    {11778, 11779},
+    {11779, 11778},
+    {11780, 11781},
+    {11781, 11780},
+    {11785, 11786},
+    {11786, 11785},
+    {11788, 11789},
+    {11789, 11788},
+    {11804, 11805},
+    {11805, 11804},
+    {11808, 11809},
+    {11809, 11808},
+    {11810, 11811},
+    {11811, 11810},
+    {11812, 11813},
+    {11813, 11812},
+    {11814, 11815},
+    {11815, 11814},
+    {11816, 11817},
+    {11817, 11816},
+    {12296, 12297},
+    {12297, 12296},
+    {12298, 12299},
+    {12299, 12298},
+    {12300, 12301},
+    {12301, 12300},
+    {12302, 12303},
+    {12303, 12302},
+    {12304, 12305},
+    {12305, 12304},
+    {12308, 12309},
+    {12309, 12308},
+    {12310, 12311},
+    {12311, 12310},
+    {12312, 12313},
+    {12313, 12312},
+    {12314, 12315},
+    {12315, 12314},
+    {65113, 65114},
+    {65114, 65113},
+    {65115, 65116},
+    {65116, 65115},
+    {65117, 65118},
+    {65118, 65117},
+    {65124, 65125},
+    {65125, 65124},
+    {65288, 65289},
+    {65289, 65288},
+    {65308, 65310},
+    {65310, 65308},
+    {65339, 65341},
+    {65341, 65339},
+    {65371, 65373},
+    {65373, 65371},
+    {65375, 65376},
+    {65376, 65375},
+    {65378, 65379},
+    {65379, 65378},
+};
+
+#define BIDI_BRACKET_LEN 120
+static const BracketPair bracket_pairs[] = {
+    {40, 41, 0},
+    {41, 40, 1},
+    {91, 93, 0},
+    {93, 91, 1},
+    {123, 125, 0},
+    {125, 123, 1},
+    {3898, 3899, 0},
+    {3899, 3898, 1},
+    {3900, 3901, 0},
+    {3901, 3900, 1},
+    {5787, 5788, 0},
+    {5788, 5787, 1},
+    {8261, 8262, 0},
+    {8262, 8261, 1},
+    {8317, 8318, 0},
+    {8318, 8317, 1},
+    {8333, 8334, 0},
+    {8334, 8333, 1},
+    {8968, 8969, 0},
+    {8969, 8968, 1},
+    {8970, 8971, 0},
+    {8971, 8970, 1},
+    {9001, 9002, 0},
+    {9002, 9001, 1},
+    {10088, 10089, 0},
+    {10089, 10088, 1},
+    {10090, 10091, 0},
+    {10091, 10090, 1},
+    {10092, 10093, 0},
+    {10093, 10092, 1},
+    {10094, 10095, 0},
+    {10095, 10094, 1},
+    {10096, 10097, 0},
+    {10097, 10096, 1},
+    {10098, 10099, 0},
+    {10099, 10098, 1},
+    {10100, 10101, 0},
+    {10101, 10100, 1},
+    {10181, 10182, 0},
+    {10182, 10181, 1},
+    {10214, 10215, 0},
+    {10215, 10214, 1},
+    {10216, 10217, 0},
+    {10217, 10216, 1},
+    {10218, 10219, 0},
+    {10219, 10218, 1},
+    {10220, 10221, 0},
+    {10221, 10220, 1},
+    {10222, 10223, 0},
+    {10223, 10222, 1},
+    {10627, 10628, 0},
+    {10628, 10627, 1},
+    {10629, 10630, 0},
+    {10630, 10629, 1},
+    {10631, 10632, 0},
+    {10632, 10631, 1},
+    {10633, 10634, 0},
+    {10634, 10633, 1},
+    {10635, 10636, 0},
+    {10636, 10635, 1},
+    {10637, 10640, 0},
+    {10638, 10639, 1},
+    {10639, 10638, 0},
+    {10640, 10637, 1},
+    {10641, 10642, 0},
+    {10642, 10641, 1},
+    {10643, 10644, 0},
+    {10644, 10643, 1},
+    {10645, 10646, 0},
+    {10646, 10645, 1},
+    {10647, 10648, 0},
+    {10648, 10647, 1},
+    {10712, 10713, 0},
+    {10713, 10712, 1},
+    {10714, 10715, 0},
+    {10715, 10714, 1},
+    {10748, 10749, 0},
+    {10749, 10748, 1},
+    {11810, 11811, 0},
+    {11811, 11810, 1},
+    {11812, 11813, 0},
+    {11813, 11812, 1},
+    {11814, 11815, 0},
+    {11815, 11814, 1},
+    {11816, 11817, 0},
+    {11817, 11816, 1},
+    {12296, 12297, 0},
+    {12297, 12296, 1},
+    {12298, 12299, 0},
+    {12299, 12298, 1},
+    {12300, 12301, 0},
+    {12301, 12300, 1},
+    {12302, 12303, 0},
+    {12303, 12302, 1},
+    {12304, 12305, 0},
+    {12305, 12304, 1},
+    {12308, 12309, 0},
+    {12309, 12308, 1},
+    {12310, 12311, 0},
+    {12311, 12310, 1},
+    {12312, 12313, 0},
+    {12313, 12312, 1},
+    {12314, 12315, 0},
+    {12315, 12314, 1},
+    {65113, 65114, 0},
+    {65114, 65113, 1},
+    {65115, 65116, 0},
+    {65116, 65115, 1},
+    {65117, 65118, 0},
+    {65118, 65117, 1},
+    {65288, 65289, 0},
+    {65289, 65288, 1},
+    {65339, 65341, 0},
+    {65341, 65339, 1},
+    {65371, 65373, 0},
+    {65373, 65371, 1},
+    {65375, 65376, 0},
+    {65376, 65375, 1},
+    {65378, 65379, 0},
+    {65379, 65378, 1},
+};
+
+/* Reindexing of NFC first characters. */
+#define TOTAL_FIRST 376
+#define TOTAL_LAST 62
+static const Reindex nfc_first[] = {
+  { 60, 2, 0},
+  { 65, 15, 3},
+  { 82, 8, 19},
+  { 97, 15, 28},
+  { 114, 8, 44},
+  { 168, 0, 53},
+  { 194, 0, 54},
+  { 196, 3, 55},
+  { 202, 0, 59},
+  { 207, 0, 60},
+  { 212, 2, 61},
+  { 216, 0, 64},
+  { 220, 0, 65},
+  { 226, 0, 66},
+  { 228, 3, 67},
+  { 234, 0, 71},
+  { 239, 0, 72},
+  { 244, 2, 73},
+  { 248, 0, 76},
+  { 252, 0, 77},
+  { 258, 1, 78},
+  { 274, 1, 80},
+  { 332, 1, 82},
+  { 346, 1, 84},
+  { 352, 1, 86},
+  { 360, 3, 88},
+  { 383, 0, 92},
+  { 416, 1, 93},
+  { 431, 1, 95},
+  { 439, 0, 97},
+  { 490, 1, 98},
+  { 550, 3, 100},
+  { 558, 1, 104},
+  { 658, 0, 106},
+  { 913, 0, 107},
+  { 917, 0, 108},
+  { 919, 0, 109},
+  { 921, 0, 110},
+  { 927, 0, 111},
+  { 929, 0, 112},
+  { 933, 0, 113},
+  { 937, 0, 114},
+  { 940, 0, 115},
+  { 942, 0, 116},
+  { 945, 0, 117},
+  { 949, 0, 118},
+  { 951, 0, 119},
+  { 953, 0, 120},
+  { 959, 0, 121},
+  { 961, 0, 122},
+  { 965, 0, 123},
+  { 969, 2, 124},
+  { 974, 0, 127},
+  { 978, 0, 128},
+  { 1030, 0, 129},
+  { 1040, 0, 130},
+  { 1043, 0, 131},
+  { 1045, 3, 132},
+  { 1050, 0, 136},
+  { 1054, 0, 137},
+  { 1059, 0, 138},
+  { 1063, 0, 139},
+  { 1067, 0, 140},
+  { 1069, 0, 141},
+  { 1072, 0, 142},
+  { 1075, 0, 143},
+  { 1077, 3, 144},
+  { 1082, 0, 148},
+  { 1086, 0, 149},
+  { 1091, 0, 150},
+  { 1095, 0, 151},
+  { 1099, 0, 152},
+  { 1101, 0, 153},
+  { 1110, 0, 154},
+  { 1140, 1, 155},
+  { 1240, 1, 157},
+  { 1256, 1, 159},
+  { 1575, 0, 161},
+  { 1608, 0, 162},
+  { 1610, 0, 163},
+  { 1729, 0, 164},
+  { 1746, 0, 165},
+  { 1749, 0, 166},
+  { 2344, 0, 167},
+  { 2352, 0, 168},
+  { 2355, 0, 169},
+  { 2503, 0, 170},
+  { 2887, 0, 171},
+  { 2962, 0, 172},
+  { 3014, 1, 173},
+  { 3142, 0, 175},
+  { 3263, 0, 176},
+  { 3270, 0, 177},
+  { 3274, 0, 178},
+  { 3398, 1, 179},
+  { 3545, 0, 181},
+  { 3548, 0, 182},
+  { 4133, 0, 183},
+  { 6917, 0, 184},
+  { 6919, 0, 185},
+  { 6921, 0, 186},
+  { 6923, 0, 187},
+  { 6925, 0, 188},
+  { 6929, 0, 189},
+  { 6970, 0, 190},
+  { 6972, 0, 191},
+  { 6974, 1, 192},
+  { 6978, 0, 194},
+  { 7734, 1, 195},
+  { 7770, 1, 197},
+  { 7778, 1, 199},
+  { 7840, 1, 201},
+  { 7864, 1, 203},
+  { 7884, 1, 205},
+  { 7936, 17, 207},
+  { 7960, 1, 225},
+  { 7968, 17, 227},
+  { 7992, 1, 245},
+  { 8000, 1, 247},
+  { 8008, 1, 249},
+  { 8016, 1, 251},
+  { 8025, 0, 253},
+  { 8032, 16, 254},
+  { 8052, 0, 271},
+  { 8060, 0, 272},
+  { 8118, 0, 273},
+  { 8127, 0, 274},
+  { 8134, 0, 275},
+  { 8182, 0, 276},
+  { 8190, 0, 277},
+  { 8592, 0, 278},
+  { 8594, 0, 279},
+  { 8596, 0, 280},
+  { 8656, 0, 281},
+  { 8658, 0, 282},
+  { 8660, 0, 283},
+  { 8707, 0, 284},
+  { 8712, 0, 285},
+  { 8715, 0, 286},
+  { 8739, 0, 287},
+  { 8741, 0, 288},
+  { 8764, 0, 289},
+  { 8771, 0, 290},
+  { 8773, 0, 291},
+  { 8776, 0, 292},
+  { 8781, 0, 293},
+  { 8801, 0, 294},
+  { 8804, 1, 295},
+  { 8818, 1, 297},
+  { 8822, 1, 299},
+  { 8826, 3, 301},
+  { 8834, 1, 305},
+  { 8838, 1, 307},
+  { 8849, 1, 309},
+  { 8866, 0, 311},
+  { 8872, 1, 312},
+  { 8875, 0, 314},
+  { 8882, 3, 315},
+  { 12358, 0, 319},
+  { 12363, 0, 320},
+  { 12365, 0, 321},
+  { 12367, 0, 322},
+  { 12369, 0, 323},
+  { 12371, 0, 324},
+  { 12373, 0, 325},
+  { 12375, 0, 326},
+  { 12377, 0, 327},
+  { 12379, 0, 328},
+  { 12381, 0, 329},
+  { 12383, 0, 330},
+  { 12385, 0, 331},
+  { 12388, 0, 332},
+  { 12390, 0, 333},
+  { 12392, 0, 334},
+  { 12399, 0, 335},
+  { 12402, 0, 336},
+  { 12405, 0, 337},
+  { 12408, 0, 338},
+  { 12411, 0, 339},
+  { 12445, 0, 340},
+  { 12454, 0, 341},
+  { 12459, 0, 342},
+  { 12461, 0, 343},
+  { 12463, 0, 344},
+  { 12465, 0, 345},
+  { 12467, 0, 346},
+  { 12469, 0, 347},
+  { 12471, 0, 348},
+  { 12473, 0, 349},
+  { 12475, 0, 350},
+  { 12477, 0, 351},
+  { 12479, 0, 352},
+  { 12481, 0, 353},
+  { 12484, 0, 354},
+  { 12486, 0, 355},
+  { 12488, 0, 356},
+  { 12495, 0, 357},
+  { 12498, 0, 358},
+  { 12501, 0, 359},
+  { 12504, 0, 360},
+  { 12507, 0, 361},
+  { 12527, 3, 362},
+  { 12541, 0, 366},
+  { 69785, 0, 367},
+  { 69787, 0, 368},
+  { 69797, 0, 369},
+  { 69937, 1, 370},
+  { 70471, 0, 372},
+  { 70841, 0, 373},
+  { 71096, 1, 374},
+  {0,0,0}
+};
+
+static const Reindex nfc_last[] = {
+  { 768, 4, 0},
+  { 774, 6, 5},
+  { 783, 0, 12},
+  { 785, 0, 13},
+  { 787, 1, 14},
+  { 795, 0, 16},
+  { 803, 5, 17},
+  { 813, 1, 23},
+  { 816, 1, 25},
+  { 824, 0, 27},
+  { 834, 0, 28},
+  { 837, 0, 29},
+  { 1619, 2, 30},
+  { 2364, 0, 33},
+  { 2494, 0, 34},
+  { 2519, 0, 35},
+  { 2878, 0, 36},
+  { 2902, 1, 37},
+  { 3006, 0, 39},
+  { 3031, 0, 40},
+  { 3158, 0, 41},
+  { 3266, 0, 42},
+  { 3285, 1, 43},
+  { 3390, 0, 45},
+  { 3415, 0, 46},
+  { 3530, 0, 47},
+  { 3535, 0, 48},
+  { 3551, 0, 49},
+  { 4142, 0, 50},
+  { 6965, 0, 51},
+  { 12441, 1, 52},
+  { 69818, 0, 54},
+  { 69927, 0, 55},
+  { 70462, 0, 56},
+  { 70487, 0, 57},
+  { 70832, 0, 58},
+  { 70842, 0, 59},
+  { 70845, 0, 60},
+  { 71087, 0, 61},
+  {0,0,0}
+};
+
+#define UCDN_EAST_ASIAN_F 0
+#define UCDN_EAST_ASIAN_H 1
+#define UCDN_EAST_ASIAN_W 2
+#define UCDN_EAST_ASIAN_NA 3
+#define UCDN_EAST_ASIAN_A 4
+#define UCDN_EAST_ASIAN_N 5
+
+#define UCDN_SCRIPT_COMMON 0
+#define UCDN_SCRIPT_LATIN 1
+#define UCDN_SCRIPT_GREEK 2
+#define UCDN_SCRIPT_CYRILLIC 3
+#define UCDN_SCRIPT_ARMENIAN 4
+#define UCDN_SCRIPT_HEBREW 5
+#define UCDN_SCRIPT_ARABIC 6
+#define UCDN_SCRIPT_SYRIAC 7
+#define UCDN_SCRIPT_THAANA 8
+#define UCDN_SCRIPT_DEVANAGARI 9
+#define UCDN_SCRIPT_BENGALI 10
+#define UCDN_SCRIPT_GURMUKHI 11
+#define UCDN_SCRIPT_GUJARATI 12
+#define UCDN_SCRIPT_ORIYA 13
+#define UCDN_SCRIPT_TAMIL 14
+#define UCDN_SCRIPT_TELUGU 15
+#define UCDN_SCRIPT_KANNADA 16
+#define UCDN_SCRIPT_MALAYALAM 17
+#define UCDN_SCRIPT_SINHALA 18
+#define UCDN_SCRIPT_THAI 19
+#define UCDN_SCRIPT_LAO 20
+#define UCDN_SCRIPT_TIBETAN 21
+#define UCDN_SCRIPT_MYANMAR 22
+#define UCDN_SCRIPT_GEORGIAN 23
+#define UCDN_SCRIPT_HANGUL 24
+#define UCDN_SCRIPT_ETHIOPIC 25
+#define UCDN_SCRIPT_CHEROKEE 26
+#define UCDN_SCRIPT_CANADIAN_ABORIGINAL 27
+#define UCDN_SCRIPT_OGHAM 28
+#define UCDN_SCRIPT_RUNIC 29
+#define UCDN_SCRIPT_KHMER 30
+#define UCDN_SCRIPT_MONGOLIAN 31
+#define UCDN_SCRIPT_HIRAGANA 32
+#define UCDN_SCRIPT_KATAKANA 33
+#define UCDN_SCRIPT_BOPOMOFO 34
+#define UCDN_SCRIPT_HAN 35
+#define UCDN_SCRIPT_YI 36
+#define UCDN_SCRIPT_OLD_ITALIC 37
+#define UCDN_SCRIPT_GOTHIC 38
+#define UCDN_SCRIPT_DESERET 39
+#define UCDN_SCRIPT_INHERITED 40
+#define UCDN_SCRIPT_TAGALOG 41
+#define UCDN_SCRIPT_HANUNOO 42
+#define UCDN_SCRIPT_BUHID 43
+#define UCDN_SCRIPT_TAGBANWA 44
+#define UCDN_SCRIPT_LIMBU 45
+#define UCDN_SCRIPT_TAI_LE 46
+#define UCDN_SCRIPT_LINEAR_B 47
+#define UCDN_SCRIPT_UGARITIC 48
+#define UCDN_SCRIPT_SHAVIAN 49
+#define UCDN_SCRIPT_OSMANYA 50
+#define UCDN_SCRIPT_CYPRIOT 51
+#define UCDN_SCRIPT_BRAILLE 52
+#define UCDN_SCRIPT_BUGINESE 53
+#define UCDN_SCRIPT_COPTIC 54
+#define UCDN_SCRIPT_NEW_TAI_LUE 55
+#define UCDN_SCRIPT_GLAGOLITIC 56
+#define UCDN_SCRIPT_TIFINAGH 57
+#define UCDN_SCRIPT_SYLOTI_NAGRI 58
+#define UCDN_SCRIPT_OLD_PERSIAN 59
+#define UCDN_SCRIPT_KHAROSHTHI 60
+#define UCDN_SCRIPT_BALINESE 61
+#define UCDN_SCRIPT_CUNEIFORM 62
+#define UCDN_SCRIPT_PHOENICIAN 63
+#define UCDN_SCRIPT_PHAGS_PA 64
+#define UCDN_SCRIPT_NKO 65
+#define UCDN_SCRIPT_SUNDANESE 66
+#define UCDN_SCRIPT_LEPCHA 67
+#define UCDN_SCRIPT_OL_CHIKI 68
+#define UCDN_SCRIPT_VAI 69
+#define UCDN_SCRIPT_SAURASHTRA 70
+#define UCDN_SCRIPT_KAYAH_LI 71
+#define UCDN_SCRIPT_REJANG 72
+#define UCDN_SCRIPT_LYCIAN 73
+#define UCDN_SCRIPT_CARIAN 74
+#define UCDN_SCRIPT_LYDIAN 75
+#define UCDN_SCRIPT_CHAM 76
+#define UCDN_SCRIPT_TAI_THAM 77
+#define UCDN_SCRIPT_TAI_VIET 78
+#define UCDN_SCRIPT_AVESTAN 79
+#define UCDN_SCRIPT_EGYPTIAN_HIEROGLYPHS 80
+#define UCDN_SCRIPT_SAMARITAN 81
+#define UCDN_SCRIPT_LISU 82
+#define UCDN_SCRIPT_BAMUM 83
+#define UCDN_SCRIPT_JAVANESE 84
+#define UCDN_SCRIPT_MEETEI_MAYEK 85
+#define UCDN_SCRIPT_IMPERIAL_ARAMAIC 86
+#define UCDN_SCRIPT_OLD_SOUTH_ARABIAN 87
+#define UCDN_SCRIPT_INSCRIPTIONAL_PARTHIAN 88
+#define UCDN_SCRIPT_INSCRIPTIONAL_PAHLAVI 89
+#define UCDN_SCRIPT_OLD_TURKIC 90
+#define UCDN_SCRIPT_KAITHI 91
+#define UCDN_SCRIPT_BATAK 92
+#define UCDN_SCRIPT_BRAHMI 93
+#define UCDN_SCRIPT_MANDAIC 94
+#define UCDN_SCRIPT_CHAKMA 95
+#define UCDN_SCRIPT_MEROITIC_CURSIVE 96
+#define UCDN_SCRIPT_MEROITIC_HIEROGLYPHS 97
+#define UCDN_SCRIPT_MIAO 98
+#define UCDN_SCRIPT_SHARADA 99
+#define UCDN_SCRIPT_SORA_SOMPENG 100
+#define UCDN_SCRIPT_TAKRI 101
+#define UCDN_SCRIPT_UNKNOWN 102
+#define UCDN_SCRIPT_BASSA_VAH 103
+#define UCDN_SCRIPT_CAUCASIAN_ALBANIAN 104
+#define UCDN_SCRIPT_DUPLOYAN 105
+#define UCDN_SCRIPT_ELBASAN 106
+#define UCDN_SCRIPT_GRANTHA 107
+#define UCDN_SCRIPT_KHOJKI 108
+#define UCDN_SCRIPT_KHUDAWADI 109
+#define UCDN_SCRIPT_LINEAR_A 110
+#define UCDN_SCRIPT_MAHAJANI 111
+#define UCDN_SCRIPT_MANICHAEAN 112
+#define UCDN_SCRIPT_MENDE_KIKAKUI 113
+#define UCDN_SCRIPT_MODI 114
+#define UCDN_SCRIPT_MRO 115
+#define UCDN_SCRIPT_NABATAEAN 116
+#define UCDN_SCRIPT_OLD_NORTH_ARABIAN 117
+#define UCDN_SCRIPT_OLD_PERMIC 118
+#define UCDN_SCRIPT_PAHAWH_HMONG 119
+#define UCDN_SCRIPT_PALMYRENE 120
+#define UCDN_SCRIPT_PAU_CIN_HAU 121
+#define UCDN_SCRIPT_PSALTER_PAHLAVI 122
+#define UCDN_SCRIPT_SIDDHAM 123
+#define UCDN_SCRIPT_TIRHUTA 124
+#define UCDN_SCRIPT_WARANG_CITI 125
+#define UCDN_SCRIPT_AHOM 126
+#define UCDN_SCRIPT_ANATOLIAN_HIEROGLYPHS 127
+#define UCDN_SCRIPT_HATRAN 128
+#define UCDN_SCRIPT_MULTANI 129
+#define UCDN_SCRIPT_OLD_HUNGARIAN 130
+#define UCDN_SCRIPT_SIGNWRITING 131
+#define UCDN_SCRIPT_ADLAM 132
+#define UCDN_SCRIPT_BHAIKSUKI 133
+#define UCDN_SCRIPT_MARCHEN 134
+#define UCDN_SCRIPT_NEWA 135
+#define UCDN_SCRIPT_OSAGE 136
+#define UCDN_SCRIPT_TANGUT 137
+
+#define UCDN_GENERAL_CATEGORY_CC 0
+#define UCDN_GENERAL_CATEGORY_CF 1
+#define UCDN_GENERAL_CATEGORY_CN 2
+#define UCDN_GENERAL_CATEGORY_CO 3
+#define UCDN_GENERAL_CATEGORY_CS 4
+#define UCDN_GENERAL_CATEGORY_LL 5
+#define UCDN_GENERAL_CATEGORY_LM 6
+#define UCDN_GENERAL_CATEGORY_LO 7
+#define UCDN_GENERAL_CATEGORY_LT 8
+#define UCDN_GENERAL_CATEGORY_LU 9
+#define UCDN_GENERAL_CATEGORY_MC 10
+#define UCDN_GENERAL_CATEGORY_ME 11
+#define UCDN_GENERAL_CATEGORY_MN 12
+#define UCDN_GENERAL_CATEGORY_ND 13
+#define UCDN_GENERAL_CATEGORY_NL 14
+#define UCDN_GENERAL_CATEGORY_NO 15
+#define UCDN_GENERAL_CATEGORY_PC 16
+#define UCDN_GENERAL_CATEGORY_PD 17
+#define UCDN_GENERAL_CATEGORY_PE 18
+#define UCDN_GENERAL_CATEGORY_PF 19
+#define UCDN_GENERAL_CATEGORY_PI 20
+#define UCDN_GENERAL_CATEGORY_PO 21
+#define UCDN_GENERAL_CATEGORY_PS 22
+#define UCDN_GENERAL_CATEGORY_SC 23
+#define UCDN_GENERAL_CATEGORY_SK 24
+#define UCDN_GENERAL_CATEGORY_SM 25
+#define UCDN_GENERAL_CATEGORY_SO 26
+#define UCDN_GENERAL_CATEGORY_ZL 27
+#define UCDN_GENERAL_CATEGORY_ZP 28
+#define UCDN_GENERAL_CATEGORY_ZS 29
+
+#define UCDN_BIDI_CLASS_L 0
+#define UCDN_BIDI_CLASS_LRE 1
+#define UCDN_BIDI_CLASS_LRO 2
+#define UCDN_BIDI_CLASS_R 3
+#define UCDN_BIDI_CLASS_AL 4
+#define UCDN_BIDI_CLASS_RLE 5
+#define UCDN_BIDI_CLASS_RLO 6
+#define UCDN_BIDI_CLASS_PDF 7
+#define UCDN_BIDI_CLASS_EN 8
+#define UCDN_BIDI_CLASS_ES 9
+#define UCDN_BIDI_CLASS_ET 10
+#define UCDN_BIDI_CLASS_AN 11
+#define UCDN_BIDI_CLASS_CS 12
+#define UCDN_BIDI_CLASS_NSM 13
+#define UCDN_BIDI_CLASS_BN 14
+#define UCDN_BIDI_CLASS_B 15
+#define UCDN_BIDI_CLASS_S 16
+#define UCDN_BIDI_CLASS_WS 17
+#define UCDN_BIDI_CLASS_ON 18
+#define UCDN_BIDI_CLASS_LRI 19
+#define UCDN_BIDI_CLASS_RLI 20
+#define UCDN_BIDI_CLASS_FSI 21
+#define UCDN_BIDI_CLASS_PDI 22
+
+/* index tables for the database records */
+#define SHIFT1 5
+#define SHIFT2 3
+static const unsigned char index0[] = {
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+    21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+    39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 52, 52, 52, 52,
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    52, 52, 53, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 54, 55, 56, 56, 56, 57,
+    58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 65, 66, 67, 68,
+    69, 70, 71, 65, 66, 67, 68, 69, 70, 71, 65, 66, 67, 68, 69, 70, 71, 65,
+    66, 67, 68, 69, 70, 71, 65, 66, 67, 68, 69, 70, 71, 65, 72, 73, 73, 73,
+    73, 73, 73, 73, 73, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 52, 75, 76, 77, 78, 79,
+    80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 94, 96,
+    97, 98, 99, 100, 101, 102, 103, 104, 94, 105, 94, 106, 94, 94, 94, 107,
+    107, 107, 108, 109, 110, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 111,
+    111, 112, 113, 114, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 115, 116, 117, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 118, 118, 119, 120, 94, 94, 94, 121, 122, 122, 122, 122, 122,
+    122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122,
+    122, 122, 122, 122, 123, 122, 122, 124, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 125, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 126, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 127, 128, 129, 130, 131, 132, 133, 134, 135,
+    135, 136, 94, 94, 94, 94, 94, 137, 94, 94, 94, 94, 94, 94, 94, 138, 139,
+    94, 94, 94, 94, 140, 94, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+    150, 151, 151, 151, 151, 151, 152, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 153, 52, 52, 52, 52,
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 154, 155, 52, 52, 52, 52,
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 156,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 52, 52,
+    158, 157, 157, 157, 157, 159, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 159, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 160, 161,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+    94, 94, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 162, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 162,
+};
+
+static const unsigned short index1[] = {
+    0, 1, 0, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 11, 12, 13, 0, 0, 0, 14, 15,
+    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 29, 31, 32,
+    33, 34, 35, 27, 30, 29, 27, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+    47, 48, 27, 27, 49, 27, 27, 27, 27, 27, 27, 27, 50, 51, 52, 27, 53, 54,
+    53, 54, 54, 54, 54, 54, 55, 54, 54, 54, 56, 57, 58, 59, 60, 61, 62, 63,
+    64, 64, 65, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 65, 77, 78,
+    79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
+    97, 97, 97, 97, 98, 98, 98, 98, 99, 100, 101, 101, 101, 101, 102, 103,
+    101, 101, 101, 101, 101, 101, 104, 105, 101, 101, 101, 101, 101, 101,
+    101, 101, 101, 101, 101, 101, 106, 107, 107, 107, 108, 109, 110, 111,
+    111, 111, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 121,
+    121, 122, 123, 120, 124, 125, 126, 127, 128, 128, 128, 128, 129, 130,
+    131, 132, 133, 134, 135, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 145, 145,
+    146, 147, 148, 149, 128, 128, 128, 128, 128, 128, 150, 150, 150, 150,
+    151, 152, 153, 120, 154, 155, 156, 156, 156, 157, 158, 159, 160, 160,
+    161, 162, 163, 164, 165, 166, 167, 167, 167, 168, 120, 120, 120, 120,
+    120, 120, 120, 120, 128, 128, 169, 170, 120, 120, 171, 126, 172, 173,
+    174, 175, 176, 177, 177, 177, 177, 177, 177, 178, 179, 180, 181, 177,
+    182, 183, 184, 177, 185, 186, 187, 188, 188, 189, 190, 191, 192, 193,
+    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 203, 204, 205, 206,
+    207, 208, 209, 210, 211, 212, 213, 120, 214, 215, 216, 217, 217, 218,
+    219, 220, 221, 222, 223, 120, 224, 225, 226, 227, 228, 229, 230, 231,
+    231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 120, 242, 243,
+    244, 245, 246, 243, 247, 248, 249, 250, 251, 120, 252, 253, 254, 255,
+    256, 257, 258, 259, 259, 258, 259, 260, 261, 262, 263, 264, 265, 266,
+    120, 267, 268, 269, 270, 271, 271, 270, 272, 273, 274, 275, 276, 277,
+    278, 279, 280, 120, 281, 282, 283, 284, 284, 284, 284, 285, 286, 287,
+    288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 295, 295, 298, 299,
+    296, 300, 301, 302, 303, 304, 305, 120, 306, 307, 307, 307, 307, 307,
+    308, 309, 310, 311, 312, 313, 120, 120, 120, 120, 314, 315, 316, 317,
+    318, 319, 320, 321, 322, 323, 324, 325, 120, 120, 120, 120, 326, 327,
+    328, 329, 330, 331, 332, 333, 334, 335, 334, 334, 334, 336, 337, 338,
+    339, 340, 341, 342, 341, 341, 341, 343, 344, 345, 346, 347, 120, 120,
+    120, 120, 348, 348, 348, 348, 348, 349, 350, 351, 352, 353, 354, 355,
+    356, 357, 358, 348, 359, 360, 352, 361, 362, 362, 362, 362, 363, 364,
+    365, 365, 365, 365, 365, 366, 367, 367, 367, 367, 367, 367, 367, 367,
+    367, 367, 367, 367, 368, 368, 368, 368, 368, 368, 368, 368, 368, 369,
+    369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 370, 370, 370, 370,
+    370, 370, 370, 370, 370, 371, 372, 371, 370, 370, 370, 370, 370, 371,
+    370, 370, 370, 370, 371, 372, 371, 370, 372, 370, 370, 370, 370, 370,
+    370, 370, 371, 370, 370, 370, 370, 370, 370, 370, 370, 373, 374, 375,
+    376, 377, 370, 370, 378, 379, 380, 380, 380, 380, 380, 380, 380, 380,
+    380, 380, 381, 382, 383, 384, 384, 384, 384, 384, 384, 384, 384, 384,
+    384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384,
+    384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384,
+    384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384,
+    384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384,
+    384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 385, 384, 384,
+    386, 387, 387, 388, 389, 389, 389, 389, 389, 389, 389, 389, 389, 390,
+    391, 392, 393, 394, 395, 120, 396, 396, 397, 120, 398, 398, 399, 120,
+    400, 401, 402, 120, 403, 403, 403, 403, 403, 403, 404, 405, 406, 407,
+    408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 418, 418, 418,
+    419, 418, 418, 418, 418, 418, 418, 120, 420, 418, 418, 418, 418, 421,
+    384, 384, 384, 384, 384, 384, 384, 384, 422, 120, 423, 423, 423, 424,
+    425, 426, 427, 428, 429, 430, 431, 431, 431, 432, 433, 120, 434, 434,
+    434, 434, 434, 435, 434, 434, 434, 436, 437, 438, 439, 439, 439, 439,
+    440, 440, 441, 442, 443, 443, 443, 443, 443, 443, 444, 445, 446, 447,
+    448, 449, 450, 451, 450, 451, 452, 453, 454, 455, 120, 120, 120, 120,
+    120, 120, 120, 120, 456, 457, 457, 457, 457, 457, 458, 459, 460, 461,
+    462, 463, 464, 465, 466, 467, 468, 469, 469, 469, 470, 471, 472, 473,
+    474, 474, 474, 474, 475, 476, 477, 478, 479, 479, 479, 479, 480, 481,
+    482, 483, 484, 485, 486, 487, 488, 488, 488, 489, 100, 490, 120, 120,
+    120, 120, 120, 120, 491, 120, 492, 493, 494, 495, 496, 497, 54, 54, 54,
+    54, 498, 499, 56, 56, 56, 56, 56, 500, 501, 502, 54, 503, 54, 54, 54,
+    504, 56, 56, 56, 505, 506, 507, 508, 509, 509, 509, 510, 511, 27, 27, 27,
+    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 512, 513, 27,
+    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 514, 515, 516, 517, 514, 515,
+    514, 515, 516, 517, 514, 518, 514, 515, 514, 516, 514, 519, 514, 519,
+    514, 519, 520, 521, 522, 523, 524, 525, 514, 526, 527, 528, 529, 530,
+    531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544,
+    545, 546, 56, 547, 548, 549, 550, 551, 552, 552, 553, 554, 555, 556, 557,
+    120, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570,
+    571, 570, 572, 573, 574, 575, 576, 577, 578, 579, 580, 579, 581, 582,
+    579, 583, 579, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594,
+    595, 596, 597, 598, 599, 594, 594, 600, 601, 602, 603, 604, 594, 594,
+    605, 585, 606, 607, 594, 594, 608, 594, 594, 579, 609, 610, 611, 612,
+    613, 614, 615, 615, 615, 615, 615, 615, 615, 615, 616, 579, 579, 617,
+    618, 585, 585, 619, 579, 579, 579, 579, 584, 620, 621, 622, 623, 579,
+    579, 579, 579, 623, 120, 120, 120, 579, 624, 120, 120, 625, 625, 625,
+    625, 625, 626, 626, 627, 628, 628, 628, 628, 628, 628, 628, 628, 628,
+    629, 625, 630, 631, 631, 631, 631, 631, 631, 631, 631, 631, 632, 631,
+    631, 631, 631, 633, 579, 631, 631, 634, 579, 635, 636, 637, 638, 639,
+    640, 636, 579, 634, 641, 579, 642, 643, 644, 645, 646, 579, 579, 579,
+    647, 648, 649, 650, 579, 651, 652, 579, 653, 579, 579, 654, 655, 656,
+    657, 579, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 579,
+    579, 579, 669, 579, 670, 579, 671, 672, 673, 674, 675, 676, 625, 677,
+    677, 678, 579, 579, 579, 669, 679, 680, 681, 682, 683, 684, 685, 585,
+    585, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686,
+    686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686,
+    686, 686, 686, 686, 686, 585, 585, 585, 585, 585, 585, 585, 585, 585,
+    585, 585, 585, 585, 585, 585, 585, 687, 688, 688, 689, 594, 594, 585,
+    690, 691, 692, 693, 694, 695, 696, 697, 698, 585, 699, 594, 700, 701,
+    702, 703, 683, 585, 585, 597, 690, 703, 704, 705, 706, 594, 594, 594,
+    594, 707, 708, 594, 594, 594, 594, 709, 710, 711, 683, 712, 713, 579,
+    579, 579, 714, 579, 579, 585, 585, 715, 716, 717, 636, 579, 579, 718,
+    579, 579, 579, 719, 579, 579, 579, 579, 720, 579, 721, 722, 120, 120,
+    723, 120, 120, 724, 724, 724, 724, 724, 725, 726, 726, 726, 726, 726,
+    727, 728, 729, 730, 731, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
+    732, 733, 734, 735, 736, 736, 736, 736, 737, 738, 739, 739, 739, 739,
+    739, 739, 739, 740, 741, 742, 370, 370, 372, 120, 372, 372, 372, 372,
+    372, 372, 372, 372, 743, 743, 743, 743, 744, 745, 746, 747, 748, 749,
+    750, 751, 752, 120, 120, 120, 120, 120, 120, 120, 753, 753, 753, 754,
+    753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 755, 120, 753, 753,
+    753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 753,
+    753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 756, 120, 120, 120,
+    757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 769,
+    770, 769, 769, 769, 771, 772, 773, 774, 775, 776, 777, 777, 778, 777,
+    777, 777, 779, 780, 781, 782, 783, 784, 784, 784, 784, 785, 786, 787,
+    787, 787, 787, 787, 787, 787, 787, 787, 787, 788, 789, 790, 784, 784,
+    784, 791, 757, 757, 757, 757, 758, 120, 792, 792, 793, 793, 793, 794,
+    795, 796, 790, 790, 790, 797, 798, 799, 793, 793, 793, 800, 795, 796,
+    790, 790, 790, 790, 801, 799, 790, 802, 803, 803, 803, 803, 803, 804,
+    803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 790, 790, 790,
+    805, 806, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 807,
+    790, 790, 790, 805, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808,
+    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808,
+    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808,
+    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808,
+    808, 808, 809, 810, 579, 579, 579, 579, 579, 579, 579, 579, 808, 808,
+    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808,
+    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 809, 810, 810, 810,
+    810, 810, 811, 811, 812, 811, 811, 811, 811, 811, 811, 811, 811, 811,
+    811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811,
+    811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811,
+    811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811,
+    811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811,
+    811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 813,
+    814, 814, 814, 814, 814, 814, 815, 120, 816, 816, 816, 816, 816, 817,
+    818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818,
+    818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818,
+    818, 818, 818, 818, 818, 819, 818, 818, 820, 821, 120, 120, 101, 101,
+    101, 101, 101, 822, 823, 824, 101, 101, 101, 825, 826, 826, 826, 826,
+    826, 826, 826, 826, 827, 828, 829, 120, 64, 64, 830, 831, 832, 27, 833,
+    27, 27, 27, 27, 27, 27, 27, 834, 835, 27, 836, 837, 27, 27, 838, 839,
+    120, 120, 120, 120, 120, 120, 120, 840, 841, 842, 843, 844, 844, 845,
+    846, 847, 848, 849, 849, 849, 849, 849, 849, 850, 120, 851, 852, 852,
+    852, 852, 852, 853, 854, 855, 856, 857, 858, 859, 859, 860, 861, 862,
+    863, 864, 864, 865, 866, 867, 867, 868, 869, 870, 871, 367, 367, 367,
+    872, 873, 874, 874, 874, 874, 874, 875, 876, 877, 878, 879, 880, 881,
+    348, 352, 882, 883, 883, 883, 883, 883, 884, 885, 120, 886, 887, 888,
+    889, 348, 348, 890, 891, 892, 892, 892, 892, 892, 892, 893, 894, 895,
+    120, 120, 896, 897, 898, 899, 120, 900, 900, 900, 120, 372, 372, 54, 54,
+    54, 54, 54, 901, 902, 120, 903, 903, 903, 903, 903, 903, 903, 903, 903,
+    903, 897, 897, 897, 897, 904, 905, 906, 907, 908, 909, 909, 910, 909,
+    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909,
+    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909,
+    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909,
+    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909,
+    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909,
+    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909,
+    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909,
+    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909,
+    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909,
+    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909,
+    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909,
+    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909,
+    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909,
+    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909,
+    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909,
+    909, 909, 908, 909, 909, 910, 909, 909, 909, 909, 909, 909, 908, 909,
+    909, 910, 909, 909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909,
+    909, 911, 120, 368, 368, 912, 913, 369, 369, 369, 369, 369, 914, 915,
+    915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915,
+    915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915,
+    915, 915, 915, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916,
+    916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916,
+    916, 916, 916, 916, 916, 916, 916, 808, 808, 808, 808, 808, 808, 808,
+    808, 808, 808, 808, 808, 808, 809, 808, 808, 808, 808, 808, 808, 808,
+    808, 808, 808, 808, 808, 808, 917, 810, 810, 810, 810, 918, 120, 919,
+    920, 121, 921, 922, 923, 924, 121, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 925, 926, 927, 120, 928, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 929, 120,
+    120, 128, 128, 128, 128, 128, 128, 128, 128, 930, 128, 128, 128, 128,
+    128, 128, 120, 120, 120, 120, 120, 128, 931, 932, 932, 933, 934, 935,
+    936, 937, 938, 939, 940, 941, 942, 943, 944, 169, 128, 128, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 945, 946,
+    947, 948, 949, 950, 951, 951, 952, 953, 954, 954, 955, 956, 957, 958,
+    959, 959, 959, 959, 960, 961, 961, 961, 962, 963, 963, 963, 964, 965,
+    966, 120, 967, 968, 969, 968, 968, 970, 968, 968, 971, 968, 972, 968,
+    972, 120, 120, 120, 120, 968, 968, 968, 968, 968, 968, 968, 968, 968,
+    968, 968, 968, 968, 968, 968, 973, 974, 975, 975, 975, 975, 975, 976,
+    615, 977, 977, 977, 977, 977, 977, 978, 979, 980, 981, 579, 982, 983,
+    120, 120, 120, 120, 120, 615, 615, 615, 615, 615, 984, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 985,
+    985, 985, 986, 987, 987, 987, 987, 987, 987, 988, 120, 989, 990, 990,
+    991, 992, 992, 992, 992, 993, 120, 994, 994, 995, 996, 997, 997, 997,
+    997, 998, 999, 1000, 1000, 1000, 1001, 1002, 1002, 1002, 1002, 1003,
+    1002, 1004, 120, 120, 120, 120, 120, 1005, 1005, 1005, 1005, 1005, 1006,
+    1006, 1006, 1006, 1006, 1007, 1007, 1007, 1007, 1007, 1007, 1008, 1008,
+    1008, 1009, 1010, 1011, 1012, 1012, 1012, 1012, 1013, 1014, 1014, 1014,
+    1014, 1015, 1016, 1016, 1016, 1016, 1016, 120, 1017, 1017, 1017, 1017,
+    1017, 1017, 1018, 1019, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 1020, 1020, 1020, 1020, 1020,
+    1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020,
+    1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020,
+    1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1021, 120, 1020,
+    1020, 1022, 120, 1020, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 1023, 1024, 1025, 1025,
+    1025, 1025, 1026, 1027, 1028, 1028, 1029, 1030, 1031, 1031, 1032, 1033,
+    1034, 1034, 1034, 1035, 1036, 1037, 120, 120, 120, 120, 120, 120, 1038,
+    1038, 1039, 1040, 1041, 1041, 1042, 1043, 1044, 1044, 1044, 1045, 120,
+    120, 120, 120, 120, 120, 120, 120, 1046, 1046, 1046, 1046, 1047, 1047,
+    1047, 1048, 1049, 1049, 1050, 1049, 1049, 1049, 1049, 1049, 1051, 1052,
+    1053, 1054, 1055, 1055, 1056, 1057, 1058, 120, 1059, 1060, 1061, 1061,
+    1061, 1062, 1063, 1063, 1063, 1064, 120, 120, 120, 120, 1065, 1066, 1065,
+    1065, 1067, 1068, 1069, 120, 1070, 1070, 1070, 1070, 1070, 1070, 1071,
+    1072, 1073, 1073, 1074, 1075, 1076, 1076, 1077, 1078, 1079, 1079, 1080,
+    1081, 120, 1082, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1083,
+    1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1084, 120, 120, 120, 120,
+    120, 120, 1085, 1085, 1085, 1085, 1085, 1085, 1086, 120, 1087, 1087,
+    1087, 1087, 1087, 1087, 1088, 1089, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 1090, 1090, 1090, 1091, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 1092, 1093, 1093, 1093, 1093, 1093, 1093, 1094, 1095, 1096, 1097,
+    1098, 1099, 1100, 120, 1101, 1102, 1103, 1103, 1103, 1103, 1103, 1104,
+    1105, 1106, 120, 1107, 1107, 1107, 1108, 1109, 1110, 1111, 1112, 1112,
+    1112, 1113, 1114, 1115, 1116, 1117, 120, 1118, 1118, 1118, 1118, 1119,
+    120, 1120, 1121, 1121, 1121, 1121, 1121, 1122, 1123, 1124, 1125, 1126,
+    1127, 1128, 1129, 1130, 120, 1131, 1131, 1132, 1131, 1131, 1133, 1134,
+    1135, 120, 120, 120, 120, 120, 120, 120, 120, 1136, 1137, 1138, 1139,
+    1138, 1140, 1141, 1141, 1141, 1141, 1141, 1142, 1143, 1144, 1145, 1146,
+    1147, 1148, 1149, 1150, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157,
+    1158, 1159, 1159, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 1160, 1160, 1160, 1160, 1160, 1160, 1161,
+    1162, 1163, 1164, 1165, 1166, 120, 120, 120, 120, 1167, 1167, 1167, 1167,
+    1167, 1167, 1168, 1169, 1170, 120, 1171, 1172, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 1173, 1173, 1173, 1173, 1173, 1174, 1175, 1176, 1177, 1178, 1179,
+    1180, 120, 120, 120, 120, 1181, 1181, 1181, 1181, 1181, 1181, 1182, 1183,
+    1184, 120, 1185, 1186, 1187, 1188, 120, 120, 1189, 1189, 1189, 1189,
+    1189, 1190, 1191, 120, 1192, 1193, 120, 120, 120, 120, 120, 120, 1194,
+    1194, 1194, 1195, 1196, 1197, 1198, 1199, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1200, 1200, 1200, 1200,
+    1201, 1201, 1201, 1201, 1202, 1203, 1204, 1205, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1207,
+    1208, 1209, 1208, 1208, 1208, 1210, 1211, 1212, 1213, 120, 1214, 1215,
+    1216, 1217, 1218, 1219, 1219, 1219, 1220, 1221, 1221, 1222, 1223, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 1224, 1224, 1224, 1224, 1224,
+    1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224,
+    1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224,
+    1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224,
+    1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1225, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1226, 1226, 1226,
+    1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1227, 1228,
+    120, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224,
+    1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224,
+    1224, 1229, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1230, 1230, 1230,
+    1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
+    1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
+    1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
+    1230, 1230, 1230, 1230, 1231, 1230, 1230, 1230, 1230, 1232, 1233, 1230,
+    1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
+    1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
+    1230, 1230, 1230, 1230, 1234, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
+    1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
+    1230, 1230, 1235, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+    1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+    1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+    1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+    1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1237, 1236,
+    1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+    1236, 1238, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 826, 826, 826,
+    826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 826,
+    826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 826,
+    826, 826, 826, 826, 826, 826, 826, 826, 1239, 1240, 1240, 1240, 1241,
+    1242, 1243, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    1244, 1244, 1244, 1245, 1246, 120, 1247, 1247, 1247, 1247, 1247, 1247,
+    1248, 1249, 1250, 120, 1251, 1252, 1253, 1247, 1247, 1254, 1247, 1247,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1256, 120, 1257, 1258,
+    1258, 1258, 1258, 1259, 120, 1260, 1261, 1262, 120, 120, 120, 120, 120,
+    120, 120, 120, 1263, 120, 120, 120, 1264, 1264, 1264, 1264, 1264, 1264,
+    1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264,
+    1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264,
+    1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264,
+    1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264,
+    1264, 1264, 1264, 1264, 1264, 1264, 1264, 1265, 120, 120, 1264, 1264,
+    1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264,
+    1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264,
+    1264, 1264, 1264, 1264, 1266, 120, 1267, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1268, 1268, 1268,
+    1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1269, 1268,
+    1270, 1268, 1271, 1268, 1272, 1273, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615,
+    615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615,
+    615, 615, 615, 615, 615, 615, 1274, 120, 615, 615, 615, 615, 1275, 1276,
+    615, 615, 615, 615, 615, 615, 1277, 1278, 1279, 1280, 1281, 1282, 615,
+    615, 615, 1283, 615, 615, 615, 615, 615, 615, 615, 1284, 120, 120, 980,
+    980, 980, 980, 980, 980, 980, 980, 1285, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 579, 579, 579, 579, 579, 579, 579, 579, 579, 579, 623,
+    120, 975, 975, 1286, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 1287, 1287, 1287, 1288, 1289, 1289,
+    1290, 1287, 1287, 1291, 1292, 1289, 1289, 1287, 1287, 1287, 1288, 1289,
+    1289, 1293, 1294, 1295, 1291, 1296, 1297, 1289, 1287, 1287, 1287, 1288,
+    1289, 1289, 1298, 1299, 1300, 1301, 1289, 1289, 1289, 1302, 1303, 1304,
+    1305, 1289, 1289, 1290, 1287, 1287, 1291, 1289, 1289, 1289, 1287, 1287,
+    1287, 1288, 1289, 1289, 1290, 1287, 1287, 1291, 1289, 1289, 1289, 1287,
+    1287, 1287, 1288, 1289, 1289, 1290, 1287, 1287, 1291, 1289, 1289, 1289,
+    1287, 1287, 1287, 1288, 1289, 1289, 1306, 1287, 1287, 1287, 1307, 1289,
+    1289, 1308, 1309, 1287, 1287, 1310, 1289, 1289, 1311, 1290, 1287, 1287,
+    1312, 1289, 1289, 1313, 1314, 1287, 1287, 1315, 1289, 1289, 1289, 1316,
+    1287, 1287, 1287, 1307, 1289, 1289, 1308, 1317, 1318, 1318, 1318, 1318,
+    1318, 1318, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319,
+    1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319,
+    1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1320, 1320,
+    1320, 1320, 1320, 1320, 1321, 1322, 1320, 1320, 1320, 1320, 1320, 1323,
+    1324, 1319, 1325, 1326, 120, 1327, 1328, 1320, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 1329, 1330, 1330, 1331, 1332, 1333, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1334, 1334, 1334, 1334,
+    1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334,
+    1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1335, 1336, 1337, 120,
+    120, 120, 120, 120, 1338, 1338, 1338, 1338, 1339, 1340, 1340, 1340, 1341,
+    1342, 1343, 1344, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 1345, 128, 128, 128, 1346,
+    1347, 1348, 1349, 1350, 1351, 1346, 1352, 1346, 1348, 1348, 1353, 128,
+    1354, 128, 1355, 1356, 1354, 128, 1355, 120, 120, 120, 120, 120, 120,
+    1357, 120, 1358, 1359, 1359, 1359, 1359, 1360, 1359, 1359, 1359, 1359,
+    1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1360, 1361, 1359, 1362,
+    1363, 1359, 1363, 1364, 1363, 1359, 1359, 1359, 1365, 1361, 626, 1366,
+    628, 628, 628, 1367, 628, 628, 628, 628, 628, 628, 628, 1368, 628, 628,
+    628, 1369, 1370, 1371, 628, 1372, 1361, 1361, 1361, 1361, 1361, 1361,
+    1373, 1374, 1374, 1374, 1375, 1361, 790, 790, 790, 790, 790, 1376, 790,
+    1377, 1378, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361,
+    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 757,
+    757, 757, 757, 1379, 1380, 1381, 757, 757, 757, 757, 757, 757, 757, 757,
+    1382, 1383, 757, 1384, 1385, 757, 757, 1386, 1387, 1388, 1389, 1384,
+    1359, 757, 757, 1390, 1391, 757, 757, 757, 757, 757, 757, 757, 1392,
+    1393, 1394, 1395, 757, 1396, 1397, 1394, 1398, 1399, 757, 757, 757, 1400,
+    1401, 1402, 757, 757, 757, 757, 757, 757, 757, 757, 1403, 1404, 757,
+    1405, 649, 1406, 757, 1407, 1408, 579, 1409, 757, 757, 757, 1359, 1410,
+    1411, 1359, 1359, 1412, 1359, 1358, 1359, 1359, 1359, 1359, 1359, 1413,
+    1414, 1359, 1359, 1413, 1415, 757, 757, 757, 757, 757, 757, 757, 757,
+    1416, 1417, 579, 579, 579, 579, 1418, 1419, 757, 757, 757, 757, 1420,
+    757, 1421, 757, 1422, 1358, 1423, 1361, 1359, 1424, 1425, 1361, 579, 579,
+    579, 579, 579, 579, 579, 579, 579, 579, 579, 579, 579, 579, 1426, 1361,
+    579, 579, 579, 579, 579, 579, 579, 579, 579, 579, 1427, 1361, 1361, 1361,
+    1361, 1361, 579, 1426, 579, 579, 579, 579, 579, 579, 579, 1361, 579,
+    1428, 579, 579, 579, 579, 579, 1361, 579, 579, 579, 1429, 1361, 1361,
+    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 757, 1430,
+    1431, 1361, 1432, 1433, 757, 1434, 757, 1435, 1361, 1361, 1361, 1361,
+    757, 757, 1436, 1361, 1361, 1361, 1361, 1361, 1437, 1361, 1361, 1361,
+    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361,
+    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361,
+    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361,
+    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361,
+    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361,
+    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1438, 808, 808, 808, 808, 808,
+    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808,
+    808, 808, 808, 808, 808, 808, 808, 1439, 810, 810, 810, 810, 810, 808,
+    808, 808, 808, 808, 808, 1440, 810, 808, 808, 808, 808, 808, 808, 808,
+    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808,
+    808, 808, 808, 808, 808, 808, 809, 808, 808, 808, 808, 808, 808, 808,
+    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808,
+    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808,
+    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 917,
+    810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810,
+    810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810,
+    810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810,
+    810, 808, 808, 808, 809, 810, 810, 810, 810, 810, 810, 810, 810, 810,
+    810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810,
+    810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810,
+    810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810,
+    810, 810, 810, 810, 810, 810, 810, 810, 1441, 1442, 120, 120, 120, 1443,
+    1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 120,
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+    120, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+    932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932,
+    932, 932, 932, 120, 120, 916, 916, 916, 916, 916, 916, 916, 916, 916,
+    916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916,
+    916, 916, 916, 916, 916, 916, 916, 916, 1444,
+};
+
+static const unsigned short index2[] = {
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 1, 1, 1, 1, 1, 1, 7, 7, 7, 8,
+    9, 10, 11, 12, 13, 14, 15, 11, 16, 17, 15, 18, 19, 20, 19, 21, 22, 22,
+    22, 22, 22, 22, 22, 22, 22, 22, 19, 23, 24, 25, 24, 10, 15, 26, 26, 26,
+    26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 16, 27, 17,
+    28, 29, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+    30, 30, 30, 16, 31, 32, 25, 1, 1, 1, 1, 1, 1, 33, 1, 1, 34, 35, 36, 13,
+    37, 13, 38, 39, 40, 41, 42, 43, 25, 44, 45, 28, 46, 47, 48, 48, 49, 50,
+    39, 39, 40, 48, 42, 51, 52, 52, 52, 35, 53, 53, 53, 53, 53, 53, 54, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 54, 53, 53, 53, 53, 53, 53, 55, 54, 53,
+    53, 53, 53, 53, 54, 56, 56, 56, 57, 57, 57, 57, 56, 57, 56, 56, 56, 57,
+    56, 56, 57, 57, 56, 57, 56, 56, 57, 57, 57, 55, 56, 56, 56, 57, 56, 57,
+    56, 57, 53, 56, 53, 57, 53, 57, 53, 57, 53, 57, 53, 57, 53, 57, 53, 57,
+    53, 56, 53, 56, 53, 57, 53, 57, 53, 57, 53, 56, 53, 57, 53, 57, 53, 57,
+    53, 57, 53, 57, 54, 56, 53, 56, 54, 56, 53, 57, 53, 57, 56, 53, 57, 53,
+    57, 53, 57, 54, 56, 54, 56, 53, 56, 53, 57, 53, 56, 56, 54, 56, 53, 56,
+    53, 57, 53, 57, 54, 56, 53, 57, 53, 57, 53, 53, 57, 53, 57, 53, 57, 57,
+    57, 53, 53, 57, 53, 57, 53, 53, 57, 53, 53, 53, 57, 57, 53, 53, 53, 53,
+    57, 53, 53, 57, 53, 53, 53, 57, 57, 57, 53, 53, 57, 53, 53, 57, 53, 57,
+    53, 57, 53, 53, 57, 53, 57, 57, 53, 57, 53, 53, 57, 53, 53, 53, 57, 53,
+    57, 53, 53, 57, 57, 58, 53, 57, 57, 57, 58, 58, 58, 58, 53, 59, 57, 53,
+    59, 57, 53, 59, 57, 53, 56, 53, 56, 53, 56, 53, 56, 53, 56, 53, 56, 53,
+    56, 53, 56, 57, 53, 57, 57, 53, 59, 57, 53, 57, 53, 53, 53, 57, 53, 57,
+    57, 57, 57, 57, 57, 57, 53, 53, 57, 53, 53, 57, 57, 53, 57, 53, 53, 53,
+    53, 57, 57, 56, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 58, 57, 57, 57, 60, 60, 60, 60, 60, 60, 60, 60, 60, 61,
+    61, 62, 62, 62, 62, 62, 62, 62, 63, 63, 64, 63, 61, 65, 66, 65, 65, 65,
+    66, 65, 61, 61, 67, 62, 63, 63, 63, 63, 63, 63, 40, 40, 40, 40, 63, 40,
+    63, 49, 60, 60, 60, 60, 60, 63, 63, 63, 63, 63, 68, 68, 61, 63, 62, 63,
+    63, 63, 63, 63, 63, 63, 63, 63, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+    69, 69, 69, 70, 71, 71, 71, 71, 70, 72, 71, 71, 71, 71, 71, 73, 73, 71,
+    71, 71, 71, 73, 73, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 74, 74,
+    74, 74, 74, 71, 71, 71, 71, 69, 69, 69, 69, 69, 69, 69, 69, 75, 69, 71,
+    71, 71, 69, 69, 69, 71, 71, 76, 69, 69, 69, 71, 71, 71, 71, 69, 70, 71,
+    71, 69, 77, 78, 78, 77, 78, 78, 77, 69, 69, 69, 69, 69, 79, 80, 79, 80,
+    61, 81, 79, 80, 82, 82, 83, 80, 80, 80, 84, 79, 82, 82, 82, 82, 81, 63,
+    79, 85, 79, 79, 79, 82, 79, 82, 79, 79, 80, 86, 86, 86, 86, 86, 86, 86,
+    86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 82, 86, 86, 86, 86, 86, 86, 86,
+    79, 79, 80, 80, 80, 80, 80, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
+    87, 87, 87, 87, 87, 87, 80, 87, 87, 87, 87, 87, 87, 87, 80, 80, 80, 80,
+    80, 79, 80, 80, 79, 79, 79, 80, 80, 80, 79, 80, 79, 80, 79, 80, 79, 80,
+    79, 80, 88, 89, 88, 89, 88, 89, 88, 89, 88, 89, 88, 89, 88, 89, 80, 80,
+    80, 80, 79, 80, 90, 79, 80, 79, 79, 80, 80, 79, 79, 79, 91, 92, 91, 91,
+    91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92,
+    92, 92, 93, 93, 93, 93, 93, 93, 93, 93, 94, 93, 94, 94, 94, 94, 94, 94,
+    94, 94, 94, 94, 94, 94, 94, 94, 91, 94, 91, 94, 91, 94, 91, 94, 91, 94,
+    95, 96, 96, 97, 97, 96, 98, 98, 91, 94, 91, 94, 91, 94, 91, 91, 94, 91,
+    94, 91, 94, 91, 94, 91, 94, 91, 94, 91, 94, 94, 82, 99, 99, 99, 99, 99,
+    99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 82,
+    82, 100, 101, 101, 101, 101, 101, 101, 82, 102, 102, 102, 102, 102, 102,
+    102, 102, 102, 102, 102, 102, 102, 102, 102, 82, 103, 104, 82, 82, 105,
+    105, 106, 82, 107, 108, 108, 108, 108, 107, 108, 108, 108, 109, 107, 108,
+    108, 108, 108, 108, 108, 107, 107, 107, 107, 107, 107, 108, 108, 107,
+    108, 108, 109, 110, 108, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+    120, 120, 121, 122, 123, 124, 125, 126, 127, 128, 126, 108, 107, 129,
+    119, 82, 82, 82, 82, 82, 82, 82, 82, 130, 130, 130, 130, 130, 130, 130,
+    130, 130, 130, 130, 82, 82, 82, 82, 82, 130, 130, 130, 126, 126, 82, 82,
+    82, 131, 131, 131, 131, 131, 132, 133, 133, 134, 135, 135, 136, 137, 138,
+    139, 139, 140, 140, 140, 140, 140, 140, 140, 140, 141, 142, 143, 144,
+    145, 82, 146, 144, 147, 147, 147, 147, 147, 147, 147, 147, 148, 147, 147,
+    147, 147, 147, 147, 147, 147, 147, 147, 149, 150, 151, 152, 153, 154,
+    155, 156, 97, 97, 157, 158, 140, 140, 140, 140, 140, 158, 140, 140, 158,
+    159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 135, 160, 160, 161,
+    147, 147, 162, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+    146, 147, 140, 140, 140, 140, 140, 140, 140, 132, 139, 140, 140, 140,
+    140, 158, 140, 163, 163, 140, 140, 139, 158, 140, 140, 158, 147, 147,
+    164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 147, 147, 147, 165,
+    165, 147, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166,
+    166, 166, 82, 167, 168, 169, 168, 168, 168, 168, 168, 168, 168, 168, 168,
+    168, 168, 168, 168, 168, 170, 171, 170, 170, 171, 170, 170, 171, 171,
+    171, 170, 171, 171, 170, 171, 170, 170, 170, 171, 170, 171, 170, 171,
+    170, 171, 170, 170, 82, 82, 168, 168, 168, 172, 172, 172, 172, 172, 172,
+    172, 172, 172, 172, 172, 172, 172, 172, 173, 173, 173, 173, 173, 173,
+    173, 173, 173, 173, 173, 172, 82, 82, 82, 82, 82, 82, 174, 174, 174, 174,
+    174, 174, 174, 174, 174, 174, 175, 175, 175, 175, 175, 175, 175, 175,
+    175, 175, 175, 175, 175, 175, 175, 175, 175, 176, 176, 176, 176, 176,
+    176, 176, 177, 176, 178, 178, 179, 180, 181, 182, 178, 82, 82, 82, 82,
+    82, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183,
+    184, 184, 184, 184, 185, 184, 184, 184, 184, 184, 184, 184, 184, 184,
+    185, 184, 184, 184, 185, 184, 184, 184, 184, 184, 82, 82, 186, 186, 186,
+    186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 82, 187, 187,
+    187, 187, 187, 187, 187, 187, 187, 188, 188, 188, 82, 82, 189, 82, 147,
+    147, 147, 147, 147, 82, 147, 147, 147, 147, 147, 147, 147, 147, 82, 82,
+    82, 82, 82, 82, 140, 140, 140, 140, 140, 140, 132, 158, 140, 140, 158,
+    140, 140, 158, 140, 140, 140, 158, 158, 158, 190, 191, 192, 140, 140,
+    140, 158, 140, 140, 158, 158, 140, 140, 140, 140, 140, 193, 193, 193,
+    194, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195,
+    195, 193, 194, 196, 195, 194, 194, 194, 193, 193, 193, 193, 193, 193,
+    193, 193, 194, 194, 194, 194, 197, 194, 194, 195, 97, 157, 198, 198, 193,
+    193, 193, 195, 195, 193, 193, 199, 199, 200, 200, 200, 200, 200, 200,
+    200, 200, 200, 200, 201, 202, 195, 195, 195, 195, 195, 195, 203, 204,
+    205, 205, 82, 203, 203, 203, 203, 203, 203, 203, 203, 82, 82, 203, 203,
+    82, 82, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
+    203, 82, 203, 203, 203, 203, 203, 203, 203, 82, 203, 82, 82, 82, 203,
+    203, 203, 203, 82, 82, 206, 203, 205, 205, 205, 204, 204, 204, 204, 82,
+    82, 205, 205, 82, 82, 205, 205, 207, 203, 82, 82, 82, 82, 82, 82, 82, 82,
+    205, 82, 82, 82, 82, 203, 203, 82, 203, 203, 203, 204, 204, 82, 82, 208,
+    208, 208, 208, 208, 208, 208, 208, 208, 208, 203, 203, 209, 209, 210,
+    210, 210, 210, 210, 211, 212, 213, 82, 82, 82, 82, 82, 214, 214, 215, 82,
+    216, 216, 216, 216, 216, 216, 82, 82, 82, 82, 216, 216, 82, 82, 216, 216,
+    216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 82, 216, 216,
+    216, 216, 216, 216, 216, 82, 216, 216, 82, 216, 216, 82, 216, 216, 82,
+    82, 217, 82, 215, 215, 215, 214, 214, 82, 82, 82, 82, 214, 214, 82, 82,
+    214, 214, 218, 82, 82, 82, 214, 82, 82, 82, 82, 82, 82, 82, 216, 216,
+    216, 216, 82, 216, 82, 82, 82, 82, 82, 82, 82, 219, 219, 219, 219, 219,
+    219, 219, 219, 219, 219, 214, 214, 216, 216, 216, 214, 82, 82, 82, 220,
+    220, 221, 82, 222, 222, 222, 222, 222, 222, 222, 222, 222, 82, 222, 222,
+    222, 82, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222,
+    222, 82, 222, 222, 222, 222, 222, 222, 222, 82, 222, 222, 82, 222, 222,
+    222, 222, 222, 82, 82, 223, 222, 221, 221, 221, 220, 220, 220, 220, 220,
+    82, 220, 220, 221, 82, 221, 221, 224, 82, 82, 222, 82, 82, 82, 82, 82,
+    82, 82, 222, 222, 220, 220, 82, 82, 225, 225, 225, 225, 225, 225, 225,
+    225, 225, 225, 226, 227, 82, 82, 82, 82, 82, 82, 82, 222, 82, 82, 82, 82,
+    82, 82, 82, 228, 229, 229, 82, 230, 230, 230, 230, 230, 230, 230, 230,
+    82, 82, 230, 230, 82, 82, 230, 230, 230, 230, 230, 230, 230, 230, 230,
+    230, 230, 230, 230, 230, 82, 230, 230, 230, 230, 230, 230, 230, 82, 230,
+    230, 82, 230, 230, 230, 230, 230, 82, 82, 231, 230, 229, 228, 229, 228,
+    228, 228, 228, 82, 82, 229, 229, 82, 82, 229, 229, 232, 82, 82, 82, 82,
+    82, 82, 82, 82, 228, 229, 82, 82, 82, 82, 230, 230, 82, 230, 230, 230,
+    228, 228, 82, 82, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 234,
+    230, 235, 235, 235, 235, 235, 235, 82, 82, 236, 237, 82, 237, 237, 237,
+    237, 237, 237, 82, 82, 82, 237, 237, 237, 82, 237, 237, 237, 237, 82, 82,
+    82, 237, 237, 82, 237, 82, 237, 237, 82, 82, 82, 237, 237, 82, 82, 82,
+    237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 82, 82, 82, 82, 238,
+    238, 236, 238, 238, 82, 82, 82, 238, 238, 238, 82, 238, 238, 238, 239,
+    82, 82, 237, 82, 82, 82, 82, 82, 82, 238, 82, 82, 82, 82, 82, 82, 240,
+    240, 240, 240, 240, 240, 240, 240, 240, 240, 241, 241, 241, 242, 242,
+    242, 242, 242, 242, 243, 242, 82, 82, 82, 82, 82, 244, 245, 245, 245, 82,
+    246, 246, 246, 246, 246, 246, 246, 246, 82, 246, 246, 246, 82, 246, 246,
+    246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 82,
+    82, 82, 246, 244, 244, 244, 245, 245, 245, 245, 82, 244, 244, 244, 82,
+    244, 244, 244, 247, 82, 82, 82, 82, 82, 82, 82, 248, 249, 82, 246, 246,
+    246, 82, 82, 82, 82, 82, 246, 246, 244, 244, 82, 82, 250, 250, 250, 250,
+    250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251, 251, 251, 252,
+    253, 254, 255, 255, 82, 253, 253, 253, 253, 253, 253, 253, 253, 82, 253,
+    253, 253, 82, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253,
+    253, 253, 253, 253, 253, 253, 82, 253, 253, 253, 253, 253, 82, 82, 256,
+    253, 255, 257, 255, 255, 255, 255, 255, 82, 257, 255, 255, 82, 255, 255,
+    254, 258, 82, 82, 82, 82, 82, 82, 82, 255, 255, 82, 82, 82, 82, 82, 82,
+    82, 253, 82, 253, 253, 254, 254, 82, 82, 259, 259, 259, 259, 259, 259,
+    259, 259, 259, 259, 82, 253, 253, 82, 82, 82, 82, 82, 82, 260, 261, 261,
+    82, 262, 262, 262, 262, 262, 262, 262, 262, 82, 262, 262, 262, 82, 262,
+    262, 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, 262,
+    262, 262, 82, 82, 262, 261, 261, 261, 260, 260, 260, 260, 82, 261, 261,
+    261, 82, 261, 261, 261, 263, 262, 264, 82, 82, 82, 82, 262, 262, 262,
+    261, 265, 265, 265, 265, 265, 265, 265, 262, 262, 262, 260, 260, 82, 82,
+    266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 265, 265, 265, 265,
+    265, 265, 265, 265, 265, 267, 262, 262, 262, 262, 262, 262, 82, 82, 268,
+    268, 82, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269,
+    269, 269, 269, 269, 269, 82, 82, 82, 269, 269, 269, 269, 269, 269, 269,
+    269, 82, 269, 269, 269, 269, 269, 269, 269, 269, 269, 82, 269, 82, 82,
+    82, 82, 270, 82, 82, 82, 82, 268, 268, 268, 271, 271, 271, 82, 271, 82,
+    268, 268, 268, 268, 268, 268, 268, 268, 82, 82, 82, 82, 82, 82, 272, 272,
+    272, 272, 272, 272, 272, 272, 272, 272, 82, 82, 268, 268, 273, 82, 82,
+    82, 82, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274,
+    274, 274, 274, 275, 274, 274, 275, 275, 275, 275, 276, 276, 277, 82, 82,
+    82, 82, 278, 274, 274, 274, 274, 274, 274, 279, 275, 280, 280, 280, 280,
+    275, 275, 275, 281, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282,
+    283, 283, 82, 82, 82, 82, 82, 284, 284, 82, 284, 82, 82, 284, 284, 82,
+    284, 82, 82, 284, 82, 82, 82, 82, 82, 82, 284, 284, 284, 284, 82, 284,
+    284, 284, 284, 284, 284, 284, 82, 284, 284, 284, 82, 284, 82, 284, 82,
+    82, 284, 284, 82, 284, 284, 284, 284, 285, 284, 284, 285, 285, 285, 285,
+    286, 286, 82, 285, 285, 284, 82, 82, 284, 284, 284, 284, 284, 82, 287,
+    82, 288, 288, 288, 288, 285, 285, 82, 82, 289, 289, 289, 289, 289, 289,
+    289, 289, 289, 289, 82, 82, 284, 284, 284, 284, 290, 291, 291, 291, 292,
+    293, 292, 292, 294, 292, 292, 295, 294, 296, 296, 296, 296, 296, 294,
+    297, 296, 297, 297, 297, 298, 298, 297, 297, 297, 297, 297, 297, 299,
+    299, 299, 299, 299, 299, 299, 299, 299, 299, 300, 300, 300, 300, 300,
+    300, 300, 300, 300, 300, 301, 298, 297, 298, 297, 302, 303, 304, 303,
+    304, 305, 305, 290, 290, 290, 290, 290, 290, 290, 290, 82, 290, 290, 290,
+    290, 290, 290, 290, 290, 290, 290, 290, 290, 82, 82, 82, 82, 306, 307,
+    308, 309, 308, 308, 308, 308, 308, 307, 307, 307, 307, 308, 310, 307,
+    308, 311, 311, 312, 295, 311, 311, 290, 290, 290, 290, 290, 308, 308,
+    308, 308, 308, 308, 308, 308, 308, 308, 308, 82, 308, 308, 308, 308, 308,
+    308, 308, 308, 308, 308, 308, 308, 82, 301, 301, 297, 297, 297, 297, 297,
+    297, 298, 297, 297, 297, 297, 297, 297, 82, 297, 297, 292, 292, 295, 292,
+    293, 313, 313, 313, 313, 294, 294, 82, 82, 82, 82, 82, 314, 314, 314,
+    314, 314, 314, 314, 314, 314, 314, 314, 315, 315, 316, 316, 316, 316,
+    315, 316, 316, 316, 316, 316, 317, 315, 318, 318, 315, 315, 316, 316,
+    314, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 320, 320, 321,
+    321, 321, 321, 314, 314, 314, 314, 314, 314, 315, 315, 316, 316, 314,
+    314, 314, 314, 316, 316, 316, 314, 315, 315, 315, 314, 314, 315, 315,
+    315, 315, 315, 315, 315, 314, 314, 314, 316, 316, 316, 316, 314, 314,
+    314, 314, 314, 316, 315, 315, 316, 316, 315, 315, 315, 315, 315, 315,
+    322, 314, 315, 319, 319, 315, 315, 315, 316, 323, 323, 324, 324, 324,
+    324, 324, 324, 324, 324, 324, 324, 324, 324, 324, 324, 82, 324, 82, 82,
+    82, 82, 82, 324, 82, 82, 325, 325, 325, 325, 325, 325, 325, 325, 325,
+    325, 325, 326, 327, 325, 325, 325, 328, 328, 328, 328, 328, 328, 328,
+    328, 329, 329, 329, 329, 329, 329, 329, 329, 330, 330, 330, 330, 330,
+    330, 330, 330, 331, 331, 331, 331, 331, 331, 331, 331, 331, 82, 331, 331,
+    331, 331, 82, 82, 331, 331, 331, 331, 331, 331, 331, 82, 331, 331, 331,
+    82, 82, 332, 332, 332, 333, 334, 333, 333, 333, 333, 333, 333, 333, 335,
+    335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335,
+    335, 335, 335, 335, 335, 82, 82, 82, 336, 336, 336, 336, 336, 336, 336,
+    336, 336, 336, 82, 82, 82, 82, 82, 82, 337, 337, 337, 337, 337, 337, 337,
+    337, 337, 337, 337, 337, 337, 337, 82, 82, 338, 338, 338, 338, 338, 338,
+    82, 82, 339, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+    340, 340, 340, 340, 340, 340, 340, 340, 341, 341, 340, 342, 343, 343,
+    343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343,
+    343, 343, 344, 345, 82, 82, 82, 346, 346, 346, 346, 346, 346, 346, 346,
+    346, 346, 346, 199, 199, 199, 347, 347, 347, 346, 346, 346, 346, 346,
+    346, 346, 346, 82, 82, 82, 82, 82, 82, 82, 348, 348, 348, 348, 348, 348,
+    348, 348, 348, 348, 348, 348, 348, 82, 348, 348, 348, 348, 349, 349, 350,
+    82, 82, 82, 351, 351, 351, 351, 351, 351, 351, 351, 351, 351, 352, 352,
+    353, 199, 199, 82, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 355,
+    355, 82, 82, 82, 82, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356,
+    356, 356, 356, 82, 356, 356, 356, 82, 357, 357, 82, 82, 82, 82, 358, 358,
+    358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 359, 359, 360, 359,
+    359, 359, 359, 359, 359, 359, 360, 360, 360, 360, 360, 360, 360, 360,
+    359, 360, 360, 359, 359, 359, 359, 359, 359, 359, 359, 359, 361, 359,
+    362, 362, 363, 364, 362, 365, 362, 366, 358, 367, 82, 82, 368, 368, 368,
+    368, 368, 368, 368, 368, 368, 368, 82, 82, 82, 82, 82, 82, 369, 369, 369,
+    369, 369, 369, 369, 369, 369, 369, 82, 82, 82, 82, 82, 82, 370, 370, 371,
+    371, 372, 373, 374, 370, 375, 375, 370, 376, 376, 376, 377, 82, 378, 378,
+    378, 378, 378, 378, 378, 378, 378, 378, 82, 82, 82, 82, 82, 82, 379, 379,
+    379, 379, 379, 379, 379, 379, 379, 379, 379, 380, 379, 379, 379, 379,
+    379, 379, 379, 379, 379, 376, 376, 379, 379, 381, 379, 82, 82, 82, 82,
+    82, 340, 340, 340, 340, 340, 340, 82, 82, 382, 382, 382, 382, 382, 382,
+    382, 382, 382, 382, 382, 382, 382, 382, 382, 82, 383, 383, 383, 384, 384,
+    384, 384, 383, 383, 384, 384, 384, 82, 82, 82, 82, 384, 384, 383, 384,
+    384, 384, 384, 384, 384, 385, 386, 387, 82, 82, 82, 82, 388, 82, 82, 82,
+    389, 389, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 391, 391,
+    391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 82, 82, 391,
+    391, 391, 391, 391, 82, 82, 82, 392, 392, 392, 392, 392, 392, 392, 392,
+    392, 392, 392, 392, 82, 82, 82, 82, 392, 392, 82, 82, 82, 82, 82, 82,
+    393, 393, 393, 393, 393, 393, 393, 393, 393, 393, 394, 82, 82, 82, 395,
+    395, 396, 396, 396, 396, 396, 396, 396, 396, 397, 397, 397, 397, 397,
+    397, 397, 397, 397, 397, 397, 397, 397, 397, 397, 398, 399, 400, 400,
+    401, 82, 82, 402, 402, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403,
+    403, 403, 403, 404, 405, 404, 405, 405, 405, 405, 405, 405, 405, 82, 406,
+    404, 405, 404, 404, 405, 405, 405, 405, 405, 405, 405, 405, 404, 404,
+    404, 404, 404, 404, 405, 405, 407, 407, 407, 407, 407, 407, 407, 407, 82,
+    82, 408, 409, 409, 409, 409, 409, 409, 409, 409, 409, 409, 82, 82, 82,
+    82, 82, 82, 410, 410, 410, 410, 410, 410, 410, 411, 410, 410, 410, 410,
+    410, 410, 82, 82, 97, 97, 97, 97, 97, 157, 157, 157, 157, 157, 157, 97,
+    97, 157, 412, 82, 413, 413, 413, 413, 414, 415, 415, 415, 415, 415, 415,
+    415, 415, 415, 415, 415, 415, 415, 415, 415, 416, 414, 413, 413, 413,
+    413, 413, 414, 413, 414, 414, 414, 414, 414, 413, 414, 417, 415, 415,
+    415, 415, 415, 415, 415, 82, 82, 82, 82, 418, 418, 418, 418, 418, 418,
+    418, 418, 418, 418, 419, 419, 420, 419, 419, 419, 419, 421, 421, 421,
+    421, 421, 421, 421, 421, 421, 421, 422, 423, 422, 422, 422, 422, 422,
+    422, 422, 421, 421, 421, 421, 421, 421, 421, 421, 421, 82, 82, 82, 424,
+    424, 425, 426, 426, 426, 426, 426, 426, 426, 426, 426, 426, 426, 426,
+    426, 426, 425, 424, 424, 424, 424, 425, 425, 424, 424, 427, 428, 424,
+    424, 426, 426, 429, 429, 429, 429, 429, 429, 429, 429, 429, 429, 426,
+    426, 426, 426, 426, 426, 430, 430, 430, 430, 430, 430, 430, 430, 430,
+    430, 430, 430, 430, 430, 431, 432, 433, 433, 432, 432, 432, 433, 432,
+    433, 433, 433, 434, 434, 82, 82, 82, 82, 82, 82, 82, 82, 435, 435, 435,
+    435, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 437,
+    437, 437, 437, 437, 437, 437, 437, 438, 438, 438, 438, 438, 438, 438,
+    438, 437, 437, 438, 439, 82, 82, 82, 440, 440, 440, 440, 440, 441, 441,
+    441, 441, 441, 441, 441, 441, 441, 441, 82, 82, 82, 436, 436, 436, 442,
+    442, 442, 442, 442, 442, 442, 442, 442, 442, 443, 443, 443, 443, 443,
+    443, 443, 443, 443, 443, 443, 443, 443, 443, 444, 444, 444, 444, 444,
+    444, 445, 445, 94, 82, 82, 82, 82, 82, 82, 82, 446, 446, 446, 446, 446,
+    446, 446, 446, 97, 97, 97, 326, 447, 157, 157, 157, 157, 157, 97, 97,
+    157, 157, 157, 157, 97, 448, 447, 447, 447, 447, 447, 447, 447, 449, 449,
+    449, 449, 157, 449, 449, 449, 449, 448, 448, 97, 449, 449, 82, 97, 97,
+    82, 82, 82, 82, 82, 82, 57, 57, 57, 57, 57, 57, 80, 80, 80, 80, 80, 94,
+    60, 60, 60, 60, 60, 60, 60, 60, 60, 83, 83, 83, 83, 83, 60, 60, 60, 60,
+    83, 83, 83, 83, 83, 57, 57, 57, 57, 57, 450, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 83, 97, 97,
+    157, 97, 97, 97, 97, 97, 97, 97, 157, 97, 97, 451, 452, 157, 453, 97, 97,
+    97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+    97, 82, 82, 82, 82, 82, 97, 454, 157, 97, 157, 53, 57, 53, 57, 53, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 53, 57, 80, 80, 80, 80, 80, 80, 80, 80,
+    79, 79, 79, 79, 79, 79, 79, 79, 80, 80, 80, 80, 80, 80, 82, 82, 79, 79,
+    79, 79, 79, 79, 82, 82, 82, 79, 82, 79, 82, 79, 82, 79, 455, 455, 455,
+    455, 455, 455, 455, 455, 80, 80, 80, 80, 80, 82, 80, 80, 79, 79, 79, 79,
+    455, 81, 80, 81, 81, 81, 80, 80, 80, 82, 80, 80, 79, 79, 79, 79, 455, 81,
+    81, 81, 80, 80, 80, 80, 82, 82, 80, 80, 79, 79, 79, 79, 82, 81, 81, 81,
+    79, 79, 79, 79, 79, 81, 81, 81, 82, 82, 80, 80, 80, 82, 80, 80, 79, 79,
+    79, 79, 455, 456, 81, 82, 457, 457, 457, 457, 457, 457, 457, 458, 457,
+    457, 457, 459, 460, 461, 462, 463, 464, 465, 466, 464, 467, 468, 39, 85,
+    469, 470, 471, 472, 469, 470, 471, 472, 39, 39, 473, 85, 474, 474, 474,
+    475, 476, 477, 478, 479, 480, 481, 482, 34, 483, 484, 483, 483, 484, 485,
+    486, 486, 85, 43, 51, 39, 487, 487, 473, 488, 488, 85, 85, 85, 489, 490,
+    491, 487, 487, 487, 85, 85, 85, 85, 85, 85, 85, 85, 492, 85, 488, 85,
+    373, 85, 373, 373, 373, 373, 85, 373, 373, 457, 493, 494, 494, 494, 494,
+    82, 495, 496, 497, 498, 499, 499, 499, 499, 499, 499, 500, 60, 82, 82,
+    48, 500, 500, 500, 500, 500, 501, 501, 492, 490, 491, 502, 500, 48, 48,
+    48, 48, 500, 500, 500, 500, 500, 501, 501, 492, 490, 491, 82, 60, 60, 60,
+    60, 60, 82, 82, 82, 278, 278, 278, 278, 278, 278, 278, 503, 278, 504,
+    278, 278, 37, 278, 278, 278, 278, 278, 278, 278, 278, 278, 503, 278, 278,
+    278, 278, 503, 278, 278, 503, 505, 505, 505, 505, 505, 505, 505, 505,
+    505, 97, 97, 447, 447, 97, 97, 97, 97, 447, 447, 447, 97, 97, 412, 412,
+    412, 412, 97, 412, 412, 412, 447, 447, 97, 157, 97, 447, 447, 157, 157,
+    157, 157, 97, 82, 82, 82, 82, 82, 82, 82, 41, 41, 506, 507, 41, 508, 41,
+    506, 41, 507, 50, 506, 506, 506, 50, 50, 506, 506, 506, 509, 41, 506,
+    510, 41, 492, 506, 506, 506, 506, 506, 41, 41, 41, 508, 508, 41, 506, 41,
+    86, 41, 506, 41, 53, 511, 506, 506, 512, 50, 506, 506, 53, 506, 50, 449,
+    449, 449, 449, 50, 41, 41, 50, 50, 506, 506, 513, 492, 492, 492, 492,
+    506, 50, 50, 50, 50, 41, 492, 41, 41, 57, 313, 514, 514, 514, 515, 52,
+    516, 514, 514, 514, 514, 514, 52, 515, 515, 52, 514, 517, 517, 517, 517,
+    517, 517, 517, 517, 517, 517, 517, 517, 518, 518, 518, 518, 517, 517,
+    518, 518, 518, 518, 518, 518, 518, 518, 518, 53, 57, 518, 518, 518, 518,
+    52, 41, 41, 82, 82, 82, 82, 55, 55, 55, 55, 55, 508, 508, 508, 508, 508,
+    492, 492, 41, 41, 41, 41, 492, 41, 41, 492, 41, 41, 492, 41, 41, 41, 41,
+    41, 41, 41, 492, 41, 41, 41, 41, 41, 41, 41, 41, 41, 45, 45, 41, 41, 41,
+    41, 41, 41, 41, 41, 41, 41, 41, 41, 492, 492, 41, 41, 55, 41, 55, 41, 41,
+    41, 41, 41, 41, 41, 41, 41, 41, 45, 41, 41, 41, 41, 492, 492, 492, 492,
+    492, 492, 492, 492, 492, 492, 492, 492, 55, 513, 519, 519, 513, 492, 492,
+    55, 519, 513, 513, 519, 513, 513, 492, 55, 492, 519, 520, 521, 492, 519,
+    513, 492, 492, 492, 519, 513, 513, 519, 55, 519, 519, 513, 513, 55, 513,
+    55, 513, 55, 55, 55, 55, 519, 519, 513, 519, 513, 513, 513, 513, 513, 55,
+    55, 55, 55, 492, 513, 492, 513, 519, 519, 513, 513, 513, 513, 513, 513,
+    513, 513, 513, 513, 519, 513, 513, 513, 519, 492, 492, 492, 492, 492,
+    519, 513, 513, 513, 492, 492, 492, 492, 492, 492, 492, 492, 492, 513,
+    519, 55, 513, 492, 519, 519, 519, 519, 513, 513, 519, 519, 492, 492, 519,
+    519, 513, 513, 519, 519, 513, 513, 519, 519, 513, 513, 513, 513, 513,
+    492, 492, 513, 513, 513, 513, 492, 492, 55, 492, 492, 513, 55, 492, 492,
+    492, 492, 492, 492, 492, 492, 513, 513, 492, 55, 513, 513, 513, 492, 492,
+    492, 492, 492, 513, 519, 492, 513, 513, 513, 513, 513, 492, 492, 513,
+    513, 492, 492, 492, 492, 513, 513, 513, 513, 513, 513, 513, 513, 492,
+    522, 490, 491, 490, 491, 41, 41, 41, 41, 41, 41, 508, 41, 41, 41, 41, 41,
+    41, 41, 523, 523, 41, 41, 41, 41, 513, 513, 41, 41, 41, 41, 41, 41, 41,
+    524, 525, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 313, 313, 313, 313,
+    313, 313, 313, 313, 313, 313, 313, 313, 313, 41, 492, 41, 41, 41, 41, 41,
+    41, 41, 41, 313, 41, 41, 41, 41, 41, 492, 492, 492, 492, 492, 492, 492,
+    492, 492, 41, 41, 41, 41, 492, 492, 41, 41, 41, 41, 41, 41, 41, 526, 526,
+    526, 526, 41, 41, 41, 523, 527, 527, 523, 41, 41, 41, 41, 41, 41, 41, 41,
+    41, 41, 41, 82, 41, 41, 41, 82, 82, 82, 82, 82, 52, 52, 52, 52, 52, 52,
+    52, 52, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 528, 528, 528,
+    528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 516, 52, 52, 52,
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 515, 508, 508, 508, 508, 508, 508,
+    508, 508, 508, 508, 508, 508, 41, 41, 41, 41, 508, 508, 508, 508, 529,
+    41, 41, 41, 41, 41, 508, 508, 508, 508, 41, 41, 508, 508, 41, 508, 508,
+    508, 508, 508, 508, 508, 41, 41, 41, 41, 41, 41, 41, 41, 508, 508, 41,
+    41, 508, 55, 41, 41, 41, 41, 508, 508, 41, 41, 508, 55, 41, 41, 41, 41,
+    508, 508, 508, 41, 41, 508, 41, 41, 508, 508, 41, 41, 41, 41, 41, 41, 41,
+    508, 492, 492, 492, 492, 492, 530, 530, 492, 527, 527, 527, 527, 41, 508,
+    508, 41, 41, 508, 41, 41, 41, 41, 508, 508, 41, 41, 41, 41, 523, 523,
+    529, 529, 527, 41, 527, 527, 531, 532, 531, 527, 41, 527, 527, 527, 41,
+    41, 41, 41, 508, 41, 508, 41, 41, 41, 41, 41, 526, 526, 526, 526, 526,
+    526, 526, 526, 526, 526, 526, 526, 41, 41, 41, 41, 508, 508, 41, 508,
+    508, 508, 41, 508, 531, 508, 508, 41, 508, 508, 41, 55, 41, 41, 41, 41,
+    41, 41, 41, 523, 41, 41, 41, 526, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+    508, 508, 41, 526, 41, 41, 41, 41, 41, 41, 41, 41, 526, 526, 313, 41, 41,
+    41, 41, 41, 41, 41, 41, 523, 523, 531, 527, 527, 527, 527, 523, 523, 531,
+    531, 531, 508, 508, 508, 508, 531, 526, 531, 531, 531, 508, 531, 523,
+    508, 508, 508, 531, 531, 508, 508, 531, 508, 508, 531, 531, 531, 41, 508,
+    41, 41, 41, 41, 508, 508, 523, 508, 508, 508, 508, 508, 508, 531, 523,
+    523, 531, 523, 508, 531, 531, 533, 523, 508, 508, 523, 531, 531, 527,
+    527, 527, 527, 527, 526, 41, 41, 527, 527, 534, 534, 532, 532, 41, 41,
+    526, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 45, 41, 41, 41, 41,
+    41, 41, 526, 41, 526, 41, 41, 41, 41, 526, 526, 526, 41, 535, 41, 41, 41,
+    536, 536, 536, 536, 536, 536, 41, 537, 537, 527, 41, 41, 41, 490, 491,
+    490, 491, 490, 491, 490, 491, 490, 491, 490, 491, 490, 491, 52, 52, 516,
+    516, 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, 41, 526, 526, 526,
+    41, 41, 41, 41, 41, 41, 41, 526, 513, 492, 492, 513, 513, 490, 491, 492,
+    513, 513, 492, 513, 513, 513, 492, 492, 492, 492, 492, 513, 513, 513,
+    513, 492, 492, 492, 492, 492, 513, 513, 513, 492, 492, 492, 513, 513,
+    513, 513, 16, 32, 16, 32, 16, 32, 16, 32, 490, 491, 538, 538, 538, 538,
+    538, 538, 538, 538, 492, 492, 492, 490, 491, 16, 32, 490, 491, 490, 491,
+    490, 491, 490, 491, 490, 491, 492, 492, 513, 513, 513, 513, 513, 513,
+    492, 492, 492, 492, 492, 492, 492, 513, 513, 513, 513, 513, 513, 492,
+    492, 492, 513, 492, 492, 492, 492, 513, 513, 513, 513, 513, 492, 513,
+    513, 492, 492, 490, 491, 490, 491, 513, 492, 492, 492, 492, 513, 492,
+    513, 513, 513, 492, 492, 513, 513, 492, 492, 492, 492, 492, 492, 492,
+    492, 492, 492, 513, 513, 513, 513, 513, 513, 492, 492, 490, 491, 492,
+    492, 492, 492, 513, 513, 513, 513, 513, 513, 513, 513, 513, 513, 513,
+    492, 513, 513, 513, 513, 492, 492, 513, 492, 513, 492, 492, 513, 492,
+    513, 513, 513, 513, 492, 492, 492, 492, 492, 513, 513, 492, 492, 492,
+    492, 513, 513, 513, 513, 492, 513, 513, 492, 492, 513, 513, 492, 492,
+    492, 492, 513, 513, 513, 513, 513, 513, 513, 513, 513, 513, 513, 492,
+    492, 513, 513, 513, 513, 513, 513, 513, 513, 492, 513, 513, 513, 513,
+    513, 513, 513, 513, 492, 492, 492, 492, 492, 513, 492, 513, 492, 492,
+    492, 513, 513, 513, 513, 513, 492, 492, 492, 492, 513, 492, 492, 492,
+    513, 513, 513, 513, 513, 492, 513, 492, 492, 41, 41, 41, 526, 526, 41,
+    41, 41, 492, 492, 492, 492, 492, 41, 41, 492, 492, 492, 492, 492, 492,
+    41, 41, 41, 526, 41, 41, 41, 41, 535, 508, 508, 41, 41, 41, 41, 82, 82,
+    41, 41, 41, 41, 41, 41, 41, 41, 82, 82, 41, 41, 82, 82, 82, 41, 41, 41,
+    41, 82, 41, 41, 41, 41, 41, 41, 41, 41, 82, 82, 82, 82, 82, 82, 82, 82,
+    82, 82, 41, 41, 41, 41, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539,
+    539, 539, 539, 539, 539, 82, 540, 540, 540, 540, 540, 540, 540, 540, 540,
+    540, 540, 540, 540, 540, 540, 82, 53, 57, 53, 53, 53, 57, 57, 53, 57, 53,
+    57, 53, 57, 53, 53, 53, 53, 57, 53, 57, 57, 53, 57, 57, 57, 57, 57, 57,
+    60, 60, 53, 53, 88, 89, 88, 89, 89, 541, 541, 541, 541, 541, 541, 88, 89,
+    88, 89, 542, 542, 542, 88, 89, 82, 82, 82, 82, 82, 543, 544, 544, 544,
+    545, 543, 544, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546,
+    546, 546, 546, 82, 546, 82, 82, 82, 82, 82, 546, 82, 82, 547, 547, 547,
+    547, 547, 547, 547, 547, 82, 82, 82, 82, 82, 82, 82, 548, 549, 82, 82,
+    82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 550, 96, 96, 96, 96, 96,
+    96, 96, 96, 551, 551, 43, 51, 43, 51, 551, 551, 551, 43, 51, 551, 43, 51,
+    373, 373, 373, 373, 373, 373, 373, 373, 85, 466, 552, 373, 553, 85, 43,
+    51, 85, 85, 43, 51, 490, 491, 490, 491, 490, 491, 490, 491, 373, 373,
+    373, 373, 371, 61, 373, 373, 85, 373, 373, 85, 85, 85, 85, 85, 554, 554,
+    373, 373, 373, 85, 466, 373, 471, 373, 373, 82, 82, 82, 555, 555, 555,
+    555, 555, 555, 555, 555, 555, 555, 82, 555, 555, 555, 555, 555, 555, 555,
+    555, 555, 82, 82, 82, 82, 555, 555, 555, 555, 555, 555, 82, 82, 523, 523,
+    523, 523, 523, 523, 523, 523, 523, 523, 523, 523, 82, 82, 82, 82, 556,
+    557, 557, 558, 523, 559, 560, 561, 524, 525, 524, 525, 524, 525, 524,
+    525, 524, 525, 523, 523, 524, 525, 524, 525, 524, 525, 524, 525, 562,
+    563, 564, 564, 523, 561, 561, 561, 561, 561, 561, 561, 561, 561, 565,
+    566, 567, 568, 569, 569, 570, 571, 571, 571, 571, 572, 523, 523, 561,
+    561, 561, 559, 573, 558, 523, 527, 82, 574, 575, 574, 575, 574, 575, 574,
+    575, 574, 575, 575, 575, 575, 575, 575, 575, 575, 575, 575, 575, 575,
+    575, 575, 575, 575, 575, 574, 575, 575, 575, 575, 575, 575, 575, 574,
+    575, 574, 575, 574, 575, 575, 575, 575, 575, 575, 574, 575, 575, 575,
+    575, 575, 575, 574, 574, 82, 82, 576, 576, 577, 577, 578, 578, 575, 562,
+    579, 580, 579, 580, 579, 580, 579, 580, 579, 580, 580, 580, 580, 580,
+    580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 579, 580,
+    580, 580, 580, 580, 580, 580, 579, 580, 579, 580, 579, 580, 580, 580,
+    580, 580, 580, 579, 580, 580, 580, 580, 580, 580, 579, 579, 580, 580,
+    580, 580, 581, 582, 583, 583, 580, 82, 82, 82, 82, 82, 584, 584, 584,
+    584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 82,
+    82, 82, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585,
+    585, 585, 585, 585, 585, 585, 585, 585, 585, 82, 586, 586, 587, 587, 587,
+    587, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 584, 584, 584, 82,
+    82, 82, 82, 82, 579, 579, 579, 579, 579, 579, 579, 579, 588, 588, 588,
+    588, 588, 588, 588, 588, 588, 588, 588, 588, 588, 589, 589, 82, 587, 587,
+    587, 587, 587, 587, 587, 587, 587, 587, 586, 586, 586, 586, 586, 586,
+    590, 590, 590, 590, 590, 590, 590, 590, 523, 591, 591, 591, 591, 591,
+    591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 588, 588, 588, 588,
+    589, 589, 589, 586, 586, 591, 591, 591, 591, 591, 591, 591, 586, 586,
+    586, 586, 523, 523, 523, 523, 592, 592, 592, 592, 592, 592, 592, 592,
+    592, 592, 592, 592, 592, 592, 592, 82, 586, 586, 586, 586, 586, 586, 586,
+    523, 523, 523, 523, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586,
+    586, 523, 523, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593,
+    593, 593, 593, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 595,
+    595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 596, 595,
+    595, 595, 595, 595, 595, 595, 82, 82, 82, 597, 597, 597, 597, 597, 597,
+    597, 597, 597, 597, 597, 597, 597, 597, 597, 82, 598, 598, 598, 598, 598,
+    598, 598, 598, 599, 599, 599, 599, 599, 599, 600, 600, 601, 601, 601,
+    601, 601, 601, 601, 601, 601, 601, 601, 601, 602, 603, 604, 603, 605,
+    605, 605, 605, 605, 605, 605, 605, 605, 605, 601, 601, 82, 82, 82, 82,
+    91, 94, 91, 94, 91, 94, 606, 96, 98, 98, 98, 607, 96, 96, 96, 96, 96, 96,
+    96, 96, 96, 96, 607, 608, 91, 94, 91, 94, 450, 450, 96, 96, 609, 609,
+    609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 610, 610,
+    610, 610, 610, 610, 610, 610, 610, 610, 611, 611, 612, 613, 613, 613,
+    613, 613, 63, 63, 63, 63, 63, 63, 63, 61, 61, 61, 61, 61, 61, 61, 61, 61,
+    63, 63, 53, 57, 53, 57, 53, 57, 57, 57, 53, 57, 53, 57, 53, 57, 60, 57,
+    57, 57, 57, 57, 57, 57, 57, 53, 57, 53, 57, 53, 53, 57, 61, 614, 614, 53,
+    57, 53, 57, 58, 53, 57, 53, 57, 57, 57, 53, 57, 53, 57, 53, 53, 53, 53,
+    53, 82, 53, 53, 53, 53, 53, 57, 53, 57, 82, 82, 82, 82, 82, 82, 82, 58,
+    60, 60, 57, 58, 58, 58, 58, 58, 615, 615, 616, 615, 615, 615, 617, 615,
+    615, 615, 615, 616, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615,
+    615, 615, 615, 615, 615, 618, 618, 616, 616, 618, 619, 619, 619, 619, 82,
+    82, 82, 82, 620, 620, 620, 620, 620, 620, 313, 313, 503, 512, 82, 82, 82,
+    82, 82, 82, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621,
+    622, 622, 623, 623, 624, 624, 625, 625, 625, 625, 625, 625, 625, 625,
+    625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 624, 624, 624, 624,
+    624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 626, 627, 82,
+    82, 82, 82, 82, 82, 82, 82, 628, 628, 629, 629, 629, 629, 629, 629, 629,
+    629, 629, 629, 82, 82, 82, 82, 82, 82, 198, 198, 198, 198, 198, 198, 198,
+    198, 198, 198, 195, 195, 195, 195, 195, 195, 201, 201, 201, 195, 630,
+    195, 82, 82, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 632, 632,
+    632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632,
+    632, 632, 632, 632, 633, 633, 633, 633, 633, 634, 634, 634, 199, 635,
+    636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636,
+    636, 637, 637, 637, 637, 637, 637, 637, 637, 637, 637, 637, 638, 639, 82,
+    82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 640, 328, 328, 328, 328, 328, 82,
+    82, 82, 641, 641, 641, 642, 643, 643, 643, 643, 643, 643, 643, 643, 643,
+    643, 643, 643, 643, 643, 643, 644, 642, 642, 641, 641, 641, 641, 642,
+    642, 641, 642, 642, 642, 645, 646, 646, 646, 646, 646, 646, 647, 647,
+    647, 646, 646, 646, 646, 82, 62, 648, 648, 648, 648, 648, 648, 648, 648,
+    648, 648, 82, 82, 82, 82, 646, 646, 314, 314, 314, 314, 314, 316, 649,
+    314, 319, 319, 314, 314, 314, 314, 314, 82, 650, 650, 650, 650, 650, 650,
+    650, 650, 650, 651, 651, 651, 651, 651, 651, 652, 652, 651, 651, 652,
+    652, 651, 651, 82, 650, 650, 650, 651, 650, 650, 650, 650, 650, 650, 650,
+    650, 651, 652, 82, 82, 653, 653, 653, 653, 653, 653, 653, 653, 653, 653,
+    82, 82, 654, 655, 655, 655, 649, 314, 314, 314, 314, 314, 314, 323, 323,
+    323, 314, 315, 316, 315, 314, 314, 656, 656, 656, 656, 656, 656, 656,
+    656, 657, 656, 657, 657, 658, 656, 656, 657, 657, 656, 656, 656, 656,
+    656, 657, 657, 656, 657, 656, 82, 82, 82, 82, 82, 82, 82, 82, 656, 656,
+    659, 660, 660, 661, 661, 661, 661, 661, 661, 661, 661, 661, 661, 661,
+    662, 663, 663, 662, 662, 664, 664, 661, 665, 665, 662, 666, 82, 82, 331,
+    331, 331, 331, 331, 331, 82, 57, 57, 57, 614, 60, 60, 60, 60, 57, 57, 57,
+    57, 57, 80, 82, 82, 338, 338, 338, 338, 338, 338, 338, 338, 661, 661,
+    661, 662, 662, 663, 662, 662, 663, 662, 662, 664, 662, 666, 82, 82, 667,
+    667, 667, 667, 667, 667, 667, 667, 667, 667, 82, 82, 82, 82, 82, 82, 668,
+    669, 669, 669, 669, 669, 669, 669, 669, 669, 669, 669, 669, 669, 669,
+    669, 669, 669, 669, 669, 668, 669, 669, 669, 669, 669, 669, 669, 82, 82,
+    82, 82, 329, 329, 329, 329, 329, 329, 329, 82, 82, 82, 82, 330, 330, 330,
+    330, 330, 330, 330, 330, 330, 82, 82, 82, 82, 670, 670, 670, 670, 670,
+    670, 670, 670, 671, 671, 671, 671, 671, 671, 671, 671, 593, 593, 594,
+    594, 594, 594, 594, 594, 57, 57, 57, 57, 57, 57, 57, 82, 82, 82, 82, 102,
+    102, 102, 102, 102, 82, 82, 82, 82, 82, 130, 672, 130, 130, 673, 130,
+    130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 82, 130, 130,
+    130, 130, 130, 82, 130, 82, 130, 130, 82, 130, 130, 82, 130, 130, 147,
+    147, 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, 674,
+    674, 674, 674, 82, 82, 82, 82, 82, 82, 82, 82, 82, 147, 147, 147, 147,
+    147, 147, 147, 147, 147, 147, 147, 675, 471, 82, 82, 147, 147, 147, 147,
+    147, 147, 147, 147, 147, 147, 136, 139, 82, 82, 676, 676, 676, 676, 676,
+    676, 676, 676, 677, 557, 557, 677, 677, 678, 678, 563, 564, 679, 82, 82,
+    82, 82, 82, 82, 97, 97, 97, 97, 97, 97, 97, 157, 157, 157, 157, 157, 157,
+    157, 96, 96, 558, 570, 570, 680, 680, 563, 564, 563, 564, 563, 564, 563,
+    564, 563, 564, 563, 564, 563, 564, 563, 564, 558, 558, 563, 564, 558,
+    558, 558, 558, 680, 680, 680, 681, 558, 681, 82, 581, 682, 678, 678, 570,
+    524, 525, 524, 525, 524, 525, 683, 558, 558, 684, 685, 686, 686, 687, 82,
+    558, 688, 689, 558, 82, 82, 82, 82, 147, 147, 147, 147, 147, 82, 82, 493,
+    82, 690, 691, 692, 693, 694, 691, 691, 695, 696, 691, 697, 698, 699, 698,
+    700, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 702, 703, 704,
+    705, 704, 690, 691, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706,
+    706, 706, 706, 706, 706, 706, 706, 706, 695, 691, 696, 707, 708, 707,
+    709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709,
+    709, 709, 709, 709, 695, 705, 696, 705, 695, 696, 710, 711, 712, 710,
+    713, 714, 715, 715, 715, 715, 715, 715, 715, 715, 715, 716, 714, 714,
+    714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 714,
+    714, 714, 714, 714, 714, 717, 717, 718, 718, 718, 718, 718, 718, 718,
+    718, 718, 718, 718, 718, 718, 718, 718, 82, 82, 82, 718, 718, 718, 718,
+    718, 718, 82, 82, 718, 718, 718, 82, 82, 82, 719, 693, 705, 707, 720,
+    693, 693, 82, 721, 722, 722, 722, 722, 721, 721, 82, 82, 723, 723, 723,
+    724, 508, 82, 82, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725,
+    725, 82, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, 82, 725, 725,
+    725, 82, 725, 725, 82, 725, 725, 725, 725, 725, 725, 725, 82, 82, 725,
+    725, 725, 82, 82, 82, 82, 82, 199, 373, 199, 82, 82, 82, 82, 620, 620,
+    620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 82, 82, 82, 313,
+    726, 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, 727,
+    727, 727, 727, 728, 728, 728, 728, 728, 728, 728, 728, 728, 728, 728,
+    728, 728, 728, 728, 728, 728, 727, 727, 728, 729, 729, 82, 41, 41, 41,
+    41, 82, 82, 82, 82, 728, 82, 82, 82, 82, 82, 82, 82, 313, 313, 313, 313,
+    313, 157, 82, 82, 730, 730, 730, 730, 730, 730, 730, 730, 730, 730, 730,
+    730, 730, 82, 82, 82, 731, 731, 731, 731, 731, 731, 731, 731, 731, 82,
+    82, 82, 82, 82, 82, 82, 157, 500, 500, 500, 500, 500, 500, 500, 500, 500,
+    500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 82, 82, 82, 82, 732,
+    732, 732, 732, 732, 732, 732, 732, 733, 733, 733, 733, 82, 82, 82, 82,
+    734, 734, 734, 734, 734, 734, 734, 734, 734, 735, 734, 734, 734, 734,
+    734, 734, 734, 734, 735, 82, 82, 82, 82, 82, 736, 736, 736, 736, 736,
+    736, 736, 736, 736, 736, 736, 736, 736, 736, 737, 737, 737, 737, 737, 82,
+    82, 82, 82, 82, 738, 738, 738, 738, 738, 738, 738, 738, 738, 738, 738,
+    738, 738, 738, 82, 739, 740, 740, 740, 740, 740, 740, 740, 740, 740, 740,
+    740, 740, 82, 82, 82, 82, 741, 742, 742, 742, 742, 742, 82, 82, 743, 743,
+    743, 743, 743, 743, 743, 743, 744, 744, 744, 744, 744, 744, 744, 744,
+    745, 745, 745, 745, 745, 745, 745, 745, 746, 746, 746, 746, 746, 746,
+    746, 746, 746, 746, 746, 746, 746, 746, 82, 82, 747, 747, 747, 747, 747,
+    747, 747, 747, 747, 747, 82, 82, 82, 82, 82, 82, 748, 748, 748, 748, 748,
+    748, 748, 748, 748, 748, 748, 748, 82, 82, 82, 82, 749, 749, 749, 749,
+    749, 749, 749, 749, 749, 749, 749, 749, 82, 82, 82, 82, 750, 750, 750,
+    750, 750, 750, 750, 750, 751, 751, 751, 751, 751, 751, 751, 751, 751,
+    751, 751, 751, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 752, 753, 753,
+    753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 82, 753,
+    753, 753, 753, 753, 753, 82, 82, 754, 754, 754, 754, 754, 754, 82, 82,
+    754, 82, 754, 754, 754, 754, 754, 754, 754, 754, 754, 754, 754, 754, 754,
+    754, 754, 754, 754, 754, 754, 754, 82, 754, 754, 82, 82, 82, 754, 82, 82,
+    754, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755,
+    755, 82, 756, 757, 757, 757, 757, 757, 757, 757, 757, 758, 758, 758, 758,
+    758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 759, 759, 760,
+    760, 760, 760, 760, 760, 760, 761, 761, 761, 761, 761, 761, 761, 761,
+    761, 761, 761, 761, 761, 761, 761, 82, 82, 82, 82, 82, 82, 82, 82, 762,
+    762, 762, 762, 762, 762, 762, 762, 762, 763, 763, 763, 763, 763, 763,
+    763, 763, 763, 763, 763, 82, 763, 763, 82, 82, 82, 82, 82, 764, 764, 764,
+    764, 764, 765, 765, 765, 765, 765, 765, 765, 765, 765, 765, 765, 765,
+    765, 765, 766, 766, 766, 766, 766, 766, 82, 82, 82, 767, 768, 768, 768,
+    768, 768, 768, 768, 768, 768, 768, 82, 82, 82, 82, 82, 769, 770, 770,
+    770, 770, 770, 770, 770, 770, 771, 771, 771, 771, 771, 771, 771, 771, 82,
+    82, 82, 82, 772, 772, 771, 771, 772, 772, 772, 772, 772, 772, 772, 772,
+    82, 82, 772, 772, 772, 772, 772, 772, 773, 774, 774, 774, 82, 774, 774,
+    82, 82, 82, 82, 82, 774, 775, 774, 776, 773, 773, 773, 773, 82, 773, 773,
+    773, 82, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773,
+    773, 773, 773, 773, 773, 773, 82, 82, 82, 82, 776, 777, 775, 82, 82, 82,
+    82, 778, 779, 779, 779, 779, 779, 779, 779, 779, 780, 780, 780, 780, 780,
+    780, 780, 780, 781, 82, 82, 82, 82, 82, 82, 82, 782, 782, 782, 782, 782,
+    782, 782, 782, 782, 782, 782, 782, 782, 783, 783, 784, 785, 785, 785,
+    785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 786, 786, 786, 787,
+    787, 787, 787, 787, 787, 787, 787, 788, 787, 787, 787, 787, 787, 787,
+    787, 787, 787, 787, 787, 787, 789, 790, 82, 82, 82, 82, 791, 791, 791,
+    791, 791, 792, 792, 792, 792, 792, 792, 793, 82, 794, 794, 794, 794, 794,
+    794, 794, 794, 794, 794, 794, 794, 794, 794, 82, 82, 82, 795, 795, 795,
+    795, 795, 795, 795, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796,
+    796, 796, 796, 796, 82, 82, 797, 797, 797, 797, 797, 797, 797, 797, 798,
+    798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 82, 82, 82, 82, 82,
+    799, 799, 799, 799, 799, 799, 799, 799, 800, 800, 800, 800, 800, 800,
+    800, 800, 800, 800, 82, 82, 82, 82, 82, 82, 82, 801, 801, 801, 801, 82,
+    82, 82, 82, 802, 802, 802, 802, 802, 802, 802, 803, 803, 803, 803, 803,
+    803, 803, 803, 803, 82, 82, 82, 82, 82, 82, 82, 804, 804, 804, 804, 804,
+    804, 804, 804, 804, 804, 804, 82, 82, 82, 82, 82, 805, 805, 805, 805,
+    805, 805, 805, 805, 805, 805, 805, 82, 82, 82, 82, 82, 82, 82, 806, 806,
+    806, 806, 806, 806, 807, 807, 807, 807, 807, 807, 807, 807, 807, 807,
+    807, 807, 807, 807, 807, 82, 808, 809, 808, 810, 810, 810, 810, 810, 810,
+    810, 810, 810, 810, 810, 810, 810, 809, 809, 809, 809, 809, 809, 809,
+    809, 809, 809, 809, 809, 809, 809, 811, 812, 812, 813, 813, 813, 813,
+    813, 82, 82, 82, 82, 814, 814, 814, 814, 814, 814, 814, 814, 814, 814,
+    814, 814, 814, 814, 814, 814, 814, 814, 814, 814, 815, 815, 815, 815,
+    815, 815, 815, 815, 815, 815, 82, 82, 82, 82, 82, 82, 82, 811, 816, 816,
+    817, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818,
+    817, 817, 817, 816, 816, 816, 816, 817, 817, 819, 820, 821, 821, 822,
+    823, 823, 823, 823, 82, 82, 82, 82, 82, 82, 824, 824, 824, 824, 824, 824,
+    824, 824, 824, 82, 82, 82, 82, 82, 82, 82, 825, 825, 825, 825, 825, 825,
+    825, 825, 825, 825, 82, 82, 82, 82, 82, 82, 826, 826, 826, 827, 827, 827,
+    827, 827, 827, 827, 827, 827, 827, 827, 827, 827, 827, 827, 827, 827,
+    827, 827, 827, 828, 828, 828, 828, 828, 829, 828, 828, 828, 828, 828,
+    828, 830, 830, 82, 831, 831, 831, 831, 831, 831, 831, 831, 831, 831, 832,
+    832, 832, 832, 82, 82, 82, 82, 833, 833, 833, 833, 833, 833, 833, 833,
+    833, 833, 833, 834, 835, 836, 833, 82, 837, 837, 838, 839, 839, 839, 839,
+    839, 839, 839, 839, 839, 839, 839, 839, 839, 839, 839, 839, 838, 838,
+    838, 837, 837, 837, 837, 837, 837, 837, 837, 837, 838, 840, 839, 839,
+    839, 839, 841, 841, 842, 841, 842, 843, 837, 837, 842, 82, 82, 844, 844,
+    844, 844, 844, 844, 844, 844, 844, 844, 839, 845, 839, 841, 841, 841, 82,
+    846, 846, 846, 846, 846, 846, 846, 846, 846, 846, 846, 846, 846, 846,
+    846, 846, 846, 846, 846, 846, 82, 82, 82, 847, 847, 847, 847, 847, 847,
+    847, 847, 847, 847, 82, 847, 847, 847, 847, 847, 847, 847, 847, 847, 848,
+    848, 848, 849, 849, 849, 848, 848, 849, 850, 851, 849, 852, 852, 853,
+    852, 852, 853, 849, 82, 854, 854, 854, 854, 854, 854, 854, 82, 854, 82,
+    854, 854, 854, 854, 82, 854, 854, 854, 854, 854, 854, 854, 854, 854, 854,
+    854, 854, 854, 854, 854, 82, 854, 854, 855, 82, 82, 82, 82, 82, 82, 856,
+    856, 856, 856, 856, 856, 856, 856, 856, 856, 856, 856, 856, 856, 856,
+    857, 858, 858, 858, 857, 857, 857, 857, 857, 857, 859, 860, 82, 82, 82,
+    82, 82, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 82, 82, 82, 82,
+    82, 82, 862, 862, 863, 863, 82, 864, 864, 864, 864, 864, 864, 864, 864,
+    82, 82, 864, 864, 82, 82, 864, 864, 864, 864, 864, 864, 864, 864, 864,
+    864, 864, 864, 864, 864, 82, 864, 864, 864, 864, 864, 864, 864, 82, 864,
+    864, 82, 864, 864, 864, 864, 864, 82, 82, 865, 864, 863, 863, 862, 863,
+    863, 863, 863, 82, 82, 863, 863, 82, 82, 863, 863, 866, 82, 82, 864, 82,
+    82, 82, 82, 82, 82, 863, 82, 82, 82, 82, 82, 864, 864, 864, 864, 864,
+    863, 863, 82, 82, 867, 867, 867, 867, 867, 867, 867, 82, 82, 82, 868,
+    868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 869, 869,
+    869, 870, 870, 870, 870, 870, 870, 870, 870, 869, 869, 871, 870, 870,
+    869, 872, 868, 868, 868, 868, 873, 873, 873, 873, 874, 875, 875, 875,
+    875, 875, 875, 875, 875, 875, 875, 82, 873, 82, 874, 82, 82, 876, 876,
+    876, 876, 876, 876, 876, 876, 877, 877, 877, 878, 878, 878, 878, 878,
+    878, 877, 878, 877, 877, 877, 877, 878, 878, 877, 879, 880, 876, 876,
+    881, 876, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 82, 82, 82,
+    82, 82, 82, 883, 883, 883, 883, 883, 883, 883, 883, 883, 883, 883, 883,
+    883, 883, 883, 884, 884, 884, 885, 885, 885, 885, 82, 82, 884, 884, 884,
+    884, 885, 885, 884, 886, 887, 888, 889, 889, 890, 890, 891, 891, 891,
+    889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889,
+    889, 883, 883, 883, 883, 885, 885, 82, 82, 892, 892, 892, 892, 892, 892,
+    892, 892, 893, 893, 893, 894, 894, 894, 894, 894, 894, 894, 894, 893,
+    893, 894, 893, 895, 894, 896, 896, 897, 892, 82, 82, 82, 898, 898, 898,
+    898, 898, 898, 898, 898, 898, 898, 82, 82, 82, 82, 82, 82, 899, 899, 899,
+    899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 82, 82, 82, 900, 900,
+    900, 900, 900, 900, 900, 900, 900, 900, 900, 901, 902, 901, 902, 902,
+    901, 901, 901, 901, 901, 901, 903, 904, 905, 905, 905, 905, 905, 905,
+    905, 905, 905, 905, 82, 82, 82, 82, 82, 82, 906, 906, 906, 906, 906, 906,
+    906, 906, 906, 906, 82, 82, 82, 907, 907, 907, 908, 908, 907, 907, 907,
+    907, 908, 907, 907, 907, 907, 909, 82, 82, 82, 82, 910, 910, 910, 910,
+    910, 910, 910, 910, 910, 910, 911, 911, 912, 912, 912, 913, 914, 914,
+    914, 914, 914, 914, 914, 914, 915, 915, 915, 915, 915, 915, 915, 915,
+    916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 917, 917, 917, 917,
+    917, 917, 917, 917, 917, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
+    918, 919, 919, 919, 919, 919, 919, 919, 919, 919, 82, 82, 82, 82, 82, 82,
+    82, 920, 920, 920, 920, 920, 920, 920, 920, 920, 82, 920, 920, 920, 920,
+    920, 920, 920, 920, 920, 920, 920, 920, 920, 921, 922, 922, 922, 922,
+    922, 922, 922, 82, 922, 922, 922, 922, 922, 922, 921, 923, 920, 924, 924,
+    924, 924, 924, 82, 82, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925,
+    926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926,
+    926, 926, 926, 926, 926, 82, 82, 82, 927, 928, 929, 929, 929, 929, 929,
+    929, 929, 929, 929, 929, 929, 929, 929, 929, 82, 82, 930, 930, 930, 930,
+    930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 82, 931, 930, 930, 930,
+    930, 930, 930, 930, 931, 930, 930, 931, 930, 930, 82, 932, 932, 932, 932,
+    932, 932, 932, 932, 932, 932, 82, 82, 82, 82, 82, 82, 933, 933, 933, 933,
+    933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 82, 934, 934, 934,
+    934, 934, 82, 82, 82, 932, 932, 932, 932, 82, 82, 82, 82, 935, 935, 935,
+    935, 935, 935, 935, 935, 936, 936, 936, 937, 937, 937, 935, 935, 935,
+    935, 937, 935, 935, 935, 936, 937, 936, 937, 935, 935, 935, 935, 935,
+    935, 935, 936, 937, 937, 935, 935, 935, 935, 935, 935, 935, 935, 935,
+    935, 935, 82, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938,
+    938, 938, 939, 940, 938, 938, 938, 938, 938, 938, 938, 82, 609, 82, 82,
+    82, 82, 82, 82, 82, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941,
+    941, 941, 941, 941, 941, 82, 942, 942, 942, 942, 942, 942, 942, 942, 942,
+    942, 82, 82, 82, 82, 943, 943, 944, 944, 944, 944, 944, 944, 944, 944,
+    944, 944, 944, 944, 944, 944, 82, 82, 945, 945, 945, 945, 945, 946, 82,
+    82, 947, 947, 947, 947, 947, 947, 947, 947, 948, 948, 948, 948, 948, 948,
+    948, 949, 949, 949, 950, 950, 951, 951, 951, 951, 952, 952, 952, 952,
+    949, 951, 82, 82, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 82,
+    954, 954, 954, 954, 954, 954, 954, 82, 947, 947, 947, 947, 947, 82, 82,
+    82, 82, 82, 947, 947, 947, 955, 955, 955, 955, 955, 955, 955, 955, 955,
+    955, 955, 955, 955, 82, 82, 82, 955, 956, 956, 956, 956, 956, 956, 956,
+    956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956,
+    956, 82, 82, 82, 82, 82, 82, 82, 82, 957, 957, 957, 957, 958, 958, 958,
+    958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 959, 82, 82, 82, 82,
+    82, 82, 82, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960,
+    960, 82, 82, 82, 960, 960, 960, 82, 82, 82, 82, 82, 580, 575, 82, 82, 82,
+    82, 82, 82, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 82,
+    82, 82, 82, 82, 961, 961, 961, 961, 961, 82, 82, 82, 961, 82, 82, 82, 82,
+    82, 82, 82, 961, 961, 82, 82, 962, 963, 964, 965, 499, 499, 499, 499, 82,
+    82, 82, 82, 313, 313, 313, 313, 313, 313, 82, 82, 313, 313, 313, 313,
+    313, 313, 313, 82, 82, 313, 313, 313, 313, 313, 313, 313, 313, 313, 313,
+    313, 313, 966, 966, 447, 447, 447, 313, 313, 313, 967, 966, 966, 966,
+    966, 966, 499, 499, 499, 499, 499, 499, 499, 499, 157, 157, 157, 157,
+    157, 157, 157, 157, 313, 313, 97, 97, 97, 97, 97, 157, 157, 313, 313,
+    313, 313, 313, 313, 97, 97, 97, 97, 313, 313, 313, 82, 82, 82, 82, 82,
+    82, 82, 728, 728, 968, 968, 968, 728, 82, 82, 620, 620, 82, 82, 82, 82,
+    82, 82, 506, 506, 506, 506, 506, 506, 506, 506, 506, 506, 50, 50, 50, 50,
+    50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 506, 506, 506,
+    506, 506, 506, 506, 506, 506, 506, 50, 50, 50, 50, 50, 50, 50, 82, 50,
+    50, 50, 50, 50, 50, 506, 82, 506, 506, 82, 82, 506, 82, 82, 506, 506, 82,
+    82, 506, 506, 506, 506, 82, 506, 506, 50, 50, 82, 50, 82, 50, 50, 50, 50,
+    50, 50, 50, 82, 50, 50, 50, 50, 50, 50, 50, 506, 506, 82, 506, 506, 506,
+    506, 82, 82, 506, 506, 506, 506, 506, 506, 506, 506, 82, 506, 506, 506,
+    506, 506, 506, 506, 82, 50, 50, 506, 506, 82, 506, 506, 506, 506, 82,
+    506, 506, 506, 506, 506, 82, 506, 82, 82, 82, 506, 506, 506, 506, 506,
+    506, 506, 82, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 82, 82,
+    506, 969, 50, 50, 50, 50, 50, 50, 50, 50, 50, 513, 50, 50, 50, 50, 50,
+    50, 506, 506, 506, 506, 506, 506, 506, 506, 506, 969, 50, 50, 50, 50, 50,
+    50, 50, 50, 50, 513, 50, 50, 506, 506, 506, 506, 506, 969, 50, 50, 50,
+    50, 50, 50, 50, 50, 50, 513, 50, 50, 50, 50, 50, 50, 506, 506, 506, 506,
+    506, 506, 506, 506, 506, 969, 50, 513, 50, 50, 50, 50, 50, 50, 50, 50,
+    506, 50, 82, 82, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 971,
+    971, 971, 971, 971, 971, 971, 971, 972, 972, 972, 972, 972, 972, 972,
+    972, 972, 972, 972, 972, 972, 972, 972, 971, 971, 971, 971, 972, 972,
+    972, 972, 972, 972, 972, 972, 972, 972, 971, 971, 971, 971, 971, 971,
+    971, 971, 972, 971, 971, 971, 971, 971, 971, 972, 971, 971, 973, 973,
+    973, 973, 974, 82, 82, 82, 82, 82, 82, 82, 972, 972, 972, 972, 972, 82,
+    972, 972, 972, 972, 972, 972, 972, 975, 975, 975, 975, 975, 975, 975, 82,
+    975, 975, 975, 975, 975, 975, 975, 975, 975, 82, 82, 975, 975, 975, 975,
+    975, 975, 975, 82, 975, 975, 82, 975, 975, 975, 975, 975, 82, 82, 82, 82,
+    82, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 82,
+    82, 977, 977, 977, 977, 977, 977, 977, 977, 977, 978, 978, 978, 978, 978,
+    978, 978, 82, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 980, 980,
+    980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980,
+    980, 980, 981, 981, 981, 981, 981, 981, 982, 82, 82, 82, 82, 82, 983,
+    983, 983, 983, 983, 983, 983, 983, 983, 983, 82, 82, 82, 82, 984, 984,
+    147, 147, 147, 147, 82, 147, 147, 147, 82, 147, 147, 82, 147, 82, 82,
+    147, 82, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 82, 147, 147,
+    147, 147, 82, 147, 82, 147, 82, 82, 82, 82, 82, 82, 147, 82, 82, 82, 82,
+    147, 82, 147, 82, 147, 82, 147, 147, 147, 82, 147, 82, 147, 82, 147, 82,
+    147, 82, 147, 147, 147, 147, 82, 147, 82, 147, 147, 82, 147, 147, 147,
+    147, 147, 147, 147, 147, 147, 82, 82, 82, 82, 82, 147, 147, 147, 82, 147,
+    147, 147, 133, 133, 82, 82, 82, 82, 82, 82, 527, 527, 527, 527, 523, 527,
+    527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527,
+    985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 527, 527,
+    527, 527, 527, 527, 527, 985, 985, 527, 527, 527, 527, 527, 527, 527,
+    527, 527, 527, 527, 527, 527, 527, 523, 527, 527, 527, 527, 527, 527,
+    985, 985, 48, 48, 48, 516, 516, 985, 985, 985, 528, 528, 528, 528, 528,
+    528, 313, 985, 528, 528, 41, 41, 985, 985, 985, 985, 528, 528, 528, 528,
+    528, 528, 986, 528, 528, 986, 986, 986, 986, 986, 986, 986, 986, 986,
+    986, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 985, 985, 985,
+    985, 985, 985, 985, 985, 985, 987, 987, 987, 987, 987, 987, 987, 987,
+    987, 987, 988, 586, 586, 985, 985, 985, 985, 985, 586, 586, 586, 586,
+    985, 985, 985, 985, 586, 985, 985, 985, 985, 985, 985, 985, 586, 586,
+    985, 985, 985, 985, 985, 985, 523, 527, 527, 527, 527, 527, 527, 527,
+    527, 527, 527, 527, 527, 523, 523, 523, 523, 523, 523, 523, 523, 523,
+    527, 523, 523, 523, 523, 523, 523, 527, 523, 523, 523, 523, 523, 523,
+    523, 534, 523, 523, 523, 523, 523, 523, 527, 527, 527, 527, 527, 527,
+    527, 527, 41, 41, 527, 527, 523, 523, 523, 523, 523, 526, 526, 523, 523,
+    523, 523, 523, 526, 523, 523, 523, 523, 523, 523, 534, 534, 523, 523,
+    523, 523, 523, 534, 532, 527, 527, 527, 523, 523, 527, 527, 527, 523,
+    527, 527, 527, 523, 523, 523, 989, 989, 989, 989, 989, 523, 523, 523,
+    523, 523, 523, 523, 527, 523, 527, 534, 534, 523, 523, 534, 534, 534,
+    534, 534, 534, 534, 534, 534, 534, 534, 523, 523, 523, 523, 523, 523,
+    523, 523, 523, 523, 523, 523, 523, 534, 534, 534, 534, 523, 523, 523,
+    523, 534, 523, 534, 523, 523, 523, 534, 523, 523, 523, 523, 534, 534,
+    534, 523, 534, 534, 534, 526, 523, 526, 523, 526, 523, 523, 523, 523,
+    523, 534, 523, 523, 523, 523, 526, 523, 526, 526, 523, 523, 523, 523,
+    523, 523, 523, 523, 523, 523, 527, 527, 523, 526, 526, 526, 526, 526,
+    526, 526, 523, 523, 523, 523, 523, 523, 523, 523, 526, 526, 526, 526,
+    526, 526, 523, 523, 523, 523, 523, 526, 526, 526, 526, 526, 526, 526,
+    526, 526, 526, 526, 526, 41, 41, 41, 41, 527, 523, 523, 523, 523, 527,
+    527, 527, 527, 527, 527, 532, 527, 527, 527, 527, 534, 527, 527, 527,
+    527, 527, 532, 527, 527, 527, 527, 534, 534, 527, 527, 527, 527, 527, 41,
+    41, 41, 41, 41, 41, 41, 41, 527, 527, 527, 527, 41, 41, 527, 523, 523,
+    523, 523, 523, 523, 523, 523, 523, 523, 534, 534, 534, 523, 523, 523,
+    534, 534, 534, 534, 534, 41, 41, 41, 41, 41, 41, 536, 536, 536, 990, 990,
+    990, 41, 41, 41, 41, 523, 523, 523, 534, 523, 523, 523, 523, 523, 523,
+    523, 523, 534, 534, 534, 523, 534, 523, 523, 523, 523, 523, 527, 527,
+    523, 523, 523, 985, 985, 985, 985, 985, 527, 527, 527, 523, 523, 985,
+    985, 985, 527, 527, 527, 527, 523, 523, 523, 985, 41, 41, 41, 41, 985,
+    985, 985, 985, 41, 41, 41, 41, 41, 985, 985, 985, 41, 41, 985, 985, 985,
+    985, 985, 985, 41, 41, 41, 41, 41, 41, 985, 985, 534, 534, 534, 534, 534,
+    534, 534, 985, 523, 523, 523, 523, 523, 523, 534, 523, 534, 985, 985,
+    534, 534, 534, 534, 534, 534, 534, 523, 523, 534, 534, 534, 985, 523,
+    523, 523, 523, 985, 985, 985, 985, 523, 523, 523, 523, 523, 523, 523,
+    985, 523, 523, 985, 985, 985, 985, 985, 985, 523, 985, 985, 985, 985,
+    985, 985, 985, 985, 985, 985, 985, 985, 985, 82, 82, 593, 593, 593, 593,
+    593, 593, 593, 594, 593, 593, 593, 593, 593, 594, 594, 594, 594, 594,
+    594, 594, 594, 594, 82, 82, 82, 499, 82, 82, 82, 82, 82, 82, 499, 499,
+    499, 499, 499, 499, 499, 499, 671, 671, 671, 671, 671, 671, 82, 82,
+};
+
+/* decomposition data */
+static const unsigned short decomp_data[] = {
+    0, 257, 32, 514, 32, 776, 259, 97, 514, 32, 772, 259, 50, 259, 51, 514,
+    32, 769, 258, 956, 514, 32, 807, 259, 49, 259, 111, 772, 49, 8260, 52,
+    772, 49, 8260, 50, 772, 51, 8260, 52, 512, 65, 768, 512, 65, 769, 512,
+    65, 770, 512, 65, 771, 512, 65, 776, 512, 65, 778, 512, 67, 807, 512, 69,
+    768, 512, 69, 769, 512, 69, 770, 512, 69, 776, 512, 73, 768, 512, 73,
+    769, 512, 73, 770, 512, 73, 776, 512, 78, 771, 512, 79, 768, 512, 79,
+    769, 512, 79, 770, 512, 79, 771, 512, 79, 776, 512, 85, 768, 512, 85,
+    769, 512, 85, 770, 512, 85, 776, 512, 89, 769, 512, 97, 768, 512, 97,
+    769, 512, 97, 770, 512, 97, 771, 512, 97, 776, 512, 97, 778, 512, 99,
+    807, 512, 101, 768, 512, 101, 769, 512, 101, 770, 512, 101, 776, 512,
+    105, 768, 512, 105, 769, 512, 105, 770, 512, 105, 776, 512, 110, 771,
+    512, 111, 768, 512, 111, 769, 512, 111, 770, 512, 111, 771, 512, 111,
+    776, 512, 117, 768, 512, 117, 769, 512, 117, 770, 512, 117, 776, 512,
+    121, 769, 512, 121, 776, 512, 65, 772, 512, 97, 772, 512, 65, 774, 512,
+    97, 774, 512, 65, 808, 512, 97, 808, 512, 67, 769, 512, 99, 769, 512, 67,
+    770, 512, 99, 770, 512, 67, 775, 512, 99, 775, 512, 67, 780, 512, 99,
+    780, 512, 68, 780, 512, 100, 780, 512, 69, 772, 512, 101, 772, 512, 69,
+    774, 512, 101, 774, 512, 69, 775, 512, 101, 775, 512, 69, 808, 512, 101,
+    808, 512, 69, 780, 512, 101, 780, 512, 71, 770, 512, 103, 770, 512, 71,
+    774, 512, 103, 774, 512, 71, 775, 512, 103, 775, 512, 71, 807, 512, 103,
+    807, 512, 72, 770, 512, 104, 770, 512, 73, 771, 512, 105, 771, 512, 73,
+    772, 512, 105, 772, 512, 73, 774, 512, 105, 774, 512, 73, 808, 512, 105,
+    808, 512, 73, 775, 514, 73, 74, 514, 105, 106, 512, 74, 770, 512, 106,
+    770, 512, 75, 807, 512, 107, 807, 512, 76, 769, 512, 108, 769, 512, 76,
+    807, 512, 108, 807, 512, 76, 780, 512, 108, 780, 514, 76, 183, 514, 108,
+    183, 512, 78, 769, 512, 110, 769, 512, 78, 807, 512, 110, 807, 512, 78,
+    780, 512, 110, 780, 514, 700, 110, 512, 79, 772, 512, 111, 772, 512, 79,
+    774, 512, 111, 774, 512, 79, 779, 512, 111, 779, 512, 82, 769, 512, 114,
+    769, 512, 82, 807, 512, 114, 807, 512, 82, 780, 512, 114, 780, 512, 83,
+    769, 512, 115, 769, 512, 83, 770, 512, 115, 770, 512, 83, 807, 512, 115,
+    807, 512, 83, 780, 512, 115, 780, 512, 84, 807, 512, 116, 807, 512, 84,
+    780, 512, 116, 780, 512, 85, 771, 512, 117, 771, 512, 85, 772, 512, 117,
+    772, 512, 85, 774, 512, 117, 774, 512, 85, 778, 512, 117, 778, 512, 85,
+    779, 512, 117, 779, 512, 85, 808, 512, 117, 808, 512, 87, 770, 512, 119,
+    770, 512, 89, 770, 512, 121, 770, 512, 89, 776, 512, 90, 769, 512, 122,
+    769, 512, 90, 775, 512, 122, 775, 512, 90, 780, 512, 122, 780, 258, 115,
+    512, 79, 795, 512, 111, 795, 512, 85, 795, 512, 117, 795, 514, 68, 381,
+    514, 68, 382, 514, 100, 382, 514, 76, 74, 514, 76, 106, 514, 108, 106,
+    514, 78, 74, 514, 78, 106, 514, 110, 106, 512, 65, 780, 512, 97, 780,
+    512, 73, 780, 512, 105, 780, 512, 79, 780, 512, 111, 780, 512, 85, 780,
+    512, 117, 780, 512, 220, 772, 512, 252, 772, 512, 220, 769, 512, 252,
+    769, 512, 220, 780, 512, 252, 780, 512, 220, 768, 512, 252, 768, 512,
+    196, 772, 512, 228, 772, 512, 550, 772, 512, 551, 772, 512, 198, 772,
+    512, 230, 772, 512, 71, 780, 512, 103, 780, 512, 75, 780, 512, 107, 780,
+    512, 79, 808, 512, 111, 808, 512, 490, 772, 512, 491, 772, 512, 439, 780,
+    512, 658, 780, 512, 106, 780, 514, 68, 90, 514, 68, 122, 514, 100, 122,
+    512, 71, 769, 512, 103, 769, 512, 78, 768, 512, 110, 768, 512, 197, 769,
+    512, 229, 769, 512, 198, 769, 512, 230, 769, 512, 216, 769, 512, 248,
+    769, 512, 65, 783, 512, 97, 783, 512, 65, 785, 512, 97, 785, 512, 69,
+    783, 512, 101, 783, 512, 69, 785, 512, 101, 785, 512, 73, 783, 512, 105,
+    783, 512, 73, 785, 512, 105, 785, 512, 79, 783, 512, 111, 783, 512, 79,
+    785, 512, 111, 785, 512, 82, 783, 512, 114, 783, 512, 82, 785, 512, 114,
+    785, 512, 85, 783, 512, 117, 783, 512, 85, 785, 512, 117, 785, 512, 83,
+    806, 512, 115, 806, 512, 84, 806, 512, 116, 806, 512, 72, 780, 512, 104,
+    780, 512, 65, 775, 512, 97, 775, 512, 69, 807, 512, 101, 807, 512, 214,
+    772, 512, 246, 772, 512, 213, 772, 512, 245, 772, 512, 79, 775, 512, 111,
+    775, 512, 558, 772, 512, 559, 772, 512, 89, 772, 512, 121, 772, 259, 104,
+    259, 614, 259, 106, 259, 114, 259, 633, 259, 635, 259, 641, 259, 119,
+    259, 121, 514, 32, 774, 514, 32, 775, 514, 32, 778, 514, 32, 808, 514,
+    32, 771, 514, 32, 779, 259, 611, 259, 108, 259, 115, 259, 120, 259, 661,
+    256, 768, 256, 769, 256, 787, 512, 776, 769, 256, 697, 514, 32, 837, 256,
+    59, 514, 32, 769, 512, 168, 769, 512, 913, 769, 256, 183, 512, 917, 769,
+    512, 919, 769, 512, 921, 769, 512, 927, 769, 512, 933, 769, 512, 937,
+    769, 512, 970, 769, 512, 921, 776, 512, 933, 776, 512, 945, 769, 512,
+    949, 769, 512, 951, 769, 512, 953, 769, 512, 971, 769, 512, 953, 776,
+    512, 965, 776, 512, 959, 769, 512, 965, 769, 512, 969, 769, 258, 946,
+    258, 952, 258, 933, 512, 978, 769, 512, 978, 776, 258, 966, 258, 960,
+    258, 954, 258, 961, 258, 962, 258, 920, 258, 949, 258, 931, 512, 1045,
+    768, 512, 1045, 776, 512, 1043, 769, 512, 1030, 776, 512, 1050, 769, 512,
+    1048, 768, 512, 1059, 774, 512, 1048, 774, 512, 1080, 774, 512, 1077,
+    768, 512, 1077, 776, 512, 1075, 769, 512, 1110, 776, 512, 1082, 769, 512,
+    1080, 768, 512, 1091, 774, 512, 1140, 783, 512, 1141, 783, 512, 1046,
+    774, 512, 1078, 774, 512, 1040, 774, 512, 1072, 774, 512, 1040, 776, 512,
+    1072, 776, 512, 1045, 774, 512, 1077, 774, 512, 1240, 776, 512, 1241,
+    776, 512, 1046, 776, 512, 1078, 776, 512, 1047, 776, 512, 1079, 776, 512,
+    1048, 772, 512, 1080, 772, 512, 1048, 776, 512, 1080, 776, 512, 1054,
+    776, 512, 1086, 776, 512, 1256, 776, 512, 1257, 776, 512, 1069, 776, 512,
+    1101, 776, 512, 1059, 772, 512, 1091, 772, 512, 1059, 776, 512, 1091,
+    776, 512, 1059, 779, 512, 1091, 779, 512, 1063, 776, 512, 1095, 776, 512,
+    1067, 776, 512, 1099, 776, 514, 1381, 1410, 512, 1575, 1619, 512, 1575,
+    1620, 512, 1608, 1620, 512, 1575, 1621, 512, 1610, 1620, 514, 1575, 1652,
+    514, 1608, 1652, 514, 1735, 1652, 514, 1610, 1652, 512, 1749, 1620, 512,
+    1729, 1620, 512, 1746, 1620, 512, 2344, 2364, 512, 2352, 2364, 512, 2355,
+    2364, 512, 2325, 2364, 512, 2326, 2364, 512, 2327, 2364, 512, 2332, 2364,
+    512, 2337, 2364, 512, 2338, 2364, 512, 2347, 2364, 512, 2351, 2364, 512,
+    2503, 2494, 512, 2503, 2519, 512, 2465, 2492, 512, 2466, 2492, 512, 2479,
+    2492, 512, 2610, 2620, 512, 2616, 2620, 512, 2582, 2620, 512, 2583, 2620,
+    512, 2588, 2620, 512, 2603, 2620, 512, 2887, 2902, 512, 2887, 2878, 512,
+    2887, 2903, 512, 2849, 2876, 512, 2850, 2876, 512, 2962, 3031, 512, 3014,
+    3006, 512, 3015, 3006, 512, 3014, 3031, 512, 3142, 3158, 512, 3263, 3285,
+    512, 3270, 3285, 512, 3270, 3286, 512, 3270, 3266, 512, 3274, 3285, 512,
+    3398, 3390, 512, 3399, 3390, 512, 3398, 3415, 512, 3545, 3530, 512, 3545,
+    3535, 512, 3548, 3530, 512, 3545, 3551, 514, 3661, 3634, 514, 3789, 3762,
+    514, 3755, 3737, 514, 3755, 3745, 257, 3851, 512, 3906, 4023, 512, 3916,
+    4023, 512, 3921, 4023, 512, 3926, 4023, 512, 3931, 4023, 512, 3904, 4021,
+    512, 3953, 3954, 512, 3953, 3956, 512, 4018, 3968, 514, 4018, 3969, 512,
+    4019, 3968, 514, 4019, 3969, 512, 3953, 3968, 512, 3986, 4023, 512, 3996,
+    4023, 512, 4001, 4023, 512, 4006, 4023, 512, 4011, 4023, 512, 3984, 4021,
+    512, 4133, 4142, 259, 4316, 512, 6917, 6965, 512, 6919, 6965, 512, 6921,
+    6965, 512, 6923, 6965, 512, 6925, 6965, 512, 6929, 6965, 512, 6970, 6965,
+    512, 6972, 6965, 512, 6974, 6965, 512, 6975, 6965, 512, 6978, 6965, 259,
+    65, 259, 198, 259, 66, 259, 68, 259, 69, 259, 398, 259, 71, 259, 72, 259,
+    73, 259, 74, 259, 75, 259, 76, 259, 77, 259, 78, 259, 79, 259, 546, 259,
+    80, 259, 82, 259, 84, 259, 85, 259, 87, 259, 97, 259, 592, 259, 593, 259,
+    7426, 259, 98, 259, 100, 259, 101, 259, 601, 259, 603, 259, 604, 259,
+    103, 259, 107, 259, 109, 259, 331, 259, 111, 259, 596, 259, 7446, 259,
+    7447, 259, 112, 259, 116, 259, 117, 259, 7453, 259, 623, 259, 118, 259,
+    7461, 259, 946, 259, 947, 259, 948, 259, 966, 259, 967, 261, 105, 261,
+    114, 261, 117, 261, 118, 261, 946, 261, 947, 261, 961, 261, 966, 261,
+    967, 259, 1085, 259, 594, 259, 99, 259, 597, 259, 240, 259, 604, 259,
+    102, 259, 607, 259, 609, 259, 613, 259, 616, 259, 617, 259, 618, 259,
+    7547, 259, 669, 259, 621, 259, 7557, 259, 671, 259, 625, 259, 624, 259,
+    626, 259, 627, 259, 628, 259, 629, 259, 632, 259, 642, 259, 643, 259,
+    427, 259, 649, 259, 650, 259, 7452, 259, 651, 259, 652, 259, 122, 259,
+    656, 259, 657, 259, 658, 259, 952, 512, 65, 805, 512, 97, 805, 512, 66,
+    775, 512, 98, 775, 512, 66, 803, 512, 98, 803, 512, 66, 817, 512, 98,
+    817, 512, 199, 769, 512, 231, 769, 512, 68, 775, 512, 100, 775, 512, 68,
+    803, 512, 100, 803, 512, 68, 817, 512, 100, 817, 512, 68, 807, 512, 100,
+    807, 512, 68, 813, 512, 100, 813, 512, 274, 768, 512, 275, 768, 512, 274,
+    769, 512, 275, 769, 512, 69, 813, 512, 101, 813, 512, 69, 816, 512, 101,
+    816, 512, 552, 774, 512, 553, 774, 512, 70, 775, 512, 102, 775, 512, 71,
+    772, 512, 103, 772, 512, 72, 775, 512, 104, 775, 512, 72, 803, 512, 104,
+    803, 512, 72, 776, 512, 104, 776, 512, 72, 807, 512, 104, 807, 512, 72,
+    814, 512, 104, 814, 512, 73, 816, 512, 105, 816, 512, 207, 769, 512, 239,
+    769, 512, 75, 769, 512, 107, 769, 512, 75, 803, 512, 107, 803, 512, 75,
+    817, 512, 107, 817, 512, 76, 803, 512, 108, 803, 512, 7734, 772, 512,
+    7735, 772, 512, 76, 817, 512, 108, 817, 512, 76, 813, 512, 108, 813, 512,
+    77, 769, 512, 109, 769, 512, 77, 775, 512, 109, 775, 512, 77, 803, 512,
+    109, 803, 512, 78, 775, 512, 110, 775, 512, 78, 803, 512, 110, 803, 512,
+    78, 817, 512, 110, 817, 512, 78, 813, 512, 110, 813, 512, 213, 769, 512,
+    245, 769, 512, 213, 776, 512, 245, 776, 512, 332, 768, 512, 333, 768,
+    512, 332, 769, 512, 333, 769, 512, 80, 769, 512, 112, 769, 512, 80, 775,
+    512, 112, 775, 512, 82, 775, 512, 114, 775, 512, 82, 803, 512, 114, 803,
+    512, 7770, 772, 512, 7771, 772, 512, 82, 817, 512, 114, 817, 512, 83,
+    775, 512, 115, 775, 512, 83, 803, 512, 115, 803, 512, 346, 775, 512, 347,
+    775, 512, 352, 775, 512, 353, 775, 512, 7778, 775, 512, 7779, 775, 512,
+    84, 775, 512, 116, 775, 512, 84, 803, 512, 116, 803, 512, 84, 817, 512,
+    116, 817, 512, 84, 813, 512, 116, 813, 512, 85, 804, 512, 117, 804, 512,
+    85, 816, 512, 117, 816, 512, 85, 813, 512, 117, 813, 512, 360, 769, 512,
+    361, 769, 512, 362, 776, 512, 363, 776, 512, 86, 771, 512, 118, 771, 512,
+    86, 803, 512, 118, 803, 512, 87, 768, 512, 119, 768, 512, 87, 769, 512,
+    119, 769, 512, 87, 776, 512, 119, 776, 512, 87, 775, 512, 119, 775, 512,
+    87, 803, 512, 119, 803, 512, 88, 775, 512, 120, 775, 512, 88, 776, 512,
+    120, 776, 512, 89, 775, 512, 121, 775, 512, 90, 770, 512, 122, 770, 512,
+    90, 803, 512, 122, 803, 512, 90, 817, 512, 122, 817, 512, 104, 817, 512,
+    116, 776, 512, 119, 778, 512, 121, 778, 514, 97, 702, 512, 383, 775, 512,
+    65, 803, 512, 97, 803, 512, 65, 777, 512, 97, 777, 512, 194, 769, 512,
+    226, 769, 512, 194, 768, 512, 226, 768, 512, 194, 777, 512, 226, 777,
+    512, 194, 771, 512, 226, 771, 512, 7840, 770, 512, 7841, 770, 512, 258,
+    769, 512, 259, 769, 512, 258, 768, 512, 259, 768, 512, 258, 777, 512,
+    259, 777, 512, 258, 771, 512, 259, 771, 512, 7840, 774, 512, 7841, 774,
+    512, 69, 803, 512, 101, 803, 512, 69, 777, 512, 101, 777, 512, 69, 771,
+    512, 101, 771, 512, 202, 769, 512, 234, 769, 512, 202, 768, 512, 234,
+    768, 512, 202, 777, 512, 234, 777, 512, 202, 771, 512, 234, 771, 512,
+    7864, 770, 512, 7865, 770, 512, 73, 777, 512, 105, 777, 512, 73, 803,
+    512, 105, 803, 512, 79, 803, 512, 111, 803, 512, 79, 777, 512, 111, 777,
+    512, 212, 769, 512, 244, 769, 512, 212, 768, 512, 244, 768, 512, 212,
+    777, 512, 244, 777, 512, 212, 771, 512, 244, 771, 512, 7884, 770, 512,
+    7885, 770, 512, 416, 769, 512, 417, 769, 512, 416, 768, 512, 417, 768,
+    512, 416, 777, 512, 417, 777, 512, 416, 771, 512, 417, 771, 512, 416,
+    803, 512, 417, 803, 512, 85, 803, 512, 117, 803, 512, 85, 777, 512, 117,
+    777, 512, 431, 769, 512, 432, 769, 512, 431, 768, 512, 432, 768, 512,
+    431, 777, 512, 432, 777, 512, 431, 771, 512, 432, 771, 512, 431, 803,
+    512, 432, 803, 512, 89, 768, 512, 121, 768, 512, 89, 803, 512, 121, 803,
+    512, 89, 777, 512, 121, 777, 512, 89, 771, 512, 121, 771, 512, 945, 787,
+    512, 945, 788, 512, 7936, 768, 512, 7937, 768, 512, 7936, 769, 512, 7937,
+    769, 512, 7936, 834, 512, 7937, 834, 512, 913, 787, 512, 913, 788, 512,
+    7944, 768, 512, 7945, 768, 512, 7944, 769, 512, 7945, 769, 512, 7944,
+    834, 512, 7945, 834, 512, 949, 787, 512, 949, 788, 512, 7952, 768, 512,
+    7953, 768, 512, 7952, 769, 512, 7953, 769, 512, 917, 787, 512, 917, 788,
+    512, 7960, 768, 512, 7961, 768, 512, 7960, 769, 512, 7961, 769, 512, 951,
+    787, 512, 951, 788, 512, 7968, 768, 512, 7969, 768, 512, 7968, 769, 512,
+    7969, 769, 512, 7968, 834, 512, 7969, 834, 512, 919, 787, 512, 919, 788,
+    512, 7976, 768, 512, 7977, 768, 512, 7976, 769, 512, 7977, 769, 512,
+    7976, 834, 512, 7977, 834, 512, 953, 787, 512, 953, 788, 512, 7984, 768,
+    512, 7985, 768, 512, 7984, 769, 512, 7985, 769, 512, 7984, 834, 512,
+    7985, 834, 512, 921, 787, 512, 921, 788, 512, 7992, 768, 512, 7993, 768,
+    512, 7992, 769, 512, 7993, 769, 512, 7992, 834, 512, 7993, 834, 512, 959,
+    787, 512, 959, 788, 512, 8000, 768, 512, 8001, 768, 512, 8000, 769, 512,
+    8001, 769, 512, 927, 787, 512, 927, 788, 512, 8008, 768, 512, 8009, 768,
+    512, 8008, 769, 512, 8009, 769, 512, 965, 787, 512, 965, 788, 512, 8016,
+    768, 512, 8017, 768, 512, 8016, 769, 512, 8017, 769, 512, 8016, 834, 512,
+    8017, 834, 512, 933, 788, 512, 8025, 768, 512, 8025, 769, 512, 8025, 834,
+    512, 969, 787, 512, 969, 788, 512, 8032, 768, 512, 8033, 768, 512, 8032,
+    769, 512, 8033, 769, 512, 8032, 834, 512, 8033, 834, 512, 937, 787, 512,
+    937, 788, 512, 8040, 768, 512, 8041, 768, 512, 8040, 769, 512, 8041, 769,
+    512, 8040, 834, 512, 8041, 834, 512, 945, 768, 256, 940, 512, 949, 768,
+    256, 941, 512, 951, 768, 256, 942, 512, 953, 768, 256, 943, 512, 959,
+    768, 256, 972, 512, 965, 768, 256, 973, 512, 969, 768, 256, 974, 512,
+    7936, 837, 512, 7937, 837, 512, 7938, 837, 512, 7939, 837, 512, 7940,
+    837, 512, 7941, 837, 512, 7942, 837, 512, 7943, 837, 512, 7944, 837, 512,
+    7945, 837, 512, 7946, 837, 512, 7947, 837, 512, 7948, 837, 512, 7949,
+    837, 512, 7950, 837, 512, 7951, 837, 512, 7968, 837, 512, 7969, 837, 512,
+    7970, 837, 512, 7971, 837, 512, 7972, 837, 512, 7973, 837, 512, 7974,
+    837, 512, 7975, 837, 512, 7976, 837, 512, 7977, 837, 512, 7978, 837, 512,
+    7979, 837, 512, 7980, 837, 512, 7981, 837, 512, 7982, 837, 512, 7983,
+    837, 512, 8032, 837, 512, 8033, 837, 512, 8034, 837, 512, 8035, 837, 512,
+    8036, 837, 512, 8037, 837, 512, 8038, 837, 512, 8039, 837, 512, 8040,
+    837, 512, 8041, 837, 512, 8042, 837, 512, 8043, 837, 512, 8044, 837, 512,
+    8045, 837, 512, 8046, 837, 512, 8047, 837, 512, 945, 774, 512, 945, 772,
+    512, 8048, 837, 512, 945, 837, 512, 940, 837, 512, 945, 834, 512, 8118,
+    837, 512, 913, 774, 512, 913, 772, 512, 913, 768, 256, 902, 512, 913,
+    837, 514, 32, 787, 256, 953, 514, 32, 787, 514, 32, 834, 512, 168, 834,
+    512, 8052, 837, 512, 951, 837, 512, 942, 837, 512, 951, 834, 512, 8134,
+    837, 512, 917, 768, 256, 904, 512, 919, 768, 256, 905, 512, 919, 837,
+    512, 8127, 768, 512, 8127, 769, 512, 8127, 834, 512, 953, 774, 512, 953,
+    772, 512, 970, 768, 256, 912, 512, 953, 834, 512, 970, 834, 512, 921,
+    774, 512, 921, 772, 512, 921, 768, 256, 906, 512, 8190, 768, 512, 8190,
+    769, 512, 8190, 834, 512, 965, 774, 512, 965, 772, 512, 971, 768, 256,
+    944, 512, 961, 787, 512, 961, 788, 512, 965, 834, 512, 971, 834, 512,
+    933, 774, 512, 933, 772, 512, 933, 768, 256, 910, 512, 929, 788, 512,
+    168, 768, 256, 901, 256, 96, 512, 8060, 837, 512, 969, 837, 512, 974,
+    837, 512, 969, 834, 512, 8182, 837, 512, 927, 768, 256, 908, 512, 937,
+    768, 256, 911, 512, 937, 837, 256, 180, 514, 32, 788, 256, 8194, 256,
+    8195, 258, 32, 258, 32, 258, 32, 258, 32, 258, 32, 257, 32, 258, 32, 258,
+    32, 258, 32, 257, 8208, 514, 32, 819, 258, 46, 514, 46, 46, 770, 46, 46,
+    46, 257, 32, 514, 8242, 8242, 770, 8242, 8242, 8242, 514, 8245, 8245,
+    770, 8245, 8245, 8245, 514, 33, 33, 514, 32, 773, 514, 63, 63, 514, 63,
+    33, 514, 33, 63, 1026, 8242, 8242, 8242, 8242, 258, 32, 259, 48, 259,
+    105, 259, 52, 259, 53, 259, 54, 259, 55, 259, 56, 259, 57, 259, 43, 259,
+    8722, 259, 61, 259, 40, 259, 41, 259, 110, 261, 48, 261, 49, 261, 50,
+    261, 51, 261, 52, 261, 53, 261, 54, 261, 55, 261, 56, 261, 57, 261, 43,
+    261, 8722, 261, 61, 261, 40, 261, 41, 261, 97, 261, 101, 261, 111, 261,
+    120, 261, 601, 261, 104, 261, 107, 261, 108, 261, 109, 261, 110, 261,
+    112, 261, 115, 261, 116, 514, 82, 115, 770, 97, 47, 99, 770, 97, 47, 115,
+    262, 67, 514, 176, 67, 770, 99, 47, 111, 770, 99, 47, 117, 258, 400, 514,
+    176, 70, 262, 103, 262, 72, 262, 72, 262, 72, 262, 104, 262, 295, 262,
+    73, 262, 73, 262, 76, 262, 108, 262, 78, 514, 78, 111, 262, 80, 262, 81,
+    262, 82, 262, 82, 262, 82, 515, 83, 77, 770, 84, 69, 76, 515, 84, 77,
+    262, 90, 256, 937, 262, 90, 256, 75, 256, 197, 262, 66, 262, 67, 262,
+    101, 262, 69, 262, 70, 262, 77, 262, 111, 258, 1488, 258, 1489, 258,
+    1490, 258, 1491, 262, 105, 770, 70, 65, 88, 262, 960, 262, 947, 262, 915,
+    262, 928, 262, 8721, 262, 68, 262, 100, 262, 101, 262, 105, 262, 106,
+    772, 49, 8260, 55, 772, 49, 8260, 57, 1028, 49, 8260, 49, 48, 772, 49,
+    8260, 51, 772, 50, 8260, 51, 772, 49, 8260, 53, 772, 50, 8260, 53, 772,
+    51, 8260, 53, 772, 52, 8260, 53, 772, 49, 8260, 54, 772, 53, 8260, 54,
+    772, 49, 8260, 56, 772, 51, 8260, 56, 772, 53, 8260, 56, 772, 55, 8260,
+    56, 516, 49, 8260, 258, 73, 514, 73, 73, 770, 73, 73, 73, 514, 73, 86,
+    258, 86, 514, 86, 73, 770, 86, 73, 73, 1026, 86, 73, 73, 73, 514, 73, 88,
+    258, 88, 514, 88, 73, 770, 88, 73, 73, 258, 76, 258, 67, 258, 68, 258,
+    77, 258, 105, 514, 105, 105, 770, 105, 105, 105, 514, 105, 118, 258, 118,
+    514, 118, 105, 770, 118, 105, 105, 1026, 118, 105, 105, 105, 514, 105,
+    120, 258, 120, 514, 120, 105, 770, 120, 105, 105, 258, 108, 258, 99, 258,
+    100, 258, 109, 772, 48, 8260, 51, 512, 8592, 824, 512, 8594, 824, 512,
+    8596, 824, 512, 8656, 824, 512, 8660, 824, 512, 8658, 824, 512, 8707,
+    824, 512, 8712, 824, 512, 8715, 824, 512, 8739, 824, 512, 8741, 824, 514,
+    8747, 8747, 770, 8747, 8747, 8747, 514, 8750, 8750, 770, 8750, 8750,
+    8750, 512, 8764, 824, 512, 8771, 824, 512, 8773, 824, 512, 8776, 824,
+    512, 61, 824, 512, 8801, 824, 512, 8781, 824, 512, 60, 824, 512, 62, 824,
+    512, 8804, 824, 512, 8805, 824, 512, 8818, 824, 512, 8819, 824, 512,
+    8822, 824, 512, 8823, 824, 512, 8826, 824, 512, 8827, 824, 512, 8834,
+    824, 512, 8835, 824, 512, 8838, 824, 512, 8839, 824, 512, 8866, 824, 512,
+    8872, 824, 512, 8873, 824, 512, 8875, 824, 512, 8828, 824, 512, 8829,
+    824, 512, 8849, 824, 512, 8850, 824, 512, 8882, 824, 512, 8883, 824, 512,
+    8884, 824, 512, 8885, 824, 256, 12296, 256, 12297, 263, 49, 263, 50, 263,
+    51, 263, 52, 263, 53, 263, 54, 263, 55, 263, 56, 263, 57, 519, 49, 48,
+    519, 49, 49, 519, 49, 50, 519, 49, 51, 519, 49, 52, 519, 49, 53, 519, 49,
+    54, 519, 49, 55, 519, 49, 56, 519, 49, 57, 519, 50, 48, 770, 40, 49, 41,
+    770, 40, 50, 41, 770, 40, 51, 41, 770, 40, 52, 41, 770, 40, 53, 41, 770,
+    40, 54, 41, 770, 40, 55, 41, 770, 40, 56, 41, 770, 40, 57, 41, 1026, 40,
+    49, 48, 41, 1026, 40, 49, 49, 41, 1026, 40, 49, 50, 41, 1026, 40, 49, 51,
+    41, 1026, 40, 49, 52, 41, 1026, 40, 49, 53, 41, 1026, 40, 49, 54, 41,
+    1026, 40, 49, 55, 41, 1026, 40, 49, 56, 41, 1026, 40, 49, 57, 41, 1026,
+    40, 50, 48, 41, 514, 49, 46, 514, 50, 46, 514, 51, 46, 514, 52, 46, 514,
+    53, 46, 514, 54, 46, 514, 55, 46, 514, 56, 46, 514, 57, 46, 770, 49, 48,
+    46, 770, 49, 49, 46, 770, 49, 50, 46, 770, 49, 51, 46, 770, 49, 52, 46,
+    770, 49, 53, 46, 770, 49, 54, 46, 770, 49, 55, 46, 770, 49, 56, 46, 770,
+    49, 57, 46, 770, 50, 48, 46, 770, 40, 97, 41, 770, 40, 98, 41, 770, 40,
+    99, 41, 770, 40, 100, 41, 770, 40, 101, 41, 770, 40, 102, 41, 770, 40,
+    103, 41, 770, 40, 104, 41, 770, 40, 105, 41, 770, 40, 106, 41, 770, 40,
+    107, 41, 770, 40, 108, 41, 770, 40, 109, 41, 770, 40, 110, 41, 770, 40,
+    111, 41, 770, 40, 112, 41, 770, 40, 113, 41, 770, 40, 114, 41, 770, 40,
+    115, 41, 770, 40, 116, 41, 770, 40, 117, 41, 770, 40, 118, 41, 770, 40,
+    119, 41, 770, 40, 120, 41, 770, 40, 121, 41, 770, 40, 122, 41, 263, 65,
+    263, 66, 263, 67, 263, 68, 263, 69, 263, 70, 263, 71, 263, 72, 263, 73,
+    263, 74, 263, 75, 263, 76, 263, 77, 263, 78, 263, 79, 263, 80, 263, 81,
+    263, 82, 263, 83, 263, 84, 263, 85, 263, 86, 263, 87, 263, 88, 263, 89,
+    263, 90, 263, 97, 263, 98, 263, 99, 263, 100, 263, 101, 263, 102, 263,
+    103, 263, 104, 263, 105, 263, 106, 263, 107, 263, 108, 263, 109, 263,
+    110, 263, 111, 263, 112, 263, 113, 263, 114, 263, 115, 263, 116, 263,
+    117, 263, 118, 263, 119, 263, 120, 263, 121, 263, 122, 263, 48, 1026,
+    8747, 8747, 8747, 8747, 770, 58, 58, 61, 514, 61, 61, 770, 61, 61, 61,
+    512, 10973, 824, 261, 106, 259, 86, 259, 11617, 258, 27597, 258, 40863,
+    258, 19968, 258, 20008, 258, 20022, 258, 20031, 258, 20057, 258, 20101,
+    258, 20108, 258, 20128, 258, 20154, 258, 20799, 258, 20837, 258, 20843,
+    258, 20866, 258, 20886, 258, 20907, 258, 20960, 258, 20981, 258, 20992,
+    258, 21147, 258, 21241, 258, 21269, 258, 21274, 258, 21304, 258, 21313,
+    258, 21340, 258, 21353, 258, 21378, 258, 21430, 258, 21448, 258, 21475,
+    258, 22231, 258, 22303, 258, 22763, 258, 22786, 258, 22794, 258, 22805,
+    258, 22823, 258, 22899, 258, 23376, 258, 23424, 258, 23544, 258, 23567,
+    258, 23586, 258, 23608, 258, 23662, 258, 23665, 258, 24027, 258, 24037,
+    258, 24049, 258, 24062, 258, 24178, 258, 24186, 258, 24191, 258, 24308,
+    258, 24318, 258, 24331, 258, 24339, 258, 24400, 258, 24417, 258, 24435,
+    258, 24515, 258, 25096, 258, 25142, 258, 25163, 258, 25903, 258, 25908,
+    258, 25991, 258, 26007, 258, 26020, 258, 26041, 258, 26080, 258, 26085,
+    258, 26352, 258, 26376, 258, 26408, 258, 27424, 258, 27490, 258, 27513,
+    258, 27571, 258, 27595, 258, 27604, 258, 27611, 258, 27663, 258, 27668,
+    258, 27700, 258, 28779, 258, 29226, 258, 29238, 258, 29243, 258, 29247,
+    258, 29255, 258, 29273, 258, 29275, 258, 29356, 258, 29572, 258, 29577,
+    258, 29916, 258, 29926, 258, 29976, 258, 29983, 258, 29992, 258, 30000,
+    258, 30091, 258, 30098, 258, 30326, 258, 30333, 258, 30382, 258, 30399,
+    258, 30446, 258, 30683, 258, 30690, 258, 30707, 258, 31034, 258, 31160,
+    258, 31166, 258, 31348, 258, 31435, 258, 31481, 258, 31859, 258, 31992,
+    258, 32566, 258, 32593, 258, 32650, 258, 32701, 258, 32769, 258, 32780,
+    258, 32786, 258, 32819, 258, 32895, 258, 32905, 258, 33251, 258, 33258,
+    258, 33267, 258, 33276, 258, 33292, 258, 33307, 258, 33311, 258, 33390,
+    258, 33394, 258, 33400, 258, 34381, 258, 34411, 258, 34880, 258, 34892,
+    258, 34915, 258, 35198, 258, 35211, 258, 35282, 258, 35328, 258, 35895,
+    258, 35910, 258, 35925, 258, 35960, 258, 35997, 258, 36196, 258, 36208,
+    258, 36275, 258, 36523, 258, 36554, 258, 36763, 258, 36784, 258, 36789,
+    258, 37009, 258, 37193, 258, 37318, 258, 37324, 258, 37329, 258, 38263,
+    258, 38272, 258, 38428, 258, 38582, 258, 38585, 258, 38632, 258, 38737,
+    258, 38750, 258, 38754, 258, 38761, 258, 38859, 258, 38893, 258, 38899,
+    258, 38913, 258, 39080, 258, 39131, 258, 39135, 258, 39318, 258, 39321,
+    258, 39340, 258, 39592, 258, 39640, 258, 39647, 258, 39717, 258, 39727,
+    258, 39730, 258, 39740, 258, 39770, 258, 40165, 258, 40565, 258, 40575,
+    258, 40613, 258, 40635, 258, 40643, 258, 40653, 258, 40657, 258, 40697,
+    258, 40701, 258, 40718, 258, 40723, 258, 40736, 258, 40763, 258, 40778,
+    258, 40786, 258, 40845, 258, 40860, 258, 40864, 264, 32, 258, 12306, 258,
+    21313, 258, 21316, 258, 21317, 512, 12363, 12441, 512, 12365, 12441, 512,
+    12367, 12441, 512, 12369, 12441, 512, 12371, 12441, 512, 12373, 12441,
+    512, 12375, 12441, 512, 12377, 12441, 512, 12379, 12441, 512, 12381,
+    12441, 512, 12383, 12441, 512, 12385, 12441, 512, 12388, 12441, 512,
+    12390, 12441, 512, 12392, 12441, 512, 12399, 12441, 512, 12399, 12442,
+    512, 12402, 12441, 512, 12402, 12442, 512, 12405, 12441, 512, 12405,
+    12442, 512, 12408, 12441, 512, 12408, 12442, 512, 12411, 12441, 512,
+    12411, 12442, 512, 12358, 12441, 514, 32, 12441, 514, 32, 12442, 512,
+    12445, 12441, 521, 12424, 12426, 512, 12459, 12441, 512, 12461, 12441,
+    512, 12463, 12441, 512, 12465, 12441, 512, 12467, 12441, 512, 12469,
+    12441, 512, 12471, 12441, 512, 12473, 12441, 512, 12475, 12441, 512,
+    12477, 12441, 512, 12479, 12441, 512, 12481, 12441, 512, 12484, 12441,
+    512, 12486, 12441, 512, 12488, 12441, 512, 12495, 12441, 512, 12495,
+    12442, 512, 12498, 12441, 512, 12498, 12442, 512, 12501, 12441, 512,
+    12501, 12442, 512, 12504, 12441, 512, 12504, 12442, 512, 12507, 12441,
+    512, 12507, 12442, 512, 12454, 12441, 512, 12527, 12441, 512, 12528,
+    12441, 512, 12529, 12441, 512, 12530, 12441, 512, 12541, 12441, 521,
+    12467, 12488, 258, 4352, 258, 4353, 258, 4522, 258, 4354, 258, 4524, 258,
+    4525, 258, 4355, 258, 4356, 258, 4357, 258, 4528, 258, 4529, 258, 4530,
+    258, 4531, 258, 4532, 258, 4533, 258, 4378, 258, 4358, 258, 4359, 258,
+    4360, 258, 4385, 258, 4361, 258, 4362, 258, 4363, 258, 4364, 258, 4365,
+    258, 4366, 258, 4367, 258, 4368, 258, 4369, 258, 4370, 258, 4449, 258,
+    4450, 258, 4451, 258, 4452, 258, 4453, 258, 4454, 258, 4455, 258, 4456,
+    258, 4457, 258, 4458, 258, 4459, 258, 4460, 258, 4461, 258, 4462, 258,
+    4463, 258, 4464, 258, 4465, 258, 4466, 258, 4467, 258, 4468, 258, 4469,
+    258, 4448, 258, 4372, 258, 4373, 258, 4551, 258, 4552, 258, 4556, 258,
+    4558, 258, 4563, 258, 4567, 258, 4569, 258, 4380, 258, 4573, 258, 4575,
+    258, 4381, 258, 4382, 258, 4384, 258, 4386, 258, 4387, 258, 4391, 258,
+    4393, 258, 4395, 258, 4396, 258, 4397, 258, 4398, 258, 4399, 258, 4402,
+    258, 4406, 258, 4416, 258, 4423, 258, 4428, 258, 4593, 258, 4594, 258,
+    4439, 258, 4440, 258, 4441, 258, 4484, 258, 4485, 258, 4488, 258, 4497,
+    258, 4498, 258, 4500, 258, 4510, 258, 4513, 259, 19968, 259, 20108, 259,
+    19977, 259, 22235, 259, 19978, 259, 20013, 259, 19979, 259, 30002, 259,
+    20057, 259, 19993, 259, 19969, 259, 22825, 259, 22320, 259, 20154, 770,
+    40, 4352, 41, 770, 40, 4354, 41, 770, 40, 4355, 41, 770, 40, 4357, 41,
+    770, 40, 4358, 41, 770, 40, 4359, 41, 770, 40, 4361, 41, 770, 40, 4363,
+    41, 770, 40, 4364, 41, 770, 40, 4366, 41, 770, 40, 4367, 41, 770, 40,
+    4368, 41, 770, 40, 4369, 41, 770, 40, 4370, 41, 1026, 40, 4352, 4449, 41,
+    1026, 40, 4354, 4449, 41, 1026, 40, 4355, 4449, 41, 1026, 40, 4357, 4449,
+    41, 1026, 40, 4358, 4449, 41, 1026, 40, 4359, 4449, 41, 1026, 40, 4361,
+    4449, 41, 1026, 40, 4363, 4449, 41, 1026, 40, 4364, 4449, 41, 1026, 40,
+    4366, 4449, 41, 1026, 40, 4367, 4449, 41, 1026, 40, 4368, 4449, 41, 1026,
+    40, 4369, 4449, 41, 1026, 40, 4370, 4449, 41, 1026, 40, 4364, 4462, 41,
+    1794, 40, 4363, 4457, 4364, 4453, 4523, 41, 1538, 40, 4363, 4457, 4370,
+    4462, 41, 770, 40, 19968, 41, 770, 40, 20108, 41, 770, 40, 19977, 41,
+    770, 40, 22235, 41, 770, 40, 20116, 41, 770, 40, 20845, 41, 770, 40,
+    19971, 41, 770, 40, 20843, 41, 770, 40, 20061, 41, 770, 40, 21313, 41,
+    770, 40, 26376, 41, 770, 40, 28779, 41, 770, 40, 27700, 41, 770, 40,
+    26408, 41, 770, 40, 37329, 41, 770, 40, 22303, 41, 770, 40, 26085, 41,
+    770, 40, 26666, 41, 770, 40, 26377, 41, 770, 40, 31038, 41, 770, 40,
+    21517, 41, 770, 40, 29305, 41, 770, 40, 36001, 41, 770, 40, 31069, 41,
+    770, 40, 21172, 41, 770, 40, 20195, 41, 770, 40, 21628, 41, 770, 40,
+    23398, 41, 770, 40, 30435, 41, 770, 40, 20225, 41, 770, 40, 36039, 41,
+    770, 40, 21332, 41, 770, 40, 31085, 41, 770, 40, 20241, 41, 770, 40,
+    33258, 41, 770, 40, 33267, 41, 263, 21839, 263, 24188, 263, 25991, 263,
+    31631, 778, 80, 84, 69, 519, 50, 49, 519, 50, 50, 519, 50, 51, 519, 50,
+    52, 519, 50, 53, 519, 50, 54, 519, 50, 55, 519, 50, 56, 519, 50, 57, 519,
+    51, 48, 519, 51, 49, 519, 51, 50, 519, 51, 51, 519, 51, 52, 519, 51, 53,
+    263, 4352, 263, 4354, 263, 4355, 263, 4357, 263, 4358, 263, 4359, 263,
+    4361, 263, 4363, 263, 4364, 263, 4366, 263, 4367, 263, 4368, 263, 4369,
+    263, 4370, 519, 4352, 4449, 519, 4354, 4449, 519, 4355, 4449, 519, 4357,
+    4449, 519, 4358, 4449, 519, 4359, 4449, 519, 4361, 4449, 519, 4363, 4449,
+    519, 4364, 4449, 519, 4366, 4449, 519, 4367, 4449, 519, 4368, 4449, 519,
+    4369, 4449, 519, 4370, 4449, 1287, 4366, 4449, 4535, 4352, 4457, 1031,
+    4364, 4462, 4363, 4468, 519, 4363, 4462, 263, 19968, 263, 20108, 263,
+    19977, 263, 22235, 263, 20116, 263, 20845, 263, 19971, 263, 20843, 263,
+    20061, 263, 21313, 263, 26376, 263, 28779, 263, 27700, 263, 26408, 263,
+    37329, 263, 22303, 263, 26085, 263, 26666, 263, 26377, 263, 31038, 263,
+    21517, 263, 29305, 263, 36001, 263, 31069, 263, 21172, 263, 31192, 263,
+    30007, 263, 22899, 263, 36969, 263, 20778, 263, 21360, 263, 27880, 263,
+    38917, 263, 20241, 263, 20889, 263, 27491, 263, 19978, 263, 20013, 263,
+    19979, 263, 24038, 263, 21491, 263, 21307, 263, 23447, 263, 23398, 263,
+    30435, 263, 20225, 263, 36039, 263, 21332, 263, 22812, 519, 51, 54, 519,
+    51, 55, 519, 51, 56, 519, 51, 57, 519, 52, 48, 519, 52, 49, 519, 52, 50,
+    519, 52, 51, 519, 52, 52, 519, 52, 53, 519, 52, 54, 519, 52, 55, 519, 52,
+    56, 519, 52, 57, 519, 53, 48, 514, 49, 26376, 514, 50, 26376, 514, 51,
+    26376, 514, 52, 26376, 514, 53, 26376, 514, 54, 26376, 514, 55, 26376,
+    514, 56, 26376, 514, 57, 26376, 770, 49, 48, 26376, 770, 49, 49, 26376,
+    770, 49, 50, 26376, 522, 72, 103, 778, 101, 114, 103, 522, 101, 86, 778,
+    76, 84, 68, 263, 12450, 263, 12452, 263, 12454, 263, 12456, 263, 12458,
+    263, 12459, 263, 12461, 263, 12463, 263, 12465, 263, 12467, 263, 12469,
+    263, 12471, 263, 12473, 263, 12475, 263, 12477, 263, 12479, 263, 12481,
+    263, 12484, 263, 12486, 263, 12488, 263, 12490, 263, 12491, 263, 12492,
+    263, 12493, 263, 12494, 263, 12495, 263, 12498, 263, 12501, 263, 12504,
+    263, 12507, 263, 12510, 263, 12511, 263, 12512, 263, 12513, 263, 12514,
+    263, 12516, 263, 12518, 263, 12520, 263, 12521, 263, 12522, 263, 12523,
+    263, 12524, 263, 12525, 263, 12527, 263, 12528, 263, 12529, 263, 12530,
+    1034, 12450, 12497, 12540, 12488, 1034, 12450, 12523, 12501, 12449, 1034,
+    12450, 12531, 12506, 12450, 778, 12450, 12540, 12523, 1034, 12452, 12491,
+    12531, 12464, 778, 12452, 12531, 12481, 778, 12454, 12457, 12531, 1290,
+    12456, 12473, 12463, 12540, 12489, 1034, 12456, 12540, 12459, 12540, 778,
+    12458, 12531, 12473, 778, 12458, 12540, 12512, 778, 12459, 12452, 12522,
+    1034, 12459, 12521, 12483, 12488, 1034, 12459, 12525, 12522, 12540, 778,
+    12460, 12525, 12531, 778, 12460, 12531, 12510, 522, 12462, 12460, 778,
+    12462, 12491, 12540, 1034, 12461, 12517, 12522, 12540, 1034, 12462,
+    12523, 12480, 12540, 522, 12461, 12525, 1290, 12461, 12525, 12464, 12521,
+    12512, 1546, 12461, 12525, 12513, 12540, 12488, 12523, 1290, 12461,
+    12525, 12527, 12483, 12488, 778, 12464, 12521, 12512, 1290, 12464, 12521,
+    12512, 12488, 12531, 1290, 12463, 12523, 12476, 12452, 12525, 1034,
+    12463, 12525, 12540, 12493, 778, 12465, 12540, 12473, 778, 12467, 12523,
+    12490, 778, 12467, 12540, 12509, 1034, 12469, 12452, 12463, 12523, 1290,
+    12469, 12531, 12481, 12540, 12512, 1034, 12471, 12522, 12531, 12464, 778,
+    12475, 12531, 12481, 778, 12475, 12531, 12488, 778, 12480, 12540, 12473,
+    522, 12487, 12471, 522, 12489, 12523, 522, 12488, 12531, 522, 12490,
+    12494, 778, 12494, 12483, 12488, 778, 12495, 12452, 12484, 1290, 12497,
+    12540, 12475, 12531, 12488, 778, 12497, 12540, 12484, 1034, 12496, 12540,
+    12524, 12523, 1290, 12500, 12450, 12473, 12488, 12523, 778, 12500, 12463,
+    12523, 522, 12500, 12467, 522, 12499, 12523, 1290, 12501, 12449, 12521,
+    12483, 12489, 1034, 12501, 12451, 12540, 12488, 1290, 12502, 12483,
+    12471, 12455, 12523, 778, 12501, 12521, 12531, 1290, 12504, 12463, 12479,
+    12540, 12523, 522, 12506, 12477, 778, 12506, 12491, 12498, 778, 12504,
+    12523, 12484, 778, 12506, 12531, 12473, 778, 12506, 12540, 12472, 778,
+    12505, 12540, 12479, 1034, 12509, 12452, 12531, 12488, 778, 12508, 12523,
+    12488, 522, 12507, 12531, 778, 12509, 12531, 12489, 778, 12507, 12540,
+    12523, 778, 12507, 12540, 12531, 1034, 12510, 12452, 12463, 12525, 778,
+    12510, 12452, 12523, 778, 12510, 12483, 12495, 778, 12510, 12523, 12463,
+    1290, 12510, 12531, 12471, 12519, 12531, 1034, 12511, 12463, 12525,
+    12531, 522, 12511, 12522, 1290, 12511, 12522, 12496, 12540, 12523, 522,
+    12513, 12460, 1034, 12513, 12460, 12488, 12531, 1034, 12513, 12540,
+    12488, 12523, 778, 12516, 12540, 12489, 778, 12516, 12540, 12523, 778,
+    12518, 12450, 12531, 1034, 12522, 12483, 12488, 12523, 522, 12522, 12521,
+    778, 12523, 12500, 12540, 1034, 12523, 12540, 12502, 12523, 522, 12524,
+    12512, 1290, 12524, 12531, 12488, 12466, 12531, 778, 12527, 12483, 12488,
+    514, 48, 28857, 514, 49, 28857, 514, 50, 28857, 514, 51, 28857, 514, 52,
+    28857, 514, 53, 28857, 514, 54, 28857, 514, 55, 28857, 514, 56, 28857,
+    514, 57, 28857, 770, 49, 48, 28857, 770, 49, 49, 28857, 770, 49, 50,
+    28857, 770, 49, 51, 28857, 770, 49, 52, 28857, 770, 49, 53, 28857, 770,
+    49, 54, 28857, 770, 49, 55, 28857, 770, 49, 56, 28857, 770, 49, 57,
+    28857, 770, 50, 48, 28857, 770, 50, 49, 28857, 770, 50, 50, 28857, 770,
+    50, 51, 28857, 770, 50, 52, 28857, 778, 104, 80, 97, 522, 100, 97, 522,
+    65, 85, 778, 98, 97, 114, 522, 111, 86, 522, 112, 99, 522, 100, 109, 778,
+    100, 109, 178, 778, 100, 109, 179, 522, 73, 85, 522, 24179, 25104, 522,
+    26157, 21644, 522, 22823, 27491, 522, 26126, 27835, 1034, 26666, 24335,
+    20250, 31038, 522, 112, 65, 522, 110, 65, 522, 956, 65, 522, 109, 65,
+    522, 107, 65, 522, 75, 66, 522, 77, 66, 522, 71, 66, 778, 99, 97, 108,
+    1034, 107, 99, 97, 108, 522, 112, 70, 522, 110, 70, 522, 956, 70, 522,
+    956, 103, 522, 109, 103, 522, 107, 103, 522, 72, 122, 778, 107, 72, 122,
+    778, 77, 72, 122, 778, 71, 72, 122, 778, 84, 72, 122, 522, 956, 8467,
+    522, 109, 8467, 522, 100, 8467, 522, 107, 8467, 522, 102, 109, 522, 110,
+    109, 522, 956, 109, 522, 109, 109, 522, 99, 109, 522, 107, 109, 778, 109,
+    109, 178, 778, 99, 109, 178, 522, 109, 178, 778, 107, 109, 178, 778, 109,
+    109, 179, 778, 99, 109, 179, 522, 109, 179, 778, 107, 109, 179, 778, 109,
+    8725, 115, 1034, 109, 8725, 115, 178, 522, 80, 97, 778, 107, 80, 97, 778,
+    77, 80, 97, 778, 71, 80, 97, 778, 114, 97, 100, 1290, 114, 97, 100, 8725,
+    115, 1546, 114, 97, 100, 8725, 115, 178, 522, 112, 115, 522, 110, 115,
+    522, 956, 115, 522, 109, 115, 522, 112, 86, 522, 110, 86, 522, 956, 86,
+    522, 109, 86, 522, 107, 86, 522, 77, 86, 522, 112, 87, 522, 110, 87, 522,
+    956, 87, 522, 109, 87, 522, 107, 87, 522, 77, 87, 522, 107, 937, 522, 77,
+    937, 1034, 97, 46, 109, 46, 522, 66, 113, 522, 99, 99, 522, 99, 100,
+    1034, 67, 8725, 107, 103, 778, 67, 111, 46, 522, 100, 66, 522, 71, 121,
+    522, 104, 97, 522, 72, 80, 522, 105, 110, 522, 75, 75, 522, 75, 77, 522,
+    107, 116, 522, 108, 109, 522, 108, 110, 778, 108, 111, 103, 522, 108,
+    120, 522, 109, 98, 778, 109, 105, 108, 778, 109, 111, 108, 522, 80, 72,
+    1034, 112, 46, 109, 46, 778, 80, 80, 77, 522, 80, 82, 522, 115, 114, 522,
+    83, 118, 522, 87, 98, 778, 86, 8725, 109, 778, 65, 8725, 109, 514, 49,
+    26085, 514, 50, 26085, 514, 51, 26085, 514, 52, 26085, 514, 53, 26085,
+    514, 54, 26085, 514, 55, 26085, 514, 56, 26085, 514, 57, 26085, 770, 49,
+    48, 26085, 770, 49, 49, 26085, 770, 49, 50, 26085, 770, 49, 51, 26085,
+    770, 49, 52, 26085, 770, 49, 53, 26085, 770, 49, 54, 26085, 770, 49, 55,
+    26085, 770, 49, 56, 26085, 770, 49, 57, 26085, 770, 50, 48, 26085, 770,
+    50, 49, 26085, 770, 50, 50, 26085, 770, 50, 51, 26085, 770, 50, 52,
+    26085, 770, 50, 53, 26085, 770, 50, 54, 26085, 770, 50, 55, 26085, 770,
+    50, 56, 26085, 770, 50, 57, 26085, 770, 51, 48, 26085, 770, 51, 49,
+    26085, 778, 103, 97, 108, 259, 1098, 259, 1100, 259, 42863, 259, 294,
+    259, 339, 259, 42791, 259, 43831, 259, 619, 259, 43858, 256, 35912, 256,
+    26356, 256, 36554, 256, 36040, 256, 28369, 256, 20018, 256, 21477, 256,
+    40860, 256, 40860, 256, 22865, 256, 37329, 256, 21895, 256, 22856, 256,
+    25078, 256, 30313, 256, 32645, 256, 34367, 256, 34746, 256, 35064, 256,
+    37007, 256, 27138, 256, 27931, 256, 28889, 256, 29662, 256, 33853, 256,
+    37226, 256, 39409, 256, 20098, 256, 21365, 256, 27396, 256, 29211, 256,
+    34349, 256, 40478, 256, 23888, 256, 28651, 256, 34253, 256, 35172, 256,
+    25289, 256, 33240, 256, 34847, 256, 24266, 256, 26391, 256, 28010, 256,
+    29436, 256, 37070, 256, 20358, 256, 20919, 256, 21214, 256, 25796, 256,
+    27347, 256, 29200, 256, 30439, 256, 32769, 256, 34310, 256, 34396, 256,
+    36335, 256, 38706, 256, 39791, 256, 40442, 256, 30860, 256, 31103, 256,
+    32160, 256, 33737, 256, 37636, 256, 40575, 256, 35542, 256, 22751, 256,
+    24324, 256, 31840, 256, 32894, 256, 29282, 256, 30922, 256, 36034, 256,
+    38647, 256, 22744, 256, 23650, 256, 27155, 256, 28122, 256, 28431, 256,
+    32047, 256, 32311, 256, 38475, 256, 21202, 256, 32907, 256, 20956, 256,
+    20940, 256, 31260, 256, 32190, 256, 33777, 256, 38517, 256, 35712, 256,
+    25295, 256, 27138, 256, 35582, 256, 20025, 256, 23527, 256, 24594, 256,
+    29575, 256, 30064, 256, 21271, 256, 30971, 256, 20415, 256, 24489, 256,
+    19981, 256, 27852, 256, 25976, 256, 32034, 256, 21443, 256, 22622, 256,
+    30465, 256, 33865, 256, 35498, 256, 27578, 256, 36784, 256, 27784, 256,
+    25342, 256, 33509, 256, 25504, 256, 30053, 256, 20142, 256, 20841, 256,
+    20937, 256, 26753, 256, 31975, 256, 33391, 256, 35538, 256, 37327, 256,
+    21237, 256, 21570, 256, 22899, 256, 24300, 256, 26053, 256, 28670, 256,
+    31018, 256, 38317, 256, 39530, 256, 40599, 256, 40654, 256, 21147, 256,
+    26310, 256, 27511, 256, 36706, 256, 24180, 256, 24976, 256, 25088, 256,
+    25754, 256, 28451, 256, 29001, 256, 29833, 256, 31178, 256, 32244, 256,
+    32879, 256, 36646, 256, 34030, 256, 36899, 256, 37706, 256, 21015, 256,
+    21155, 256, 21693, 256, 28872, 256, 35010, 256, 35498, 256, 24265, 256,
+    24565, 256, 25467, 256, 27566, 256, 31806, 256, 29557, 256, 20196, 256,
+    22265, 256, 23527, 256, 23994, 256, 24604, 256, 29618, 256, 29801, 256,
+    32666, 256, 32838, 256, 37428, 256, 38646, 256, 38728, 256, 38936, 256,
+    20363, 256, 31150, 256, 37300, 256, 38584, 256, 24801, 256, 20102, 256,
+    20698, 256, 23534, 256, 23615, 256, 26009, 256, 27138, 256, 29134, 256,
+    30274, 256, 34044, 256, 36988, 256, 40845, 256, 26248, 256, 38446, 256,
+    21129, 256, 26491, 256, 26611, 256, 27969, 256, 28316, 256, 29705, 256,
+    30041, 256, 30827, 256, 32016, 256, 39006, 256, 20845, 256, 25134, 256,
+    38520, 256, 20523, 256, 23833, 256, 28138, 256, 36650, 256, 24459, 256,
+    24900, 256, 26647, 256, 29575, 256, 38534, 256, 21033, 256, 21519, 256,
+    23653, 256, 26131, 256, 26446, 256, 26792, 256, 27877, 256, 29702, 256,
+    30178, 256, 32633, 256, 35023, 256, 35041, 256, 37324, 256, 38626, 256,
+    21311, 256, 28346, 256, 21533, 256, 29136, 256, 29848, 256, 34298, 256,
+    38563, 256, 40023, 256, 40607, 256, 26519, 256, 28107, 256, 33256, 256,
+    31435, 256, 31520, 256, 31890, 256, 29376, 256, 28825, 256, 35672, 256,
+    20160, 256, 33590, 256, 21050, 256, 20999, 256, 24230, 256, 25299, 256,
+    31958, 256, 23429, 256, 27934, 256, 26292, 256, 36667, 256, 34892, 256,
+    38477, 256, 35211, 256, 24275, 256, 20800, 256, 21952, 256, 22618, 256,
+    26228, 256, 20958, 256, 29482, 256, 30410, 256, 31036, 256, 31070, 256,
+    31077, 256, 31119, 256, 38742, 256, 31934, 256, 32701, 256, 34322, 256,
+    35576, 256, 36920, 256, 37117, 256, 39151, 256, 39164, 256, 39208, 256,
+    40372, 256, 37086, 256, 38583, 256, 20398, 256, 20711, 256, 20813, 256,
+    21193, 256, 21220, 256, 21329, 256, 21917, 256, 22022, 256, 22120, 256,
+    22592, 256, 22696, 256, 23652, 256, 23662, 256, 24724, 256, 24936, 256,
+    24974, 256, 25074, 256, 25935, 256, 26082, 256, 26257, 256, 26757, 256,
+    28023, 256, 28186, 256, 28450, 256, 29038, 256, 29227, 256, 29730, 256,
+    30865, 256, 31038, 256, 31049, 256, 31048, 256, 31056, 256, 31062, 256,
+    31069, 256, 31117, 256, 31118, 256, 31296, 256, 31361, 256, 31680, 256,
+    32244, 256, 32265, 256, 32321, 256, 32626, 256, 32773, 256, 33261, 256,
+    33401, 256, 33401, 256, 33879, 256, 35088, 256, 35222, 256, 35585, 256,
+    35641, 256, 36051, 256, 36104, 256, 36790, 256, 36920, 256, 38627, 256,
+    38911, 256, 38971, 256, 24693, 256, 55376, 57070, 256, 33304, 256, 20006,
+    256, 20917, 256, 20840, 256, 20352, 256, 20805, 256, 20864, 256, 21191,
+    256, 21242, 256, 21917, 256, 21845, 256, 21913, 256, 21986, 256, 22618,
+    256, 22707, 256, 22852, 256, 22868, 256, 23138, 256, 23336, 256, 24274,
+    256, 24281, 256, 24425, 256, 24493, 256, 24792, 256, 24910, 256, 24840,
+    256, 24974, 256, 24928, 256, 25074, 256, 25140, 256, 25540, 256, 25628,
+    256, 25682, 256, 25942, 256, 26228, 256, 26391, 256, 26395, 256, 26454,
+    256, 27513, 256, 27578, 256, 27969, 256, 28379, 256, 28363, 256, 28450,
+    256, 28702, 256, 29038, 256, 30631, 256, 29237, 256, 29359, 256, 29482,
+    256, 29809, 256, 29958, 256, 30011, 256, 30237, 256, 30239, 256, 30410,
+    256, 30427, 256, 30452, 256, 30538, 256, 30528, 256, 30924, 256, 31409,
+    256, 31680, 256, 31867, 256, 32091, 256, 32244, 256, 32574, 256, 32773,
+    256, 33618, 256, 33775, 256, 34681, 256, 35137, 256, 35206, 256, 35222,
+    256, 35519, 256, 35576, 256, 35531, 256, 35585, 256, 35582, 256, 35565,
+    256, 35641, 256, 35722, 256, 36104, 256, 36664, 256, 36978, 256, 37273,
+    256, 37494, 256, 38524, 256, 38627, 256, 38742, 256, 38875, 256, 38911,
+    256, 38923, 256, 38971, 256, 39698, 256, 40860, 256, 55370, 56394, 256,
+    55370, 56388, 256, 55372, 57301, 256, 15261, 256, 16408, 256, 16441, 256,
+    55380, 56905, 256, 55383, 56528, 256, 55391, 57043, 256, 40771, 256,
+    40846, 514, 102, 102, 514, 102, 105, 514, 102, 108, 770, 102, 102, 105,
+    770, 102, 102, 108, 514, 383, 116, 514, 115, 116, 514, 1396, 1398, 514,
+    1396, 1381, 514, 1396, 1387, 514, 1406, 1398, 514, 1396, 1389, 512, 1497,
+    1460, 512, 1522, 1463, 262, 1506, 262, 1488, 262, 1491, 262, 1492, 262,
+    1499, 262, 1500, 262, 1501, 262, 1512, 262, 1514, 262, 43, 512, 1513,
+    1473, 512, 1513, 1474, 512, 64329, 1473, 512, 64329, 1474, 512, 1488,
+    1463, 512, 1488, 1464, 512, 1488, 1468, 512, 1489, 1468, 512, 1490, 1468,
+    512, 1491, 1468, 512, 1492, 1468, 512, 1493, 1468, 512, 1494, 1468, 512,
+    1496, 1468, 512, 1497, 1468, 512, 1498, 1468, 512, 1499, 1468, 512, 1500,
+    1468, 512, 1502, 1468, 512, 1504, 1468, 512, 1505, 1468, 512, 1507, 1468,
+    512, 1508, 1468, 512, 1510, 1468, 512, 1511, 1468, 512, 1512, 1468, 512,
+    1513, 1468, 512, 1514, 1468, 512, 1493, 1465, 512, 1489, 1471, 512, 1499,
+    1471, 512, 1508, 1471, 514, 1488, 1500, 267, 1649, 268, 1649, 267, 1659,
+    268, 1659, 269, 1659, 270, 1659, 267, 1662, 268, 1662, 269, 1662, 270,
+    1662, 267, 1664, 268, 1664, 269, 1664, 270, 1664, 267, 1658, 268, 1658,
+    269, 1658, 270, 1658, 267, 1663, 268, 1663, 269, 1663, 270, 1663, 267,
+    1657, 268, 1657, 269, 1657, 270, 1657, 267, 1700, 268, 1700, 269, 1700,
+    270, 1700, 267, 1702, 268, 1702, 269, 1702, 270, 1702, 267, 1668, 268,
+    1668, 269, 1668, 270, 1668, 267, 1667, 268, 1667, 269, 1667, 270, 1667,
+    267, 1670, 268, 1670, 269, 1670, 270, 1670, 267, 1671, 268, 1671, 269,
+    1671, 270, 1671, 267, 1677, 268, 1677, 267, 1676, 268, 1676, 267, 1678,
+    268, 1678, 267, 1672, 268, 1672, 267, 1688, 268, 1688, 267, 1681, 268,
+    1681, 267, 1705, 268, 1705, 269, 1705, 270, 1705, 267, 1711, 268, 1711,
+    269, 1711, 270, 1711, 267, 1715, 268, 1715, 269, 1715, 270, 1715, 267,
+    1713, 268, 1713, 269, 1713, 270, 1713, 267, 1722, 268, 1722, 267, 1723,
+    268, 1723, 269, 1723, 270, 1723, 267, 1728, 268, 1728, 267, 1729, 268,
+    1729, 269, 1729, 270, 1729, 267, 1726, 268, 1726, 269, 1726, 270, 1726,
+    267, 1746, 268, 1746, 267, 1747, 268, 1747, 267, 1709, 268, 1709, 269,
+    1709, 270, 1709, 267, 1735, 268, 1735, 267, 1734, 268, 1734, 267, 1736,
+    268, 1736, 267, 1655, 267, 1739, 268, 1739, 267, 1733, 268, 1733, 267,
+    1737, 268, 1737, 267, 1744, 268, 1744, 269, 1744, 270, 1744, 269, 1609,
+    270, 1609, 523, 1574, 1575, 524, 1574, 1575, 523, 1574, 1749, 524, 1574,
+    1749, 523, 1574, 1608, 524, 1574, 1608, 523, 1574, 1735, 524, 1574, 1735,
+    523, 1574, 1734, 524, 1574, 1734, 523, 1574, 1736, 524, 1574, 1736, 523,
+    1574, 1744, 524, 1574, 1744, 525, 1574, 1744, 523, 1574, 1609, 524, 1574,
+    1609, 525, 1574, 1609, 267, 1740, 268, 1740, 269, 1740, 270, 1740, 523,
+    1574, 1580, 523, 1574, 1581, 523, 1574, 1605, 523, 1574, 1609, 523, 1574,
+    1610, 523, 1576, 1580, 523, 1576, 1581, 523, 1576, 1582, 523, 1576, 1605,
+    523, 1576, 1609, 523, 1576, 1610, 523, 1578, 1580, 523, 1578, 1581, 523,
+    1578, 1582, 523, 1578, 1605, 523, 1578, 1609, 523, 1578, 1610, 523, 1579,
+    1580, 523, 1579, 1605, 523, 1579, 1609, 523, 1579, 1610, 523, 1580, 1581,
+    523, 1580, 1605, 523, 1581, 1580, 523, 1581, 1605, 523, 1582, 1580, 523,
+    1582, 1581, 523, 1582, 1605, 523, 1587, 1580, 523, 1587, 1581, 523, 1587,
+    1582, 523, 1587, 1605, 523, 1589, 1581, 523, 1589, 1605, 523, 1590, 1580,
+    523, 1590, 1581, 523, 1590, 1582, 523, 1590, 1605, 523, 1591, 1581, 523,
+    1591, 1605, 523, 1592, 1605, 523, 1593, 1580, 523, 1593, 1605, 523, 1594,
+    1580, 523, 1594, 1605, 523, 1601, 1580, 523, 1601, 1581, 523, 1601, 1582,
+    523, 1601, 1605, 523, 1601, 1609, 523, 1601, 1610, 523, 1602, 1581, 523,
+    1602, 1605, 523, 1602, 1609, 523, 1602, 1610, 523, 1603, 1575, 523, 1603,
+    1580, 523, 1603, 1581, 523, 1603, 1582, 523, 1603, 1604, 523, 1603, 1605,
+    523, 1603, 1609, 523, 1603, 1610, 523, 1604, 1580, 523, 1604, 1581, 523,
+    1604, 1582, 523, 1604, 1605, 523, 1604, 1609, 523, 1604, 1610, 523, 1605,
+    1580, 523, 1605, 1581, 523, 1605, 1582, 523, 1605, 1605, 523, 1605, 1609,
+    523, 1605, 1610, 523, 1606, 1580, 523, 1606, 1581, 523, 1606, 1582, 523,
+    1606, 1605, 523, 1606, 1609, 523, 1606, 1610, 523, 1607, 1580, 523, 1607,
+    1605, 523, 1607, 1609, 523, 1607, 1610, 523, 1610, 1580, 523, 1610, 1581,
+    523, 1610, 1582, 523, 1610, 1605, 523, 1610, 1609, 523, 1610, 1610, 523,
+    1584, 1648, 523, 1585, 1648, 523, 1609, 1648, 779, 32, 1612, 1617, 779,
+    32, 1613, 1617, 779, 32, 1614, 1617, 779, 32, 1615, 1617, 779, 32, 1616,
+    1617, 779, 32, 1617, 1648, 524, 1574, 1585, 524, 1574, 1586, 524, 1574,
+    1605, 524, 1574, 1606, 524, 1574, 1609, 524, 1574, 1610, 524, 1576, 1585,
+    524, 1576, 1586, 524, 1576, 1605, 524, 1576, 1606, 524, 1576, 1609, 524,
+    1576, 1610, 524, 1578, 1585, 524, 1578, 1586, 524, 1578, 1605, 524, 1578,
+    1606, 524, 1578, 1609, 524, 1578, 1610, 524, 1579, 1585, 524, 1579, 1586,
+    524, 1579, 1605, 524, 1579, 1606, 524, 1579, 1609, 524, 1579, 1610, 524,
+    1601, 1609, 524, 1601, 1610, 524, 1602, 1609, 524, 1602, 1610, 524, 1603,
+    1575, 524, 1603, 1604, 524, 1603, 1605, 524, 1603, 1609, 524, 1603, 1610,
+    524, 1604, 1605, 524, 1604, 1609, 524, 1604, 1610, 524, 1605, 1575, 524,
+    1605, 1605, 524, 1606, 1585, 524, 1606, 1586, 524, 1606, 1605, 524, 1606,
+    1606, 524, 1606, 1609, 524, 1606, 1610, 524, 1609, 1648, 524, 1610, 1585,
+    524, 1610, 1586, 524, 1610, 1605, 524, 1610, 1606, 524, 1610, 1609, 524,
+    1610, 1610, 525, 1574, 1580, 525, 1574, 1581, 525, 1574, 1582, 525, 1574,
+    1605, 525, 1574, 1607, 525, 1576, 1580, 525, 1576, 1581, 525, 1576, 1582,
+    525, 1576, 1605, 525, 1576, 1607, 525, 1578, 1580, 525, 1578, 1581, 525,
+    1578, 1582, 525, 1578, 1605, 525, 1578, 1607, 525, 1579, 1605, 525, 1580,
+    1581, 525, 1580, 1605, 525, 1581, 1580, 525, 1581, 1605, 525, 1582, 1580,
+    525, 1582, 1605, 525, 1587, 1580, 525, 1587, 1581, 525, 1587, 1582, 525,
+    1587, 1605, 525, 1589, 1581, 525, 1589, 1582, 525, 1589, 1605, 525, 1590,
+    1580, 525, 1590, 1581, 525, 1590, 1582, 525, 1590, 1605, 525, 1591, 1581,
+    525, 1592, 1605, 525, 1593, 1580, 525, 1593, 1605, 525, 1594, 1580, 525,
+    1594, 1605, 525, 1601, 1580, 525, 1601, 1581, 525, 1601, 1582, 525, 1601,
+    1605, 525, 1602, 1581, 525, 1602, 1605, 525, 1603, 1580, 525, 1603, 1581,
+    525, 1603, 1582, 525, 1603, 1604, 525, 1603, 1605, 525, 1604, 1580, 525,
+    1604, 1581, 525, 1604, 1582, 525, 1604, 1605, 525, 1604, 1607, 525, 1605,
+    1580, 525, 1605, 1581, 525, 1605, 1582, 525, 1605, 1605, 525, 1606, 1580,
+    525, 1606, 1581, 525, 1606, 1582, 525, 1606, 1605, 525, 1606, 1607, 525,
+    1607, 1580, 525, 1607, 1605, 525, 1607, 1648, 525, 1610, 1580, 525, 1610,
+    1581, 525, 1610, 1582, 525, 1610, 1605, 525, 1610, 1607, 526, 1574, 1605,
+    526, 1574, 1607, 526, 1576, 1605, 526, 1576, 1607, 526, 1578, 1605, 526,
+    1578, 1607, 526, 1579, 1605, 526, 1579, 1607, 526, 1587, 1605, 526, 1587,
+    1607, 526, 1588, 1605, 526, 1588, 1607, 526, 1603, 1604, 526, 1603, 1605,
+    526, 1604, 1605, 526, 1606, 1605, 526, 1606, 1607, 526, 1610, 1605, 526,
+    1610, 1607, 782, 1600, 1614, 1617, 782, 1600, 1615, 1617, 782, 1600,
+    1616, 1617, 523, 1591, 1609, 523, 1591, 1610, 523, 1593, 1609, 523, 1593,
+    1610, 523, 1594, 1609, 523, 1594, 1610, 523, 1587, 1609, 523, 1587, 1610,
+    523, 1588, 1609, 523, 1588, 1610, 523, 1581, 1609, 523, 1581, 1610, 523,
+    1580, 1609, 523, 1580, 1610, 523, 1582, 1609, 523, 1582, 1610, 523, 1589,
+    1609, 523, 1589, 1610, 523, 1590, 1609, 523, 1590, 1610, 523, 1588, 1580,
+    523, 1588, 1581, 523, 1588, 1582, 523, 1588, 1605, 523, 1588, 1585, 523,
+    1587, 1585, 523, 1589, 1585, 523, 1590, 1585, 524, 1591, 1609, 524, 1591,
+    1610, 524, 1593, 1609, 524, 1593, 1610, 524, 1594, 1609, 524, 1594, 1610,
+    524, 1587, 1609, 524, 1587, 1610, 524, 1588, 1609, 524, 1588, 1610, 524,
+    1581, 1609, 524, 1581, 1610, 524, 1580, 1609, 524, 1580, 1610, 524, 1582,
+    1609, 524, 1582, 1610, 524, 1589, 1609, 524, 1589, 1610, 524, 1590, 1609,
+    524, 1590, 1610, 524, 1588, 1580, 524, 1588, 1581, 524, 1588, 1582, 524,
+    1588, 1605, 524, 1588, 1585, 524, 1587, 1585, 524, 1589, 1585, 524, 1590,
+    1585, 525, 1588, 1580, 525, 1588, 1581, 525, 1588, 1582, 525, 1588, 1605,
+    525, 1587, 1607, 525, 1588, 1607, 525, 1591, 1605, 526, 1587, 1580, 526,
+    1587, 1581, 526, 1587, 1582, 526, 1588, 1580, 526, 1588, 1581, 526, 1588,
+    1582, 526, 1591, 1605, 526, 1592, 1605, 524, 1575, 1611, 523, 1575, 1611,
+    781, 1578, 1580, 1605, 780, 1578, 1581, 1580, 781, 1578, 1581, 1580, 781,
+    1578, 1581, 1605, 781, 1578, 1582, 1605, 781, 1578, 1605, 1580, 781,
+    1578, 1605, 1581, 781, 1578, 1605, 1582, 780, 1580, 1605, 1581, 781,
+    1580, 1605, 1581, 780, 1581, 1605, 1610, 780, 1581, 1605, 1609, 781,
+    1587, 1581, 1580, 781, 1587, 1580, 1581, 780, 1587, 1580, 1609, 780,
+    1587, 1605, 1581, 781, 1587, 1605, 1581, 781, 1587, 1605, 1580, 780,
+    1587, 1605, 1605, 781, 1587, 1605, 1605, 780, 1589, 1581, 1581, 781,
+    1589, 1581, 1581, 780, 1589, 1605, 1605, 780, 1588, 1581, 1605, 781,
+    1588, 1581, 1605, 780, 1588, 1580, 1610, 780, 1588, 1605, 1582, 781,
+    1588, 1605, 1582, 780, 1588, 1605, 1605, 781, 1588, 1605, 1605, 780,
+    1590, 1581, 1609, 780, 1590, 1582, 1605, 781, 1590, 1582, 1605, 780,
+    1591, 1605, 1581, 781, 1591, 1605, 1581, 781, 1591, 1605, 1605, 780,
+    1591, 1605, 1610, 780, 1593, 1580, 1605, 780, 1593, 1605, 1605, 781,
+    1593, 1605, 1605, 780, 1593, 1605, 1609, 780, 1594, 1605, 1605, 780,
+    1594, 1605, 1610, 780, 1594, 1605, 1609, 780, 1601, 1582, 1605, 781,
+    1601, 1582, 1605, 780, 1602, 1605, 1581, 780, 1602, 1605, 1605, 780,
+    1604, 1581, 1605, 780, 1604, 1581, 1610, 780, 1604, 1581, 1609, 781,
+    1604, 1580, 1580, 780, 1604, 1580, 1580, 780, 1604, 1582, 1605, 781,
+    1604, 1582, 1605, 780, 1604, 1605, 1581, 781, 1604, 1605, 1581, 781,
+    1605, 1581, 1580, 781, 1605, 1581, 1605, 780, 1605, 1581, 1610, 781,
+    1605, 1580, 1581, 781, 1605, 1580, 1605, 781, 1605, 1582, 1580, 781,
+    1605, 1582, 1605, 781, 1605, 1580, 1582, 781, 1607, 1605, 1580, 781,
+    1607, 1605, 1605, 781, 1606, 1581, 1605, 780, 1606, 1581, 1609, 780,
+    1606, 1580, 1605, 781, 1606, 1580, 1605, 780, 1606, 1580, 1609, 780,
+    1606, 1605, 1610, 780, 1606, 1605, 1609, 780, 1610, 1605, 1605, 781,
+    1610, 1605, 1605, 780, 1576, 1582, 1610, 780, 1578, 1580, 1610, 780,
+    1578, 1580, 1609, 780, 1578, 1582, 1610, 780, 1578, 1582, 1609, 780,
+    1578, 1605, 1610, 780, 1578, 1605, 1609, 780, 1580, 1605, 1610, 780,
+    1580, 1581, 1609, 780, 1580, 1605, 1609, 780, 1587, 1582, 1609, 780,
+    1589, 1581, 1610, 780, 1588, 1581, 1610, 780, 1590, 1581, 1610, 780,
+    1604, 1580, 1610, 780, 1604, 1605, 1610, 780, 1610, 1581, 1610, 780,
+    1610, 1580, 1610, 780, 1610, 1605, 1610, 780, 1605, 1605, 1610, 780,
+    1602, 1605, 1610, 780, 1606, 1581, 1610, 781, 1602, 1605, 1581, 781,
+    1604, 1581, 1605, 780, 1593, 1605, 1610, 780, 1603, 1605, 1610, 781,
+    1606, 1580, 1581, 780, 1605, 1582, 1610, 781, 1604, 1580, 1605, 780,
+    1603, 1605, 1605, 780, 1604, 1580, 1605, 780, 1606, 1580, 1581, 780,
+    1580, 1581, 1610, 780, 1581, 1580, 1610, 780, 1605, 1580, 1610, 780,
+    1601, 1605, 1610, 780, 1576, 1581, 1610, 781, 1603, 1605, 1605, 781,
+    1593, 1580, 1605, 781, 1589, 1605, 1605, 780, 1587, 1582, 1610, 780,
+    1606, 1580, 1610, 779, 1589, 1604, 1746, 779, 1602, 1604, 1746, 1035,
+    1575, 1604, 1604, 1607, 1035, 1575, 1603, 1576, 1585, 1035, 1605, 1581,
+    1605, 1583, 1035, 1589, 1604, 1593, 1605, 1035, 1585, 1587, 1608, 1604,
+    1035, 1593, 1604, 1610, 1607, 1035, 1608, 1587, 1604, 1605, 779, 1589,
+    1604, 1609, 4619, 1589, 1604, 1609, 32, 1575, 1604, 1604, 1607, 32, 1593,
+    1604, 1610, 1607, 32, 1608, 1587, 1604, 1605, 2059, 1580, 1604, 32, 1580,
+    1604, 1575, 1604, 1607, 1035, 1585, 1740, 1575, 1604, 265, 44, 265,
+    12289, 265, 12290, 265, 58, 265, 59, 265, 33, 265, 63, 265, 12310, 265,
+    12311, 265, 8230, 265, 8229, 265, 8212, 265, 8211, 265, 95, 265, 95, 265,
+    40, 265, 41, 265, 123, 265, 125, 265, 12308, 265, 12309, 265, 12304, 265,
+    12305, 265, 12298, 265, 12299, 265, 12296, 265, 12297, 265, 12300, 265,
+    12301, 265, 12302, 265, 12303, 265, 91, 265, 93, 258, 8254, 258, 8254,
+    258, 8254, 258, 8254, 258, 95, 258, 95, 258, 95, 271, 44, 271, 12289,
+    271, 46, 271, 59, 271, 58, 271, 63, 271, 33, 271, 8212, 271, 40, 271, 41,
+    271, 123, 271, 125, 271, 12308, 271, 12309, 271, 35, 271, 38, 271, 42,
+    271, 43, 271, 45, 271, 60, 271, 62, 271, 61, 271, 92, 271, 36, 271, 37,
+    271, 64, 523, 32, 1611, 526, 1600, 1611, 523, 32, 1612, 523, 32, 1613,
+    523, 32, 1614, 526, 1600, 1614, 523, 32, 1615, 526, 1600, 1615, 523, 32,
+    1616, 526, 1600, 1616, 523, 32, 1617, 526, 1600, 1617, 523, 32, 1618,
+    526, 1600, 1618, 267, 1569, 267, 1570, 268, 1570, 267, 1571, 268, 1571,
+    267, 1572, 268, 1572, 267, 1573, 268, 1573, 267, 1574, 268, 1574, 269,
+    1574, 270, 1574, 267, 1575, 268, 1575, 267, 1576, 268, 1576, 269, 1576,
+    270, 1576, 267, 1577, 268, 1577, 267, 1578, 268, 1578, 269, 1578, 270,
+    1578, 267, 1579, 268, 1579, 269, 1579, 270, 1579, 267, 1580, 268, 1580,
+    269, 1580, 270, 1580, 267, 1581, 268, 1581, 269, 1581, 270, 1581, 267,
+    1582, 268, 1582, 269, 1582, 270, 1582, 267, 1583, 268, 1583, 267, 1584,
+    268, 1584, 267, 1585, 268, 1585, 267, 1586, 268, 1586, 267, 1587, 268,
+    1587, 269, 1587, 270, 1587, 267, 1588, 268, 1588, 269, 1588, 270, 1588,
+    267, 1589, 268, 1589, 269, 1589, 270, 1589, 267, 1590, 268, 1590, 269,
+    1590, 270, 1590, 267, 1591, 268, 1591, 269, 1591, 270, 1591, 267, 1592,
+    268, 1592, 269, 1592, 270, 1592, 267, 1593, 268, 1593, 269, 1593, 270,
+    1593, 267, 1594, 268, 1594, 269, 1594, 270, 1594, 267, 1601, 268, 1601,
+    269, 1601, 270, 1601, 267, 1602, 268, 1602, 269, 1602, 270, 1602, 267,
+    1603, 268, 1603, 269, 1603, 270, 1603, 267, 1604, 268, 1604, 269, 1604,
+    270, 1604, 267, 1605, 268, 1605, 269, 1605, 270, 1605, 267, 1606, 268,
+    1606, 269, 1606, 270, 1606, 267, 1607, 268, 1607, 269, 1607, 270, 1607,
+    267, 1608, 268, 1608, 267, 1609, 268, 1609, 267, 1610, 268, 1610, 269,
+    1610, 270, 1610, 523, 1604, 1570, 524, 1604, 1570, 523, 1604, 1571, 524,
+    1604, 1571, 523, 1604, 1573, 524, 1604, 1573, 523, 1604, 1575, 524, 1604,
+    1575, 264, 33, 264, 34, 264, 35, 264, 36, 264, 37, 264, 38, 264, 39, 264,
+    40, 264, 41, 264, 42, 264, 43, 264, 44, 264, 45, 264, 46, 264, 47, 264,
+    48, 264, 49, 264, 50, 264, 51, 264, 52, 264, 53, 264, 54, 264, 55, 264,
+    56, 264, 57, 264, 58, 264, 59, 264, 60, 264, 61, 264, 62, 264, 63, 264,
+    64, 264, 65, 264, 66, 264, 67, 264, 68, 264, 69, 264, 70, 264, 71, 264,
+    72, 264, 73, 264, 74, 264, 75, 264, 76, 264, 77, 264, 78, 264, 79, 264,
+    80, 264, 81, 264, 82, 264, 83, 264, 84, 264, 85, 264, 86, 264, 87, 264,
+    88, 264, 89, 264, 90, 264, 91, 264, 92, 264, 93, 264, 94, 264, 95, 264,
+    96, 264, 97, 264, 98, 264, 99, 264, 100, 264, 101, 264, 102, 264, 103,
+    264, 104, 264, 105, 264, 106, 264, 107, 264, 108, 264, 109, 264, 110,
+    264, 111, 264, 112, 264, 113, 264, 114, 264, 115, 264, 116, 264, 117,
+    264, 118, 264, 119, 264, 120, 264, 121, 264, 122, 264, 123, 264, 124,
+    264, 125, 264, 126, 264, 10629, 264, 10630, 272, 12290, 272, 12300, 272,
+    12301, 272, 12289, 272, 12539, 272, 12530, 272, 12449, 272, 12451, 272,
+    12453, 272, 12455, 272, 12457, 272, 12515, 272, 12517, 272, 12519, 272,
+    12483, 272, 12540, 272, 12450, 272, 12452, 272, 12454, 272, 12456, 272,
+    12458, 272, 12459, 272, 12461, 272, 12463, 272, 12465, 272, 12467, 272,
+    12469, 272, 12471, 272, 12473, 272, 12475, 272, 12477, 272, 12479, 272,
+    12481, 272, 12484, 272, 12486, 272, 12488, 272, 12490, 272, 12491, 272,
+    12492, 272, 12493, 272, 12494, 272, 12495, 272, 12498, 272, 12501, 272,
+    12504, 272, 12507, 272, 12510, 272, 12511, 272, 12512, 272, 12513, 272,
+    12514, 272, 12516, 272, 12518, 272, 12520, 272, 12521, 272, 12522, 272,
+    12523, 272, 12524, 272, 12525, 272, 12527, 272, 12531, 272, 12441, 272,
+    12442, 272, 12644, 272, 12593, 272, 12594, 272, 12595, 272, 12596, 272,
+    12597, 272, 12598, 272, 12599, 272, 12600, 272, 12601, 272, 12602, 272,
+    12603, 272, 12604, 272, 12605, 272, 12606, 272, 12607, 272, 12608, 272,
+    12609, 272, 12610, 272, 12611, 272, 12612, 272, 12613, 272, 12614, 272,
+    12615, 272, 12616, 272, 12617, 272, 12618, 272, 12619, 272, 12620, 272,
+    12621, 272, 12622, 272, 12623, 272, 12624, 272, 12625, 272, 12626, 272,
+    12627, 272, 12628, 272, 12629, 272, 12630, 272, 12631, 272, 12632, 272,
+    12633, 272, 12634, 272, 12635, 272, 12636, 272, 12637, 272, 12638, 272,
+    12639, 272, 12640, 272, 12641, 272, 12642, 272, 12643, 264, 162, 264,
+    163, 264, 172, 264, 175, 264, 166, 264, 165, 264, 8361, 272, 9474, 272,
+    8592, 272, 8593, 272, 8594, 272, 8595, 272, 9632, 272, 9675, 512, 55300,
+    56473, 55300, 56506, 512, 55300, 56475, 55300, 56506, 512, 55300, 56485,
+    55300, 56506, 512, 55300, 56625, 55300, 56615, 512, 55300, 56626, 55300,
+    56615, 512, 55300, 57159, 55300, 57150, 512, 55300, 57159, 55300, 57175,
+    512, 55301, 56505, 55301, 56506, 512, 55301, 56505, 55301, 56496, 512,
+    55301, 56505, 55301, 56509, 512, 55301, 56760, 55301, 56751, 512, 55301,
+    56761, 55301, 56751, 512, 55348, 56663, 55348, 56677, 512, 55348, 56664,
+    55348, 56677, 512, 55348, 56671, 55348, 56686, 512, 55348, 56671, 55348,
+    56687, 512, 55348, 56671, 55348, 56688, 512, 55348, 56671, 55348, 56689,
+    512, 55348, 56671, 55348, 56690, 512, 55348, 56761, 55348, 56677, 512,
+    55348, 56762, 55348, 56677, 512, 55348, 56763, 55348, 56686, 512, 55348,
+    56764, 55348, 56686, 512, 55348, 56763, 55348, 56687, 512, 55348, 56764,
+    55348, 56687, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262,
+    71, 262, 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262,
+    79, 262, 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262,
+    87, 262, 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262,
+    101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262,
+    108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262,
+    115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262,
+    122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262,
+    72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262,
+    80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262,
+    88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262,
+    102, 262, 103, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262,
+    110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262,
+    117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66,
+    262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74,
+    262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82,
+    262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90,
+    262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262,
+    104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262,
+    111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262,
+    118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 67, 262, 68,
+    262, 71, 262, 74, 262, 75, 262, 78, 262, 79, 262, 80, 262, 81, 262, 83,
+    262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97,
+    262, 98, 262, 99, 262, 100, 262, 102, 262, 104, 262, 105, 262, 106, 262,
+    107, 262, 108, 262, 109, 262, 110, 262, 112, 262, 113, 262, 114, 262,
+    115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262,
+    122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262,
+    72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262,
+    80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262,
+    88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262,
+    102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262,
+    109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262,
+    116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65,
+    262, 66, 262, 68, 262, 69, 262, 70, 262, 71, 262, 74, 262, 75, 262, 76,
+    262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 83, 262, 84, 262, 85,
+    262, 86, 262, 87, 262, 88, 262, 89, 262, 97, 262, 98, 262, 99, 262, 100,
+    262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107,
+    262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114,
+    262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121,
+    262, 122, 262, 65, 262, 66, 262, 68, 262, 69, 262, 70, 262, 71, 262, 73,
+    262, 74, 262, 75, 262, 76, 262, 77, 262, 79, 262, 83, 262, 84, 262, 85,
+    262, 86, 262, 87, 262, 88, 262, 89, 262, 97, 262, 98, 262, 99, 262, 100,
+    262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107,
+    262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114,
+    262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121,
+    262, 122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71,
+    262, 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79,
+    262, 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87,
+    262, 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101,
+    262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108,
+    262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115,
+    262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122,
+    262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72,
+    262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80,
+    262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88,
+    262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262,
+    102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262,
+    109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262,
+    116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65,
+    262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73,
+    262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81,
+    262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89,
+    262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262,
+    103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262,
+    110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262,
+    117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66,
+    262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74,
+    262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82,
+    262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90,
+    262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262,
+    104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262,
+    111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262,
+    118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 262, 67,
+    262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 262, 75,
+    262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 262, 83,
+    262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97,
+    262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 104, 262,
+    105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 111, 262,
+    112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 118, 262,
+    119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 262, 67, 262, 68,
+    262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 262, 75, 262, 76,
+    262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 262, 83, 262, 84,
+    262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97, 262, 98,
+    262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262,
+    106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262,
+    113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262,
+    120, 262, 121, 262, 122, 262, 305, 262, 567, 262, 913, 262, 914, 262,
+    915, 262, 916, 262, 917, 262, 918, 262, 919, 262, 920, 262, 921, 262,
+    922, 262, 923, 262, 924, 262, 925, 262, 926, 262, 927, 262, 928, 262,
+    929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, 935, 262,
+    936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, 948, 262,
+    949, 262, 950, 262, 951, 262, 952, 262, 953, 262, 954, 262, 955, 262,
+    956, 262, 957, 262, 958, 262, 959, 262, 960, 262, 961, 262, 962, 262,
+    963, 262, 964, 262, 965, 262, 966, 262, 967, 262, 968, 262, 969, 262,
+    8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, 982, 262,
+    913, 262, 914, 262, 915, 262, 916, 262, 917, 262, 918, 262, 919, 262,
+    920, 262, 921, 262, 922, 262, 923, 262, 924, 262, 925, 262, 926, 262,
+    927, 262, 928, 262, 929, 262, 1012, 262, 931, 262, 932, 262, 933, 262,
+    934, 262, 935, 262, 936, 262, 937, 262, 8711, 262, 945, 262, 946, 262,
+    947, 262, 948, 262, 949, 262, 950, 262, 951, 262, 952, 262, 953, 262,
+    954, 262, 955, 262, 956, 262, 957, 262, 958, 262, 959, 262, 960, 262,
+    961, 262, 962, 262, 963, 262, 964, 262, 965, 262, 966, 262, 967, 262,
+    968, 262, 969, 262, 8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262,
+    1009, 262, 982, 262, 913, 262, 914, 262, 915, 262, 916, 262, 917, 262,
+    918, 262, 919, 262, 920, 262, 921, 262, 922, 262, 923, 262, 924, 262,
+    925, 262, 926, 262, 927, 262, 928, 262, 929, 262, 1012, 262, 931, 262,
+    932, 262, 933, 262, 934, 262, 935, 262, 936, 262, 937, 262, 8711, 262,
+    945, 262, 946, 262, 947, 262, 948, 262, 949, 262, 950, 262, 951, 262,
+    952, 262, 953, 262, 954, 262, 955, 262, 956, 262, 957, 262, 958, 262,
+    959, 262, 960, 262, 961, 262, 962, 262, 963, 262, 964, 262, 965, 262,
+    966, 262, 967, 262, 968, 262, 969, 262, 8706, 262, 1013, 262, 977, 262,
+    1008, 262, 981, 262, 1009, 262, 982, 262, 913, 262, 914, 262, 915, 262,
+    916, 262, 917, 262, 918, 262, 919, 262, 920, 262, 921, 262, 922, 262,
+    923, 262, 924, 262, 925, 262, 926, 262, 927, 262, 928, 262, 929, 262,
+    1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, 935, 262, 936, 262,
+    937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, 948, 262, 949, 262,
+    950, 262, 951, 262, 952, 262, 953, 262, 954, 262, 955, 262, 956, 262,
+    957, 262, 958, 262, 959, 262, 960, 262, 961, 262, 962, 262, 963, 262,
+    964, 262, 965, 262, 966, 262, 967, 262, 968, 262, 969, 262, 8706, 262,
+    1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, 982, 262, 913, 262,
+    914, 262, 915, 262, 916, 262, 917, 262, 918, 262, 919, 262, 920, 262,
+    921, 262, 922, 262, 923, 262, 924, 262, 925, 262, 926, 262, 927, 262,
+    928, 262, 929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, 934, 262,
+    935, 262, 936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, 947, 262,
+    948, 262, 949, 262, 950, 262, 951, 262, 952, 262, 953, 262, 954, 262,
+    955, 262, 956, 262, 957, 262, 958, 262, 959, 262, 960, 262, 961, 262,
+    962, 262, 963, 262, 964, 262, 965, 262, 966, 262, 967, 262, 968, 262,
+    969, 262, 8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262,
+    982, 262, 988, 262, 989, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52,
+    262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 48, 262, 49, 262, 50,
+    262, 51, 262, 52, 262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 48,
+    262, 49, 262, 50, 262, 51, 262, 52, 262, 53, 262, 54, 262, 55, 262, 56,
+    262, 57, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52, 262, 53, 262, 54,
+    262, 55, 262, 56, 262, 57, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52,
+    262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 1575, 262, 1576, 262,
+    1580, 262, 1583, 262, 1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610,
+    262, 1603, 262, 1604, 262, 1605, 262, 1606, 262, 1587, 262, 1593, 262,
+    1601, 262, 1589, 262, 1602, 262, 1585, 262, 1588, 262, 1578, 262, 1579,
+    262, 1582, 262, 1584, 262, 1590, 262, 1592, 262, 1594, 262, 1646, 262,
+    1722, 262, 1697, 262, 1647, 262, 1576, 262, 1580, 262, 1607, 262, 1581,
+    262, 1610, 262, 1603, 262, 1604, 262, 1605, 262, 1606, 262, 1587, 262,
+    1593, 262, 1601, 262, 1589, 262, 1602, 262, 1588, 262, 1578, 262, 1579,
+    262, 1582, 262, 1590, 262, 1594, 262, 1580, 262, 1581, 262, 1610, 262,
+    1604, 262, 1606, 262, 1587, 262, 1593, 262, 1589, 262, 1602, 262, 1588,
+    262, 1582, 262, 1590, 262, 1594, 262, 1722, 262, 1647, 262, 1576, 262,
+    1580, 262, 1607, 262, 1581, 262, 1591, 262, 1610, 262, 1603, 262, 1605,
+    262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262, 1602, 262,
+    1588, 262, 1578, 262, 1579, 262, 1582, 262, 1590, 262, 1592, 262, 1594,
+    262, 1646, 262, 1697, 262, 1575, 262, 1576, 262, 1580, 262, 1583, 262,
+    1607, 262, 1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610, 262, 1604,
+    262, 1605, 262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262,
+    1602, 262, 1585, 262, 1588, 262, 1578, 262, 1579, 262, 1582, 262, 1584,
+    262, 1590, 262, 1592, 262, 1594, 262, 1576, 262, 1580, 262, 1583, 262,
+    1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610, 262, 1604, 262, 1605,
+    262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262, 1602, 262,
+    1585, 262, 1588, 262, 1578, 262, 1579, 262, 1582, 262, 1584, 262, 1590,
+    262, 1592, 262, 1594, 514, 48, 46, 514, 48, 44, 514, 49, 44, 514, 50, 44,
+    514, 51, 44, 514, 52, 44, 514, 53, 44, 514, 54, 44, 514, 55, 44, 514, 56,
+    44, 514, 57, 44, 770, 40, 65, 41, 770, 40, 66, 41, 770, 40, 67, 41, 770,
+    40, 68, 41, 770, 40, 69, 41, 770, 40, 70, 41, 770, 40, 71, 41, 770, 40,
+    72, 41, 770, 40, 73, 41, 770, 40, 74, 41, 770, 40, 75, 41, 770, 40, 76,
+    41, 770, 40, 77, 41, 770, 40, 78, 41, 770, 40, 79, 41, 770, 40, 80, 41,
+    770, 40, 81, 41, 770, 40, 82, 41, 770, 40, 83, 41, 770, 40, 84, 41, 770,
+    40, 85, 41, 770, 40, 86, 41, 770, 40, 87, 41, 770, 40, 88, 41, 770, 40,
+    89, 41, 770, 40, 90, 41, 770, 12308, 83, 12309, 263, 67, 263, 82, 519,
+    67, 68, 519, 87, 90, 266, 65, 266, 66, 266, 67, 266, 68, 266, 69, 266,
+    70, 266, 71, 266, 72, 266, 73, 266, 74, 266, 75, 266, 76, 266, 77, 266,
+    78, 266, 79, 266, 80, 266, 81, 266, 82, 266, 83, 266, 84, 266, 85, 266,
+    86, 266, 87, 266, 88, 266, 89, 266, 90, 522, 72, 86, 522, 77, 86, 522,
+    83, 68, 522, 83, 83, 778, 80, 80, 86, 522, 87, 67, 515, 77, 67, 515, 77,
+    68, 522, 68, 74, 522, 12411, 12363, 522, 12467, 12467, 266, 12469, 266,
+    25163, 266, 23383, 266, 21452, 266, 12487, 266, 20108, 266, 22810, 266,
+    35299, 266, 22825, 266, 20132, 266, 26144, 266, 28961, 266, 26009, 266,
+    21069, 266, 24460, 266, 20877, 266, 26032, 266, 21021, 266, 32066, 266,
+    29983, 266, 36009, 266, 22768, 266, 21561, 266, 28436, 266, 25237, 266,
+    25429, 266, 19968, 266, 19977, 266, 36938, 266, 24038, 266, 20013, 266,
+    21491, 266, 25351, 266, 36208, 266, 25171, 266, 31105, 266, 31354, 266,
+    21512, 266, 28288, 266, 26377, 266, 26376, 266, 30003, 266, 21106, 266,
+    21942, 266, 37197, 770, 12308, 26412, 12309, 770, 12308, 19977, 12309,
+    770, 12308, 20108, 12309, 770, 12308, 23433, 12309, 770, 12308, 28857,
+    12309, 770, 12308, 25171, 12309, 770, 12308, 30423, 12309, 770, 12308,
+    21213, 12309, 770, 12308, 25943, 12309, 263, 24471, 263, 21487, 256,
+    20029, 256, 20024, 256, 20033, 256, 55360, 56610, 256, 20320, 256, 20398,
+    256, 20411, 256, 20482, 256, 20602, 256, 20633, 256, 20711, 256, 20687,
+    256, 13470, 256, 55361, 56890, 256, 20813, 256, 20820, 256, 20836, 256,
+    20855, 256, 55361, 56604, 256, 13497, 256, 20839, 256, 20877, 256, 55361,
+    56651, 256, 20887, 256, 20900, 256, 20172, 256, 20908, 256, 20917, 256,
+    55396, 56799, 256, 20981, 256, 20995, 256, 13535, 256, 21051, 256, 21062,
+    256, 21106, 256, 21111, 256, 13589, 256, 21191, 256, 21193, 256, 21220,
+    256, 21242, 256, 21253, 256, 21254, 256, 21271, 256, 21321, 256, 21329,
+    256, 21338, 256, 21363, 256, 21373, 256, 21375, 256, 21375, 256, 21375,
+    256, 55362, 56876, 256, 28784, 256, 21450, 256, 21471, 256, 55362, 57187,
+    256, 21483, 256, 21489, 256, 21510, 256, 21662, 256, 21560, 256, 21576,
+    256, 21608, 256, 21666, 256, 21750, 256, 21776, 256, 21843, 256, 21859,
+    256, 21892, 256, 21892, 256, 21913, 256, 21931, 256, 21939, 256, 21954,
+    256, 22294, 256, 22022, 256, 22295, 256, 22097, 256, 22132, 256, 20999,
+    256, 22766, 256, 22478, 256, 22516, 256, 22541, 256, 22411, 256, 22578,
+    256, 22577, 256, 22700, 256, 55365, 56548, 256, 22770, 256, 22775, 256,
+    22790, 256, 22810, 256, 22818, 256, 22882, 256, 55365, 57000, 256, 55365,
+    57066, 256, 23020, 256, 23067, 256, 23079, 256, 23000, 256, 23142, 256,
+    14062, 256, 14076, 256, 23304, 256, 23358, 256, 23358, 256, 55366, 56776,
+    256, 23491, 256, 23512, 256, 23527, 256, 23539, 256, 55366, 57112, 256,
+    23551, 256, 23558, 256, 24403, 256, 23586, 256, 14209, 256, 23648, 256,
+    23662, 256, 23744, 256, 23693, 256, 55367, 56804, 256, 23875, 256, 55367,
+    56806, 256, 23918, 256, 23915, 256, 23932, 256, 24033, 256, 24034, 256,
+    14383, 256, 24061, 256, 24104, 256, 24125, 256, 24169, 256, 14434, 256,
+    55368, 56707, 256, 14460, 256, 24240, 256, 24243, 256, 24246, 256, 24266,
+    256, 55400, 57234, 256, 24318, 256, 55368, 57137, 256, 55368, 57137, 256,
+    33281, 256, 24354, 256, 24354, 256, 14535, 256, 55372, 57016, 256, 55384,
+    56794, 256, 24418, 256, 24427, 256, 14563, 256, 24474, 256, 24525, 256,
+    24535, 256, 24569, 256, 24705, 256, 14650, 256, 14620, 256, 24724, 256,
+    55369, 57044, 256, 24775, 256, 24904, 256, 24908, 256, 24910, 256, 24908,
+    256, 24954, 256, 24974, 256, 25010, 256, 24996, 256, 25007, 256, 25054,
+    256, 25074, 256, 25078, 256, 25104, 256, 25115, 256, 25181, 256, 25265,
+    256, 25300, 256, 25424, 256, 55370, 57100, 256, 25405, 256, 25340, 256,
+    25448, 256, 25475, 256, 25572, 256, 55370, 57329, 256, 25634, 256, 25541,
+    256, 25513, 256, 14894, 256, 25705, 256, 25726, 256, 25757, 256, 25719,
+    256, 14956, 256, 25935, 256, 25964, 256, 55372, 56330, 256, 26083, 256,
+    26360, 256, 26185, 256, 15129, 256, 26257, 256, 15112, 256, 15076, 256,
+    20882, 256, 20885, 256, 26368, 256, 26268, 256, 32941, 256, 17369, 256,
+    26391, 256, 26395, 256, 26401, 256, 26462, 256, 26451, 256, 55372, 57283,
+    256, 15177, 256, 26618, 256, 26501, 256, 26706, 256, 26757, 256, 55373,
+    56429, 256, 26766, 256, 26655, 256, 26900, 256, 15261, 256, 26946, 256,
+    27043, 256, 27114, 256, 27304, 256, 55373, 56995, 256, 27355, 256, 15384,
+    256, 27425, 256, 55374, 56487, 256, 27476, 256, 15438, 256, 27506, 256,
+    27551, 256, 27578, 256, 27579, 256, 55374, 56973, 256, 55367, 56587, 256,
+    55374, 57082, 256, 27726, 256, 55375, 56508, 256, 27839, 256, 27853, 256,
+    27751, 256, 27926, 256, 27966, 256, 28023, 256, 27969, 256, 28009, 256,
+    28024, 256, 28037, 256, 55375, 56606, 256, 27956, 256, 28207, 256, 28270,
+    256, 15667, 256, 28363, 256, 28359, 256, 55375, 57041, 256, 28153, 256,
+    28526, 256, 55375, 57182, 256, 55375, 57230, 256, 28614, 256, 28729, 256,
+    28702, 256, 28699, 256, 15766, 256, 28746, 256, 28797, 256, 28791, 256,
+    28845, 256, 55361, 56613, 256, 28997, 256, 55376, 56931, 256, 29084, 256,
+    55376, 57259, 256, 29224, 256, 29237, 256, 29264, 256, 55377, 56840, 256,
+    29312, 256, 29333, 256, 55377, 57141, 256, 55378, 56340, 256, 29562, 256,
+    29579, 256, 16044, 256, 29605, 256, 16056, 256, 16056, 256, 29767, 256,
+    29788, 256, 29809, 256, 29829, 256, 29898, 256, 16155, 256, 29988, 256,
+    55379, 56374, 256, 30014, 256, 55379, 56466, 256, 30064, 256, 55368,
+    56735, 256, 30224, 256, 55379, 57249, 256, 55379, 57272, 256, 55380,
+    56388, 256, 16380, 256, 16392, 256, 30452, 256, 55380, 56563, 256, 55380,
+    56562, 256, 55380, 56601, 256, 55380, 56627, 256, 30494, 256, 30495, 256,
+    30495, 256, 30538, 256, 16441, 256, 30603, 256, 16454, 256, 16534, 256,
+    55381, 56349, 256, 30798, 256, 30860, 256, 30924, 256, 16611, 256, 55381,
+    56870, 256, 31062, 256, 55381, 56986, 256, 55381, 57029, 256, 31119, 256,
+    31211, 256, 16687, 256, 31296, 256, 31306, 256, 31311, 256, 55382, 56700,
+    256, 55382, 56999, 256, 55382, 56999, 256, 31470, 256, 16898, 256, 55382,
+    57259, 256, 31686, 256, 31689, 256, 16935, 256, 55383, 56448, 256, 31954,
+    256, 17056, 256, 31976, 256, 31971, 256, 32000, 256, 55383, 57222, 256,
+    32099, 256, 17153, 256, 32199, 256, 32258, 256, 32325, 256, 17204, 256,
+    55384, 56872, 256, 55384, 56903, 256, 17241, 256, 55384, 57049, 256,
+    32634, 256, 55384, 57150, 256, 32661, 256, 32762, 256, 32773, 256, 55385,
+    56538, 256, 55385, 56611, 256, 32864, 256, 55385, 56744, 256, 32880, 256,
+    55372, 57183, 256, 17365, 256, 32946, 256, 33027, 256, 17419, 256, 33086,
+    256, 23221, 256, 55385, 57255, 256, 55385, 57269, 256, 55372, 57235, 256,
+    55372, 57244, 256, 33281, 256, 33284, 256, 36766, 256, 17515, 256, 33425,
+    256, 33419, 256, 33437, 256, 21171, 256, 33457, 256, 33459, 256, 33469,
+    256, 33510, 256, 55386, 57148, 256, 33509, 256, 33565, 256, 33635, 256,
+    33709, 256, 33571, 256, 33725, 256, 33767, 256, 33879, 256, 33619, 256,
+    33738, 256, 33740, 256, 33756, 256, 55387, 56374, 256, 55387, 56683, 256,
+    55387, 56533, 256, 17707, 256, 34033, 256, 34035, 256, 34070, 256, 55388,
+    57290, 256, 34148, 256, 55387, 57132, 256, 17757, 256, 17761, 256, 55387,
+    57265, 256, 55388, 56530, 256, 17771, 256, 34384, 256, 34396, 256, 34407,
+    256, 34409, 256, 34473, 256, 34440, 256, 34574, 256, 34530, 256, 34681,
+    256, 34600, 256, 34667, 256, 34694, 256, 17879, 256, 34785, 256, 34817,
+    256, 17913, 256, 34912, 256, 34915, 256, 55389, 56935, 256, 35031, 256,
+    35038, 256, 17973, 256, 35066, 256, 13499, 256, 55390, 56494, 256, 55390,
+    56678, 256, 18110, 256, 18119, 256, 35488, 256, 35565, 256, 35722, 256,
+    35925, 256, 55391, 56488, 256, 36011, 256, 36033, 256, 36123, 256, 36215,
+    256, 55391, 57135, 256, 55362, 56324, 256, 36299, 256, 36284, 256, 36336,
+    256, 55362, 56542, 256, 36564, 256, 36664, 256, 55393, 56786, 256, 55393,
+    56813, 256, 37012, 256, 37105, 256, 37137, 256, 55393, 57134, 256, 37147,
+    256, 37432, 256, 37591, 256, 37592, 256, 37500, 256, 37881, 256, 37909,
+    256, 55394, 57338, 256, 38283, 256, 18837, 256, 38327, 256, 55395, 56695,
+    256, 18918, 256, 38595, 256, 23986, 256, 38691, 256, 55396, 56645, 256,
+    55396, 56858, 256, 19054, 256, 19062, 256, 38880, 256, 55397, 56330, 256,
+    19122, 256, 55397, 56470, 256, 38923, 256, 38923, 256, 38953, 256, 55397,
+    56758, 256, 39138, 256, 19251, 256, 39209, 256, 39335, 256, 39362, 256,
+    39422, 256, 19406, 256, 55398, 57136, 256, 39698, 256, 40000, 256, 40189,
+    256, 19662, 256, 19693, 256, 40295, 256, 55400, 56526, 256, 19704, 256,
+    55400, 56581, 256, 55400, 56846, 256, 55400, 56977, 256, 40635, 256,
+    19798, 256, 40697, 256, 40702, 256, 40709, 256, 40719, 256, 40726, 256,
+    40763, 256, 55401, 56832,
+};
+
+/* index tables for the decomposition data */
+#define DECOMP_SHIFT1 6
+#define DECOMP_SHIFT2 4
+static const unsigned char decomp_index0[] = {
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 13, 14, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 15, 16, 5, 5, 5, 5, 17, 18,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 19, 20,
+    5, 5, 5, 5, 5, 21, 22, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    23, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const unsigned short decomp_index1[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+    14, 0, 0, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, 0, 0, 0, 0,
+    25, 0, 26, 27, 0, 0, 0, 0, 0, 28, 0, 0, 29, 30, 31, 32, 33, 34, 35, 0,
+    36, 37, 38, 0, 39, 0, 40, 0, 41, 0, 0, 0, 0, 42, 43, 44, 45, 0, 0, 0, 0,
+    0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 48, 0, 0, 0,
+    0, 49, 50, 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, 51, 52, 0, 53, 0, 0, 0, 0,
+    0, 0, 54, 55, 0, 0, 0, 0, 0, 56, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 58, 59, 0, 0, 0, 60, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0,
+    0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0,
+    0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 67, 0, 68, 0, 0, 69, 0, 0, 0, 70,
+    71, 72, 73, 74, 75, 76, 77, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 79, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 81, 0,
+    82, 83, 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, 84, 85, 86, 87, 88, 89, 0, 90, 91, 92, 0, 0, 0, 0,
+    93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
+    109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
+    123, 124, 125, 126, 127, 128, 129, 130, 0, 131, 132, 133, 134, 0, 0, 0,
+    0, 0, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 0, 146, 0,
+    0, 0, 147, 0, 148, 149, 150, 0, 151, 152, 153, 0, 154, 0, 0, 0, 155, 0,
+    0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 157,
+    158, 159, 160, 161, 162, 163, 164, 165, 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, 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, 166, 0,
+    0, 0, 0, 0, 0, 167, 0, 0, 0, 0, 0, 168, 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, 169, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    171, 0, 0, 0, 0, 0, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181,
+    182, 183, 184, 185, 186, 0, 0, 187, 0, 0, 188, 189, 190, 191, 192, 0,
+    193, 194, 195, 196, 197, 0, 198, 0, 0, 0, 199, 200, 201, 202, 203, 204,
+    205, 0, 0, 0, 0, 0, 0, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215,
+    216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
+    230, 231, 232, 233, 234, 235, 236, 237, 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, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, 0, 0,
+    0, 0, 0, 0, 0, 240, 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, 0, 0, 0, 0, 0, 241, 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, 242, 243, 244, 245, 246, 247,
+    248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261,
+    262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 0, 0, 272, 273, 274,
+    275, 276, 277, 278, 279, 280, 281, 282, 283, 0, 284, 285, 286, 287, 288,
+    289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302,
+    303, 304, 305, 306, 0, 307, 308, 309, 310, 311, 312, 313, 314, 0, 0, 315,
+    0, 316, 0, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328,
+    329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342,
+    343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 345, 346, 0, 0, 0, 0, 0, 0, 0,
+    347, 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, 348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 350, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 351, 352, 0, 0, 0, 0, 353, 354, 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, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364,
+    365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378,
+    379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392,
+    393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406,
+    407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 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, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430,
+    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, 431, 432, 433, 434, 435, 0, 436, 0,
+    0, 437, 0, 0, 0, 0, 0, 0, 438, 439, 440, 441, 442, 443, 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, 444, 445,
+    446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459,
+    460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473,
+    474, 475, 476, 477, 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,
+};
+
+static const unsigned short decomp_index2[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+    3, 0, 6, 0, 0, 0, 0, 8, 0, 0, 11, 13, 15, 18, 0, 0, 20, 23, 25, 0, 27,
+    31, 35, 0, 39, 42, 45, 48, 51, 54, 0, 57, 60, 63, 66, 69, 72, 75, 78, 81,
+    0, 84, 87, 90, 93, 96, 99, 0, 0, 102, 105, 108, 111, 114, 0, 0, 117, 120,
+    123, 126, 129, 132, 0, 135, 138, 141, 144, 147, 150, 153, 156, 159, 0,
+    162, 165, 168, 171, 174, 177, 0, 0, 180, 183, 186, 189, 192, 0, 195, 198,
+    201, 204, 207, 210, 213, 216, 219, 222, 225, 228, 231, 234, 237, 240,
+    243, 0, 0, 246, 249, 252, 255, 258, 261, 264, 267, 270, 273, 276, 279,
+    282, 285, 288, 291, 294, 297, 300, 303, 0, 0, 306, 309, 312, 315, 318,
+    321, 324, 327, 330, 0, 333, 336, 339, 342, 345, 348, 0, 351, 354, 357,
+    360, 363, 366, 369, 372, 0, 0, 375, 378, 381, 384, 387, 390, 393, 0, 0,
+    396, 399, 402, 405, 408, 411, 0, 0, 414, 417, 420, 423, 426, 429, 432,
+    435, 438, 441, 444, 447, 450, 453, 456, 459, 462, 465, 0, 0, 468, 471,
+    474, 477, 480, 483, 486, 489, 492, 495, 498, 501, 504, 507, 510, 513,
+    516, 519, 522, 525, 528, 531, 534, 537, 539, 542, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 545, 548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 551, 554, 557, 560, 563, 566, 569, 572, 575, 578, 581, 584, 587,
+    590, 593, 596, 599, 602, 605, 608, 611, 614, 617, 620, 623, 0, 626, 629,
+    632, 635, 638, 641, 0, 0, 644, 647, 650, 653, 656, 659, 662, 665, 668,
+    671, 674, 677, 680, 683, 686, 689, 0, 0, 692, 695, 698, 701, 704, 707,
+    710, 713, 716, 719, 722, 725, 728, 731, 734, 737, 740, 743, 746, 749,
+    752, 755, 758, 761, 764, 767, 770, 773, 776, 779, 782, 785, 788, 791,
+    794, 797, 0, 0, 800, 803, 0, 0, 0, 0, 0, 0, 806, 809, 812, 815, 818, 821,
+    824, 827, 830, 833, 836, 839, 842, 845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 848, 850, 852, 854, 856, 858, 860, 862, 864, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 866, 869, 872, 875, 878, 881, 0, 0, 884, 886, 888,
+    890, 892, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 894, 896, 0, 898, 900, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 903, 0, 0, 0, 0, 0, 905, 0, 0, 0,
+    908, 0, 0, 0, 0, 0, 910, 913, 916, 919, 921, 924, 927, 0, 930, 0, 933,
+    936, 939, 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, 942, 945, 948, 951, 954, 957, 960, 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, 963, 966, 969, 972, 975,
+    0, 978, 980, 982, 984, 987, 990, 992, 0, 0, 0, 0, 0, 0, 0, 0, 0, 994,
+    996, 998, 0, 1000, 1002, 0, 0, 0, 1004, 0, 0, 0, 0, 0, 0, 1006, 1009, 0,
+    1012, 0, 0, 0, 1015, 0, 0, 0, 0, 1018, 1021, 1024, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 1027, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1030, 0, 0,
+    0, 0, 0, 0, 1033, 1036, 0, 1039, 0, 0, 0, 1042, 0, 0, 0, 0, 1045, 1048,
+    1051, 0, 0, 0, 0, 0, 0, 0, 1054, 1057, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1060,
+    1063, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1066, 1069, 1072, 1075, 0,
+    0, 1078, 1081, 0, 0, 1084, 1087, 1090, 1093, 1096, 1099, 0, 0, 1102,
+    1105, 1108, 1111, 1114, 1117, 0, 0, 1120, 1123, 1126, 1129, 1132, 1135,
+    1138, 1141, 1144, 1147, 1150, 1153, 0, 0, 1156, 1159, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 1162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1165, 1168,
+    1171, 1174, 1177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1180, 1183,
+    1186, 1189, 0, 0, 0, 0, 0, 0, 0, 1192, 0, 1195, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 1198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 1201, 0, 0, 0, 0, 0, 0, 0, 1204, 0, 0, 1207, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1210, 1213, 1216,
+    1219, 1222, 1225, 1228, 1231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1234,
+    1237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1240, 1243, 0, 1246,
+    0, 0, 0, 1249, 0, 0, 1252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 1255, 1258, 1261, 0, 0, 1264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1267,
+    0, 0, 1270, 1273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1276,
+    1279, 0, 0, 0, 0, 0, 0, 1282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 1285, 1288, 1291, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    1294, 0, 0, 0, 0, 0, 0, 0, 1297, 0, 0, 0, 0, 0, 0, 1300, 1303, 0, 1306,
+    1309, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1312, 1315, 1318, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1321, 0, 1324, 1327, 1330, 0, 0, 0, 0,
+    1333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1336, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1339, 1342, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1345, 0, 0, 0, 0, 0, 0, 1347, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 1350, 0, 0, 0, 0, 1353, 0, 0, 0, 0, 1356, 0, 0,
+    0, 0, 1359, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1362, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 1365, 0, 1368, 1371, 1374, 1377, 1380, 0, 0, 0, 0, 0, 0, 0,
+    1383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1386, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 1389, 0, 0, 0, 0, 1392, 0, 0, 0, 0, 1395, 0, 0, 0, 0,
+    1398, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1401, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 1404, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 1407, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1409, 0, 1412, 0, 1415, 0,
+    1418, 0, 1421, 0, 0, 0, 1424, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1427, 0, 1430, 0, 0, 1433, 1436, 0, 1439,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    1442, 1444, 1446, 0, 1448, 1450, 1452, 1454, 1456, 1458, 1460, 1462,
+    1464, 1466, 1468, 0, 1470, 1472, 1474, 1476, 1478, 1480, 1482, 1484,
+    1486, 1488, 1490, 1492, 1494, 1496, 1498, 1500, 1502, 1504, 0, 1506,
+    1508, 1510, 1512, 1514, 1516, 1518, 1520, 1522, 1524, 1526, 1528, 1530,
+    1532, 1534, 1536, 1538, 1540, 1542, 1544, 1546, 1548, 1550, 1552, 1554,
+    1556, 1558, 1560, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1562, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1564, 1566, 1568, 1570,
+    1572, 1574, 1576, 1578, 1580, 1582, 1584, 1586, 1588, 1590, 1592, 1594,
+    1596, 1598, 1600, 1602, 1604, 1606, 1608, 1610, 1612, 1614, 1616, 1618,
+    1620, 1622, 1624, 1626, 1628, 1630, 1632, 1634, 1636, 1638, 1641, 1644,
+    1647, 1650, 1653, 1656, 1659, 1662, 1665, 1668, 1671, 1674, 1677, 1680,
+    1683, 1686, 1689, 1692, 1695, 1698, 1701, 1704, 1707, 1710, 1713, 1716,
+    1719, 1722, 1725, 1728, 1731, 1734, 1737, 1740, 1743, 1746, 1749, 1752,
+    1755, 1758, 1761, 1764, 1767, 1770, 1773, 1776, 1779, 1782, 1785, 1788,
+    1791, 1794, 1797, 1800, 1803, 1806, 1809, 1812, 1815, 1818, 1821, 1824,
+    1827, 1830, 1833, 1836, 1839, 1842, 1845, 1848, 1851, 1854, 1857, 1860,
+    1863, 1866, 1869, 1872, 1875, 1878, 1881, 1884, 1887, 1890, 1893, 1896,
+    1899, 1902, 1905, 1908, 1911, 1914, 1917, 1920, 1923, 1926, 1929, 1932,
+    1935, 1938, 1941, 1944, 1947, 1950, 1953, 1956, 1959, 1962, 1965, 1968,
+    1971, 1974, 1977, 1980, 1983, 1986, 1989, 1992, 1995, 1998, 2001, 2004,
+    2007, 2010, 2013, 2016, 2019, 2022, 2025, 2028, 2031, 2034, 2037, 2040,
+    2043, 2046, 2049, 2052, 2055, 2058, 2061, 2064, 2067, 2070, 2073, 2076,
+    2079, 2082, 2085, 2088, 2091, 2094, 2097, 2100, 2103, 0, 0, 0, 0, 2106,
+    2109, 2112, 2115, 2118, 2121, 2124, 2127, 2130, 2133, 2136, 2139, 2142,
+    2145, 2148, 2151, 2154, 2157, 2160, 2163, 2166, 2169, 2172, 2175, 2178,
+    2181, 2184, 2187, 2190, 2193, 2196, 2199, 2202, 2205, 2208, 2211, 2214,
+    2217, 2220, 2223, 2226, 2229, 2232, 2235, 2238, 2241, 2244, 2247, 2250,
+    2253, 2256, 2259, 2262, 2265, 2268, 2271, 2274, 2277, 2280, 2283, 2286,
+    2289, 2292, 2295, 2298, 2301, 2304, 2307, 2310, 2313, 2316, 2319, 2322,
+    2325, 2328, 2331, 2334, 2337, 2340, 2343, 2346, 2349, 2352, 2355, 2358,
+    2361, 2364, 2367, 2370, 2373, 0, 0, 0, 0, 0, 0, 2376, 2379, 2382, 2385,
+    2388, 2391, 2394, 2397, 2400, 2403, 2406, 2409, 2412, 2415, 2418, 2421,
+    2424, 2427, 2430, 2433, 2436, 2439, 0, 0, 2442, 2445, 2448, 2451, 2454,
+    2457, 0, 0, 2460, 2463, 2466, 2469, 2472, 2475, 2478, 2481, 2484, 2487,
+    2490, 2493, 2496, 2499, 2502, 2505, 2508, 2511, 2514, 2517, 2520, 2523,
+    2526, 2529, 2532, 2535, 2538, 2541, 2544, 2547, 2550, 2553, 2556, 2559,
+    2562, 2565, 2568, 2571, 0, 0, 2574, 2577, 2580, 2583, 2586, 2589, 0, 0,
+    2592, 2595, 2598, 2601, 2604, 2607, 2610, 2613, 0, 2616, 0, 2619, 0,
+    2622, 0, 2625, 2628, 2631, 2634, 2637, 2640, 2643, 2646, 2649, 2652,
+    2655, 2658, 2661, 2664, 2667, 2670, 2673, 2676, 2679, 2681, 2684, 2686,
+    2689, 2691, 2694, 2696, 2699, 2701, 2704, 2706, 2709, 0, 0, 2711, 2714,
+    2717, 2720, 2723, 2726, 2729, 2732, 2735, 2738, 2741, 2744, 2747, 2750,
+    2753, 2756, 2759, 2762, 2765, 2768, 2771, 2774, 2777, 2780, 2783, 2786,
+    2789, 2792, 2795, 2798, 2801, 2804, 2807, 2810, 2813, 2816, 2819, 2822,
+    2825, 2828, 2831, 2834, 2837, 2840, 2843, 2846, 2849, 2852, 2855, 2858,
+    2861, 2864, 2867, 0, 2870, 2873, 2876, 2879, 2882, 2885, 2887, 2890,
+    2893, 2895, 2898, 2901, 2904, 2907, 2910, 0, 2913, 2916, 2919, 2922,
+    2924, 2927, 2929, 2932, 2935, 2938, 2941, 2944, 2947, 2950, 0, 0, 2952,
+    2955, 2958, 2961, 2964, 2967, 0, 2969, 2972, 2975, 2978, 2981, 2984,
+    2987, 2989, 2992, 2995, 2998, 3001, 3004, 3007, 3010, 3012, 3015, 3018,
+    3020, 0, 0, 3022, 3025, 3028, 0, 3031, 3034, 3037, 3040, 3042, 3045,
+    3047, 3050, 3052, 0, 3055, 3057, 3059, 3061, 3063, 3065, 3067, 3069,
+    3071, 3073, 3075, 0, 0, 0, 0, 0, 0, 3077, 0, 0, 0, 0, 0, 3079, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 3082, 3084, 3087, 0, 0, 0, 0, 0, 0, 0, 0,
+    3091, 0, 0, 0, 3093, 3096, 0, 3100, 3103, 0, 0, 0, 0, 3107, 0, 3110, 0,
+    0, 0, 0, 0, 0, 0, 0, 3113, 3116, 3119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 3122, 0, 0, 0, 0, 0, 0, 0, 3127, 3129, 3131, 0, 0, 3133, 3135,
+    3137, 3139, 3141, 3143, 3145, 3147, 3149, 3151, 3153, 3155, 3157, 3159,
+    3161, 3163, 3165, 3167, 3169, 3171, 3173, 3175, 3177, 3179, 3181, 3183,
+    3185, 0, 3187, 3189, 3191, 3193, 3195, 3197, 3199, 3201, 3203, 3205,
+    3207, 3209, 3211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3213, 0, 0, 0, 0, 0,
+    0, 0, 3216, 3220, 3224, 3226, 0, 3229, 3233, 3237, 0, 3239, 3242, 3244,
+    3246, 3248, 3250, 3252, 3254, 3256, 3258, 3260, 0, 3262, 3264, 0, 0,
+    3267, 3269, 3271, 3273, 3275, 0, 0, 3277, 3280, 3284, 0, 3287, 0, 3289,
+    0, 3291, 0, 3293, 3295, 3297, 3299, 0, 3301, 3303, 3305, 0, 3307, 3309,
+    3311, 3313, 3315, 3317, 3319, 0, 3321, 3325, 3327, 3329, 3331, 3333, 0,
+    0, 0, 0, 3335, 3337, 3339, 3341, 3343, 0, 0, 0, 0, 0, 0, 3345, 3349,
+    3353, 3358, 3362, 3366, 3370, 3374, 3378, 3382, 3386, 3390, 3394, 3398,
+    3402, 3406, 3409, 3411, 3414, 3418, 3421, 3423, 3426, 3430, 3435, 3438,
+    3440, 3443, 3447, 3449, 3451, 3453, 3455, 3457, 3460, 3464, 3467, 3469,
+    3472, 3476, 3481, 3484, 3486, 3489, 3493, 3495, 3497, 3499, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 3501, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    3505, 3508, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3511,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3514, 3517, 3520, 0, 0, 0, 0,
+    3523, 0, 0, 0, 0, 3526, 0, 0, 3529, 0, 0, 0, 0, 0, 0, 0, 3532, 0, 3535,
+    0, 0, 0, 0, 0, 3538, 3541, 0, 3545, 3548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 3552, 0, 0, 3555, 0, 0, 3558, 0, 3561, 0, 0, 0, 0, 0,
+    0, 3564, 0, 3567, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3570, 3573, 3576, 3579,
+    3582, 0, 0, 3585, 3588, 0, 0, 3591, 3594, 0, 0, 0, 0, 0, 0, 3597, 3600,
+    0, 0, 3603, 3606, 0, 0, 3609, 3612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 3615, 3618, 3621, 3624, 3627, 3630, 3633, 3636, 0, 0,
+    0, 0, 0, 0, 3639, 3642, 3645, 3648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    3651, 3653, 0, 0, 0, 0, 0, 3655, 3657, 3659, 3661, 3663, 3665, 3667,
+    3669, 3671, 3673, 3676, 3679, 3682, 3685, 3688, 3691, 3694, 3697, 3700,
+    3703, 3706, 3710, 3714, 3718, 3722, 3726, 3730, 3734, 3738, 3742, 3747,
+    3752, 3757, 3762, 3767, 3772, 3777, 3782, 3787, 3792, 3797, 3800, 3803,
+    3806, 3809, 3812, 3815, 3818, 3821, 3824, 3828, 3832, 3836, 3840, 3844,
+    3848, 3852, 3856, 3860, 3864, 3868, 3872, 3876, 3880, 3884, 3888, 3892,
+    3896, 3900, 3904, 3908, 3912, 3916, 3920, 3924, 3928, 3932, 3936, 3940,
+    3944, 3948, 3952, 3956, 3960, 3964, 3968, 3972, 3974, 3976, 3978, 3980,
+    3982, 3984, 3986, 3988, 3990, 3992, 3994, 3996, 3998, 4000, 4002, 4004,
+    4006, 4008, 4010, 4012, 4014, 4016, 4018, 4020, 4022, 4024, 4026, 4028,
+    4030, 4032, 4034, 4036, 4038, 4040, 4042, 4044, 4046, 4048, 4050, 4052,
+    4054, 4056, 4058, 4060, 4062, 4064, 4066, 4068, 4070, 4072, 4074, 4076,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4078, 0, 0, 0, 0, 0,
+    0, 0, 4083, 4087, 4090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 4094, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4097,
+    4099, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4101, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4103, 0, 0, 0, 4105, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 4107, 4109, 4111, 4113, 4115, 4117, 4119, 4121,
+    4123, 4125, 4127, 4129, 4131, 4133, 4135, 4137, 4139, 4141, 4143, 4145,
+    4147, 4149, 4151, 4153, 4155, 4157, 4159, 4161, 4163, 4165, 4167, 4169,
+    4171, 4173, 4175, 4177, 4179, 4181, 4183, 4185, 4187, 4189, 4191, 4193,
+    4195, 4197, 4199, 4201, 4203, 4205, 4207, 4209, 4211, 4213, 4215, 4217,
+    4219, 4221, 4223, 4225, 4227, 4229, 4231, 4233, 4235, 4237, 4239, 4241,
+    4243, 4245, 4247, 4249, 4251, 4253, 4255, 4257, 4259, 4261, 4263, 4265,
+    4267, 4269, 4271, 4273, 4275, 4277, 4279, 4281, 4283, 4285, 4287, 4289,
+    4291, 4293, 4295, 4297, 4299, 4301, 4303, 4305, 4307, 4309, 4311, 4313,
+    4315, 4317, 4319, 4321, 4323, 4325, 4327, 4329, 4331, 4333, 4335, 4337,
+    4339, 4341, 4343, 4345, 4347, 4349, 4351, 4353, 4355, 4357, 4359, 4361,
+    4363, 4365, 4367, 4369, 4371, 4373, 4375, 4377, 4379, 4381, 4383, 4385,
+    4387, 4389, 4391, 4393, 4395, 4397, 4399, 4401, 4403, 4405, 4407, 4409,
+    4411, 4413, 4415, 4417, 4419, 4421, 4423, 4425, 4427, 4429, 4431, 4433,
+    4435, 4437, 4439, 4441, 4443, 4445, 4447, 4449, 4451, 4453, 4455, 4457,
+    4459, 4461, 4463, 4465, 4467, 4469, 4471, 4473, 4475, 4477, 4479, 4481,
+    4483, 4485, 4487, 4489, 4491, 4493, 4495, 4497, 4499, 4501, 4503, 4505,
+    4507, 4509, 4511, 4513, 4515, 4517, 4519, 4521, 4523, 4525, 4527, 4529,
+    4531, 4533, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4535, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4537, 0, 4539, 4541, 4543, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4545, 0, 4548, 0, 4551, 0,
+    4554, 0, 4557, 0, 4560, 0, 4563, 0, 4566, 0, 4569, 0, 4572, 0, 4575, 0,
+    4578, 0, 0, 4581, 0, 4584, 0, 4587, 0, 0, 0, 0, 0, 0, 4590, 4593, 0,
+    4596, 4599, 0, 4602, 4605, 0, 4608, 4611, 0, 4614, 4617, 0, 0, 0, 0, 0,
+    0, 4620, 0, 0, 0, 0, 0, 0, 4623, 4626, 0, 4629, 4632, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 4635, 0, 4638, 0, 4641, 0, 4644, 0, 4647, 0, 4650, 0,
+    4653, 0, 4656, 0, 4659, 0, 4662, 0, 4665, 0, 4668, 0, 0, 4671, 0, 4674,
+    0, 4677, 0, 0, 0, 0, 0, 0, 4680, 4683, 0, 4686, 4689, 0, 4692, 4695, 0,
+    4698, 4701, 0, 4704, 4707, 0, 0, 0, 0, 0, 0, 4710, 0, 0, 4713, 4716,
+    4719, 4722, 0, 0, 0, 4725, 4728, 0, 4731, 4733, 4735, 4737, 4739, 4741,
+    4743, 4745, 4747, 4749, 4751, 4753, 4755, 4757, 4759, 4761, 4763, 4765,
+    4767, 4769, 4771, 4773, 4775, 4777, 4779, 4781, 4783, 4785, 4787, 4789,
+    4791, 4793, 4795, 4797, 4799, 4801, 4803, 4805, 4807, 4809, 4811, 4813,
+    4815, 4817, 4819, 4821, 4823, 4825, 4827, 4829, 4831, 4833, 4835, 4837,
+    4839, 4841, 4843, 4845, 4847, 4849, 4851, 4853, 4855, 4857, 4859, 4861,
+    4863, 4865, 4867, 4869, 4871, 4873, 4875, 4877, 4879, 4881, 4883, 4885,
+    4887, 4889, 4891, 4893, 4895, 4897, 4899, 4901, 4903, 4905, 4907, 4909,
+    4911, 4913, 4915, 4917, 0, 0, 0, 4919, 4921, 4923, 4925, 4927, 4929,
+    4931, 4933, 4935, 4937, 4939, 4941, 4943, 4945, 4947, 4951, 4955, 4959,
+    4963, 4967, 4971, 4975, 4979, 4983, 4987, 4991, 4995, 4999, 5003, 5008,
+    5013, 5018, 5023, 5028, 5033, 5038, 5043, 5048, 5053, 5058, 5063, 5068,
+    5073, 5078, 5086, 0, 5093, 5097, 5101, 5105, 5109, 5113, 5117, 5121,
+    5125, 5129, 5133, 5137, 5141, 5145, 5149, 5153, 5157, 5161, 5165, 5169,
+    5173, 5177, 5181, 5185, 5189, 5193, 5197, 5201, 5205, 5209, 5213, 5217,
+    5221, 5225, 5229, 5233, 5237, 5239, 5241, 5243, 0, 0, 0, 0, 0, 0, 0, 0,
+    5245, 5249, 5252, 5255, 5258, 5261, 5264, 5267, 5270, 5273, 5276, 5279,
+    5282, 5285, 5288, 5291, 5294, 5296, 5298, 5300, 5302, 5304, 5306, 5308,
+    5310, 5312, 5314, 5316, 5318, 5320, 5322, 5325, 5328, 5331, 5334, 5337,
+    5340, 5343, 5346, 5349, 5352, 5355, 5358, 5361, 5364, 5370, 5375, 0,
+    5378, 5380, 5382, 5384, 5386, 5388, 5390, 5392, 5394, 5396, 5398, 5400,
+    5402, 5404, 5406, 5408, 5410, 5412, 5414, 5416, 5418, 5420, 5422, 5424,
+    5426, 5428, 5430, 5432, 5434, 5436, 5438, 5440, 5442, 5444, 5446, 5448,
+    5450, 5452, 5454, 5456, 5458, 5460, 5462, 5464, 5466, 5468, 5470, 5472,
+    5474, 5476, 5479, 5482, 5485, 5488, 5491, 5494, 5497, 5500, 5503, 5506,
+    5509, 5512, 5515, 5518, 5521, 5524, 5527, 5530, 5533, 5536, 5539, 5542,
+    5545, 5548, 5552, 5556, 5560, 5563, 5567, 5570, 5574, 5576, 5578, 5580,
+    5582, 5584, 5586, 5588, 5590, 5592, 5594, 5596, 5598, 5600, 5602, 5604,
+    5606, 5608, 5610, 5612, 5614, 5616, 5618, 5620, 5622, 5624, 5626, 5628,
+    5630, 5632, 5634, 5636, 5638, 5640, 5642, 5644, 5646, 5648, 5650, 5652,
+    5654, 5656, 5658, 5660, 5662, 5664, 5666, 0, 5668, 5673, 5678, 5683,
+    5687, 5692, 5696, 5700, 5706, 5711, 5715, 5719, 5723, 5728, 5733, 5737,
+    5741, 5744, 5748, 5753, 5758, 5761, 5767, 5774, 5780, 5784, 5790, 5796,
+    5801, 5805, 5809, 5813, 5818, 5824, 5829, 5833, 5837, 5841, 5844, 5847,
+    5850, 5853, 5857, 5861, 5867, 5871, 5876, 5882, 5886, 5889, 5892, 5898,
+    5903, 5909, 5913, 5919, 5922, 5926, 5930, 5934, 5938, 5942, 5947, 5951,
+    5954, 5958, 5962, 5966, 5971, 5975, 5979, 5983, 5989, 5994, 5997, 6003,
+    6006, 6011, 6016, 6020, 6024, 6028, 6033, 6036, 6040, 6045, 6048, 6054,
+    6058, 6061, 6064, 6067, 6070, 6073, 6076, 6079, 6082, 6085, 6088, 6092,
+    6096, 6100, 6104, 6108, 6112, 6116, 6120, 6124, 6128, 6132, 6136, 6140,
+    6144, 6148, 6152, 6155, 6158, 6162, 6165, 6168, 6171, 6175, 6179, 6182,
+    6185, 6188, 6191, 6194, 6199, 6202, 6205, 6208, 6211, 6214, 6217, 6220,
+    6223, 6227, 6232, 6235, 6238, 6241, 6244, 6247, 6250, 6253, 6257, 6261,
+    6265, 6269, 6272, 6275, 6278, 6281, 6284, 6287, 6290, 6293, 6296, 6299,
+    6303, 6307, 6310, 6314, 6318, 6322, 6325, 6329, 6333, 6338, 6341, 6345,
+    6349, 6353, 6357, 6363, 6370, 6373, 6376, 6379, 6382, 6385, 6388, 6391,
+    6394, 6397, 6400, 6403, 6406, 6409, 6412, 6415, 6418, 6421, 6424, 6429,
+    6432, 6435, 6438, 6443, 6447, 6450, 6453, 6456, 6459, 6462, 6465, 6468,
+    6471, 6474, 6477, 6481, 6484, 6487, 6491, 6495, 6498, 6503, 6507, 6510,
+    6513, 6516, 6519, 6523, 6527, 6530, 6533, 6536, 6539, 6542, 6545, 6548,
+    6551, 6554, 6558, 6562, 6566, 6570, 6574, 6578, 6582, 6586, 6590, 6594,
+    6598, 6602, 6606, 6610, 6614, 6618, 6622, 6626, 6630, 6634, 6638, 6642,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6646, 6648, 0, 0, 6650, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6652, 6654, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6656, 6658, 6660,
+    6662, 6664, 6666, 6668, 6670, 6672, 6674, 6676, 6678, 6680, 6682, 6684,
+    6686, 6688, 6690, 6692, 6694, 6696, 6698, 6700, 6702, 6704, 6706, 6708,
+    6710, 6712, 6714, 6716, 6718, 6720, 6722, 6724, 6726, 6728, 6730, 6732,
+    6734, 6736, 6738, 6740, 6742, 6744, 6746, 6748, 6750, 6752, 6754, 6756,
+    6758, 6760, 6762, 6764, 6766, 6768, 6770, 6772, 6774, 6776, 6778, 6780,
+    6782, 6784, 6786, 6788, 6790, 6792, 6794, 6796, 6798, 6800, 6802, 6804,
+    6806, 6808, 6810, 6812, 6814, 6816, 6818, 6820, 6822, 6824, 6826, 6828,
+    6830, 6832, 6834, 6836, 6838, 6840, 6842, 6844, 6846, 6848, 6850, 6852,
+    6854, 6856, 6858, 6860, 6862, 6864, 6866, 6868, 6870, 6872, 6874, 6876,
+    6878, 6880, 6882, 6884, 6886, 6888, 6890, 6892, 6894, 6896, 6898, 6900,
+    6902, 6904, 6906, 6908, 6910, 6912, 6914, 6916, 6918, 6920, 6922, 6924,
+    6926, 6928, 6930, 6932, 6934, 6936, 6938, 6940, 6942, 6944, 6946, 6948,
+    6950, 6952, 6954, 6956, 6958, 6960, 6962, 6964, 6966, 6968, 6970, 6972,
+    6974, 6976, 6978, 6980, 6982, 6984, 6986, 6988, 6990, 6992, 6994, 6996,
+    6998, 7000, 7002, 7004, 7006, 7008, 7010, 7012, 7014, 7016, 7018, 7020,
+    7022, 7024, 7026, 7028, 7030, 7032, 7034, 7036, 7038, 7040, 7042, 7044,
+    7046, 7048, 7050, 7052, 7054, 7056, 7058, 7060, 7062, 7064, 7066, 7068,
+    7070, 7072, 7074, 7076, 7078, 7080, 7082, 7084, 7086, 7088, 7090, 7092,
+    7094, 7096, 7098, 7100, 7102, 7104, 7106, 7108, 7110, 7112, 7114, 7116,
+    7118, 7120, 7122, 7124, 7126, 7128, 7130, 7132, 7134, 7136, 7138, 7140,
+    7142, 7144, 7146, 7148, 7150, 7152, 7154, 7156, 7158, 7160, 7162, 7164,
+    7166, 7168, 7170, 7172, 7174, 7176, 7178, 7180, 7182, 7184, 7186, 7188,
+    7190, 7192, 7194, 7196, 7198, 7200, 7202, 0, 0, 7204, 0, 7206, 0, 0,
+    7208, 7210, 7212, 7214, 7216, 7218, 7220, 7222, 7224, 7226, 0, 7228, 0,
+    7230, 0, 0, 7232, 7234, 0, 0, 0, 7236, 7238, 7240, 7242, 7244, 7246,
+    7248, 7250, 7252, 7254, 7256, 7258, 7260, 7262, 7264, 7266, 7268, 7270,
+    7272, 7274, 7276, 7278, 7280, 7282, 7284, 7286, 7288, 7290, 7292, 7294,
+    7296, 7298, 7300, 7302, 7304, 7306, 7308, 7310, 7312, 7314, 7316, 7318,
+    7320, 7322, 7324, 7326, 7328, 7330, 7332, 7334, 7336, 7338, 7340, 7342,
+    7344, 7346, 7348, 7350, 7352, 7354, 7356, 7358, 7360, 7362, 7364, 7366,
+    7368, 7371, 0, 0, 7373, 7375, 7377, 7379, 7381, 7383, 7385, 7387, 7389,
+    7391, 7393, 7395, 7397, 7399, 7401, 7403, 7405, 7407, 7409, 7411, 7413,
+    7415, 7417, 7419, 7421, 7423, 7425, 7427, 7429, 7431, 7433, 7435, 7437,
+    7439, 7441, 7443, 7445, 7447, 7449, 7451, 7453, 7455, 7457, 7459, 7461,
+    7463, 7465, 7467, 7469, 7471, 7473, 7475, 7477, 7479, 7481, 7483, 7485,
+    7487, 7489, 7491, 7493, 7495, 7497, 7499, 7501, 7503, 7505, 7507, 7509,
+    7511, 7513, 7515, 7517, 7519, 7521, 7523, 7525, 7527, 7529, 7531, 7533,
+    7535, 7537, 7539, 7541, 7543, 7545, 7547, 7549, 7551, 7553, 7555, 7557,
+    7559, 7561, 7563, 7566, 7569, 7572, 7574, 7576, 7578, 7581, 7584, 7587,
+    7589, 0, 0, 0, 0, 0, 0, 7591, 7594, 7597, 7600, 7604, 7608, 7611, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7614, 7617, 7620, 7623, 7626, 0, 0, 0, 0,
+    0, 7629, 0, 7632, 7635, 7637, 7639, 7641, 7643, 7645, 7647, 7649, 7651,
+    7653, 7655, 7658, 7661, 7664, 7667, 7670, 7673, 7676, 7679, 7682, 7685,
+    7688, 7691, 0, 7694, 7697, 7700, 7703, 7706, 0, 7709, 0, 7712, 7715, 0,
+    7718, 7721, 0, 7724, 7727, 7730, 7733, 7736, 7739, 7742, 7745, 7748,
+    7751, 7754, 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, 7772, 7774,
+    7776, 7778, 7780, 7782, 7784, 7786, 7788, 7790, 7792, 7794, 7796, 7798,
+    7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814, 7816, 7818, 7820, 7822,
+    7824, 7826, 7828, 7830, 7832, 7834, 7836, 7838, 7840, 7842, 7844, 7846,
+    7848, 7850, 7852, 7854, 7856, 7858, 7860, 7862, 7864, 7866, 7868, 7870,
+    7872, 7874, 7876, 7878, 7880, 7882, 7884, 7886, 7888, 7890, 7892, 7894,
+    7896, 7898, 7900, 7902, 7904, 7906, 7908, 7910, 7912, 7914, 7916, 7918,
+    7920, 7922, 7924, 7926, 7928, 7930, 7932, 7934, 7936, 7938, 7940, 7942,
+    7944, 7946, 7948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    7950, 7952, 7954, 7956, 7958, 7960, 7962, 7964, 7966, 7968, 7970, 7972,
+    7974, 7976, 7978, 7980, 7982, 7984, 7986, 7988, 7990, 7992, 7994, 7996,
+    7999, 8002, 8005, 8008, 8011, 8014, 8017, 8020, 8023, 8026, 8029, 8032,
+    8035, 8038, 8041, 8044, 8047, 8050, 8052, 8054, 8056, 8058, 8061, 8064,
+    8067, 8070, 8073, 8076, 8079, 8082, 8085, 8088, 8091, 8094, 8097, 8100,
+    8103, 8106, 8109, 8112, 8115, 8118, 8121, 8124, 8127, 8130, 8133, 8136,
+    8139, 8142, 8145, 8148, 8151, 8154, 8157, 8160, 8163, 8166, 8169, 8172,
+    8175, 8178, 8181, 8184, 8187, 8190, 8193, 8196, 8199, 8202, 8205, 8208,
+    8211, 8214, 8217, 8220, 8223, 8226, 8229, 8232, 8235, 8238, 8241, 8244,
+    8247, 8250, 8253, 8256, 8259, 8262, 8265, 8268, 8271, 8274, 8277, 8280,
+    8283, 8286, 8289, 8292, 8295, 8298, 8301, 8304, 8307, 8310, 8313, 8316,
+    8319, 8322, 8325, 8328, 8331, 8334, 8337, 8340, 8344, 8348, 8352, 8356,
+    8360, 8364, 8367, 8370, 8373, 8376, 8379, 8382, 8385, 8388, 8391, 8394,
+    8397, 8400, 8403, 8406, 8409, 8412, 8415, 8418, 8421, 8424, 8427, 8430,
+    8433, 8436, 8439, 8442, 8445, 8448, 8451, 8454, 8457, 8460, 8463, 8466,
+    8469, 8472, 8475, 8478, 8481, 8484, 8487, 8490, 8493, 8496, 8499, 8502,
+    8505, 8508, 8511, 8514, 8517, 8520, 8523, 8526, 8529, 8532, 8535, 8538,
+    8541, 8544, 8547, 8550, 8553, 8556, 8559, 8562, 8565, 8568, 8571, 8574,
+    8577, 8580, 8583, 8586, 8589, 8592, 8595, 8598, 8601, 8604, 8607, 8610,
+    8613, 8616, 8619, 8622, 8625, 8628, 8631, 8634, 8637, 8640, 8643, 8646,
+    8649, 8652, 8655, 8658, 8661, 8664, 8667, 8670, 8673, 8676, 8679, 8682,
+    8685, 8688, 8691, 8694, 8697, 8700, 8703, 8706, 8709, 8712, 8715, 8718,
+    8721, 8724, 8727, 8730, 8733, 8736, 8739, 8742, 8745, 8748, 8751, 8754,
+    8757, 8760, 8763, 8766, 8769, 8772, 8775, 8778, 8781, 8784, 8787, 8790,
+    8794, 8798, 8802, 8805, 8808, 8811, 8814, 8817, 8820, 8823, 8826, 8829,
+    8832, 8835, 8838, 8841, 8844, 8847, 8850, 8853, 8856, 8859, 8862, 8865,
+    8868, 8871, 8874, 8877, 8880, 8883, 8886, 8889, 8892, 8895, 8898, 8901,
+    8904, 8907, 8910, 8913, 8916, 8919, 8922, 8925, 8928, 8931, 8934, 8937,
+    8940, 8943, 8946, 8949, 8952, 8955, 8958, 8961, 8964, 8967, 8970, 8973,
+    8976, 8979, 8982, 8985, 8988, 8991, 8994, 8997, 9000, 9003, 9006, 9009,
+    9012, 9015, 9018, 0, 0, 9021, 9025, 9029, 9033, 9037, 9041, 9045, 9049,
+    9053, 9057, 9061, 9065, 9069, 9073, 9077, 9081, 9085, 9089, 9093, 9097,
+    9101, 9105, 9109, 9113, 9117, 9121, 9125, 9129, 9133, 9137, 9141, 9145,
+    9149, 9153, 9157, 9161, 9165, 9169, 9173, 9177, 9181, 9185, 9189, 9193,
+    9197, 9201, 9205, 9209, 9213, 9217, 9221, 9225, 9229, 9233, 9237, 9241,
+    9245, 9249, 9253, 9257, 9261, 9265, 9269, 9273, 0, 0, 9277, 9281, 9285,
+    9289, 9293, 9297, 9301, 9305, 9309, 9313, 9317, 9321, 9325, 9329, 9333,
+    9337, 9341, 9345, 9349, 9353, 9357, 9361, 9365, 9369, 9373, 9377, 9381,
+    9385, 9389, 9393, 9397, 9401, 9405, 9409, 9413, 9417, 9421, 9425, 9429,
+    9433, 9437, 9441, 9445, 9449, 9453, 9457, 9461, 9465, 9469, 9473, 9477,
+    9481, 9485, 9489, 0, 0, 0, 0, 0, 0, 0, 0, 9493, 9497, 9501, 9506, 9511,
+    9516, 9521, 9526, 9531, 9536, 9540, 9559, 9568, 0, 0, 0, 9573, 9575,
+    9577, 9579, 9581, 9583, 9585, 9587, 9589, 9591, 0, 0, 0, 0, 0, 0, 9593,
+    9595, 9597, 9599, 9601, 9603, 9605, 9607, 9609, 9611, 9613, 9615, 9617,
+    9619, 9621, 9623, 9625, 9627, 9629, 9631, 9633, 0, 0, 9635, 9637, 9639,
+    9641, 9643, 9645, 9647, 9649, 9651, 9653, 9655, 9657, 0, 9659, 9661,
+    9663, 9665, 9667, 9669, 9671, 9673, 9675, 9677, 9679, 9681, 9683, 9685,
+    9687, 9689, 9691, 9693, 9695, 0, 9697, 9699, 9701, 9703, 0, 0, 0, 0,
+    9705, 9708, 9711, 0, 9714, 0, 9717, 9720, 9723, 9726, 9729, 9732, 9735,
+    9738, 9741, 9744, 9747, 9749, 9751, 9753, 9755, 9757, 9759, 9761, 9763,
+    9765, 9767, 9769, 9771, 9773, 9775, 9777, 9779, 9781, 9783, 9785, 9787,
+    9789, 9791, 9793, 9795, 9797, 9799, 9801, 9803, 9805, 9807, 9809, 9811,
+    9813, 9815, 9817, 9819, 9821, 9823, 9825, 9827, 9829, 9831, 9833, 9835,
+    9837, 9839, 9841, 9843, 9845, 9847, 9849, 9851, 9853, 9855, 9857, 9859,
+    9861, 9863, 9865, 9867, 9869, 9871, 9873, 9875, 9877, 9879, 9881, 9883,
+    9885, 9887, 9889, 9891, 9893, 9895, 9897, 9899, 9901, 9903, 9905, 9907,
+    9909, 9911, 9913, 9915, 9917, 9919, 9921, 9923, 9925, 9927, 9929, 9931,
+    9933, 9935, 9937, 9939, 9941, 9943, 9945, 9947, 9949, 9951, 9953, 9955,
+    9957, 9959, 9961, 9963, 9965, 9967, 9969, 9971, 9973, 9975, 9977, 9979,
+    9981, 9984, 9987, 9990, 9993, 9996, 9999, 10002, 0, 0, 0, 0, 10005,
+    10007, 10009, 10011, 10013, 10015, 10017, 10019, 10021, 10023, 10025,
+    10027, 10029, 10031, 10033, 10035, 10037, 10039, 10041, 10043, 10045,
+    10047, 10049, 10051, 10053, 10055, 10057, 10059, 10061, 10063, 10065,
+    10067, 10069, 10071, 10073, 10075, 10077, 10079, 10081, 10083, 10085,
+    10087, 10089, 10091, 10093, 10095, 10097, 10099, 10101, 10103, 10105,
+    10107, 10109, 10111, 10113, 10115, 10117, 10119, 10121, 10123, 10125,
+    10127, 10129, 10131, 10133, 10135, 10137, 10139, 10141, 10143, 10145,
+    10147, 10149, 10151, 10153, 10155, 10157, 10159, 10161, 10163, 10165,
+    10167, 10169, 10171, 10173, 10175, 10177, 10179, 10181, 10183, 10185,
+    10187, 10189, 10191, 10193, 10195, 10197, 10199, 10201, 10203, 10205,
+    10207, 10209, 10211, 10213, 10215, 10217, 10219, 10221, 10223, 10225,
+    10227, 10229, 10231, 10233, 10235, 10237, 10239, 10241, 10243, 10245,
+    10247, 10249, 10251, 10253, 10255, 10257, 10259, 10261, 10263, 10265,
+    10267, 10269, 10271, 10273, 10275, 10277, 10279, 10281, 10283, 10285,
+    10287, 10289, 10291, 10293, 10295, 10297, 10299, 10301, 10303, 10305,
+    10307, 10309, 10311, 10313, 10315, 10317, 10319, 10321, 10323, 10325,
+    10327, 10329, 10331, 10333, 10335, 10337, 10339, 10341, 10343, 10345,
+    10347, 10349, 10351, 10353, 10355, 10357, 10359, 10361, 10363, 10365,
+    10367, 10369, 10371, 10373, 10375, 10377, 10379, 10381, 10383, 0, 0, 0,
+    10385, 10387, 10389, 10391, 10393, 10395, 0, 0, 10397, 10399, 10401,
+    10403, 10405, 10407, 0, 0, 10409, 10411, 10413, 10415, 10417, 10419, 0,
+    0, 10421, 10423, 10425, 0, 0, 0, 10427, 10429, 10431, 10433, 10435,
+    10437, 10439, 0, 10441, 10443, 10445, 10447, 10449, 10451, 10453, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 10455, 0, 10460, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 10465, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    10470, 10475, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10480, 10485, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10490, 10495, 0, 10500, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 10505, 10510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 10515, 10520, 10525, 10530, 10535, 10540, 10545, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10550, 10555, 10560,
+    10565, 10570, 10575, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10580,
+    10582, 10584, 10586, 10588, 10590, 10592, 10594, 10596, 10598, 10600,
+    10602, 10604, 10606, 10608, 10610, 10612, 10614, 10616, 10618, 10620,
+    10622, 10624, 10626, 10628, 10630, 10632, 10634, 10636, 10638, 10640,
+    10642, 10644, 10646, 10648, 10650, 10652, 10654, 10656, 10658, 10660,
+    10662, 10664, 10666, 10668, 10670, 10672, 10674, 10676, 10678, 10680,
+    10682, 10684, 10686, 10688, 10690, 10692, 10694, 10696, 10698, 10700,
+    10702, 10704, 10706, 10708, 10710, 10712, 10714, 10716, 10718, 10720,
+    10722, 10724, 10726, 10728, 10730, 10732, 10734, 10736, 10738, 10740,
+    10742, 10744, 10746, 10748, 0, 10750, 10752, 10754, 10756, 10758, 10760,
+    10762, 10764, 10766, 10768, 10770, 10772, 10774, 10776, 10778, 10780,
+    10782, 10784, 10786, 10788, 10790, 10792, 10794, 10796, 10798, 10800,
+    10802, 10804, 10806, 10808, 10810, 10812, 10814, 10816, 10818, 10820,
+    10822, 10824, 10826, 10828, 10830, 10832, 10834, 10836, 10838, 10840,
+    10842, 10844, 10846, 10848, 10850, 10852, 10854, 10856, 10858, 10860,
+    10862, 10864, 10866, 10868, 10870, 10872, 10874, 10876, 10878, 10880,
+    10882, 10884, 10886, 10888, 10890, 0, 10892, 10894, 0, 0, 10896, 0, 0,
+    10898, 10900, 0, 0, 10902, 10904, 10906, 10908, 0, 10910, 10912, 10914,
+    10916, 10918, 10920, 10922, 10924, 10926, 10928, 10930, 10932, 0, 10934,
+    0, 10936, 10938, 10940, 10942, 10944, 10946, 10948, 0, 10950, 10952,
+    10954, 10956, 10958, 10960, 10962, 10964, 10966, 10968, 10970, 10972,
+    10974, 10976, 10978, 10980, 10982, 10984, 10986, 10988, 10990, 10992,
+    10994, 10996, 10998, 11000, 11002, 11004, 11006, 11008, 11010, 11012,
+    11014, 11016, 11018, 11020, 11022, 11024, 11026, 11028, 11030, 11032,
+    11034, 11036, 11038, 11040, 11042, 11044, 11046, 11048, 11050, 11052,
+    11054, 11056, 11058, 11060, 11062, 11064, 11066, 11068, 11070, 11072,
+    11074, 11076, 11078, 0, 11080, 11082, 11084, 11086, 0, 0, 11088, 11090,
+    11092, 11094, 11096, 11098, 11100, 11102, 0, 11104, 11106, 11108, 11110,
+    11112, 11114, 11116, 0, 11118, 11120, 11122, 11124, 11126, 11128, 11130,
+    11132, 11134, 11136, 11138, 11140, 11142, 11144, 11146, 11148, 11150,
+    11152, 11154, 11156, 11158, 11160, 11162, 11164, 11166, 11168, 11170,
+    11172, 0, 11174, 11176, 11178, 11180, 0, 11182, 11184, 11186, 11188,
+    11190, 0, 11192, 0, 0, 0, 11194, 11196, 11198, 11200, 11202, 11204,
+    11206, 0, 11208, 11210, 11212, 11214, 11216, 11218, 11220, 11222, 11224,
+    11226, 11228, 11230, 11232, 11234, 11236, 11238, 11240, 11242, 11244,
+    11246, 11248, 11250, 11252, 11254, 11256, 11258, 11260, 11262, 11264,
+    11266, 11268, 11270, 11272, 11274, 11276, 11278, 11280, 11282, 11284,
+    11286, 11288, 11290, 11292, 11294, 11296, 11298, 11300, 11302, 11304,
+    11306, 11308, 11310, 11312, 11314, 11316, 11318, 11320, 11322, 11324,
+    11326, 11328, 11330, 11332, 11334, 11336, 11338, 11340, 11342, 11344,
+    11346, 11348, 11350, 11352, 11354, 11356, 11358, 11360, 11362, 11364,
+    11366, 11368, 11370, 11372, 11374, 11376, 11378, 11380, 11382, 11384,
+    11386, 11388, 11390, 11392, 11394, 11396, 11398, 11400, 11402, 11404,
+    11406, 11408, 11410, 11412, 11414, 11416, 11418, 11420, 11422, 11424,
+    11426, 11428, 11430, 11432, 11434, 11436, 11438, 11440, 11442, 11444,
+    11446, 11448, 11450, 11452, 11454, 11456, 11458, 11460, 11462, 11464,
+    11466, 11468, 11470, 11472, 11474, 11476, 11478, 11480, 11482, 11484,
+    11486, 11488, 11490, 11492, 11494, 11496, 11498, 11500, 11502, 11504,
+    11506, 11508, 11510, 11512, 11514, 11516, 11518, 11520, 11522, 11524,
+    11526, 11528, 11530, 11532, 11534, 11536, 11538, 11540, 11542, 11544,
+    11546, 11548, 11550, 11552, 11554, 11556, 11558, 11560, 11562, 11564,
+    11566, 11568, 11570, 11572, 11574, 11576, 11578, 11580, 11582, 11584,
+    11586, 11588, 11590, 11592, 11594, 11596, 11598, 11600, 11602, 11604,
+    11606, 11608, 11610, 11612, 11614, 11616, 11618, 11620, 11622, 11624,
+    11626, 11628, 11630, 11632, 11634, 11636, 11638, 11640, 11642, 11644,
+    11646, 11648, 11650, 11652, 11654, 11656, 11658, 11660, 11662, 11664,
+    11666, 11668, 11670, 11672, 11674, 11676, 11678, 11680, 11682, 11684,
+    11686, 11688, 11690, 11692, 11694, 11696, 11698, 11700, 11702, 11704,
+    11706, 11708, 11710, 11712, 11714, 11716, 11718, 11720, 11722, 11724,
+    11726, 11728, 11730, 11732, 11734, 11736, 11738, 11740, 11742, 11744,
+    11746, 11748, 11750, 11752, 11754, 11756, 11758, 11760, 11762, 11764,
+    11766, 11768, 11770, 11772, 11774, 11776, 11778, 11780, 11782, 11784,
+    11786, 11788, 11790, 11792, 11794, 11796, 11798, 11800, 11802, 11804,
+    11806, 11808, 11810, 11812, 11814, 11816, 11818, 11820, 11822, 11824,
+    11826, 11828, 11830, 11832, 11834, 11836, 11838, 11840, 11842, 11844,
+    11846, 11848, 11850, 11852, 11854, 11856, 11858, 11860, 11862, 11864,
+    11866, 11868, 11870, 11872, 11874, 11876, 11878, 11880, 11882, 11884,
+    11886, 0, 0, 11888, 11890, 11892, 11894, 11896, 11898, 11900, 11902,
+    11904, 11906, 11908, 11910, 11912, 11914, 11916, 11918, 11920, 11922,
+    11924, 11926, 11928, 11930, 11932, 11934, 11936, 11938, 11940, 11942,
+    11944, 11946, 11948, 11950, 11952, 11954, 11956, 11958, 11960, 11962,
+    11964, 11966, 11968, 11970, 11972, 11974, 11976, 11978, 11980, 11982,
+    11984, 11986, 11988, 11990, 11992, 11994, 11996, 11998, 12000, 12002,
+    12004, 12006, 12008, 12010, 12012, 12014, 12016, 12018, 12020, 12022,
+    12024, 12026, 12028, 12030, 12032, 12034, 12036, 12038, 12040, 12042,
+    12044, 12046, 12048, 12050, 12052, 12054, 12056, 12058, 12060, 12062,
+    12064, 12066, 12068, 12070, 12072, 12074, 12076, 12078, 12080, 12082,
+    12084, 12086, 12088, 12090, 12092, 12094, 12096, 12098, 12100, 12102,
+    12104, 12106, 12108, 12110, 12112, 12114, 12116, 12118, 12120, 12122,
+    12124, 12126, 12128, 12130, 12132, 12134, 12136, 12138, 12140, 12142,
+    12144, 12146, 12148, 12150, 12152, 12154, 12156, 12158, 12160, 12162,
+    12164, 12166, 12168, 12170, 12172, 12174, 12176, 12178, 12180, 12182,
+    12184, 12186, 12188, 12190, 12192, 12194, 12196, 12198, 12200, 12202,
+    12204, 12206, 12208, 12210, 12212, 12214, 12216, 12218, 12220, 12222,
+    12224, 12226, 12228, 12230, 12232, 12234, 12236, 12238, 12240, 12242,
+    12244, 12246, 12248, 12250, 12252, 12254, 12256, 12258, 12260, 12262,
+    12264, 12266, 12268, 12270, 12272, 12274, 12276, 12278, 12280, 12282,
+    12284, 12286, 12288, 12290, 12292, 12294, 12296, 12298, 12300, 12302,
+    12304, 12306, 12308, 12310, 12312, 12314, 12316, 12318, 12320, 12322,
+    12324, 12326, 12328, 12330, 12332, 12334, 12336, 12338, 12340, 12342,
+    12344, 12346, 12348, 12350, 12352, 12354, 12356, 12358, 12360, 12362,
+    12364, 12366, 12368, 12370, 12372, 12374, 12376, 12378, 12380, 12382,
+    12384, 12386, 12388, 12390, 12392, 12394, 12396, 12398, 12400, 12402,
+    12404, 12406, 12408, 12410, 12412, 12414, 12416, 12418, 12420, 12422,
+    12424, 12426, 12428, 12430, 12432, 12434, 12436, 12438, 12440, 12442,
+    12444, 12446, 12448, 12450, 12452, 12454, 12456, 12458, 12460, 12462,
+    12464, 12466, 12468, 12470, 0, 0, 12472, 12474, 12476, 12478, 12480,
+    12482, 12484, 12486, 12488, 12490, 12492, 12494, 12496, 12498, 12500,
+    12502, 12504, 12506, 12508, 12510, 12512, 12514, 12516, 12518, 12520,
+    12522, 12524, 12526, 12528, 12530, 12532, 12534, 12536, 12538, 12540,
+    12542, 12544, 12546, 12548, 12550, 12552, 12554, 12556, 12558, 12560,
+    12562, 12564, 12566, 12568, 12570, 12572, 12574, 12576, 12578, 0, 12580,
+    12582, 12584, 12586, 12588, 12590, 12592, 12594, 12596, 12598, 12600,
+    12602, 12604, 12606, 12608, 12610, 12612, 12614, 12616, 12618, 12620,
+    12622, 12624, 12626, 12628, 12630, 12632, 0, 12634, 12636, 0, 12638, 0,
+    0, 12640, 0, 12642, 12644, 12646, 12648, 12650, 12652, 12654, 12656,
+    12658, 12660, 0, 12662, 12664, 12666, 12668, 0, 12670, 0, 12672, 0, 0, 0,
+    0, 0, 0, 12674, 0, 0, 0, 0, 12676, 0, 12678, 0, 12680, 0, 12682, 12684,
+    12686, 0, 12688, 12690, 0, 12692, 0, 0, 12694, 0, 12696, 0, 12698, 0,
+    12700, 0, 12702, 0, 12704, 12706, 0, 12708, 0, 0, 12710, 12712, 12714,
+    12716, 0, 12718, 12720, 12722, 12724, 12726, 12728, 12730, 0, 12732,
+    12734, 12736, 12738, 0, 12740, 12742, 12744, 12746, 0, 12748, 0, 12750,
+    12752, 12754, 12756, 12758, 12760, 12762, 12764, 12766, 12768, 0, 12770,
+    12772, 12774, 12776, 12778, 12780, 12782, 12784, 12786, 12788, 12790,
+    12792, 12794, 12796, 12798, 12800, 12802, 0, 0, 0, 0, 0, 12804, 12806,
+    12808, 0, 12810, 12812, 12814, 12816, 12818, 0, 12820, 12822, 12824,
+    12826, 12828, 12830, 12832, 12834, 12836, 12838, 12840, 12842, 12844,
+    12846, 12848, 12850, 12852, 0, 0, 0, 0, 12854, 12857, 12860, 12863,
+    12866, 12869, 12872, 12875, 12878, 12881, 12884, 0, 0, 0, 0, 0, 12887,
+    12891, 12895, 12899, 12903, 12907, 12911, 12915, 12919, 12923, 12927,
+    12931, 12935, 12939, 12943, 12947, 12951, 12955, 12959, 12963, 12967,
+    12971, 12975, 12979, 12983, 12987, 12991, 12995, 12997, 12999, 13002, 0,
+    13005, 13007, 13009, 13011, 13013, 13015, 13017, 13019, 13021, 13023,
+    13025, 13027, 13029, 13031, 13033, 13035, 13037, 13039, 13041, 13043,
+    13045, 13047, 13049, 13051, 13053, 13055, 13057, 13060, 13063, 13066,
+    13069, 13073, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13076, 13079, 0, 0, 0, 0,
+    13082, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13085, 13088, 13091,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13093, 13095, 13097, 13099, 13101,
+    13103, 13105, 13107, 13109, 13111, 13113, 13115, 13117, 13119, 13121,
+    13123, 13125, 13127, 13129, 13131, 13133, 13135, 13137, 13139, 13141,
+    13143, 13145, 13147, 13149, 13151, 13153, 13155, 13157, 13159, 13161,
+    13163, 13165, 13167, 13169, 13171, 13173, 13175, 13177, 13179, 0, 0, 0,
+    0, 13181, 13185, 13189, 13193, 13197, 13201, 13205, 13209, 13213, 0, 0,
+    0, 0, 0, 0, 0, 13217, 13219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    13221, 13223, 13225, 13227, 13230, 13232, 13234, 13236, 13238, 13240,
+    13242, 13244, 13246, 13248, 13251, 13253, 13255, 13257, 13259, 13262,
+    13264, 13266, 13268, 13271, 13273, 13275, 13277, 13279, 13281, 13284,
+    13286, 13288, 13290, 13292, 13294, 13296, 13298, 13300, 13302, 13304,
+    13306, 13308, 13310, 13312, 13314, 13316, 13318, 13320, 13322, 13324,
+    13326, 13328, 13330, 13333, 13335, 13337, 13339, 13342, 13344, 13346,
+    13348, 13350, 13352, 13354, 13356, 13358, 13360, 13362, 13364, 13366,
+    13368, 13370, 13372, 13374, 13376, 13378, 13380, 13382, 13384, 13386,
+    13388, 13390, 13392, 13394, 13396, 13398, 13400, 13402, 13404, 13406,
+    13409, 13411, 13413, 13415, 13417, 13419, 13421, 13424, 13427, 13429,
+    13431, 13433, 13435, 13437, 13439, 13441, 13443, 13445, 13447, 13450,
+    13452, 13454, 13456, 13458, 13461, 13463, 13465, 13467, 13469, 13471,
+    13473, 13475, 13477, 13479, 13482, 13484, 13487, 13489, 13491, 13493,
+    13495, 13497, 13499, 13501, 13503, 13505, 13507, 13509, 13512, 13514,
+    13516, 13518, 13520, 13522, 13525, 13527, 13530, 13533, 13535, 13537,
+    13539, 13541, 13544, 13547, 13549, 13551, 13553, 13555, 13557, 13559,
+    13561, 13563, 13565, 13567, 13569, 13572, 13574, 13576, 13578, 13580,
+    13582, 13584, 13586, 13588, 13590, 13592, 13594, 13596, 13598, 13600,
+    13602, 13604, 13606, 13608, 13610, 13613, 13615, 13617, 13619, 13621,
+    13623, 13626, 13628, 13630, 13632, 13634, 13636, 13638, 13640, 13642,
+    13644, 13646, 13648, 13651, 13653, 13655, 13657, 13659, 13661, 13663,
+    13665, 13667, 13669, 13671, 13673, 13675, 13677, 13679, 13681, 13683,
+    13685, 13687, 13690, 13692, 13694, 13696, 13698, 13700, 13703, 13705,
+    13707, 13709, 13711, 13713, 13715, 13717, 13719, 13722, 13724, 13726,
+    13728, 13731, 13733, 13735, 13737, 13739, 13741, 13743, 13746, 13749,
+    13752, 13754, 13757, 13759, 13761, 13763, 13765, 13767, 13769, 13771,
+    13773, 13775, 13777, 13780, 13782, 13784, 13786, 13788, 13790, 13792,
+    13795, 13797, 13799, 13802, 13805, 13807, 13809, 13811, 13813, 13815,
+    13817, 13819, 13821, 13823, 13826, 13828, 13831, 13833, 13836, 13838,
+    13840, 13842, 13845, 13847, 13849, 13852, 13855, 13857, 13859, 13861,
+    13863, 13865, 13867, 13869, 13871, 13873, 13875, 13877, 13879, 13881,
+    13884, 13886, 13889, 13891, 13894, 13896, 13899, 13902, 13905, 13907,
+    13909, 13911, 13914, 13917, 13920, 13923, 13925, 13927, 13929, 13931,
+    13933, 13935, 13937, 13939, 13942, 13944, 13946, 13948, 13950, 13953,
+    13955, 13958, 13961, 13963, 13965, 13967, 13969, 13971, 13973, 13976,
+    13979, 13982, 13984, 13986, 13989, 13991, 13993, 13995, 13998, 14000,
+    14002, 14004, 14006, 14008, 14011, 14013, 14015, 14017, 14019, 14021,
+    14023, 14026, 14029, 14031, 14034, 14036, 14039, 14041, 14043, 14045,
+    14048, 14051, 14053, 14056, 14058, 14061, 14063, 14065, 14067, 14069,
+    14071, 14073, 14076, 14079, 14082, 14085, 14087, 14089, 14091, 14093,
+    14095, 14097, 14099, 14101, 14103, 14105, 14107, 14109, 14112, 14114,
+    14116, 14118, 14120, 14122, 14124, 14126, 14128, 14130, 14132, 14134,
+    14136, 14139, 14142, 14145, 14147, 14149, 14151, 14153, 14156, 14158,
+    14161, 14163, 14165, 14168, 14171, 14173, 14175, 14177, 14179, 14181,
+    14183, 14185, 14187, 14189, 14191, 14193, 14195, 14197, 14199, 14201,
+    14203, 14205, 14207, 14209, 14212, 14214, 14216, 14218, 14220, 14222,
+    14225, 14228, 14230, 14232, 14234, 14236, 14238, 14240, 14243, 14245,
+    14247, 14249, 14251, 14254, 14257, 14259, 14261, 14263, 14266, 14268,
+    14270, 14273, 14276, 14278, 14280, 14282, 14285, 14287, 14289, 14291,
+    14293, 14295, 14297, 14299, 14302, 14304, 14306, 14308, 14311, 14313,
+    14315, 14317, 14319, 14322, 14325, 14327, 14329, 14331, 14334, 14336,
+    14339, 14341, 14343, 14345, 14348, 14350, 14352, 14354, 14356, 14358,
+    14360, 14362, 14365, 14367, 14369, 14371, 14373, 14375, 14377, 14380,
+    14382, 14385, 14388, 14391, 14393, 14395, 14397, 14399, 14401, 14403,
+    14405, 14407, 0, 0,
+};
+
+/* NFC pairs */
+#define COMP_SHIFT1 2
+#define COMP_SHIFT2 1
+static const unsigned short comp_index0[] = {
+    0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 4,
+    5, 6, 7, 0, 0, 0, 0, 8, 0, 9, 10, 0, 0, 0, 11, 12, 13, 14, 0, 0, 0, 0, 0,
+    15, 16, 17, 0, 0, 0, 0, 18, 19, 20, 21, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0,
+    23, 24, 25, 26, 0, 0, 0, 0, 27, 28, 29, 30, 0, 0, 0, 0, 31, 32, 33, 34,
+    0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 36, 0, 37, 38, 39, 0, 0, 0, 40, 41, 42,
+    43, 0, 0, 0, 0, 44, 45, 46, 0, 0, 0, 0, 0, 47, 48, 49, 50, 0, 0, 0, 51,
+    52, 53, 54, 0, 0, 0, 0, 55, 56, 0, 0, 0, 0, 0, 0, 57, 58, 59, 60, 0, 0,
+    0, 0, 61, 62, 63, 0, 0, 0, 0, 0, 64, 65, 66, 67, 0, 0, 0, 68, 69, 70, 71,
+    0, 0, 0, 0, 72, 0, 73, 0, 0, 0, 0, 0, 74, 0, 75, 0, 0, 0, 0, 0, 76, 0, 0,
+    0, 0, 0, 0, 77, 78, 79, 0, 0, 0, 0, 0, 80, 81, 82, 83, 0, 0, 0, 0, 84,
+    85, 86, 0, 0, 0, 0, 0, 87, 88, 0, 89, 0, 0, 0, 90, 91, 0, 92, 0, 0, 0, 0,
+    0, 93, 94, 95, 0, 0, 0, 0, 96, 97, 98, 99, 0, 0, 0, 0, 100, 0, 0, 0, 0,
+    0, 0, 101, 102, 0, 103, 0, 0, 0, 0, 104, 105, 106, 107, 0, 0, 0, 0, 108,
+    109, 110, 111, 0, 0, 0, 0, 112, 113, 0, 0, 0, 0, 0, 114, 115, 116, 117,
+    0, 0, 0, 0, 118, 119, 120, 121, 0, 0, 0, 0, 122, 0, 123, 0, 0, 0, 0, 124,
+    125, 126, 127, 128, 0, 0, 0, 129, 130, 131, 132, 0, 0, 0, 0, 133, 134, 0,
+    0, 0, 0, 0, 0, 135, 136, 137, 138, 0, 0, 0, 139, 140, 141, 142, 0, 0, 0,
+    0, 0, 143, 144, 145, 0, 0, 0, 0, 146, 147, 148, 149, 0, 0, 0, 0, 150, 0,
+    151, 0, 0, 0, 0, 152, 153, 154, 0, 0, 0, 0, 0, 0, 155, 0, 0, 0, 0, 0, 0,
+    156, 157, 158, 0, 0, 0, 0, 0, 159, 160, 161, 162, 0, 0, 0, 163, 0, 0, 0,
+    164, 0, 0, 0, 165, 166, 0, 0, 0, 0, 0, 0, 167, 0, 0, 0, 0, 0, 0, 0, 168,
+    0, 0, 0, 0, 0, 0, 169, 170, 0, 0, 0, 0, 0, 0, 171, 0, 0, 0, 0, 0, 0, 0,
+    172, 173, 0, 0, 0, 0, 0, 0, 174, 0, 0, 0, 0, 0, 0, 175, 176, 0, 0, 0, 0,
+    0, 0, 177, 178, 0, 0, 0, 0, 0, 0, 179, 0, 0, 0, 0, 0, 0, 0, 180, 0, 0, 0,
+    0, 0, 0, 181, 182, 183, 0, 0, 0, 0, 0, 184, 185, 0, 0, 0, 0, 0, 0, 186,
+    0, 0, 0, 0, 0, 0, 0, 187, 0, 0, 0, 0, 0, 0, 188, 189, 0, 0, 0, 0, 0, 0,
+    190, 0, 0, 0, 0, 0, 0, 0, 191, 192, 0, 0, 0, 0, 0, 0, 193, 0, 0, 0, 0, 0,
+    0, 194, 195, 0, 0, 0, 0, 0, 0, 196, 197, 0, 0, 0, 0, 0, 0, 198, 0, 0, 0,
+    0, 0, 0, 0, 199, 0, 0, 0, 0, 0, 0, 200, 201, 202, 0, 0, 0, 0, 0, 203,
+    204, 0, 0, 0, 0, 0, 0, 205, 206, 0, 0, 0, 0, 0, 0, 207, 0, 0, 0, 0, 0, 0,
+    208, 0, 0, 0, 0, 0, 0, 0, 209, 0, 0, 0, 0, 0, 0, 0, 210, 0, 0, 0, 0, 0,
+    0, 0, 211, 0, 0, 0, 0, 0, 0, 0, 212, 0, 0, 0, 0, 0, 0, 0, 213, 0, 0, 0,
+    0, 0, 0, 0, 214, 0, 0, 0, 0, 0, 0, 215, 0, 0, 0, 0, 0, 0, 216, 0, 0, 0,
+    0, 0, 0, 0, 0, 217, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 219, 0,
+    0, 0, 0, 0, 0, 220, 221, 222, 0, 0, 0, 0, 0, 223, 224, 225, 0, 0, 0, 0,
+    0, 226, 227, 228, 0, 0, 0, 0, 0, 229, 230, 231, 0, 0, 0, 0, 0, 0, 232, 0,
+    0, 0, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 234, 0, 0, 0, 0, 0, 0, 0, 235, 0,
+    0, 0, 0, 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, 0, 237, 0, 0, 0, 0, 0, 0, 238,
+    0, 0, 0, 0, 0, 0, 0, 239, 0, 0, 0, 0, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0,
+    241, 0, 0, 0, 0, 0, 0, 242, 0, 243, 244, 0, 0, 0, 0, 245, 246, 0, 0, 0,
+    0, 0, 247, 0, 248, 0, 249, 0, 0, 0, 250, 251, 252, 0, 0, 0, 0, 0, 253, 0,
+    254, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 256, 257, 258, 0, 0, 0, 0, 0,
+    259, 0, 260, 0, 261, 0, 0, 0, 0, 0, 0, 262, 0, 0, 0, 0, 0, 0, 0, 263, 0,
+    0, 0, 264, 265, 266, 0, 267, 0, 0, 0, 268, 0, 269, 0, 0, 0, 0, 0, 270, 0,
+    271, 272, 0, 0, 0, 0, 273, 274, 0, 275, 0, 0, 0, 276, 0, 277, 0, 0, 0, 0,
+    0, 0, 0, 278, 0, 0, 0, 0, 0, 279, 280, 281, 282, 0, 0, 0, 0, 283, 284, 0,
+    285, 0, 0, 0, 286, 0, 0, 0, 287, 0, 0, 0, 288, 0, 0, 0, 289, 0, 0, 0, 0,
+    0, 0, 290, 0, 0, 0, 0, 291, 0, 0, 0, 0, 0, 0, 0, 292, 0, 0, 0, 0, 0, 0,
+    0, 293, 0, 0, 0, 0, 0, 0, 294, 0, 0, 0, 0, 0, 0, 0, 295, 0, 0, 0, 0, 0,
+    0, 0, 296, 0, 0, 0, 0, 0, 0, 0, 297, 0, 0, 0, 0, 0, 0, 298, 299, 0, 0, 0,
+    0, 0, 0, 300, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 302, 0, 0,
+    0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 304, 0, 0, 0, 0, 0, 0, 0, 305, 0,
+    0, 0, 0, 0, 0, 0, 306, 0, 0, 0, 0, 0, 0, 307, 0, 0, 0, 0, 0, 0, 0, 308,
+    0, 0, 0, 0, 0, 0, 0, 309, 0, 0, 0, 0, 0, 0, 0, 310, 0, 0, 0, 0, 0, 0,
+    311, 312, 0, 0, 0, 0, 0, 0, 313, 0, 0, 0, 0, 0, 0, 0, 314, 0, 0, 0, 0, 0,
+    0, 0, 315, 0, 0, 0, 0, 0, 0, 0, 316, 0, 0, 0, 0, 0, 0, 317, 0, 0, 0, 0,
+    0, 0, 0, 318, 0, 0, 0, 0, 0, 0, 0, 319, 0, 0, 0, 0, 0, 0, 0, 320, 0, 0,
+    0, 0, 0, 0, 0, 321, 0, 0, 0, 0, 0, 0, 322, 0, 0, 0, 0, 0, 0, 0, 323, 0,
+    0, 0, 0, 0, 0, 0, 324, 0, 0, 0, 0, 0, 0, 325, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 326, 0, 0, 0, 0, 0, 0, 0, 327, 0, 0, 0, 0, 0, 0, 0, 328, 0, 0, 0, 0,
+    0, 0, 329, 0, 0, 0, 0, 0, 0, 0, 330, 0, 0, 0, 0, 0, 0, 0, 331, 0, 0, 0,
+    0, 0, 0, 0, 332, 0, 0, 0, 0, 0, 0, 0, 333, 0, 0, 0, 0, 0, 0, 334, 0, 0,
+    0, 0, 0, 0, 0, 335, 0, 0, 0, 0, 0, 0, 0, 336, 337, 0, 0, 0, 0, 0, 0, 0,
+    338, 0, 0, 0, 0, 0, 0, 339, 0, 0, 0, 0, 0, 0, 0, 340, 0, 0, 0, 0, 0, 0,
+    0, 341, 0, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0,
+    0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 345, 346, 0, 0, 0, 0, 0, 0, 347, 0, 0, 0,
+    0, 0, 0, 0, 348, 0, 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 350, 0,
+    0, 0, 0, 0, 0, 0, 351, 0, 0, 0, 0, 0, 0, 0, 352, 0, 0, 0, 0, 0, 0, 353,
+    0, 0, 0, 0, 0, 0, 0, 354, 0, 0, 0, 0, 0, 0, 0, 355, 0, 0, 0, 0, 0, 0, 0,
+    356, 0, 0, 0, 0, 0, 0, 357, 0, 0, 0, 0, 0, 0, 0, 358, 0, 0, 0, 0, 0, 0,
+    0, 359, 0, 0, 0, 0, 0, 0, 0, 360, 0, 0, 0, 0, 0, 0, 361, 0, 362, 0, 0, 0,
+    0, 0, 0, 0, 363, 0, 0, 0, 0, 0, 0, 0, 364, 0, 0, 0, 0, 0, 0, 0, 365, 0,
+    0, 0, 0, 0, 0, 0, 366, 0, 0, 0, 0, 0, 0, 367, 0, 0, 0, 0, 0, 0, 0, 368,
+    0, 0, 0, 0, 0, 0, 369, 370, 0, 0, 0, 0, 0, 0, 371, 0, 0, 0, 0, 0, 0, 0,
+    372, 0, 0, 0, 0, 0, 0, 0, 373, 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, 0, 0,
+    0, 375, 0, 0, 376, 0, 0, 0, 0, 377, 0, 0, 378, 0, 0, 0, 0, 0, 0, 0, 379,
+    0, 0, 0, 0, 0, 0, 0, 380, 0, 0, 0, 0, 0, 0, 381, 0, 0, 0, 0, 0, 0, 0,
+    382, 0, 0, 0, 0, 0, 0, 0, 383, 0, 0, 0, 0, 0, 0, 0, 384, 0, 0, 0, 385, 0,
+    0, 386, 0, 0, 0, 0, 387, 0, 0, 388, 0, 0, 0, 0, 0, 0, 0, 389, 0, 0, 0, 0,
+    0, 0, 0, 390, 0, 0, 0, 0, 0, 0, 391, 0, 0, 0, 0, 0, 0, 0, 392, 0, 0, 0,
+    0, 0, 0, 0, 393, 0, 0, 0, 0, 0, 0, 0, 394, 0, 0, 0, 395, 0, 0, 0, 0, 0,
+    0, 0, 396, 0, 0, 0, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, 0, 398, 0, 0, 0, 0,
+    0, 0, 0, 399, 0, 0, 400, 0, 0, 0, 0, 401, 0, 0, 402, 0, 0, 0, 0, 0, 0, 0,
+    403, 0, 0, 0, 0, 0, 0, 0, 404, 0, 0, 0, 0, 0, 0, 405, 0, 0, 0, 0, 0, 0,
+    0, 406, 0, 0, 0, 0, 0, 0, 0, 407, 0, 0, 0, 0, 0, 0, 0, 408, 0, 0, 0, 409,
+    0, 0, 410, 0, 0, 0, 0, 411, 0, 0, 412, 0, 0, 0, 0, 0, 0, 0, 413, 0, 0, 0,
+    0, 0, 0, 0, 414, 0, 0, 0, 0, 0, 0, 415, 0, 0, 0, 0, 0, 0, 0, 416, 0, 0,
+    0, 0, 0, 0, 0, 417, 0, 0, 0, 0, 0, 0, 0, 418, 0, 0, 0, 419, 0, 0, 420, 0,
+    0, 0, 0, 421, 0, 0, 422, 0, 0, 0, 423, 0, 0, 0, 424, 0, 0, 0, 425, 0, 0,
+    0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 428, 0, 0, 0, 0, 0, 0, 429, 0,
+    0, 0, 0, 0, 0, 0, 430, 0, 0, 0, 0, 0, 0, 0, 431, 0, 0, 432, 0, 0, 0, 0,
+    433, 0, 0, 434, 0, 0, 0, 435, 0, 0, 0, 436, 0, 0, 0, 437, 0, 0, 0, 438,
+    0, 0, 0, 439, 0, 0, 440, 0, 0, 0, 0, 0, 0, 0, 441, 0, 0, 0, 0, 0, 0, 0,
+    442, 0, 0, 0, 0, 0, 0, 0, 443, 0, 0, 0, 0, 0, 0, 444, 0, 0, 0, 0, 0, 0,
+    0, 445, 0, 0, 0, 0, 0, 0, 0, 446, 0, 0, 0, 447, 0, 0, 0, 448, 0, 0, 0,
+    449, 0, 0, 450, 0, 0, 0, 0, 0, 0, 0, 451, 0, 0, 0, 0, 0, 0, 0, 452, 0, 0,
+    0, 0, 0, 0, 0, 453, 0, 0, 0, 0, 0, 0, 454, 0, 0, 0, 0, 0, 0, 0, 455, 0,
+    0, 0, 0, 0, 0, 0, 456, 0, 0, 0, 0, 0, 0, 0, 457, 0, 0, 0, 0, 0, 0, 458,
+    0, 0, 0, 0, 0, 0, 0, 459, 0, 0, 0, 0, 0, 0, 0, 460, 0, 0, 0, 461, 0, 0,
+    0, 462, 0, 0, 0, 0, 0, 0, 463, 0, 0, 0, 0, 0, 0, 0, 464, 0, 0, 0, 465, 0,
+    0, 0, 466, 0, 0, 0, 0, 0, 0, 467, 0, 0, 0, 0, 0, 0, 0, 468, 0, 0, 0, 0,
+    0, 0, 0, 469, 0, 0, 0, 0, 0, 0, 0, 470, 0, 0, 0, 0, 0, 0, 471, 0, 0, 0,
+    0, 0, 0, 0, 472, 0, 0, 0, 0, 0, 0, 0, 473, 0, 0, 0, 0, 0, 0, 0, 474, 0,
+    0, 0, 0, 0, 0, 475, 0, 0, 0, 0, 0, 0, 0, 476, 0, 0, 0, 0, 0, 0, 0, 477,
+    0, 0, 0, 0, 0, 0, 0, 478, 0, 0, 0, 0, 0, 0, 479, 0, 0, 0, 0, 0, 0, 0,
+    480, 0, 0, 0, 0, 0, 0, 0, 481, 0, 0, 0, 0, 0, 0, 0, 482, 0, 0, 0, 0, 0,
+    0, 483, 0, 0, 0, 0, 0, 0, 0, 484, 0, 0, 0, 0, 0, 0, 0, 485, 0, 0, 0, 0,
+    0, 0, 0, 486, 0, 0, 0, 0, 0, 0, 487, 0, 0, 0, 0, 0, 0, 0, 488, 0, 0, 0,
+    0, 0, 0, 0, 489, 0, 0, 0, 0, 0, 0, 0, 490, 0, 0, 0, 0, 0, 0, 491, 0, 0,
+    0, 0, 0, 0, 0, 492, 0, 0, 0, 0, 0, 0, 0, 493, 0, 0, 0, 0, 0, 0, 0, 494,
+    0, 0, 0, 0, 0, 0, 495, 0, 0, 0, 0, 0, 0, 0, 496, 0, 0, 0, 0, 0, 0, 0,
+    497, 0, 0, 0, 0, 0, 0, 0, 498, 0, 0, 0, 0, 0, 0, 499, 0, 0, 0, 0, 0, 0,
+    0, 500, 0, 0, 0, 0, 0, 0, 0, 501, 0, 0, 0, 0, 0, 0, 0, 502, 0, 0, 0, 0,
+    0, 0, 503, 0, 0, 0, 0, 0, 0, 0, 504, 0, 0, 0, 0, 0, 0, 0, 505, 0, 0, 0,
+    0, 0, 0, 0, 506, 0, 0, 0, 0, 0, 0, 507, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    508, 0, 0, 0, 0, 0, 0, 0, 509, 0, 0, 0, 0, 0, 0, 0, 510, 0, 0, 0, 0, 0,
+    0, 0, 511, 0, 0, 0, 0, 0, 0, 512, 0, 0, 0, 0, 0, 0, 0, 513, 0, 0, 0, 0,
+    0, 0, 0, 514, 0, 0, 0, 0, 0, 0, 0, 515, 0, 0, 0, 0, 0, 0, 516, 0, 0, 0,
+    0, 0, 0, 0, 517, 0, 0, 0, 0, 0, 0, 0, 518, 0, 0, 0, 0, 0, 0, 0, 519, 0,
+    0, 0, 0, 0, 0, 520, 0, 0, 0, 0, 0, 0, 0, 521, 0, 0, 0, 0, 0, 0, 0, 522,
+    0, 0, 0, 0, 0, 0, 0, 523, 0, 0, 0, 0, 0, 0, 524, 0, 0, 0, 0, 0, 0, 0,
+    525, 0, 0, 0, 0, 0, 0, 0, 526, 0, 0, 0, 0, 0, 0, 0, 527, 0, 0, 0, 0, 0,
+    0, 528, 0, 0, 0, 0, 0, 0, 0, 529, 0, 0, 0, 0, 0, 0, 0, 530, 0, 0, 0, 0,
+    0, 0, 0, 531, 0, 0, 0, 0, 0, 0, 532, 0, 0, 0, 0, 0, 0, 0, 533, 0, 0, 0,
+    0, 0, 0, 0, 534, 0, 0, 0, 0, 0, 0, 0, 535, 0, 0, 0, 0, 0, 0, 536, 0, 0,
+    0, 0, 0, 0, 0, 537, 0, 0, 0, 0, 0, 0, 0, 538, 0, 0, 0, 0, 0, 0, 0, 539,
+    0, 0, 0, 0, 0, 0, 540, 0, 0, 0, 0, 0, 0, 0, 541, 0, 0, 0, 0, 0, 0, 0,
+    542, 0, 0, 0, 0, 0, 0, 0, 543, 0, 0, 0, 0, 0, 0, 544, 0, 0, 0, 0, 0, 0,
+    0, 545, 0, 0, 0, 0, 0, 0, 0, 546, 0, 0, 0, 0, 0, 0, 0, 547, 0, 0, 0, 0,
+    0, 0, 548, 0, 0, 0, 0, 0, 0, 0, 549, 0, 0, 0, 0, 0, 0, 0, 550, 0, 0, 0,
+    0, 0, 0, 0, 551, 0, 0, 0, 0, 0, 0, 552, 0, 0, 0, 0, 0, 0, 0, 553, 0, 0,
+    0, 0, 0, 0, 0, 554, 0, 0, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0, 0, 0, 0, 556,
+    0, 0, 0, 0, 0, 0, 557, 0, 0, 0, 0, 0, 0, 0, 558, 0, 0, 0, 0, 0, 0, 0,
+    559, 0, 0, 0, 0, 0, 0, 0, 560, 0, 0, 0, 0, 0, 0, 0, 561, 0, 0, 0, 0, 0,
+    0, 0, 562, 0, 0, 0, 0, 0, 0, 0, 563, 0, 0, 0, 0, 0, 0, 564,
+};
+
+static const unsigned short comp_index1[] = {
+    0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 4, 5, 6, 7, 8, 9, 10,
+    0, 11, 12, 0, 13, 0, 0, 0, 0, 0, 0, 14, 15, 0, 0, 0, 0, 16, 0, 0, 0, 0,
+    0, 17, 18, 0, 19, 0, 20, 0, 0, 0, 0, 21, 0, 0, 0, 22, 0, 23, 0, 0, 24, 0,
+    25, 26, 0, 27, 0, 28, 29, 30, 31, 32, 33, 34, 0, 35, 0, 36, 37, 38, 0, 0,
+    0, 0, 0, 39, 0, 0, 0, 40, 41, 42, 43, 0, 44, 0, 0, 0, 0, 45, 0, 0, 0, 0,
+    0, 46, 0, 47, 0, 48, 0, 0, 49, 0, 50, 0, 51, 0, 0, 52, 53, 54, 55, 56,
+    57, 58, 0, 59, 0, 0, 60, 61, 0, 0, 0, 62, 0, 0, 0, 0, 0, 63, 64, 0, 0,
+    65, 0, 66, 0, 0, 67, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 69, 0, 0, 70, 0, 71,
+    72, 0, 73, 0, 74, 0, 0, 75, 0, 0, 0, 0, 76, 0, 0, 77, 78, 0, 79, 0, 80,
+    0, 0, 81, 0, 82, 83, 0, 84, 0, 0, 0, 0, 0, 85, 86, 87, 88, 89, 90, 91, 0,
+    92, 0, 0, 93, 0, 0, 0, 94, 0, 0, 95, 0, 0, 0, 96, 0, 0, 97, 0, 98, 99, 0,
+    100, 0, 101, 0, 0, 102, 0, 103, 104, 0, 105, 0, 106, 0, 0, 107, 0, 108,
+    0, 0, 0, 109, 0, 110, 0, 0, 111, 0, 112, 113, 0, 114, 0, 0, 0, 0, 0, 115,
+    116, 117, 118, 119, 120, 121, 0, 122, 123, 0, 124, 125, 0, 0, 0, 126, 0,
+    0, 127, 0, 0, 128, 129, 0, 130, 131, 0, 0, 0, 0, 0, 132, 0, 0, 0, 133,
+    134, 135, 136, 137, 0, 0, 0, 138, 0, 0, 139, 140, 0, 141, 0, 142, 0, 0,
+    143, 0, 0, 0, 0, 144, 0, 145, 146, 147, 148, 149, 150, 151, 0, 152, 153,
+    0, 154, 0, 0, 155, 0, 0, 0, 0, 156, 157, 0, 0, 0, 0, 0, 158, 159, 0, 160,
+    0, 161, 162, 0, 0, 0, 163, 0, 164, 0, 0, 165, 0, 166, 167, 0, 168, 0,
+    169, 170, 171, 172, 173, 174, 175, 0, 176, 0, 177, 178, 179, 0, 0, 0, 0,
+    0, 180, 0, 0, 0, 181, 182, 183, 184, 0, 185, 186, 0, 0, 0, 0, 0, 187, 0,
+    188, 0, 189, 0, 0, 190, 0, 191, 0, 192, 193, 0, 194, 195, 196, 197, 198,
+    199, 200, 0, 201, 0, 0, 202, 203, 0, 0, 0, 204, 0, 0, 0, 205, 0, 0, 0, 0,
+    0, 206, 0, 0, 0, 0, 207, 0, 0, 208, 0, 209, 0, 0, 210, 0, 211, 0, 0, 0,
+    0, 212, 0, 0, 213, 0, 214, 215, 0, 216, 0, 217, 0, 0, 218, 219, 0, 0, 0,
+    0, 0, 0, 220, 221, 0, 222, 0, 223, 0, 0, 224, 0, 225, 226, 0, 227, 0, 0,
+    0, 0, 0, 228, 229, 230, 231, 232, 233, 234, 0, 235, 0, 0, 236, 0, 0, 0,
+    237, 0, 0, 238, 0, 0, 0, 239, 0, 0, 240, 0, 241, 242, 0, 243, 0, 244, 0,
+    0, 245, 0, 0, 0, 0, 0, 246, 247, 0, 248, 0, 249, 0, 0, 250, 0, 251, 0, 0,
+    0, 252, 0, 253, 0, 0, 254, 0, 255, 256, 0, 257, 0, 258, 259, 260, 261,
+    262, 263, 264, 0, 265, 266, 0, 267, 268, 0, 0, 0, 269, 0, 0, 270, 0, 0,
+    0, 0, 0, 0, 271, 272, 0, 273, 274, 0, 0, 0, 275, 0, 276, 0, 0, 0, 277,
+    278, 279, 280, 281, 0, 0, 0, 282, 0, 0, 283, 284, 0, 285, 0, 286, 0, 0,
+    287, 0, 0, 0, 0, 288, 0, 0, 0, 0, 0, 289, 0, 290, 0, 0, 0, 0, 291, 292,
+    0, 0, 293, 0, 0, 0, 0, 294, 295, 0, 0, 0, 0, 0, 0, 296, 0, 297, 0, 0, 0,
+    0, 298, 0, 0, 299, 300, 0, 0, 301, 0, 0, 302, 0, 0, 0, 0, 0, 0, 303, 304,
+    0, 0, 305, 0, 0, 306, 0, 307, 308, 0, 0, 0, 0, 0, 309, 310, 0, 0, 0, 0,
+    0, 0, 311, 0, 312, 0, 0, 313, 0, 0, 0, 0, 0, 314, 315, 0, 0, 316, 0, 0,
+    0, 0, 317, 318, 0, 0, 0, 0, 0, 0, 319, 0, 320, 0, 0, 0, 0, 321, 0, 0,
+    322, 323, 0, 0, 324, 0, 0, 325, 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, 328, 0,
+    0, 329, 0, 330, 331, 0, 0, 0, 0, 0, 332, 333, 0, 0, 0, 0, 0, 0, 334, 0,
+    335, 0, 0, 336, 0, 0, 0, 0, 0, 337, 338, 0, 0, 339, 0, 0, 340, 341, 0, 0,
+    342, 0, 0, 343, 0, 0, 0, 0, 0, 0, 344, 0, 0, 345, 0, 0, 346, 0, 0, 0, 0,
+    0, 347, 0, 0, 348, 0, 0, 349, 0, 0, 350, 0, 0, 0, 351, 0, 0, 0, 0, 0, 0,
+    352, 0, 353, 0, 0, 354, 0, 0, 0, 0, 0, 0, 355, 0, 0, 0, 356, 357, 0, 0,
+    358, 0, 0, 0, 359, 0, 0, 360, 361, 0, 0, 362, 0, 0, 0, 363, 0, 0, 364,
+    365, 0, 0, 366, 0, 0, 0, 367, 0, 0, 368, 369, 0, 0, 370, 0, 0, 0, 371, 0,
+    0, 0, 372, 0, 0, 0, 373, 0, 0, 0, 0, 0, 0, 374, 0, 0, 375, 0, 0, 376, 0,
+    0, 377, 0, 0, 0, 0, 0, 0, 378, 0, 0, 379, 0, 0, 380, 0, 0, 0, 0, 0, 381,
+    0, 382, 0, 383, 384, 0, 0, 0, 0, 0, 0, 385, 386, 0, 0, 0, 0, 0, 0, 387,
+    0, 0, 0, 388, 0, 0, 389, 0, 0, 390, 0, 0, 0, 0, 391, 0, 392, 393, 0, 0,
+    0, 394, 0, 0, 0, 395, 0, 0, 396, 0, 0, 0, 0, 0, 0, 397, 0, 0, 0, 398, 0,
+    399, 400, 0, 0, 0, 401, 0, 0, 0, 402, 0, 0, 403, 0, 0, 404, 0, 0, 0, 0,
+    0, 0, 405, 0, 0, 406, 0, 0, 0, 0, 407, 0, 408, 0, 0, 0, 0, 409, 0, 0,
+    410, 0, 0, 0, 0, 411, 0, 0, 412, 0, 0, 0, 413, 0, 0, 414, 0, 0, 0, 0, 0,
+    0, 415, 416, 0, 417, 418, 0, 0, 0, 419, 0, 0, 420, 0, 0, 0, 0, 421, 0, 0,
+    422, 0, 0, 423, 0, 0, 0, 424, 0, 425, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0,
+    0, 428, 429, 0, 0, 0, 0, 0, 0, 430, 0, 0, 431, 0, 0, 0, 0, 432, 0, 433,
+    0, 0, 0, 0, 434, 0, 435, 0, 0, 0, 0, 0, 0, 436, 437, 0, 0, 438, 0, 0,
+    439, 0, 440, 441, 0, 0, 0, 442, 0, 0, 443, 0, 444, 445, 0, 446, 447, 0,
+    0, 448, 0, 0, 0, 449, 0, 450, 451, 0, 0, 0, 452, 0, 0, 0, 0, 0, 453, 0,
+    454, 455, 0, 456, 457, 0, 0, 0, 0, 0, 0, 458, 0, 0, 459, 0, 460, 461, 0,
+    0, 0, 462, 0, 0, 463, 0, 464, 465, 0, 466, 467, 0, 0, 468, 0, 0, 0, 469,
+    0, 470, 471, 0, 0, 0, 472, 0, 0, 0, 0, 0, 473, 0, 474, 475, 0, 476, 477,
+    0, 0, 0, 0, 0, 0, 478, 0, 0, 479, 0, 0, 480, 0, 0, 0, 0, 0, 481, 0, 0,
+    482, 0, 0, 0, 483, 0, 0, 484, 0, 0, 485, 0, 0, 0, 0, 0, 0, 486, 0, 0,
+    487, 488, 0, 489, 0, 0, 490, 0, 0, 0, 0, 0, 0, 491, 0, 0, 492, 0, 0, 493,
+    0, 0, 0, 494, 0, 0, 495, 0, 0, 0, 0, 0, 0, 496, 0, 0, 0, 497, 0, 0, 0,
+    498, 499, 0, 0, 0, 500, 0, 0, 0, 0, 0, 501, 502, 0, 503, 0, 0, 0, 504, 0,
+    0, 0, 505, 0, 0, 506, 507, 0, 0, 0, 0, 0, 508, 0, 0, 0, 509, 510, 0, 0,
+    0, 0, 0, 511, 0, 0, 0, 512, 513, 0, 514, 0, 0, 0, 0, 515, 0, 0, 516, 0,
+    0, 517, 0, 0, 0, 0, 0, 0, 518, 0, 0, 519, 0, 0, 520, 0, 0, 521, 0, 0, 0,
+    0, 0, 0, 522, 0, 0, 523, 0, 0, 524, 0, 0, 525, 0, 0, 0, 0, 0, 0, 526, 0,
+    0, 0, 527, 0, 0, 528, 0, 0, 529, 0, 0, 530, 0, 0, 0, 531, 0, 0, 0, 0, 0,
+    0, 532, 533, 534, 0, 0, 0, 0, 0, 535, 536, 0, 0, 0, 0, 0, 537, 0, 0, 538,
+    0, 0, 539, 0, 0, 0, 0, 0, 0, 540, 0, 541, 0, 0, 0, 0, 0, 542, 543, 0, 0,
+    0, 0, 0, 544, 0, 0, 545, 0, 0, 546, 0, 0, 0, 0, 0, 0, 547, 0, 0, 548, 0,
+    0, 549, 0, 0, 550, 0, 0, 0, 0, 551, 0, 0, 0, 0, 0, 552, 553, 0, 0, 0, 0,
+    0, 554, 0, 0, 555, 0, 0, 556, 0, 0, 0, 0, 0, 0, 557, 0, 0, 558, 0, 0,
+    559, 0, 0, 560, 0, 0, 0, 0, 561, 0, 0, 562, 0, 0, 0, 0, 0, 0, 563, 0, 0,
+    564, 0, 0, 565, 0, 0, 0, 0, 0, 566, 567, 0, 0, 0, 0, 0, 568, 0, 0, 569,
+    0, 0, 570, 0, 0, 0, 0, 0, 0, 571, 0, 0, 572, 0, 0, 573, 0, 0, 574, 0, 0,
+    0, 0, 575, 0, 0, 0, 0, 0, 576, 577, 0, 0, 0, 0, 0, 578, 0, 0, 579, 0, 0,
+    580, 0, 0, 0, 0, 0, 0, 581, 0, 0, 582, 0, 0, 583, 0, 0, 584, 0, 0, 0, 0,
+    585, 0, 0, 0, 0, 0, 586, 587, 0, 0, 0, 0, 0, 588, 0, 0, 0, 0, 589, 0,
+    590, 0, 0, 0, 0, 591, 0, 592, 0, 0, 0, 0, 593, 0, 0, 594, 0, 0, 0, 0, 0,
+    0, 595, 0, 0, 596, 0, 0, 597, 0, 0, 0, 0, 0, 598, 599, 0, 0, 0, 0, 0,
+    600, 0, 0, 0, 0, 601, 0, 602, 0, 0, 0, 0, 603, 0, 604, 0, 0, 0, 0, 605,
+    0, 0, 0, 0, 0, 606, 0, 0, 607, 0, 0, 608, 0, 0, 609, 0, 0, 0, 0, 0, 0,
+    610, 0, 0, 611, 0, 0, 612, 0, 0, 0, 0, 613, 0, 614, 0, 0, 0, 0, 615, 0,
+    0, 0, 0, 0, 616, 0, 0, 617, 0, 0, 618, 0, 0, 619, 0, 0, 0, 0, 0, 0, 620,
+    0, 0, 621, 0, 0, 622, 0, 0, 623, 0, 0, 0, 0, 0, 0, 624, 0, 0, 625, 0, 0,
+    626, 0, 0, 0, 0, 627, 0, 628, 0, 0, 0, 0, 0, 0, 629, 0, 0, 630, 0, 0, 0,
+    0, 631, 0, 632, 0, 0, 0, 0, 0, 633, 0, 0, 634, 0, 0, 635, 0, 0, 636, 0,
+    0, 0, 0, 0, 0, 637, 0, 0, 638, 0, 0, 639, 0, 0, 640, 0, 0, 0, 0, 0, 0,
+    641, 0, 0, 642, 0, 0, 643, 0, 0, 644, 0, 0, 0, 0, 0, 0, 645, 0, 0, 646,
+    0, 0, 647, 0, 0, 648, 0, 0, 0, 0, 0, 0, 649, 0, 0, 650, 0, 0, 651, 0, 0,
+    652, 0, 0, 0, 0, 0, 0, 653, 0, 0, 654, 0, 0, 655, 0, 0, 656, 0, 0, 0, 0,
+    0, 0, 657, 0, 0, 658, 0, 0, 659, 0, 0, 660, 0, 0, 0, 0, 0, 0, 661, 0, 0,
+    662, 0, 0, 663, 0, 0, 664, 0, 0, 0, 0, 0, 0, 665, 0, 0, 666, 0, 0, 667,
+    0, 0, 668, 0, 0, 0, 0, 0, 0, 669, 0, 0, 670, 0, 0, 671, 0, 0, 672, 0, 0,
+    0, 0, 0, 0, 673, 0, 0, 0, 674, 0, 0, 675, 0, 0, 676, 0, 0, 677, 0, 0, 0,
+    0, 0, 0, 678, 0, 0, 679, 0, 0, 680, 0, 0, 681, 0, 0, 0, 0, 0, 0, 682, 0,
+    0, 683, 0, 0, 684, 0, 0, 685, 0, 0, 0, 0, 0, 0, 686, 0, 0, 687, 0, 0,
+    688, 0, 0, 689, 0, 0, 0, 0, 0, 0, 690, 0, 0, 691, 0, 0, 692, 0, 0, 693,
+    0, 0, 0, 0, 0, 0, 694, 0, 0, 695, 0, 0, 696, 0, 0, 697, 0, 0, 0, 0, 0, 0,
+    698, 0, 0, 699, 0, 0, 700, 0, 0, 701, 0, 0, 0, 0, 0, 0, 702, 0, 0, 703,
+    0, 0, 704, 0, 0, 705, 0, 0, 0, 0, 0, 0, 706, 0, 0, 707, 0, 0, 708, 0, 0,
+    709, 0, 0, 0, 0, 0, 0, 710, 0, 0, 711, 0, 0, 712, 0, 0, 713, 0, 0, 0, 0,
+    0, 0, 714, 0, 0, 715, 0, 0, 716, 0, 0, 717, 0, 0, 0, 0, 0, 0, 718, 0, 0,
+    719, 0, 0, 720, 0, 0, 721, 0, 0, 0, 722, 0, 0, 0, 0, 0, 0, 723, 0, 0,
+    724, 0, 0, 725, 0, 0, 726, 0, 0, 0, 727, 0, 0, 0, 728, 729, 0, 0, 730, 0,
+    0, 0, 0, 0, 0, 731,
+};
+
+static const unsigned int comp_data[] = {
+    0, 0, 0, 8814, 0, 8800, 0, 8815, 192, 193, 194, 195, 256, 258, 550, 196,
+    7842, 197, 0, 461, 512, 514, 0, 7840, 0, 7680, 260, 0, 7682, 0, 0, 7684,
+    7686, 0, 0, 262, 264, 0, 266, 0, 0, 268, 0, 199, 7690, 0, 0, 270, 0,
+    7692, 0, 7696, 0, 7698, 7694, 0, 200, 201, 202, 7868, 274, 276, 278, 203,
+    7866, 0, 0, 282, 516, 518, 0, 7864, 0, 552, 280, 7704, 0, 7706, 7710, 0,
+    0, 500, 284, 0, 7712, 286, 288, 0, 0, 486, 0, 290, 292, 0, 7714, 7718, 0,
+    542, 0, 7716, 0, 7720, 7722, 0, 204, 205, 206, 296, 298, 300, 304, 207,
+    7880, 0, 0, 463, 520, 522, 0, 7882, 302, 0, 0, 7724, 308, 0, 0, 7728, 0,
+    488, 0, 7730, 0, 310, 7732, 0, 0, 313, 0, 317, 0, 7734, 0, 315, 0, 7740,
+    7738, 0, 0, 7742, 7744, 0, 0, 7746, 504, 323, 0, 209, 7748, 0, 0, 327, 0,
+    7750, 0, 325, 0, 7754, 7752, 0, 210, 211, 212, 213, 332, 334, 558, 214,
+    7886, 0, 336, 465, 524, 526, 416, 7884, 490, 0, 0, 7764, 7766, 0, 0, 340,
+    7768, 0, 0, 344, 528, 530, 0, 7770, 0, 342, 7774, 0, 0, 346, 348, 0,
+    7776, 0, 0, 352, 0, 7778, 536, 350, 7786, 0, 0, 356, 0, 7788, 538, 354,
+    0, 7792, 7790, 0, 217, 218, 219, 360, 362, 364, 0, 220, 7910, 366, 368,
+    467, 532, 534, 431, 7908, 7794, 0, 370, 7798, 0, 7796, 0, 7804, 0, 7806,
+    7808, 7810, 372, 0, 7814, 7812, 0, 7816, 7818, 7820, 7922, 221, 374,
+    7928, 562, 0, 7822, 376, 7926, 0, 0, 7924, 0, 377, 7824, 0, 379, 0, 0,
+    381, 0, 7826, 7828, 0, 224, 225, 226, 227, 257, 259, 551, 228, 7843, 229,
+    0, 462, 513, 515, 0, 7841, 0, 7681, 261, 0, 7683, 0, 0, 7685, 7687, 0, 0,
+    263, 265, 0, 267, 0, 0, 269, 0, 231, 7691, 0, 0, 271, 0, 7693, 0, 7697,
+    0, 7699, 7695, 0, 232, 233, 234, 7869, 275, 277, 279, 235, 7867, 0, 0,
+    283, 517, 519, 0, 7865, 0, 553, 281, 7705, 0, 7707, 7711, 0, 0, 501, 285,
+    0, 7713, 287, 289, 0, 0, 487, 0, 291, 293, 0, 7715, 7719, 0, 543, 0,
+    7717, 0, 7721, 7723, 0, 7830, 0, 236, 237, 238, 297, 299, 301, 0, 239,
+    7881, 0, 0, 464, 521, 523, 0, 7883, 303, 0, 0, 7725, 309, 0, 0, 496, 0,
+    7729, 0, 489, 0, 7731, 0, 311, 7733, 0, 0, 314, 0, 318, 0, 7735, 0, 316,
+    0, 7741, 7739, 0, 0, 7743, 7745, 0, 0, 7747, 505, 324, 0, 241, 7749, 0,
+    0, 328, 0, 7751, 0, 326, 0, 7755, 7753, 0, 242, 243, 244, 245, 333, 335,
+    559, 246, 7887, 0, 337, 466, 525, 527, 417, 7885, 491, 0, 0, 7765, 7767,
+    0, 0, 341, 7769, 0, 0, 345, 529, 531, 0, 7771, 0, 343, 7775, 0, 0, 347,
+    349, 0, 7777, 0, 0, 353, 0, 7779, 537, 351, 7787, 7831, 0, 357, 0, 7789,
+    539, 355, 0, 7793, 7791, 0, 249, 250, 251, 361, 363, 365, 0, 252, 7911,
+    367, 369, 468, 533, 535, 432, 7909, 7795, 0, 371, 7799, 0, 7797, 0, 7805,
+    0, 7807, 7809, 7811, 373, 0, 7815, 7813, 0, 7832, 0, 7817, 7819, 7821,
+    7923, 253, 375, 7929, 563, 0, 7823, 255, 7927, 7833, 0, 7925, 0, 378,
+    7825, 0, 380, 0, 0, 382, 0, 7827, 7829, 0, 8173, 901, 8129, 0, 7846,
+    7844, 0, 7850, 7848, 0, 478, 0, 0, 506, 0, 508, 482, 0, 0, 7688, 7872,
+    7870, 0, 7876, 7874, 0, 0, 7726, 7890, 7888, 0, 7894, 7892, 0, 0, 7756,
+    556, 0, 0, 7758, 554, 0, 0, 510, 475, 471, 469, 0, 0, 473, 7847, 7845, 0,
+    7851, 7849, 0, 479, 0, 0, 507, 0, 509, 483, 0, 0, 7689, 7873, 7871, 0,
+    7877, 7875, 0, 0, 7727, 7891, 7889, 0, 7895, 7893, 0, 0, 7757, 557, 0, 0,
+    7759, 555, 0, 0, 511, 476, 472, 470, 0, 0, 474, 7856, 7854, 0, 7860,
+    7858, 0, 7857, 7855, 0, 7861, 7859, 0, 7700, 7702, 7701, 7703, 7760,
+    7762, 7761, 7763, 7780, 0, 7781, 0, 7782, 0, 7783, 0, 0, 7800, 0, 7801,
+    0, 7802, 0, 7803, 7835, 0, 7900, 7898, 0, 7904, 7902, 0, 0, 7906, 7901,
+    7899, 0, 7905, 7903, 0, 0, 7907, 7914, 7912, 0, 7918, 7916, 0, 0, 7920,
+    7915, 7913, 0, 7919, 7917, 0, 0, 7921, 0, 494, 492, 0, 493, 0, 480, 0,
+    481, 0, 0, 7708, 0, 7709, 560, 0, 561, 0, 0, 495, 8122, 902, 8121, 8120,
+    7944, 7945, 0, 8124, 8136, 904, 7960, 7961, 8138, 905, 7976, 7977, 0,
+    8140, 8154, 906, 8153, 8152, 0, 938, 7992, 7993, 8184, 908, 8008, 8009,
+    0, 8172, 8170, 910, 8169, 8168, 0, 939, 0, 8025, 8186, 911, 8040, 8041,
+    0, 8188, 0, 8116, 0, 8132, 8048, 940, 8113, 8112, 7936, 7937, 8118, 8115,
+    8050, 941, 7952, 7953, 8052, 942, 7968, 7969, 8134, 8131, 8054, 943,
+    8145, 8144, 0, 970, 7984, 7985, 8150, 0, 8056, 972, 8000, 8001, 8164,
+    8165, 8058, 973, 8161, 8160, 0, 971, 8016, 8017, 8166, 0, 8060, 974,
+    8032, 8033, 8182, 8179, 8146, 912, 8151, 0, 8162, 944, 8167, 0, 0, 8180,
+    0, 979, 0, 980, 0, 1031, 0, 1232, 0, 1234, 0, 1027, 1024, 0, 0, 1238, 0,
+    1025, 0, 1217, 0, 1244, 0, 1246, 1037, 0, 1250, 1049, 0, 1252, 0, 1036,
+    0, 1254, 1262, 1038, 0, 1264, 1266, 0, 0, 1268, 0, 1272, 0, 1260, 0,
+    1233, 0, 1235, 0, 1107, 1104, 0, 0, 1239, 0, 1105, 0, 1218, 0, 1245, 0,
+    1247, 1117, 0, 1251, 1081, 0, 1253, 0, 1116, 0, 1255, 1263, 1118, 0,
+    1265, 1267, 0, 0, 1269, 0, 1273, 0, 1261, 0, 1111, 1142, 0, 1143, 0, 0,
+    1242, 0, 1243, 0, 1258, 0, 1259, 1570, 1571, 1573, 0, 0, 1572, 0, 1574,
+    0, 1730, 0, 1747, 0, 1728, 0, 2345, 0, 2353, 0, 2356, 2507, 2508, 2891,
+    2888, 2892, 0, 2964, 0, 0, 3018, 3020, 0, 0, 3019, 0, 3144, 0, 3264,
+    3274, 3271, 3272, 0, 0, 3275, 0, 3402, 3404, 0, 0, 3403, 0, 3546, 3548,
+    3550, 0, 3549, 4134, 0, 0, 6918, 0, 6920, 0, 6922, 0, 6924, 0, 6926, 0,
+    6930, 0, 6971, 0, 6973, 0, 6976, 0, 6977, 0, 6979, 7736, 0, 7737, 0,
+    7772, 0, 7773, 0, 7784, 0, 7785, 0, 7852, 0, 0, 7862, 7853, 0, 0, 7863,
+    7878, 0, 7879, 0, 7896, 0, 7897, 0, 7938, 7940, 7942, 8064, 7939, 7941,
+    7943, 8065, 0, 8066, 0, 8067, 0, 8068, 0, 8069, 0, 8070, 0, 8071, 7946,
+    7948, 7950, 8072, 7947, 7949, 7951, 8073, 0, 8074, 0, 8075, 0, 8076, 0,
+    8077, 0, 8078, 0, 8079, 7954, 7956, 7955, 7957, 7962, 7964, 7963, 7965,
+    7970, 7972, 7974, 8080, 7971, 7973, 7975, 8081, 0, 8082, 0, 8083, 0,
+    8084, 0, 8085, 0, 8086, 0, 8087, 7978, 7980, 7982, 8088, 7979, 7981,
+    7983, 8089, 0, 8090, 0, 8091, 0, 8092, 0, 8093, 0, 8094, 0, 8095, 7986,
+    7988, 7990, 0, 7987, 7989, 7991, 0, 7994, 7996, 7998, 0, 7995, 7997,
+    7999, 0, 8002, 8004, 8003, 8005, 8010, 8012, 8011, 8013, 8018, 8020,
+    8022, 0, 8019, 8021, 8023, 0, 8027, 8029, 8031, 0, 8034, 8036, 8038,
+    8096, 8035, 8037, 8039, 8097, 0, 8098, 0, 8099, 0, 8100, 0, 8101, 0,
+    8102, 0, 8103, 8042, 8044, 8046, 8104, 8043, 8045, 8047, 8105, 0, 8106,
+    0, 8107, 0, 8108, 0, 8109, 0, 8110, 0, 8111, 0, 8114, 0, 8130, 0, 8178,
+    0, 8119, 8141, 8142, 8143, 0, 0, 8135, 0, 8183, 8157, 8158, 8159, 0, 0,
+    8602, 0, 8603, 0, 8622, 0, 8653, 0, 8655, 0, 8654, 0, 8708, 0, 8713, 0,
+    8716, 0, 8740, 0, 8742, 0, 8769, 0, 8772, 0, 8775, 0, 8777, 0, 8813, 0,
+    8802, 0, 8816, 0, 8817, 0, 8820, 0, 8821, 0, 8824, 0, 8825, 0, 8832, 0,
+    8833, 0, 8928, 0, 8929, 0, 8836, 0, 8837, 0, 8840, 0, 8841, 0, 8930, 0,
+    8931, 0, 8876, 0, 8877, 0, 8878, 0, 8879, 0, 8938, 0, 8939, 0, 8940, 0,
+    8941, 12436, 0, 12364, 0, 12366, 0, 12368, 0, 12370, 0, 12372, 0, 12374,
+    0, 12376, 0, 12378, 0, 12380, 0, 12382, 0, 12384, 0, 12386, 0, 12389, 0,
+    12391, 0, 12393, 0, 12400, 12401, 12403, 12404, 12406, 12407, 12409,
+    12410, 12412, 12413, 12446, 0, 12532, 0, 12460, 0, 12462, 0, 12464, 0,
+    12466, 0, 12468, 0, 12470, 0, 12472, 0, 12474, 0, 12476, 0, 12478, 0,
+    12480, 0, 12482, 0, 12485, 0, 12487, 0, 12489, 0, 12496, 12497, 12499,
+    12500, 12502, 12503, 12505, 12506, 12508, 12509, 12535, 0, 12536, 0,
+    12537, 0, 12538, 0, 12542, 0, 69786, 0, 69788, 0, 69803, 0, 0, 69934, 0,
+    69935, 70475, 70476, 70844, 70843, 70846, 0, 0, 71098, 0, 71099,
+};
+
diff --git a/src/share/native/sun/font/harfbuzz/hb-unicode-private.hh b/src/share/native/sun/font/harfbuzz/hb-unicode-private.hh
new file mode 100644
index 0000000..3e342d4
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-unicode-private.hh
@@ -0,0 +1,370 @@
+/*
+ * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2011  Codethink Limited
+ * Copyright © 2010,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
+ * Codethink Author(s): Ryan Lortie
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_UNICODE_PRIVATE_HH
+#define HB_UNICODE_PRIVATE_HH
+
+#include "hb-private.hh"
+#include "hb-object-private.hh"
+
+
+extern HB_INTERNAL const uint8_t _hb_modified_combining_class[256];
+
+/*
+ * hb_unicode_funcs_t
+ */
+
+#define HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS \
+  HB_UNICODE_FUNC_IMPLEMENT (combining_class) \
+  HB_UNICODE_FUNC_IMPLEMENT (eastasian_width) \
+  HB_UNICODE_FUNC_IMPLEMENT (general_category) \
+  HB_UNICODE_FUNC_IMPLEMENT (mirroring) \
+  HB_UNICODE_FUNC_IMPLEMENT (script) \
+  HB_UNICODE_FUNC_IMPLEMENT (compose) \
+  HB_UNICODE_FUNC_IMPLEMENT (decompose) \
+  HB_UNICODE_FUNC_IMPLEMENT (decompose_compatibility) \
+  /* ^--- Add new callbacks here */
+
+/* Simple callbacks are those taking a hb_codepoint_t and returning a hb_codepoint_t */
+#define HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE \
+  HB_UNICODE_FUNC_IMPLEMENT (hb_unicode_combining_class_t, combining_class) \
+  HB_UNICODE_FUNC_IMPLEMENT (unsigned int, eastasian_width) \
+  HB_UNICODE_FUNC_IMPLEMENT (hb_unicode_general_category_t, general_category) \
+  HB_UNICODE_FUNC_IMPLEMENT (hb_codepoint_t, mirroring) \
+  HB_UNICODE_FUNC_IMPLEMENT (hb_script_t, script) \
+  /* ^--- Add new simple callbacks here */
+
+struct hb_unicode_funcs_t {
+  hb_object_header_t header;
+  ASSERT_POD ();
+
+  hb_unicode_funcs_t *parent;
+
+  bool immutable;
+
+#define HB_UNICODE_FUNC_IMPLEMENT(return_type, name) \
+  inline return_type name (hb_codepoint_t unicode) { return func.name (this, unicode, user_data.name); }
+HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
+#undef HB_UNICODE_FUNC_IMPLEMENT
+
+  inline hb_bool_t compose (hb_codepoint_t a, hb_codepoint_t b,
+                            hb_codepoint_t *ab)
+  {
+    *ab = 0;
+    if (unlikely (!a || !b)) return false;
+    return func.compose (this, a, b, ab, user_data.compose);
+  }
+
+  inline hb_bool_t decompose (hb_codepoint_t ab,
+                              hb_codepoint_t *a, hb_codepoint_t *b)
+  {
+    *a = ab; *b = 0;
+    return func.decompose (this, ab, a, b, user_data.decompose);
+  }
+
+  inline unsigned int decompose_compatibility (hb_codepoint_t  u,
+                                               hb_codepoint_t *decomposed)
+  {
+    unsigned int ret = func.decompose_compatibility (this, u, decomposed, user_data.decompose_compatibility);
+    if (ret == 1 && u == decomposed[0]) {
+      decomposed[0] = 0;
+      return 0;
+    }
+    decomposed[ret] = 0;
+    return ret;
+  }
+
+
+  inline unsigned int
+  modified_combining_class (hb_codepoint_t unicode)
+  {
+    /* XXX This hack belongs to the Myanmar shaper. */
+    if (unlikely (unicode == 0x1037u)) unicode = 0x103Au;
+
+    /* XXX This hack belongs to the SEA shaper (for Tai Tham):
+     * Reorder SAKOT to ensure it comes after any tone marks. */
+    if (unlikely (unicode == 0x1A60u)) return 254;
+
+    /* XXX This hack belongs to the Tibetan shaper:
+     * Reorder PADMA to ensure it comes after any vowel marks. */
+    if (unlikely (unicode == 0x0FC6u)) return 254;
+    /* Reorder TSA -PHRU to reorder before U+0F74 */
+    if (unlikely (unicode == 0x0F39u)) return 127;
+
+    return _hb_modified_combining_class[combining_class (unicode)];
+  }
+
+  static inline hb_bool_t
+  is_variation_selector (hb_codepoint_t unicode)
+  {
+    /* U+180B..180D MONGOLIAN FREE VARIATION SELECTORs are handled in the
+     * Arabic shaper.  No need to match them here. */
+    return unlikely (hb_in_ranges (unicode,
+                                   0xFE00u, 0xFE0Fu, /* VARIATION SELECTOR-1..16 */
+                                   0xE0100u, 0xE01EFu));  /* VARIATION SELECTOR-17..256 */
+  }
+
+  /* Default_Ignorable codepoints:
+   *
+   * Note: While U+115F, U+1160, U+3164 and U+FFA0 are Default_Ignorable,
+   * we do NOT want to hide them, as the way Uniscribe has implemented them
+   * is with regular spacing glyphs, and that's the way fonts are made to work.
+   * As such, we make exceptions for those four.
+   *
+   * Unicode 7.0:
+   * $ grep '; Default_Ignorable_Code_Point ' DerivedCoreProperties.txt | sed 's/;.*#/#/'
+   * 00AD          # Cf       SOFT HYPHEN
+   * 034F          # Mn       COMBINING GRAPHEME JOINER
+   * 061C          # Cf       ARABIC LETTER MARK
+   * 115F..1160    # Lo   [2] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG FILLER
+   * 17B4..17B5    # Mn   [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+   * 180B..180D    # Mn   [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+   * 180E          # Cf       MONGOLIAN VOWEL SEPARATOR
+   * 200B..200F    # Cf   [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK
+   * 202A..202E    # Cf   [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
+   * 2060..2064    # Cf   [5] WORD JOINER..INVISIBLE PLUS
+   * 2065          # Cn       <reserved-2065>
+   * 2066..206F    # Cf  [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES
+   * 3164          # Lo       HANGUL FILLER
+   * FE00..FE0F    # Mn  [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+   * FEFF          # Cf       ZERO WIDTH NO-BREAK SPACE
+   * FFA0          # Lo       HALFWIDTH HANGUL FILLER
+   * FFF0..FFF8    # Cn   [9] <reserved-FFF0>..<reserved-FFF8>
+   * 1BCA0..1BCA3  # Cf   [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP
+   * 1D173..1D17A  # Cf   [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
+   * E0000         # Cn       <reserved-E0000>
+   * E0001         # Cf       LANGUAGE TAG
+   * E0002..E001F  # Cn  [30] <reserved-E0002>..<reserved-E001F>
+   * E0020..E007F  # Cf  [96] TAG SPACE..CANCEL TAG
+   * E0080..E00FF  # Cn [128] <reserved-E0080>..<reserved-E00FF>
+   * E0100..E01EF  # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
+   * E01F0..E0FFF  # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
+   */
+  static inline hb_bool_t
+  is_default_ignorable (hb_codepoint_t ch)
+  {
+    hb_codepoint_t plane = ch >> 16;
+    if (likely (plane == 0))
+    {
+      /* BMP */
+      hb_codepoint_t page = ch >> 8;
+      switch (page) {
+        case 0x00: return unlikely (ch == 0x00ADu);
+        case 0x03: return unlikely (ch == 0x034Fu);
+        case 0x06: return unlikely (ch == 0x061Cu);
+        case 0x17: return hb_in_range (ch, 0x17B4u, 0x17B5u);
+        case 0x18: return hb_in_range (ch, 0x180Bu, 0x180Eu);
+        case 0x20: return hb_in_ranges (ch, 0x200Bu, 0x200Fu,
+                                            0x202Au, 0x202Eu,
+                                            0x2060u, 0x206Fu);
+        case 0xFE: return hb_in_range (ch, 0xFE00u, 0xFE0Fu) || ch == 0xFEFFu;
+        case 0xFF: return hb_in_range (ch, 0xFFF0u, 0xFFF8u);
+        default: return false;
+      }
+    }
+    else
+    {
+      /* Other planes */
+      switch (plane) {
+        case 0x01: return hb_in_ranges (ch, 0x1BCA0u, 0x1BCA3u,
+                                            0x1D173u, 0x1D17Au);
+        case 0x0E: return hb_in_range (ch, 0xE0000u, 0xE0FFFu);
+        default: return false;
+      }
+    }
+  }
+
+  /* Space estimates based on:
+   * http://www.unicode.org/charts/PDF/U2000.pdf
+   * https://www.microsoft.com/typography/developers/fdsspec/spaces.aspx
+   */
+  enum space_t {
+    NOT_SPACE = 0,
+    SPACE_EM   = 1,
+    SPACE_EM_2 = 2,
+    SPACE_EM_3 = 3,
+    SPACE_EM_4 = 4,
+    SPACE_EM_5 = 5,
+    SPACE_EM_6 = 6,
+    SPACE_EM_16 = 16,
+    SPACE_4_EM_18,      /* 4/18th of an EM! */
+    SPACE,
+    SPACE_FIGURE,
+    SPACE_PUNCTUATION,
+    SPACE_NARROW,
+  };
+  static inline space_t
+  space_fallback_type (hb_codepoint_t u)
+  {
+    switch (u)
+    {
+      /* All GC=Zs chars that can use a fallback. */
+      default:      return NOT_SPACE;   /* U+1680 OGHAM SPACE MARK */
+      case 0x0020u: return SPACE;       /* U+0020 SPACE */
+      case 0x00A0u: return SPACE;       /* U+00A0 NO-BREAK SPACE */
+      case 0x2000u: return SPACE_EM_2;  /* U+2000 EN QUAD */
+      case 0x2001u: return SPACE_EM;    /* U+2001 EM QUAD */
+      case 0x2002u: return SPACE_EM_2;  /* U+2002 EN SPACE */
+      case 0x2003u: return SPACE_EM;    /* U+2003 EM SPACE */
+      case 0x2004u: return SPACE_EM_3;  /* U+2004 THREE-PER-EM SPACE */
+      case 0x2005u: return SPACE_EM_4;  /* U+2005 FOUR-PER-EM SPACE */
+      case 0x2006u: return SPACE_EM_6;  /* U+2006 SIX-PER-EM SPACE */
+      case 0x2007u: return SPACE_FIGURE;        /* U+2007 FIGURE SPACE */
+      case 0x2008u: return SPACE_PUNCTUATION;   /* U+2008 PUNCTUATION SPACE */
+      case 0x2009u: return SPACE_EM_5;          /* U+2009 THIN SPACE */
+      case 0x200Au: return SPACE_EM_16;         /* U+200A HAIR SPACE */
+      case 0x202Fu: return SPACE_NARROW;        /* U+202F NARROW NO-BREAK SPACE */
+      case 0x205Fu: return SPACE_4_EM_18;       /* U+205F MEDIUM MATHEMATICAL SPACE */
+      case 0x3000u: return SPACE_EM;            /* U+3000 IDEOGRAPHIC SPACE */
+    }
+  }
+
+  struct {
+#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_func_t name;
+    HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_UNICODE_FUNC_IMPLEMENT
+  } func;
+
+  struct {
+#define HB_UNICODE_FUNC_IMPLEMENT(name) void *name;
+    HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_UNICODE_FUNC_IMPLEMENT
+  } user_data;
+
+  struct {
+#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
+    HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_UNICODE_FUNC_IMPLEMENT
+  } destroy;
+};
+
+
+extern HB_INTERNAL const hb_unicode_funcs_t _hb_unicode_funcs_nil;
+
+
+/* Modified combining marks */
+
+/* Hebrew
+ *
+ * We permute the "fixed-position" classes 10-26 into the order
+ * described in the SBL Hebrew manual:
+ *
+ * http://www.sbl-site.org/Fonts/SBLHebrewUserManual1.5x.pdf
+ *
+ * (as recommended by:
+ *  http://forum.fontlab.com/archive-old-microsoft-volt-group/vista-and-diacritic-ordering-t6751.0.html)
+ *
+ * More details here:
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=662055
+ */
+#define HB_MODIFIED_COMBINING_CLASS_CCC10 22 /* sheva */
+#define HB_MODIFIED_COMBINING_CLASS_CCC11 15 /* hataf segol */
+#define HB_MODIFIED_COMBINING_CLASS_CCC12 16 /* hataf patah */
+#define HB_MODIFIED_COMBINING_CLASS_CCC13 17 /* hataf qamats */
+#define HB_MODIFIED_COMBINING_CLASS_CCC14 23 /* hiriq */
+#define HB_MODIFIED_COMBINING_CLASS_CCC15 18 /* tsere */
+#define HB_MODIFIED_COMBINING_CLASS_CCC16 19 /* segol */
+#define HB_MODIFIED_COMBINING_CLASS_CCC17 20 /* patah */
+#define HB_MODIFIED_COMBINING_CLASS_CCC18 21 /* qamats */
+#define HB_MODIFIED_COMBINING_CLASS_CCC19 14 /* holam */
+#define HB_MODIFIED_COMBINING_CLASS_CCC20 24 /* qubuts */
+#define HB_MODIFIED_COMBINING_CLASS_CCC21 12 /* dagesh */
+#define HB_MODIFIED_COMBINING_CLASS_CCC22 25 /* meteg */
+#define HB_MODIFIED_COMBINING_CLASS_CCC23 13 /* rafe */
+#define HB_MODIFIED_COMBINING_CLASS_CCC24 10 /* shin dot */
+#define HB_MODIFIED_COMBINING_CLASS_CCC25 11 /* sin dot */
+#define HB_MODIFIED_COMBINING_CLASS_CCC26 26 /* point varika */
+
+/*
+ * Arabic
+ *
+ * Modify to move Shadda (ccc=33) before other marks.  See:
+ * http://unicode.org/faq/normalization.html#8
+ * http://unicode.org/faq/normalization.html#9
+ */
+#define HB_MODIFIED_COMBINING_CLASS_CCC27 28 /* fathatan */
+#define HB_MODIFIED_COMBINING_CLASS_CCC28 29 /* dammatan */
+#define HB_MODIFIED_COMBINING_CLASS_CCC29 30 /* kasratan */
+#define HB_MODIFIED_COMBINING_CLASS_CCC30 31 /* fatha */
+#define HB_MODIFIED_COMBINING_CLASS_CCC31 32 /* damma */
+#define HB_MODIFIED_COMBINING_CLASS_CCC32 33 /* kasra */
+#define HB_MODIFIED_COMBINING_CLASS_CCC33 27 /* shadda */
+#define HB_MODIFIED_COMBINING_CLASS_CCC34 34 /* sukun */
+#define HB_MODIFIED_COMBINING_CLASS_CCC35 35 /* superscript alef */
+
+/* Syriac */
+#define HB_MODIFIED_COMBINING_CLASS_CCC36 36 /* superscript alaph */
+
+/* Telugu
+ *
+ * Modify Telugu length marks (ccc=84, ccc=91).
+ * These are the only matras in the main Indic scripts range that have
+ * a non-zero ccc.  That makes them reorder with the Halant that is
+ * ccc=9.  Just zero them, we don't need them in our Indic shaper.
+ */
+#define HB_MODIFIED_COMBINING_CLASS_CCC84 0 /* length mark */
+#define HB_MODIFIED_COMBINING_CLASS_CCC91 0 /* ai length mark */
+
+/* Thai
+ *
+ * Modify U+0E38 and U+0E39 (ccc=103) to be reordered before U+0E3A (ccc=9).
+ * Assign 3, which is unassigned otherwise.
+ * Uniscribe does this reordering too.
+ */
+#define HB_MODIFIED_COMBINING_CLASS_CCC103 3 /* sara u / sara uu */
+#define HB_MODIFIED_COMBINING_CLASS_CCC107 107 /* mai * */
+
+/* Lao */
+#define HB_MODIFIED_COMBINING_CLASS_CCC118 118 /* sign u / sign uu */
+#define HB_MODIFIED_COMBINING_CLASS_CCC122 122 /* mai * */
+
+/* Tibetan
+ * Modify U+0F74 (ccc=132) to reorder before ccc=130 marks.
+ */
+#define HB_MODIFIED_COMBINING_CLASS_CCC129 129 /* sign aa */
+#define HB_MODIFIED_COMBINING_CLASS_CCC130 130 /* sign i */
+#define HB_MODIFIED_COMBINING_CLASS_CCC132 128 /* sign u */
+
+
+/* Misc */
+
+#define HB_UNICODE_GENERAL_CATEGORY_IS_MARK(gen_cat) \
+        (FLAG_SAFE (gen_cat) & \
+         (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
+          FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
+          FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
+
+#define HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL(gen_cat) \
+        (FLAG_SAFE (gen_cat) & \
+         (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
+          FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | \
+          FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL)))
+
+#endif /* HB_UNICODE_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-unicode.cpp b/src/share/native/sun/font/harfbuzz/hb-unicode.cpp
new file mode 100644
index 0000000..81a474e
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-unicode.cpp
@@ -0,0 +1,563 @@
+/*
+ * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2011  Codethink Limited
+ * Copyright © 2010,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
+ * Codethink Author(s): Ryan Lortie
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-private.hh"
+
+#include "hb-unicode-private.hh"
+
+
+
+/*
+ * hb_unicode_funcs_t
+ */
+
+static hb_unicode_combining_class_t
+hb_unicode_combining_class_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
+                                hb_codepoint_t      unicode   HB_UNUSED,
+                                void               *user_data HB_UNUSED)
+{
+  return HB_UNICODE_COMBINING_CLASS_NOT_REORDERED;
+}
+
+static unsigned int
+hb_unicode_eastasian_width_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
+                                hb_codepoint_t      unicode   HB_UNUSED,
+                                void               *user_data HB_UNUSED)
+{
+  return 1;
+}
+
+static hb_unicode_general_category_t
+hb_unicode_general_category_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
+                                 hb_codepoint_t      unicode   HB_UNUSED,
+                                 void               *user_data HB_UNUSED)
+{
+  return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;
+}
+
+static hb_codepoint_t
+hb_unicode_mirroring_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
+                          hb_codepoint_t      unicode   HB_UNUSED,
+                          void               *user_data HB_UNUSED)
+{
+  return unicode;
+}
+
+static hb_script_t
+hb_unicode_script_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
+                       hb_codepoint_t      unicode   HB_UNUSED,
+                       void               *user_data HB_UNUSED)
+{
+  return HB_SCRIPT_UNKNOWN;
+}
+
+static hb_bool_t
+hb_unicode_compose_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
+                        hb_codepoint_t      a         HB_UNUSED,
+                        hb_codepoint_t      b         HB_UNUSED,
+                        hb_codepoint_t     *ab        HB_UNUSED,
+                        void               *user_data HB_UNUSED)
+{
+  return false;
+}
+
+static hb_bool_t
+hb_unicode_decompose_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
+                          hb_codepoint_t      ab        HB_UNUSED,
+                          hb_codepoint_t     *a         HB_UNUSED,
+                          hb_codepoint_t     *b         HB_UNUSED,
+                          void               *user_data HB_UNUSED)
+{
+  return false;
+}
+
+
+static unsigned int
+hb_unicode_decompose_compatibility_nil (hb_unicode_funcs_t *ufuncs     HB_UNUSED,
+                                        hb_codepoint_t      u          HB_UNUSED,
+                                        hb_codepoint_t     *decomposed HB_UNUSED,
+                                        void               *user_data  HB_UNUSED)
+{
+  return 0;
+}
+
+
+#define HB_UNICODE_FUNCS_IMPLEMENT_SET \
+  HB_UNICODE_FUNCS_IMPLEMENT (glib) \
+  HB_UNICODE_FUNCS_IMPLEMENT (icu) \
+  HB_UNICODE_FUNCS_IMPLEMENT (ucdn) \
+  HB_UNICODE_FUNCS_IMPLEMENT (nil) \
+  /* ^--- Add new callbacks before nil */
+
+#define hb_nil_get_unicode_funcs hb_unicode_funcs_get_empty
+
+/* Prototype them all */
+#define HB_UNICODE_FUNCS_IMPLEMENT(set) \
+extern "C" hb_unicode_funcs_t *hb_##set##_get_unicode_funcs (void);
+HB_UNICODE_FUNCS_IMPLEMENT_SET
+#undef HB_UNICODE_FUNCS_IMPLEMENT
+
+
+hb_unicode_funcs_t *
+hb_unicode_funcs_get_default (void)
+{
+#define HB_UNICODE_FUNCS_IMPLEMENT(set) \
+  return hb_##set##_get_unicode_funcs ();
+
+#ifdef HAVE_GLIB
+  HB_UNICODE_FUNCS_IMPLEMENT(glib)
+#elif defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN)
+  HB_UNICODE_FUNCS_IMPLEMENT(icu)
+#elif defined(HAVE_UCDN)
+  HB_UNICODE_FUNCS_IMPLEMENT(ucdn)
+#else
+#define HB_UNICODE_FUNCS_NIL 1
+  HB_UNICODE_FUNCS_IMPLEMENT(nil)
+#endif
+
+#undef HB_UNICODE_FUNCS_IMPLEMENT
+}
+
+#if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL)
+#error "Could not find any Unicode functions implementation, you have to provide your own"
+#error "Consider building hb-ucdn.c.  If you absolutely want to build without any, check the code."
+#endif
+
+/**
+ * hb_unicode_funcs_create: (Xconstructor)
+ * @parent: (nullable):
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.2
+ **/
+hb_unicode_funcs_t *
+hb_unicode_funcs_create (hb_unicode_funcs_t *parent)
+{
+  hb_unicode_funcs_t *ufuncs;
+
+  if (!(ufuncs = hb_object_create<hb_unicode_funcs_t> ()))
+    return hb_unicode_funcs_get_empty ();
+
+  if (!parent)
+    parent = hb_unicode_funcs_get_empty ();
+
+  hb_unicode_funcs_make_immutable (parent);
+  ufuncs->parent = hb_unicode_funcs_reference (parent);
+
+  ufuncs->func = parent->func;
+
+  /* We can safely copy user_data from parent since we hold a reference
+   * onto it and it's immutable.  We should not copy the destroy notifiers
+   * though. */
+  ufuncs->user_data = parent->user_data;
+
+  return ufuncs;
+}
+
+
+const hb_unicode_funcs_t _hb_unicode_funcs_nil = {
+  HB_OBJECT_HEADER_STATIC,
+
+  NULL, /* parent */
+  true, /* immutable */
+  {
+#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_nil,
+    HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_UNICODE_FUNC_IMPLEMENT
+  }
+};
+
+/**
+ * hb_unicode_funcs_get_empty:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.2
+ **/
+hb_unicode_funcs_t *
+hb_unicode_funcs_get_empty (void)
+{
+  return const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil);
+}
+
+/**
+ * hb_unicode_funcs_reference: (skip)
+ * @ufuncs: Unicode functions.
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.2
+ **/
+hb_unicode_funcs_t *
+hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs)
+{
+  return hb_object_reference (ufuncs);
+}
+
+/**
+ * hb_unicode_funcs_destroy: (skip)
+ * @ufuncs: Unicode functions.
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
+{
+  if (!hb_object_destroy (ufuncs)) return;
+
+#define HB_UNICODE_FUNC_IMPLEMENT(name) \
+  if (ufuncs->destroy.name) ufuncs->destroy.name (ufuncs->user_data.name);
+    HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_UNICODE_FUNC_IMPLEMENT
+
+  hb_unicode_funcs_destroy (ufuncs->parent);
+
+  free (ufuncs);
+}
+
+/**
+ * hb_unicode_funcs_set_user_data: (skip)
+ * @ufuncs: Unicode functions.
+ * @key:
+ * @data:
+ * @destroy:
+ * @replace:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
+                                hb_user_data_key_t *key,
+                                void *              data,
+                                hb_destroy_func_t   destroy,
+                                hb_bool_t           replace)
+{
+  return hb_object_set_user_data (ufuncs, key, data, destroy, replace);
+}
+
+/**
+ * hb_unicode_funcs_get_user_data: (skip)
+ * @ufuncs: Unicode functions.
+ * @key:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.2
+ **/
+void *
+hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
+                                hb_user_data_key_t *key)
+{
+  return hb_object_get_user_data (ufuncs, key);
+}
+
+
+/**
+ * hb_unicode_funcs_make_immutable:
+ * @ufuncs: Unicode functions.
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+void
+hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
+{
+  if (unlikely (hb_object_is_inert (ufuncs)))
+    return;
+
+  ufuncs->immutable = true;
+}
+
+/**
+ * hb_unicode_funcs_is_immutable:
+ * @ufuncs: Unicode functions.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs)
+{
+  return ufuncs->immutable;
+}
+
+/**
+ * hb_unicode_funcs_get_parent:
+ * @ufuncs: Unicode functions.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_unicode_funcs_t *
+hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs)
+{
+  return ufuncs->parent ? ufuncs->parent : hb_unicode_funcs_get_empty ();
+}
+
+
+#define HB_UNICODE_FUNC_IMPLEMENT(name)                                         \
+                                                                                \
+void                                                                            \
+hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t             *ufuncs,     \
+                                    hb_unicode_##name##_func_t      func,       \
+                                    void                           *user_data,  \
+                                    hb_destroy_func_t               destroy)    \
+{                                                                               \
+  if (ufuncs->immutable)                                                        \
+    return;                                                                     \
+                                                                                \
+  if (ufuncs->destroy.name)                                                     \
+    ufuncs->destroy.name (ufuncs->user_data.name);                              \
+                                                                                \
+  if (func) {                                                                   \
+    ufuncs->func.name = func;                                                   \
+    ufuncs->user_data.name = user_data;                                         \
+    ufuncs->destroy.name = destroy;                                             \
+  } else {                                                                      \
+    ufuncs->func.name = ufuncs->parent->func.name;                              \
+    ufuncs->user_data.name = ufuncs->parent->user_data.name;                    \
+    ufuncs->destroy.name = NULL;                                                \
+  }                                                                             \
+}
+
+HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_UNICODE_FUNC_IMPLEMENT
+
+
+#define HB_UNICODE_FUNC_IMPLEMENT(return_type, name)                            \
+                                                                                \
+return_type                                                                     \
+hb_unicode_##name (hb_unicode_funcs_t *ufuncs,                                  \
+                   hb_codepoint_t      unicode)                                 \
+{                                                                               \
+  return ufuncs->name (unicode);                                                \
+}
+HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
+#undef HB_UNICODE_FUNC_IMPLEMENT
+
+/**
+ * hb_unicode_compose:
+ * @ufuncs: Unicode functions.
+ * @a:
+ * @b:
+ * @ab: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
+                    hb_codepoint_t      a,
+                    hb_codepoint_t      b,
+                    hb_codepoint_t     *ab)
+{
+  return ufuncs->compose (a, b, ab);
+}
+
+/**
+ * hb_unicode_decompose:
+ * @ufuncs: Unicode functions.
+ * @ab:
+ * @a: (out):
+ * @b: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+hb_bool_t
+hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
+                      hb_codepoint_t      ab,
+                      hb_codepoint_t     *a,
+                      hb_codepoint_t     *b)
+{
+  return ufuncs->decompose (ab, a, b);
+}
+
+/**
+ * hb_unicode_decompose_compatibility:
+ * @ufuncs: Unicode functions.
+ * @u:
+ * @decomposed: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+unsigned int
+hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
+                                    hb_codepoint_t      u,
+                                    hb_codepoint_t     *decomposed)
+{
+  return ufuncs->decompose_compatibility (u, decomposed);
+}
+
+
+/* See hb-unicode-private.hh for details. */
+const uint8_t
+_hb_modified_combining_class[256] =
+{
+  0, /* HB_UNICODE_COMBINING_CLASS_NOT_REORDERED */
+  1, /* HB_UNICODE_COMBINING_CLASS_OVERLAY */
+  2, 3, 4, 5, 6,
+  7, /* HB_UNICODE_COMBINING_CLASS_NUKTA */
+  8, /* HB_UNICODE_COMBINING_CLASS_KANA_VOICING */
+  9, /* HB_UNICODE_COMBINING_CLASS_VIRAMA */
+
+  /* Hebrew */
+  HB_MODIFIED_COMBINING_CLASS_CCC10,
+  HB_MODIFIED_COMBINING_CLASS_CCC11,
+  HB_MODIFIED_COMBINING_CLASS_CCC12,
+  HB_MODIFIED_COMBINING_CLASS_CCC13,
+  HB_MODIFIED_COMBINING_CLASS_CCC14,
+  HB_MODIFIED_COMBINING_CLASS_CCC15,
+  HB_MODIFIED_COMBINING_CLASS_CCC16,
+  HB_MODIFIED_COMBINING_CLASS_CCC17,
+  HB_MODIFIED_COMBINING_CLASS_CCC18,
+  HB_MODIFIED_COMBINING_CLASS_CCC19,
+  HB_MODIFIED_COMBINING_CLASS_CCC20,
+  HB_MODIFIED_COMBINING_CLASS_CCC21,
+  HB_MODIFIED_COMBINING_CLASS_CCC22,
+  HB_MODIFIED_COMBINING_CLASS_CCC23,
+  HB_MODIFIED_COMBINING_CLASS_CCC24,
+  HB_MODIFIED_COMBINING_CLASS_CCC25,
+  HB_MODIFIED_COMBINING_CLASS_CCC26,
+
+  /* Arabic */
+  HB_MODIFIED_COMBINING_CLASS_CCC27,
+  HB_MODIFIED_COMBINING_CLASS_CCC28,
+  HB_MODIFIED_COMBINING_CLASS_CCC29,
+  HB_MODIFIED_COMBINING_CLASS_CCC30,
+  HB_MODIFIED_COMBINING_CLASS_CCC31,
+  HB_MODIFIED_COMBINING_CLASS_CCC32,
+  HB_MODIFIED_COMBINING_CLASS_CCC33,
+  HB_MODIFIED_COMBINING_CLASS_CCC34,
+  HB_MODIFIED_COMBINING_CLASS_CCC35,
+
+  /* Syriac */
+  HB_MODIFIED_COMBINING_CLASS_CCC36,
+
+  37, 38, 39,
+  40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+  60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+  80, 81, 82, 83,
+
+  /* Telugu */
+  HB_MODIFIED_COMBINING_CLASS_CCC84,
+  85, 86, 87, 88, 89, 90,
+  HB_MODIFIED_COMBINING_CLASS_CCC91,
+  92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
+
+  /* Thai */
+  HB_MODIFIED_COMBINING_CLASS_CCC103,
+  104, 105, 106,
+  HB_MODIFIED_COMBINING_CLASS_CCC107,
+  108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+
+  /* Lao */
+  HB_MODIFIED_COMBINING_CLASS_CCC118,
+  119, 120, 121,
+  HB_MODIFIED_COMBINING_CLASS_CCC122,
+  123, 124, 125, 126, 127, 128,
+
+  /* Tibetan */
+  HB_MODIFIED_COMBINING_CLASS_CCC129,
+  HB_MODIFIED_COMBINING_CLASS_CCC130,
+  131,
+  HB_MODIFIED_COMBINING_CLASS_CCC132,
+  133, 134, 135, 136, 137, 138, 139,
+
+
+  140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+  150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+  160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
+  170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+  180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
+  190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+
+  200, /* HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT */
+  201,
+  202, /* HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW */
+  203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213,
+  214, /* HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE */
+  215,
+  216, /* HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT */
+  217,
+  218, /* HB_UNICODE_COMBINING_CLASS_BELOW_LEFT */
+  219,
+  220, /* HB_UNICODE_COMBINING_CLASS_BELOW */
+  221,
+  222, /* HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT */
+  223,
+  224, /* HB_UNICODE_COMBINING_CLASS_LEFT */
+  225,
+  226, /* HB_UNICODE_COMBINING_CLASS_RIGHT */
+  227,
+  228, /* HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT */
+  229,
+  230, /* HB_UNICODE_COMBINING_CLASS_ABOVE */
+  231,
+  232, /* HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT */
+  233, /* HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW */
+  234, /* HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE */
+  235, 236, 237, 238, 239,
+  240, /* HB_UNICODE_COMBINING_CLASS_IOTA_SUBSCRIPT */
+  241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
+  255, /* HB_UNICODE_COMBINING_CLASS_INVALID */
+};
diff --git a/src/share/native/sun/font/harfbuzz/hb-unicode.h b/src/share/native/sun/font/harfbuzz/hb-unicode.h
new file mode 100644
index 0000000..99b2986
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-unicode.h
@@ -0,0 +1,471 @@
+/*
+ * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2011  Codethink Limited
+ * 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
+ * Codethink Author(s): Ryan Lortie
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_UNICODE_H
+#define HB_UNICODE_H
+
+#include "hb-common.h"
+
+HB_BEGIN_DECLS
+
+
+/* hb_unicode_general_category_t */
+
+/* Unicode Character Database property: General_Category (gc) */
+typedef enum
+{
+  HB_UNICODE_GENERAL_CATEGORY_CONTROL,                  /* Cc */
+  HB_UNICODE_GENERAL_CATEGORY_FORMAT,                   /* Cf */
+  HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED,               /* Cn */
+  HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE,              /* Co */
+  HB_UNICODE_GENERAL_CATEGORY_SURROGATE,                /* Cs */
+  HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER,         /* Ll */
+  HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER,          /* Lm */
+  HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER,             /* Lo */
+  HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER,         /* Lt */
+  HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER,         /* Lu */
+  HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK,             /* Mc */
+  HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK,           /* Me */
+  HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK,         /* Mn */
+  HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER,           /* Nd */
+  HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER,            /* Nl */
+  HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER,             /* No */
+  HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION,      /* Pc */
+  HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION,         /* Pd */
+  HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION,        /* Pe */
+  HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION,        /* Pf */
+  HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION,      /* Pi */
+  HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION,        /* Po */
+  HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION,         /* Ps */
+  HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL,          /* Sc */
+  HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL,          /* Sk */
+  HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL,              /* Sm */
+  HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL,             /* So */
+  HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR,           /* Zl */
+  HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR,      /* Zp */
+  HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR           /* Zs */
+} hb_unicode_general_category_t;
+
+/* hb_unicode_combining_class_t */
+
+/* Note: newer versions of Unicode may add new values.  Clients should be ready to handle
+ * any value in the 0..254 range being returned from hb_unicode_combining_class().
+ */
+
+/* Unicode Character Database property: Canonical_Combining_Class (ccc) */
+typedef enum
+{
+  HB_UNICODE_COMBINING_CLASS_NOT_REORDERED      = 0,
+  HB_UNICODE_COMBINING_CLASS_OVERLAY            = 1,
+  HB_UNICODE_COMBINING_CLASS_NUKTA              = 7,
+  HB_UNICODE_COMBINING_CLASS_KANA_VOICING       = 8,
+  HB_UNICODE_COMBINING_CLASS_VIRAMA             = 9,
+
+  /* Hebrew */
+  HB_UNICODE_COMBINING_CLASS_CCC10      =  10,
+  HB_UNICODE_COMBINING_CLASS_CCC11      =  11,
+  HB_UNICODE_COMBINING_CLASS_CCC12      =  12,
+  HB_UNICODE_COMBINING_CLASS_CCC13      =  13,
+  HB_UNICODE_COMBINING_CLASS_CCC14      =  14,
+  HB_UNICODE_COMBINING_CLASS_CCC15      =  15,
+  HB_UNICODE_COMBINING_CLASS_CCC16      =  16,
+  HB_UNICODE_COMBINING_CLASS_CCC17      =  17,
+  HB_UNICODE_COMBINING_CLASS_CCC18      =  18,
+  HB_UNICODE_COMBINING_CLASS_CCC19      =  19,
+  HB_UNICODE_COMBINING_CLASS_CCC20      =  20,
+  HB_UNICODE_COMBINING_CLASS_CCC21      =  21,
+  HB_UNICODE_COMBINING_CLASS_CCC22      =  22,
+  HB_UNICODE_COMBINING_CLASS_CCC23      =  23,
+  HB_UNICODE_COMBINING_CLASS_CCC24      =  24,
+  HB_UNICODE_COMBINING_CLASS_CCC25      =  25,
+  HB_UNICODE_COMBINING_CLASS_CCC26      =  26,
+
+  /* Arabic */
+  HB_UNICODE_COMBINING_CLASS_CCC27      =  27,
+  HB_UNICODE_COMBINING_CLASS_CCC28      =  28,
+  HB_UNICODE_COMBINING_CLASS_CCC29      =  29,
+  HB_UNICODE_COMBINING_CLASS_CCC30      =  30,
+  HB_UNICODE_COMBINING_CLASS_CCC31      =  31,
+  HB_UNICODE_COMBINING_CLASS_CCC32      =  32,
+  HB_UNICODE_COMBINING_CLASS_CCC33      =  33,
+  HB_UNICODE_COMBINING_CLASS_CCC34      =  34,
+  HB_UNICODE_COMBINING_CLASS_CCC35      =  35,
+
+  /* Syriac */
+  HB_UNICODE_COMBINING_CLASS_CCC36      =  36,
+
+  /* Telugu */
+  HB_UNICODE_COMBINING_CLASS_CCC84      =  84,
+  HB_UNICODE_COMBINING_CLASS_CCC91      =  91,
+
+  /* Thai */
+  HB_UNICODE_COMBINING_CLASS_CCC103     = 103,
+  HB_UNICODE_COMBINING_CLASS_CCC107     = 107,
+
+  /* Lao */
+  HB_UNICODE_COMBINING_CLASS_CCC118     = 118,
+  HB_UNICODE_COMBINING_CLASS_CCC122     = 122,
+
+  /* Tibetan */
+  HB_UNICODE_COMBINING_CLASS_CCC129     = 129,
+  HB_UNICODE_COMBINING_CLASS_CCC130     = 130,
+  HB_UNICODE_COMBINING_CLASS_CCC133     = 132,
+
+
+  HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT        = 200,
+  HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW             = 202,
+  HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE             = 214,
+  HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT       = 216,
+  HB_UNICODE_COMBINING_CLASS_BELOW_LEFT                 = 218,
+  HB_UNICODE_COMBINING_CLASS_BELOW                      = 220,
+  HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT                = 222,
+  HB_UNICODE_COMBINING_CLASS_LEFT                       = 224,
+  HB_UNICODE_COMBINING_CLASS_RIGHT                      = 226,
+  HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT                 = 228,
+  HB_UNICODE_COMBINING_CLASS_ABOVE                      = 230,
+  HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT                = 232,
+  HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW               = 233,
+  HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE               = 234,
+
+  HB_UNICODE_COMBINING_CLASS_IOTA_SUBSCRIPT             = 240,
+
+  HB_UNICODE_COMBINING_CLASS_INVALID    = 255
+} hb_unicode_combining_class_t;
+
+
+/*
+ * hb_unicode_funcs_t
+ */
+
+typedef struct hb_unicode_funcs_t hb_unicode_funcs_t;
+
+
+/*
+ * just give me the best implementation you've got there.
+ */
+HB_EXTERN hb_unicode_funcs_t *
+hb_unicode_funcs_get_default (void);
+
+
+HB_EXTERN hb_unicode_funcs_t *
+hb_unicode_funcs_create (hb_unicode_funcs_t *parent);
+
+HB_EXTERN hb_unicode_funcs_t *
+hb_unicode_funcs_get_empty (void);
+
+HB_EXTERN hb_unicode_funcs_t *
+hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs);
+
+HB_EXTERN void
+hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs);
+
+HB_EXTERN hb_bool_t
+hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
+                                hb_user_data_key_t *key,
+                                void *              data,
+                                hb_destroy_func_t   destroy,
+                                hb_bool_t           replace);
+
+
+HB_EXTERN void *
+hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
+                                hb_user_data_key_t *key);
+
+
+HB_EXTERN void
+hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs);
+
+HB_EXTERN hb_bool_t
+hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs);
+
+HB_EXTERN hb_unicode_funcs_t *
+hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs);
+
+
+/*
+ * funcs
+ */
+
+/* typedefs */
+
+typedef hb_unicode_combining_class_t    (*hb_unicode_combining_class_func_t)    (hb_unicode_funcs_t *ufuncs,
+                                                                                 hb_codepoint_t      unicode,
+                                                                                 void               *user_data);
+typedef unsigned int                    (*hb_unicode_eastasian_width_func_t)    (hb_unicode_funcs_t *ufuncs,
+                                                                                 hb_codepoint_t      unicode,
+                                                                                 void               *user_data);
+typedef hb_unicode_general_category_t   (*hb_unicode_general_category_func_t)   (hb_unicode_funcs_t *ufuncs,
+                                                                                 hb_codepoint_t      unicode,
+                                                                                 void               *user_data);
+typedef hb_codepoint_t                  (*hb_unicode_mirroring_func_t)          (hb_unicode_funcs_t *ufuncs,
+                                                                                 hb_codepoint_t      unicode,
+                                                                                 void               *user_data);
+typedef hb_script_t                     (*hb_unicode_script_func_t)             (hb_unicode_funcs_t *ufuncs,
+                                                                                 hb_codepoint_t      unicode,
+                                                                                 void               *user_data);
+
+typedef hb_bool_t                       (*hb_unicode_compose_func_t)            (hb_unicode_funcs_t *ufuncs,
+                                                                                 hb_codepoint_t      a,
+                                                                                 hb_codepoint_t      b,
+                                                                                 hb_codepoint_t     *ab,
+                                                                                 void               *user_data);
+typedef hb_bool_t                       (*hb_unicode_decompose_func_t)          (hb_unicode_funcs_t *ufuncs,
+                                                                                 hb_codepoint_t      ab,
+                                                                                 hb_codepoint_t     *a,
+                                                                                 hb_codepoint_t     *b,
+                                                                                 void               *user_data);
+
+/**
+ * hb_unicode_decompose_compatibility_func_t:
+ * @ufuncs: a Unicode function structure
+ * @u: codepoint to decompose
+ * @decomposed: address of codepoint array (of length %HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into
+ * @user_data: user data pointer as passed to hb_unicode_funcs_set_decompose_compatibility_func()
+ *
+ * Fully decompose @u to its Unicode compatibility decomposition. The codepoints of the decomposition will be written to @decomposed.
+ * The complete length of the decomposition will be returned.
+ *
+ * If @u has no compatibility decomposition, zero should be returned.
+ *
+ * The Unicode standard guarantees that a buffer of length %HB_UNICODE_MAX_DECOMPOSITION_LEN codepoints will always be sufficient for any
+ * compatibility decomposition plus an terminating value of 0.  Consequently, @decompose must be allocated by the caller to be at least this length.  Implementations
+ * of this function type must ensure that they do not write past the provided array.
+ *
+ * Return value: number of codepoints in the full compatibility decomposition of @u, or 0 if no decomposition available.
+ */
+typedef unsigned int                    (*hb_unicode_decompose_compatibility_func_t)    (hb_unicode_funcs_t *ufuncs,
+                                                                                         hb_codepoint_t      u,
+                                                                                         hb_codepoint_t     *decomposed,
+                                                                                         void               *user_data);
+
+/* See Unicode 6.1 for details on the maximum decomposition length. */
+#define HB_UNICODE_MAX_DECOMPOSITION_LEN (18+1) /* codepoints */
+
+/* setters */
+
+/**
+ * hb_unicode_funcs_set_combining_class_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
+                                           hb_unicode_combining_class_func_t func,
+                                           void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_unicode_funcs_set_eastasian_width_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
+                                           hb_unicode_eastasian_width_func_t func,
+                                           void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_unicode_funcs_set_general_category_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
+                                            hb_unicode_general_category_func_t func,
+                                            void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_unicode_funcs_set_mirroring_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
+                                     hb_unicode_mirroring_func_t func,
+                                     void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_unicode_funcs_set_script_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
+                                  hb_unicode_script_func_t func,
+                                  void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_unicode_funcs_set_compose_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_unicode_funcs_set_compose_func (hb_unicode_funcs_t *ufuncs,
+                                   hb_unicode_compose_func_t func,
+                                   void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_unicode_funcs_set_decompose_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_unicode_funcs_set_decompose_func (hb_unicode_funcs_t *ufuncs,
+                                     hb_unicode_decompose_func_t func,
+                                     void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_unicode_funcs_set_decompose_compatibility_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs,
+                                                   hb_unicode_decompose_compatibility_func_t func,
+                                                   void *user_data, hb_destroy_func_t destroy);
+
+/* accessors */
+
+/**
+ * hb_unicode_combining_class:
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN hb_unicode_combining_class_t
+hb_unicode_combining_class (hb_unicode_funcs_t *ufuncs,
+                            hb_codepoint_t unicode);
+
+/**
+ * hb_unicode_eastasian_width:
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN unsigned int
+hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs,
+                            hb_codepoint_t unicode);
+
+/**
+ * hb_unicode_general_category:
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN hb_unicode_general_category_t
+hb_unicode_general_category (hb_unicode_funcs_t *ufuncs,
+                             hb_codepoint_t unicode);
+
+/**
+ * hb_unicode_mirroring:
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN hb_codepoint_t
+hb_unicode_mirroring (hb_unicode_funcs_t *ufuncs,
+                      hb_codepoint_t unicode);
+
+/**
+ * hb_unicode_script:
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN hb_script_t
+hb_unicode_script (hb_unicode_funcs_t *ufuncs,
+                   hb_codepoint_t unicode);
+
+HB_EXTERN hb_bool_t
+hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
+                    hb_codepoint_t      a,
+                    hb_codepoint_t      b,
+                    hb_codepoint_t     *ab);
+
+HB_EXTERN hb_bool_t
+hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
+                      hb_codepoint_t      ab,
+                      hb_codepoint_t     *a,
+                      hb_codepoint_t     *b);
+
+HB_EXTERN unsigned int
+hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
+                                    hb_codepoint_t      u,
+                                    hb_codepoint_t     *decomposed);
+
+HB_END_DECLS
+
+#endif /* HB_UNICODE_H */
diff --git a/src/share/native/sun/font/harfbuzz/hb-utf-private.hh b/src/share/native/sun/font/harfbuzz/hb-utf-private.hh
new file mode 100644
index 0000000..a465842
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-utf-private.hh
@@ -0,0 +1,282 @@
+/*
+ * Copyright © 2011,2012,2014  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_UTF_PRIVATE_HH
+#define HB_UTF_PRIVATE_HH
+
+#include "hb-private.hh"
+
+
+struct hb_utf8_t
+{
+  typedef uint8_t codepoint_t;
+
+  static inline const uint8_t *
+  next (const uint8_t *text,
+        const uint8_t *end,
+        hb_codepoint_t *unicode,
+        hb_codepoint_t replacement)
+  {
+    /* Written to only accept well-formed sequences.
+     * Based on ideas from ICU's U8_NEXT.
+     * Generates one "replacement" for each ill-formed byte. */
+
+    hb_codepoint_t c = *text++;
+
+    if (c > 0x7Fu)
+    {
+      if (hb_in_range (c, 0xC2u, 0xDFu)) /* Two-byte */
+      {
+        unsigned int t1;
+        if (likely (text < end &&
+                    (t1 = text[0] - 0x80u) <= 0x3Fu))
+        {
+          c = ((c&0x1Fu)<<6) | t1;
+          text++;
+        }
+        else
+          goto error;
+      }
+      else if (hb_in_range (c, 0xE0u, 0xEFu)) /* Three-byte */
+      {
+        unsigned int t1, t2;
+        if (likely (1 < end - text &&
+                    (t1 = text[0] - 0x80u) <= 0x3Fu &&
+                    (t2 = text[1] - 0x80u) <= 0x3Fu))
+        {
+          c = ((c&0xFu)<<12) | (t1<<6) | t2;
+          if (unlikely (c < 0x0800u || hb_in_range (c, 0xD800u, 0xDFFFu)))
+            goto error;
+          text += 2;
+        }
+        else
+          goto error;
+      }
+      else if (hb_in_range (c, 0xF0u, 0xF4u)) /* Four-byte */
+      {
+        unsigned int t1, t2, t3;
+        if (likely (2 < end - text &&
+                    (t1 = text[0] - 0x80u) <= 0x3Fu &&
+                    (t2 = text[1] - 0x80u) <= 0x3Fu &&
+                    (t3 = text[2] - 0x80u) <= 0x3Fu))
+        {
+          c = ((c&0x7u)<<18) | (t1<<12) | (t2<<6) | t3;
+          if (unlikely (!hb_in_range (c, 0x10000u, 0x10FFFFu)))
+            goto error;
+          text += 3;
+        }
+        else
+          goto error;
+      }
+      else
+        goto error;
+    }
+
+    *unicode = c;
+    return text;
+
+  error:
+    *unicode = replacement;
+    return text;
+  }
+
+  static inline const uint8_t *
+  prev (const uint8_t *text,
+        const uint8_t *start,
+        hb_codepoint_t *unicode,
+        hb_codepoint_t replacement)
+  {
+    const uint8_t *end = text--;
+    while (start < text && (*text & 0xc0) == 0x80 && end - text < 4)
+      text--;
+
+    if (likely (next (text, end, unicode, replacement) == end))
+      return text;
+
+    *unicode = replacement;
+    return end - 1;
+  }
+
+  static inline unsigned int
+  strlen (const uint8_t *text)
+  {
+    return ::strlen ((const char *) text);
+  }
+};
+
+
+struct hb_utf16_t
+{
+  typedef uint16_t codepoint_t;
+
+  static inline const uint16_t *
+  next (const uint16_t *text,
+        const uint16_t *end,
+        hb_codepoint_t *unicode,
+        hb_codepoint_t replacement)
+  {
+    hb_codepoint_t c = *text++;
+
+    if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
+    {
+      *unicode = c;
+      return text;
+    }
+
+    if (likely (c <= 0xDBFFu && text < end))
+    {
+      /* High-surrogate in c */
+      hb_codepoint_t l = *text;
+      if (likely (hb_in_range (l, 0xDC00u, 0xDFFFu)))
+      {
+        /* Low-surrogate in l */
+        *unicode = (c << 10) + l - ((0xD800u << 10) - 0x10000u + 0xDC00u);
+         text++;
+         return text;
+      }
+    }
+
+    /* Lonely / out-of-order surrogate. */
+    *unicode = replacement;
+    return text;
+  }
+
+  static inline const uint16_t *
+  prev (const uint16_t *text,
+        const uint16_t *start,
+        hb_codepoint_t *unicode,
+        hb_codepoint_t replacement)
+  {
+    hb_codepoint_t c = *--text;
+
+    if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
+    {
+      *unicode = c;
+      return text;
+    }
+
+    if (likely (c >= 0xDC00u && start < text))
+    {
+      /* Low-surrogate in c */
+      hb_codepoint_t h = text[-1];
+      if (likely (hb_in_range (h, 0xD800u, 0xDBFFu)))
+      {
+        /* High-surrogate in h */
+        *unicode = (h << 10) + c - ((0xD800u << 10) - 0x10000u + 0xDC00u);
+        text--;
+        return text;
+      }
+    }
+
+    /* Lonely / out-of-order surrogate. */
+    *unicode = replacement;
+    return text;
+  }
+
+
+  static inline unsigned int
+  strlen (const uint16_t *text)
+  {
+    unsigned int l = 0;
+    while (*text++) l++;
+    return l;
+  }
+};
+
+
+template <bool validate=true>
+struct hb_utf32_t
+{
+  typedef uint32_t codepoint_t;
+
+  static inline const uint32_t *
+  next (const uint32_t *text,
+        const uint32_t *end HB_UNUSED,
+        hb_codepoint_t *unicode,
+        hb_codepoint_t replacement)
+  {
+    hb_codepoint_t c = *unicode = *text++;
+    if (validate && unlikely (c >= 0xD800u && (c <= 0xDFFFu || c > 0x10FFFFu)))
+      *unicode = replacement;
+    return text;
+  }
+
+  static inline const uint32_t *
+  prev (const uint32_t *text,
+        const uint32_t *start HB_UNUSED,
+        hb_codepoint_t *unicode,
+        hb_codepoint_t replacement)
+  {
+    hb_codepoint_t c = *unicode = *--text;
+    if (validate && unlikely (c >= 0xD800u && (c <= 0xDFFFu || c > 0x10FFFFu)))
+      *unicode = replacement;
+    return text;
+  }
+
+  static inline unsigned int
+  strlen (const uint32_t *text)
+  {
+    unsigned int l = 0;
+    while (*text++) l++;
+    return l;
+  }
+};
+
+
+struct hb_latin1_t
+{
+  typedef uint8_t codepoint_t;
+
+  static inline const uint8_t *
+  next (const uint8_t *text,
+        const uint8_t *end HB_UNUSED,
+        hb_codepoint_t *unicode,
+        hb_codepoint_t replacement HB_UNUSED)
+  {
+    *unicode = *text++;
+    return text;
+  }
+
+  static inline const uint8_t *
+  prev (const uint8_t *text,
+        const uint8_t *start HB_UNUSED,
+        hb_codepoint_t *unicode,
+        hb_codepoint_t replacement)
+  {
+    *unicode = *--text;
+    return text;
+  }
+
+  static inline unsigned int
+  strlen (const uint8_t *text)
+  {
+    unsigned int l = 0;
+    while (*text++) l++;
+    return l;
+  }
+};
+
+#endif /* HB_UTF_PRIVATE_HH */
diff --git a/src/share/native/sun/font/harfbuzz/hb-version.h b/src/share/native/sun/font/harfbuzz/hb-version.h
new file mode 100644
index 0000000..5bcd33c
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-version.h
@@ -0,0 +1,66 @@
+/*
+ * 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
+ */
+
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_VERSION_H
+#define HB_VERSION_H
+
+#include "hb-common.h"
+
+HB_BEGIN_DECLS
+
+
+#define HB_VERSION_MAJOR 1
+#define HB_VERSION_MINOR 3
+#define HB_VERSION_MICRO 0
+
+#define HB_VERSION_STRING "1.3.0"
+
+#define HB_VERSION_ATLEAST(major,minor,micro) \
+        ((major)*10000+(minor)*100+(micro) <= \
+         HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
+
+
+HB_EXTERN void
+hb_version (unsigned int *major,
+            unsigned int *minor,
+            unsigned int *micro);
+
+HB_EXTERN const char *
+hb_version_string (void);
+
+HB_EXTERN hb_bool_t
+hb_version_atleast (unsigned int major,
+                    unsigned int minor,
+                    unsigned int micro);
+
+
+HB_END_DECLS
+
+#endif /* HB_VERSION_H */
diff --git a/src/share/native/sun/font/harfbuzz/hb-warning.cpp b/src/share/native/sun/font/harfbuzz/hb-warning.cpp
new file mode 100644
index 0000000..8f322bc
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb-warning.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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
+ */
+
+#include "hb-atomic-private.hh"
+#include "hb-mutex-private.hh"
+
+
+#if defined(HB_ATOMIC_INT_NIL)
+#error "Could not find any system to define atomic_int macros, library WILL NOT be thread-safe"
+#error "Check hb-atomic-private.hh for possible resolutions."
+#endif
+
+#if defined(HB_MUTEX_IMPL_NIL)
+#error "Could not find any system to define mutex macros, library WILL NOT be thread-safe"
+#error "Check hb-mutex-private.hh for possible resolutions."
+#endif
diff --git a/src/share/native/sun/font/harfbuzz/hb.h b/src/share/native/sun/font/harfbuzz/hb.h
new file mode 100644
index 0000000..7402034
--- /dev/null
+++ b/src/share/native/sun/font/harfbuzz/hb.h
@@ -0,0 +1,51 @@
+/*
+ * 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
+#define HB_H
+#define HB_H_IN
+
+#ifndef HB_EXTERN
+#define HB_EXTERN extern
+#endif
+
+#include "hb-blob.h"
+#include "hb-buffer.h"
+#include "hb-common.h"
+#include "hb-deprecated.h"
+#include "hb-face.h"
+#include "hb-font.h"
+#include "hb-set.h"
+#include "hb-shape.h"
+#include "hb-shape-plan.h"
+#include "hb-unicode.h"
+#include "hb-version.h"
+
+HB_BEGIN_DECLS
+HB_END_DECLS
+
+#undef HB_H_IN
+#endif /* HB_H */
diff --git a/src/share/native/sun/font/hb-jdk-font.cpp b/src/share/native/sun/font/hb-jdk-font.cpp
new file mode 100644
index 0000000..3b05783
--- /dev/null
+++ b/src/share/native/sun/font/hb-jdk-font.cpp
@@ -0,0 +1,402 @@
+/*
+ * 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 "jlong.h"
+#include "sun_font_Font2D.h"
+#include "hb.h"
+#include "hb-jdk.h"
+#ifdef MACOSX
+#include "hb-coretext.h"
+#endif
+#include <stdlib.h>
+
+#if defined(__GNUC__) &&  __GNUC__ >= 4
+#define HB_UNUSED       __attribute__((unused))
+#else
+#define HB_UNUSED
+#endif
+
+static hb_bool_t
+hb_jdk_get_glyph (hb_font_t *font HB_UNUSED,
+		 void *font_data,
+		 hb_codepoint_t unicode,
+		 hb_codepoint_t variation_selector,
+		 hb_codepoint_t *glyph,
+		 void *user_data HB_UNUSED)
+{
+
+    JDKFontInfo *jdkFontInfo = (JDKFontInfo*)font_data;
+    JNIEnv* env = jdkFontInfo->env;
+    jobject font2D = jdkFontInfo->font2D;
+    hb_codepoint_t u = (variation_selector==0) ? unicode : variation_selector;
+ 
+    *glyph = (hb_codepoint_t)
+          env->CallIntMethod(font2D, sunFontIDs.f2dCharToGlyphMID, u);
+    return (*glyph != 0);
+}
+
+static hb_position_t
+hb_jdk_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
+			   void *font_data,
+			   hb_codepoint_t glyph,
+			   void *user_data HB_UNUSED)
+{
+    
+    float fadv = 0.0f;
+    if ((glyph & 0xfffe) == 0xfffe) {
+        return 0; // JDK uses this glyph code.
+    }
+
+    JDKFontInfo *jdkFontInfo = (JDKFontInfo*)font_data;
+    JNIEnv* env = jdkFontInfo->env;
+    jobject fontStrike = jdkFontInfo->fontStrike;
+    jobject pt = env->CallObjectMethod(fontStrike,
+                                       sunFontIDs.getGlyphMetricsMID, glyph);
+  
+    if (pt == NULL) {
+        return 0;
+    }
+    fadv = env->GetFloatField(pt, sunFontIDs.xFID);
+    fadv *= jdkFontInfo->devScale;
+    env->DeleteLocalRef(pt);
+
+    return HBFloatToFixed(fadv);
+}
+
+static hb_position_t
+hb_jdk_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
+			   void *font_data,
+			   hb_codepoint_t glyph,
+			   void *user_data HB_UNUSED)
+{
+  
+    float fadv = 0.0f;
+    if ((glyph & 0xfffe) == 0xfffe) {
+        return 0; // JDK uses this glyph code.
+    }
+
+    JDKFontInfo *jdkFontInfo = (JDKFontInfo*)font_data;
+    JNIEnv* env = jdkFontInfo->env;
+    jobject fontStrike = jdkFontInfo->fontStrike;
+    jobject pt = env->CallObjectMethod(fontStrike,
+                                       sunFontIDs.getGlyphMetricsMID, glyph);
+  
+    if (pt == NULL) {
+        return 0;
+    }
+    fadv = env->GetFloatField(pt, sunFontIDs.yFID);
+    env->DeleteLocalRef(pt);
+
+    return HBFloatToFixed(fadv);
+  
+}
+
+static hb_bool_t
+hb_jdk_get_glyph_h_origin (hb_font_t *font HB_UNUSED,
+			  void *font_data HB_UNUSED,
+			  hb_codepoint_t glyph HB_UNUSED,
+			  hb_position_t *x HB_UNUSED,
+			  hb_position_t *y HB_UNUSED,
+			  void *user_data HB_UNUSED)
+{
+  /* We always work in the horizontal coordinates. */
+  return true;
+}
+
+static hb_bool_t
+hb_jdk_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
+			  void *font_data,
+			  hb_codepoint_t glyph,
+			  hb_position_t *x,
+			  hb_position_t *y,
+			  void *user_data HB_UNUSED)
+{
+  return false;
+}
+
+static hb_position_t
+hb_jdk_get_glyph_h_kerning (hb_font_t *font,
+			   void *font_data,
+			   hb_codepoint_t lejdk_glyph,
+			   hb_codepoint_t right_glyph,
+			   void *user_data HB_UNUSED)
+{
+  /* Not implemented. This seems to be in the HB API
+   * as a way to fall back to Freetype's kerning support
+   * which could be based on some on-the fly glyph analysis.
+   * But more likely it reads the kern table. That is easy
+   * enough code to add if we find a need to fall back
+   * to that instead of using gpos. It seems like if
+   * there is a gpos table at all, the practice is to
+   * use that and ignore kern, no matter that gpos does
+   * not implement the kern feature.
+   */
+  return 0;
+}
+
+static hb_position_t
+hb_jdk_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
+			   void *font_data HB_UNUSED,
+			   hb_codepoint_t top_glyph HB_UNUSED,
+			   hb_codepoint_t bottom_glyph HB_UNUSED,
+			   void *user_data HB_UNUSED)
+{
+  /* OpenType doesn't have vertical-kerning other than GPOS. */
+  return 0;
+}
+
+static hb_bool_t
+hb_jdk_get_glyph_extents (hb_font_t *font HB_UNUSED,
+			 void *font_data,
+			 hb_codepoint_t glyph,
+			 hb_glyph_extents_t *extents,
+			 void *user_data HB_UNUSED)
+{
+  /* TODO */
+  return false;
+}
+
+static hb_bool_t
+hb_jdk_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
+			       void *font_data,
+			       hb_codepoint_t glyph,
+			       unsigned int point_index,
+			       hb_position_t *x,
+			       hb_position_t *y,
+			       void *user_data HB_UNUSED)
+{
+    if ((glyph & 0xfffe) == 0xfffe) {
+        *x = 0; *y = 0;
+        return true;
+    }
+
+    JDKFontInfo *jdkFontInfo = (JDKFontInfo*)font_data;
+    JNIEnv* env = jdkFontInfo->env;
+    jobject fontStrike = jdkFontInfo->fontStrike;
+    jobject pt = env->CallObjectMethod(fontStrike,
+                                       sunFontIDs.getGlyphPointMID,
+                                       glyph, point_index);
+  
+    if (pt == NULL) {
+        *x = 0; *y = 0;
+        return true;
+    }
+    *x = HBFloatToFixed(env->GetFloatField(pt, sunFontIDs.xFID));
+    *y = HBFloatToFixed(env->GetFloatField(pt, sunFontIDs.yFID));
+    env->DeleteLocalRef(pt);
+
+  return true;
+}
+
+static hb_bool_t
+hb_jdk_get_glyph_name (hb_font_t *font HB_UNUSED,
+		      void *font_data,
+		      hb_codepoint_t glyph,
+		      char *name, unsigned int size,
+		      void *user_data HB_UNUSED)
+{
+  return false;
+}
+
+static hb_bool_t
+hb_jdk_get_glyph_from_name (hb_font_t *font HB_UNUSED,
+			   void *font_data,
+			   const char *name, int len,
+			   hb_codepoint_t *glyph,
+			   void *user_data HB_UNUSED)
+{
+  return false;
+}
+
+// remind : can we initialise this from the code we call
+// from the class static method in Java to make it
+// completely thread safe.
+static hb_font_funcs_t *
+_hb_jdk_get_font_funcs (void)
+{
+  static hb_font_funcs_t *jdk_ffuncs = NULL;
+  hb_font_funcs_t *ff;
+
+  if (!jdk_ffuncs) {
+      ff = hb_font_funcs_create(); 
+      
+      hb_font_funcs_set_glyph_func(ff, hb_jdk_get_glyph, NULL, NULL);
+      hb_font_funcs_set_glyph_h_advance_func(ff,
+                    hb_jdk_get_glyph_h_advance, NULL, NULL);
+      hb_font_funcs_set_glyph_v_advance_func(ff,
+                    hb_jdk_get_glyph_v_advance, NULL, NULL);
+      hb_font_funcs_set_glyph_h_origin_func(ff,
+                    hb_jdk_get_glyph_h_origin, NULL, NULL);
+      hb_font_funcs_set_glyph_v_origin_func(ff,
+                    hb_jdk_get_glyph_v_origin, NULL, NULL);
+      hb_font_funcs_set_glyph_h_kerning_func(ff,
+                    hb_jdk_get_glyph_h_kerning, NULL, NULL);
+      hb_font_funcs_set_glyph_v_kerning_func(ff,
+                    hb_jdk_get_glyph_v_kerning, NULL, NULL);
+      hb_font_funcs_set_glyph_extents_func(ff,
+                    hb_jdk_get_glyph_extents, NULL, NULL);
+      hb_font_funcs_set_glyph_contour_point_func(ff,
+                    hb_jdk_get_glyph_contour_point, NULL, NULL);
+      hb_font_funcs_set_glyph_name_func(ff,
+                    hb_jdk_get_glyph_name, NULL, NULL);
+      hb_font_funcs_set_glyph_from_name_func(ff,
+                    hb_jdk_get_glyph_from_name, NULL, NULL);
+      hb_font_funcs_make_immutable(ff); // done setting functions.
+      jdk_ffuncs = ff;
+  }
+  return jdk_ffuncs;
+}
+
+static void _do_nothing(void) {
+}
+
+struct Font2DPtr {
+    JavaVM* vmPtr;
+    jweak font2DRef;
+};
+
+static void cleanupFontInfo(void* data) {
+  Font2DPtr* fontInfo; 
+  JNIEnv* env;
+  
+  fontInfo = (Font2DPtr*) data;
+  fontInfo->vmPtr->GetEnv((void**)&env, JNI_VERSION_1_1);
+  env->DeleteWeakGlobalRef(fontInfo->font2DRef);
+  free((void*)data);
+}
+
+static hb_blob_t *
+reference_table(hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) {
+
+  Font2DPtr *fontInfo;
+  JNIEnv* env;
+  jobject font2D;
+  jsize length;
+  jbyte* buffer;
+  
+  fontInfo = (Font2DPtr*)user_data;
+  fontInfo->vmPtr->GetEnv((void**)&env, JNI_VERSION_1_1);
+  if (env == NULL) {
+    return NULL;
+  }
+  font2D = fontInfo->font2DRef;
+  
+  // HB_TAG_NONE is 0 and is used to get the whole font file.
+  // It is not expected not be needed for JDK.
+  if (tag == 0) {
+      return NULL;
+  }
+  jbyteArray tableBytes = (jbyteArray)
+     env->CallObjectMethod(font2D, sunFontIDs.getTableBytesMID, tag);
+  if (tableBytes == NULL) {
+      return NULL;
+  }
+  length = env->GetArrayLength(tableBytes);
+  buffer = (jbyte *)calloc(length, sizeof(jbyte));
+  env->GetByteArrayRegion(tableBytes, 0, length, buffer);
+
+  return hb_blob_create((const char *)buffer, length,
+                         HB_MEMORY_MODE_WRITABLE,
+                         buffer, free);
+}
+
+/*
+ * Class:     sun_font_Font2D
+ * Method:    createHarfbuzzFace
+ * Signature: (ZJ)J
+ */
+JNIEXPORT jlong JNICALL Java_sun_font_Font2D_createHarfbuzzFace(JNIEnv *env, jobject font2D, jboolean aat, jlong platformFontPtr) {
+#ifdef MACOSX
+    if (aat && platformFontPtr) {
+        hb_face_t *face = hb_coretext_face_create((CGFontRef)platformFontPtr);
+        return ptr_to_jlong(face);
+    }
+#endif
+    Font2DPtr *fi = (Font2DPtr*)malloc(sizeof(Font2DPtr));
+    if (!fi) {
+        return 0;
+    }
+    JavaVM* vmPtr;
+    env->GetJavaVM(&vmPtr);
+    fi->vmPtr = vmPtr;
+    fi->font2DRef = env->NewWeakGlobalRef(font2D);
+    hb_face_t *face = hb_face_create_for_tables(reference_table, fi, cleanupFontInfo);
+    return ptr_to_jlong(face);
+}
+
+/*
+ * Class:     sun_font_Font2D
+ * Method:    disposeHarfbuzzFace
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_sun_font_Font2D_disposeHarfbuzzFace(JNIEnv *env, jclass cls, jlong ptr) {
+    hb_face_t* face = (hb_face_t*) jlong_to_ptr(ptr);
+    hb_face_destroy(face);
+}
+
+static hb_font_t* _hb_jdk_font_create(hb_face_t* face, 
+                                      JDKFontInfo *jdkFontInfo,
+                                      hb_destroy_func_t destroy) {
+
+    hb_font_t *font;
+
+    font = hb_font_create(face);
+    hb_font_set_funcs (font,
+                       _hb_jdk_get_font_funcs (),
+                       jdkFontInfo, (hb_destroy_func_t) _do_nothing);
+    hb_font_set_scale (font,
+                      HBFloatToFixed(jdkFontInfo->ptSize*jdkFontInfo->devScale),
+                      HBFloatToFixed(jdkFontInfo->ptSize*jdkFontInfo->devScale));
+  return font;
+}
+
+#ifdef MACOSX
+static hb_font_t* _hb_jdk_ct_font_create(hb_face_t* face, JDKFontInfo *jdkFontInfo) {
+
+    hb_font_t *font = NULL;
+    font = hb_font_create(face);
+    hb_font_set_scale(font,
+                     HBFloatToFixed(jdkFontInfo->ptSize),
+                     HBFloatToFixed(jdkFontInfo->ptSize));
+    return font;
+}
+#endif
+
+hb_font_t* hb_jdk_font_create(hb_face_t* hbface,
+                              JDKFontInfo *jdkFontInfo,
+                             hb_destroy_func_t destroy) {
+
+   hb_font_t* font = NULL;
+
+#ifdef MACOSX
+     if (jdkFontInfo->aat && jdkFontInfo->nativeFont) {
+         font = _hb_jdk_ct_font_create(hbface, jdkFontInfo);
+     }
+#endif
+    if (font == NULL) {
+        font = _hb_jdk_font_create(hbface, jdkFontInfo, destroy);
+    }
+   return font;
+}
diff --git a/src/share/native/sun/font/hb-jdk.h b/src/share/native/sun/font/hb-jdk.h
new file mode 100644
index 0000000..2d0c107
--- /dev/null
+++ b/src/share/native/sun/font/hb-jdk.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#ifndef HB_JDK_H
+#define HB_JDK_H
+
+#include "hb.h"
+#include <jni.h>
+#include <sunfontids.h>
+
+# ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct JDKFontInfo_Struct {
+    JNIEnv* env;
+    jobject font2D;
+    jobject fontStrike;
+    long nativeFont;
+    float matrix[4];
+    float ptSize;
+    float xPtSize;
+    float yPtSize;
+    float devScale; // How much applying the full glyph tx scales x distance.
+    jboolean aat;
+} JDKFontInfo;
+
+
+// Use 16.16 for better precision than 26.6
+#define HBFloatToFixedScale ((float)(1 << 16))
+#define HBFloatToFixed(f) ((unsigned int)((f) * HBFloatToFixedScale))
+
+/*
+ * Note:
+ *
+ * Set face size on ft-face before creating hb-font from it.
+ * Otherwise hb-ft would NOT pick up the font size correctly.
+ */
+
+hb_face_t *
+hb_jdk_face_create(JDKFontInfo*   jdkFontInfo,
+                   hb_destroy_func_t destroy);
+hb_font_t *
+hb_jdk_font_create(hb_face_t* hbface,
+                   JDKFontInfo*   jdkFontInfo,
+                   hb_destroy_func_t destroy);
+
+
+/* Makes an hb_font_t use JDK internally to implement font functions. */
+void
+hb_jdk_font_set_funcs(hb_font_t *font);
+
+
+# ifdef __cplusplus
+}
+#endif
+
+#endif /* HB_JDK_H */
diff --git a/src/share/native/sun/font/scriptMapping.c b/src/share/native/sun/font/scriptMapping.c
new file mode 100644
index 0000000..038b63c
--- /dev/null
+++ b/src/share/native/sun/font/scriptMapping.c
@@ -0,0 +1,92 @@
+/*
+ * 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 "scriptMapping.h"
+/*
+ * Java level-code has a script code indexes that correspond to
+ * the indexes used by the ICU layout library. In order to call
+ * harfbuzz we must map these to the equivalent harfbuzz codes.
+ * Some of these happen to be the same but not many.
+ */
+
+hb_script_t ICU_to_Harfbuzz_ScriptCode[] = {
+
+    HB_SCRIPT_COMMON,           /* 0 */
+    HB_SCRIPT_INHERITED,        /* 1 */
+    HB_SCRIPT_ARABIC,           /* 2 */
+    HB_SCRIPT_ARMENIAN,         /* 3 */
+    HB_SCRIPT_BENGALI,          /* 4 */
+    HB_SCRIPT_BOPOMOFO,         /* 5 */
+    HB_SCRIPT_CHEROKEE,         /* 6 */
+    HB_SCRIPT_COPTIC,           /* 7 */
+    HB_SCRIPT_CYRILLIC,         /* 8 */
+    HB_SCRIPT_DESERET,          /* 9 */
+    HB_SCRIPT_DEVANAGARI,       /* 10 */
+    HB_SCRIPT_ETHIOPIC,         /* 11 */
+    HB_SCRIPT_GEORGIAN,         /* 12 */
+    HB_SCRIPT_GOTHIC,           /* 13 */
+    HB_SCRIPT_GREEK,            /* 14 */
+    HB_SCRIPT_GUJARATI,         /* 15 */
+    HB_SCRIPT_GURMUKHI,         /* 16 */
+    HB_SCRIPT_HAN,              /* 17 */
+    HB_SCRIPT_HANGUL,           /* 18 */
+    HB_SCRIPT_HEBREW,           /* 19 */
+    HB_SCRIPT_HIRAGANA,         /* 20 */
+    HB_SCRIPT_KANNADA,          /* 21 */
+    HB_SCRIPT_KATAKANA,         /* 22 */
+    HB_SCRIPT_KHMER,            /* 23 */
+    HB_SCRIPT_LAO,              /* 24 */
+    HB_SCRIPT_LATIN,            /* 25 */
+    HB_SCRIPT_MALAYALAM,        /* 26 */
+    HB_SCRIPT_MONGOLIAN,        /* 27 */
+    HB_SCRIPT_MYANMAR,          /* 28 */
+    HB_SCRIPT_OGHAM,            /* 29 */
+    HB_SCRIPT_OLD_ITALIC,       /* 30 */
+    HB_SCRIPT_ORIYA,            /* 31 */
+    HB_SCRIPT_RUNIC,            /* 32 */
+    HB_SCRIPT_SINHALA,          /* 33 */
+    HB_SCRIPT_SYRIAC,           /* 34 */
+    HB_SCRIPT_TAMIL,            /* 35 */
+    HB_SCRIPT_TELUGU,           /* 36 */
+    HB_SCRIPT_THAANA,           /* 37 */
+    HB_SCRIPT_THAI,             /* 38 */
+    HB_SCRIPT_TIBETAN,          /* 39 */
+    HB_SCRIPT_CANADIAN_SYLLABICS,   /* 40 */
+    HB_SCRIPT_YI,               /* 41 */
+    HB_SCRIPT_TAGALOG,          /* 42 */
+    HB_SCRIPT_HANUNOO,          /* 43 */
+    HB_SCRIPT_BUHID,            /* 44 */
+    HB_SCRIPT_TAGBANWA,         /* 45 */
+
+};
+
+int MAX_ICU_SCRIPTCODE = 45;
+
+hb_script_t getHBScriptCode(int code) {
+    if ((code < 0) || (code > MAX_ICU_SCRIPTCODE)) {
+        return HB_SCRIPT_INVALID;
+    }
+    return ICU_to_Harfbuzz_ScriptCode[code];
+}
diff --git a/src/share/native/sun/font/scriptMapping.h b/src/share/native/sun/font/scriptMapping.h
new file mode 100644
index 0000000..a56a233
--- /dev/null
+++ b/src/share/native/sun/font/scriptMapping.h
@@ -0,0 +1,33 @@
+/*
+ * 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 <hb.h>
+
+extern int MAX_ICU_SCRIPTCODE;
+
+extern hb_script_t ICU_to_Harfbuzz_ScriptCode[];
+
+hb_script_t getHBScriptCode(int code);
+
diff --git a/src/share/native/sun/font/sunFont.c b/src/share/native/sun/font/sunFont.c
index 294328b..fe19f04 100644
--- a/src/share/native/sun/font/sunFont.c
+++ b/src/share/native/sun/font/sunFont.c
@@ -167,9 +167,9 @@
 
      CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/GlyphList"));
      CHECK_NULL(sunFontIDs.glyphListX =
-         (*env)->GetFieldID(env, tmpClass, "x", "F"));
+         (*env)->GetFieldID(env, tmpClass, "gposx", "F"));
      CHECK_NULL(sunFontIDs.glyphListY =
-         (*env)->GetFieldID(env, tmpClass, "y", "F"));
+         (*env)->GetFieldID(env, tmpClass, "gposy", "F"));
      CHECK_NULL(sunFontIDs.glyphListLen =
          (*env)->GetFieldID(env, tmpClass, "len", "I"));
      CHECK_NULL(sunFontIDs.glyphImages =
diff --git a/src/share/native/sun/java2d/SurfaceData.c b/src/share/native/sun/java2d/SurfaceData.c
index b8cb9fd..4f88d28 100644
--- a/src/share/native/sun/java2d/SurfaceData.c
+++ b/src/share/native/sun/java2d/SurfaceData.c
@@ -231,7 +231,8 @@
     GETMIN(src->y2, dst->y2 - dy);
 }
 
-SurfaceDataOps *SurfaceData_InitOps(JNIEnv *env, jobject sData, int opsSize)
+JNIEXPORT SurfaceDataOps * JNICALL
+SurfaceData_InitOps(JNIEnv *env, jobject sData, int opsSize)
 {
     SurfaceDataOps *ops = malloc(opsSize);
     SurfaceData_SetOps(env, sData, ops);
diff --git a/src/share/native/sun/java2d/SurfaceData.h b/src/share/native/sun/java2d/SurfaceData.h
index 349aad1..e1e7489 100644
--- a/src/share/native/sun/java2d/SurfaceData.h
+++ b/src/share/native/sun/java2d/SurfaceData.h
@@ -648,7 +648,8 @@
  * Subclasses of SurfaceData should call this function instead of allocating
  * the memory directly.
  */
-SurfaceDataOps *SurfaceData_InitOps(JNIEnv *env, jobject sData, int opsSize);
+JNIEXPORT SurfaceDataOps * JNICALL
+SurfaceData_InitOps(JNIEnv *env, jobject sData, int opsSize);
 
 /*
  * This function invokes the ops-specific disposal function.
diff --git a/src/share/native/sun/java2d/opengl/OGLTextRenderer.c b/src/share/native/sun/java2d/opengl/OGLTextRenderer.c
index 53184c2..1352621 100644
--- a/src/share/native/sun/java2d/opengl/OGLTextRenderer.c
+++ b/src/share/native/sun/java2d/opengl/OGLTextRenderer.c
@@ -26,6 +26,7 @@
 #ifndef HEADLESS
 
 #include <stdlib.h>
+#include <limits.h>
 #include <math.h>
 #include <jlong.h>
 
@@ -33,21 +34,19 @@
 
 #include "SurfaceData.h"
 #include "OGLContext.h"
-#include "OGLSurfaceData.h"
 #include "OGLRenderQueue.h"
 #include "OGLTextRenderer.h"
 #include "OGLVertexCache.h"
 #include "AccelGlyphCache.h"
-#include "fontscalerdefs.h"
 
 /**
  * The following constants define the inner and outer bounds of the
  * accelerated glyph cache.
  */
-#define OGLTR_CACHE_WIDTH       512
-#define OGLTR_CACHE_HEIGHT      512
-#define OGLTR_CACHE_CELL_WIDTH  32
-#define OGLTR_CACHE_CELL_HEIGHT 32
+#define OGLTR_CACHE_WIDTH       1024
+#define OGLTR_CACHE_HEIGHT      1024
+#define OGLTR_CACHE_CELL_WIDTH  64
+#define OGLTR_CACHE_CELL_HEIGHT 64
 
 /**
  * The current "glyph mode" state.  This variable is used to track the
@@ -63,7 +62,8 @@
     MODE_USE_CACHE_GRAY,
     MODE_USE_CACHE_LCD,
     MODE_NO_CACHE_GRAY,
-    MODE_NO_CACHE_LCD
+    MODE_NO_CACHE_LCD,
+    MODE_NO_CACHE_COLOR
 } GlyphMode;
 static GlyphMode glyphMode = MODE_NOT_INITED;
 
@@ -107,7 +107,7 @@
  * OGLTR_DrawLCDGlyphNoCache() method.  See below for more on why we
  * restrict this value to a particular size.
  */
-#define OGLTR_NOCACHE_TILE_SIZE 32
+#define OGLTR_NOCACHE_TILE_SIZE 64
 
 /**
  * These constants define the size of the "cached destination" texture.
@@ -128,7 +128,7 @@
  *     (OGLTR_CACHED_DEST_HEIGHT >= OGLTR_CACHE_CELL_HEIGHT) &&
  *     (OGLTR_CACHED_DEST_HEIGHT >= OGLTR_NOCACHE_TILE_SIZE)
  */
-#define OGLTR_CACHED_DEST_WIDTH  512
+#define OGLTR_CACHED_DEST_WIDTH  1024
 #define OGLTR_CACHED_DEST_HEIGHT (OGLTR_CACHE_CELL_HEIGHT * 2)
 
 /**
@@ -710,13 +710,17 @@
                            GlyphInfo *ginfo, jint x, jint y,
                            jint glyphIndex, jint totalGlyphs,
                            jboolean rgbOrder, jint contrast,
-                            GLuint dstTextureID)
+                           GLuint dstTextureID, jboolean * opened)
 {
     CacheCellInfo *cell;
     jint dx1, dy1, dx2, dy2;
     jfloat dtx1, dty1, dtx2, dty2;
 
     if (glyphMode != MODE_USE_CACHE_LCD) {
+        if (*opened) {
+            *opened = JNI_FALSE;
+            j2d_glEnd();
+        }
         OGLTR_DisableGlyphModeState();
         CHECK_PREVIOUS_OP(GL_TEXTURE_2D);
         j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
@@ -748,6 +752,10 @@
     }
 
     if (ginfo->cellInfo == NULL) {
+        if (*opened) {
+            *opened = JNI_FALSE;
+            j2d_glEnd();
+        }
         // rowBytes will always be a multiple of 3, so the following is safe
         j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, ginfo->rowBytes / 3);
 
@@ -773,6 +781,10 @@
     dy2 = dy1 + ginfo->height;
 
     if (dstTextureID == 0) {
+        if (*opened) {
+            *opened = JNI_FALSE;
+            j2d_glEnd();
+        }
         // copy destination into second cached texture, if necessary
         OGLTR_UpdateCachedDestination(dstOps, ginfo,
                                       dx1, dy1, dx2, dy2,
@@ -797,12 +809,14 @@
 
         dty1 = ((GLfloat)dyadj + gh) / dstOps->textureHeight;
         dty2 = ((GLfloat)dyadj) / dstOps->textureHeight;
-
-        j2d_glTextureBarrierNV();
     }
 
     // render composed texture to the destination surface
-    j2d_glBegin(GL_QUADS);
+    if (!*opened)  {
+        j2d_glBegin(GL_QUADS);
+        *opened = JNI_TRUE;
+    }
+
     j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx1, cell->ty1);
     j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty1);
     j2d_glVertex2i(dx1, dy1);
@@ -815,7 +829,6 @@
     j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx1, cell->ty2);
     j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty2);
     j2d_glVertex2i(dx1, dy2);
-    j2d_glEnd();
 
     return JNI_TRUE;
 }
@@ -855,7 +868,6 @@
 
     return JNI_TRUE;
 }
-
 static jboolean
 OGLTR_DrawLCDGlyphNoCache(OGLContext *oglc, OGLSDOps *dstOps,
                           GlyphInfo *ginfo, jint x, jint y,
@@ -900,40 +912,87 @@
     j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, ginfo->rowBytes / 3);
 
     x0 = x;
-    tx1 = 0.0f;
-    ty1 = 0.0f;
-    dtx1 = 0.0f;
-    dty2 = 0.0f;
     tw = OGLTR_NOCACHE_TILE_SIZE;
     th = OGLTR_NOCACHE_TILE_SIZE;
 
-    for (sy = 0; sy < h; sy += th, y += th) {
-        x = x0;
-        sh = ((sy + th) > h) ? (h - sy) : th;
+    if (dstTextureID) {
+        // use the destination texture directly
 
-        for (sx = 0; sx < w; sx += tw, x += tw) {
-            sw = ((sx + tw) > w) ? (w - sx) : tw;
+        // update the source pointer offsets
+        j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+        j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
 
-            // update the source pointer offsets
-            j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx);
-            j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy);
+        // copy LCD mask into glyph texture tile
+        j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
+        j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
+                            0, 0, w, h,
+                            pixelFormat, GL_UNSIGNED_BYTE,
+                            ginfo->image + rowBytesOffset);
 
-            // copy LCD mask into glyph texture tile
-            j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
-            j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
-                                0, 0, sw, sh,
-                                pixelFormat, GL_UNSIGNED_BYTE,
-                                ginfo->image + rowBytesOffset);
+        tx2 = ((GLfloat)w) / OGLC_BLIT_TILE_SIZE;
+        ty2 = ((GLfloat)h) / OGLC_BLIT_TILE_SIZE;;
+        dxadj = dstOps->xOffset + x;
+        dyadj = dstOps->yOffset + dstOps->height - y;
+        dtx1 = ((GLfloat)dxadj) / dstOps->textureWidth;
+        dty1 = ((GLfloat)dyadj) / dstOps->textureHeight;
+        dtx2 = ((GLfloat)dxadj + w) / dstOps->textureWidth;
+        dty2 = ((GLfloat)dyadj - h) / dstOps->textureHeight;
 
-            // update the lower-right glyph texture coordinates
-            tx2 = ((GLfloat)sw) / OGLC_BLIT_TILE_SIZE;
+        // render composed texture to the destination surface
+        j2d_glBegin(GL_QUADS);
+        j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0, 0);
+        j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty1);
+        j2d_glVertex2i(x, y);
+        j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx2, 0);
+        j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty1);
+        j2d_glVertex2i(x + w, y);
+        j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx2, ty2);
+        j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty2);
+        j2d_glVertex2i(x + w, y + h);
+        j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0, ty2);
+        j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty2);
+        j2d_glVertex2i(x, y + h);
+        j2d_glEnd();
+
+    } else {
+        tx1 = 0.0f;
+        ty1 = 0.0f;
+        dtx1 = 0.0f;
+        dty2 = 0.0f;
+
+        for (sy = 0; sy < h; sy += th, y += th) {
+            x = x0;
+            sh = ((sy + th) > h) ? (h - sy) : th;
+
+            // update lower glyph texture coordinate
             ty2 = ((GLfloat)sh) / OGLC_BLIT_TILE_SIZE;
 
-            // this accounts for lower-left origin of the destination region
-            dxadj = dstOps->xOffset + x;
+            // update the destination texture coordinate
+            dty1 = ((GLfloat)sh) / OGLTR_CACHED_DEST_HEIGHT;
+
+            // this accounts for lower origin of the destination region
             dyadj = dstOps->yOffset + dstOps->height - (y + sh);
 
-            if (dstTextureID == 0) {
+            for (sx = 0; sx < w; sx += tw, x += tw) {
+                sw = ((sx + tw) > w) ? (w - sx) : tw;
+
+                // update the source pointer offsets
+                j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx);
+                j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy);
+
+                // copy LCD mask into glyph texture tile
+                j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
+                j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
+                                    0, 0, sw, sh,
+                                    pixelFormat, GL_UNSIGNED_BYTE,
+                                    ginfo->image + rowBytesOffset);
+
+                // update right glyph texture coordinate
+                tx2 = ((GLfloat)sw) / OGLC_BLIT_TILE_SIZE;
+
+                // this accounts for left origin of the destination region
+                dxadj = dstOps->xOffset + x;
+
                 // copy destination into cached texture tile (the lower-left
                 // corner of the destination region will be positioned at the
                 // lower-left corner (0,0) of the texture)
@@ -942,42 +1001,52 @@
                                         0, 0,
                                         dxadj, dyadj,
                                         sw, sh);
-                // update the remaining destination texture coordinates
-                dtx2 = ((GLfloat)sw) / OGLTR_CACHED_DEST_WIDTH;
-                dty1 = ((GLfloat)sh) / OGLTR_CACHED_DEST_HEIGHT;
-            } else {
-                // use the destination texture directly
-                // update the remaining destination texture coordinates
-                dtx1 =((GLfloat)dxadj) / dstOps->textureWidth;
-                dtx2 = ((GLfloat)dxadj + sw) / dstOps->textureWidth;
 
-                dty1 = ((GLfloat)dyadj + sh) / dstOps->textureHeight;
-                dty2 = ((GLfloat)dyadj) / dstOps->textureHeight;
+                // update the destination texture coordinate
+                dtx2 = ((GLfloat) sw) / OGLTR_CACHED_DEST_WIDTH;
 
-                j2d_glTextureBarrierNV();
+                // render composed texture to the destination surface
+                j2d_glBegin(GL_QUADS);
+                j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx1, ty1);
+                j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty1);
+                j2d_glVertex2i(x, y);
+                j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx2, ty1);
+                j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty1);
+                j2d_glVertex2i(x + sw, y);
+                j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx2, ty2);
+                j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty2);
+                j2d_glVertex2i(x + sw, y + sh);
+                j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx1, ty2);
+                j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty2);
+                j2d_glVertex2i(x, y + sh);
+                j2d_glEnd();
             }
-
-            // render composed texture to the destination surface
-            j2d_glBegin(GL_QUADS);
-            j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx1, ty1);
-            j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty1);
-            j2d_glVertex2i(x, y);
-            j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx2, ty1);
-            j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty1);
-            j2d_glVertex2i(x + sw, y);
-            j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx2, ty2);
-            j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty2);
-            j2d_glVertex2i(x + sw, y + sh);
-            j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx1, ty2);
-            j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty2);
-            j2d_glVertex2i(x, y + sh);
-            j2d_glEnd();
         }
     }
+    return JNI_TRUE;
+}
+
+static jboolean
+OGLTR_DrawColorGlyphNoCache(OGLContext *oglc, GlyphInfo *ginfo, jint x, jint y)
+{
+    if (glyphMode != MODE_NO_CACHE_COLOR) {
+        OGLTR_DisableGlyphModeState();
+        CHECK_PREVIOUS_OP(OGL_STATE_RESET);
+        glyphMode = MODE_NO_CACHE_COLOR;
+    }
+
+    // see OGLBlitSwToSurface() in OGLBlitLoops.c for more info on the following two lines
+    j2d_glRasterPos2i(0, 0);
+    j2d_glBitmap(0, 0, 0, 0, (GLfloat) x, (GLfloat) (-y), NULL);
+
+    j2d_glPixelZoom(1, -1); // in OpenGL image data is assumed to contain lines from bottom to top
+    j2d_glDrawPixels(ginfo->width, ginfo->height, GL_BGRA, GL_UNSIGNED_BYTE, ginfo->image);
+    j2d_glPixelZoom(1, 1); // restoring state
 
     return JNI_TRUE;
 }
 
+
 // see DrawGlyphList.c for more on this macro...
 #define FLOOR_ASSIGN(l, r) \
     if ((r)<0) (l) = ((int)floor(r)); else (l) = ((int)(r))
@@ -991,6 +1060,9 @@
 {
     int glyphCounter;
     GLuint dstTextureID = 0;
+    jboolean hasLCDGlyphs = JNI_FALSE;
+    jboolean lcdOpened = JNI_FALSE;
+    jint ox1 = INT_MIN;
 
     J2dTraceLn(J2D_TRACE_INFO, "OGLTR_DrawGlyphList");
 
@@ -1030,7 +1102,7 @@
     for (glyphCounter = 0; glyphCounter < totalGlyphs; glyphCounter++) {
         jint x, y;
         jfloat glyphx, glyphy;
-        jboolean grayscale, ok;
+        jboolean ok;
         GlyphInfo *ginfo = (GlyphInfo *)jlong_to_ptr(NEXT_LONG(images));
 
         if (ginfo == NULL) {
@@ -1040,8 +1112,6 @@
             break;
         }
 
-        grayscale = (ginfo->rowBytes == ginfo->width);
-
         if (usePositions) {
             jfloat posx = NEXT_FLOAT(positions);
             jfloat posy = NEXT_FLOAT(positions);
@@ -1062,7 +1132,11 @@
             continue;
         }
 
-        if (grayscale) {
+        if (ginfo->rowBytes == ginfo->width) {
+            if (lcdOpened) {
+                lcdOpened = JNI_FALSE;
+                j2d_glEnd();
+            }
             // grayscale or monochrome glyph data
             if (ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&
                 ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
@@ -1071,9 +1145,23 @@
             } else {
                 ok = OGLTR_DrawGrayscaleGlyphNoCache(oglc, ginfo, x, y);
             }
+        } else if (ginfo->rowBytes == ginfo->width * 4) {
+            if (lcdOpened) {
+                lcdOpened = JNI_FALSE;
+                j2d_glEnd();
+            }
+            // color glyph data
+            ok = OGLTR_DrawColorGlyphNoCache(oglc, ginfo, x, y);
         } else {
             // LCD-optimized glyph data
             jint rowBytesOffset = 0;
+            if (!hasLCDGlyphs) {
+                // Flush GPU buffers before processing first LCD glyph
+                hasLCDGlyphs = JNI_TRUE;
+                if (dstTextureID != 0) {
+                    j2d_glTextureBarrierNV();
+                }
+            }
 
             if (subPixPos) {
                 jint frac = (jint)((glyphx - x) * 3);
@@ -1083,6 +1171,15 @@
                 }
             }
 
+            // Flush GPU buffers before processing overlapping LCD glyphs on OSX
+            if (dstTextureID != 0 && ox1 > x) {
+                if (lcdOpened) {
+                    lcdOpened = JNI_FALSE;
+                    j2d_glEnd();
+                }
+                j2d_glTextureBarrierNV();
+            }
+
             if (rowBytesOffset == 0 &&
                 ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&
                 ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
@@ -1091,8 +1188,12 @@
                                                 ginfo, x, y,
                                                 glyphCounter, totalGlyphs,
                                                 rgbOrder, lcdContrast,
-                                                dstTextureID);
+                                                dstTextureID, &lcdOpened);
             } else {
+                if (lcdOpened) {
+                    lcdOpened = JNI_FALSE;
+                    j2d_glEnd();
+                }
                 ok = OGLTR_DrawLCDGlyphNoCache(oglc, dstOps,
                                                ginfo, x, y,
                                                rowBytesOffset,
@@ -1101,11 +1202,14 @@
             }
         }
 
+        ox1 = x + ginfo->width;
         if (!ok) {
             break;
         }
     }
-
+    if (lcdOpened) {
+        j2d_glEnd();
+    }
     OGLTR_DisableGlyphModeState();
 }
 
diff --git a/src/share/share.iml b/src/share/share.iml
new file mode 100644
index 0000000..a8d091b
--- /dev/null
+++ b/src/share/share.iml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/classes" isTestSource="false" />
+      <excludeFolder url="file://$MODULE_DIR$/classes/com/sun/jmx/snmp" />
+      <excludeFolder url="file://$MODULE_DIR$/classes/sun/dc" />
+      <excludeFolder url="file://$MODULE_DIR$/classes/sun/management/snmp" />
+    </content>
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="inheritedJdk" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/src/solaris/classes/sun/awt/X11/XCustomCursor.java b/src/solaris/classes/sun/awt/X11/XCustomCursor.java
index 0135e25..cb265c7 100644
--- a/src/solaris/classes/sun/awt/X11/XCustomCursor.java
+++ b/src/solaris/classes/sun/awt/X11/XCustomCursor.java
@@ -59,9 +59,18 @@
             long display = XToolkit.getDisplay();
             long root_window = XlibWrapper.RootWindow(display,
                     XlibWrapper.DefaultScreen(display));
+            preferredWidth = Math.abs(preferredWidth);
+            preferredHeight = Math.abs(preferredHeight);
 
-            XlibWrapper.XQueryBestCursor(display,root_window, Math.abs(preferredWidth),Math.abs(preferredHeight),XlibWrapper.larg1,XlibWrapper.larg2);
-            d = new Dimension(XlibWrapper.unsafe.getInt(XlibWrapper.larg1),XlibWrapper.unsafe.getInt(XlibWrapper.larg2));
+            XlibWrapper.XQueryBestCursor(display, root_window,
+                    preferredWidth, preferredHeight,
+                    XlibWrapper.larg1, XlibWrapper.larg2);
+
+            int cWidth = XlibWrapper.unsafe.getInt(XlibWrapper.larg1);
+            int cHeight = XlibWrapper.unsafe.getInt(XlibWrapper.larg2);
+            if (cWidth == 0) cWidth = preferredWidth;
+            if (cHeight == 0) cHeight = preferredHeight;
+            d = new Dimension(cWidth, cHeight);
         }
         finally {
             XToolkit.awtUnlock();
diff --git a/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java b/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java
index fa5c884..5166645 100644
--- a/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java
+++ b/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java
@@ -29,6 +29,9 @@
 import java.awt.event.ComponentEvent;
 import java.awt.event.InvocationEvent;
 import java.awt.event.WindowEvent;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 
 import sun.awt.IconInfo;
 import sun.util.logging.PlatformLogger;
@@ -48,10 +51,12 @@
     boolean insets_corrected;
 
     XIconWindow iconWindow;
-    WindowDimensions dimensions;
+    volatile WindowDimensions dimensions;
     XContentWindow content;
-    Insets currentInsets;
+    volatile Insets currentInsets;
     XFocusProxyWindow focusProxy;
+    static final Map<Class<?>,Insets> lastKnownInsets =
+                                   Collections.synchronizedMap(new HashMap<>());
 
     XDecoratedPeer(Window target) {
         super(target);
@@ -74,6 +79,9 @@
         winAttr.initialFocus = true;
 
         currentInsets = new Insets(0,0,0,0);
+        if (XWM.getWMID() == XWM.UNITY_COMPIZ_WM) {
+            currentInsets = lastKnownInsets.get(getClass());
+        }
         applyGuessedInsets();
 
         Rectangle bounds = (Rectangle)params.get(BOUNDS);
@@ -98,7 +106,7 @@
 
         // The lines that follow need to be in a postInit, so they
         // happen after the X window is created.
-        initResizability();
+        setResizable(winAttr.initialResizability);
         XWM.requestWMExtents(getWindow());
 
         content = XContentWindow.createContent(this);
@@ -122,7 +130,12 @@
 
     public void updateMinimumSize() {
         super.updateMinimumSize();
-        updateMinSizeHints();
+        XToolkit.awtLock();
+        try {
+            updateMinSizeHints();
+        } finally {
+            XToolkit.awtUnlock();
+        }
     }
 
     private void updateMinSizeHints() {
@@ -185,8 +198,13 @@
         if (log.isLoggable(PlatformLogger.Level.FINE)) {
             log.fine("Title is " + title);
         }
-        winAttr.title = title;
-        updateWMName();
+        XToolkit.awtLock();
+        try {
+            winAttr.title = title;
+            updateWMName();
+        } finally {
+            XToolkit.awtUnlock();
+        }
     }
 
     protected String getWMName() {
@@ -198,10 +216,10 @@
     }
 
     void updateWMName() {
-        super.updateWMName();
-        String name = getWMName();
         XToolkit.awtLock();
         try {
+            super.updateWMName();
+            String name = getWMName();
             if (name == null || name.trim().equals("")) {
                 name = "Java";
             }
@@ -287,17 +305,73 @@
     }
 
     private void resetWMSetInsets() {
-        wm_set_insets = null;
+        if (XWM.getWMID() != XWM.UNITY_COMPIZ_WM) {
+            currentInsets = new Insets(0, 0, 0, 0);
+            wm_set_insets = null;
+        } else {
+            insets_corrected = false;
+        }
     }
 
     public void handlePropertyNotify(XEvent xev) {
         super.handlePropertyNotify(xev);
 
         XPropertyEvent ev = xev.get_xproperty();
+        if( !insets_corrected && isReparented() &&
+                                         XWM.getWMID() == XWM.UNITY_COMPIZ_WM) {
+            int state = XWM.getWM().getState(this);
+            if ((state & Frame.MAXIMIZED_BOTH) ==  Frame.MAXIMIZED_BOTH) {
+                // Stop ignoring ConfigureNotify because no extents will be sent
+                // by WM for initially maximized decorated window.
+                // Re-request window bounds to ensure actual dimensions and
+                // notify the target with the initial size.
+                insets_corrected = true;
+                XlibWrapper.XConfigureWindow(XToolkit.getDisplay(),
+                                                             getWindow(), 0, 0);
+            }
+        }
         if (ev.get_atom() == XWM.XA_KDE_NET_WM_FRAME_STRUT.getAtom()
             || ev.get_atom() == XWM.XA_NET_FRAME_EXTENTS.getAtom())
         {
-            getWMSetInsets(XAtom.get(ev.get_atom()));
+            if (XWM.getWMID() != XWM.UNITY_COMPIZ_WM) {
+                getWMSetInsets(XAtom.get(ev.get_atom()));
+            } else {
+                if (!isReparented()) {
+                    return;
+                }
+                wm_set_insets = null;
+                Insets in = getWMSetInsets(XAtom.get(ev.get_atom()));
+                if (isNull(in)) {
+                    return;
+                }
+                if (!isEmbedded() && !isTargetUndecorated()) {
+                    lastKnownInsets.put(getClass(), in);
+                }
+                if (!in.equals(dimensions.getInsets())) {
+                    if (insets_corrected || isMaximized()) {
+                        currentInsets = in;
+                        insets_corrected = true;
+                        // insets were changed by WM. To handle this situation
+                        // re-request window bounds because the current
+                        // dimensions may be not actual as well.
+                        XlibWrapper.XConfigureWindow(XToolkit.getDisplay(),
+                                                             getWindow(), 0, 0);
+                    } else {
+                        // recalculate dimensions when window is just created
+                        // and the initially guessed insets were wrong
+                        handleCorrectInsets(in);
+                    }
+                } else if (!insets_corrected || !dimensions.isClientSizeSet()) {
+                    insets_corrected = true;
+                    // initial insets were guessed correctly. Re-request
+                    // frame bounds because they may be changed by WM if the
+                    // initial window position overlapped desktop's toolbars.
+                    // This should initiate the final ConfigureNotify upon which
+                    // the target will be notified with the final size.
+                    XlibWrapper.XConfigureWindow(XToolkit.getDisplay(),
+                                                             getWindow(), 0, 0);
+                }
+            }
         }
     }
 
@@ -309,57 +383,62 @@
             insLog.fine(xe.toString());
         }
         reparent_serial = xe.get_serial();
-        XToolkit.awtLock();
-        try {
-            long root = XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber());
+        long root = XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber());
 
-            if (isEmbedded()) {
-                setReparented(true);
-                insets_corrected = true;
+        if (isEmbedded()) {
+            setReparented(true);
+            insets_corrected = true;
+            return;
+        }
+        if (getDecorations() == XWindowAttributesData.AWT_DECOR_NONE) {
+            setReparented(true);
+            insets_corrected = true;
+            reshape(dimensions, SET_SIZE, false);
+        } else if (xe.get_parent() == root) {
+            configure_seen = false;
+            insets_corrected = false;
+
+            /*
+             * We can be repareted to root for two reasons:
+             *   . setVisible(false)
+             *   . WM exited
+             */
+            if (isVisible()) { /* WM exited */
+                /* Work around 4775545 */
+                XWM.getWM().unshadeKludge(this);
+                insLog.fine("- WM exited");
+            } else {
+                insLog.fine(" - reparent due to hide");
+            }
+        } else { /* reparented to WM frame, figure out our insets */
+            setReparented(true);
+            insets_corrected = false;
+            if (XWM.getWMID() == XWM.UNITY_COMPIZ_WM) {
                 return;
             }
-            Component t = (Component)target;
-            if (getDecorations() == XWindowAttributesData.AWT_DECOR_NONE) {
-                setReparented(true);
-                insets_corrected = true;
-                reshape(dimensions, SET_SIZE, false);
-            } else if (xe.get_parent() == root) {
-                configure_seen = false;
-                insets_corrected = false;
 
-                /*
-                 * We can be repareted to root for two reasons:
-                 *   . setVisible(false)
-                 *   . WM exited
-                 */
-                if (isVisible()) { /* WM exited */
-                    /* Work around 4775545 */
-                    XWM.getWM().unshadeKludge(this);
-                    insLog.fine("- WM exited");
-                } else {
-                    insLog.fine(" - reparent due to hide");
+            // Check if we have insets provided by the WM
+            Insets correctWM = getWMSetInsets(null);
+            if (correctWM != null) {
+                if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
+                    insLog.finer("wm-provided insets {0}", correctWM);
                 }
-            } else { /* reparented to WM frame, figure out our insets */
-                setReparented(true);
-                insets_corrected = false;
-
-                // Check if we have insets provided by the WM
-                Insets correctWM = getWMSetInsets(null);
+                // If these insets are equal to our current insets - no actions are necessary
+                Insets dimInsets = dimensions.getInsets();
+                if (correctWM.equals(dimInsets)) {
+                    insLog.finer("Insets are the same as estimated - no additional reshapes necessary");
+                    no_reparent_artifacts = true;
+                    insets_corrected = true;
+                    applyGuessedInsets();
+                    return;
+                }
+            } else {
+                correctWM = XWM.getWM().getInsets(this, xe.get_window(), xe.get_parent());
                 if (correctWM != null) {
-                    if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
-                        insLog.finer("wm-provided insets {0}", correctWM);
-                    }
-                    // If these insets are equal to our current insets - no actions are necessary
-                    Insets dimInsets = dimensions.getInsets();
-                    if (correctWM.equals(dimInsets)) {
-                        insLog.finer("Insets are the same as estimated - no additional reshapes necessary");
-                        no_reparent_artifacts = true;
-                        insets_corrected = true;
-                        applyGuessedInsets();
-                        return;
-                    }
-                } else {
-                    correctWM = XWM.getWM().getInsets(this, xe.get_window(), xe.get_parent());
+                    correctWM = copy(correctWM);
+                }
+
+                if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
 
                     if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
                         if (correctWM != null) {
@@ -369,71 +448,66 @@
                         }
                     }
                 }
-
-                if (correctWM != null) {
-                    handleCorrectInsets(correctWM);
-                }
             }
-        } finally {
-            XToolkit.awtUnlock();
+
+            if (correctWM != null) {
+                handleCorrectInsets(correctWM);
+            }
+        }
+
+    }
+
+    private void handleCorrectInsets(Insets correctWM) {
+        /*
+         * Ok, now see if we need adjust window size because
+         * initial insets were wrong (most likely they were).
+         */
+        Insets correction = difference(correctWM, currentInsets);
+        if (insLog.isLoggable(PlatformLogger.Level.FINEST)) {
+            insLog.finest("Corrention {0}", correction);
+        }
+        if (!isNull(correction)) {
+            currentInsets = copy(correctWM);
+            applyGuessedInsets();
+
+            //Fix for 6318109: PIT: Min Size is not honored properly when a
+            //smaller size is specified in setSize(), XToolkit
+            //update minimum size hints
+            updateMinSizeHints();
+        }
+        if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
+            insLog.finer("Dimensions before reparent: " + dimensions);
+        }
+        WindowDimensions newDimensions = new WindowDimensions(dimensions);
+        newDimensions.setInsets(getRealInsets());
+        dimensions = newDimensions;
+        insets_corrected = true;
+
+        if (isMaximized()) {
+            return;
+        }
+
+        /*
+         * If this window has been sized by a pack() we need
+         * to keep the interior geometry intact.  Since pack()
+         * computed width and height with wrong insets, we
+         * must adjust the target dimensions appropriately.
+         */
+        if ((getHints().get_flags() & (XUtilConstants.USPosition | XUtilConstants.PPosition)) != 0) {
+            reshape(dimensions, SET_BOUNDS, false);
+        } else {
+            reshape(dimensions, SET_SIZE, false);
         }
     }
 
-    protected void handleCorrectInsets(Insets correctWM) {
-        XToolkit.awtLock();
-        try {
-            /*
-             * Ok, now see if we need adjust window size because
-             * initial insets were wrong (most likely they were).
-             */
-            Insets correction = difference(correctWM, currentInsets);
-            if (insLog.isLoggable(PlatformLogger.Level.FINEST)) {
-                insLog.finest("Corrention {0}", correction);
-            }
-            if (!isNull(correction)) {
-                currentInsets = copy(correctWM);
-                applyGuessedInsets();
-
-                //Fix for 6318109: PIT: Min Size is not honored properly when a
-                //smaller size is specified in setSize(), XToolkit
-                //update minimum size hints
-                updateMinSizeHints();
-            }
-            if (insLog.isLoggable(PlatformLogger.Level.FINER)) {
-                insLog.finer("Dimensions before reparent: " + dimensions);
-            }
-
-            dimensions.setInsets(getRealInsets());
-            insets_corrected = true;
-
-            if (isMaximized()) {
-                return;
-            }
-
-            /*
-             * If this window has been sized by a pack() we need
-             * to keep the interior geometry intact.  Since pack()
-             * computed width and height with wrong insets, we
-             * must adjust the target dimensions appropriately.
-             */
-            if ((getHints().get_flags() & (XUtilConstants.USPosition | XUtilConstants.PPosition)) != 0) {
-                reshape(dimensions, SET_BOUNDS, false);
-            } else {
-                reshape(dimensions, SET_SIZE, false);
-            }
-        } finally {
-            XToolkit.awtUnlock();
-        }
-    }
-
-    public void handleMoved(WindowDimensions dims) {
+    void handleMoved(WindowDimensions dims) {
         Point loc = dims.getLocation();
         AWTAccessor.getComponentAccessor().setLocation((Component)target, loc.x, loc.y);
         postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED));
     }
 
 
-    protected Insets guessInsets() {
+    private Insets guessInsets() {
         if (isEmbedded() || isTargetUndecorated()) {
             return new Insets(0, 0, 0, 0);
         } else {
@@ -444,6 +518,9 @@
                 Insets res = getWMSetInsets(null);
                 if (res == null) {
                     res = XWM.getWM().guessInsets(this);
+                    if (res != null) {
+                        res = copy(res);
+                    }
                 }
                 return res;
             }
@@ -455,16 +532,7 @@
         currentInsets = copy(guessed);
     }
 
-    public void revalidate() {
-        XToolkit.executeOnEventHandlerThread(target, new Runnable() {
-                public void run() {
-                    target.invalidate();
-                    target.validate();
-                }
-            });
-    }
-
-    Insets getRealInsets() {
+    private Insets getRealInsets() {
         if (isNull(currentInsets)) {
             applyGuessedInsets();
         }
@@ -501,7 +569,7 @@
 
     // Coordinates are that of the target
     // Called only on Toolkit thread
-    public void reshape(WindowDimensions newDimensions, int op,
+    private void reshape(WindowDimensions newDimensions, int op,
                         boolean userReshape)
     {
         if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
@@ -522,81 +590,77 @@
             }
             newDimensions = new WindowDimensions(newBounds, insets, newDimensions.isClientSizeSet());
         }
-        XToolkit.awtLock();
-        try {
-            if (!isReparented() || !isVisible()) {
-                if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
-                    insLog.fine("- not reparented({0}) or not visible({1}), default reshape",
-                           Boolean.valueOf(isReparented()), Boolean.valueOf(visible));
-                }
 
-                // Fix for 6323293.
-                // This actually is needed to preserve compatibility with previous releases -
-                // some of licensees are expecting componentMoved event on invisible one while
-                // its location changes.
-                Point oldLocation = getLocation();
-
-                Point newLocation = new Point(AWTAccessor.getComponentAccessor().getX((Component)target),
-                                              AWTAccessor.getComponentAccessor().getY((Component)target));
-
-                if (!newLocation.equals(oldLocation)) {
-                    handleMoved(newDimensions);
-                }
-
-                dimensions = new WindowDimensions(newDimensions);
-                updateSizeHints(dimensions);
-                Rectangle client = dimensions.getClientRect();
-                checkShellRect(client);
-                setShellBounds(client);
-                if (content != null &&
-                    !content.getSize().equals(newDimensions.getSize()))
-                {
-                    reconfigureContentWindow(newDimensions);
-                }
-                return;
+        if (!isReparented() || !isVisible()) {
+            if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
+                insLog.fine("- not reparented({0}) or not visible({1}), default reshape",
+                        Boolean.valueOf(isReparented()), Boolean.valueOf(visible));
             }
 
-            int wm = XWM.getWMID();
-            updateChildrenSizes();
-            applyGuessedInsets();
 
-            Rectangle shellRect = newDimensions.getClientRect();
 
-            if (gravityBug()) {
-                Insets in = newDimensions.getInsets();
-                shellRect.translate(in.left, in.top);
+            // Fix for 6323293.
+            // This actually is needed to preserve compatibility with previous releases -
+            // some of licensees are expecting componentMoved event on invisible one while
+            // its location changes.
+            Point oldLocation = getLocation();
+
+            Point newLocation = new Point(AWTAccessor.getComponentAccessor().getX(target),
+                                          AWTAccessor.getComponentAccessor().getY(target));
+
+            if (!newLocation.equals(oldLocation)) {
+                handleMoved(newDimensions);
             }
 
-            if ((op & NO_EMBEDDED_CHECK) == 0 && isEmbedded()) {
-                shellRect.setLocation(0, 0);
+            dimensions = new WindowDimensions(newDimensions);
+            updateSizeHints(dimensions);
+            Rectangle client = dimensions.getClientRect();
+            checkShellRect(client);
+            setShellBounds(client);
+            if (content != null &&
+                !content.getSize().equals(newDimensions.getSize()))
+            {
+                reconfigureContentWindow(newDimensions);
             }
-
-            checkShellRectSize(shellRect);
-            if (!isEmbedded()) {
-                checkShellRectPos(shellRect);
-            }
-
-            op = op & ~NO_EMBEDDED_CHECK;
-
-            if (op == SET_LOCATION) {
-                setShellPosition(shellRect);
-            } else if (isResizable()) {
-                if (op == SET_BOUNDS) {
-                    setShellBounds(shellRect);
-                } else {
-                    setShellSize(shellRect);
-                }
-            } else {
-                XWM.setShellNotResizable(this, newDimensions, shellRect, true);
-                if (op == SET_BOUNDS) {
-                    setShellPosition(shellRect);
-                }
-            }
-
-            reconfigureContentWindow(newDimensions);
-        } finally {
-            XToolkit.awtUnlock();
+            return;
         }
+
+        updateChildrenSizes();
+        applyGuessedInsets();
+
+        Rectangle shellRect = newDimensions.getClientRect();
+
+        if (gravityBug()) {
+            Insets in = newDimensions.getInsets();
+            shellRect.translate(in.left, in.top);
+        }
+
+        if ((op & NO_EMBEDDED_CHECK) == 0 && isEmbedded()) {
+            shellRect.setLocation(0, 0);
+        }
+
+        checkShellRectSize(shellRect);
+        if (!isEmbedded()) {
+            checkShellRectPos(shellRect);
+        }
+
+        op = op & ~NO_EMBEDDED_CHECK;
+
+        if (op == SET_LOCATION) {
+            setShellPosition(shellRect);
+        } else if (isResizable()) {
+            if (op == SET_BOUNDS) {
+                setShellBounds(shellRect);
+            } else {
+                setShellSize(shellRect);
+            }
+        } else {
+            XWM.setShellNotResizable(this, newDimensions, shellRect, true);
+            if (op == SET_BOUNDS) {
+                setShellPosition(shellRect);
+            }
+        }
+        reconfigureContentWindow(newDimensions);
     }
 
     /**
@@ -605,8 +669,6 @@
     private void reshape(int x, int y, int width, int height, int operation,
                          boolean userReshape)
     {
-        Rectangle newRec;
-        boolean setClient = false;
         WindowDimensions dims = new WindowDimensions(dimensions);
         switch (operation & (~NO_EMBEDDED_CHECK)) {
           case SET_LOCATION:
@@ -649,7 +711,12 @@
      */
     public void setBounds(int x, int y, int width, int height, int op) {
         // TODO: Rewrite with WindowDimensions
-        reshape(x, y, width, height, op, true);
+        XToolkit.awtLock();
+        try {
+            reshape(x, y, width, height, op, true);
+        } finally {
+            XToolkit.awtUnlock();
+        }
         validateSurface();
     }
 
@@ -664,6 +731,9 @@
 
     boolean no_reparent_artifacts = false;
     public void handleConfigureNotifyEvent(XEvent xev) {
+        if (XWM.getWMID() == XWM.UNITY_COMPIZ_WM && !insets_corrected) {
+            return;
+        }
         assert (SunToolkit.isAWTLockHeldByCurrentThread());
         XConfigureEvent xe = xev.get_xconfigure();
         if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
@@ -785,80 +855,71 @@
         checkShellRectPos(shellRect);
     }
 
-    public void setShellBounds(Rectangle rec) {
+    private void setShellBounds(Rectangle rec) {
         if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
             insLog.fine("Setting shell bounds on " + this + " to " + rec);
         }
-        XToolkit.awtLock();
-        try {
-            updateSizeHints(rec.x, rec.y, rec.width, rec.height);
-            XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), rec.width, rec.height);
-            XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), rec.x, rec.y);
-        }
-        finally {
-            XToolkit.awtUnlock();
-        }
+        updateSizeHints(rec.x, rec.y, rec.width, rec.height);
+        XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), getShell(),
+                rec.x, rec.y, rec.width, rec.height);
     }
-    public void setShellSize(Rectangle rec) {
+
+    private void setShellSize(Rectangle rec) {
         if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
             insLog.fine("Setting shell size on " + this + " to " + rec);
         }
-        XToolkit.awtLock();
-        try {
-            updateSizeHints(rec.x, rec.y, rec.width, rec.height);
-            XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), rec.width, rec.height);
-        }
-        finally {
-            XToolkit.awtUnlock();
-        }
+        updateSizeHints(rec.x, rec.y, rec.width, rec.height);
+        XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), rec.width, rec.height);
     }
-    public void setShellPosition(Rectangle rec) {
+
+    private void setShellPosition(Rectangle rec) {
         if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
             insLog.fine("Setting shell position on " + this + " to " + rec);
         }
-        XToolkit.awtLock();
-        try {
-            updateSizeHints(rec.x, rec.y, rec.width, rec.height);
-            XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), rec.x, rec.y);
-        }
-        finally {
-            XToolkit.awtUnlock();
-        }
+        updateSizeHints(rec.x, rec.y, rec.width, rec.height);
+        XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), rec.x, rec.y);
     }
 
-    void initResizability() {
-        setResizable(winAttr.initialResizability);
-    }
     public void setResizable(boolean resizable) {
-        int fs = winAttr.functions;
-        if (!isResizable() && resizable) {
-            currentInsets = new Insets(0, 0, 0, 0);
-            resetWMSetInsets();
-            if (!isEmbedded()) {
-                setReparented(false);
+        XToolkit.awtLock();
+        try {
+            int fs = winAttr.functions;
+            if (!isResizable() && resizable) {
+                resetWMSetInsets();
+                if (!isEmbedded()) {
+                    setReparented(false);
+                }
+                winAttr.isResizable = resizable;
+                if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) {
+                    fs &= ~(MWMConstants.MWM_FUNC_RESIZE
+                          | MWMConstants.MWM_FUNC_MAXIMIZE);
+                } else {
+                    fs |= (MWMConstants.MWM_FUNC_RESIZE
+                         | MWMConstants.MWM_FUNC_MAXIMIZE);
+                }
+                winAttr.functions = fs;
+                XWM.setShellResizable(this);
+            } else if (isResizable() && !resizable) {
+                resetWMSetInsets();
+                if (!isEmbedded()) {
+                    setReparented(false);
+                }
+                winAttr.isResizable = resizable;
+                if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) {
+                    fs |= (MWMConstants.MWM_FUNC_RESIZE
+                         | MWMConstants.MWM_FUNC_MAXIMIZE);
+                } else {
+                    fs &= ~(MWMConstants.MWM_FUNC_RESIZE
+                          | MWMConstants.MWM_FUNC_MAXIMIZE);
+                }
+                winAttr.functions = fs;
+                XWM.setShellNotResizable(this, dimensions,
+                        XWM.getWMID() == XWM.UNITY_COMPIZ_WM && configure_seen ?
+                        dimensions.getScreenBounds() :
+                        dimensions.getBounds(), false);
             }
-            winAttr.isResizable = resizable;
-            if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) {
-                fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE);
-            } else {
-                fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE);
-            }
-            winAttr.functions = fs;
-            XWM.setShellResizable(this);
-        } else if (isResizable() && !resizable) {
-            currentInsets = new Insets(0, 0, 0, 0);
-            resetWMSetInsets();
-            if (!isEmbedded()) {
-                setReparented(false);
-            }
-            winAttr.isResizable = resizable;
-            if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) {
-                fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE);
-            } else {
-                fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE);
-            }
-            winAttr.functions = fs;
-            XWM.setShellNotResizable(this, dimensions, dimensions.getBounds(), false);
+        } finally {
+            XToolkit.awtUnlock();
         }
     }
 
@@ -913,17 +974,16 @@
         try {
             if (configure_seen) {
                 return toGlobal(0,0);
-            } else {
-                Point location = target.getLocation();
-                if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
-                    insLog.fine("getLocationOnScreen {0} not reparented: {1} ",
-                                this, location);
-                }
-                return location;
             }
         } finally {
             XToolkit.awtUnlock();
         }
+        Point location = target.getLocation();
+        if (insLog.isLoggable(PlatformLogger.Level.FINE)) {
+            insLog.fine("getLocationOnScreen {0} not reparented: {1} ",
+                        this, location);
+        }
+        return location;
     }
 
 
@@ -1011,7 +1071,22 @@
         if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
             focusLog.fine("WM_TAKE_FOCUS on {0}", this);
         }
-        requestWindowFocus(cl.get_data(1), true);
+
+        if (XWM.getWMID() == XWM.UNITY_COMPIZ_WM) {
+            // JDK-8159460
+            Window focusedWindow = XKeyboardFocusManagerPeer.getInstance()
+                    .getCurrentFocusedWindow();
+            Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow);
+            if (activeWindow != target) {
+                requestWindowFocus(cl.get_data(1), true);
+            } else {
+                WindowEvent we = new WindowEvent(focusedWindow,
+                        WindowEvent.WINDOW_GAINED_FOCUS);
+                sendEvent(we);
+            }
+        } else {
+            requestWindowFocus(cl.get_data(1), true);
+        }
     }
 
     /**
@@ -1042,7 +1117,7 @@
         return focusProxy;
     }
 
-    public void handleQuit() {
+    private void handleQuit() {
         postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_CLOSING));
     }
 
@@ -1161,6 +1236,7 @@
                 return true;
             }
         }
+
         if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
             focusLog.fine("Requesting focus to " + (this == toFocus ? "this window" : toFocus));
         }
diff --git a/src/solaris/classes/sun/awt/X11/XWM.java b/src/solaris/classes/sun/awt/X11/XWM.java
index 33776d7..12d13d7 100644
--- a/src/solaris/classes/sun/awt/X11/XWM.java
+++ b/src/solaris/classes/sun/awt/X11/XWM.java
@@ -104,7 +104,8 @@
         COMPIZ_WM = 12,
         LG3D_WM = 13,
         CWM_WM = 14,
-        MUTTER_WM = 15;
+        MUTTER_WM = 15,
+        UNITY_COMPIZ_WM = 16;
     public String toString() {
         switch  (WMID) {
           case NO_WM:
@@ -129,6 +130,8 @@
               return "Metacity";
           case COMPIZ_WM:
               return "Compiz";
+            case UNITY_COMPIZ_WM:
+              return "Unity Compiz";
           case LG3D_WM:
               return "LookingGlass";
           case CWM_WM:
@@ -572,6 +575,10 @@
         return isNetWMName("compiz");
     }
 
+    static boolean isUnityCompiz() {
+        return isNetWMName("Compiz");
+    }
+
     static boolean isLookingGlass() {
         return isNetWMName("LG3D");
     }
@@ -790,6 +797,8 @@
                 awt_wmgr = CWM_WM;
             } else if (doIsIceWM && isIceWM()) {
                 awt_wmgr = XWM.ICE_WM;
+            } else if (isUnityCompiz()) {
+                awt_wmgr = XWM.UNITY_COMPIZ_WM;
             }
             /*
              * We don't check for legacy WM when we already know that WM
@@ -1020,8 +1029,14 @@
         }
         XToolkit.awtLock();
         try {
-            Rectangle shellBounds = window.getShellBounds();
-            shellBounds.translate(-window.currentInsets.left, -window.currentInsets.top);
+            Rectangle shellBounds;
+            if (getWMID() != UNITY_COMPIZ_WM) {
+                shellBounds = window.getShellBounds();
+                shellBounds.translate(-window.currentInsets.left,
+                                      -window.currentInsets.top);
+            } else {
+                shellBounds = window.getDimensions().getScreenBounds();
+            }
             window.updateSizeHints(window.getDimensions());
             requestWMExtents(window.getWindow());
             XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), window.getShell(),
@@ -1340,6 +1355,9 @@
               case LG3D_WM:
                   res = zeroInsets;
                   break;
+              case UNITY_COMPIZ_WM:
+                  res = new Insets(35, 1, 1, 1);
+                  break;
               case MOTIF_WM:
               case OPENLOOK_WM:
               default:
diff --git a/src/solaris/classes/sun/awt/X11/XWindow.java b/src/solaris/classes/sun/awt/X11/XWindow.java
index d455979..6fb6aac 100644
--- a/src/solaris/classes/sun/awt/X11/XWindow.java
+++ b/src/solaris/classes/sun/awt/X11/XWindow.java
@@ -560,11 +560,15 @@
     }
 
     public void postPaintEvent(Component target, int x, int y, int w, int h) {
-        PaintEvent event = PaintEventDispatcher.getPaintEventDispatcher().
-            createPaintEvent(target, x, y, w, h);
-        if (event != null) {
-            postEventToEventQueue(event);
-        }
+        postEventToEventQueue(new InvocationEvent(target, new Runnable() {
+            public void run() {
+                PaintEvent event = PaintEventDispatcher.getPaintEventDispatcher().
+                        createPaintEvent(target, x, y, w, h);
+                if (event != null) {
+                    postEventToEventQueue(event);
+                }
+            }
+        }));
     }
 
     static int getModifiers(int state, int button, int keyCode) {
diff --git a/src/solaris/classes/sun/awt/X11/XWindowPeer.java b/src/solaris/classes/sun/awt/X11/XWindowPeer.java
index 0930293..a2896ab 100644
--- a/src/solaris/classes/sun/awt/X11/XWindowPeer.java
+++ b/src/solaris/classes/sun/awt/X11/XWindowPeer.java
@@ -775,6 +775,7 @@
                 case XWM.METACITY_WM:
                 case XWM.MUTTER_WM:
                 case XWM.SAWFISH_WM:
+                case XWM.UNITY_COMPIZ_WM:
                 {
                     Point xlocation = queryXLocation();
                     if (log.isLoggable(PlatformLogger.Level.FINE)) {
diff --git a/src/solaris/classes/sun/awt/fontconfigs/linux.fontconfig.properties b/src/solaris/classes/sun/awt/fontconfigs/linux.fontconfig.properties
new file mode 100644
index 0000000..cb8a536
--- /dev/null
+++ b/src/solaris/classes/sun/awt/fontconfigs/linux.fontconfig.properties
@@ -0,0 +1,42 @@
+# Version
+
+version=1
+
+# Component Font Mappings
+
+
+serif.plain.latin-1=-b&h-droidserif-medium-r-normal--*-%d-*-*-p-*-iso8859-1
+serif.bold.latin-1=-b&h-droidserif-demibold-r-normal--*-%d-*-*-p-*-iso8859-1
+serif.italic.latin-1=-b&h-droidserif-medium-i-normal--*-%d-*-*-p-*-iso8859-1
+serif.bolditalic.latin-1=-b&h-droidserif-demibold-i-normal--*-%d-*-*-p-*-iso8859-1
+
+sansserif.plain.latin-1=-b&h-droidsans-medium-r-normal-sans-*-%d-*-*-p-*-iso8859-1
+sansserif.bold.latin-1=-b&h-droidsans-bold-r-normal-sans-*-%d-*-*-p-*-iso8859-1
+sansserif.italic.latin-1=-b&h-droidsans-medium-i-normal-sans-*-%d-*-*-p-*-iso8859-1
+sansserif.bolditalic.latin-1=-b&h-droidsans-bold-i-normal-sans-*-%d-*-*-p-*-iso8859-1
+
+monospaced.plain.latin-1=-b&h-droidsansmono-medium-r-normal-sans-*-%d-*-*-m-*-iso8859-1
+monospaced.bold.latin-1=-b&h-droidsansmono-bold-r-normal-sans-*-%d-*-*-m-*-iso8859-1
+monospaced.italic.latin-1=-b&h-droidsansmono-medium-i-normal-sans-*-%d-*-*-m-*-iso8859-1
+monospaced.bolditalic.latin-1=-b&h-droidsansmono-bold-i-normal-sans-*-%d-*-*-m-*-iso8859-1
+
+dialog.plain.latin-1=-b&h-droidsans-medium-r-normal-sans-*-%d-*-*-p-*-iso8859-1
+dialog.bold.latin-1=-b&h-droidsans-bold-r-normal-sans-*-%d-*-*-p-*-iso8859-1
+dialog.italic.latin-1=-b&h-droidsans-medium-i-normal-sans-*-%d-*-*-p-*-iso8859-1
+dialog.bolditalic.latin-1=-b&h-droidsans-bold-i-normal-sans-*-%d-*-*-p-*-iso8859-1
+
+dialoginput.plain.latin-1=-b&h-droidsansmono-medium-r-normal-sans-*-%d-*-*-m-*-iso8859-1
+dialoginput.bold.latin-1=-b&h-droidsansmono-bold-r-normal-sans-*-%d-*-*-m-*-iso8859-1
+dialoginput.italic.latin-1=-b&h-droidsansmono-medium-i-normal-sans-*-%d-*-*-m-*-iso8859-1
+dialoginput.bolditalic.latin-1=-b&h-droidsansmono-bold-i-normal-sans-*-%d-*-*-m-*-iso8859-1
+
+# Search Sequences
+
+sequence.allfonts=latin-1
+
+# Exclusion Ranges
+
+# Font File Names
+
+
+
diff --git a/src/solaris/classes/sun/font/XRTextRenderer.java b/src/solaris/classes/sun/font/XRTextRenderer.java
index e4ee3cf..93cce2e 100644
--- a/src/solaris/classes/sun/font/XRTextRenderer.java
+++ b/src/solaris/classes/sun/font/XRTextRenderer.java
@@ -26,6 +26,7 @@
 package sun.font;
 
 import sun.awt.*;
+import sun.java2d.InvalidPipeException;
 import sun.java2d.SunGraphics2D;
 import sun.java2d.pipe.GlyphListPipe;
 import sun.java2d.xr.*;
@@ -61,8 +62,12 @@
 
         try {
             SunToolkit.awtLock();
-
-            XRSurfaceData x11sd = (XRSurfaceData) sg2d.surfaceData;
+            XRSurfaceData x11sd;
+            try {
+                x11sd = (XRSurfaceData) sg2d.surfaceData;
+            } catch (ClassCastException e) {
+                throw new InvalidPipeException("wrong surface data type: " + sg2d.surfaceData);
+            }
             x11sd.validateAsDestination(null, sg2d.getCompClip());
             x11sd.maskBuffer.validateCompositeState(sg2d.composite, sg2d.transform, sg2d.paint, sg2d);
 
@@ -83,7 +88,7 @@
             int activeGlyphSet = cachedGlyphs[0].getGlyphSet();
 
             int eltIndex = -1;
-            gl.getBounds();
+            gl.startGlyphIteration();
             float[] positions = gl.getPositions();
             for (int i = 0; i < gl.getNumGlyphs(); i++) {
                 gl.setGlyphIndex(i);
diff --git a/src/solaris/classes/sun/java2d/xr/XRMaskFill.java b/src/solaris/classes/sun/java2d/xr/XRMaskFill.java
index 8be8457..6d484ff 100644
--- a/src/solaris/classes/sun/java2d/xr/XRMaskFill.java
+++ b/src/solaris/classes/sun/java2d/xr/XRMaskFill.java
@@ -99,7 +99,12 @@
         try {
             SunToolkit.awtLock();
 
-            XRSurfaceData x11sd = (XRSurfaceData) sData;
+            XRSurfaceData x11sd;
+            try {
+                x11sd = (XRSurfaceData) sData;
+            } catch (ClassCastException e) {
+                throw new InvalidPipeException("wrong surface data type: " + sData);
+            }
             x11sd.validateAsDestination(null, sg2d.getCompClip());
 
             XRCompositeManager maskBuffer = x11sd.maskBuffer;
diff --git a/src/solaris/classes/sun/java2d/xr/XRPMBlitLoops.java b/src/solaris/classes/sun/java2d/xr/XRPMBlitLoops.java
index 6a2f714..9109680 100644
--- a/src/solaris/classes/sun/java2d/xr/XRPMBlitLoops.java
+++ b/src/solaris/classes/sun/java2d/xr/XRPMBlitLoops.java
@@ -127,7 +127,10 @@
             vImgSurfaceType = SurfaceType.IntArgbPre;
         }
 
-        if (vImg == null || vImg.getWidth() < w || vImg.getHeight() < h) {
+        if (vImg == null || vImg.getWidth() < w || vImg.getHeight() < h ||
+            // Sometimes we get volatile image of wrong dest surface type, so recreating it
+            !(vImg.getDestSurface() instanceof XRSurfaceData))
+        {
             if (vImg != null) {
                 vImg.flush();
             }
@@ -145,6 +148,11 @@
         }
 
         Blit swToSurfaceBlit = Blit.getFromCache(src.getSurfaceType(), CompositeType.SrcNoEa, vImgSurfaceType);
+
+        if (!(vImg.getDestSurface() instanceof XRSurfaceData)) {
+            throw new InvalidPipeException("wrong surface data type: " + vImg.getDestSurface());
+        }
+
         XRSurfaceData vImgSurface = (XRSurfaceData) vImg.getDestSurface();
         swToSurfaceBlit.Blit(src, vImgSurface, AlphaComposite.Src, null,
                              sx, sy, 0, 0, w, h);
diff --git a/src/solaris/native/sun/awt/gtk2_interface.c b/src/solaris/native/sun/awt/gtk2_interface.c
index 1ba9beb..efc421e 100644
--- a/src/solaris/native/sun/awt/gtk2_interface.c
+++ b/src/solaris/native/sun/awt/gtk2_interface.c
@@ -2507,14 +2507,14 @@
 
     return result;
 }
-/*
+
 jobject get_integer_property(JNIEnv *env, GtkSettings* settings, const gchar* key)
 {
     gint    intval = NULL;
 
     (*fp_g_object_get)(settings, key, &intval, NULL);
     return create_Integer(env, intval);
-}*/
+}
 
 jobject gtk2_get_setting(JNIEnv *env, Setting property)
 {
@@ -2526,6 +2526,8 @@
             return get_string_property(env, settings, "gtk-font-name");
         case GTK_ICON_SIZES:
             return get_string_property(env, settings, "gtk-icon-sizes");
+        case GTK_XFT_DPI:
+            return get_integer_property(env, settings, "gtk-xft-dpi");
     }
 
     return NULL;
diff --git a/src/solaris/native/sun/awt/gtk2_interface.h b/src/solaris/native/sun/awt/gtk2_interface.h
index 3498e38..6fb1e82 100644
--- a/src/solaris/native/sun/awt/gtk2_interface.h
+++ b/src/solaris/native/sun/awt/gtk2_interface.h
@@ -140,7 +140,8 @@
 typedef enum _Setting
 {
     GTK_FONT_NAME,
-    GTK_ICON_SIZES
+    GTK_ICON_SIZES,
+    GTK_XFT_DPI
 } Setting;
 
 /* GTK types, here to eliminate need for GTK headers at compile time */
diff --git a/src/solaris/native/sun/font/X11TextRenderer.c b/src/solaris/native/sun/font/X11TextRenderer.c
index 3aa9530..e1f64c5 100644
--- a/src/solaris/native/sun/font/X11TextRenderer.c
+++ b/src/solaris/native/sun/font/X11TextRenderer.c
@@ -57,11 +57,13 @@
      jlong dstData, jlong xgc, jobject clip,
      jobject glyphlist)
 {
+    jint glyphCount;
     GlyphBlitVector* gbv;
     SurfaceDataBounds bounds;
     Region_GetBounds(env, clip, &bounds);
 
-    if ((gbv = setupBlitVector(env, glyphlist)) == NULL) {
+    glyphCount =  (*env)->GetIntField(env, glyphlist, sunFontIDs.glyphListLen);
+    if ((gbv = setupBlitVector(env, glyphlist, 0, glyphCount)) == NULL) {
         return;
     }
     if (!RefineBounds(gbv, &bounds)) {
diff --git a/src/solaris/native/sun/xawt/XlibWrapper.c b/src/solaris/native/sun/xawt/XlibWrapper.c
index f1d6318..8f5e05b 100644
--- a/src/solaris/native/sun/xawt/XlibWrapper.c
+++ b/src/solaris/native/sun/xawt/XlibWrapper.c
@@ -1022,6 +1022,25 @@
     status  =  XQueryBestCursor((Display *) jlong_to_ptr(display), (Drawable) drawable, width,height,
                                 (unsigned int *) jlong_to_ptr(width_return), (unsigned int *) jlong_to_ptr(height_return));
 
+    static int xQueryBestCursorLogEnabled = JNI_FALSE;
+    static int xQueryBestCursorLogNotChecked = JNI_TRUE;
+
+    if (xQueryBestCursorLogNotChecked) {
+        xQueryBestCursorLogNotChecked = JNI_FALSE;
+        char *logSetting = getenv("OPENJDK_LOG_XQUERYBESTCURSOR");
+
+        if (logSetting != NULL && !strcmp(logSetting, "yes")) {
+             xQueryBestCursorLogEnabled = JNI_TRUE;
+        }
+    }
+
+    if (xQueryBestCursorLogEnabled) {
+        fprintf(stderr, "LOG_XQueryBestCursor(%p, %lu, %d %d) : "
+                        "w=%ld h=%ld s=%d \n", display, drawable, width, height,
+                        *((unsigned int *) jlong_to_ptr(width_return)), 
+                        *((unsigned int *) jlong_to_ptr(height_return)), status);
+    } 
+
     if (status == 0) return JNI_FALSE;
     else return JNI_TRUE;
 }
diff --git a/src/windows/classes/sun/awt/Win32GraphicsConfig.java b/src/windows/classes/sun/awt/Win32GraphicsConfig.java
index 2ec0d1b..4773934 100644
--- a/src/windows/classes/sun/awt/Win32GraphicsConfig.java
+++ b/src/windows/classes/sun/awt/Win32GraphicsConfig.java
@@ -106,7 +106,7 @@
     /**
      * Return the graphics device associated with this configuration.
      */
-    public GraphicsDevice getDevice() {
+    public Win32GraphicsDevice getDevice() {
         return screen;
     }
 
@@ -182,7 +182,9 @@
      * For image buffers, this Transform will be the Identity transform.
      */
     public AffineTransform getDefaultTransform() {
-        return new AffineTransform();
+        double scaleX = screen.getDefaultScaleX();
+        double scaleY = screen.getDefaultScaleY();
+        return AffineTransform.getScaleInstance(scaleX, scaleY);
     }
 
     /**
diff --git a/src/windows/classes/sun/awt/Win32GraphicsDevice.java b/src/windows/classes/sun/awt/Win32GraphicsDevice.java
index a380685..466bb07 100644
--- a/src/windows/classes/sun/awt/Win32GraphicsDevice.java
+++ b/src/windows/classes/sun/awt/Win32GraphicsDevice.java
@@ -37,13 +37,19 @@
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 import java.awt.event.WindowListener;
+import java.awt.geom.Point2D;
 import java.awt.image.ColorModel;
 import java.util.ArrayList;
 import java.util.Vector;
 import java.awt.peer.WindowPeer;
+import java.security.AccessController;
 import sun.awt.windows.WWindowPeer;
+import sun.java2d.SunGraphicsEnvironment;
 import sun.java2d.opengl.WGLGraphicsConfig;
 import sun.java2d.windows.WindowsFlags;
+import sun.security.action.GetPropertyAction;
+import static sun.awt.Win32GraphicsEnvironment.debugScaleX;
+import static sun.awt.Win32GraphicsEnvironment.debugScaleY;
 
 /**
  * This is an implementation of a GraphicsDevice object for a single
@@ -81,6 +87,9 @@
     // activation/deactivation listener for the full-screen window
     private WindowListener fsWindowListener;
 
+    private float scaleX;
+    private float scaleY;
+
     static {
 
         // 4455041 - Even when ddraw is disabled, ddraw.dll is loaded when
@@ -97,6 +106,10 @@
     private static native void initIDs();
 
     native void initDevice(int screen);
+    native void initNativeScale(int screen, boolean fractionalScaleEnabled);
+    native void setNativeScale(int screen, float scaleX, float scaleY);
+    native float getNativeScaleX(int screen);
+    native float getNativeScaleY(int screen);
 
     public Win32GraphicsDevice(int screennum) {
         this.screen = screennum;
@@ -109,6 +122,7 @@
         valid = true;
 
         initDevice(screennum);
+        initScaleFactors();
     }
 
     /**
@@ -128,6 +142,33 @@
         return screen;
     }
 
+    public float getDefaultScaleX() {
+        return scaleX;
+    }
+
+    public float getDefaultScaleY() {
+        return scaleY;
+    }
+
+    private void initScaleFactors() {
+        if (SunGraphicsEnvironment.isUIScaleEnabled()) {
+            if (debugScaleX > 0 && debugScaleY > 0) {
+                scaleX = debugScaleX;
+                scaleY = debugScaleY;
+                setNativeScale(screen, scaleX, scaleY);
+            } else {
+                boolean fScaleEnabled = "true".equals(AccessController.doPrivileged(
+                        new GetPropertyAction("sun.java2d.uiFractScale.enabled", "false")));
+                initNativeScale(screen, fScaleEnabled);
+                scaleX = getNativeScaleX(screen);
+                scaleY = getNativeScaleY(screen);
+            }
+        } else {
+            scaleX = 1;
+            scaleY = 1;
+        }
+    }
+
     /**
      * Returns whether this is a valid devicie. Device can become
      * invalid as a result of device removal event.
@@ -486,6 +527,7 @@
         configs = null;
         // pass on to all top-level windows on this display
         topLevels.notifyListeners();
+        initScaleFactors();
     }
 
     /**
diff --git a/src/windows/classes/sun/awt/Win32GraphicsEnvironment.java b/src/windows/classes/sun/awt/Win32GraphicsEnvironment.java
index a1c57b6..999c626 100644
--- a/src/windows/classes/sun/awt/Win32GraphicsEnvironment.java
+++ b/src/windows/classes/sun/awt/Win32GraphicsEnvironment.java
@@ -57,9 +57,16 @@
  * @see GraphicsConfiguration
  */
 
-public class Win32GraphicsEnvironment
-    extends SunGraphicsEnvironment
-{
+public class Win32GraphicsEnvironment extends SunGraphicsEnvironment {
+
+    // [tav] the values match the native ones
+    private final static int PROCESS_DPI_UNAWARE            = 0;
+    private final static int PROCESS_SYSTEM_DPI_AWARE       = 1;
+    private final static int PROCESS_PER_MONITOR_DPI_AWARE  = 2;
+
+    static final float debugScaleX;
+    static final float debugScaleY;
+
     static {
         // Ensure awt is loaded already.  Also, this forces static init
         // of WToolkit and Toolkit, which we depend upon
@@ -70,6 +77,21 @@
 
         // Install correct surface manager factory.
         SurfaceManagerFactory.setInstance(new WindowsSurfaceManagerFactory());
+
+        double sx = -1;
+        double sy = -1;
+        if (isUIScaleEnabled()) {
+            sx = getScaleFactor("sun.java2d.win.uiScaleX");
+            sy = getScaleFactor("sun.java2d.win.uiScaleY");
+            if (sx <= 0 || sy <= 0) {
+                double s = getDebugScale();
+                sx = s;
+                sy = s;
+            }
+        }
+
+        debugScaleX = (float) sx;
+        debugScaleY = (float) sy;
     }
 
     /**
@@ -83,13 +105,25 @@
     public static void initDisplayWrapper() {
         if (!displayInitialized) {
             displayInitialized = true;
+            setProcessDPIAwareness(isUIScaleEnabled() ? PROCESS_PER_MONITOR_DPI_AWARE : PROCESS_SYSTEM_DPI_AWARE);
             initDisplay();
         }
     }
 
     public Win32GraphicsEnvironment() {
+        // check if UI scale was rejected natively
+        if (isUIScaleEnabled() && !isUIScaleOn()) {
+            // [tav]
+            // Fallback to the previous level for backward compatibility.
+            // This will work since Windows 10 only, as per MSDN:
+            // https://msdn.microsoft.com/en-us/library/windows/desktop/dn302122(v=vs.85).aspx
+            // For Windows 8.1, the following VM option should be used to fallback:
+            // -Dsun.java2d.uiScale.enabled=false
+            setProcessDPIAwareness(PROCESS_SYSTEM_DPI_AWARE);
+        }
     }
 
+    private native static void setProcessDPIAwareness(int level);
     protected native int getNumScreens();
     protected native int getDefaultScreen();
 
diff --git a/src/windows/classes/sun/awt/windows/WComponentPeer.java b/src/windows/classes/sun/awt/windows/WComponentPeer.java
index 1008004..6a79ed4 100644
--- a/src/windows/classes/sun/awt/windows/WComponentPeer.java
+++ b/src/windows/classes/sun/awt/windows/WComponentPeer.java
@@ -58,6 +58,9 @@
 import java.awt.dnd.peer.DropTargetPeer;
 import sun.awt.AWTAccessor;
 
+import sun.security.action.GetBooleanAction;
+import java.security.AccessController;
+
 import sun.util.logging.PlatformLogger;
 
 public abstract class WComponentPeer extends WObjectPeer
@@ -72,6 +75,23 @@
     private static final PlatformLogger shapeLog = PlatformLogger.getLogger("sun.awt.windows.shape.WComponentPeer");
     private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.windows.focus.WComponentPeer");
 
+    private static boolean flipHorizontalScrolling;
+    private static boolean flipVerticalScrolling;
+
+    private static native void setPlatformScrollingFlip(boolean horizontal, boolean vertical);
+
+    private static void setScrollingFlip(boolean horizontal, boolean vertical) {
+        setPlatformScrollingFlip(
+                flipHorizontalScrolling = horizontal,
+                flipVerticalScrolling = vertical);
+    }
+
+    static {
+        setScrollingFlip(
+                AccessController.doPrivileged(new GetBooleanAction("awt.flip.horizontal.scrolling")),
+                AccessController.doPrivileged(new GetBooleanAction("awt.flip.vertical.scrolling")));
+    }
+
     // ComponentPeer implementation
     SurfaceData surfaceData;
 
diff --git a/src/windows/classes/sun/awt/windows/WFileDialogPeer.java b/src/windows/classes/sun/awt/windows/WFileDialogPeer.java
index beeb103..4d80996 100644
--- a/src/windows/classes/sun/awt/windows/WFileDialogPeer.java
+++ b/src/windows/classes/sun/awt/windows/WFileDialogPeer.java
@@ -71,6 +71,11 @@
     }
 
     @Override
+    public void updateGC() {
+        // nop
+    }
+
+    @Override
     void create(WComponentPeer parent) {
         this.parent = parent;
     }
diff --git a/src/windows/classes/sun/awt/windows/WPrintDialogPeer.java b/src/windows/classes/sun/awt/windows/WPrintDialogPeer.java
index d1efab0..362afa9 100644
--- a/src/windows/classes/sun/awt/windows/WPrintDialogPeer.java
+++ b/src/windows/classes/sun/awt/windows/WPrintDialogPeer.java
@@ -48,6 +48,11 @@
     }
 
     @Override
+    public void updateGC() {
+        // nop
+    }
+
+    @Override
     void create(WComponentPeer parent) {
         this.parent = parent;
     }
diff --git a/src/windows/classes/sun/awt/windows/WWindowPeer.java b/src/windows/classes/sun/awt/windows/WWindowPeer.java
index 51bf837..c8f00fc 100644
--- a/src/windows/classes/sun/awt/windows/WWindowPeer.java
+++ b/src/windows/classes/sun/awt/windows/WWindowPeer.java
@@ -169,6 +169,8 @@
 
     WWindowPeer(Window target) {
         super(target);
+        // update GC based on the current bounds
+        updateGC();
     }
 
     @Override
@@ -294,6 +296,12 @@
 
     synchronized native void reshapeFrame(int x, int y, int width, int height);
 
+    native Dimension getNativeWindowSize();
+
+    public Dimension getScaledWindowSize() {
+        return getNativeWindowSize();
+    }
+
     public boolean requestWindowFocus(CausedFocusEvent.Cause cause) {
         if (!focusAllowedFor()) {
             return false;
@@ -490,8 +498,7 @@
         }
 
         // get current GD
-        Win32GraphicsDevice oldDev = (Win32GraphicsDevice)winGraphicsConfig
-                                     .getDevice();
+        Win32GraphicsDevice oldDev = winGraphicsConfig.getDevice();
 
         Win32GraphicsDevice newDev;
         GraphicsDevice devs[] = GraphicsEnvironment
diff --git a/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java b/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java
index 451e5fa..e0a9362 100644
--- a/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java
+++ b/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java
@@ -63,9 +63,12 @@
 import static sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType.*;
 import sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType;
 import java.awt.BufferCapabilities.FlipContents;
+import java.awt.Dimension;
 import java.awt.Window;
+import java.awt.geom.AffineTransform;
 import sun.awt.SunToolkit;
 import sun.awt.image.SunVolatileImage;
+import sun.awt.windows.WWindowPeer;
 import sun.java2d.ScreenUpdateManager;
 import sun.java2d.StateTracker;
 import sun.java2d.SurfaceDataProxy;
@@ -162,6 +165,8 @@
 
     private int type;
     private int width, height;
+    private final double scaleX;
+    private final double scaleY;
     // these fields are set from the native code when the surface is
     // initialized
     private int nativeWidth, nativeHeight;
@@ -218,16 +223,29 @@
     {
         super(getCustomSurfaceType(type), cm);
         this.graphicsDevice = gc.getD3DDevice();
+        this.scaleX = type == TEXTURE ? 1 : graphicsDevice.getDefaultScaleX();
+        this.scaleY = type == TEXTURE ? 1 : graphicsDevice.getDefaultScaleY();
         this.peer = peer;
         this.type = type;
-        this.width = width;
-        this.height = height;
+
+        if (scaleX == 1 && scaleY == 1) {
+            this.width = width;
+            this.height = height;
+        } else if (peer instanceof WWindowPeer) {
+            Dimension scaledSize = ((WWindowPeer) peer).getScaledWindowSize();
+            this.width = scaledSize.width;
+            this.height = scaledSize.height;
+        } else {
+            this.width = (int) Math.ceil(width * scaleX);
+            this.height = (int) Math.ceil(height * scaleY);
+        }
+
         this.offscreenImage = image;
         this.backBuffersNum = numBackBuffers;
         this.swapEffect = swapEffect;
         this.syncType = vSyncType;
 
-        initOps(graphicsDevice.getScreen(), width, height);
+        initOps(graphicsDevice.getScreen(), this.width, this.height);
         if (type == WINDOW) {
             // we put the surface into the "lost"
             // state; it will be restored by the D3DScreenUpdateManager
@@ -241,6 +259,16 @@
     }
 
     @Override
+    public double getDefaultScaleX() {
+        return scaleX;
+    }
+
+    @Override
+    public double getDefaultScaleY() {
+        return scaleY;
+    }
+
+    @Override
     public SurfaceDataProxy makeProxyFor(SurfaceData srcData) {
         return D3DSurfaceDataProxy.
             createProxy(srcData,
@@ -777,8 +805,12 @@
 
     public Rectangle getBounds() {
         if (type == FLIP_BACKBUFFER || type == WINDOW) {
+            double scaleX = getDefaultScaleX();
+            double scaleY = getDefaultScaleY();
             Rectangle r = peer.getBounds();
             r.x = r.y = 0;
+            r.width = (int) Math.ceil(r.width * scaleX);
+            r.height = (int) Math.ceil(r.height * scaleY);
             return r;
         } else {
             return new Rectangle(width, height);
diff --git a/src/windows/classes/sun/java2d/opengl/WGLSurfaceData.java b/src/windows/classes/sun/java2d/opengl/WGLSurfaceData.java
index a96d58f..bc24304 100644
--- a/src/windows/classes/sun/java2d/opengl/WGLSurfaceData.java
+++ b/src/windows/classes/sun/java2d/opengl/WGLSurfaceData.java
@@ -31,8 +31,10 @@
 import java.awt.GraphicsEnvironment;
 import java.awt.Image;
 import java.awt.Rectangle;
+import java.awt.geom.AffineTransform;
 import java.awt.image.ColorModel;
 import sun.awt.SunToolkit;
+import sun.awt.Win32GraphicsDevice;
 import sun.awt.windows.WComponentPeer;
 import sun.java2d.SurfaceData;
 
@@ -40,6 +42,8 @@
 
     protected WComponentPeer peer;
     private WGLGraphicsConfig graphicsConfig;
+    protected double scaleX = 1;
+    protected double scaleY = 1;
 
     private native void initOps(long pConfigInfo, WComponentPeer peer,
                                 long hwnd);
@@ -53,6 +57,9 @@
         super(gc, cm, type);
         this.peer = peer;
         this.graphicsConfig = gc;
+        Win32GraphicsDevice device = gc.getDevice();
+        this.scaleX = type == TEXTURE ? 1 : device.getDefaultScaleX();
+        this.scaleY = type == TEXTURE ? 1 : device.getDefaultScaleY();
 
         long pConfigInfo = gc.getNativeConfigInfo();
         long hwnd = peer != null ? peer.getHWnd() : 0L;
@@ -60,6 +67,16 @@
         initOps(pConfigInfo, peer, hwnd);
     }
 
+    @Override
+    public double getDefaultScaleX() {
+        return scaleX;
+    }
+
+    @Override
+    public double getDefaultScaleY() {
+        return scaleY;
+    }
+
     public GraphicsConfiguration getDeviceConfiguration() {
         return graphicsConfig;
     }
@@ -151,6 +168,8 @@
         public Rectangle getBounds() {
             Rectangle r = peer.getBounds();
             r.x = r.y = 0;
+            r.width = (int) Math.ceil(r.width * scaleX);
+            r.height = (int) Math.ceil(r.height * scaleY);
             return r;
         }
 
@@ -211,11 +230,11 @@
         {
             super(peer, gc, cm, type);
 
-            this.width = width;
-            this.height = height;
+            this.width = (int) Math.ceil(width * scaleX);
+            this.height = (int) Math.ceil(height * scaleY);
             offscreenImage = image;
 
-            initSurface(width, height);
+            initSurface(this.width, this.height);
         }
 
         public SurfaceData getReplacement() {
@@ -225,6 +244,8 @@
         public Rectangle getBounds() {
             if (type == FLIP_BACKBUFFER) {
                 Rectangle r = peer.getBounds();
+                r.width = (int) Math.ceil(r.width * scaleX);
+                r.height = (int) Math.ceil(r.height * scaleY);
                 r.x = r.y = 0;
                 return r;
             } else {
diff --git a/src/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java b/src/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java
index deaf9c6..903578a 100644
--- a/src/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java
+++ b/src/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java
@@ -28,6 +28,7 @@
 import java.awt.Rectangle;
 import java.awt.GraphicsConfiguration;
 import java.awt.color.ColorSpace;
+import java.awt.geom.AffineTransform;
 import java.awt.image.ColorModel;
 import java.awt.image.ComponentColorModel;
 import java.awt.image.DirectColorModel;
@@ -77,6 +78,9 @@
 
     private static native void initIDs(Class xorComp);
 
+    private final double scaleX;
+    private final double scaleY;
+
     static {
         initIDs(XORComposite.class);
         if (WindowsFlags.isGdiBlitEnabled()) {
@@ -265,13 +269,23 @@
         this.graphicsConfig =
             (Win32GraphicsConfig) peer.getGraphicsConfiguration();
         this.solidloops = graphicsConfig.getSolidLoops(sType);
-
-        Win32GraphicsDevice gd =
-            (Win32GraphicsDevice)graphicsConfig.getDevice();
+        Win32GraphicsDevice gd = graphicsConfig.getDevice();
+        scaleX = gd.getDefaultScaleX();
+        scaleY = gd.getDefaultScaleY();
         initOps(peer, depth, rMask, gMask, bMask, gd.getScreen());
         setBlitProxyKey(graphicsConfig.getProxyKey());
     }
 
+    @Override
+    public double getDefaultScaleX() {
+        return scaleX;
+    }
+
+    @Override
+    public double getDefaultScaleY() {
+        return scaleY;
+    }
+
     /**
      * {@inheritDoc}
      *
@@ -288,6 +302,8 @@
     public Rectangle getBounds() {
         Rectangle r = peer.getBounds();
         r.x = r.y = 0;
+        r.width = (int) Math.ceil(r.width * scaleX);
+        r.height = (int) Math.ceil(r.height * scaleY);
         return r;
     }
 
diff --git a/src/windows/classes/sun/java2d/windows/WindowsFlags.java b/src/windows/classes/sun/java2d/windows/WindowsFlags.java
index a6d265f..b005852 100644
--- a/src/windows/classes/sun/java2d/windows/WindowsFlags.java
+++ b/src/windows/classes/sun/java2d/windows/WindowsFlags.java
@@ -251,7 +251,7 @@
                         javaVersion = javaVersion.substring(0, dashIndex);
                     }
                 }
-                String dpiOverride = System.getProperty("sun.java2d.dpiaware");
+                String dpiOverride = System.getProperty("sun.java2d.dpiaware", "true");
                 if (dpiOverride != null) {
                     setHighDPIAware = dpiOverride.equalsIgnoreCase("true");
                 } else {
diff --git a/src/windows/native/sun/font/lcdglyph.c b/src/windows/native/sun/font/lcdglyph.c
index d940e8c..bc60cee 100644
--- a/src/windows/native/sun/font/lcdglyph.c
+++ b/src/windows/native/sun/font/lcdglyph.c
@@ -172,7 +172,7 @@
 JNIEXPORT jlong JNICALL
 Java_sun_font_FileFontStrike__1getGlyphImageFromWindows
 (JNIEnv *env, jobject unused,
- jstring fontFamily, jint style, jint size, jint glyphCode, jboolean fm) {
+ jstring fontFamily, jint style, jint size, jint glyphCode, jboolean fm, jint rotation) {
 
     GLYPHMETRICS glyphMetrics;
     LOGFONTW lf;
@@ -233,6 +233,7 @@
     lf.lfOutPrecision = OUT_TT_PRECIS;
     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
     lf.lfPitchAndFamily = DEFAULT_PITCH;
+    lf.lfEscapement = lf.lfOrientation = 900 * rotation;
 
     nameLen = (*env)->GetStringLength(env, fontFamily);
     name = (LPWSTR)alloca((nameLen+1)*2);
@@ -362,7 +363,17 @@
     if (fm) {
         x += 1;
     }
-    y = topLeftY - textMetric.tmAscent;
+    if (rotation == 1) {
+        x -= textMetric.tmAscent;
+    } else if (rotation == 3) {
+        x += textMetric.tmAscent;
+    }
+    y = topLeftY;
+    if (rotation == 0) {
+        y -= textMetric.tmAscent;
+    } else if (rotation == 2) {
+        y += textMetric.tmAscent;
+    }
     err = ExtTextOutW(hMemoryDC, x, y, ETO_GLYPH_INDEX|ETO_OPAQUE,
                 (LPRECT)&rect, (LPCWSTR)&glyphCode, 1, NULL);
     if (err == 0) {
diff --git a/src/windows/native/sun/font/lcdglyphDW.cpp b/src/windows/native/sun/font/lcdglyphDW.cpp
new file mode 100644
index 0000000..b66d0a3
--- /dev/null
+++ b/src/windows/native/sun/font/lcdglyphDW.cpp
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2016 JetBrains s.r.o.
+ * 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 <stdio.h>
+#include <malloc.h>
+#include <math.h>
+#include <windows.h>
+#include <winuser.h>
+#include <Dwrite.h>
+
+#include <jni.h>
+#include <jni_util.h>
+#include <jlong_md.h>
+#include <jdk_util.h>
+#include <sizecalc.h>
+#include <sun_font_FileFontStrike.h>
+
+#include "fontscalerdefs.h"
+
+extern "C" {
+
+#define FREE \
+    if (target != NULL) { \
+        target->Release(); \
+    }\
+    if (params != NULL) { \
+        params->Release(); \
+    }\
+    if (defaultParams != NULL) { \
+        defaultParams->Release(); \
+    }\
+    if (face != NULL) { \
+        face->Release(); \
+    }\
+    if (font != NULL) { \
+        font->Release(); \
+    }\
+    if (interop != NULL) { \
+        interop->Release(); \
+    }\
+    if (factory != NULL) { \
+        factory->Release(); \
+    }
+
+#define FREE_AND_RETURN \
+    FREE\
+    return (jlong)0;
+
+typedef HRESULT (WINAPI *DWriteCreateFactoryType)(DWRITE_FACTORY_TYPE, REFIID, IUnknown**);
+
+static BOOL checkedForDirectWriteAvailability = FALSE;
+static DWriteCreateFactoryType fDWriteCreateFactory = NULL;
+
+JNIEXPORT jboolean JNICALL
+Java_sun_font_FileFontStrike_isDirectWriteAvailable(JNIEnv *env, jclass unused) {
+    if (!checkedForDirectWriteAvailability) {
+        checkedForDirectWriteAvailability = TRUE;
+        HMODULE hDwrite = JDK_LoadSystemLibrary("Dwrite.dll");
+        if (hDwrite) {
+            fDWriteCreateFactory = (DWriteCreateFactoryType)GetProcAddress(hDwrite, "DWriteCreateFactory");
+        }
+    }
+    return fDWriteCreateFactory != NULL ? JNI_TRUE : JNI_FALSE;
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_font_FileFontStrike__1getGlyphImageFromWindowsUsingDirectWrite
+(JNIEnv *env, jobject unused, jstring fontFamily, jint style, jint size, jint glyphCode, jint rotation,
+    jint measuringMode, jint renderingMode, jfloat clearTypeLevel, jfloat enhancedContrast, jfloat gamma, jint pixelGeometry) {
+    // variables cleared by FREE macro
+    IDWriteFactory* factory = NULL;
+    IDWriteGdiInterop* interop = NULL;
+    IDWriteFont* font = NULL;
+    IDWriteFontFace* face = NULL;
+    IDWriteRenderingParams* defaultParams = NULL;
+    IDWriteRenderingParams* params = NULL;
+    IDWriteBitmapRenderTarget* target = NULL;
+
+    LOGFONTW lf;
+    memset(&lf, 0, sizeof(LOGFONTW));
+    lf.lfWeight = (style & 1) ? FW_BOLD : FW_NORMAL;
+    lf.lfItalic = (style & 2) ? TRUE : FALSE;
+
+    int nameLen = env->GetStringLength(fontFamily);
+    if (nameLen >= (sizeof(lf.lfFaceName) / sizeof(lf.lfFaceName[0]))) {
+        FREE_AND_RETURN
+    }
+    env->GetStringRegion(fontFamily, 0, nameLen, lf.lfFaceName);
+    lf.lfFaceName[nameLen] = '\0';
+
+    if (fDWriteCreateFactory == NULL) {
+        FREE_AND_RETURN
+    }
+    HRESULT hr = (*fDWriteCreateFactory)(DWRITE_FACTORY_TYPE_SHARED,
+                                         __uuidof(IDWriteFactory),
+                                         reinterpret_cast<IUnknown**>(&factory));
+    if (FAILED(hr)) {
+        FREE_AND_RETURN
+    }
+    hr = factory->GetGdiInterop(&interop);
+    if (FAILED(hr)) {
+        FREE_AND_RETURN
+    }
+    hr = interop->CreateFontFromLOGFONT(&lf, &font);
+    if (FAILED(hr)) {
+        FREE_AND_RETURN
+    }
+    hr = font->CreateFontFace(&face);
+    if (FAILED(hr)) {
+        FREE_AND_RETURN
+    }
+    hr = factory->CreateRenderingParams(&defaultParams);
+    if (FAILED(hr)) {
+        FREE_AND_RETURN
+    }
+    hr = factory->CreateCustomRenderingParams(
+        gamma > 0 && gamma <= 256                  ? gamma                                : defaultParams->GetGamma(),
+        enhancedContrast >= 0                      ? enhancedContrast                     : defaultParams->GetEnhancedContrast(),
+        clearTypeLevel >= 0 && clearTypeLevel <= 1 ? clearTypeLevel                       : defaultParams->GetClearTypeLevel(),
+        pixelGeometry >= 0 && pixelGeometry <= 2   ? (DWRITE_PIXEL_GEOMETRY)pixelGeometry : defaultParams->GetPixelGeometry(),
+        renderingMode >= 0 && renderingMode <= 6   ? (DWRITE_RENDERING_MODE)renderingMode : defaultParams->GetRenderingMode(),
+        &params);
+    if (FAILED(hr)) {
+        FREE_AND_RETURN
+    }
+
+    UINT16 indices[] = {(UINT16)glyphCode};
+    FLOAT advances[] = {0};
+    DWRITE_GLYPH_OFFSET offsets[] = {{0, 0}};
+    DWRITE_GLYPH_RUN glyphRun;
+    glyphRun.fontFace = face;
+    glyphRun.fontEmSize = (FLOAT)size;
+    glyphRun.glyphCount = 1;
+    glyphRun.glyphIndices = indices;
+    glyphRun.glyphAdvances = advances;
+    glyphRun.glyphOffsets = offsets;
+    glyphRun.isSideways = FALSE;
+    glyphRun.bidiLevel = 0;
+
+    DWRITE_FONT_METRICS fontMetrics;
+    face->GetMetrics(&fontMetrics);
+    FLOAT pxPerDU = ((FLOAT)size) / fontMetrics.designUnitsPerEm;
+
+    DWRITE_GLYPH_METRICS metrics[1];
+    hr = face->GetDesignGlyphMetrics(indices, 1, metrics, FALSE);
+    if (FAILED(hr)) {
+        FREE_AND_RETURN
+    }
+
+    // trying to derive required bitmap size from glyph metrics (adding several spare pixels on each border)
+    // if that will fail, we'll perform a second attempt based on the output of DrawGlyphRun
+    int width = (int)((metrics[0].advanceWidth - metrics[0].leftSideBearing - metrics[0].rightSideBearing) * pxPerDU) + 10;
+    int height = (int)((metrics[0].advanceHeight - metrics[0].topSideBearing - metrics[0].bottomSideBearing) * pxPerDU) + 10;
+    int x = (int)(-metrics[0].leftSideBearing * pxPerDU) + 5;
+    int y = (int)((metrics[0].verticalOriginY - metrics[0].topSideBearing) * pxPerDU) + 5;
+    float advance = (float)((int)(metrics[0].advanceWidth * pxPerDU + 0.5));
+    RECT bbRect;
+
+    DWRITE_MATRIX mx;
+    switch (rotation) {
+        case 0: mx.m11 = mx.m22 = 1; mx.m12 = mx.m21 = mx.dx = mx.dy = 0; break;
+        case 1: mx.m11 = mx.m22 = 0; mx.m12 = -1; mx.m21 = 1; mx.dx = 0; mx.dy = (float)width; break;
+        case 2: mx.m11 = mx.m22 = -1; mx.m12 = mx.m21 = 0; mx.dx = (float)width; mx.dy = (float)height; break;
+        case 3: mx.m11 = mx.m22 = 0; mx.m12 = 1; mx.m21 = -1; mx.dx = (float)height; mx.dy = 0;
+    }
+    if (rotation == 1 || rotation == 3) {
+        int tmp = width;
+        width = height;
+        height = tmp;
+    }
+    float xTransformed = mx.m11 * x - mx.m12 * y + mx.dx;
+    float yTransformed = -mx.m21 * x + mx.m22 * y + mx.dy;
+
+    for (int attempt = 0; attempt < 2 && target == NULL; attempt++) {
+        hr = interop->CreateBitmapRenderTarget(NULL, width, height, &target);
+        if (FAILED(hr)) {
+            FREE_AND_RETURN
+        }
+        hr = target->SetCurrentTransform(&mx);
+        if (FAILED(hr)) {
+            FREE_AND_RETURN
+        }
+        hr = target->DrawGlyphRun((FLOAT)x,
+                                  (FLOAT)y,
+                                  measuringMode >= 0 && measuringMode <= 2 ? (DWRITE_MEASURING_MODE)measuringMode : DWRITE_MEASURING_MODE_NATURAL,
+                                  &glyphRun,
+                                  params,
+                                  RGB(255,255,255),
+                                  &bbRect);
+        if (FAILED(hr) || bbRect.left > bbRect.right || bbRect.top > bbRect.bottom
+            || attempt > 0 && (bbRect.left < 0 || bbRect.top < 0 || bbRect.right > width || bbRect.bottom > height)) {
+            FREE_AND_RETURN
+        }
+        if (bbRect.left < 0 || bbRect.top < 0 || bbRect.right > width || bbRect.bottom > height) {
+            target->Release();
+            target = NULL;
+            if (bbRect.right > width) width = bbRect.right;
+            if (bbRect.bottom > height) height = bbRect.bottom;
+            if (bbRect.left < 0) {
+                width -= bbRect.left;
+                switch (rotation) {
+                    case 0: x -= bbRect.left; break;
+                    case 1: y -= bbRect.left; break;
+                    case 2: x += bbRect.left; break;
+                    case 3: y += bbRect.left;
+                }
+            }
+            if (bbRect.top < 0) {
+                height -= bbRect.top;
+                switch (rotation) {
+                    case 0: y -= bbRect.top; break;
+                    case 1: x += bbRect.top; break;
+                    case 2: y += bbRect.top; break;
+                    case 3: x -= bbRect.top;
+                }
+            }
+        }
+    }
+
+    HDC glyphDC = target->GetMemoryDC();
+    HGDIOBJ glyphBitmap = GetCurrentObject(glyphDC, OBJ_BITMAP);
+    if (glyphBitmap == NULL) {
+        FREE_AND_RETURN
+    }
+    DIBSECTION dibSection;
+    if (GetObject(glyphBitmap, sizeof(DIBSECTION), &dibSection) == 0) {
+        FREE_AND_RETURN
+    }
+
+    int glyphWidth = bbRect.right - bbRect.left;
+    int glyphHeight = bbRect.bottom - bbRect.top;
+    int glyphBytesWidth = glyphWidth * 3;
+    GlyphInfo* glyphInfo = (GlyphInfo*)SAFE_SIZE_STRUCT_ALLOC(malloc, sizeof(GlyphInfo), glyphBytesWidth, glyphHeight);
+    if (glyphInfo == NULL) {
+        FREE_AND_RETURN
+    }
+    glyphInfo->managed = UNMANAGED_GLYPH;
+    glyphInfo->cellInfo = NULL;
+    glyphInfo->image = (unsigned char*)glyphInfo+sizeof(GlyphInfo);
+    glyphInfo->rowBytes = glyphBytesWidth;
+    glyphInfo->width = glyphWidth;
+    glyphInfo->height = glyphHeight;
+    glyphInfo->advanceX = rotation == 0 ? advance : rotation == 2 ? -advance : 0;
+    glyphInfo->advanceY = rotation == 3 ? advance : rotation == 1 ? -advance : 0;
+    glyphInfo->topLeftX = bbRect.left - xTransformed;
+    glyphInfo->topLeftY = bbRect.top - yTransformed;
+
+    int srcRowBytes = width * 4;
+    unsigned char* srcPtr = (unsigned char*) dibSection.dsBm.bmBits + srcRowBytes * bbRect.top;
+    unsigned char* destPtr = glyphInfo->image;
+    for (int y = 0; y < glyphHeight; y++) {
+        srcPtr += bbRect.left * 4;
+        for (int x = 0; x < glyphWidth; x++) {
+            // converting from BGRA to RGB
+            unsigned char b = *srcPtr++;
+            unsigned char g = *srcPtr++;
+            unsigned char r = *srcPtr++;
+            srcPtr++;
+            *destPtr++ = r;
+            *destPtr++ = g;
+            *destPtr++ = b;
+        }
+        srcPtr += (width - bbRect.right) * 4;
+    }
+
+    FREE
+    return ptr_to_jlong(glyphInfo);
+}
+
+} // extern "C"
\ No newline at end of file
diff --git a/src/windows/native/sun/windows/MouseInfo.cpp b/src/windows/native/sun/windows/MouseInfo.cpp
index b109f28..17e0769 100644
--- a/src/windows/native/sun/windows/MouseInfo.cpp
+++ b/src/windows/native/sun/windows/MouseInfo.cpp
@@ -85,6 +85,7 @@
     POINT pt;
 
     VERIFY(::GetCursorPos(&pt));
+    AwtWin32GraphicsDevice::ScaleDownDPoint(&pt);
     if (pointClass == NULL) {
         jclass pointClassLocal = env->FindClass("java/awt/Point");
         DASSERT(pointClassLocal != NULL);
@@ -94,10 +95,12 @@
         pointClass = (jclass)env->NewGlobalRef(pointClassLocal);
         env->DeleteLocalRef(pointClassLocal);
     }
+
     xID = env->GetFieldID(pointClass, "x", "I");
     CHECK_NULL_RETURN(xID, (jint)0);
     yID = env->GetFieldID(pointClass, "y", "I");
     CHECK_NULL_RETURN(yID, (jint)0);
+
     env->SetIntField(point, xID, pt.x);
     env->SetIntField(point, yID, pt.y);
 
diff --git a/src/windows/native/sun/windows/ThemeReader.cpp b/src/windows/native/sun/windows/ThemeReader.cpp
index ef67775..2cebde7 100644
--- a/src/windows/native/sun/windows/ThemeReader.cpp
+++ b/src/windows/native/sun/windows/ThemeReader.cpp
@@ -31,6 +31,8 @@
 #include "awt_Object.h"
 #include "awt_Component.h"
 
+#include "math.h"
+
 // Important note about VC6 and VC7 (or XP Platform SDK)   !
 //
 // These type definitions have been imported from UxTheme.h
@@ -745,6 +747,23 @@
     return NULL;
 }
 
+void rescale(SIZE *size) {
+    HWND hWnd = ::GetDesktopWindow();
+    HDC hDC = ::GetDC(hWnd);
+    int dpiX = ::GetDeviceCaps(hDC, LOGPIXELSX);
+    int dpiY = ::GetDeviceCaps(hDC, LOGPIXELSY);
+
+    if (dpiX !=0 && dpiX != 96) {
+        float invScaleX = 96.0f / dpiX;
+        size->cx = (int)round(size->cx * invScaleX);
+    }
+    if (dpiY != 0 && dpiY != 96) {
+        float invScaleY = 96.0f / dpiY;
+        size->cy = (int)round(size->cy * invScaleY);
+    }
+    ::ReleaseDC(hWnd, hDC);
+}
+
 /*
  * Class:     sun_awt_windows_ThemeReader
  * Method:    getPartSize
@@ -770,6 +789,8 @@
                 dimMID = env->GetMethodID(dimClassID, "<init>", "(II)V");
                 CHECK_NULL_RETURN(dimMID, NULL);
             }
+
+            rescale(&size);
             jobject dimObj = env->NewObject(dimClassID, dimMID, size.cx, size.cy);
             if (safe_ExceptionOccurred(env)) {
                 env->ExceptionDescribe();
diff --git a/src/windows/native/sun/windows/awt.h b/src/windows/native/sun/windows/awt.h
index 83c3fcb..9191035 100644
--- a/src/windows/native/sun/windows/awt.h
+++ b/src/windows/native/sun/windows/awt.h
@@ -44,6 +44,17 @@
 
 extern COLORREF DesktopColor2RGB(int colorIndex);
 
+#ifndef _WIN32_WINNT_WINBLUE
+typedef enum _PROCESS_DPI_AWARENESS {
+    PROCESS_DPI_UNAWARE            = 0,
+    PROCESS_SYSTEM_DPI_AWARE       = 1,
+    PROCESS_PER_MONITOR_DPI_AWARE  = 2
+} PROCESS_DPI_AWARENESS;
+#endif
+
+// val >= 0 todo [tav] until switch to VS'12
+#define round(val) floor(val + 0.5)
+
 class AwtObject;
 typedef AwtObject* PDATA;
 
diff --git a/src/windows/native/sun/windows/awt_Choice.cpp b/src/windows/native/sun/windows/awt_Choice.cpp
index 6a59747..be1c41e 100644
--- a/src/windows/native/sun/windows/awt_Choice.cpp
+++ b/src/windows/native/sun/windows/awt_Choice.cpp
@@ -206,9 +206,10 @@
     int itemHeight =(int)::SendMessage(GetHWnd(), CB_GETITEMHEIGHT, (UINT)0,0);
     int numItemsToShow = (int)::SendMessage(GetHWnd(), CB_GETCOUNT, 0,0);
     numItemsToShow = min(MINIMUM_NUMBER_OF_VISIBLE_ITEMS, numItemsToShow);
+
     // drop-down height snaps to nearest line, so add a
     // fudge factor of 1/2 line to ensure last line shows
-    return itemHeight*numItemsToShow + itemHeight/2;
+    return ScaleDownY(itemHeight * numItemsToShow + itemHeight / 2);
 }
 
 // get the height of the field portion of the combobox
@@ -221,7 +222,7 @@
     // Win 4.x (3d edge) vs 3.x (1 pixel line)
     borderHeight = ::GetSystemMetrics(SM_CYEDGE);
     fieldHeight += borderHeight*2;
-    return fieldHeight;
+    return ScaleDownY(fieldHeight);
 }
 
 // gets the total height of the combobox, including drop down
@@ -325,8 +326,8 @@
      * Fix: Set the Choice to its actual size in the component.
      */
     ::GetClientRect(GetHWnd(), &rc);
-    env->SetIntField(target, AwtComponent::widthID,  (jint)rc.right);
-    env->SetIntField(target, AwtComponent::heightID, (jint)rc.bottom);
+    env->SetIntField(target, AwtComponent::widthID, ScaleDownX(rc.right));
+    env->SetIntField(target, AwtComponent::heightID, ScaleDownY(rc.bottom));
 
     env->DeleteLocalRef(target);
     env->DeleteLocalRef(parent);
diff --git a/src/windows/native/sun/windows/awt_Clipboard.cpp b/src/windows/native/sun/windows/awt_Clipboard.cpp
index 12f47a2..6f89a30 100644
--- a/src/windows/native/sun/windows/awt_Clipboard.cpp
+++ b/src/windows/native/sun/windows/awt_Clipboard.cpp
@@ -156,8 +156,16 @@
     DASSERT(::GetOpenClipboardWindow() != AwtToolkit::GetInstance().GetHWnd());
 
     if (!::OpenClipboard(AwtToolkit::GetInstance().GetHWnd())) {
-        JNU_ThrowByName(env, "java/lang/IllegalStateException",
-                        "cannot open system clipboard");
+        HRESULT hr = HRESULT_FROM_WIN32(::GetLastError());
+
+        if (hr == E_ACCESSDENIED) {
+            JNU_ThrowByName(env, "java/lang/IllegalStateException",
+                                 "Clipboard is busy");
+        } else {
+            JNU_ThrowByName(env, "java/lang/IllegalStateException",
+                                 "Clipboard problem");
+        }
+
         return;
     }
     if (newOwner != NULL) {
diff --git a/src/windows/native/sun/windows/awt_Component.cpp b/src/windows/native/sun/windows/awt_Component.cpp
index 8fb8b51..d3a8167 100644
--- a/src/windows/native/sun/windows/awt_Component.cpp
+++ b/src/windows/native/sun/windows/awt_Component.cpp
@@ -45,6 +45,7 @@
 #include "awt_Toolkit.h"
 #include "awt_Window.h"
 #include "awt_Win32GraphicsDevice.h"
+#include "awt_Win32GraphicsConfig.h"
 #include "Hashtable.h"
 #include "ComCtl32Util.h"
 
@@ -210,6 +211,21 @@
 CriticalSection windowMoveLock;
 BOOL windowMoveLockHeld = FALSE;
 
+static BOOL flipHorizontalScrolling = FALSE;
+static BOOL flipVerticalScrolling = FALSE;
+
+/*
+ * Class:     sun_awt_windows_WComponentPeer
+ * Method:    setPlatformScrollingFlip
+ * Signature: (ZZ)V
+ */
+JNIEXPORT void JNICALL Java_sun_awt_windows_WComponentPeer_setPlatformScrollingFlip
+  (JNIEnv* env, jclass c, jboolean horizontal, jboolean vertical)
+{
+    flipHorizontalScrolling = horizontal == JNI_TRUE;
+    flipVerticalScrolling = vertical == JNI_TRUE;
+}
+
 /************************************************************************
  * AwtComponent methods
  */
@@ -250,7 +266,8 @@
     m_bPauseDestroy = FALSE;
 
     m_MessagesProcessing = 0;
-    m_wheelRotationAmount = 0;
+    m_wheelRotationAmountX = 0;
+    m_wheelRotationAmountY = 0;
     if (!sm_PrimaryDynamicTableBuilt) {
         // do it once.
         AwtComponent::BuildPrimaryDynamicTable();
@@ -965,6 +982,14 @@
     ::MapWindowPoints(HWND_DESKTOP, ::GetParent(GetHWnd()), (LPPOINT)&rc, 2);
     DTRACE_PRINTLN4("AwtComponent::Reshape from %d, %d, %d, %d", rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top);
 #endif
+
+    AwtWin32GraphicsDevice* device = AwtWin32GraphicsDevice::GetDeviceByBounds(RECT_BOUNDS(x, y, w, h), GetHWnd());
+    x = device->ScaleUpDX(x);
+    y = device->ScaleUpDY(y);
+    w = device->ScaleUpX(w);
+    h = device->ScaleUpY(h);
+
+
     AwtWindow* container = GetContainer();
     AwtComponent* parent = GetParent();
     if (container != NULL && container == parent) {
@@ -1201,6 +1226,7 @@
         WIN_MSG(WM_XBUTTONDOWN)
         WIN_MSG(WM_XBUTTONUP)
         WIN_MSG(WM_MOUSEWHEEL)
+        WIN_MSG(WM_MOUSEHWHEEL)
         WIN_MSG(WM_PARENTNOTIFY)
         WIN_MSG(WM_ENTERMENULOOP)
         WIN_MSG(WM_EXITMENULOOP)
@@ -1632,6 +1658,7 @@
       case WM_XBUTTONUP:
       case WM_MOUSEMOVE:
       case WM_MOUSEWHEEL:
+      case WM_MOUSEHWHEEL:
       case WM_AWT_MOUSEENTER:
       case WM_AWT_MOUSEEXIT:
           curPos = ::GetMessagePos();
@@ -1702,9 +1729,11 @@
               mr = WmMouseExit(static_cast<UINT>(wParam), myPos.x, myPos.y);
               break;
           case  WM_MOUSEWHEEL:
+          case  WM_MOUSEHWHEEL:
               mr = WmMouseWheel(GET_KEYSTATE_WPARAM(wParam),
                                 GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),
-                                GET_WHEEL_DELTA_WPARAM(wParam));
+                                GET_WHEEL_DELTA_WPARAM(wParam),
+                                switchMessage == WM_MOUSEHWHEEL);
               break;
           }
           break;
@@ -1919,6 +1948,10 @@
           mr = WmContextMenu((HWND)wParam,
                              GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
           break;
+#define WM_DPICHANGED       0x02E0 // Since Win 8.1 in WinUser.h
+      case WM_DPICHANGED:
+          mr = WmDPIChanged(HIWORD(wParam), LOWORD(wParam), (RECT*)lParam);
+          break;
 
           /*
            * These messages are used to route Win32 calls to the
@@ -2071,13 +2104,15 @@
 
 MsgRouting AwtComponent::WmSetFocus(HWND hWndLostFocus)
 {
-    m_wheelRotationAmount = 0;
+    m_wheelRotationAmountX = 0;
+    m_wheelRotationAmountY = 0;
     return mrDoDefault;
 }
 
 MsgRouting AwtComponent::WmKillFocus(HWND hWndGotFocus)
 {
-    m_wheelRotationAmount = 0;
+    m_wheelRotationAmountX = 0;
+    m_wheelRotationAmountY = 0;
     return mrDoDefault;
 }
 
@@ -2233,8 +2268,11 @@
         }
         for(i = 0; i < 2; i++) {
             if (un[i] != 0) {
-                DoCallback("handleExpose", "(IIII)V", un[i]->left, un[i]->top,
-                    un[i]->right-un[i]->left, un[i]->bottom-un[i]->top);
+                DoCallback("handleExpose", "(IIII)V",
+                           ScaleDownX(un[i]->left),
+                           ScaleDownY(un[i]->top),
+                           ScaleDownX(un[i]->right - un[i]->left),
+                           ScaleDownY(un[i]->bottom - un[i]->top));
             }
         }
         delete [] buffer;
@@ -2470,7 +2508,7 @@
 }
 
 MsgRouting AwtComponent::WmMouseWheel(UINT flags, int x, int y,
-                                      int wheelRotation)
+                                      int wheelRotation, BOOL isHorizontal)
 {
     // convert coordinates to be Component-relative, not screen relative
     // for wheeling when outside the window, this works similar to
@@ -2484,42 +2522,54 @@
 
     // set some defaults
     jint scrollType = java_awt_event_MouseWheelEvent_WHEEL_UNIT_SCROLL;
-    jint scrollLines = 3;
+    jint scrollUnits = 3;
 
     BOOL result;
-    UINT platformLines;
-
-    m_wheelRotationAmount += wheelRotation;
+    UINT platformUnits;
+    jint roundedWheelRotation;
+    jdouble preciseWheelRotation;
 
     // AWT interprets wheel rotation differently than win32, so we need to
     // decode wheel amount.
-    jint roundedWheelRotation = m_wheelRotationAmount / (-1 * WHEEL_DELTA);
-    jdouble preciseWheelRotation = (jdouble) wheelRotation / (-1 * WHEEL_DELTA);
+    jint modifiers = GetJavaModifiers();
+    if (isHorizontal) {
+        modifiers |= java_awt_event_InputEvent_SHIFT_DOWN_MASK;
+        m_wheelRotationAmountX += wheelRotation;
+        int wheelDelta = flipHorizontalScrolling ? -WHEEL_DELTA : WHEEL_DELTA;
+        roundedWheelRotation = m_wheelRotationAmountX / wheelDelta;
+        preciseWheelRotation = (jdouble) wheelRotation / wheelDelta;
+        result = ::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &platformUnits, 0);
+    } else {
+        m_wheelRotationAmountY += wheelRotation;
+        int wheelDelta = flipVerticalScrolling ? WHEEL_DELTA : -WHEEL_DELTA;
+        roundedWheelRotation = m_wheelRotationAmountY / wheelDelta;
+        preciseWheelRotation = (jdouble) wheelRotation / wheelDelta;
+        result = ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &platformUnits, 0);
+    }
 
     MSG msg;
-    result = ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
-                                    &platformLines, 0);
     InitMessage(&msg, lastMessage, MAKEWPARAM(flags, wheelRotation),
                 MAKELPARAM(x, y));
 
     if (result) {
-        if (platformLines == WHEEL_PAGESCROLL) {
+        if (platformUnits == WHEEL_PAGESCROLL) {
             scrollType = java_awt_event_MouseWheelEvent_WHEEL_BLOCK_SCROLL;
-            scrollLines = 1;
+            scrollUnits = 1;
         }
         else {
             scrollType = java_awt_event_MouseWheelEvent_WHEEL_UNIT_SCROLL;
-            scrollLines = platformLines;
+            scrollUnits = platformUnits;
         }
     }
 
     DTRACE_PRINTLN("calling SendMouseWheelEvent");
 
     SendMouseWheelEvent(java_awt_event_MouseEvent_MOUSE_WHEEL, TimeHelper::getMessageTimeUTC(),
-                        eventPt.x, eventPt.y, GetJavaModifiers(), 0, 0, scrollType,
-                        scrollLines, roundedWheelRotation, preciseWheelRotation, &msg);
+                        eventPt.x, eventPt.y, modifiers, 0, 0, scrollType,
+                        scrollUnits, roundedWheelRotation, preciseWheelRotation, &msg);
 
-    m_wheelRotationAmount %= WHEEL_DELTA;
+    m_wheelRotationAmountX %= WHEEL_DELTA;
+    m_wheelRotationAmountY %= WHEEL_DELTA;
     // this message could be propagated up to the parent chain
     // by the mouse message post processors
     return mrConsume;
@@ -4636,6 +4686,62 @@
     }
 }
 
+int AwtComponent::ScaleUpX(int x) {
+    int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
+    return device == NULL ? x : device->ScaleUpX(x);
+}
+
+int AwtComponent::ScaleUpDX(int x) {
+    int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
+    return device == NULL ? x : device->ScaleUpDX(x);
+}
+
+int AwtComponent::ScaleUpY(int y) {
+    int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
+    return device == NULL ? y : device->ScaleUpY(y);
+}
+
+int AwtComponent::ScaleUpDY(int y) {
+    int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
+    return device == NULL ? y : device->ScaleUpDY(y);
+}
+
+int AwtComponent::ScaleDownX(int x) {
+    int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
+    return device == NULL ? x : device->ScaleDownX(x);
+}
+
+int AwtComponent::ScaleDownDX(int x) {
+    int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
+    return device == NULL ? x : device->ScaleDownDX(x);
+}
+
+int AwtComponent::ScaleDownY(int y) {
+    int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
+    return device == NULL ? y : device->ScaleDownY(y);
+}
+
+int AwtComponent::ScaleDownDY(int y) {
+    int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
+    return device == NULL ? y : device->ScaleDownDY(y);
+}
+
 jintArray AwtComponent::CreatePrintedPixels(SIZE &loc, SIZE &size, int alpha) {
     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 
@@ -4929,8 +5035,9 @@
     jobject mouseEvent = env->NewObject(mouseEventCls, mouseEventConst,
                                         target,
                                         id, when, modifiers,
-                                        x+insets.left, y+insets.top,
-                                        xAbs, yAbs,
+                                        ScaleDownX(x + insets.left),
+                                        ScaleDownY(y + insets.top),
+                                        ScaleDownDX(xAbs), ScaleDownDY(yAbs),
                                         clickCount, popupTrigger, button);
 
     if (safe_ExceptionOccurred(env)) {
@@ -4988,13 +5095,16 @@
     }
     jobject target = GetTarget(env);
     DTRACE_PRINTLN("creating MWE in JNI");
-
+    DWORD curMousePos = ::GetMessagePos();
+    int xAbs = GET_X_LPARAM(curMousePos);
+    int yAbs = GET_Y_LPARAM(curMousePos);
     jobject mouseWheelEvent = env->NewObject(mouseWheelEventCls,
                                              mouseWheelEventConst,
                                              target,
                                              id, when, modifiers,
-                                             x+insets.left, y+insets.top,
-                                             0, 0,
+                                             ScaleDownX(x + insets.left),
+                                             ScaleDownY(y + insets.top),
+                                             ScaleDownDX(xAbs), ScaleDownDY(yAbs),
                                              clickCount, popupTrigger,
                                              scrollType, scrollAmount,
                                              roundedWheelRotation, preciseWheelRotation);
@@ -5504,7 +5614,8 @@
         RECT rect;
         VERIFY(::GetWindowRect(p->GetHWnd(),&rect));
         result = JNU_NewObjectByName(env, "java/awt/Point", "(II)V",
-            rect.left, rect.top);
+                                     p->ScaleDownDX(rect.left),
+                                     p->ScaleDownDY(rect.top));
     }
 ret:
     env->DeleteGlobalRef(self);
@@ -7092,6 +7203,11 @@
         target = parent;
     }
 
+    x = ScaleUpDX(x);
+    y = ScaleUpDY(y);
+    width = ScaleUpX(width);
+    height = ScaleUpY(height);
+
     // Test whether component's bounds match the native window's
     RECT rect;
     VERIFY(::GetWindowRect(GetHWnd(), &rect));
@@ -7285,4 +7401,3 @@
         delete tmpDCList;
     }
 }
-
diff --git a/src/windows/native/sun/windows/awt_Component.h b/src/windows/native/sun/windows/awt_Component.h
index 780d810..85e6faa 100644
--- a/src/windows/native/sun/windows/awt_Component.h
+++ b/src/windows/native/sun/windows/awt_Component.h
@@ -521,7 +521,7 @@
     virtual MsgRouting WmMouseMove(UINT flags, int x, int y);
     virtual MsgRouting WmMouseExit(UINT flags, int x, int y);
     virtual MsgRouting WmMouseWheel(UINT flags, int x, int y,
-                                    int wheelRotation);
+                                    int wheelRotation, BOOL isHorizontal);
     virtual MsgRouting WmNcMouseDown(WPARAM hitTest, int x, int y, int button);
     virtual MsgRouting WmNcMouseUp(WPARAM hitTest, int x, int y, int button);
     virtual MsgRouting WmWindowPosChanging(LPARAM windowPos);
@@ -595,6 +595,10 @@
         return mrDoDefault;
     }
 
+    virtual MsgRouting WmDPIChanged(UINT xDPI, UINT yDPI, RECT* bounds) {
+        return mrDoDefault;
+    }
+
     void UpdateColorModel();
 
     jintArray CreatePrintedPixels(SIZE &loc, SIZE &size, int alpha);
@@ -716,6 +720,15 @@
         return m_bPauseDestroy;
     }
 
+    int ScaleUpX(int x);
+    int ScaleUpY(int y);
+    int ScaleDownX(int x);
+    int ScaleDownY(int y);
+    int ScaleUpDX(int x);
+    int ScaleUpDY(int y);
+    int ScaleDownDX(int x);
+    int ScaleDownDY(int y);
+
 protected:
     static AwtComponent* GetComponentImpl(HWND hWnd);
 
@@ -818,7 +831,8 @@
     int windowMoveLockPosCY;
 
     // 6524352: support finer-resolution
-    int m_wheelRotationAmount;
+    int m_wheelRotationAmountX;
+    int m_wheelRotationAmountY;
 
     BOOL deadKeyActive;
 
diff --git a/src/windows/native/sun/windows/awt_Cursor.cpp b/src/windows/native/sun/windows/awt_Cursor.cpp
index 3cdf9d8..1dccd48 100644
--- a/src/windows/native/sun/windows/awt_Cursor.cpp
+++ b/src/windows/native/sun/windows/awt_Cursor.cpp
@@ -473,6 +473,7 @@
 
     POINT p;
     ::GetCursorPos(&p);
+    AwtWin32GraphicsDevice::ScaleDownDPoint(&p);
     env->SetIntField(point, AwtCursor::pointXID, (jint)p.x);
     env->SetIntField(point, AwtCursor::pointYID, (jint)p.y);
 
diff --git a/src/windows/native/sun/windows/awt_DesktopProperties.cpp b/src/windows/native/sun/windows/awt_DesktopProperties.cpp
index 454a2fe..ba66d7d 100644
--- a/src/windows/native/sun/windows/awt_DesktopProperties.cpp
+++ b/src/windows/native/sun/windows/awt_DesktopProperties.cpp
@@ -27,6 +27,7 @@
 #include "mmsystem.h"
 #include "jlong.h"
 #include "awt_DesktopProperties.h"
+#include "awt_Win32GraphicsDevice.h"
 #include "awt_Toolkit.h"
 #include "sun_awt_windows_WDesktopProperties.h"
 #include "java_awt_Font.h"
@@ -35,6 +36,8 @@
 #include <shellapi.h>
 #include <shlobj.h>
 
+#include "math.h"
+
 // WDesktopProperties fields
 jfieldID AwtDesktopProperties::pDataID = 0;
 jmethodID AwtDesktopProperties::setBooleanPropertyID = 0;
@@ -79,18 +82,40 @@
     }
 }
 
+void getInvScale(float &invScaleX, float &invScaleY) {
+    if (!AwtWin32GraphicsDevice::IsUiScaleEnabled()) {
+        invScaleX = 1.0f;
+        invScaleY = 1.0f;
+        return;
+    }
+    HWND hWnd = ::GetDesktopWindow();
+    HDC hDC = ::GetDC(hWnd);
+    int dpiX = ::GetDeviceCaps(hDC, LOGPIXELSX);
+    int dpiY = ::GetDeviceCaps(hDC, LOGPIXELSY);
+    ::ReleaseDC(hWnd, hDC);
+    invScaleX = (dpiX == 0.0f) ? 1.0f : 96.0f / dpiX;
+    invScaleY = (dpiY == 0.0f) ? 1.0f : 96.0f / dpiY;
+}
+
+int rescale(int value, float invScale){
+    return invScale == 1.0f ? value : (int)round(value * invScale);
+}
+
 void AwtDesktopProperties::GetSystemProperties() {
     HDC dc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
 
     if (dc != NULL) {
         try {
-            SetFontProperty(dc, ANSI_FIXED_FONT, TEXT("win.ansiFixed.font"));
-            SetFontProperty(dc, ANSI_VAR_FONT, TEXT("win.ansiVar.font"));
-            SetFontProperty(dc, DEVICE_DEFAULT_FONT, TEXT("win.deviceDefault.font"));
-            SetFontProperty(dc, DEFAULT_GUI_FONT, TEXT("win.defaultGUI.font"));
-            SetFontProperty(dc, OEM_FIXED_FONT, TEXT("win.oemFixed.font"));
-            SetFontProperty(dc, SYSTEM_FONT, TEXT("win.system.font"));
-            SetFontProperty(dc, SYSTEM_FIXED_FONT, TEXT("win.systemFixed.font"));
+            float invScaleX;
+            float invScaleY;
+            getInvScale(invScaleX, invScaleY);
+            SetFontProperty(dc, ANSI_FIXED_FONT, TEXT("win.ansiFixed.font"), 1.0f);
+            SetFontProperty(dc, ANSI_VAR_FONT, TEXT("win.ansiVar.font"), 1.0f);
+            SetFontProperty(dc, DEVICE_DEFAULT_FONT, TEXT("win.deviceDefault.font"), 1.0f);
+            SetFontProperty(dc, DEFAULT_GUI_FONT, TEXT("win.defaultGUI.font"), invScaleY);
+            SetFontProperty(dc, OEM_FIXED_FONT, TEXT("win.oemFixed.font"), 1.0f);
+            SetFontProperty(dc, SYSTEM_FONT, TEXT("win.system.font"), 1.0f);
+            SetFontProperty(dc, SYSTEM_FIXED_FONT, TEXT("win.systemFixed.font"), 1.0f);
         }
         catch (std::bad_alloc&) {
             DeleteDC(dc);
@@ -266,31 +291,35 @@
     }
     VERIFY( SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncmetrics.cbSize, &ncmetrics, FALSE) );
 
-    SetFontProperty( TEXT("win.frame.captionFont"), ncmetrics.lfCaptionFont );
-    SetIntegerProperty( TEXT("win.frame.captionHeight"), ncmetrics.iCaptionHeight );
-    SetIntegerProperty( TEXT("win.frame.captionButtonWidth"), ncmetrics.iCaptionWidth );
-    SetIntegerProperty( TEXT("win.frame.captionButtonHeight"), ncmetrics.iCaptionHeight );
-    SetFontProperty( TEXT("win.frame.smallCaptionFont"), ncmetrics.lfSmCaptionFont );
-    SetIntegerProperty( TEXT("win.frame.smallCaptionHeight"), ncmetrics.iSmCaptionHeight );
-    SetIntegerProperty( TEXT("win.frame.smallCaptionButtonWidth"), ncmetrics.iSmCaptionWidth );
-    SetIntegerProperty( TEXT("win.frame.smallCaptionButtonHeight"), ncmetrics.iSmCaptionHeight );
-    SetIntegerProperty( TEXT("win.frame.sizingBorderWidth"), ncmetrics.iBorderWidth );
+    float invScaleX;
+    float invScaleY;
+    getInvScale(invScaleX, invScaleY);
+
+    SetFontProperty(TEXT("win.frame.captionFont"), ncmetrics.lfCaptionFont, invScaleY);
+    SetIntegerProperty(TEXT("win.frame.captionHeight"), rescale(ncmetrics.iCaptionHeight, invScaleY));
+    SetIntegerProperty(TEXT("win.frame.captionButtonWidth"), rescale(ncmetrics.iCaptionWidth, invScaleX));
+    SetIntegerProperty(TEXT("win.frame.captionButtonHeight"), rescale(ncmetrics.iCaptionHeight, invScaleY));
+    SetFontProperty(TEXT("win.frame.smallCaptionFont"), ncmetrics.lfSmCaptionFont, invScaleY);
+    SetIntegerProperty(TEXT("win.frame.smallCaptionHeight"), rescale(ncmetrics.iSmCaptionHeight, invScaleY));
+    SetIntegerProperty(TEXT("win.frame.smallCaptionButtonWidth"), rescale(ncmetrics.iSmCaptionWidth, invScaleX));
+    SetIntegerProperty(TEXT("win.frame.smallCaptionButtonHeight"), rescale(ncmetrics.iSmCaptionHeight, invScaleY));
+    SetIntegerProperty(TEXT("win.frame.sizingBorderWidth"), rescale(ncmetrics.iBorderWidth, invScaleX));
 
     // menu properties
-    SetFontProperty( TEXT("win.menu.font"), ncmetrics.lfMenuFont );
-    SetIntegerProperty( TEXT("win.menu.height"), ncmetrics.iMenuHeight );
-    SetIntegerProperty( TEXT("win.menu.buttonWidth"), ncmetrics.iMenuWidth );
+    SetFontProperty(TEXT("win.menu.font"), ncmetrics.lfMenuFont, invScaleY);
+    SetIntegerProperty(TEXT("win.menu.height"), rescale(ncmetrics.iMenuHeight, invScaleY));
+    SetIntegerProperty(TEXT("win.menu.buttonWidth"), rescale(ncmetrics.iMenuWidth, invScaleX));
 
     // scrollbar properties
-    SetIntegerProperty( TEXT("win.scrollbar.width"), ncmetrics.iScrollWidth );
-    SetIntegerProperty( TEXT("win.scrollbar.height"), ncmetrics.iScrollHeight );
+    SetIntegerProperty(TEXT("win.scrollbar.width"), rescale(ncmetrics.iScrollWidth, invScaleX));
+    SetIntegerProperty(TEXT("win.scrollbar.height"), rescale(ncmetrics.iScrollHeight, invScaleY));
 
     // status bar and tooltip properties
-    SetFontProperty( TEXT("win.status.font"), ncmetrics.lfStatusFont );
-    SetFontProperty( TEXT("win.tooltip.font"), ncmetrics.lfStatusFont );
+    SetFontProperty(TEXT("win.status.font"), ncmetrics.lfStatusFont, invScaleY);
+    SetFontProperty(TEXT("win.tooltip.font"), ncmetrics.lfStatusFont, invScaleY);
 
     // message box properties
-    SetFontProperty( TEXT("win.messagebox.font"), ncmetrics.lfMessageFont );
+    SetFontProperty(TEXT("win.messagebox.font"), ncmetrics.lfMessageFont, invScaleY);
 }
 
 void AwtDesktopProperties::GetIconParameters() {
@@ -302,10 +331,13 @@
     iconmetrics.cbSize = sizeof(iconmetrics);
     VERIFY( SystemParametersInfo(SPI_GETICONMETRICS, iconmetrics.cbSize, &iconmetrics, FALSE) );
 
-    SetIntegerProperty(TEXT("win.icon.hspacing"), iconmetrics.iHorzSpacing);
-    SetIntegerProperty(TEXT("win.icon.vspacing"), iconmetrics.iVertSpacing);
+    float invScaleX;
+    float invScaleY;
+    getInvScale(invScaleX, invScaleY);
+    SetIntegerProperty(TEXT("win.icon.hspacing"), rescale(iconmetrics.iHorzSpacing, invScaleX));
+    SetIntegerProperty(TEXT("win.icon.vspacing"), rescale(iconmetrics.iVertSpacing, invScaleY));
     SetBooleanProperty(TEXT("win.icon.titleWrappingOn"), iconmetrics.iTitleWrap != 0);
-    SetFontProperty(TEXT("win.icon.font"), iconmetrics.lfFont);
+    SetFontProperty(TEXT("win.icon.font"), iconmetrics.lfFont, invScaleY);
 }
 /*
  Windows settings for these are also in the registry
@@ -718,6 +750,7 @@
 }
 
 void AwtDesktopProperties::SetIntegerProperty(LPCTSTR propName, int value) {
+
     jstring key = JNU_NewStringPlatform(GetEnv(), propName);
     if (key == NULL) {
         throw std::bad_alloc();
@@ -752,8 +785,8 @@
 }
 
 void AwtDesktopProperties::SetFontProperty(HDC dc, int fontID,
-                                           LPCTSTR propName) {
-    HGDIOBJ font = GetStockObject(fontID);
+    LPCTSTR propName, float invScale) {
+        HGDIOBJ font = GetStockObject(fontID);
     if (font != NULL && SelectObject(dc, font) != NULL) {
         int length = GetTextFace(dc, 0, NULL);
 
@@ -789,8 +822,8 @@
                         throw std::bad_alloc();
                     }
 
-                    jint pointSize = metrics.tmHeight -
-                                     metrics.tmInternalLeading;
+                    jint pointSize = rescale(metrics.tmHeight -
+                                     metrics.tmInternalLeading, invScale);
                     jint style = java_awt_Font_PLAIN;
 
                     if (metrics.tmWeight >= FW_BOLD) {
@@ -818,7 +851,8 @@
     }
 }
 
-void AwtDesktopProperties::SetFontProperty(LPCTSTR propName, const LOGFONT & font) {
+void AwtDesktopProperties::SetFontProperty(LPCTSTR propName, const LOGFONT & font,
+    float invScale) {
     jstring fontName;
     jint pointSize;
     jint style;
@@ -836,7 +870,7 @@
     ReleaseDC(NULL, hdc);
 #endif
     // Java uses point sizes, but assumes 1 pixel = 1 point
-    pointSize = -font.lfHeight;
+    pointSize = rescale(-font.lfHeight, invScale);
 
     // convert Windows font style to Java style
     style = java_awt_Font_PLAIN;
diff --git a/src/windows/native/sun/windows/awt_DesktopProperties.h b/src/windows/native/sun/windows/awt_DesktopProperties.h
index e93530e..70f0bf8 100644
--- a/src/windows/native/sun/windows/awt_DesktopProperties.h
+++ b/src/windows/native/sun/windows/awt_DesktopProperties.h
@@ -73,8 +73,8 @@
         void SetIntegerProperty(LPCTSTR, int);
         void SetStringProperty(LPCTSTR, LPTSTR);
         void SetColorProperty(LPCTSTR, DWORD);
-        void SetFontProperty(HDC, int, LPCTSTR);
-        void SetFontProperty(LPCTSTR, const LOGFONT &);
+        void SetFontProperty(HDC, int, LPCTSTR, float invScale);
+        void SetFontProperty(LPCTSTR, const LOGFONT &, float invScale);
         void SetSoundProperty(LPCTSTR, LPCTSTR);
 
         JNIEnv * GetEnv() {
diff --git a/src/windows/native/sun/windows/awt_Dialog.cpp b/src/windows/native/sun/windows/awt_Dialog.cpp
index 7bb201b..607e607 100644
--- a/src/windows/native/sun/windows/awt_Dialog.cpp
+++ b/src/windows/native/sun/windows/awt_Dialog.cpp
@@ -250,6 +250,7 @@
             (wParam == WM_RBUTTONDOWN) ||
             (wParam == WM_MOUSEACTIVATE) ||
             (wParam == WM_MOUSEWHEEL) ||
+            (wParam == WM_MOUSEHWHEEL) ||
             (wParam == WM_NCLBUTTONDOWN) ||
             (wParam == WM_NCMBUTTONDOWN) ||
             (wParam == WM_NCRBUTTONDOWN))
diff --git a/src/windows/native/sun/windows/awt_DnDDS.cpp b/src/windows/native/sun/windows/awt_DnDDS.cpp
index 27999b6..7b8521b 100644
--- a/src/windows/native/sun/windows/awt_DnDDS.cpp
+++ b/src/windows/native/sun/windows/awt_DnDDS.cpp
@@ -263,6 +263,8 @@
     AwtDropTarget::SetCurrentDnDDataObject(dragSource);
 
     ::GetCursorPos(&dragSource->m_dragPoint);
+    POINT dragPoint = {dragSource->m_dragPoint.x, dragSource->m_dragPoint.y};
+    AwtWin32GraphicsDevice::ScaleDownDPoint(&dragPoint);
 
     dragSource->Signal();
 
@@ -279,7 +281,7 @@
 
     call_dSCddfinished(env, peer, res == DRAGDROP_S_DROP && effects != DROPEFFECT_NONE,
                        convertDROPEFFECTToActions(effects),
-                       dragSource->m_dragPoint.x, dragSource->m_dragPoint.y);
+                       dragPoint.x, dragPoint.y);
 
     env->DeleteLocalRef(peer);
 
@@ -638,11 +640,13 @@
     POINT dragPoint;
 
     ::GetCursorPos(&dragPoint);
+    POINT _dragPoint = {dragPoint.x, dragPoint.y};
+    AwtWin32GraphicsDevice::ScaleDownDPoint(&_dragPoint);
 
     if ( (dragPoint.x != m_dragPoint.x || dragPoint.y != m_dragPoint.y) &&
          m_lastmods == modifiers) {//cannot move before cursor change
         call_dSCmouseMoved(env, m_peer,
-                           m_actions, modifiers, dragPoint.x, dragPoint.y);
+                           m_actions, modifiers, _dragPoint.x, _dragPoint.y);
         JNU_CHECK_EXCEPTION_RETURN(env, E_UNEXPECTED);
         m_dragPoint = dragPoint;
     }
@@ -655,7 +659,7 @@
         return DRAGDROP_S_CANCEL;
     } else if (m_lastmods != modifiers) {
         call_dSCchanged(env, m_peer,
-                        m_actions, modifiers, dragPoint.x, dragPoint.y);
+                        m_actions, modifiers, _dragPoint.x, _dragPoint.y);
         m_bRestoreNodropCustomCursor = TRUE;
     }
 
@@ -709,6 +713,8 @@
     POINT curs;
 
     ::GetCursorPos(&curs);
+    POINT _curs = {curs.x, curs.y};
+    AwtWin32GraphicsDevice::ScaleDownDPoint(&_curs);
 
     m_droptarget = ::WindowFromPoint(curs);
 
@@ -717,13 +723,13 @@
     if (invalid) {
         // Don't call dragExit if dragEnter and dragOver haven't been called.
         if (!m_enterpending) {
-            call_dSCexit(env, m_peer, curs.x, curs.y);
+            call_dSCexit(env, m_peer, _curs.x, _curs.y);
         }
         m_droptarget = (HWND)NULL;
         m_enterpending = TRUE;
     } else if (m_droptarget != NULL) {
         (*(m_enterpending ? call_dSCenter : call_dSCmotion))
-            (env, m_peer, m_actions, modifiers, curs.x, curs.y);
+            (env, m_peer, m_actions, modifiers, _curs.x, _curs.y);
 
         m_enterpending = FALSE;
     }
diff --git a/src/windows/native/sun/windows/awt_DnDDT.cpp b/src/windows/native/sun/windows/awt_DnDDT.cpp
index 8739fc8..8e14739 100644
--- a/src/windows/native/sun/windows/awt_DnDDT.cpp
+++ b/src/windows/native/sun/windows/awt_DnDDT.cpp
@@ -173,9 +173,8 @@
         RECT  wr;
 
         ::GetWindowRect(m_window, &wr);
-
-        cp.x = pt.x - wr.left;
-        cp.y = pt.y - wr.top;
+        cp.x = m_component->ScaleDownX(pt.x - wr.left);
+        cp.y = m_component->ScaleDownY(pt.y - wr.top);
 
         jint actions = call_dTCenter(env, m_dtcp, m_target,
                                      (jint)cp.x, (jint)cp.y,
@@ -235,8 +234,8 @@
 
     ::GetWindowRect(m_window, &wr);
 
-    cp.x = pt.x - wr.left;
-    cp.y = pt.y - wr.top;
+    cp.x = m_component->ScaleDownX(pt.x - wr.left);
+    cp.y = m_component->ScaleDownY(pt.y - wr.top);
 
     actions = call_dTCmotion(env, m_dtcp, m_target,(jint)cp.x, (jint)cp.y,
                              ::convertDROPEFFECTToActions(mapModsToDROPEFFECT(*pdwEffect, grfKeyState)),
@@ -334,8 +333,8 @@
 
     ::GetWindowRect(m_window, &wr);
 
-    cp.x = pt.x - wr.left;
-    cp.y = pt.y - wr.top;
+    cp.x = m_component->ScaleDownX(pt.x - wr.left);
+    cp.y = m_component->ScaleDownY(pt.y - wr.top);
 
     m_dropActions = java_awt_dnd_DnDConstants_ACTION_NONE;
 
diff --git a/src/windows/native/sun/windows/awt_Font.cpp b/src/windows/native/sun/windows/awt_Font.cpp
index abdffdc..748dc41 100644
--- a/src/windows/native/sun/windows/awt_Font.cpp
+++ b/src/windows/native/sun/windows/awt_Font.cpp
@@ -400,6 +400,38 @@
 
 }
 
+static int ScaleUpX(float x) {
+    int deviceIndex = AwtWin32GraphicsDevice::DeviceIndexForWindow(
+        ::GetDesktopWindow());
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice *device = devices->GetDevice(deviceIndex);
+    return device == NULL ? x : device->ScaleUpX(x);
+}
+
+static int ScaleUpY(int y) {
+    int deviceIndex = AwtWin32GraphicsDevice::DeviceIndexForWindow(
+        ::GetDesktopWindow());
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice *device = devices->GetDevice(deviceIndex);
+    return device == NULL ? y : device->ScaleUpY(y);
+}
+
+static int ScaleDownX(int x) {
+    int deviceIndex = AwtWin32GraphicsDevice::DeviceIndexForWindow(
+        ::GetDesktopWindow());
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice *device = devices->GetDevice(deviceIndex);
+    return device == NULL ? x : device->ScaleDownX(x);
+}
+
+static int ScaleDownY(int y) {
+    int deviceIndex = AwtWin32GraphicsDevice::DeviceIndexForWindow(
+        ::GetDesktopWindow());
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice *device = devices->GetDevice(deviceIndex);
+    return device == NULL ? y : device->ScaleDownY(y);
+}
+
 static HFONT CreateHFont_sub(LPCWSTR name, int style, int height,
                              int angle=0, float awScale=1.0f)
 {
@@ -426,7 +458,7 @@
     logFont.lfUnderline = 0;//(style & java_awt_Font_UNDERLINE) != 0;
 
     // Get point size
-    logFont.lfHeight = -height;
+    logFont.lfHeight = ScaleUpY(-height);
 
     // Set font name
     WCHAR tmpname[80];
@@ -453,7 +485,7 @@
             VERIFY(::DeleteObject(oldFont));
         }
         avgWidth = tm.tmAveCharWidth;
-        logFont.lfWidth = (LONG)((fabs)(avgWidth*awScale));
+        logFont.lfWidth = (LONG) ScaleUpX((fabs) (avgWidth * awScale));
         hFont = ::CreateFontIndirect(&logFont);
         DASSERT(hFont != NULL);
         VERIFY(::ReleaseDC(0, hDC));
@@ -537,19 +569,20 @@
     int ascent = metrics.tmAscent;
     int descent = metrics.tmDescent;
     int leading = metrics.tmExternalLeading;
-    env->SetIntField(fontMetrics, AwtFont::ascentID, ascent);
-    env->SetIntField(fontMetrics, AwtFont::descentID, descent);
-    env->SetIntField(fontMetrics, AwtFont::leadingID, leading);
-    env->SetIntField(fontMetrics, AwtFont::heightID, metrics.tmAscent +
-                     metrics.tmDescent + leading);
-    env->SetIntField(fontMetrics, AwtFont::maxAscentID, ascent);
-    env->SetIntField(fontMetrics, AwtFont::maxDescentID, descent);
+
+    env->SetIntField(fontMetrics, AwtFont::ascentID, ScaleDownY(ascent));
+    env->SetIntField(fontMetrics, AwtFont::descentID, ScaleDownY(descent));
+    env->SetIntField(fontMetrics, AwtFont::leadingID, ScaleDownX(leading));
+    env->SetIntField(fontMetrics, AwtFont::heightID,
+        ScaleDownY(metrics.tmAscent + metrics.tmDescent + leading));
+    env->SetIntField(fontMetrics, AwtFont::maxAscentID, ScaleDownY(ascent));
+    env->SetIntField(fontMetrics, AwtFont::maxDescentID, ScaleDownY(descent));
 
     int maxHeight =  ascent + descent + leading;
-    env->SetIntField(fontMetrics, AwtFont::maxHeightID, maxHeight);
+    env->SetIntField(fontMetrics, AwtFont::maxHeightID, ScaleDownY(maxHeight));
 
     int maxAdvance = metrics.tmMaxCharWidth;
-    env->SetIntField(fontMetrics, AwtFont::maxAdvanceID, maxAdvance);
+    env->SetIntField(fontMetrics, AwtFont::maxAdvanceID, ScaleDownX(maxAdvance));
 
     awtFont->m_overhang = metrics.tmOverhang;
 
@@ -824,6 +857,7 @@
     jobject font = env->GetObjectField(self, AwtFont::fontID);
 
     long ret = AwtFont::getMFStringWidth(hDC, font, str);
+    ret = ScaleDownX(ret);
     VERIFY(::ReleaseDC(0, hDC));
     return ret;
 
@@ -930,7 +964,7 @@
     }
 
     env->ReleasePrimitiveArrayCritical(str, pStrBody, 0);
-    return result;
+    return ScaleDownX(result);
 
     CATCH_BAD_ALLOC_RET(0);
 }
diff --git a/src/windows/native/sun/windows/awt_Robot.cpp b/src/windows/native/sun/windows/awt_Robot.cpp
index 7739af4..88cb497 100644
--- a/src/windows/native/sun/windows/awt_Robot.cpp
+++ b/src/windows/native/sun/windows/awt_Robot.cpp
@@ -80,6 +80,10 @@
                                      (PVOID)newSpeed,
                                      SPIF_SENDCHANGE);
 
+      AwtWin32GraphicsDevice *device = AwtWin32GraphicsDevice::GetDeviceByBounds(RECT_BOUNDS(x, y, 0, 0));
+      x = device == NULL ? x : device->ScaleUpDX(x);
+      y = device == NULL ? y : device->ScaleUpDY(y);
+
       POINT curPos;
       ::GetCursorPos(&curPos);
       x -= curPos.x;
@@ -217,11 +221,24 @@
         AwtWin32GraphicsDevice::SelectPalette(hdcMem, primaryIndex);
     AwtWin32GraphicsDevice::RealizePalette(hdcMem, primaryIndex);
 
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice *device = devices->GetDevice(primaryIndex);
+    int sWidth = (device == NULL) ? width : device->ScaleUpX(width);
+    int sHeight = (device == NULL) ? height : device->ScaleUpY(height);
+
     // copy screen image to offscreen bitmap
     // CAPTUREBLT flag is required to capture WS_EX_LAYERED windows' contents
     // correctly on Win2K/XP
-    VERIFY(::BitBlt(hdcMem, 0, 0, width, height, hdcScreen, x, y,
-                                                SRCCOPY|CAPTUREBLT) != 0);
+    if (width == sWidth && height == sHeight) {
+        VERIFY(::BitBlt(hdcMem, 0, 0, width, height, hdcScreen, x, y,
+               SRCCOPY | CAPTUREBLT) != 0);
+    } else {
+        int sX = (device == NULL) ? x : device->ScaleUpDX(x);
+        int sY = (device == NULL) ? y : device->ScaleUpDY(y);
+        VERIFY(::StretchBlt(hdcMem, 0, 0, width, height,
+               hdcScreen, sX, sY, sWidth, sHeight,
+               SRCCOPY | CAPTUREBLT) != 0);
+    }
 
     static const int BITS_PER_PIXEL = 32;
     static const int BYTES_PER_PIXEL = BITS_PER_PIXEL/8;
diff --git a/src/windows/native/sun/windows/awt_Toolkit.cpp b/src/windows/native/sun/windows/awt_Toolkit.cpp
index dcb4ea7..987403f 100644
--- a/src/windows/native/sun/windows/awt_Toolkit.cpp
+++ b/src/windows/native/sun/windows/awt_Toolkit.cpp
@@ -1394,7 +1394,7 @@
     if (p && p->PreProcessMsg(msg) == mrConsume)
         return TRUE;
 
-    if ((msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) ||
+    if ((msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) || (msg.message == WM_MOUSEHWHEEL) ||
         (msg.message >= WM_NCMOUSEMOVE && msg.message <= WM_NCMBUTTONDBLCLK)) {
         if (PreProcessMouseMsg(p, msg)) {
             return TRUE;
@@ -1421,7 +1421,7 @@
         return FALSE;
     }
 
-    if (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) {
+    if ((msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) || (msg.message == WM_MOUSEHWHEEL)) {
         mouseWParam = msg.wParam;
         mouseLParam = msg.lParam;
     } else {
@@ -1510,7 +1510,7 @@
      * the mouse, not the Component with the input focus.
      */
 
-    if (msg.message == WM_MOUSEWHEEL) {
+    if (msg.message == WM_MOUSEWHEEL || msg.message == WM_MOUSEHWHEEL) {
             //i.e. mouse is over client area for this window
             DWORD hWndForWheelProcess;
             DWORD hWndForWheelThread = ::GetWindowThreadProcessId(hWndForWheel, &hWndForWheelProcess);
@@ -2355,8 +2355,13 @@
 {
     TRY;
 
-    return ::GetSystemMetrics(SM_CXSCREEN);
+    int width = ::GetSystemMetrics(SM_CXSCREEN);
 
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice *device = devices->GetDevice(
+                        AwtWin32GraphicsDevice::GetDefaultDeviceIndex());
+
+    return (device == NULL) ? width : device->ScaleDownX(width);
     CATCH_BAD_ALLOC_RET(0);
 }
 
@@ -2370,7 +2375,12 @@
 {
     TRY;
 
-    return ::GetSystemMetrics(SM_CYSCREEN);
+    int height = ::GetSystemMetrics(SM_CYSCREEN);
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice *device = devices->GetDevice(
+                        AwtWin32GraphicsDevice::GetDefaultDeviceIndex());
+
+    return (device == NULL) ? height : device->ScaleDownY(height);
 
     CATCH_BAD_ALLOC_RET(0);
 }
diff --git a/src/windows/native/sun/windows/awt_Win32GraphicsConfig.cpp b/src/windows/native/sun/windows/awt_Win32GraphicsConfig.cpp
index 918ed08..5e0e6ac 100644
--- a/src/windows/native/sun/windows/awt_Win32GraphicsConfig.cpp
+++ b/src/windows/native/sun/windows/awt_Win32GraphicsConfig.cpp
@@ -77,6 +77,35 @@
     return mask;
 }
 
+RECT AwtWin32GraphicsConfig::getMonitorBounds(int screen)
+{
+    RECT rRW = {0, 0, 0, 0};
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
+
+    if (TRUE == MonitorBounds(AwtWin32GraphicsDevice::GetMonitor(screen), &rRW)) {
+        // don't scale xy to avoid overlapping of the multi-dpi-monitors bounds in the user space
+        int x = rRW.left;
+        int y = rRW.top;
+        int w = (device == NULL) ? rRW.right - rRW.left
+                                 : device->ScaleDownX(rRW.right - rRW.left);
+        int h = (device == NULL) ? rRW.bottom - rRW.top
+                                 : device->ScaleDownY(rRW.bottom - rRW.top);
+
+        ::SetRect(&rRW, x, y, x + w, y + h);
+    }
+    else {
+        // 4910760 - don't return a null bounds, return the bounds of the
+        // primary screen
+        int w = ::GetSystemMetrics(SM_CXSCREEN);
+        int h = ::GetSystemMetrics(SM_CYSCREEN);
+
+        ::SetRect(&rRW, 0, 0, device == NULL ? w : device->ScaleDownX(w),
+                              device == NULL ? h : device->ScaleDownY(h));
+    }
+    return rRW;
+}
+
 /*
  * Class:     sun_awt_Win32GraphicsConfig
  * Method:    getBounds
@@ -94,21 +123,8 @@
     CHECK_NULL_RETURN(clazz, NULL);
     mid = env->GetMethodID(clazz, "<init>", "(IIII)V");
     if (mid != 0) {
-        RECT rRW = {0, 0, 0, 0};
-        if (TRUE == MonitorBounds(AwtWin32GraphicsDevice::GetMonitor(screen), &rRW)) {
-            bounds = env->NewObject(clazz, mid,
-                                    rRW.left, rRW.top,
-                                    rRW.right - rRW.left,
-                                    rRW.bottom - rRW.top);
-        }
-        else {
-            // 4910760 - don't return a null bounds, return the bounds of the
-            // primary screen
-            bounds = env->NewObject(clazz, mid,
-                                    0, 0,
-                                    ::GetSystemMetrics(SM_CXSCREEN),
-                                    ::GetSystemMetrics(SM_CYSCREEN));
-        }
+        RECT r = AwtWin32GraphicsConfig::getMonitorBounds((int)screen);
+        bounds = env->NewObject(clazz, mid, r.left, r.top, r.right - r.left, r.bottom - r.top);
         if (safe_ExceptionOccurred(env)) {
            return 0;
         }
diff --git a/src/windows/native/sun/windows/awt_Win32GraphicsConfig.h b/src/windows/native/sun/windows/awt_Win32GraphicsConfig.h
index 5cfd7f7..726402b 100644
--- a/src/windows/native/sun/windows/awt_Win32GraphicsConfig.h
+++ b/src/windows/native/sun/windows/awt_Win32GraphicsConfig.h
@@ -32,6 +32,7 @@
 public:
         /* sun.awt.Win32GraphicsConfig fields and method IDs */
         static jfieldID win32GCVisualID;
+        static RECT getMonitorBounds(int screen);
 };
 
 #endif /* AWT_WIN32GRAPHICSCONFIG_H */
diff --git a/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp b/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp
index b7ab7e0..eddfb29 100644
--- a/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp
+++ b/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp
@@ -41,6 +41,7 @@
 #include <sun_awt_Win32GraphicsDevice.h>
 #include "awt_Canvas.h"
 #include "awt_Win32GraphicsDevice.h"
+#include "awt_Win32GraphicsConfig.h"
 #include "awt_Window.h"
 #include "java_awt_Transparency.h"
 #include "java_awt_color_ColorSpace.h"
@@ -49,6 +50,12 @@
 #include "dither.h"
 #include "img_util_md.h"
 #include "Devices.h"
+#include <d2d1.h>
+#pragma comment(lib, "d2d1")
+
+#ifndef MDT_Effective_DPI
+#define MDT_Effective_DPI 0
+#endif
 
 uns_ordered_dither_array img_oda_alpha;
 
@@ -74,6 +81,8 @@
 {
     this->screen  = screen;
     this->devicesArray = arr;
+    this->scaleX = 1;
+    this->scaleY = 1;
     javaDevice = NULL;
     colorData = new ImgColorData;
     colorData->grayscale = GS_NOTGRAY;
@@ -617,6 +626,149 @@
 }
 
 /**
+ * Sets horizontal and vertical scale factors
+ */
+void AwtWin32GraphicsDevice::SetScale(float sx, float sy)
+{
+    scaleX = sx;
+    scaleY = sy;
+}
+
+int AwtWin32GraphicsDevice::ScaleUpX(int x)
+{
+    return (int)ceil(x * scaleX);
+}
+
+// scale up the delta [x - device.x]
+int AwtWin32GraphicsDevice::ScaleUpDX(int x)
+{
+    RECT devBounds = AwtWin32GraphicsConfig::getMonitorBounds(screen);
+    return devBounds.left + (int)ceil((x - devBounds.left) * scaleX);
+}
+
+int AwtWin32GraphicsDevice::ScaleUpY(int y)
+{
+    return (int)ceil(y * scaleY);
+}
+
+// scale up the delta [y - device.y]
+int AwtWin32GraphicsDevice::ScaleUpDY(int y)
+{
+    RECT devBounds = AwtWin32GraphicsConfig::getMonitorBounds(screen);
+    return devBounds.top + (int)ceil((y - devBounds.top) * scaleY);
+}
+
+int AwtWin32GraphicsDevice::ScaleDownX(int x)
+{
+    return (int)ceil(x / scaleX);
+}
+
+// scale down the delta [x - device.x]
+int AwtWin32GraphicsDevice::ScaleDownDX(int x)
+{
+    RECT devBounds = AwtWin32GraphicsConfig::getMonitorBounds(screen);
+    return devBounds.left + (int)ceil((x - devBounds.left) / scaleX);
+}
+
+int AwtWin32GraphicsDevice::ScaleDownY(int y)
+{
+    return (int)ceil(y / scaleY);
+}
+
+// scale down the delta [y - device.y]
+int AwtWin32GraphicsDevice::ScaleDownDY(int y)
+{
+    RECT devBounds = AwtWin32GraphicsConfig::getMonitorBounds(screen);
+    return devBounds.top + (int)ceil((y - devBounds.top) / scaleY);
+}
+
+// scale down the delta [pt.xy - device.xy]
+void AwtWin32GraphicsDevice::ScaleDownDPoint(POINT *pt)
+{
+    HMONITOR hmon = ::MonitorFromPoint(*pt, MONITOR_DEFAULTTONEAREST);
+    DASSERT(hmon != NULL);
+    int screen = AwtWin32GraphicsDevice::GetScreenFromHMONITOR(hmon);
+    DASSERT(screen > -1);
+
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
+    pt->x = device == NULL ? pt->x : device->ScaleDownDX(pt->x);
+    pt->y = device == NULL ? pt->y : device->ScaleDownDY(pt->y);
+}
+
+void AwtWin32GraphicsDevice::InitDesktopScales(bool fractionalScaleEnabled)
+{
+    unsigned x = 0;
+    unsigned y = 0;
+    float dpiX = -1.0f;
+    float dpiY = -1.0f;
+
+    // for debug purposes
+    static float scale = -2.0f;
+    if (scale == -2) {
+        scale = -1;
+        char *uiScale = getenv("J2D_UISCALE");
+        if (uiScale != NULL) {
+            scale = (float)strtod(uiScale, NULL);
+            if (errno == ERANGE || scale <= 0) {
+                scale = -1;
+            }
+        }
+    }
+
+    if (scale > 0) {
+        SetScale(scale, scale);
+        return;
+    }
+
+    typedef HRESULT(WINAPI GetDpiForMonitorFunc)(HMONITOR, int, UINT*, UINT*);
+    static HMODULE hLibSHCoreDll = NULL;
+    static GetDpiForMonitorFunc *lpGetDpiForMonitor = NULL;
+
+    if (hLibSHCoreDll == NULL) {
+        hLibSHCoreDll = JDK_LoadSystemLibrary("shcore.dll");
+        if (hLibSHCoreDll != NULL) {
+            lpGetDpiForMonitor = (GetDpiForMonitorFunc*)GetProcAddress(
+                hLibSHCoreDll, "GetDpiForMonitor");
+        }
+    }
+
+    if (lpGetDpiForMonitor != NULL) {
+        HRESULT hResult = lpGetDpiForMonitor(GetMonitor(),
+                                             MDT_Effective_DPI, &x, &y);
+        if (hResult == S_OK) {
+            dpiX = static_cast<float>(x);
+            dpiY = static_cast<float>(y);
+        }
+    } else {
+        ID2D1Factory* m_pDirect2dFactory;
+        HRESULT res = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
+                                        &m_pDirect2dFactory);
+        if (res == S_OK) {
+            m_pDirect2dFactory->GetDesktopDpi(&dpiX, &dpiY);
+            m_pDirect2dFactory->Release();
+        }
+    }
+
+    float scaleX = dpiX / 96;
+    float scaleY = dpiY / 96;
+    bool isFractScale = (scaleX != (int)scaleX || scaleY != (int)scaleY);
+    if (scaleX > 0 && scaleY > 0 && (fractionalScaleEnabled || !isFractScale)) {
+        SetScale(scaleX, scaleY);
+    }
+}
+
+float AwtWin32GraphicsDevice::GetScaleX()
+{
+    return scaleX;
+}
+
+float AwtWin32GraphicsDevice::GetScaleY()
+{
+    return scaleY;
+}
+
+/**
  * Disables offscreen acceleration for this device.  This
  * sets a flag in the java object that is used to determine
  * whether offscreen surfaces can be created on the device.
@@ -821,6 +973,31 @@
  * End of static deviceIndex-based methods
  */
 
+BOOL AwtWin32GraphicsDevice::IsUiScaleEnabled()
+{
+    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
+    static jclass cls = env->FindClass("sun/java2d/SunGraphicsEnvironment");
+    CHECK_NULL_RETURN(cls, FALSE);
+
+    static jmethodID isUIScaleEnabledID = env->GetStaticMethodID(cls, "isUIScaleEnabled", "()Z");
+    CHECK_NULL_RETURN(isUIScaleEnabledID, FALSE);
+
+    return (BOOL)env->CallStaticBooleanMethod(cls, isUIScaleEnabledID);
+}
+
+AwtWin32GraphicsDevice* AwtWin32GraphicsDevice::GetDeviceByBounds(RECT_BOUNDS bounds, HWND hwnd) // bounds in user space
+{
+    Devices::InstanceAccess devices;
+    POINT center = {bounds.x + bounds.width / 2, bounds.y + bounds.height / 2};
+    for (int i = 0; i < devices->GetNumDevices(); i++) {
+        RECT rect = AwtWin32GraphicsConfig::getMonitorBounds(i); // rect in user space
+        if (::PtInRect(&rect, center)) {
+            return devices->GetDevice(i);
+        }
+    }
+    // default to the hwnd's device
+    return hwnd != NULL ? devices->GetDevice(AwtWin32GraphicsDevice::DeviceIndexForWindow(hwnd)) : NULL;
+}
 
     const DWORD REQUIRED_FLAGS = (   //Flags which must be set in
      PFD_SUPPORT_GDI |               //in the PixelFormatDescriptor.
@@ -1307,3 +1484,65 @@
     Devices::InstanceAccess devices;
     devices->GetDevice(screen)->SetJavaDevice(env, thisPtr);
 }
+
+/*
+ * Class:     sun_awt_Win32GraphicsDevice
+ * Method:    setNativeScale
+ * Signature: (I,F,F)V
+ */
+JNIEXPORT void JNICALL
+    Java_sun_awt_Win32GraphicsDevice_setNativeScale
+    (JNIEnv *env, jobject thisPtr, jint screen, jfloat scaleX, jfloat scaleY)
+{
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
+
+    if (device != NULL ) {
+        device->SetScale(scaleX, scaleY);
+    }
+}
+
+/*
+ * Class:     sun_awt_Win32GraphicsDevice
+ * Method:    getNativeScaleX
+ * Signature: (I)F
+ */
+JNIEXPORT jfloat JNICALL
+    Java_sun_awt_Win32GraphicsDevice_getNativeScaleX
+    (JNIEnv *env, jobject thisPtr, jint screen)
+{
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
+    return (device == NULL) ? 1 : device->GetScaleX();
+}
+
+/*
+ * Class:     sun_awt_Win32GraphicsDevice
+ * Method:    getNativeScaleY
+ * Signature: (I)F
+ */
+JNIEXPORT jfloat JNICALL
+    Java_sun_awt_Win32GraphicsDevice_getNativeScaleY
+    (JNIEnv *env, jobject thisPtr, jint screen)
+{
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
+    return (device == NULL) ? 1 : device->GetScaleY();
+}
+
+/*
+* Class:     sun_awt_Win32GraphicsDevice
+* Method:    initNativeScale
+* Signature: (I)V;
+*/
+JNIEXPORT void JNICALL
+Java_sun_awt_Win32GraphicsDevice_initNativeScale
+(JNIEnv *env, jobject thisPtr, jint screen, jboolean fractionalScaleEnabled)
+{
+    Devices::InstanceAccess devices;
+    AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
+
+    if (device != NULL) {
+        device->InitDesktopScales((bool)fractionalScaleEnabled);
+    }
+}
\ No newline at end of file
diff --git a/src/windows/native/sun/windows/awt_Win32GraphicsDevice.h b/src/windows/native/sun/windows/awt_Win32GraphicsDevice.h
index e09b4fc..a391bf3 100644
--- a/src/windows/native/sun/windows/awt_Win32GraphicsDevice.h
+++ b/src/windows/native/sun/windows/awt_Win32GraphicsDevice.h
@@ -34,6 +34,14 @@
 #include "awt_Palette.h"
 #include "Devices.h"
 
+struct RECT_BOUNDS {
+    int x;
+    int y;
+    int width;
+    int height;
+    RECT_BOUNDS(int _x, int _y, int _w, int _h) : x(_x), y(_y), width(_w), height(_h) {}
+};
+
 class AwtPalette;
 class Devices;
 
@@ -66,7 +74,20 @@
     void                    Release();
     void                    DisableOffscreenAcceleration();
     void                    Invalidate(JNIEnv *env);
+    void                    InitDesktopScales(bool fractionalScaleEnabled);
+    void                    SetScale(float scaleX, float scaleY);
+    float                   GetScaleX();
+    float                   GetScaleY();
+    int                     ScaleUpX(int x);
+    int                     ScaleUpY(int y);
+    int                     ScaleDownX(int x);
+    int                     ScaleDownY(int y);
+    int                     ScaleUpDX(int x);
+    int                     ScaleUpDY(int y);
+    int                     ScaleDownDX(int x);
+    int                     ScaleDownDY(int y);
 
+    static void             ScaleDownDPoint(POINT *pt);
     static int              DeviceIndexForWindow(HWND hWnd);
     static jobject          GetColorModel(JNIEnv *env, jboolean dynamic,
                                           int deviceIndex);
@@ -85,6 +106,15 @@
     static void             DisableOffscreenAccelerationForDevice(HMONITOR hMonitor);
     static HDC              GetDCFromScreen(int screen);
     static int              GetScreenFromHMONITOR(HMONITOR mon);
+    static BOOL             IsUiScaleEnabled(); // if not, be dpi-unaware (backward compatible behaviour)
+    static AwtWin32GraphicsDevice* GetDeviceByBounds(RECT_BOUNDS bounds , HWND hwnd = NULL); // bounds in user space
+
+    inline static RECT_BOUNDS GetWindowRect(HWND hwnd)
+    {
+        RECT r;
+        ::GetWindowRect(hwnd, &r);
+        return RECT_BOUNDS(r.left, r.top, r.right - r.left, r.bottom - r.top);
+    }
 
     static int              primaryIndex;
     static BOOL             primaryPalettized;
@@ -107,6 +137,8 @@
     LPMONITORINFO           pMonitorInfo;
     jobject                 javaDevice;
     Devices                 *devicesArray;
+    float                   scaleX;
+    float                   scaleY;
 
     static HDC              MakeDCFromMonitor(HMONITOR);
 };
diff --git a/src/windows/native/sun/windows/awt_Win32GraphicsEnv.cpp b/src/windows/native/sun/windows/awt_Win32GraphicsEnv.cpp
index bc0d6a9..287f684 100644
--- a/src/windows/native/sun/windows/awt_Win32GraphicsEnv.cpp
+++ b/src/windows/native/sun/windows/awt_Win32GraphicsEnv.cpp
@@ -76,6 +76,28 @@
     }
 }
 
+static void
+SetProcessDPIAwareness(PROCESS_DPI_AWARENESS level)
+{
+    typedef HRESULT(WINAPI SetProcessDpiAwarenessFunc)(int);
+    static HMODULE hLibSHCoreDll = NULL;
+    static SetProcessDpiAwarenessFunc *lpSetProcessDpiAwareness = NULL;
+
+    if (hLibSHCoreDll == NULL) {
+        hLibSHCoreDll = JDK_LoadSystemLibrary("shcore.dll");
+        if (hLibSHCoreDll != NULL) {
+            lpSetProcessDpiAwareness = (SetProcessDpiAwarenessFunc*)GetProcAddress(
+                hLibSHCoreDll, "SetProcessDpiAwareness");
+        }
+        ::FreeLibrary(hLibSHCoreDll);
+        hLibSHCoreDll = NULL;
+    }
+
+    if (lpSetProcessDpiAwareness != NULL) {
+        lpSetProcessDpiAwareness(level);
+    }
+}
+
 #define DWM_COMP_UNDEFINED (~(TRUE|FALSE))
 static int dwmIsCompositionEnabled = DWM_COMP_UNDEFINED;
 
@@ -344,3 +366,14 @@
 {
     return IS_WINVISTA;
 }
+
+/*
+ * Class:     sun_awt_Win32GraphicsEnvironment
+ * Method:    setProcessDPIAwareness
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_sun_awt_Win32GraphicsEnvironment_setProcessDPIAwareness
+        (JNIEnv *env, jclass wgeclass, jint level)
+{
+    SetProcessDPIAwareness(static_cast<PROCESS_DPI_AWARENESS>(level));
+}
\ No newline at end of file
diff --git a/src/windows/native/sun/windows/awt_Window.cpp b/src/windows/native/sun/windows/awt_Window.cpp
index 1242bba..152194a 100644
--- a/src/windows/native/sun/windows/awt_Window.cpp
+++ b/src/windows/native/sun/windows/awt_Window.cpp
@@ -934,6 +934,18 @@
     return mrConsume;
 }
 
+MsgRouting AwtWindow::WmDPIChanged(UINT xDPI, UINT yDPI, RECT* bounds) {
+    if (!::IsWindowVisible(GetHWnd())) {
+        // may diverge with Component::Reshape in this state
+        return mrDoDefault;
+    }
+    ::SetWindowPos(GetHWnd(), NULL,
+                   bounds->left, bounds->top,
+                   bounds->right - bounds->left, bounds->bottom - bounds->top,
+                   SWP_NOZORDER | SWP_NOACTIVATE);
+    return mrConsume;
+}
+
 // The security warning is visible if:
 //    1. The window has the keyboard window focus, OR
 //    2. The mouse pointer is located within the window bounds,
@@ -1407,19 +1419,19 @@
     /* Get insets into our peer directly */
     jobject peerInsets = (env)->GetObjectField(peer, AwtPanel::insets_ID);
     DASSERT(!safe_ExceptionOccurred(env));
+
     if (peerInsets != NULL) { // may have been called during creation
-        (env)->SetIntField(peerInsets, AwtInsets::topID, m_insets.top);
-        (env)->SetIntField(peerInsets, AwtInsets::bottomID,
-                           m_insets.bottom);
-        (env)->SetIntField(peerInsets, AwtInsets::leftID, m_insets.left);
-        (env)->SetIntField(peerInsets, AwtInsets::rightID, m_insets.right);
+        (env)->SetIntField(peerInsets, AwtInsets::topID, ScaleDownY(m_insets.top));
+        (env)->SetIntField(peerInsets, AwtInsets::bottomID, ScaleDownY(m_insets.bottom));
+        (env)->SetIntField(peerInsets, AwtInsets::leftID, ScaleDownX(m_insets.left));
+        (env)->SetIntField(peerInsets, AwtInsets::rightID, ScaleDownX(m_insets.right));
     }
     /* Get insets into the Inset object (if any) that was passed */
     if (insets != NULL) {
-        (env)->SetIntField(insets, AwtInsets::topID, m_insets.top);
-        (env)->SetIntField(insets, AwtInsets::bottomID, m_insets.bottom);
-        (env)->SetIntField(insets, AwtInsets::leftID, m_insets.left);
-        (env)->SetIntField(insets, AwtInsets::rightID, m_insets.right);
+        (env)->SetIntField(insets, AwtInsets::topID, ScaleDownY(m_insets.top));
+        (env)->SetIntField(insets, AwtInsets::bottomID, ScaleDownY(m_insets.bottom));
+        (env)->SetIntField(insets, AwtInsets::leftID, ScaleDownX(m_insets.left));
+        (env)->SetIntField(insets, AwtInsets::rightID, ScaleDownX(m_insets.right));
     }
     env->DeleteLocalRef(peerInsets);
 
@@ -1732,13 +1744,13 @@
     jobject peer = GetPeer(env);
     jobject target = env->GetObjectField(peer, AwtObject::targetID);
 
-    RECT rect;
-    ::GetWindowRect(GetHWnd(), &rect);
+    RECT_BOUNDS rect = AwtWin32GraphicsDevice::GetWindowRect(GetHWnd());
+    AwtWin32GraphicsDevice* device = AwtWin32GraphicsDevice::GetDeviceByBounds(rect, GetHWnd());
 
-    (env)->SetIntField(target, AwtComponent::xID, rect.left);
-    (env)->SetIntField(target, AwtComponent::yID, rect.top);
-    (env)->SetIntField(peer, AwtWindow::sysXID, rect.left);
-    (env)->SetIntField(peer, AwtWindow::sysYID, rect.top);
+    (env)->SetIntField(target, AwtComponent::xID, device->ScaleDownDX(rect.x));
+    (env)->SetIntField(target, AwtComponent::yID, device->ScaleDownDY(rect.y));
+    (env)->SetIntField(peer, AwtWindow::sysXID, rect.x);
+    (env)->SetIntField(peer, AwtWindow::sysYID, rect.y);
     SendComponentEvent(java_awt_event_ComponentEvent_COMPONENT_MOVED);
 
     env->DeleteLocalRef(target);
@@ -1802,9 +1814,10 @@
     BOOL insetsChanged = UpdateInsets(NULL);
     int newWidth = w + m_insets.left + m_insets.right;
     int newHeight = h + m_insets.top + m_insets.bottom;
-
-    (env)->SetIntField(target, AwtComponent::widthID, newWidth);
-    (env)->SetIntField(target, AwtComponent::heightID, newHeight);
+    RECT_BOUNDS rect = AwtWin32GraphicsDevice::GetWindowRect(GetHWnd());
+    AwtWin32GraphicsDevice* device = AwtWin32GraphicsDevice::GetDeviceByBounds(rect, GetHWnd());
+    (env)->SetIntField(target, AwtComponent::widthID, device->ScaleDownX(newWidth));
+    (env)->SetIntField(target, AwtComponent::heightID, device->ScaleDownY(newHeight));
 
     jobject peer = GetPeer(env);
     (env)->SetIntField(peer, AwtWindow::sysWID, newWidth);
@@ -3072,6 +3085,25 @@
     delete data;
 }
 
+void AwtWindow::_GetNativeWindowSize(void* param) {
+
+    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
+
+    SizeStruct *ss = (SizeStruct *)param;
+    jobject self = ss->window;
+    AwtWindow *window = NULL;
+    PDATA pData;
+    JNI_CHECK_PEER_RETURN(self);
+    window = (AwtWindow *)pData;
+
+    RECT rc;
+    ::GetWindowRect(window->GetHWnd(), &rc);
+    ss->w = rc.right - rc.left;
+    ss->h = rc.bottom - rc.top;
+
+    env->DeleteGlobalRef(self);
+}
+
 extern "C" {
 
 /*
@@ -3303,6 +3335,46 @@
 
 /*
  * Class:     sun_awt_windows_WWindowPeer
+* Method:    getNativeWindowSize
+* Signature: ()Ljava/awt/Dimension;
+*/
+JNIEXPORT jobject JNICALL Java_sun_awt_windows_WWindowPeer_getNativeWindowSize
+(JNIEnv *env, jobject self) {
+
+    jobject res = NULL;
+    TRY;
+    SizeStruct *ss = new SizeStruct;
+    ss->window = env->NewGlobalRef(self);
+
+    AwtToolkit::GetInstance().SyncCall(AwtWindow::_GetNativeWindowSize, ss);
+
+    int w = ss->w;
+    int h = ss->h;
+
+    delete ss;
+    // global ref is deleted in _GetNativeWindowSize()
+
+    static jmethodID dimMID = NULL;
+    static jclass dimClassID = NULL;
+    if (dimClassID == NULL) {
+        jclass dimClassIDLocal = env->FindClass("java/awt/Dimension");
+        CHECK_NULL_RETURN(dimClassIDLocal, NULL);
+        dimClassID = (jclass)env->NewGlobalRef(dimClassIDLocal);
+        env->DeleteLocalRef(dimClassIDLocal);
+    }
+
+    if (dimMID == NULL) {
+        dimMID = env->GetMethodID(dimClassID, "<init>", "(II)V");
+        CHECK_NULL_RETURN(dimMID, NULL);
+    }
+
+    return env->NewObject(dimClassID, dimMID, w, h);
+
+    CATCH_BAD_ALLOC_RET(NULL);
+}
+
+/*
+ * Class:     sun_awt_windows_WWindowPeer
  * Method:    getSysMinWidth
  * Signature: ()I
  */
diff --git a/src/windows/native/sun/windows/awt_Window.h b/src/windows/native/sun/windows/awt_Window.h
index 1a92a67..bbe30be 100644
--- a/src/windows/native/sun/windows/awt_Window.h
+++ b/src/windows/native/sun/windows/awt_Window.h
@@ -188,6 +188,8 @@
     virtual MsgRouting HandleEvent(MSG *msg, BOOL synthetic);
     virtual void WindowResized();
 
+    MsgRouting WmDPIChanged(UINT xDPI, UINT yDPI, RECT* bounds);
+
     static jboolean _RequestWindowFocus(void *param);
 
     virtual BOOL AwtSetActiveWindow(BOOL isMouseEventCause = FALSE, UINT hittest = HTCLIENT);
@@ -241,6 +243,7 @@
     static void _UpdateWindow(void* param);
     static void _RepositionSecurityWarning(void* param);
     static void _SetFullScreenExclusiveModeState(void* param);
+    static void _GetNativeWindowSize(void* param);
 
     inline static BOOL IsResizing() {
         return sm_resizing;
diff --git a/src/windows/native/sun/windows/awtmsg.h b/src/windows/native/sun/windows/awtmsg.h
index d0131af..88e4823 100644
--- a/src/windows/native/sun/windows/awtmsg.h
+++ b/src/windows/native/sun/windows/awtmsg.h
@@ -45,6 +45,10 @@
 #define WM_MOUSEWHEEL                   0x020A
 #endif //WM_MOUSEWHEEL
 
+#ifndef WM_MOUSEHWHEEL
+#define WM_MOUSEHWHEEL                   0x020E
+#endif //WM_MOUSEHWHEEL
+
 #ifndef WHEEL_DELTA
 #define WHEEL_DELTA                     120
 #endif //WHEEL_DELTA
@@ -54,12 +58,16 @@
 #endif //WHEEL_PAGESCROLL
 
 #ifndef SPI_GETWHEELSCROLLLINES
-#define SPI_GETWHEELSCROLLLINES         104
+#define SPI_GETWHEELSCROLLLINES         0x0068
 #endif //SPI_GETWHEELSCROLLLINES
 
+#ifndef SPI_GETWHEELSCROLLCHARS
+#define SPI_GETWHEELSCROLLCHARS         0x006C
+#endif //SPI_GETWHEELSCROLLCHARS
+
 #ifndef SM_MOUSEWHEELPRESENT
 #define SM_MOUSEWHEELPRESENT            75
-#endif //SPI_GETWHEELSCROLLLINES
+#endif //SM_MOUSEWHEELPRESENT
 
 #ifndef COLOR_HOTLIGHT
 #define COLOR_HOTLIGHT                  26
diff --git a/src/windows/resource/icons/awt.ico b/src/windows/resource/icons/awt.ico
index 8d2c957..b99c0c6 100644
--- a/src/windows/resource/icons/awt.ico
+++ b/src/windows/resource/icons/awt.ico
Binary files differ
diff --git a/src/windows/resource/java.manifest b/src/windows/resource/java.manifest
index f971a78..12942a2 100644
--- a/src/windows/resource/java.manifest
+++ b/src/windows/resource/java.manifest
@@ -34,13 +34,6 @@
        </security>
   </trustInfo>
 
-  <!-- Indicate JDK is high-dpi aware. -->
-  <asmv3:application>
-    <asmv3:windowsSettings  xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
-       <dpiAware>true</dpiAware>
-    </asmv3:windowsSettings>
-  </asmv3:application>
-
   <!-- Indicate this JDK version is Windows 7 compatible -->
    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
       <application>
diff --git a/test/com/sun/jdi/ConstantPoolInfoGC.java b/test/com/sun/jdi/ConstantPoolInfoGC.java
new file mode 100644
index 0000000..405bd5f
--- /dev/null
+++ b/test/com/sun/jdi/ConstantPoolInfoGC.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ *  @test
+ *  @bug 6822627
+ *  @summary Test that ReferenceType.constantPool does not produce an NPE
+ *
+ *  @author Egor Ushakov
+ *
+ *  @modules jdk.jdi/com.sun.tools.jdi
+ *  @run build TestScaffold VMConnection
+ *  @run compile -g ConstantPoolInfoGC.java
+ *  @run main ConstantPoolInfoGC
+ */
+
+import com.sun.jdi.ReferenceType;
+import com.sun.tools.jdi.ReferenceTypeImpl;
+
+import java.lang.ref.Reference;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+
+    /********** target program **********/
+
+class ConstantPoolGCTarg {
+    public static void main(String[] args){
+        System.out.println("Anything");
+    }
+}
+
+    /********** test program **********/
+
+public class ConstantPoolInfoGC extends TestScaffold {
+    ReferenceType targetClass;
+
+    ConstantPoolInfoGC(String args[]) {
+        super(args);
+    }
+
+    public static void main(String[] args)      throws Exception {
+        new ConstantPoolInfoGC(args).startTests();
+    }
+
+    /********** test core **********/
+
+    protected void runTests() throws Exception {
+        targetClass = startToMain("ConstantPoolGCTarg").location().declaringType();
+
+        if (vm().canGetConstantPool()) {
+            byte[] cpbytes = targetClass.constantPool();
+
+            // imitate SoftReference cleared
+            Field constantPoolBytesRef = ReferenceTypeImpl.class.getDeclaredField("constantPoolBytesRef");
+            constantPoolBytesRef.setAccessible(true);
+            Reference softRef = (Reference) constantPoolBytesRef.get(targetClass);
+            softRef.clear();
+
+            byte[] cpbytes2 = targetClass.constantPool();
+            if (!Arrays.equals(cpbytes, cpbytes2)) {
+                failure("Consequent constantPool results vary, first was : " + cpbytes + ", now: " + cpbytes2);
+            };
+
+        } else {
+            System.out.println("can get constant pool version not supported");
+        }
+
+
+        /*
+         * resume until end
+         */
+        listenUntilVMDisconnect();
+
+        /*
+         * deal with results of test
+         * if anything has called failure("foo") testFailed will be true
+         */
+        if (!testFailed) {
+            println("ConstantPoolInfoGC: passed");
+        } else {
+            throw new Exception("ConstantPoolInfoGC: failed");
+        }
+    }
+}
diff --git a/test/java/awt/Focus/ModalDialogActivationTest/ModalDialogActivationTest.java b/test/java/awt/Focus/ModalDialogActivationTest/ModalDialogActivationTest.java
index deff8ee..0f7c48b 100644
--- a/test/java/awt/Focus/ModalDialogActivationTest/ModalDialogActivationTest.java
+++ b/test/java/awt/Focus/ModalDialogActivationTest/ModalDialogActivationTest.java
@@ -55,7 +55,7 @@
 
     static void runGUI() {
         JFrame f = new JFrame("frame");
-        final JDialog d = new MyModalDialog(f, "dialog");
+        JDialog d = new MyModalDialog(f, "dialog");
         d.addWindowListener(new WindowAdapter() {
             @Override
             public void windowActivated(WindowEvent e) {
@@ -79,7 +79,7 @@
     }
 
     static class MyModalDialog extends JDialog {
-        public MyModalDialog(Frame owner, String title)ª {
+        public MyModalDialog(Frame owner, String title) {
             super(owner, title, true);
         }
 
diff --git a/test/java/awt/Frame/DecoratedFrameInsets/DecoratedFrameInsetsTest.java b/test/java/awt/Frame/DecoratedFrameInsets/DecoratedFrameInsetsTest.java
new file mode 100644
index 0000000..b24d054
--- /dev/null
+++ b/test/java/awt/Frame/DecoratedFrameInsets/DecoratedFrameInsetsTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8165619
+ * @summary Frame is not repainted if created in state=MAXIMIZED_BOTH on Unity
+ * @run main DecoratedFrameInsetsTest
+ */
+
+import java.awt.*;
+
+public class DecoratedFrameInsetsTest {
+    static Robot robot;
+    private static Insets expectedInsets;
+
+    public static void main(String[] args) throws Exception {
+        robot = new Robot();
+        expectedInsets = getExpectedInsets();
+        System.out.println("Normal state insets: " + expectedInsets);
+        testState(Frame.MAXIMIZED_BOTH);
+        testState(Frame.ICONIFIED);
+        testState(Frame.MAXIMIZED_HORIZ);
+        testState(Frame.MAXIMIZED_VERT);
+    }
+
+    private static Insets getExpectedInsets() {
+        Frame frame = new Frame();
+        frame.setVisible(true);
+        robot.waitForIdle();
+        robot.delay(200);
+        Insets expectedInsets = frame.getInsets();
+        frame.dispose();
+        return expectedInsets;
+    }
+
+    static void testState(int state) {
+        Frame frame = new Frame();
+        if( Toolkit.getDefaultToolkit().isFrameStateSupported(state)) {
+            frame.setBounds(150, 150, 200, 200);
+            frame.setExtendedState(state);
+            frame.setVisible(true);
+            robot.waitForIdle();
+            robot.delay(200);
+            System.out.println("State " + state +
+                                               " insets: " + frame.getInsets());
+
+            frame.setExtendedState(Frame.NORMAL);
+            frame.toFront();
+            robot.waitForIdle();
+            robot.delay(200);
+            Insets insets = frame.getInsets();
+            frame.dispose();
+            System.out.println("State " + state +
+                                           " back to normal insets: " + insets);
+            if(!expectedInsets.equals(insets)) {
+                throw new RuntimeException("Insets are wrong " + insets);
+            }
+        }
+    }
+}
+
diff --git a/test/java/awt/Graphics2D/ScaledTransform/ScaledTransform.java b/test/java/awt/Graphics2D/ScaledTransform/ScaledTransform.java
new file mode 100644
index 0000000..69064a2
--- /dev/null
+++ b/test/java/awt/Graphics2D/ScaledTransform/ScaledTransform.java
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+import java.awt.Dialog;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.Panel;
+import java.awt.geom.AffineTransform;
+
+/*
+ * @test
+ * @bug 8069361
+ * @summary SunGraphics2D.getDefaultTransform() does not include scale factor
+ * @author Alexander Scherbatiy
+ * @run main ScaledTransform
+ */
+public class ScaledTransform {
+
+    private static volatile boolean passed = false;
+
+    public static void main(String[] args) {
+        GraphicsEnvironment ge = GraphicsEnvironment.
+                getLocalGraphicsEnvironment();
+
+        if (ge.isHeadlessInstance()) {
+            return;
+        }
+
+        for (GraphicsDevice gd : ge.getScreenDevices()) {
+            for (GraphicsConfiguration gc : gd.getConfigurations()) {
+                testScaleFactor(gc);
+            }
+        }
+    }
+
+    private static void testScaleFactor(final GraphicsConfiguration gc) {
+        final Dialog dialog = new Dialog((Frame) null, "Test", true, gc);
+
+        try {
+            dialog.setSize(100, 100);
+            Panel panel = new Panel() {
+
+                @Override
+                public void paint(Graphics g) {
+                    if (g instanceof Graphics2D) {
+                        AffineTransform gcTx = gc.getDefaultTransform();
+                        AffineTransform gTx
+                                = ((Graphics2D) g).getTransform();
+                        passed = gcTx.getScaleX() == gTx.getScaleX()
+                                && gcTx.getScaleY() == gTx.getScaleY();
+                    } else {
+                        passed = true;
+                    }
+                    dialog.setVisible(false);
+                }
+            };
+            dialog.add(panel);
+            dialog.setVisible(true);
+
+            if (!passed) {
+                throw new RuntimeException("Transform is not scaled!");
+            }
+        } finally {
+            dialog.dispose();
+        }
+    }
+}
+
diff --git a/test/java/awt/Robot/HiDPIMouseClick/HiDPIRobotMouseClick.java b/test/java/awt/Robot/HiDPIMouseClick/HiDPIRobotMouseClick.java
new file mode 100644
index 0000000..68ef2d7
--- /dev/null
+++ b/test/java/awt/Robot/HiDPIMouseClick/HiDPIRobotMouseClick.java
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import java.awt.Frame;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.Toolkit;
+import java.awt.event.InputEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import sun.awt.SunToolkit;
+import javax.swing.UIManager;
+
+/* @test
+ * @bug 8073320
+ * @summary  Windows HiDPI support
+ * @author Alexander Scherbatiy
+ * @requires (os.family == "windows")
+ * @run main/othervm -Dsun.java2d.win.uiScale.enabled=true -Dsun.java2d.win.uiScale=2 HiDPIRobotMouseClick
+ */
+public class HiDPIRobotMouseClick {
+
+    private static volatile int mouseX;
+    private static volatile int mouseY;
+
+    public static void main(String[] args) throws Exception {
+
+        try {
+            UIManager.setLookAndFeel(
+                    "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
+        } catch (Exception e) {
+            return;
+        }
+
+        Frame frame = new Frame();
+        frame.setBounds(30, 20, 400, 300);
+        frame.setUndecorated(true);
+
+        frame.addMouseListener(new MouseAdapter() {
+
+            @Override
+            public void mouseClicked(MouseEvent e) {
+                mouseX = e.getXOnScreen();
+                mouseY = e.getYOnScreen();
+            }
+        });
+
+        frame.setVisible(true);
+
+        Robot robot = new Robot();
+        robot.waitForIdle();
+        Thread.sleep(200);
+
+        Rectangle rect = frame.getBounds();
+        rect.setLocation(frame.getLocationOnScreen());
+
+        int x = (int) rect.getCenterX();
+        int y = (int) rect.getCenterY();
+
+        robot.mouseMove(x, y);
+        robot.mousePress(InputEvent.BUTTON1_MASK);
+        robot.mouseRelease(InputEvent.BUTTON1_MASK);
+        ((SunToolkit)Toolkit.getDefaultToolkit()).realSync();
+
+        if (x != mouseX || y != mouseY) {
+            throw new RuntimeException("Wrong mouse click point!");
+        }
+    }
+}
diff --git a/test/java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java b/test/java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java
new file mode 100644
index 0000000..8e60eb7
--- /dev/null
+++ b/test/java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import java.awt.BorderLayout;
+import java.awt.Canvas;
+import java.awt.Color;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Panel;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.image.BufferedImage;
+import javax.swing.UIManager;
+
+/* @test
+ * @bug 8073320
+ * @summary  Windows HiDPI support
+ * @author Alexander Scherbatiy
+ * @requires (os.family == "windows")
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.win.uiScaleX=3 -Dsun.java2d.win.uiScaleY=2
+ *                    HiDPIRobotScreenCaptureTest
+ */
+public class HiDPIRobotScreenCaptureTest {
+
+    private static final Color[] COLORS = {
+        Color.GREEN, Color.BLUE, Color.ORANGE, Color.RED};
+
+    public static void main(String[] args) throws Exception {
+
+        try {
+            UIManager.setLookAndFeel(
+                    "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
+        } catch (Exception e) {
+            return;
+        }
+
+        Frame frame = new Frame();
+        frame.setBounds(40, 30, 400, 300);
+        frame.setUndecorated(true);
+
+        Panel panel = new Panel(new BorderLayout());
+        Canvas canvas = new Canvas() {
+            @Override
+            public void paint(Graphics g) {
+                super.paint(g);
+                int w = getWidth();
+                int h = getHeight();
+                g.setColor(COLORS[0]);
+                g.fillRect(0, 0, w / 2, h / 2);
+                g.setColor(COLORS[1]);
+                g.fillRect(w / 2, 0, w / 2, h / 2);
+                g.setColor(COLORS[2]);
+                g.fillRect(0, h / 2, w / 2, h / 2);
+                g.setColor(COLORS[3]);
+                g.fillRect(w / 2, h / 2, w / 2, h / 2);
+            }
+        };
+
+        panel.add(canvas);
+        frame.add(panel);
+        frame.setVisible(true);
+        Robot robot = new Robot();
+        robot.waitForIdle();
+        Thread.sleep(200);
+
+        Rectangle rect = canvas.getBounds();
+        rect.setLocation(canvas.getLocationOnScreen());
+
+        BufferedImage image = robot.createScreenCapture(rect);
+        frame.dispose();
+
+        int w = image.getWidth();
+        int h = image.getHeight();
+
+        if (w != frame.getWidth() || h != frame.getHeight()) {
+            throw new RuntimeException("Wrong image size!");
+        }
+
+        if (image.getRGB(w / 4, h / 4) != COLORS[0].getRGB()) {
+            throw new RuntimeException("Wrong image color!");
+        }
+
+        if (image.getRGB(3 * w / 4, h / 4) != COLORS[1].getRGB()) {
+            throw new RuntimeException("Wrong image color!");
+        }
+
+        if (image.getRGB(w / 4, 3 * h / 4) != COLORS[2].getRGB()) {
+            throw new RuntimeException("Wrong image color!");
+        }
+
+        if (image.getRGB(3 * w / 4, 3 * h / 4) != COLORS[3].getRGB()) {
+            throw new RuntimeException("Wrong image color!");
+        }
+    }
+}
\ No newline at end of file
diff --git a/test/java/awt/Window/ChangeWindowResizabilty/ChangeWindowResizabiltyTest.java b/test/java/awt/Window/ChangeWindowResizabilty/ChangeWindowResizabiltyTest.java
new file mode 100644
index 0000000..fd6a231
--- /dev/null
+++ b/test/java/awt/Window/ChangeWindowResizabilty/ChangeWindowResizabiltyTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+/* @bug      8166897
+   @summary  Some font overlap in the Optionpane dialog.
+   @run      main ChangeWindowResizabiltyTest
+*/
+
+import java.awt.*;
+
+public class ChangeWindowResizabiltyTest {
+    public static void main(String[] args) throws Exception {
+        Robot robot = new Robot();
+        for(int i = 0; i < 10; i++) {
+            Dialog dialog = new Dialog((Frame) null);
+            dialog.setLocation(100, 100);
+            Component panel = new Panel();
+            panel.setPreferredSize(new Dimension(200, 100));
+            dialog.add(panel);
+            dialog.pack();
+            dialog.setVisible(true);
+            robot.waitForIdle();
+            robot.delay(200);
+
+            Point frameLoc = dialog.getLocationOnScreen();
+            Point contentLoc = panel.getLocationOnScreen();
+
+            System.out.println("Decor location " + frameLoc);
+            System.out.println("Content location " + contentLoc);
+
+            dialog.setResizable(false);
+            robot.waitForIdle();
+            robot.delay(200);
+
+            Point l = dialog.getLocationOnScreen();
+            if (!l.equals(frameLoc)) {
+                dialog.dispose();
+                throw new RuntimeException("Decorated frame location moved " +
+                        "after setResizable(false)" + l);
+            }
+
+            l = panel.getLocationOnScreen();
+            if (!l.equals(contentLoc)) {
+                dialog.dispose();
+                throw new RuntimeException("Content location moved after " +
+                        "setResizable(false)" + l);
+            }
+
+            if (panel.getLocationOnScreen().y <
+                      dialog.getLocationOnScreen().y + dialog.getInsets().top) {
+                dialog.dispose();
+                throw new RuntimeException(
+                            "Wrong content position after setResizable(false)");
+            }
+
+            dialog.setResizable(true);
+            robot.waitForIdle();
+            robot.delay(200);
+
+            l = dialog.getLocationOnScreen();
+            if (!l.equals(frameLoc)) {
+                dialog.dispose();
+                throw new RuntimeException("Decorated frame location moved " +
+                        "after setResizable(true)" + l);
+            }
+
+            l = panel.getLocationOnScreen();
+            if (!l.equals(contentLoc)) {
+                dialog.dispose();
+                throw new RuntimeException("Content location moved after " +
+                        "setResizable(true)" + l);
+            }
+            if (panel.getLocationOnScreen().y <
+                      dialog.getLocationOnScreen().y + dialog.getInsets().top) {
+                dialog.dispose();
+                throw new RuntimeException(
+                             "Wrong content position after setResizable(true)");
+            }
+
+            dialog.dispose();
+        }
+    }
+}
+
diff --git a/test/java/awt/Window/GetScreenLocation/GetScreenLocationTest.java b/test/java/awt/Window/GetScreenLocation/GetScreenLocationTest.java
new file mode 100644
index 0000000..eeaaf07
--- /dev/null
+++ b/test/java/awt/Window/GetScreenLocation/GetScreenLocationTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+/**
+ * @test @summary setLocationRelativeTo stopped working in Ubuntu 13.10 (Unity)
+ * @bug 8036915
+ * @run main GetScreenLocationTest
+ */
+import java.awt.*;
+
+public class GetScreenLocationTest {
+
+    public static void main(String[] args) throws Exception {
+        Robot robot = new Robot();
+        Window frame = null;
+        for(int i = 0; i < 100; i++) {
+            if(frame != null) frame.dispose();
+            frame = new Dialog((Frame)null);
+            frame.setBounds(0, 0, 200, 200);
+            frame.setVisible(true);
+            robot.waitForIdle();
+            robot.delay(200);
+            frame.setLocation(321, 321);
+            robot.waitForIdle();
+            robot.delay(200);
+            Dimension size = frame.getSize();
+            if(size.width != 200 || size.height != 200) {
+                frame.dispose();
+                throw new RuntimeException("getSize() is wrong " + size);
+            }
+            Rectangle r = frame.getBounds();
+            frame.dispose();
+            if(r.x != 321 || r.y != 321) {
+                throw new RuntimeException("getLocation() returns " +
+                        "wrong coordinates " + r.getLocation());
+            }
+            if(r.width != 200 || r.height != 200) {
+                throw new RuntimeException("getSize() is wrong " + r.getSize());
+            }
+        }
+        System.out.println("ok");
+    }
+
+}
diff --git a/test/java/awt/Window/Grab/GrabTest.java b/test/java/awt/Window/Grab/GrabTest.java
index e632af1..09e5801 100644
--- a/test/java/awt/Window/Grab/GrabTest.java
+++ b/test/java/awt/Window/Grab/GrabTest.java
@@ -119,6 +119,10 @@
         Util.waitForIdle(robot);
 
         test();
+
+        frame.dispose();
+        f1.dispose();
+        f.dispose();
     }
 
     public static void test() {
diff --git a/test/java/awt/Window/WindowsLeak/WindowsLeak.java b/test/java/awt/Window/WindowsLeak/WindowsLeak.java
index 3f44687..0c25ede 100644
--- a/test/java/awt/Window/WindowsLeak/WindowsLeak.java
+++ b/test/java/awt/Window/WindowsLeak/WindowsLeak.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
diff --git a/test/java/awt/event/KeyEvent/DeadKey/DeadKeyMacOSXInputText.java b/test/java/awt/event/KeyEvent/DeadKey/DeadKeyMacOSXInputText.java
index 3ae73c6..6686733 100644
--- a/test/java/awt/event/KeyEvent/DeadKey/DeadKeyMacOSXInputText.java
+++ b/test/java/awt/event/KeyEvent/DeadKey/DeadKeyMacOSXInputText.java
@@ -102,9 +102,10 @@
                     if (keyCode != KeyEvent.VK_DEAD_ACUTE) {
                         throw new RuntimeException("Dead ACUTE is not pressed.");
                     }
-                    if (keyChar != 0xB4) {
-                        throw new RuntimeException("Pressed char is not dead acute.");
-                    }
+                    // We are sending char that is written on the keyboard key.
+                    //if (keyChar != 0xB4) {
+                    //    throw new RuntimeException("Pressed char is not dead acute.");
+                    //}
                     state++;
                     break;
             }
diff --git a/test/java/awt/event/KeyEvent/DeadKey/deadKeyMacOSX.java b/test/java/awt/event/KeyEvent/DeadKey/deadKeyMacOSX.java
index 020b987..a47719c 100644
--- a/test/java/awt/event/KeyEvent/DeadKey/deadKeyMacOSX.java
+++ b/test/java/awt/event/KeyEvent/DeadKey/deadKeyMacOSX.java
@@ -98,9 +98,10 @@
                     if (keyCode != KeyEvent.VK_DEAD_ACUTE) {
                         throw new RuntimeException("Dead ACUTE is not pressed.");
                     }
-                    if (keyChar != 0xB4) {
-                        throw new RuntimeException("Pressed char is not dead acute.");
-                    }
+                    // We should not send dead key char here
+                    //if (keyChar != 0xB4) {
+                    //    throw new RuntimeException("Pressed char is not dead acute.");
+                    //}
 
                     state++;
                     break;
@@ -108,9 +109,10 @@
                     if (keyCode != KeyEvent.VK_A) {
                         throw new RuntimeException("A is not pressed.");
                     }
-                    if (keyChar != 0xE1) {
-                        throw new RuntimeException("A char does not have ACCUTE accent");
-                    }
+                    // We should not send dead key char here
+                    //if (keyChar != 0xE1) {
+                    //    throw new RuntimeException("A char does not have ACCUTE accent");
+                    //}
                     state++;
                     break;
                 default:
@@ -124,9 +126,11 @@
             char keyChar = e.getKeyChar();
 
             if (state == 3) {
-                if (keyCode != 0) {
-                    throw new RuntimeException("Key code should be undefined.");
-                }
+                // Now we send key codes
+//                if (keyCode != 0) {
+//                    throw new RuntimeException("Key code should be undefined.");
+//                }
+                // This works for US keyboard only
                 if (keyChar != 0xE1) {
                     throw new RuntimeException("A char does not have ACCUTE accent");
                 }
diff --git a/test/java/awt/event/KeyEvent/KeyChar/KeyCharTest.java b/test/java/awt/event/KeyEvent/KeyChar/KeyCharTest.java
index dd50483..f65d968 100644
--- a/test/java/awt/event/KeyEvent/KeyChar/KeyCharTest.java
+++ b/test/java/awt/event/KeyEvent/KeyChar/KeyCharTest.java
@@ -50,9 +50,12 @@
             public void eventDispatched(AWTEvent event) {
                 eventsCount++;
                 char delete = ((KeyEvent) event).getKeyChar();
-                if (delete != '\u007f') {
-                    throw new RuntimeException("Key char is not delete: '" + delete + "'");
-                }
+                // On Mac OS X forward delete is \uf728
+                // \u007f - is 'undefined' let's do not use the check
+
+                //if (delete != '\u007f') {
+                //    throw new RuntimeException("Key char is not delete: '" + delete + "'");
+                //}
             }
         }, AWTEvent.KEY_EVENT_MASK);
     }
diff --git a/test/java/awt/font/Emoji/EmojiDrawingTest.java b/test/java/awt/font/Emoji/EmojiDrawingTest.java
new file mode 100644
index 0000000..7044541
--- /dev/null
+++ b/test/java/awt/font/Emoji/EmojiDrawingTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * @test
+ * @summary Emoji glyphs drawing on macOS
+ * @requires os.family == "mac"
+ */
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.net.URL;
+import javax.imageio.ImageIO;
+
+public class EmojiDrawingTest {
+    private static final String EMOJI = new String(Character.toChars(0x1f600));
+    private static Font FONT = new Font("Menlo", Font.PLAIN, 12);
+    private static final int IMAGE_WIDTH = 20;
+    private static final int IMAGE_HEIGHT = 20;
+    private static final int GLYPH_X = 2;
+    private static final int GLYPH_Y = 15;
+
+    public static void main(String[] args) throws Exception {
+        BufferedImage actual = createImage();
+        if (!matchesOneOfExpected(actual)) {
+            File file = File.createTempFile("emoji", ".png");
+            ImageIO.write(actual, "PNG", file);
+            throw new RuntimeException("Unexpected painting on image: " + file);
+        }
+    }
+
+    private static boolean matchesOneOfExpected(BufferedImage actualImage) throws Exception {
+        URL url;
+        for (int i = 1; (url = EmojiDrawingTest.class.getResource("emoji" + i + ".png")) != null; i++) {
+            BufferedImage expectedImage = ImageIO.read(url);
+            if (imagesAreEqual(actualImage, expectedImage)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static BufferedImage createImage() {
+        BufferedImage image = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
+        Graphics2D g = image.createGraphics();
+        g.setColor(Color.white);
+        g.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
+        g.setFont(FONT);
+        g.drawString(EMOJI, GLYPH_X, GLYPH_Y);
+        g.dispose();
+        return image;
+    }
+
+    private static boolean imagesAreEqual(BufferedImage i1, BufferedImage i2) {
+        if (i1.getWidth() != i2.getWidth() || i1.getHeight() != i2.getHeight()) return false;
+        for (int i = 0; i < i1.getWidth(); i++) {
+            for (int j = 0; j < i1.getHeight(); j++) {
+                if (i1.getRGB(i, j) != i2.getRGB(i, j)) return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/test/java/awt/font/Emoji/emoji1.png b/test/java/awt/font/Emoji/emoji1.png
new file mode 100644
index 0000000..8633dbe
--- /dev/null
+++ b/test/java/awt/font/Emoji/emoji1.png
Binary files differ
diff --git a/test/java/awt/font/Emoji/emoji2.png b/test/java/awt/font/Emoji/emoji2.png
new file mode 100644
index 0000000..6b36be6
--- /dev/null
+++ b/test/java/awt/font/Emoji/emoji2.png
Binary files differ
diff --git a/test/java/awt/font/Emoji/emoji3.png b/test/java/awt/font/Emoji/emoji3.png
new file mode 100644
index 0000000..60ad12d
--- /dev/null
+++ b/test/java/awt/font/Emoji/emoji3.png
Binary files differ
diff --git a/test/java/awt/font/FontScaling/FontScalingTest.java b/test/java/awt/font/FontScaling/FontScalingTest.java
new file mode 100644
index 0000000..dfb0f91
--- /dev/null
+++ b/test/java/awt/font/FontScaling/FontScalingTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+import javax.swing.JButton;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.plaf.metal.MetalLookAndFeel;
+
+/*
+ * @test
+ * @bug 8076545
+ * @summary Text size is twice bigger under Windows L&F on Win 8.1 with
+ *          HiDPI display
+ */
+public class FontScalingTest {
+
+    public static void main(String[] args) throws Exception {
+        int metalFontSize = getFontSize(MetalLookAndFeel.class.getName());
+        int systemFontSize = getFontSize(UIManager.getSystemLookAndFeelClassName());
+
+        if (Math.abs(systemFontSize - metalFontSize) > 8) {
+            throw new RuntimeException("System L&F is too big!");
+        }
+    }
+
+    private static int getFontSize(String laf) throws Exception {
+
+        UIManager.setLookAndFeel(laf);
+        final int[] sizes = new int[1];
+
+        SwingUtilities.invokeAndWait(() -> {
+            JButton button = new JButton("Test");
+            sizes[0] = button.getFont().getSize();
+        });
+
+        return sizes[0];
+    }
+}
diff --git a/test/java/awt/font/GlyphVector/GetGlyphCharIndexTest.java b/test/java/awt/font/GlyphVector/GetGlyphCharIndexTest.java
new file mode 100644
index 0000000..6ec6a25
--- /dev/null
+++ b/test/java/awt/font/GlyphVector/GetGlyphCharIndexTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+/* @test
+ * @summary Test getGlyphCharIndex() results from layout
+ * @bug 8152680
+ */
+
+import java.awt.Font;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+
+public class GetGlyphCharIndexTest {
+    public static void main(String[] args) {
+        Font font = new Font(Font.MONOSPACED, Font.PLAIN, 12);
+        FontRenderContext frc = new FontRenderContext(null, false, false);
+        GlyphVector gv = font.layoutGlyphVector(frc, "abc".toCharArray(), 1, 3,
+                                                Font.LAYOUT_LEFT_TO_RIGHT);
+        int idx0 = gv.getGlyphCharIndex(0);
+        if (idx0 != 0) {
+           throw new RuntimeException("Expected 0, got " + idx0);
+        }
+    }
+}
diff --git a/test/java/awt/font/LineBreakMeasurer/TestLineBreakWithFontSub.java b/test/java/awt/font/LineBreakMeasurer/TestLineBreakWithFontSub.java
new file mode 100644
index 0000000..472fca8
--- /dev/null
+++ b/test/java/awt/font/LineBreakMeasurer/TestLineBreakWithFontSub.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 1999, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4175418 8158924
+ * @author John Raley
+ * @summary This insures that bug 4175418: Font substitution in TextLayout /
+ * LineBreakMeasurer is inconsistent has been fixed.  The problem was
+ * that text was measured in one Font, but lines were produced
+ * in a different font.
+ */
+
+/*
+ * (C) Copyright IBM Corp. 1999, All Rights Reserved
+ */
+
+import java.text.AttributedString;
+import java.awt.font.LineBreakMeasurer;
+import java.awt.font.TextLayout;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextAttribute;
+
+/**
+ * This insures that bug 4175418: Font substitution in TextLayout /
+ * LineBreakMeasurer is inconsistent has been fixed.  The problem was
+ * that text was measured in one Font, but lines were produced
+ * in a different font.  One symptom of this problem is that lines are
+ * either too short or too long.  This test line-breaks a paragraph
+ * and checks the line lengths to make sure breaks were chosen well.
+ * This can be checked because the paragraph is so simple.
+ */
+public class TestLineBreakWithFontSub {
+
+    public static void main(String[] args) {
+
+        new TestLineBreakWithFontSub().test();
+        System.out.println("Line break / font substitution test PASSED");
+    }
+
+    private static final String WORD = "word";
+    private static final String SPACING = " ";
+    // The Hebrew character in this string can trigger font substitution
+    private static final String MIXED = "A\u05D0";
+
+    private static final int NUM_WORDS = 12;
+
+    private static final FontRenderContext DEFAULT_FRC =
+                            new FontRenderContext(null, false, false);
+
+    public void test() {
+
+        // construct a paragraph as follows: MIXED + [SPACING + WORD] + ...
+        StringBuffer text = new StringBuffer(MIXED);
+        for (int i=0; i < NUM_WORDS; i++) {
+            text.append(SPACING);
+            text.append(WORD);
+        }
+
+        AttributedString attrString = new AttributedString(text.toString());
+        attrString.addAttribute(TextAttribute.SIZE, new Float(24.0));
+
+        LineBreakMeasurer measurer = new LineBreakMeasurer(attrString.getIterator(),
+                                                           DEFAULT_FRC);
+
+        // get width of a space-word sequence, in context
+        int sequenceLength = WORD.length()+SPACING.length();
+        measurer.setPosition(text.length() - sequenceLength);
+
+        TextLayout layout = measurer.nextLayout(10000.0f);
+
+        if (layout.getCharacterCount() != sequenceLength) {
+            throw new Error("layout length is incorrect!");
+        }
+
+        final float sequenceAdvance = layout.getVisibleAdvance();
+
+        float wrappingWidth = sequenceAdvance * 2;
+
+        // now run test with a variety of widths
+        while (wrappingWidth < (sequenceAdvance*NUM_WORDS)) {
+            measurer.setPosition(0);
+            checkMeasurer(measurer,
+                          wrappingWidth,
+                          sequenceAdvance,
+                          text.length());
+            wrappingWidth += sequenceAdvance / 5;
+        }
+    }
+
+    /**
+     * Iterate through measurer and check that every line is
+     * not too long and not too short, but just right.
+     */
+    private void checkMeasurer(LineBreakMeasurer measurer,
+                               float wrappingWidth,
+                               float sequenceAdvance,
+                               int endPosition) {
+
+        do {
+            TextLayout layout = measurer.nextLayout(wrappingWidth);
+            float visAdvance = layout.getVisibleAdvance();
+
+            // Check that wrappingWidth-sequenceAdvance < visAdvance
+            // Also, if we're not at the end of the paragraph,
+            // check that visAdvance <= wrappingWidth
+
+            if (visAdvance > wrappingWidth) {
+                // line is too long for given wrapping width
+                throw new Error("layout is too long");
+            }
+
+            if (measurer.getPosition() < endPosition) {
+                if (visAdvance <= wrappingWidth - sequenceAdvance) {
+                    // line is too short for given wrapping width;
+                    // another word would have fit
+                    throw new Error("room for more words on line.  diff=" +
+                                    (wrappingWidth - sequenceAdvance - visAdvance));
+                }
+            }
+        } while (measurer.getPosition() != endPosition);
+    }
+}
diff --git a/test/java/awt/font/TextLayout/DrawTest.java b/test/java/awt/font/TextLayout/DrawTest.java
new file mode 100644
index 0000000..5df0fbc
--- /dev/null
+++ b/test/java/awt/font/TextLayout/DrawTest.java
@@ -0,0 +1,139 @@
+/**
+ * @test 1.0 2016/08/25
+ * @bug 8139176
+ * @run main DrawTest
+ * @summary java.awt.TextLayout does not handle correctly the bolded logical fonts (Serif)
+ */
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.awt.font.TextLayout;
+import java.awt.image.BufferedImage;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+
+// The test against java.awt.font.TextLayout, it draws the text "Gerbera" twise
+// via the methods Graphics.drawString and TextLayout.draw and then it checks
+// that both output have the same width.
+// The test does this checking for two styles of the font Serif - PLAIN and
+// BOLD in course one by one.
+
+public class DrawTest {
+    static final Font plain = new Font("Serif", Font.PLAIN, 32);
+    static final Font bold = new Font("Serif", Font.BOLD, 32);
+    static int testCaseNo = 1;
+    static final String txt = "Gerbera";
+    static boolean isPassed = true;
+    static String errMsg = "";
+    static String testCaseName;
+
+    public static void main(String[] args) {
+        final JFrame frame = new JFrame();
+        frame.getContentPane().setPreferredSize(new Dimension(116, 75));
+        frame.pack();
+        frame.setVisible(true);
+        Insets insets = frame.getInsets();
+        System.out.println(insets);
+        final JPanel panel = new JPanel() {
+
+            private void drawString(Graphics g, Font font) {
+                g.setFont(font);
+                g.drawString(txt, 0, 32);
+            }
+
+            private void drawTextLayout(Graphics g, Font font) {
+                TextLayout tl = new TextLayout(txt,
+                        font,
+                        g.getFontMetrics(font).getFontRenderContext());
+                tl.draw((Graphics2D) g, 0, 65);
+            }
+
+            /**
+             * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
+             */
+            @Override
+            protected void paintComponent(Graphics g) {
+                g.setColor(Color.WHITE);
+                g.fillRect(0, 0, getWidth(), getHeight());
+                g.setColor(Color.BLACK);
+
+                int width;
+                TextLayout tl;
+                if (testCaseNo == 1) {
+                    // Ok.
+                    // For the PLAIN font, the text painted by g.drawString and the text layout are the same.
+                    testCaseName = "PLAIN";
+                    errMsg = "plained";
+                    drawString(g, plain);
+                    drawTextLayout(g, plain);
+                } else {
+                    // Not Ok.
+                    // For the BOLD font, the text painted by g.drawString and the text layout are NOT the same.
+                    testCaseName = "BOLD";
+                    errMsg = "bolded";
+                    drawString(g, bold);
+                    drawTextLayout(g, bold);
+                }
+            }
+        };
+        frame.getContentPane().add(panel);
+        frame.setVisible(true);
+
+        for (testCaseNo = 1; testCaseNo <= 2; testCaseNo++) {
+            BufferedImage paintImage = getScreenShot(panel);
+            if (testCaseNo == 2) {
+                panel.revalidate();
+                panel.repaint();
+            }
+            paintImage = getScreenShot(panel);
+            int width1 = charWidth(paintImage, 0, 9, 116, 23);
+            int width2 = charWidth(paintImage, 0, 42, 116, 23);
+
+            if (width1 != width2) {
+                System.out.println(testCaseName + " test case FAILED");
+                isPassed = false;
+            } else
+                System.out.println(testCaseName + " test case PASSED");
+        }
+
+        frame.dispose();
+        if (!isPassed) {
+            throw new RuntimeException(errMsg + " logical fonts (Serif) was not correctly handled");
+        }
+    }
+
+    static private BufferedImage getScreenShot(JPanel panel) {
+        BufferedImage bi = new BufferedImage(
+                panel.getWidth(), panel.getHeight(), BufferedImage.TYPE_INT_ARGB);
+        panel.paint(bi.getGraphics());
+        return bi;
+    }
+
+    private static int charWidth(BufferedImage bufferedImage, int x, int y, int width, int height) {
+        int rgb;
+        int returnWidth = 0;
+        for (int row = y; row < y + height; row++) {
+            for (int col = x; col < x + width; col++) {
+                // remove transparance
+                rgb = bufferedImage.getRGB(col, row) & 0x00FFFFFF;
+
+                int r = rgb >> 16;
+                int g = (rgb >> 8) & 0x000000FF;
+                int b = rgb & 0x00000FF;
+                if (r == g && g == b && b == 255)
+                    System.out.print(" .");
+                else
+                    System.out.print(" X");
+
+                if (rgb != 0xFFFFFF && returnWidth < col)
+                    returnWidth = col;
+            }
+            System.out.println();
+        }
+        return returnWidth;
+    }
+}
diff --git a/test/java/awt/font/TextLayout/LigatureCaretTest.java b/test/java/awt/font/TextLayout/LigatureCaretTest.java
new file mode 100644
index 0000000..e59bcca
--- /dev/null
+++ b/test/java/awt/font/TextLayout/LigatureCaretTest.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 1998, 2016, 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.
+ *
+ * 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.
+ */
+
+/**
+ *  @test
+ *  @bug 4178145 8144015
+*/
+
+/*
+ * Copyright 1998 IBM Corp.  All Rights Reserved.
+ */
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.font.TextAttribute;
+import java.awt.font.TextLayout;
+import java.awt.font.TextHitInfo;
+import java.awt.font.FontRenderContext;
+import java.util.Hashtable;
+
+/**
+ * This test ensures that TextLayout will not place a caret within
+ * an Arabic lam-alef ligature, and will correctly caret through
+ * bidirectional text with numbers.
+ */
+
+public class LigatureCaretTest {
+
+    public static void main(String[] args) {
+
+        //testBidiWithNumbers();
+        testLamAlef();
+        System.out.println("LigatureCaretTest PASSED");
+    }
+
+    // These values are for TextLayout constructors
+    private static final Hashtable map = new Hashtable();
+    static {
+      map.put(TextAttribute.FONT, new Font("Lucida Sans", Font.PLAIN, 24));
+    }
+    private static final FontRenderContext frc =
+                                new FontRenderContext(null, false, false);
+
+    /**
+     * Caret through text mixed-direction text and check the results.
+     * If the test fails an Error is thrown.
+     * @exception an Error is thrown if the test fails
+     */
+    public static void testBidiWithNumbers() {
+
+        String bidiWithNumbers = "abc\u05D0\u05D1\u05D2123abc";
+        // visual order for the text:
+        // abc123<gimel><bet><aleph>abc
+
+        int[] carets = { 0, 1, 2, 3, 7, 8, 6, 5, 4, 9, 10, 11, 12 };
+        TextLayout layout = new TextLayout(bidiWithNumbers, map, frc);
+
+        // Caret through TextLayout in both directions and check results.
+        for (int i=0; i < carets.length-1; i++) {
+
+            TextHitInfo hit = layout.getNextRightHit(carets[i]);
+            if (hit.getInsertionIndex() != carets[i+1]) {
+                throw new Error("right hit failed within layout");
+            }
+        }
+
+        if (layout.getNextRightHit(carets[carets.length-1]) != null) {
+            throw new Error("right hit failed at end of layout");
+        }
+
+        for (int i=carets.length-1; i > 0; i--) {
+
+            TextHitInfo hit = layout.getNextLeftHit(carets[i]);
+            if (hit.getInsertionIndex() != carets[i-1]) {
+                throw new Error("left hit failed within layout");
+            }
+        }
+
+        if (layout.getNextLeftHit(carets[0]) != null) {
+            throw new Error("left hit failed at end of layout");
+        }
+    }
+
+    /**
+     * Ensure proper careting and hit-testing behavior with
+     * a lam-alef ligature.
+     * If the test fails, an Error is thrown.
+     * @exception an Error is thrown if the test fails
+     */
+    public static void testLamAlef() {
+
+        // lam-alef form a mandantory ligature.
+        final String lamAlef = "\u0644\u0627";
+        final String ltrText = "abcd";
+
+        // Create a TextLayout with just a lam-alef sequence.  There
+        // should only be two valid caret positions:  one at
+        // insertion offset 0 and the other at insertion offset 2.
+        TextLayout layout = new TextLayout(lamAlef, map, frc);
+
+        TextHitInfo hit;
+
+        hit = layout.getNextLeftHit(0);
+        if (hit.getInsertionIndex() != 2) {
+            throw new Error("Left hit failed.  Hit:" + hit);
+        }
+
+        hit = layout.getNextRightHit(2);
+        if (hit.getInsertionIndex() != 0) {
+            throw new Error("Right hit failed.  Hit:" + hit);
+        }
+
+        hit = layout.hitTestChar(layout.getAdvance()/2, 0);
+        if (hit.getInsertionIndex() != 0 && hit.getInsertionIndex() != 2) {
+            throw new Error("Hit-test allowed incorrect caret.  Hit:" + hit);
+        }
+
+
+        // Create a TextLayout with some left-to-right text
+        // before the lam-alef sequence.  There should not be
+        // a caret position between the lam and alef.
+        layout = new TextLayout(ltrText+lamAlef, map, frc);
+
+        final int ltrLen = ltrText.length();
+        final int layoutLen = layout.getCharacterCount();
+
+        for (int i=0; i < ltrLen; i++) {
+            hit = layout.getNextRightHit(i);
+            if (hit.getInsertionIndex() != i+1) {
+                throw new Error("Right hit failed in ltr text.");
+            }
+        }
+
+        hit = layout.getNextRightHit(ltrLen);
+        if (layoutLen != hit.getInsertionIndex()) {
+            throw new Error("Right hit failed at direction boundary.");
+        }
+
+        hit = layout.getNextLeftHit(layoutLen);
+        if (hit.getInsertionIndex() != ltrLen) {
+            throw new Error("Left hit failed at end of text.");
+        }
+    }
+}
diff --git a/test/java/awt/font/TextLayout/OSXLigatureTest.java b/test/java/awt/font/TextLayout/OSXLigatureTest.java
new file mode 100644
index 0000000..b1d2d79
--- /dev/null
+++ b/test/java/awt/font/TextLayout/OSXLigatureTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 7162125
+ * @summary Test ligatures form on OS X.
+ */
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.awt.font.TextAttribute;
+import java.util.HashMap;
+import java.util.Map;
+
+public class OSXLigatureTest {
+
+    public static void main(String[] args) {
+        if (!System.getProperty("os.name").startsWith("Mac")) {
+            return;
+        }
+        String ligStr = "ffi";
+        int w = 50, h = 50;
+
+        BufferedImage bi1 = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+        Graphics2D bi1Graphics = bi1.createGraphics();
+        bi1Graphics.setColor(Color.white);
+        bi1Graphics.fillRect(0, 0, w, h);
+        bi1Graphics.setColor(Color.black);
+        Font noLigFont = new Font("Gill Sans", Font.PLAIN, 30);
+        bi1Graphics.setFont(noLigFont);
+        bi1Graphics.drawString(ligStr, 10, 40);
+
+        BufferedImage bi2 = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+        Graphics2D bi2Graphics = bi2.createGraphics();
+        bi2Graphics.setColor(Color.white);
+        bi2Graphics.fillRect(0, 0, w, h);
+        bi2Graphics.setColor(Color.black);
+        Map<TextAttribute, Object> attributes = new HashMap<>();
+        attributes.put(TextAttribute.LIGATURES, TextAttribute.LIGATURES_ON);
+        Font ligFont = noLigFont.deriveFont(attributes);
+        bi2Graphics.setFont(ligFont);
+        bi2Graphics.drawString(ligStr, 10, 40);
+
+        boolean same = true;
+        for (int x = 0; x < w; x++) {
+            for (int y = 0; y < h; y++) {
+                int c1 = bi1.getRGB(x, y);
+                int c2 = bi2.getRGB(x, y);
+                same &= (c1 == c2);
+            }
+            if (!same) {
+               break;
+            }
+        }
+        if (same) {
+            throw new RuntimeException("Images do not differ - no ligature");
+        }
+    }
+}
diff --git a/test/java/awt/font/TextLayout/StyledFontLayoutTest.java b/test/java/awt/font/TextLayout/StyledFontLayoutTest.java
new file mode 100644
index 0000000..8063814
--- /dev/null
+++ b/test/java/awt/font/TextLayout/StyledFontLayoutTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8139176
+ * @summary Test layout uses correct styled font.
+ * @run main StyledFontLayoutTest
+ */
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import javax.swing.WindowConstants;
+
+public class StyledFontLayoutTest extends JPanel {
+
+    static final int W=600, H=400;
+    static boolean interactive;
+    static BufferedImage im;
+    public static void main(String[] args) {
+
+        interactive = args.length > 0;
+
+        runTest();
+
+        if (!interactive) {
+            return;
+        }
+        SwingUtilities.invokeLater(() -> {
+            JFrame frame = new JFrame("Styled Font Layout Test");
+            frame.add(new StyledFontLayoutTest());
+            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+            frame.setSize(W, H);
+            frame.setLocationRelativeTo(null);
+            frame.setVisible(true);
+        });
+    }
+
+    @Override
+    protected void paintComponent(Graphics g) {
+        g.drawImage(im, 0, 0, null);
+    }
+
+    private static void runTest() {
+        im = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB);
+        Graphics2D g2d = im.createGraphics();
+        g2d.setColor(Color.white);
+        g2d.fillRect(0, 0, W, H);
+        g2d.setColor(Color.black);
+        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+                             RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+        char[] chs = "Sample Text.".toCharArray();
+        int len = chs.length;
+
+        int x = 50, y = 100;
+
+        FontRenderContext frc = g2d.getFontRenderContext();
+        Font plain = new Font("Serif", Font.PLAIN, 48);
+        GlyphVector pgv = plain.layoutGlyphVector(frc, chs, 0, len, 0);
+        g2d.setFont(plain);
+        g2d.drawChars(chs, 0, len, x, y); y +=50;
+
+        g2d.drawGlyphVector(pgv, x, y); y += 50;
+        Rectangle2D plainStrBounds = plain.getStringBounds(chs, 0, len, frc);
+        Rectangle2D plainGVBounds = pgv.getLogicalBounds();
+        Font bold = new Font("Serif", Font.BOLD, 48);
+        GlyphVector bgv = bold.layoutGlyphVector(frc, chs, 0, len, 0);
+        Rectangle2D boldStrBounds = bold.getStringBounds(chs, 0, len, frc);
+        Rectangle2D boldGVBounds = bgv.getLogicalBounds();
+        g2d.setFont(bold);
+        g2d.drawChars(chs, 0, len, x, y); y +=50;
+        g2d.drawGlyphVector(bgv, x, y);
+        System.out.println("Plain String Bounds = " + plainStrBounds);
+        System.out.println("Bold String Bounds = " + boldStrBounds);
+        System.out.println("Plain GlyphVector Bounds = " + plainGVBounds);
+        System.out.println("Bold GlyphVector Bounds = " + boldGVBounds);
+        if (!plainStrBounds.equals(boldStrBounds) &&
+             plainGVBounds.equals(boldGVBounds))
+        {
+            System.out.println("Test failed: Plain GV bounds same as Bold");
+            if (!interactive) {
+                throw new RuntimeException("Plain GV bounds same as Bold");
+            }
+        }
+
+    };
+}
diff --git a/test/java/awt/font/TextLayout/TestJustification.html b/test/java/awt/font/TextLayout/TestJustification.html
new file mode 100644
index 0000000..c9e79f4
--- /dev/null
+++ b/test/java/awt/font/TextLayout/TestJustification.html
@@ -0,0 +1,52 @@
+<!--
+ Copyright (c) 1999, 2016, 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.
+ 
+ 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.
+--> 
+
+<html>
+<head>
+<title>Test Justification</title>
+</head>
+<body>
+<!--
+ @test
+ @bug 4211728 4178140 8145542
+ @summary Justify several lines of text and verify that the lines are the same
+ length and cursor positions are correct.
+Bug 4211728:  TextLayout.draw() draws characters at wrong position.
+Bug 4178140:  TextLayout does not justify
+ @run applet/manual=yesno TestJustification.html
+-->
+<h3>Test Justification</h1>
+<hr>
+<p>Five lines of text should appear, all justified to the same width,
+followed by a sixth line containing only roman characters and no spaces
+which is not justified, and instead is centered.
+Carets should appear between all characters. Pass the test if this is
+true.
+<p>
+<applet code=TestJustification.class width=500 height=500>
+alt="Your browser understands the &lt;APPLET&gt; tag but isn't running the applet, for some reason."
+Your browser is completely ignoring the &lt;APPLET&gt; tag!
+</applet>
+</body>
+</html>
+
diff --git a/test/java/awt/font/TextLayout/TestJustification.java b/test/java/awt/font/TextLayout/TestJustification.java
new file mode 100644
index 0000000..417ddd5
--- /dev/null
+++ b/test/java/awt/font/TextLayout/TestJustification.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 1999, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ *
+ * See TestJustification.html for main test.
+ */
+
+import java.applet.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.font.*;
+import java.awt.geom.*;
+import java.text.*;
+
+public class TestJustification extends Applet {
+  JustificationPanel panel;
+
+  public void init() {
+    setLayout(new BorderLayout());
+    panel = new JustificationPanel("Bitstream Cyberbit");
+    add("Center", panel);
+  }
+
+  public void destroy() {
+    remove(panel);
+  }
+
+  // calls system.exit, not for use in tests.
+  public static void main(String args[]) {
+    TestJustification justificationTest = new TestJustification();
+    justificationTest.init();
+    justificationTest.start();
+
+    Frame f = new Frame("Test Justification");
+    f.addWindowListener(new WindowAdapter() {
+      public void windowClosing(WindowEvent e) {
+        System.exit(0);
+      }
+    });
+
+    f.add("Center", justificationTest);
+    f.setSize(500, 500);
+    f.show();
+  }
+
+  public String getAppletInfo() {
+    return "Test TextLayout.getJustifiedLayout()";
+  }
+
+  static class JustificationPanel extends Panel {
+    TextLayout[] layouts;
+    String fontname;
+    float height;
+    float oldfsize;
+
+    AttributedCharacterIterator lineText;
+    TextLayout[] lines;
+    int linecount;
+    float oldwidth;
+
+    JustificationPanel(String fontname) {
+      this.fontname = fontname;
+    }
+
+    private static final String[] texts = {
+      "This is an english Highlighting demo.", "Highlighting",
+      "This is an arabic \u0627\u0628\u062a\u062c \u062e\u0644\u0627\u062e demo.", "arabic \u0627\u0628\u062a\u062c",
+      "This is a hebrew \u05d0\u05d1\u05d2 \u05d3\u05d4\u05d5 demo.", "hebrew \u05d0\u05d1\u05d2",
+      "This is a cjk \u4e00\u4e01\u4e02\uac00\uac01\uc4fa\uf900\uf901\uf902 demo.", "cjk",
+      "NoSpaceCJK:\u4e00\u4e01\u4e02and\uac00\uac01\uc4faand\uf900\uf901\uf902", "No",
+      "NoSpaceRoman", "Space"
+    };
+
+    public void paint(Graphics g) {
+      Graphics2D g2d = (Graphics2D)g;
+
+      Dimension d = getSize();
+      Insets insets = getInsets();
+
+      float w = d.width - insets.left - insets.right;
+      float h = d.height - insets.top - insets.bottom;
+      int fsize = (int)w/25;
+
+      FontRenderContext frc = g2d.getFontRenderContext();
+
+      if (layouts == null || fsize != oldfsize) {
+        oldfsize = fsize;
+
+        Font f0 = new Font(fontname, Font.PLAIN, fsize);
+        Font f1 = new Font(fontname, Font.ITALIC, (int)(fsize * 1.5));
+
+        if (layouts == null) {
+          layouts = new TextLayout[texts.length / 2];
+        }
+
+        height = 0;
+        for (int i = 0; i < layouts.length; ++i) {
+          String text = texts[i*2];
+          String target = texts[i*2+1];
+
+          AttributedString astr = new AttributedString(text);
+          astr.addAttribute(TextAttribute.FONT, f0, 0, text.length());
+
+          int start = text.indexOf(target);
+          int limit = start + target.length();
+          astr.addAttribute(TextAttribute.FONT, f1, start, limit);
+
+          TextLayout layout = new TextLayout(astr.getIterator(), frc);
+
+          layout = layout.getJustifiedLayout(w - 20);
+
+          layouts[i] = layout;
+
+          height += layout.getAscent() + layout.getDescent() + layout.getLeading();
+        }
+      }
+
+      g2d.setColor(Color.white);
+      g2d.fill(new Rectangle.Float(insets.left, insets.top, w, h));
+
+      float basey = 20;
+
+      for (int i = 0; i < layouts.length; ++i) {
+        TextLayout layout = layouts[i];
+
+        float la = layout.getAscent();
+        float ld = layout.getDescent();
+        float ll = layout.getLeading();
+        float lw = layout.getAdvance();
+        float lh = la + ld + ll;
+        float lx = (w - lw) / 2f;
+        float ly = basey + layout.getAscent();
+
+        g2d.setColor(Color.black);
+        g2d.translate(insets.left + lx, insets.top + ly);
+
+        Rectangle2D bounds = new Rectangle2D.Float(0, -la, lw, lh);
+        g2d.draw(bounds);
+
+        layout.draw(g2d, 0, 0);
+
+        g2d.setColor(Color.red);
+        for (int j = 0, e = layout.getCharacterCount(); j <= e; ++j) {
+          Shape[] carets = layout.getCaretShapes(j, bounds);
+          g2d.draw(carets[0]);
+        }
+
+        g2d.translate(-insets.left - lx, -insets.top - ly);
+        basey += layout.getAscent() + layout.getDescent() + layout.getLeading();
+      }
+
+      // add LineBreakMeasurer-generated layouts
+
+      if (lineText == null) {
+        String text = "This is a long line of text that should be broken across multiple "
+          + "lines and then justified to fit the break width.  This test should pass if "
+          + "these lines are justified to the same width, and fail otherwise.  It should "
+          + "also format the hebrew (\u05d0\u05d1\u05d2 \u05d3\u05d4\u05d5) and arabic "
+          + "(\u0627\u0628\u062a\u062c \u062e\u0644\u0627\u062e) and CJK "
+          + "(\u4e00\u4e01\u4e02\uac00\uac01\uc4fa\u67b1\u67b2\u67b3\u67b4\u67b5\u67b6\u67b7"
+          + "\u67b8\u67b9) text correctly.";
+
+        Float regular = new Float(16.0);
+        Float big = new Float(24.0);
+        AttributedString astr = new AttributedString(text);
+        astr.addAttribute(TextAttribute.SIZE, regular, 0, text.length());
+        astr.addAttribute(TextAttribute.FAMILY, fontname, 0, text.length());
+
+        int ix = text.indexOf("broken");
+        astr.addAttribute(TextAttribute.SIZE, big, ix, ix + 6);
+        ix = text.indexOf("hebrew");
+        astr.addAttribute(TextAttribute.SIZE, big, ix, ix + 6);
+        ix = text.indexOf("arabic");
+        astr.addAttribute(TextAttribute.SIZE, big, ix, ix + 6);
+        ix = text.indexOf("CJK");
+        astr.addAttribute(TextAttribute.SIZE, big, ix, ix + 3);
+
+        lineText = astr.getIterator();
+      }
+
+      float width = w - 20;
+      if (lines == null || width != oldwidth) {
+        oldwidth = width;
+
+        lines = new TextLayout[10];
+        linecount = 0;
+
+        LineBreakMeasurer measurer = new LineBreakMeasurer(lineText, frc);
+
+        for (;;) {
+          TextLayout layout = measurer.nextLayout(width);
+          if (layout == null) {
+            break;
+          }
+
+          // justify all but last line
+          if (linecount > 0) {
+            lines[linecount - 1] = lines[linecount - 1].getJustifiedLayout(width);
+          }
+
+          if (linecount == lines.length) {
+            TextLayout[] nlines = new TextLayout[lines.length * 2];
+            System.arraycopy(lines, 0, nlines, 0, lines.length);
+            lines = nlines;
+          }
+
+          lines[linecount++] = layout;
+        }
+      }
+
+      float basex = insets.left + 10;
+      basey += 10;
+      g2d.setColor(Color.black);
+
+      for (int i = 0; i < linecount; ++i) {
+        TextLayout layout = lines[i];
+
+        basey += layout.getAscent();
+        float adv = layout.getAdvance();
+        float dx = layout.isLeftToRight() ? 0 : width - adv;
+
+        layout.draw(g2d, basex + dx, basey);
+
+        basey += layout.getDescent() + layout.getLeading();
+      }
+    }
+  }
+}
diff --git a/test/java/awt/font/TextLayout/TestLayoutVsICU.java b/test/java/awt/font/TextLayout/TestLayoutVsICU.java
new file mode 100644
index 0000000..e9bbe83
--- /dev/null
+++ b/test/java/awt/font/TextLayout/TestLayoutVsICU.java
@@ -0,0 +1,889 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/**
+ * Copyright (C) 2013-2014 IBM Corporation and Others. All Rights Reserved.
+ */
+
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Font;
+import java.awt.FontFormatException;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.RenderingHints.Key;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ImageObserver;
+import java.awt.image.RenderedImage;
+import java.awt.image.renderable.RenderableImage;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.AttributedCharacterIterator;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.TreeMap;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+/**
+ * This test runs against a test XML file. It opens the fonts and attempts
+ * to shape and layout glyphs.
+ * Note that the test is highly environment dependent- you must have
+ * the same versions of the same fonts available or the test will fail.
+ *
+ * It is similar to letest which is part of ICU.
+ * For reference, here are some reference items:
+ * ICU's test file:
+ *  http://source.icu-project.org/repos/icu/icu/trunk/source/test/testdata/letest.xml
+ * ICU's readme for the similar test:
+ *  http://source.icu-project.org/repos/icu/icu/trunk/source/test/letest/readme.html
+ *
+ * @bug 8054203
+ * @test
+ * @summary manual test of layout engine behavior. Takes an XML control file.
+ * @compile TestLayoutVsICU.java
+ * @author srl
+ * @run main/manual
+ */
+public class TestLayoutVsICU {
+
+    public static boolean OPT_DRAW = false;
+    public static boolean OPT_VERBOSE = false;
+    public static boolean OPT_FAILMISSING = false;
+    public static boolean OPT_NOTHROW= false; // if true - don't stop on failure
+
+    public static int docs = 0; // # docs processed
+    public static int skipped = 0; // cases skipped due to bad font
+    public static int total = 0; // cases processed
+    public static int bad = 0; // cases with errs
+
+    public static final String XML_LAYOUT_TESTS = "layout-tests"; // top level
+    public static final String XML_TEST_CASE = "test-case";
+    public static final String XML_TEST_FONT = "test-font";
+    public static final String XML_TEST_TEXT = "test-text";
+    public static final String XML_RESULT_GLYPHS = "result-glyphs";
+    public static final String XML_ID = "id";
+    public static final String XML_SCRIPT = "script";
+    public static final String XML_NAME = "name";
+    public static final String XML_VERSION = "version";
+    public static final String XML_CHECKSUM = "checksum";
+    public static final String XML_RESULT_INDICES = "result-indices";
+    public static final String XML_RESULT_POSITIONS = "result-positions";
+
+    /**
+     * @param args
+     * @throws IOException
+     * @throws SAXException
+     * @throws ParserConfigurationException
+     */
+    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
+        System.out.println("Java " + System.getProperty("java.version") + " from " + System.getProperty("java.vendor"));
+        TestLayoutVsICU tlvi = null;
+        for(String arg : args) {
+            if(arg.equals("-d")) {
+                OPT_DRAW = true;
+            } else if(arg.equals("-n")) {
+                OPT_NOTHROW = true;
+            } else if(arg.equals("-v")) {
+                OPT_VERBOSE = true;
+            } else if(arg.equals("-f")) {
+                OPT_FAILMISSING = true;
+            } else {
+                if(tlvi == null) {
+                    tlvi = new TestLayoutVsICU();
+                }
+                try {
+                    tlvi.show(arg);
+                } finally {
+                    if(OPT_VERBOSE) {
+                        System.out.println("# done with " + arg);
+                    }
+                }
+            }
+        }
+
+        if(tlvi == null) {
+            throw new IllegalArgumentException("No XML input. Usage: " + TestLayoutVsICU.class.getSimpleName() + " [-d][-v][-f] letest.xml ...");
+        } else {
+            System.out.println("\n\nRESULTS:\n");
+            System.out.println(skipped+"\tskipped due to missing font");
+            System.out.println(total+"\ttested of which:");
+            System.out.println(bad+"\twere bad");
+
+            if(bad>0) {
+                throw new InternalError("One or more failure(s)");
+            }
+        }
+    }
+
+    String id;
+
+    private void show(String arg) throws ParserConfigurationException, SAXException, IOException {
+        id = "<none>";
+        File xmlFile = new File(arg);
+        if(!xmlFile.exists()) {
+            throw new FileNotFoundException("Can't open input XML file " + arg);
+        }
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        DocumentBuilder db = dbf.newDocumentBuilder();
+        if(OPT_VERBOSE) {
+            System.out.println("# Parsing " + xmlFile.getAbsolutePath());
+        }
+        Document doc = db.parse(xmlFile);
+        Element e = doc.getDocumentElement();
+        if(!XML_LAYOUT_TESTS.equals(e.getNodeName())) {
+            throw new IllegalArgumentException("Document " + xmlFile.getAbsolutePath() + " does not have <layout-tests> as its base");
+        }
+
+        NodeList testCases = e.getElementsByTagName(XML_TEST_CASE);
+        for(int caseNo=0;caseNo<testCases.getLength();caseNo++) {
+            final Node testCase = testCases.item(caseNo);
+            final Map<String,String> testCaseAttrs = attrs(testCase);
+            id = testCaseAttrs.get(XML_ID);
+            final String script = testCaseAttrs.get(XML_SCRIPT);
+            String testText = null;
+            Integer[] expectGlyphs = null;
+            Integer[] expectIndices = null;
+            Map<String,String> fontAttrs = null;
+            if(OPT_VERBOSE) {
+                System.out.println("#"+caseNo+" id="+id + ", script="+script);
+            }
+            NodeList children = testCase.getChildNodes();
+            for(int sub=0;sub<children.getLength();sub++) {
+                Node n = children.item(sub);
+                if(n.getNodeType()!=Node.ELEMENT_NODE) continue;
+                String nn = n.getNodeName();
+                if(nn.equals(XML_TEST_FONT)) {
+                    fontAttrs = attrs(n);
+                } else if(nn.equals(XML_TEST_TEXT)) {
+                    testText = n.getTextContent();
+                } else if(nn.equals(XML_RESULT_GLYPHS)) {
+                    String hex = n.getTextContent();
+                    expectGlyphs = parseHexArray(hex);
+                } else if(nn.equals(XML_RESULT_INDICES)) {
+                    String hex = n.getTextContent();
+                    expectIndices = parseHexArray(hex);
+                } else if(OPT_VERBOSE) {
+                    System.out.println("Ignoring node " + nn);
+                }
+            }
+            if(fontAttrs == null) {
+                throw new IllegalArgumentException(id + " Missing node " + XML_TEST_FONT);
+            }
+            if(testText == null) {
+                throw new IllegalArgumentException(id + " Missing node " + XML_TEST_TEXT);
+            }
+
+            String fontName = fontAttrs.get(XML_NAME);
+            Font f = getFont(fontName, fontAttrs);
+            if(f==null) {
+                if(OPT_FAILMISSING) {
+                    throw new MissingResourceException("Missing font,  abort test", Font.class.getName(), fontName);
+                }
+                System.out.println("Skipping " + id + " because font is missing: " + fontName);
+                skipped++;
+                continue;
+            }
+            FontRenderContext frc = new FontRenderContext(null, true, true);
+            TextLayout tl = new TextLayout(testText,f,frc);
+            final List<GlyphVector> glyphs = new ArrayList<GlyphVector>();
+            Graphics2D myg2 = new Graphics2D(){
+
+                    @Override
+                    public void draw(Shape s) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public boolean drawImage(Image img, AffineTransform xform,
+                                             ImageObserver obs) {
+                        // TODO Auto-generated method stub
+                        return false;
+                    }
+
+                    @Override
+                    public void drawImage(BufferedImage img,
+                                          BufferedImageOp op, int x, int y) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void drawRenderedImage(RenderedImage img,
+                                                  AffineTransform xform) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void drawRenderableImage(RenderableImage img,
+                                                    AffineTransform xform) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void drawString(String str, int x, int y) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void drawString(String str, float x, float y) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void drawString(
+                                           AttributedCharacterIterator iterator, int x, int y) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void drawString(
+                                           AttributedCharacterIterator iterator, float x,
+                                           float y) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void drawGlyphVector(GlyphVector g, float x, float y) {
+                        if(x!=0.0 || y!=0.0) {
+                            throw new InternalError("x,y should be 0 but got " + x+","+y);
+                        }
+                        //System.err.println("dGV : " + g.toString() + " @ "+x+","+y);
+                        glyphs.add(g);
+                    }
+
+                    @Override
+                    public void fill(Shape s) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
+                        // TODO Auto-generated method stub
+                        return false;
+                    }
+
+                    @Override
+                    public GraphicsConfiguration getDeviceConfiguration() {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    @Override
+                    public void setComposite(Composite comp) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void setPaint(Paint paint) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void setStroke(Stroke s) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void setRenderingHint(Key hintKey, Object hintValue) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public Object getRenderingHint(Key hintKey) {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    @Override
+                    public void setRenderingHints(Map<?, ?> hints) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void addRenderingHints(Map<?, ?> hints) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public RenderingHints getRenderingHints() {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    @Override
+                    public void translate(int x, int y) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void translate(double tx, double ty) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void rotate(double theta) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void rotate(double theta, double x, double y) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void scale(double sx, double sy) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void shear(double shx, double shy) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void transform(AffineTransform Tx) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void setTransform(AffineTransform Tx) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public AffineTransform getTransform() {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    @Override
+                    public Paint getPaint() {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    @Override
+                    public Composite getComposite() {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    @Override
+                    public void setBackground(Color color) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public Color getBackground() {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    @Override
+                    public Stroke getStroke() {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    @Override
+                    public void clip(Shape s) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public FontRenderContext getFontRenderContext() {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    @Override
+                    public Graphics create() {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    @Override
+                    public Color getColor() {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    @Override
+                    public void setColor(Color c) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void setPaintMode() {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void setXORMode(Color c1) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public Font getFont() {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    @Override
+                    public void setFont(Font font) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public FontMetrics getFontMetrics(Font f) {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    @Override
+                    public Rectangle getClipBounds() {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    @Override
+                    public void clipRect(int x, int y, int width, int height) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void setClip(int x, int y, int width, int height) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public Shape getClip() {
+                        // TODO Auto-generated method stub
+                        return null;
+                    }
+
+                    @Override
+                    public void setClip(Shape clip) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void copyArea(int x, int y, int width, int height,
+                                         int dx, int dy) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void drawLine(int x1, int y1, int x2, int y2) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void fillRect(int x, int y, int width, int height) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void clearRect(int x, int y, int width, int height) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void drawRoundRect(int x, int y, int width,
+                                              int height, int arcWidth, int arcHeight) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void fillRoundRect(int x, int y, int width,
+                                              int height, int arcWidth, int arcHeight) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void drawOval(int x, int y, int width, int height) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void fillOval(int x, int y, int width, int height) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void drawArc(int x, int y, int width, int height,
+                                        int startAngle, int arcAngle) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void fillArc(int x, int y, int width, int height,
+                                        int startAngle, int arcAngle) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void drawPolyline(int[] xPoints, int[] yPoints,
+                                             int nPoints) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void drawPolygon(int[] xPoints, int[] yPoints,
+                                            int nPoints) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public void fillPolygon(int[] xPoints, int[] yPoints,
+                                            int nPoints) {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                    @Override
+                    public boolean drawImage(Image img, int x, int y,
+                                             ImageObserver observer) {
+                        // TODO Auto-generated method stub
+                        return false;
+                    }
+
+                    @Override
+                    public boolean drawImage(Image img, int x, int y,
+                                             int width, int height, ImageObserver observer) {
+                        // TODO Auto-generated method stub
+                        return false;
+                    }
+
+                    @Override
+                    public boolean drawImage(Image img, int x, int y,
+                                             Color bgcolor, ImageObserver observer) {
+                        // TODO Auto-generated method stub
+                        return false;
+                    }
+
+                    @Override
+                    public boolean drawImage(Image img, int x, int y,
+                                             int width, int height, Color bgcolor,
+                                             ImageObserver observer) {
+                        // TODO Auto-generated method stub
+                        return false;
+                    }
+
+                    @Override
+                    public boolean drawImage(Image img, int dx1, int dy1,
+                                             int dx2, int dy2, int sx1, int sy1, int sx2,
+                                             int sy2, ImageObserver observer) {
+                        // TODO Auto-generated method stub
+                        return false;
+                    }
+
+                    @Override
+                    public boolean drawImage(Image img, int dx1, int dy1,
+                                             int dx2, int dy2, int sx1, int sy1, int sx2,
+                                             int sy2, Color bgcolor, ImageObserver observer) {
+                        // TODO Auto-generated method stub
+                        return false;
+                    }
+
+                    @Override
+                    public void dispose() {
+                        // TODO Auto-generated method stub
+
+                    }
+
+                };
+            tl.draw(myg2, 0, 0);
+            if(glyphs.size() != 1) {
+                err("drew " + glyphs.size() + " times - expected 1");
+                total++;
+                bad++;
+                continue;
+            }
+            boolean isBad = false;
+            GlyphVector gv = glyphs.get(0);
+
+            // GLYPHS
+            int gotGlyphs[] = gv.getGlyphCodes(0, gv.getNumGlyphs(), new int[gv.getNumGlyphs()]);
+
+            int count = Math.min(gotGlyphs.length, expectGlyphs.length); // go up to this count
+
+            for(int i=0;i<count;i++) {
+                if(gotGlyphs[i]!=expectGlyphs[i]) {
+                    err("@"+i+" - got \tglyph 0x" + Integer.toHexString(gotGlyphs[i]) + " wanted 0x" + Integer.toHexString(expectGlyphs[i]));
+                    isBad=true;
+                    break;
+                }
+            }
+
+            // INDICES
+            int gotIndices[] = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), new int[gv.getNumGlyphs()]);
+            for(int i=0;i<count;i++) {
+                if(gotIndices[i]!=expectIndices[i]) {
+                    err("@"+i+" - got \tindex 0x" + Integer.toHexString(gotGlyphs[i]) + " wanted 0x" + Integer.toHexString(expectGlyphs[i]));
+                    isBad=true;
+                    break;
+                }
+            }
+
+
+            // COUNT
+            if(gotGlyphs.length != expectGlyphs.length) {
+                System.out.println("Got " + gotGlyphs.length + " wanted " + expectGlyphs.length + " glyphs");
+                isBad=true;
+            } else {
+                if(OPT_VERBOSE) {
+                    System.out.println(">> OK: " + gotGlyphs.length + " glyphs");
+                }
+            }
+
+
+            if(isBad) {
+                bad++;
+                System.out.println("* FAIL: " + id + "  /\t" + fontName);
+            } else {
+                System.out.println("* OK  : " + id + "  /\t" + fontName);
+            }
+            total++;
+        }
+    }
+
+
+    private boolean verifyFont(File f, Map<String, String> fontAttrs) {
+        InputStream fis = null;
+        String fontName = fontAttrs.get(XML_NAME);
+        int count=0;
+        try {
+            fis = new BufferedInputStream(new FileInputStream(f));
+
+            int i = 0;
+            int r;
+            try {
+                while((r=fis.read())!=-1) {
+                    i+=(int)r;
+                    count++;
+                }
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+                return false;
+            }
+            if(OPT_VERBOSE) {
+                System.out.println("for " + f.getAbsolutePath() + " chks = 0x" + Integer.toHexString(i) + " size=" + count);
+            }
+            String theirStr = fontAttrs.get("rchecksum");
+
+            String ourStr = Integer.toHexString(i).toLowerCase();
+
+            if(theirStr!=null) {
+                if(theirStr.startsWith("0x")) {
+                    theirStr = theirStr.substring(2).toLowerCase();
+                } else {
+                    theirStr = theirStr.toLowerCase();
+                }
+                long theirs = Integer.parseInt(theirStr, 16);
+                if(theirs != i) {
+                    err("WARNING: rchecksum for " + fontName + " was " + i  + " (0x"+ourStr+") "+ " but file said " + theirs +" (0x"+theirStr+")  - perhaps a different font?");
+                    return false;
+                } else {
+                    if(OPT_VERBOSE) {
+                        System.out.println(" rchecksum for " + fontName + " OK");
+                    }
+                    return true;
+                }
+            } else {
+                //if(OPT_VERBOSE) {
+                System.err.println("WARNING: rchecksum for " + fontName + " was " + i  + " (0x"+ourStr+") "+ " but rchecksum was MISSING. Old ICU data?");
+                //}
+            }
+        } catch (FileNotFoundException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+            return false;
+        } finally {
+            try {
+                fis.close();
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+        return true;
+    }
+
+
+    private Integer[] parseHexArray(String hex) {
+        List<Integer> ret = new ArrayList<Integer>();
+        String items[] = hex.split("[\\s,]");
+        for(String i : items) {
+            if(i.isEmpty()) continue;
+            if(i.startsWith("0x")) {
+                i = i.substring(2);
+            }
+            ret.add(Integer.parseInt(i, 16));
+        }
+        return ret.toArray(new Integer[0]);
+    }
+
+
+    private void err(String string) {
+        if(OPT_NOTHROW) {
+            System.out.println(id+" ERROR: " + string +" (continuing due to -n)");
+        } else {
+            throw new InternalError(id+ ": " + string);
+        }
+    }
+
+
+    private Font getFont(String fontName, Map<String, String> fontAttrs) {
+        Font f;
+        if(false)
+            try {
+                f = Font.getFont(fontName);
+                if(f!=null)  {
+                    if(OPT_VERBOSE) {
+                        System.out.println("Loaded default path to " + fontName);
+                    }
+                    return f;
+                }
+            } catch(Throwable t) {
+                if(OPT_VERBOSE) {
+                    t.printStackTrace();
+                    System.out.println("problem loading font " + fontName + " - " + t.toString());
+                }
+            }
+
+        File homeDir = new File(System.getProperty("user.home"));
+        File fontDir = new File(homeDir, "fonts");
+        File fontFile = new File(fontDir, fontName);
+        //System.out.println("## trying " + fontFile.getAbsolutePath());
+        if(fontFile.canRead()) {
+            try {
+                if(!verifyFont(fontFile,fontAttrs)) {
+                    System.out.println("Warning: failed to verify " + fontName);
+                }
+                f = Font.createFont(Font.TRUETYPE_FONT, fontFile);
+                if(f!=null & OPT_VERBOSE) {
+                    System.out.println("> loaded from " + fontFile.getAbsolutePath() + " - " + f.toString());
+                }
+                return f;
+            } catch (FontFormatException e) {
+                if(OPT_VERBOSE) {
+                    e.printStackTrace();
+                    System.out.println("problem loading font " + fontName + " - " + e.toString());
+                }
+            } catch (IOException e) {
+                if(OPT_VERBOSE) {
+                    e.printStackTrace();
+                    System.out.println("problem loading font " + fontName + " - " + e.toString());
+                }
+            }
+        }
+        return null;
+    }
+
+
+    private static Map<String, String> attrs(Node testCase) {
+        Map<String,String> rv = new TreeMap<String,String>();
+        NamedNodeMap nnm = testCase.getAttributes();
+        for(int i=0;i<nnm.getLength();i++) {
+            Node n = nnm.item(i);
+            String k = n.getNodeName();
+            String v = n.getNodeValue();
+            rv.put(k, v);
+        }
+        return rv;
+    }
+}
diff --git a/test/java/awt/font/TextLayout/TestLayoutVsICU_jdkbase.xml b/test/java/awt/font/TextLayout/TestLayoutVsICU_jdkbase.xml
new file mode 100644
index 0000000..6cc6336
--- /dev/null
+++ b/test/java/awt/font/TextLayout/TestLayoutVsICU_jdkbase.xml
@@ -0,0 +1,1827 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+/*
+ * 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.
+ *
+ * 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.
+ */
+-->
+<!--
+   NOTE: You are unlikely to have all needed fonts.
+ -->
+<!--
+  Copyright (c) 1999-2014 International Business Machines
+  Corporation and others. All rights reserved.
+
+  WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT
+  UNLESS YOU REALLY KNOW WHAT YOU'RE DOING.
+
+  file name:    letest.xml
+  generated on: 03/04/2013 10:28:51 PM PST
+  generated by: gendata.cpp
+-->
+
+<layout-tests>
+    <test-case id="Ghita" script="deva">
+        <test-font name="raghu.ttf" version="Original Version 1.00 (2005)" checksum="0x088DB135" rchecksum="0x00803FCE"/>
+
+        <test-text>श्रीमद् भगवद्गीता अध्याय अर्जुन विषाद योग धृतराष्ट्र उवाचृ धर्मक्षेत्रे कुरुक्षेत्रे समवेता युयुत्सवः मामकाः पाण्डवाश्चैव किमकुर्वत संजव</test-text>
+
+        <result-glyphs>
+            0x0000009E, 0x0000009A, 0x00000051, 0x00000222, 0x00000098, 0x00000091, 0x00000051, 0x00000003, 
+            0x00000097, 0x00000082, 0x0000009D, 0x000001A5, 0x0000FFFF, 0x0000FFFF, 0x00000222, 0x0000008F, 
+            0x00000221, 0x00000003, 0x0000005C, 0x000000DA, 0x0000FFFF, 0x00000099, 0x00000221, 0x00000099, 
+            0x00000003, 0x0000005C, 0x00000087, 0x000001D5, 0x0000005B, 0x0000FFFF, 0x00000093, 0x00000003, 
+            0x000001D2, 0x0000009D, 0x0000009F, 0x00000221, 0x00000091, 0x00000003, 0x00000099, 0x0000022A, 
+            0x00000082, 0x00000003, 0x00000092, 0x000001D9, 0x0000008F, 0x0000009A, 0x00000221, 0x000001B4, 
+            0x0000FFFF, 0x0000FFFF, 0x0000009A, 0x00000051, 0x00000003, 0x00000060, 0x0000009D, 0x00000221, 
+            0x00000085, 0x000001D9, 0x00000003, 0x00000092, 0x00000098, 0x0000005B, 0x0000FFFF, 0x000000A2, 
+            0x0000FFFF, 0x0000FFFF, 0x0000022F, 0x0000008F, 0x0000009A, 0x00000051, 0x0000022F, 0x00000003, 
+            0x00000080, 0x000001D5, 0x0000009A, 0x000001FD, 0x000000A2, 0x0000FFFF, 0x0000FFFF, 0x0000022F, 
+            0x0000008F, 0x0000009A, 0x00000051, 0x0000022F, 0x00000003, 0x000000A0, 0x00000098, 0x0000009D, 
+            0x0000022F, 0x0000008F, 0x00000221, 0x00000003, 0x00000099, 0x000001D5, 0x00000099, 0x000001D5, 
+            0x000000D7, 0x0000FFFF, 0x000000A0, 0x0000009D, 0x0000022C, 0x00000003, 0x00000098, 0x00000221, 
+            0x00000098, 0x00000080, 0x00000221, 0x0000022C, 0x00000003, 0x00000094, 0x00000221, 0x000000D6, 
+            0x0000FFFF, 0x0000008C, 0x0000009D, 0x00000221, 0x000001B1, 0x0000FFFF, 0x0000FFFF, 0x00000230, 
+            0x0000009D, 0x00000003, 0x000001D1, 0x00000080, 0x00000098, 0x00000080, 0x000001D5, 0x0000009D, 
+            0x0000005B, 0x0000FFFF, 0x0000008F, 0x00000003, 0x000000A0, 0x00000232, 0x00000087, 0x0000009D
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000002, 0x00000001, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F, 
+            0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017, 
+            0x00000018, 0x00000019, 0x0000001C, 0x0000001D, 0x0000001A, 0x0000001B, 0x0000001E, 0x0000001F, 
+            0x00000021, 0x00000020, 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x00000026, 0x00000027, 
+            0x00000028, 0x00000029, 0x0000002A, 0x0000002B, 0x0000002C, 0x0000002D, 0x0000002E, 0x0000002F, 
+            0x00000030, 0x00000031, 0x00000033, 0x00000032, 0x00000034, 0x00000035, 0x00000036, 0x00000037, 
+            0x00000038, 0x00000039, 0x0000003A, 0x0000003B, 0x0000003E, 0x0000003C, 0x0000003D, 0x0000003F, 
+            0x00000040, 0x00000041, 0x00000042, 0x00000043, 0x00000045, 0x00000044, 0x00000046, 0x00000047, 
+            0x00000048, 0x00000049, 0x0000004A, 0x0000004B, 0x0000004C, 0x0000004D, 0x0000004E, 0x0000004F, 
+            0x00000050, 0x00000052, 0x00000051, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 
+            0x00000058, 0x00000059, 0x0000005A, 0x0000005B, 0x0000005C, 0x0000005D, 0x0000005E, 0x0000005F, 
+            0x00000060, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 
+            0x00000068, 0x00000069, 0x0000006A, 0x0000006B, 0x0000006C, 0x0000006D, 0x0000006E, 0x0000006F, 
+            0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 
+            0x00000078, 0x00000079, 0x0000007B, 0x0000007A, 0x0000007C, 0x0000007D, 0x0000007E, 0x00000081, 
+            0x0000007F, 0x00000080, 0x00000082, 0x00000083, 0x00000084, 0x00000085, 0x00000086, 0x00000087
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 9.468750, 0.000000, 19.130859, -0.451172, 15.984375, 0.000000, 
+            19.640625, 0.000000, 29.109375, 0.000000, 40.177734, -0.451172, 37.078125, 0.000000, 
+            43.078125, 0.000000, 52.546875, 0.000000, 62.015625, 0.000000, 69.984375, 0.000000, 
+            77.953125, 0.000000, 77.953125, 0.000000, 77.953125, 0.000000, 81.609375, 0.000000, 
+            89.578125, 0.000000, 93.234375, 0.000000, 99.234375, 0.000000, 109.171875, 0.000000, 
+            116.437500, 0.000000, 116.437500, 0.000000, 125.906250, 0.000000, 129.562500, 0.000000, 
+            139.031250, 0.000000, 145.031250, 0.000000, 154.968750, 0.000000, 164.718750, -0.011719, 
+            164.718750, 0.263672, 164.437500, 0.000000, 164.437500, 0.000000, 173.906250, 0.000000, 
+            179.906250, 0.000000, 184.265625, 0.000000, 192.234375, 0.000000, 200.203125, 0.000000, 
+            203.859375, 0.000000, 211.828125, 0.000000, 217.828125, 0.000000, 227.296875, 0.000000, 
+            231.375000, 0.000000, 240.843750, 0.000000, 246.843750, 0.000000, 256.740234, -0.011719, 
+            256.312500, 0.000000, 264.281250, 0.000000, 270.796875, 0.000000, 274.453125, 0.000000, 
+            282.796875, 0.000000, 282.796875, 0.000000, 282.796875, 0.000000, 292.458984, -0.451172, 
+            289.312500, 0.000000, 295.312500, 0.000000, 303.281250, 0.000000, 311.250000, 0.000000, 
+            314.906250, 0.000000, 324.890625, -0.011719, 324.375000, 0.000000, 330.375000, 0.000000, 
+            339.843750, 0.000000, 349.675781, 0.263672, 349.312500, 0.000000, 349.312500, 0.000000, 
+            360.187500, 0.000000, 360.187500, 0.000000, 359.384766, 0.275391, 360.187500, 0.000000, 
+            368.156250, 0.000000, 377.818359, -0.451172, 372.996094, 0.263672, 374.671875, 0.000000, 
+            380.671875, 0.000000, 388.371094, -0.011719, 391.546875, 0.000000, 398.062500, 0.000000, 
+            399.421875, 0.000000, 410.296875, 0.000000, 410.296875, 0.000000, 409.494141, 0.275391, 
+            410.296875, 0.000000, 418.265625, 0.000000, 427.927734, -0.451172, 423.105469, 0.263672, 
+            424.781250, 0.000000, 430.781250, 0.000000, 440.250000, 0.000000, 449.718750, 0.000000, 
+            456.832031, 0.263672, 457.687500, 0.000000, 465.656250, 0.000000, 469.312500, 0.000000, 
+            475.312500, 0.000000, 484.921875, -0.011719, 484.781250, 0.000000, 494.390625, -0.011719, 
+            494.250000, 0.000000, 500.179688, 0.000000, 500.179688, 0.000000, 509.648438, 0.000000, 
+            517.617188, 0.000000, 521.976562, 0.000000, 527.976562, 0.000000, 537.445312, 0.000000, 
+            541.101562, 0.000000, 550.570312, 0.000000, 561.445312, 0.000000, 565.101562, 0.000000, 
+            569.460938, 0.000000, 575.460938, 0.000000, 583.429688, 0.000000, 587.085938, 0.000000, 
+            594.351562, 0.000000, 594.351562, 0.000000, 602.320312, 0.000000, 610.289062, 0.000000, 
+            613.945312, 0.000000, 624.820312, 0.000000, 624.820312, 0.000000, 624.691406, 0.263672, 
+            624.820312, 0.000000, 632.789062, 0.000000, 638.789062, 0.000000, 643.148438, 0.000000, 
+            654.023438, 0.000000, 663.492188, 0.000000, 671.191406, -0.011719, 674.367188, 0.000000, 
+            682.628906, 0.263672, 682.335938, 0.000000, 682.335938, 0.000000, 690.304688, 0.000000, 
+            696.304688, 0.000000, 705.140625, 0.439453, 705.773438, 0.000000, 715.242188, 0.000000, 
+            723.210938, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Arabic" script="arab">
+        <test-font name="CODE2000.TTF" version="Version 1.171" checksum="0xD025B1AD" rchecksum="0x1F6E6F2A"/>
+
+        <test-text>أساسًا، تتعامل الحواسيب فقط مع الأرقام، وتقوم بتخزين الأحرف والمحارف الأخرى بعد أن تُعطي رقما معينا لكل واحد منها. وقبل اختراع "يونِكود"، كان هناك مئات الأنظمة للتشفير وتخصيص هذه الأرقام للمحارف، ولم يوجد نظام تشفير واحد يحتوي على جميع المحارف الضرورية</test-text>
+
+        <result-glyphs>
+            0x0000CE28, 0x0000CE87, 0x0000CE41, 0x0000CE81, 0x0000CE42, 0x0000CE54, 0x0000CE73, 0x0000CE21, 
+            0x00000003, 0x0000CE65, 0x0000CE41, 0x0000CE22, 0x0000CE38, 0x0000CE78, 0x0000CE73, 0x0000CE21, 
+            0x00000003, 0x0000CE5E, 0x0000CE88, 0x0000CE78, 0x0000CE33, 0x00000003, 0x0000CE84, 0x0000CE74, 
+            0x0000CE5F, 0x00000003, 0x0000CE85, 0x0000CE82, 0x0000CE2C, 0x0000CE38, 0x0000CE87, 0x00000003, 
+            0x0000CE3E, 0x0000CE37, 0x0000CE21, 0x0000CE81, 0x00000003, 0x0000CE42, 0x0000CE88, 0x0000CE68, 
+            0x0000CE4C, 0x0000CE2B, 0x00000003, 0x0000CE75, 0x0000CE22, 0x0000CE5C, 0x0000CE7B, 0x00000003, 
+            0x0000CE3E, 0x0000CE33, 0x0000CE82, 0x0000CE87, 0x00000003, 0x0000CE76, 0x0000CE73, 0x0000CE81, 
+            0x00000003, 0x00000588, 0x0000CE65, 0x0000CE41, 0x0000CE22, 0x0000CE38, 0x0000CE78, 0x0000CE74, 
+            0x0000CE73, 0x00000003, 0x0000CE75, 0x0000CE22, 0x0000CE6B, 0x0000CE41, 0x0000FFFE, 0x0000CE8B, 
+            0x0000CE21, 0x00000003, 0x0000CE7D, 0x0000CE40, 0x0000CE7F, 0x00000003, 0x0000CE4E, 0x0000CE88, 
+            0x0000CE50, 0x0000CE3C, 0x0000CE2B, 0x0000CE81, 0x00000003, 0x0000CE42, 0x0000CE88, 0x0000CE68, 
+            0x0000CE4C, 0x0000CE2C, 0x0000CE74, 0x0000CE73, 0x00000003, 0x0000CE28, 0x0000CE78, 0x0000CE5C, 
+            0x0000CE7B, 0x0000FFFE, 0x0000CE8B, 0x0000CE21, 0x00000003, 0x0000CE29, 0x0000CE22, 0x0000CE20, 
+            0x0000CE77, 0x00000003, 0x0000CE6D, 0x0000CE22, 0x0000CE7C, 0x0000CE7F, 0x00000003, 0x0000CE79, 
+            0x0000CE22, 0x0000CE6F, 0x00000003, 0x00000588, 0x00000005, 0x0000CE3D, 0x0000CE82, 0x0000CE70, 
+            0x000005B5, 0x0000CE7B, 0x0000CE82, 0x0000CE87, 0x00000005, 0x00000003, 0x0000CE5D, 0x0000CE21, 
+            0x0000CE42, 0x0000CE2C, 0x0000CE3B, 0x0000CE21, 0x00000003, 0x0000CE72, 0x0000CE26, 0x0000CE6B, 
+            0x0000CE81, 0x00000003, 0x00000011, 0x0000CE22, 0x0000CE80, 0x0000CE7C, 0x0000CE77, 0x00000003, 
+            0x0000CE3E, 0x0000CE37, 0x0000CE21, 0x0000CE81, 0x00000003, 0x0000CE72, 0x0000CE70, 0x0000CE73, 
+            0x00000003, 0x0000CE22, 0x0000CE7C, 0x0000CE88, 0x0000CE60, 0x0000CE77, 0x00000003, 0x0000CE22, 
+            0x0000CE78, 0x0000CE6B, 0x0000CE41, 0x00000003, 0x0000CE86, 0x0000CE58, 0x0000CE60, 0x000005B4, 
+            0x0000CE2B, 0x00000003, 0x0000CE79, 0x0000CE17, 0x00000003, 0x0000CE3E, 0x0000CE60, 0x0000CE25, 
+            0x00000003, 0x0000CE83, 0x0000CE42, 0x0000CE3B, 0x0000FFFE, 0x0000CE8B, 0x0000CE21, 0x00000003, 
+            0x0000CE65, 0x0000CE41, 0x0000CE22, 0x0000CE38, 0x0000CE78, 0x0000CE73, 0x0000CE21, 0x0000CE81, 
+            0x00000003, 0x0000CE65, 0x0000CE42, 0x0000CE37, 0x0000FFFE, 0x0000CE8B, 0x0000CE21, 0x00000003, 
+            0x0000CE7A, 0x0000CE87, 0x0000CE44, 0x0000CE3C, 0x0000CE2C, 0x0000CE25, 0x00000003, 0x0000CE75, 
+            0x0000CE82, 0x0000CE6C, 0x0000CE2B, 0x0000CE81, 0x00000003, 0x00000588, 0x0000CE75, 0x0000CE22, 
+            0x0000CE6B, 0x0000CE41, 0x0000FFFE, 0x0000CE8B, 0x0000CE21, 0x00000003, 0x0000CE5E, 0x0000CE77, 
+            0x00000003, 0x0000CE56, 0x0000CE6C, 0x0000CE67, 0x00000003, 0x0000CE24, 0x0000CE88, 0x0000CE47, 
+            0x0000CE21, 0x0000CE82, 0x0000CE38, 0x0000CE73, 0x0000CE21, 0x00000003, 0x0000CE72, 0x0000CE77, 
+            0x0000CE22, 0x0000CE60, 0x0000CE2C, 0x0000CE2B, 0x00000003, 0x00000588, 0x0000CE22, 0x000005B0, 
+            0x0000CE47, 0x0000CE22, 0x0000CE47, 0x0000CE17
+        </result-glyphs>
+
+        <result-indices>
+            0x000000FB, 0x000000FA, 0x000000F9, 0x000000F8, 0x000000F7, 0x000000F6, 0x000000F5, 0x000000F4, 
+            0x000000F3, 0x000000F2, 0x000000F1, 0x000000F0, 0x000000EF, 0x000000EE, 0x000000ED, 0x000000EC, 
+            0x000000EB, 0x000000EA, 0x000000E9, 0x000000E8, 0x000000E7, 0x000000E6, 0x000000E5, 0x000000E4, 
+            0x000000E3, 0x000000E2, 0x000000E1, 0x000000E0, 0x000000DF, 0x000000DE, 0x000000DD, 0x000000DC, 
+            0x000000DB, 0x000000DA, 0x000000D9, 0x000000D8, 0x000000D7, 0x000000D6, 0x000000D5, 0x000000D4, 
+            0x000000D3, 0x000000D2, 0x000000D1, 0x000000D0, 0x000000CF, 0x000000CE, 0x000000CD, 0x000000CC, 
+            0x000000CB, 0x000000CA, 0x000000C9, 0x000000C8, 0x000000C7, 0x000000C6, 0x000000C5, 0x000000C4, 
+            0x000000C3, 0x000000C2, 0x000000C1, 0x000000C0, 0x000000BF, 0x000000BE, 0x000000BD, 0x000000BC, 
+            0x000000BB, 0x000000BA, 0x000000B9, 0x000000B8, 0x000000B7, 0x000000B6, 0x000000B5, 0x000000B4, 
+            0x000000B3, 0x000000B2, 0x000000B1, 0x000000B0, 0x000000AF, 0x000000AE, 0x000000AD, 0x000000AC, 
+            0x000000AB, 0x000000AA, 0x000000A9, 0x000000A8, 0x000000A7, 0x000000A6, 0x000000A5, 0x000000A4, 
+            0x000000A3, 0x000000A2, 0x000000A1, 0x000000A0, 0x0000009F, 0x0000009E, 0x0000009D, 0x0000009C, 
+            0x0000009B, 0x0000009A, 0x00000099, 0x00000098, 0x00000097, 0x00000096, 0x00000095, 0x00000094, 
+            0x00000093, 0x00000092, 0x00000091, 0x00000090, 0x0000008F, 0x0000008E, 0x0000008D, 0x0000008C, 
+            0x0000008B, 0x0000008A, 0x00000089, 0x00000088, 0x00000087, 0x00000086, 0x00000085, 0x00000084, 
+            0x00000083, 0x00000082, 0x00000081, 0x00000080, 0x0000007F, 0x0000007E, 0x0000007D, 0x0000007C, 
+            0x0000007B, 0x0000007A, 0x00000079, 0x00000078, 0x00000077, 0x00000076, 0x00000075, 0x00000074, 
+            0x00000073, 0x00000072, 0x00000071, 0x00000070, 0x0000006F, 0x0000006E, 0x0000006D, 0x0000006C, 
+            0x0000006B, 0x0000006A, 0x00000069, 0x00000068, 0x00000067, 0x00000066, 0x00000065, 0x00000064, 
+            0x00000063, 0x00000062, 0x00000061, 0x00000060, 0x0000005F, 0x0000005E, 0x0000005D, 0x0000005C, 
+            0x0000005B, 0x0000005A, 0x00000059, 0x00000058, 0x00000057, 0x00000056, 0x00000055, 0x00000054, 
+            0x00000053, 0x00000052, 0x00000051, 0x00000050, 0x0000004F, 0x0000004E, 0x0000004D, 0x0000004C, 
+            0x0000004B, 0x0000004A, 0x00000049, 0x00000048, 0x00000047, 0x00000046, 0x00000045, 0x00000044, 
+            0x00000043, 0x00000042, 0x00000041, 0x00000040, 0x0000003F, 0x0000003E, 0x0000003D, 0x0000003C, 
+            0x0000003B, 0x0000003A, 0x00000039, 0x00000038, 0x00000037, 0x00000036, 0x00000035, 0x00000034, 
+            0x00000033, 0x00000032, 0x00000031, 0x00000030, 0x0000002F, 0x0000002E, 0x0000002D, 0x0000002C, 
+            0x0000002B, 0x0000002A, 0x00000029, 0x00000028, 0x00000027, 0x00000026, 0x00000025, 0x00000024, 
+            0x00000023, 0x00000022, 0x00000021, 0x00000020, 0x0000001F, 0x0000001E, 0x0000001D, 0x0000001C, 
+            0x0000001B, 0x0000001A, 0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015, 0x00000014, 
+            0x00000013, 0x00000012, 0x00000011, 0x00000010, 0x0000000F, 0x0000000E, 0x0000000D, 0x0000000C, 
+            0x0000000B, 0x0000000A, 0x00000009, 0x00000008, 0x00000007, 0x00000006, 0x00000005, 0x00000004, 
+            0x00000003, 0x00000002, 0x00000001, 0x00000000
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 4.007812, 0.000000, 8.226562, 0.000000, 12.679688, 0.000000, 
+            18.679688, 0.000000, 23.132812, 0.000000, 31.289062, 0.000000, 34.312500, 0.000000, 
+            36.375000, 0.000000, 41.062500, 0.000000, 50.296875, 0.000000, 54.750000, 0.000000, 
+            56.859375, 0.000000, 62.367188, 0.000000, 66.632812, 0.000000, 69.656250, 0.000000, 
+            71.718750, 0.000000, 76.406250, 0.000000, 81.421875, 0.000000, 85.664062, 0.000000, 
+            89.929688, 0.000000, 95.742188, 0.000000, 100.429688, 0.000000, 108.796875, 0.000000, 
+            112.171875, 0.000000, 115.734375, 0.000000, 120.421875, 0.000000, 128.765625, 0.000000, 
+            134.765625, 0.000000, 139.007812, 0.000000, 144.515625, 0.000000, 148.734375, 0.000000, 
+            153.421875, 0.000000, 157.359375, 0.000000, 163.171875, 0.000000, 165.234375, 0.000000, 
+            171.234375, 0.000000, 175.921875, 0.000000, 180.375000, 0.000000, 184.617188, 0.000000, 
+            188.085938, 0.000000, 195.117188, 0.000000, 199.312500, 0.000000, 204.000000, 0.000000, 
+            208.007812, 0.000000, 210.117188, 0.000000, 217.054688, 0.000000, 220.429688, 0.000000, 
+            225.117188, 0.000000, 229.054688, 0.000000, 234.867188, 0.000000, 240.867188, 0.000000, 
+            245.085938, 0.000000, 249.773438, 0.000000, 253.781250, 0.000000, 256.804688, 0.000000, 
+            262.804688, 0.000000, 267.492188, 0.000000, 271.007812, 0.000000, 280.242188, 0.000000, 
+            284.695312, 0.000000, 286.804688, 0.000000, 292.312500, 0.000000, 296.578125, 0.000000, 
+            299.953125, 0.000000, 302.976562, 0.000000, 307.664062, 0.000000, 311.671875, 0.000000, 
+            313.781250, 0.000000, 317.882812, 0.000000, 322.335938, 0.000000, 322.335938, 0.000000, 
+            328.500000, 0.000000, 330.562500, 0.000000, 335.250000, 0.000000, 339.140625, 0.000000, 
+            343.078125, 0.000000, 348.984375, 0.000000, 353.671875, 0.000000, 366.445312, 0.000000, 
+            370.687500, 0.000000, 378.843750, 0.000000, 384.351562, 0.000000, 388.546875, 0.000000, 
+            394.546875, 0.000000, 399.234375, 0.000000, 403.687500, 0.000000, 407.929688, 0.000000, 
+            411.398438, 0.000000, 418.429688, 0.000000, 422.671875, 0.000000, 426.046875, 0.000000, 
+            429.070312, 0.000000, 433.757812, 0.000000, 437.765625, 0.000000, 442.031250, 0.000000, 
+            448.968750, 0.000000, 452.343750, 0.000000, 452.343750, 0.000000, 458.507812, 0.000000, 
+            460.570312, 0.000000, 465.257812, 0.000000, 474.492188, 0.000000, 476.601562, 0.000000, 
+            480.843750, 0.000000, 485.109375, 0.000000, 489.796875, 0.000000, 497.437500, 0.000000, 
+            499.546875, 0.000000, 503.765625, 0.000000, 509.671875, 0.000000, 514.359375, 0.000000, 
+            521.671875, 0.000000, 523.781250, 0.000000, 529.453125, 0.000000, 534.140625, 0.000000, 
+            537.656250, 0.000000, 543.046875, 0.000000, 546.585938, 0.000000, 552.585938, 0.000000, 
+            560.367188, 0.000000, 560.367188, 0.000000, 563.742188, 0.000000, 569.742188, 0.000000, 
+            573.960938, 0.000000, 579.351562, 0.000000, 584.039062, 0.000000, 589.851562, 0.000000, 
+            591.914062, 0.000000, 596.367188, 0.000000, 600.609375, 0.000000, 606.421875, 0.000000, 
+            608.484375, 0.000000, 613.171875, 0.000000, 619.570312, 0.000000, 623.812500, 0.000000, 
+            627.914062, 0.000000, 633.914062, 0.000000, 638.601562, 0.000000, 641.929688, 0.000000, 
+            644.039062, 0.000000, 647.789062, 0.000000, 652.007812, 0.000000, 656.273438, 0.000000, 
+            660.960938, 0.000000, 664.898438, 0.000000, 670.710938, 0.000000, 672.773438, 0.000000, 
+            678.773438, 0.000000, 683.460938, 0.000000, 689.859375, 0.000000, 697.640625, 0.000000, 
+            700.664062, 0.000000, 705.351562, 0.000000, 707.460938, 0.000000, 711.679688, 0.000000, 
+            715.921875, 0.000000, 719.390625, 0.000000, 723.656250, 0.000000, 728.343750, 0.000000, 
+            730.453125, 0.000000, 734.718750, 0.000000, 738.820312, 0.000000, 743.273438, 0.000000, 
+            747.960938, 0.000000, 756.328125, 0.000000, 763.265625, 0.000000, 766.734375, 0.000000, 
+            766.734375, 0.000000, 770.929688, 0.000000, 775.617188, 0.000000, 782.929688, 0.000000, 
+            785.273438, 0.000000, 789.960938, 0.000000, 793.898438, 0.000000, 797.367188, 0.000000, 
+            800.812500, 0.000000, 805.500000, 0.000000, 813.843750, 0.000000, 818.296875, 0.000000, 
+            824.109375, 0.000000, 824.109375, 0.000000, 830.273438, 0.000000, 832.335938, 0.000000, 
+            837.023438, 0.000000, 846.257812, 0.000000, 850.710938, 0.000000, 852.820312, 0.000000, 
+            858.328125, 0.000000, 862.593750, 0.000000, 865.617188, 0.000000, 867.679688, 0.000000, 
+            873.679688, 0.000000, 878.367188, 0.000000, 887.601562, 0.000000, 892.054688, 0.000000, 
+            897.867188, 0.000000, 897.867188, 0.000000, 904.031250, 0.000000, 906.093750, 0.000000, 
+            910.781250, 0.000000, 918.257812, 0.000000, 922.476562, 0.000000, 926.929688, 0.000000, 
+            932.437500, 0.000000, 936.679688, 0.000000, 940.125000, 0.000000, 944.812500, 0.000000, 
+            948.820312, 0.000000, 954.820312, 0.000000, 958.289062, 0.000000, 962.484375, 0.000000, 
+            968.484375, 0.000000, 973.171875, 0.000000, 976.687500, 0.000000, 980.695312, 0.000000, 
+            982.804688, 0.000000, 986.906250, 0.000000, 991.359375, 0.000000, 991.359375, 0.000000, 
+            997.523438, 0.000000, 999.585938, 0.000000, 1004.273438, 0.000000, 1009.289062, 0.000000, 
+            1013.554688, 0.000000, 1018.242188, 0.000000, 1026.187500, 0.000000, 1029.656250, 0.000000, 
+            1033.757812, 0.000000, 1038.445312, 0.000000, 1047.796875, 0.000000, 1052.039062, 0.000000, 
+            1058.859375, 0.000000, 1060.921875, 0.000000, 1066.921875, 0.000000, 1072.429688, 0.000000, 
+            1075.453125, 0.000000, 1077.515625, 0.000000, 1082.203125, 0.000000, 1088.601562, 0.000000, 
+            1092.867188, 0.000000, 1094.976562, 0.000000, 1098.445312, 0.000000, 1102.687500, 0.000000, 
+            1106.882812, 0.000000, 1111.570312, 0.000000, 1115.085938, 0.000000, 1117.195312, 0.000000, 
+            1117.195312, 0.000000, 1124.015625, 0.000000, 1126.125000, 0.000000, 1132.945312, 0.000000, 
+            1135.289062, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Unicode Arabic" script="arab">
+        <test-font name="LucidaSansRegular.ttf" version="Version 1.20 - October 2000" checksum="0xF5D9BA6D" rchecksum="0x029B644F"/>
+
+        <test-text>أساسًا، تتعامل الحواسيب فقط مع الأرقام، وتقوم بتخزين الأحرف والمحارف الأخرى بعد أن تُعطي رقما معينا لكل واحد منها. وقبل اختراع "يونِكود"، كان هناك مئات الأنظمة للتشفير وتخصيص هذه الأرقام للمحارف، ولم يوجد نظام تشفير واحد يحتوي على جميع المحارف الضرورية</test-text>
+
+        <result-glyphs>
+            0x00000872, 0x000008D1, 0x000003F9, 0x0000040B, 0x0000088C, 0x0000089E, 0x000008BD, 0x000003EF, 
+            0x00000003, 0x00000404, 0x000003F9, 0x0000086C, 0x00000882, 0x000008C2, 0x000008BD, 0x000003EF, 
+            0x00000003, 0x000008A8, 0x000008D2, 0x000008C2, 0x0000087D, 0x00000003, 0x000008CE, 0x000008BE, 
+            0x000008A9, 0x00000003, 0x0000040D, 0x000008CC, 0x00000876, 0x00000882, 0x000008D1, 0x00000003, 
+            0x00000888, 0x00000881, 0x000003EF, 0x0000040B, 0x00000003, 0x0000088C, 0x000008D2, 0x000008B2, 
+            0x00000896, 0x00000875, 0x00000003, 0x00000408, 0x0000086C, 0x000008A6, 0x000008C5, 0x00000003, 
+            0x00000888, 0x0000087D, 0x000008CC, 0x000008D1, 0x00000003, 0x000008C0, 0x000008BD, 0x0000040B, 
+            0x00000003, 0x000003E6, 0x00000404, 0x000003F9, 0x0000086C, 0x00000882, 0x000008C2, 0x000008BE, 
+            0x000008BD, 0x00000003, 0x00000408, 0x0000086C, 0x000008B5, 0x000003F9, 0x0000FFFF, 0x000008D5, 
+            0x000003EF, 0x00000003, 0x0000040A, 0x0000088A, 0x000008C9, 0x00000003, 0x00000898, 0x000008D2, 
+            0x0000089A, 0x00000886, 0x00000875, 0x0000040B, 0x00000003, 0x0000088C, 0x000008D2, 0x000008B2, 
+            0x00000896, 0x00000876, 0x000008BE, 0x000008BD, 0x00000003, 0x00000872, 0x000008C2, 0x000008A6, 
+            0x000008C5, 0x0000FFFF, 0x000008D5, 0x000003EF, 0x00000003, 0x000003F2, 0x0000086C, 0x0000086A, 
+            0x000008C1, 0x00000003, 0x00000406, 0x0000086C, 0x000008C6, 0x000008C9, 0x00000003, 0x00000409, 
+            0x0000086C, 0x000008B9, 0x00000003, 0x000003E6, 0x00000005, 0x000003F7, 0x000008CC, 0x000008BA, 
+            0x00000413, 0x000008C5, 0x000008CC, 0x000008D1, 0x00000005, 0x00000003, 0x00000401, 0x000003EF, 
+            0x0000088C, 0x00000876, 0x00000885, 0x000003EF, 0x00000003, 0x000008BC, 0x00000870, 0x000008B5, 
+            0x0000040B, 0x00000003, 0x00000011, 0x0000086C, 0x000008CA, 0x000008C6, 0x000008C1, 0x00000003, 
+            0x00000888, 0x00000881, 0x000003EF, 0x0000040B, 0x00000003, 0x000008BC, 0x000008BA, 0x000008BD, 
+            0x00000003, 0x0000086C, 0x000008C6, 0x000008D2, 0x000008AA, 0x000008C1, 0x00000003, 0x0000086C, 
+            0x000008C2, 0x000008B5, 0x000003F9, 0x00000003, 0x000008D0, 0x000008A2, 0x000008AA, 0x00000412, 
+            0x00000875, 0x00000003, 0x00000409, 0x000003EB, 0x00000003, 0x00000888, 0x000008AA, 0x0000086F, 
+            0x00000003, 0x0000040C, 0x0000088C, 0x00000885, 0x0000FFFF, 0x000008D5, 0x000003EF, 0x00000003, 
+            0x00000404, 0x000003F9, 0x0000086C, 0x00000882, 0x000008C2, 0x000008BD, 0x000003EF, 0x0000040B, 
+            0x00000003, 0x00000404, 0x0000088C, 0x00000881, 0x0000FFFF, 0x000008D5, 0x000003EF, 0x00000003, 
+            0x000008C4, 0x000008D1, 0x0000088E, 0x00000886, 0x00000876, 0x0000086F, 0x00000003, 0x00000408, 
+            0x000008CC, 0x000008B6, 0x00000875, 0x0000040B, 0x00000003, 0x000003E6, 0x00000408, 0x0000086C, 
+            0x000008B5, 0x000003F9, 0x0000FFFF, 0x000008D5, 0x000003EF, 0x00000003, 0x000008A8, 0x000008C1, 
+            0x00000003, 0x000008A0, 0x000008B6, 0x000008B1, 0x00000003, 0x0000086E, 0x000008D2, 0x00000891, 
+            0x000003EF, 0x000008CC, 0x00000882, 0x000008BD, 0x000003EF, 0x00000003, 0x000008BC, 0x000008C1, 
+            0x0000086C, 0x000008AA, 0x00000876, 0x00000875, 0x00000003, 0x000003E6, 0x0000086C, 0x0000040E, 
+            0x00000891, 0x0000086C, 0x00000891, 0x000003EB
+        </result-glyphs>
+
+        <result-indices>
+            0x000000FB, 0x000000FA, 0x000000F9, 0x000000F8, 0x000000F7, 0x000000F6, 0x000000F5, 0x000000F4, 
+            0x000000F3, 0x000000F2, 0x000000F1, 0x000000F0, 0x000000EF, 0x000000EE, 0x000000ED, 0x000000EC, 
+            0x000000EB, 0x000000EA, 0x000000E9, 0x000000E8, 0x000000E7, 0x000000E6, 0x000000E5, 0x000000E4, 
+            0x000000E3, 0x000000E2, 0x000000E1, 0x000000E0, 0x000000DF, 0x000000DE, 0x000000DD, 0x000000DC, 
+            0x000000DB, 0x000000DA, 0x000000D9, 0x000000D8, 0x000000D7, 0x000000D6, 0x000000D5, 0x000000D4, 
+            0x000000D3, 0x000000D2, 0x000000D1, 0x000000D0, 0x000000CF, 0x000000CE, 0x000000CD, 0x000000CC, 
+            0x000000CB, 0x000000CA, 0x000000C9, 0x000000C8, 0x000000C7, 0x000000C6, 0x000000C5, 0x000000C4, 
+            0x000000C3, 0x000000C2, 0x000000C1, 0x000000C0, 0x000000BF, 0x000000BE, 0x000000BD, 0x000000BC, 
+            0x000000BB, 0x000000BA, 0x000000B9, 0x000000B8, 0x000000B7, 0x000000B6, 0x000000B5, 0x000000B4, 
+            0x000000B3, 0x000000B2, 0x000000B1, 0x000000B0, 0x000000AF, 0x000000AE, 0x000000AD, 0x000000AC, 
+            0x000000AB, 0x000000AA, 0x000000A9, 0x000000A8, 0x000000A7, 0x000000A6, 0x000000A5, 0x000000A4, 
+            0x000000A3, 0x000000A2, 0x000000A1, 0x000000A0, 0x0000009F, 0x0000009E, 0x0000009D, 0x0000009C, 
+            0x0000009B, 0x0000009A, 0x00000099, 0x00000098, 0x00000097, 0x00000096, 0x00000095, 0x00000094, 
+            0x00000093, 0x00000092, 0x00000091, 0x00000090, 0x0000008F, 0x0000008E, 0x0000008D, 0x0000008C, 
+            0x0000008B, 0x0000008A, 0x00000089, 0x00000088, 0x00000087, 0x00000086, 0x00000085, 0x00000084, 
+            0x00000083, 0x00000082, 0x00000081, 0x00000080, 0x0000007F, 0x0000007E, 0x0000007D, 0x0000007C, 
+            0x0000007B, 0x0000007A, 0x00000079, 0x00000078, 0x00000077, 0x00000076, 0x00000075, 0x00000074, 
+            0x00000073, 0x00000072, 0x00000071, 0x00000070, 0x0000006F, 0x0000006E, 0x0000006D, 0x0000006C, 
+            0x0000006B, 0x0000006A, 0x00000069, 0x00000068, 0x00000067, 0x00000066, 0x00000065, 0x00000064, 
+            0x00000063, 0x00000062, 0x00000061, 0x00000060, 0x0000005F, 0x0000005E, 0x0000005D, 0x0000005C, 
+            0x0000005B, 0x0000005A, 0x00000059, 0x00000058, 0x00000057, 0x00000056, 0x00000055, 0x00000054, 
+            0x00000053, 0x00000052, 0x00000051, 0x00000050, 0x0000004F, 0x0000004E, 0x0000004D, 0x0000004C, 
+            0x0000004B, 0x0000004A, 0x00000049, 0x00000048, 0x00000047, 0x00000046, 0x00000045, 0x00000044, 
+            0x00000043, 0x00000042, 0x00000041, 0x00000040, 0x0000003F, 0x0000003E, 0x0000003D, 0x0000003C, 
+            0x0000003B, 0x0000003A, 0x00000039, 0x00000038, 0x00000037, 0x00000036, 0x00000035, 0x00000034, 
+            0x00000033, 0x00000032, 0x00000031, 0x00000030, 0x0000002F, 0x0000002E, 0x0000002D, 0x0000002C, 
+            0x0000002B, 0x0000002A, 0x00000029, 0x00000028, 0x00000027, 0x00000026, 0x00000025, 0x00000024, 
+            0x00000023, 0x00000022, 0x00000021, 0x00000020, 0x0000001F, 0x0000001E, 0x0000001D, 0x0000001C, 
+            0x0000001B, 0x0000001A, 0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015, 0x00000014, 
+            0x00000013, 0x00000012, 0x00000011, 0x00000010, 0x0000000F, 0x0000000E, 0x0000000D, 0x0000000C, 
+            0x0000000B, 0x0000000A, 0x00000009, 0x00000008, 0x00000007, 0x00000006, 0x00000005, 0x00000004, 
+            0x00000003, 0x00000002, 0x00000001, 0x00000000
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 6.316406, 0.000000, 10.382812, 0.000000, 15.492188, 0.000000, 
+            21.035156, 0.000000, 27.058594, 0.000000, 39.527344, 0.000000, 43.792969, 0.000000, 
+            47.408203, 0.000000, 51.205078, 0.000000, 66.216797, 0.000000, 71.326172, 0.000000, 
+            74.695312, 0.000000, 83.367188, 0.000000, 90.826172, 0.000000, 95.091797, 0.000000, 
+            98.707031, 0.000000, 102.503906, 0.000000, 109.962891, 0.000000, 114.949219, 0.000000, 
+            122.408203, 0.000000, 130.687500, 0.000000, 134.484375, 0.000000, 145.787109, 0.000000, 
+            150.773438, 0.000000, 156.884766, 0.000000, 160.681641, 0.000000, 172.277344, 0.000000, 
+            177.919922, 0.000000, 182.906250, 0.000000, 191.578125, 0.000000, 195.644531, 0.000000, 
+            199.441406, 0.000000, 206.507812, 0.000000, 214.787109, 0.000000, 218.402344, 0.000000, 
+            223.945312, 0.000000, 227.742188, 0.000000, 233.765625, 0.000000, 238.751953, 0.000000, 
+            245.185547, 0.000000, 257.982422, 0.000000, 262.048828, 0.000000, 265.845703, 0.000000, 
+            272.654297, 0.000000, 276.023438, 0.000000, 285.240234, 0.000000, 289.306641, 0.000000, 
+            293.103516, 0.000000, 300.169922, 0.000000, 308.449219, 0.000000, 314.091797, 0.000000, 
+            318.158203, 0.000000, 321.955078, 0.000000, 329.572266, 0.000000, 333.837891, 0.000000, 
+            339.380859, 0.000000, 343.177734, 0.000000, 346.974609, 0.000000, 361.986328, 0.000000, 
+            367.095703, 0.000000, 370.464844, 0.000000, 379.136719, 0.000000, 386.595703, 0.000000, 
+            391.582031, 0.000000, 395.847656, 0.000000, 399.644531, 0.000000, 406.453125, 0.000000, 
+            409.822266, 0.000000, 415.523438, 0.000000, 420.632812, 0.000000, 420.632812, 0.000000, 
+            427.441406, 0.000000, 431.056641, 0.000000, 434.853516, 0.000000, 441.357422, 0.000000, 
+            448.423828, 0.000000, 455.912109, 0.000000, 459.708984, 0.000000, 479.255859, 0.000000, 
+            484.242188, 0.000000, 496.710938, 0.000000, 505.382812, 0.000000, 509.449219, 0.000000, 
+            514.992188, 0.000000, 518.789062, 0.000000, 524.812500, 0.000000, 529.798828, 0.000000, 
+            536.232422, 0.000000, 549.029297, 0.000000, 554.015625, 0.000000, 559.001953, 0.000000, 
+            563.267578, 0.000000, 567.064453, 0.000000, 573.380859, 0.000000, 580.839844, 0.000000, 
+            590.056641, 0.000000, 594.123047, 0.000000, 594.123047, 0.000000, 600.931641, 0.000000, 
+            604.546875, 0.000000, 608.343750, 0.000000, 620.636719, 0.000000, 624.005859, 0.000000, 
+            628.992188, 0.000000, 635.830078, 0.000000, 639.626953, 0.000000, 653.361328, 0.000000, 
+            656.730469, 0.000000, 661.716797, 0.000000, 669.205078, 0.000000, 673.001953, 0.000000, 
+            683.777344, 0.000000, 687.146484, 0.000000, 692.660156, 0.000000, 696.457031, 0.000000, 
+            700.253906, 0.000000, 704.736328, 0.000000, 711.105469, 0.000000, 716.748047, 0.000000, 
+            722.994141, 0.000000, 722.994141, 0.000000, 727.060547, 0.000000, 732.703125, 0.000000, 
+            736.769531, 0.000000, 741.251953, 0.000000, 745.048828, 0.000000, 752.507812, 0.000000, 
+            756.123047, 0.000000, 762.146484, 0.000000, 767.132812, 0.000000, 775.412109, 0.000000, 
+            779.027344, 0.000000, 782.824219, 0.000000, 794.203125, 0.000000, 799.189453, 0.000000, 
+            804.890625, 0.000000, 810.433594, 0.000000, 814.230469, 0.000000, 818.027344, 0.000000, 
+            821.396484, 0.000000, 828.128906, 0.000000, 833.115234, 0.000000, 839.953125, 0.000000, 
+            843.750000, 0.000000, 850.816406, 0.000000, 859.095703, 0.000000, 862.710938, 0.000000, 
+            868.253906, 0.000000, 872.050781, 0.000000, 883.429688, 0.000000, 889.675781, 0.000000, 
+            893.941406, 0.000000, 897.738281, 0.000000, 901.107422, 0.000000, 906.093750, 0.000000, 
+            911.080078, 0.000000, 917.800781, 0.000000, 924.638672, 0.000000, 928.435547, 0.000000, 
+            931.804688, 0.000000, 939.263672, 0.000000, 944.964844, 0.000000, 950.074219, 0.000000, 
+            953.871094, 0.000000, 965.173828, 0.000000, 974.390625, 0.000000, 981.111328, 0.000000, 
+            981.111328, 0.000000, 985.177734, 0.000000, 988.974609, 0.000000, 999.750000, 0.000000, 
+            1003.365234, 0.000000, 1007.162109, 0.000000, 1014.228516, 0.000000, 1020.949219, 0.000000, 
+            1025.015625, 0.000000, 1028.812500, 0.000000, 1040.408203, 0.000000, 1046.431641, 0.000000, 
+            1054.710938, 0.000000, 1054.710938, 0.000000, 1061.519531, 0.000000, 1065.134766, 0.000000, 
+            1068.931641, 0.000000, 1083.943359, 0.000000, 1089.052734, 0.000000, 1092.421875, 0.000000, 
+            1101.093750, 0.000000, 1108.552734, 0.000000, 1112.818359, 0.000000, 1116.433594, 0.000000, 
+            1121.976562, 0.000000, 1125.773438, 0.000000, 1140.785156, 0.000000, 1146.808594, 0.000000, 
+            1155.087891, 0.000000, 1155.087891, 0.000000, 1161.896484, 0.000000, 1165.511719, 0.000000, 
+            1169.308594, 0.000000, 1180.541016, 0.000000, 1184.607422, 0.000000, 1190.630859, 0.000000, 
+            1199.302734, 0.000000, 1204.289062, 0.000000, 1208.355469, 0.000000, 1212.152344, 0.000000, 
+            1218.960938, 0.000000, 1224.603516, 0.000000, 1231.037109, 0.000000, 1235.103516, 0.000000, 
+            1240.646484, 0.000000, 1244.443359, 0.000000, 1248.240234, 0.000000, 1255.048828, 0.000000, 
+            1258.417969, 0.000000, 1264.119141, 0.000000, 1269.228516, 0.000000, 1269.228516, 0.000000, 
+            1276.037109, 0.000000, 1279.652344, 0.000000, 1283.449219, 0.000000, 1290.908203, 0.000000, 
+            1297.746094, 0.000000, 1301.542969, 0.000000, 1311.427734, 0.000000, 1317.861328, 0.000000, 
+            1323.562500, 0.000000, 1327.359375, 0.000000, 1341.492188, 0.000000, 1346.478516, 0.000000, 
+            1357.904297, 0.000000, 1361.519531, 0.000000, 1367.162109, 0.000000, 1375.833984, 0.000000, 
+            1380.099609, 0.000000, 1383.714844, 0.000000, 1387.511719, 0.000000, 1398.890625, 0.000000, 
+            1405.728516, 0.000000, 1409.097656, 0.000000, 1415.818359, 0.000000, 1420.804688, 0.000000, 
+            1424.871094, 0.000000, 1428.667969, 0.000000, 1432.464844, 0.000000, 1435.833984, 0.000000, 
+            1435.833984, 0.000000, 1447.259766, 0.000000, 1450.628906, 0.000000, 1462.054688, 0.000000, 
+            1465.669922, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Thai" script="thai">
+        <test-font name="angsd___.ttf" version="Version 2.1 - July 1995" checksum="0x49B67200" rchecksum="0x003C2EE9"/>
+
+        <test-text>บทที่๑พายุไซโคลนโดโรธีอาศัยอยู่ท่ามกลางทุ่งใหญ่ในแคนซัสกับลุงเฮนรีชาวไร่และป้าเอ็มภรรยาชาวไร่บ้านของพวกเขาหลังเล็กเพราะไม้สร้างบ้านต้องขนมาด้วยเกวียนเป็นระยะทางหลายไมล์</test-text>
+
+        <result-glyphs>
+            0x000000F3, 0x000000F0, 0x000000F0, 0x0000010E, 0x0000011D, 0x00000126, 0x000000F7, 0x0000010B, 
+            0x000000FB, 0x00000111, 0x00000119, 0x000000E4, 0x00000117, 0x000000DD, 0x000000FE, 0x000000F2, 
+            0x00000117, 0x000000ED, 0x00000117, 0x000000FC, 0x000000F1, 0x0000010E, 0x00000106, 0x0000010B, 
+            0x00000101, 0x0000010A, 0x000000FB, 0x00000106, 0x000000FB, 0x00000112, 0x0000013B, 0x000000F0, 
+            0x0000013B, 0x0000010B, 0x000000FA, 0x000000DA, 0x000000FE, 0x0000010B, 0x000000E0, 0x000000F0, 
+            0x00000111, 0x0000013B, 0x000000E0, 0x00000118, 0x00000104, 0x000000E6, 0x0000013B, 0x00000118, 
+            0x000000F2, 0x00000116, 0x000000DD, 0x000000F2, 0x000000E4, 0x0000010A, 0x00000103, 0x000000DA, 
+            0x0000010A, 0x000000F3, 0x000000FE, 0x00000111, 0x000000E0, 0x00000115, 0x00000107, 0x000000F2, 
+            0x000000FC, 0x0000010E, 0x000000E3, 0x0000010B, 0x00000100, 0x00000119, 0x000000FC, 0x0000013B, 
+            0x00000116, 0x000000FE, 0x00000109, 0x000000F4, 0x00000137, 0x0000010B, 0x00000115, 0x00000106, 
+            0x0000011C, 0x000000FA, 0x000000F9, 0x000000FC, 0x000000FC, 0x000000FB, 0x0000010B, 0x000000E3, 
+            0x0000010B, 0x00000100, 0x00000119, 0x000000FC, 0x0000013B, 0x000000F3, 0x0000013C, 0x0000010B, 
+            0x000000F2, 0x000000DB, 0x00000106, 0x000000E0, 0x000000F7, 0x00000100, 0x000000DA, 0x00000115, 
+            0x000000DB, 0x0000010B, 0x00000104, 0x000000FE, 0x0000010A, 0x000000E0, 0x00000115, 0x000000FE, 
+            0x0000011C, 0x000000DA, 0x00000115, 0x000000F7, 0x000000FC, 0x0000010B, 0x00000109, 0x00000119, 
+            0x000000FA, 0x0000013C, 0x00000103, 0x000000FC, 0x0000013C, 0x0000010B, 0x000000E0, 0x000000F3, 
+            0x0000013C, 0x0000010B, 0x000000F2, 0x000000EE, 0x0000013C, 0x00000106, 0x000000E0, 0x000000DB, 
+            0x000000F2, 0x000000FA, 0x0000010B, 0x000000ED, 0x0000013C, 0x00000100, 0x000000FB, 0x00000115, 
+            0x000000DA, 0x00000100, 0x0000010E, 0x000000FB, 0x000000F2, 0x00000115, 0x000000F4, 0x00000143, 
+            0x000000F2, 0x000000FC, 0x00000109, 0x000000FB, 0x00000109, 0x000000F0, 0x0000010B, 0x000000E0, 
+            0x00000104, 0x000000FE, 0x0000010B, 0x000000FB, 0x00000119, 0x000000FA, 0x000000FE, 0x0000013F
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F, 
+            0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017, 
+            0x00000018, 0x00000019, 0x0000001A, 0x0000001B, 0x0000001C, 0x0000001D, 0x0000001E, 0x0000001F, 
+            0x00000020, 0x00000021, 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x00000026, 0x00000027, 
+            0x00000028, 0x00000029, 0x0000002A, 0x0000002B, 0x0000002C, 0x0000002D, 0x0000002E, 0x0000002F, 
+            0x00000030, 0x00000031, 0x00000032, 0x00000033, 0x00000034, 0x00000035, 0x00000036, 0x00000037, 
+            0x00000038, 0x00000039, 0x0000003A, 0x0000003B, 0x0000003C, 0x0000003D, 0x0000003E, 0x0000003F, 
+            0x00000040, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 
+            0x00000048, 0x00000049, 0x0000004A, 0x0000004B, 0x0000004C, 0x0000004D, 0x0000004E, 0x0000004F, 
+            0x00000050, 0x00000051, 0x00000052, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 
+            0x00000058, 0x00000059, 0x0000005A, 0x0000005B, 0x0000005C, 0x0000005D, 0x0000005E, 0x0000005F, 
+            0x00000060, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 
+            0x00000068, 0x00000069, 0x0000006A, 0x0000006B, 0x0000006C, 0x0000006D, 0x0000006E, 0x0000006F, 
+            0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 
+            0x00000078, 0x00000079, 0x0000007A, 0x0000007B, 0x0000007C, 0x0000007D, 0x0000007E, 0x0000007F, 
+            0x00000080, 0x00000081, 0x00000082, 0x00000083, 0x00000084, 0x00000085, 0x00000086, 0x00000087, 
+            0x00000088, 0x00000089, 0x0000008A, 0x0000008B, 0x0000008C, 0x0000008D, 0x0000008E, 0x0000008F, 
+            0x00000090, 0x00000091, 0x00000092, 0x00000093, 0x00000094, 0x00000095, 0x00000096, 0x00000097, 
+            0x00000098, 0x00000099, 0x0000009A, 0x0000009B, 0x0000009C, 0x0000009D, 0x0000009E, 0x0000009F, 
+            0x000000A0, 0x000000A1, 0x000000A2, 0x000000A3, 0x000000A4, 0x000000A5, 0x000000A6, 0x000000A7
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 5.399414, 0.000000, 10.798828, 0.000000, 16.198242, 0.000000, 
+            16.198242, 0.000000, 16.198242, 0.000000, 21.046875, 0.000000, 26.616211, 0.000000, 
+            30.035156, 0.000000, 34.151367, 0.000000, 34.151367, 0.000000, 38.279297, 0.000000, 
+            43.558594, 0.000000, 47.663086, 0.000000, 52.438477, 0.000000, 57.178711, 0.000000, 
+            62.698242, 0.000000, 66.802734, 0.000000, 71.601562, 0.000000, 75.706055, 0.000000, 
+            79.810547, 0.000000, 84.369141, 0.000000, 84.369141, 0.000000, 89.097656, 0.000000, 
+            92.516602, 0.000000, 97.195312, 0.000000, 97.195312, 0.000000, 101.311523, 0.000000, 
+            106.040039, 0.000000, 110.156250, 0.000000, 110.156250, 0.000000, 110.156250, 0.000000, 
+            115.555664, 0.000000, 115.555664, 0.000000, 118.974609, 0.000000, 124.013672, 0.000000, 
+            128.765625, 0.000000, 133.505859, 0.000000, 136.924805, 0.000000, 140.704102, 0.000000, 
+            146.103516, 0.000000, 146.103516, 0.000000, 146.103516, 0.000000, 149.882812, 0.000000, 
+            153.553711, 0.000000, 159.158203, 0.000000, 165.421875, 0.000000, 165.421875, 0.000000, 
+            169.092773, 0.000000, 174.612305, 0.000000, 179.135742, 0.000000, 183.911133, 0.000000, 
+            189.430664, 0.000000, 194.709961, 0.000000, 194.709961, 0.000000, 199.989258, 0.000000, 
+            204.741211, 0.000000, 204.741211, 0.000000, 210.140625, 0.000000, 214.880859, 0.000000, 
+            214.880859, 0.000000, 218.660156, 0.000000, 220.675781, 0.000000, 225.128906, 0.000000, 
+            230.648438, 0.000000, 234.752930, 0.000000, 234.752930, 0.000000, 239.613281, 0.000000, 
+            243.032227, 0.000000, 247.280273, 0.000000, 251.408203, 0.000000, 255.512695, 0.000000, 
+            255.512695, 0.000000, 260.036133, 0.000000, 264.776367, 0.000000, 269.071289, 0.000000, 
+            274.470703, 0.000000, 274.470703, 0.000000, 277.889648, 0.000000, 279.905273, 0.000000, 
+            284.633789, 0.000000, 284.633789, 0.000000, 289.672852, 0.000000, 294.641602, 0.000000, 
+            298.746094, 0.000000, 302.850586, 0.000000, 306.966797, 0.000000, 310.385742, 0.000000, 
+            315.246094, 0.000000, 318.665039, 0.000000, 322.913086, 0.000000, 327.041016, 0.000000, 
+            331.145508, 0.000000, 331.145508, 0.000000, 336.544922, 0.000000, 336.544922, 0.000000, 
+            339.963867, 0.000000, 345.483398, 0.000000, 350.258789, 0.000000, 354.987305, 0.000000, 
+            358.766602, 0.000000, 364.335938, 0.000000, 368.583984, 0.000000, 373.335938, 0.000000, 
+            375.351562, 0.000000, 380.126953, 0.000000, 383.545898, 0.000000, 389.150391, 0.000000, 
+            393.890625, 0.000000, 393.890625, 0.000000, 397.669922, 0.000000, 399.685547, 0.000000, 
+            404.425781, 0.000000, 404.425781, 0.000000, 409.177734, 0.000000, 411.193359, 0.000000, 
+            416.762695, 0.000000, 420.867188, 0.000000, 424.286133, 0.000000, 428.581055, 0.000000, 
+            432.708984, 0.000000, 437.748047, 0.000000, 437.748047, 0.000000, 443.027344, 0.000000, 
+            447.131836, 0.000000, 447.131836, 0.000000, 450.550781, 0.000000, 454.330078, 0.000000, 
+            459.729492, 0.000000, 459.729492, 0.000000, 463.148438, 0.000000, 468.667969, 0.000000, 
+            473.478516, 0.000000, 473.478516, 0.000000, 478.207031, 0.000000, 481.986328, 0.000000, 
+            486.761719, 0.000000, 492.281250, 0.000000, 497.320312, 0.000000, 500.739258, 0.000000, 
+            505.538086, 0.000000, 505.538086, 0.000000, 509.786133, 0.000000, 513.902344, 0.000000, 
+            515.917969, 0.000000, 520.669922, 0.000000, 524.917969, 0.000000, 524.917969, 0.000000, 
+            529.034180, 0.000000, 534.553711, 0.000000, 536.569336, 0.000000, 541.968750, 0.000000, 
+            541.968750, 0.000000, 547.488281, 0.000000, 551.592773, 0.000000, 555.887695, 0.000000, 
+            560.003906, 0.000000, 564.298828, 0.000000, 569.698242, 0.000000, 573.117188, 0.000000, 
+            576.896484, 0.000000, 582.500977, 0.000000, 587.241211, 0.000000, 590.660156, 0.000000, 
+            594.776367, 0.000000, 598.904297, 0.000000, 603.943359, 0.000000, 608.683594, 0.000000, 
+            608.683594, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Arabic Simple" script="arab">
+        <test-font name="LucidaSansRegular.ttf" version="Version 1.20 - October 2000" checksum="0xF5D9BA6D" rchecksum="0x029B644F"/>
+
+        <test-text>أساسًا، تتعامل الحواسيب فقط مع الأرقام، وتقوم بتخزين الأحرف والمحارف الأخرى بعد أن تُعطي رقما معينا لكل واحد منها. وقبل اختراع "يونِكود"، كان هناك مئات الأنظمة للتشفير وتخصيص هذه الأرقام للمحارف، ولم يوجد نظام تشفير واحد يحتوي على جميع المحارف الضرورية</test-text>
+
+        <result-glyphs>
+            0x00000872, 0x000008D1, 0x000003F9, 0x0000040B, 0x0000088C, 0x0000089E, 0x000008BD, 0x000003EF, 
+            0x00000003, 0x00000404, 0x000003F9, 0x0000086C, 0x00000882, 0x000008C2, 0x000008BD, 0x000003EF, 
+            0x00000003, 0x000008A8, 0x000008D2, 0x000008C2, 0x0000087D, 0x00000003, 0x000008CE, 0x000008BE, 
+            0x000008A9, 0x00000003, 0x0000040D, 0x000008CC, 0x00000876, 0x00000882, 0x000008D1, 0x00000003, 
+            0x00000888, 0x00000881, 0x000003EF, 0x0000040B, 0x00000003, 0x0000088C, 0x000008D2, 0x000008B2, 
+            0x00000896, 0x00000875, 0x00000003, 0x00000408, 0x0000086C, 0x000008A6, 0x000008C5, 0x00000003, 
+            0x00000888, 0x0000087D, 0x000008CC, 0x000008D1, 0x00000003, 0x000008C0, 0x000008BD, 0x0000040B, 
+            0x00000003, 0x000003E6, 0x00000404, 0x000003F9, 0x0000086C, 0x00000882, 0x000008C2, 0x000008BE, 
+            0x000008BD, 0x00000003, 0x00000408, 0x0000086C, 0x000008B5, 0x000003F9, 0x0000FFFF, 0x000008D5, 
+            0x000003EF, 0x00000003, 0x0000040A, 0x0000088A, 0x000008C9, 0x00000003, 0x00000898, 0x000008D2, 
+            0x0000089A, 0x00000886, 0x00000875, 0x0000040B, 0x00000003, 0x0000088C, 0x000008D2, 0x000008B2, 
+            0x00000896, 0x00000876, 0x000008BE, 0x000008BD, 0x00000003, 0x00000872, 0x000008C2, 0x000008A6, 
+            0x000008C5, 0x0000FFFF, 0x000008D5, 0x000003EF, 0x00000003, 0x000003F2, 0x0000086C, 0x0000086A, 
+            0x000008C1, 0x00000003, 0x00000406, 0x0000086C, 0x000008C6, 0x000008C9, 0x00000003, 0x00000409, 
+            0x0000086C, 0x000008B9, 0x00000003, 0x000003E6, 0x00000005, 0x000003F7, 0x000008CC, 0x000008BA, 
+            0x00000413, 0x000008C5, 0x000008CC, 0x000008D1, 0x00000005, 0x00000003, 0x00000401, 0x000003EF, 
+            0x0000088C, 0x00000876, 0x00000885, 0x000003EF, 0x00000003, 0x000008BC, 0x00000870, 0x000008B5, 
+            0x0000040B, 0x00000003, 0x00000011, 0x0000086C, 0x000008CA, 0x000008C6, 0x000008C1, 0x00000003, 
+            0x00000888, 0x00000881, 0x000003EF, 0x0000040B, 0x00000003, 0x000008BC, 0x000008BA, 0x000008BD, 
+            0x00000003, 0x0000086C, 0x000008C6, 0x000008D2, 0x000008AA, 0x000008C1, 0x00000003, 0x0000086C, 
+            0x000008C2, 0x000008B5, 0x000003F9, 0x00000003, 0x000008D0, 0x000008A2, 0x000008AA, 0x00000412, 
+            0x00000875, 0x00000003, 0x00000409, 0x000003EB, 0x00000003, 0x00000888, 0x000008AA, 0x0000086F, 
+            0x00000003, 0x0000040C, 0x0000088C, 0x00000885, 0x0000FFFF, 0x000008D5, 0x000003EF, 0x00000003, 
+            0x00000404, 0x000003F9, 0x0000086C, 0x00000882, 0x000008C2, 0x000008BD, 0x000003EF, 0x0000040B, 
+            0x00000003, 0x00000404, 0x0000088C, 0x00000881, 0x0000FFFF, 0x000008D5, 0x000003EF, 0x00000003, 
+            0x000008C4, 0x000008D1, 0x0000088E, 0x00000886, 0x00000876, 0x0000086F, 0x00000003, 0x00000408, 
+            0x000008CC, 0x000008B6, 0x00000875, 0x0000040B, 0x00000003, 0x000003E6, 0x00000408, 0x0000086C, 
+            0x000008B5, 0x000003F9, 0x0000FFFF, 0x000008D5, 0x000003EF, 0x00000003, 0x000008A8, 0x000008C1, 
+            0x00000003, 0x000008A0, 0x000008B6, 0x000008B1, 0x00000003, 0x0000086E, 0x000008D2, 0x00000891, 
+            0x000003EF, 0x000008CC, 0x00000882, 0x000008BD, 0x000003EF, 0x00000003, 0x000008BC, 0x000008C1, 
+            0x0000086C, 0x000008AA, 0x00000876, 0x00000875, 0x00000003, 0x000003E6, 0x0000086C, 0x0000040E, 
+            0x00000891, 0x0000086C, 0x00000891, 0x000003EB
+        </result-glyphs>
+
+        <result-indices>
+            0x000000FB, 0x000000FA, 0x000000F9, 0x000000F8, 0x000000F7, 0x000000F6, 0x000000F5, 0x000000F4, 
+            0x000000F3, 0x000000F2, 0x000000F1, 0x000000F0, 0x000000EF, 0x000000EE, 0x000000ED, 0x000000EC, 
+            0x000000EB, 0x000000EA, 0x000000E9, 0x000000E8, 0x000000E7, 0x000000E6, 0x000000E5, 0x000000E4, 
+            0x000000E3, 0x000000E2, 0x000000E1, 0x000000E0, 0x000000DF, 0x000000DE, 0x000000DD, 0x000000DC, 
+            0x000000DB, 0x000000DA, 0x000000D9, 0x000000D8, 0x000000D7, 0x000000D6, 0x000000D5, 0x000000D4, 
+            0x000000D3, 0x000000D2, 0x000000D1, 0x000000D0, 0x000000CF, 0x000000CE, 0x000000CD, 0x000000CC, 
+            0x000000CB, 0x000000CA, 0x000000C9, 0x000000C8, 0x000000C7, 0x000000C6, 0x000000C5, 0x000000C4, 
+            0x000000C3, 0x000000C2, 0x000000C1, 0x000000C0, 0x000000BF, 0x000000BE, 0x000000BD, 0x000000BC, 
+            0x000000BB, 0x000000BA, 0x000000B9, 0x000000B8, 0x000000B7, 0x000000B6, 0x000000B5, 0x000000B4, 
+            0x000000B3, 0x000000B2, 0x000000B1, 0x000000B0, 0x000000AF, 0x000000AE, 0x000000AD, 0x000000AC, 
+            0x000000AB, 0x000000AA, 0x000000A9, 0x000000A8, 0x000000A7, 0x000000A6, 0x000000A5, 0x000000A4, 
+            0x000000A3, 0x000000A2, 0x000000A1, 0x000000A0, 0x0000009F, 0x0000009E, 0x0000009D, 0x0000009C, 
+            0x0000009B, 0x0000009A, 0x00000099, 0x00000098, 0x00000097, 0x00000096, 0x00000095, 0x00000094, 
+            0x00000093, 0x00000092, 0x00000091, 0x00000090, 0x0000008F, 0x0000008E, 0x0000008D, 0x0000008C, 
+            0x0000008B, 0x0000008A, 0x00000089, 0x00000088, 0x00000087, 0x00000086, 0x00000085, 0x00000084, 
+            0x00000083, 0x00000082, 0x00000081, 0x00000080, 0x0000007F, 0x0000007E, 0x0000007D, 0x0000007C, 
+            0x0000007B, 0x0000007A, 0x00000079, 0x00000078, 0x00000077, 0x00000076, 0x00000075, 0x00000074, 
+            0x00000073, 0x00000072, 0x00000071, 0x00000070, 0x0000006F, 0x0000006E, 0x0000006D, 0x0000006C, 
+            0x0000006B, 0x0000006A, 0x00000069, 0x00000068, 0x00000067, 0x00000066, 0x00000065, 0x00000064, 
+            0x00000063, 0x00000062, 0x00000061, 0x00000060, 0x0000005F, 0x0000005E, 0x0000005D, 0x0000005C, 
+            0x0000005B, 0x0000005A, 0x00000059, 0x00000058, 0x00000057, 0x00000056, 0x00000055, 0x00000054, 
+            0x00000053, 0x00000052, 0x00000051, 0x00000050, 0x0000004F, 0x0000004E, 0x0000004D, 0x0000004C, 
+            0x0000004B, 0x0000004A, 0x00000049, 0x00000048, 0x00000047, 0x00000046, 0x00000045, 0x00000044, 
+            0x00000043, 0x00000042, 0x00000041, 0x00000040, 0x0000003F, 0x0000003E, 0x0000003D, 0x0000003C, 
+            0x0000003B, 0x0000003A, 0x00000039, 0x00000038, 0x00000037, 0x00000036, 0x00000035, 0x00000034, 
+            0x00000033, 0x00000032, 0x00000031, 0x00000030, 0x0000002F, 0x0000002E, 0x0000002D, 0x0000002C, 
+            0x0000002B, 0x0000002A, 0x00000029, 0x00000028, 0x00000027, 0x00000026, 0x00000025, 0x00000024, 
+            0x00000023, 0x00000022, 0x00000021, 0x00000020, 0x0000001F, 0x0000001E, 0x0000001D, 0x0000001C, 
+            0x0000001B, 0x0000001A, 0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015, 0x00000014, 
+            0x00000013, 0x00000012, 0x00000011, 0x00000010, 0x0000000F, 0x0000000E, 0x0000000D, 0x0000000C, 
+            0x0000000B, 0x0000000A, 0x00000009, 0x00000008, 0x00000007, 0x00000006, 0x00000005, 0x00000004, 
+            0x00000003, 0x00000002, 0x00000001, 0x00000000
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 6.316406, 0.000000, 10.382812, 0.000000, 15.492188, 0.000000, 
+            21.035156, 0.000000, 27.058594, 0.000000, 39.527344, 0.000000, 43.792969, 0.000000, 
+            47.408203, 0.000000, 51.205078, 0.000000, 66.216797, 0.000000, 71.326172, 0.000000, 
+            74.695312, 0.000000, 83.367188, 0.000000, 90.826172, 0.000000, 95.091797, 0.000000, 
+            98.707031, 0.000000, 102.503906, 0.000000, 109.962891, 0.000000, 114.949219, 0.000000, 
+            122.408203, 0.000000, 130.687500, 0.000000, 134.484375, 0.000000, 145.787109, 0.000000, 
+            150.773438, 0.000000, 156.884766, 0.000000, 160.681641, 0.000000, 172.277344, 0.000000, 
+            177.919922, 0.000000, 182.906250, 0.000000, 191.578125, 0.000000, 195.644531, 0.000000, 
+            199.441406, 0.000000, 206.507812, 0.000000, 214.787109, 0.000000, 218.402344, 0.000000, 
+            223.945312, 0.000000, 227.742188, 0.000000, 233.765625, 0.000000, 238.751953, 0.000000, 
+            245.185547, 0.000000, 257.982422, 0.000000, 262.048828, 0.000000, 265.845703, 0.000000, 
+            272.654297, 0.000000, 276.023438, 0.000000, 285.240234, 0.000000, 289.306641, 0.000000, 
+            293.103516, 0.000000, 300.169922, 0.000000, 308.449219, 0.000000, 314.091797, 0.000000, 
+            318.158203, 0.000000, 321.955078, 0.000000, 329.572266, 0.000000, 333.837891, 0.000000, 
+            339.380859, 0.000000, 343.177734, 0.000000, 346.974609, 0.000000, 361.986328, 0.000000, 
+            367.095703, 0.000000, 370.464844, 0.000000, 379.136719, 0.000000, 386.595703, 0.000000, 
+            391.582031, 0.000000, 395.847656, 0.000000, 399.644531, 0.000000, 406.453125, 0.000000, 
+            409.822266, 0.000000, 415.523438, 0.000000, 420.632812, 0.000000, 420.632812, 0.000000, 
+            427.441406, 0.000000, 431.056641, 0.000000, 434.853516, 0.000000, 441.357422, 0.000000, 
+            448.423828, 0.000000, 455.912109, 0.000000, 459.708984, 0.000000, 479.255859, 0.000000, 
+            484.242188, 0.000000, 496.710938, 0.000000, 505.382812, 0.000000, 509.449219, 0.000000, 
+            514.992188, 0.000000, 518.789062, 0.000000, 524.812500, 0.000000, 529.798828, 0.000000, 
+            536.232422, 0.000000, 549.029297, 0.000000, 554.015625, 0.000000, 559.001953, 0.000000, 
+            563.267578, 0.000000, 567.064453, 0.000000, 573.380859, 0.000000, 580.839844, 0.000000, 
+            590.056641, 0.000000, 594.123047, 0.000000, 594.123047, 0.000000, 600.931641, 0.000000, 
+            604.546875, 0.000000, 608.343750, 0.000000, 620.636719, 0.000000, 624.005859, 0.000000, 
+            628.992188, 0.000000, 635.830078, 0.000000, 639.626953, 0.000000, 653.361328, 0.000000, 
+            656.730469, 0.000000, 661.716797, 0.000000, 669.205078, 0.000000, 673.001953, 0.000000, 
+            683.777344, 0.000000, 687.146484, 0.000000, 692.660156, 0.000000, 696.457031, 0.000000, 
+            700.253906, 0.000000, 704.736328, 0.000000, 711.105469, 0.000000, 716.748047, 0.000000, 
+            722.994141, 0.000000, 722.994141, 0.000000, 727.060547, 0.000000, 732.703125, 0.000000, 
+            736.769531, 0.000000, 741.251953, 0.000000, 745.048828, 0.000000, 752.507812, 0.000000, 
+            756.123047, 0.000000, 762.146484, 0.000000, 767.132812, 0.000000, 775.412109, 0.000000, 
+            779.027344, 0.000000, 782.824219, 0.000000, 794.203125, 0.000000, 799.189453, 0.000000, 
+            804.890625, 0.000000, 810.433594, 0.000000, 814.230469, 0.000000, 818.027344, 0.000000, 
+            821.396484, 0.000000, 828.128906, 0.000000, 833.115234, 0.000000, 839.953125, 0.000000, 
+            843.750000, 0.000000, 850.816406, 0.000000, 859.095703, 0.000000, 862.710938, 0.000000, 
+            868.253906, 0.000000, 872.050781, 0.000000, 883.429688, 0.000000, 889.675781, 0.000000, 
+            893.941406, 0.000000, 897.738281, 0.000000, 901.107422, 0.000000, 906.093750, 0.000000, 
+            911.080078, 0.000000, 917.800781, 0.000000, 924.638672, 0.000000, 928.435547, 0.000000, 
+            931.804688, 0.000000, 939.263672, 0.000000, 944.964844, 0.000000, 950.074219, 0.000000, 
+            953.871094, 0.000000, 965.173828, 0.000000, 974.390625, 0.000000, 981.111328, 0.000000, 
+            981.111328, 0.000000, 985.177734, 0.000000, 988.974609, 0.000000, 999.750000, 0.000000, 
+            1003.365234, 0.000000, 1007.162109, 0.000000, 1014.228516, 0.000000, 1020.949219, 0.000000, 
+            1025.015625, 0.000000, 1028.812500, 0.000000, 1040.408203, 0.000000, 1046.431641, 0.000000, 
+            1054.710938, 0.000000, 1054.710938, 0.000000, 1061.519531, 0.000000, 1065.134766, 0.000000, 
+            1068.931641, 0.000000, 1083.943359, 0.000000, 1089.052734, 0.000000, 1092.421875, 0.000000, 
+            1101.093750, 0.000000, 1108.552734, 0.000000, 1112.818359, 0.000000, 1116.433594, 0.000000, 
+            1121.976562, 0.000000, 1125.773438, 0.000000, 1140.785156, 0.000000, 1146.808594, 0.000000, 
+            1155.087891, 0.000000, 1155.087891, 0.000000, 1161.896484, 0.000000, 1165.511719, 0.000000, 
+            1169.308594, 0.000000, 1180.541016, 0.000000, 1184.607422, 0.000000, 1190.630859, 0.000000, 
+            1199.302734, 0.000000, 1204.289062, 0.000000, 1208.355469, 0.000000, 1212.152344, 0.000000, 
+            1218.960938, 0.000000, 1224.603516, 0.000000, 1231.037109, 0.000000, 1235.103516, 0.000000, 
+            1240.646484, 0.000000, 1244.443359, 0.000000, 1248.240234, 0.000000, 1255.048828, 0.000000, 
+            1258.417969, 0.000000, 1264.119141, 0.000000, 1269.228516, 0.000000, 1269.228516, 0.000000, 
+            1276.037109, 0.000000, 1279.652344, 0.000000, 1283.449219, 0.000000, 1290.908203, 0.000000, 
+            1297.746094, 0.000000, 1301.542969, 0.000000, 1311.427734, 0.000000, 1317.861328, 0.000000, 
+            1323.562500, 0.000000, 1327.359375, 0.000000, 1341.492188, 0.000000, 1346.478516, 0.000000, 
+            1357.904297, 0.000000, 1361.519531, 0.000000, 1367.162109, 0.000000, 1375.833984, 0.000000, 
+            1380.099609, 0.000000, 1383.714844, 0.000000, 1387.511719, 0.000000, 1398.890625, 0.000000, 
+            1405.728516, 0.000000, 1409.097656, 0.000000, 1415.818359, 0.000000, 1420.804688, 0.000000, 
+            1424.871094, 0.000000, 1428.667969, 0.000000, 1432.464844, 0.000000, 1435.833984, 0.000000, 
+            1435.833984, 0.000000, 1447.259766, 0.000000, 1450.628906, 0.000000, 1462.054688, 0.000000, 
+            1465.669922, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Matra Test" script="deva">
+        <test-font name="raghu.ttf" version="Original Version 1.00 (2005)" checksum="0x088DB135" rchecksum="0x00803FCE"/>
+
+        <test-text>ुं ं॑</test-text>
+
+        <result-glyphs>
+            0x0000029C, 0x000001D5, 0x00000232, 0x00000003, 0x0000029C, 0x00000232, 0x00000233
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000003, 0x00000004
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 7.541016, 0.000000, 7.541016, 0.000000, 7.541016, 0.000000, 
+            13.541016, 0.000000, 21.082031, 0.000000, 19.953125, -6.052734, 21.082031, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Deva Stress Test" script="deva">
+        <test-font name="raghu.ttf" version="Original Version 1.00 (2005)" checksum="0x088DB135" rchecksum="0x00803FCE"/>
+
+        <test-text>कँ कं कः क॑ क॒ कँ॑ कं॒ कँंः क॒॑</test-text>
+
+        <result-glyphs>
+            0x00000080, 0x00000231, 0x00000003, 0x00000080, 0x00000232, 0x00000003, 0x00000080, 0x0000022C, 
+            0x00000003, 0x00000080, 0x00000233, 0x00000003, 0x00000080, 0x000001DF, 0x00000003, 0x00000080, 
+            0x00000231, 0x00000233, 0x00000003, 0x00000080, 0x000001DF, 0x00000232, 0x00000003, 0x00000080, 
+            0x00000231, 0x0000029C, 0x00000232, 0x0000029C, 0x0000022C, 0x00000003, 0x00000080, 0x00000233, 
+            0x0000029C, 0x000001DF
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F, 
+            0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000015, 0x00000014, 0x00000016, 0x00000017, 
+            0x00000018, 0x00000019, 0x00000019, 0x0000001A, 0x0000001A, 0x0000001B, 0x0000001C, 0x0000001D, 
+            0x0000001E, 0x0000001E
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 10.001953, -0.087891, 10.875000, 0.000000, 16.875000, 0.000000, 
+            23.783203, 0.439453, 27.750000, 0.000000, 33.750000, 0.000000, 44.625000, 0.000000, 
+            48.984375, 0.000000, 54.984375, 0.000000, 63.546875, -1.669922, 65.859375, 0.000000, 
+            71.859375, 0.000000, 80.332031, 0.492188, 82.734375, 0.000000, 88.734375, 0.000000, 
+            98.736328, -0.087891, 97.431641, -6.228516, 99.609375, 0.000000, 105.609375, 0.000000, 
+            114.082031, 0.492188, 112.517578, 0.439453, 116.484375, 0.000000, 122.484375, 0.000000, 
+            132.486328, -0.087891, 133.359375, 0.000000, 140.900391, 0.000000, 140.900391, 0.000000, 
+            148.441406, 0.000000, 152.800781, 0.000000, 158.800781, 0.000000, 167.363281, -1.669922, 
+            169.675781, 0.000000, 177.216797, 0.000000, 177.216797, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Deva Test" script="deva">
+        <test-font name="raghu.ttf" version="Original Version 1.00 (2005)" checksum="0x088DB135" rchecksum="0x00803FCE"/>
+
+        <test-text>रू क़् क्ष क्कि क्रि ट्रि हिन्दी र्क्रिं क्षत्रज्ञत्रक्ष श्र थ्र श्र कके र्कें केूकूेकेृ र्कू क़ क क् क्ष क्ष् क्ष्क  ज़ ज ज् ज्ञ ज्ञ् ज्ञ्क र्क र्क्क ड्र क्क क़्क क़्क क़् क्ष्क क्ष् त्र्क द्द कि हि रू रु र्के र्कं क् कु के द्द्द क़्ष क्ष र्क्षे द्दत्र्क ज्ञ क्त्व ज्ञ्क र्कँ र्किँ र्केँ र्क्रिँ हिंदी ह्मिह्यिखि ङ्क ङ्म ङ्क्त ङ्ख ङ्ग ङ्घ ङ्क्ष ङ्क्ष्व ङ्क्ष्य र्क्त्वि र्र्र्र कै के कु कू कृ कॅ कॆ हु हू हॆ है हे</test-text>
+
+        <result-glyphs>
+            0x0000009A, 0x000001FE, 0x00000003, 0x000000A4, 0x00000051, 0x00000003, 0x000000A2, 0x0000FFFF, 
+            0x0000FFFF, 0x00000003, 0x000001D4, 0x000000C8, 0x0000FFFF, 0x00000080, 0x00000003, 0x000001D1, 
+            0x00000080, 0x0000009A, 0x00000051, 0x00000003, 0x000001D1, 0x0000008A, 0x0000009A, 0x00000051, 
+            0x00000003, 0x000001D1, 0x000000A1, 0x000000DB, 0x0000FFFF, 0x00000091, 0x00000223, 0x00000003, 
+            0x000001D1, 0x00000080, 0x000000E2, 0x0000FFFF, 0x0000009A, 0x00000051, 0x00000232, 0x00000003, 
+            0x000000A2, 0x0000FFFF, 0x0000FFFF, 0x0000008F, 0x000000E2, 0x0000FFFF, 0x000000A3, 0x0000FFFF, 
+            0x0000FFFF, 0x0000008F, 0x000000E2, 0x0000FFFF, 0x000000A2, 0x0000FFFF, 0x0000FFFF, 0x00000003, 
+            0x0000009E, 0x0000009A, 0x00000051, 0x00000003, 0x00000090, 0x0000009A, 0x00000051, 0x00000003, 
+            0x0000009E, 0x0000009A, 0x00000051, 0x00000003, 0x00000080, 0x00000080, 0x0000022F, 0x00000003, 
+            0x00000080, 0x0000022F, 0x0000024D, 0x0000FFFF, 0x0000FFFF, 0x00000003, 0x00000080, 0x0000022F, 
+            0x0000029C, 0x000001D7, 0x00000080, 0x000001D7, 0x0000029C, 0x0000022F, 0x00000080, 0x0000022F, 
+            0x0000029C, 0x000001D9, 0x00000003, 0x00000080, 0x000001D7, 0x0000005B, 0x0000FFFF, 0x00000003, 
+            0x000000A4, 0x00000003, 0x00000080, 0x00000003, 0x00000080, 0x00000051, 0x00000003, 0x000000A2, 
+            0x0000FFFF, 0x0000FFFF, 0x00000003, 0x000000A2, 0x0000FFFF, 0x0000FFFF, 0x00000051, 0x00000003, 
+            0x000000EA, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x00000080, 0x00000003, 0x00000003, 0x000000AB, 
+            0x0000FFFF, 0x00000003, 0x00000087, 0x00000003, 0x00000087, 0x00000051, 0x00000003, 0x000000A3, 
+            0x0000FFFF, 0x0000FFFF, 0x00000003, 0x000000A3, 0x0000FFFF, 0x0000FFFF, 0x00000051, 0x00000003, 
+            0x000000EB, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x00000080, 0x00000003, 0x00000080, 0x0000005B, 
+            0x0000FFFF, 0x00000003, 0x000000C8, 0x0000FFFF, 0x00000080, 0x0000005B, 0x0000FFFF, 0x00000003, 
+            0x0000008C, 0x0000009A, 0x00000051, 0x00000003, 0x000000C8, 0x0000FFFF, 0x00000080, 0x00000003, 
+            0x000000EC, 0x0000FFFF, 0x00000080, 0x00000003, 0x000000EC, 0x0000FFFF, 0x00000080, 0x00000003, 
+            0x000000A4, 0x00000051, 0x00000003, 0x000000EA, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x00000080, 
+            0x00000003, 0x000000A2, 0x0000FFFF, 0x0000FFFF, 0x00000051, 0x00000003, 0x000000D7, 0x0000FFFF, 
+            0x000000E2, 0x0000FFFF, 0x00000080, 0x00000003, 0x000001A7, 0x0000FFFF, 0x0000FFFF, 0x00000003, 
+            0x000001D1, 0x00000080, 0x00000003, 0x000001D1, 0x000000A1, 0x00000003, 0x0000009A, 0x000001FE, 
+            0x00000003, 0x0000009A, 0x000001FD, 0x00000003, 0x00000080, 0x0000022F, 0x0000005A, 0x0000FFFF, 
+            0x00000003, 0x00000080, 0x0000024D, 0x0000FFFF, 0x0000FFFF, 0x00000003, 0x00000080, 0x00000051, 
+            0x00000003, 0x00000080, 0x000001D5, 0x00000003, 0x00000080, 0x0000022F, 0x00000003, 0x000000D9, 
+            0x0000FFFF, 0x000001A7, 0x0000FFFF, 0x0000FFFF, 0x00000003, 0x000000EC, 0x0000FFFF, 0x0000009F, 
+            0x00000003, 0x000000A2, 0x0000FFFF, 0x0000FFFF, 0x00000003, 0x000000A2, 0x0000FFFF, 0x0000FFFF, 
+            0x0000022F, 0x0000005A, 0x0000FFFF, 0x00000003, 0x000001A7, 0x0000FFFF, 0x0000FFFF, 0x000000D7, 
+            0x0000FFFF, 0x000000E2, 0x0000FFFF, 0x00000080, 0x00000003, 0x000000A3, 0x0000FFFF, 0x0000FFFF, 
+            0x00000003, 0x000000C8, 0x0000FFFF, 0x000000D7, 0x0000FFFF, 0x0000009D, 0x00000003, 0x000000EB, 
+            0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x00000080, 0x00000003, 0x00000080, 0x0000024C, 0x0000FFFF, 
+            0x0000FFFF, 0x00000003, 0x000001D1, 0x00000080, 0x0000024C, 0x0000FFFF, 0x0000FFFF, 0x00000003, 
+            0x00000080, 0x0000022F, 0x0000024C, 0x0000FFFF, 0x0000FFFF, 0x00000003, 0x000001D1, 0x00000080, 
+            0x000000E2, 0x0000FFFF, 0x0000009A, 0x00000051, 0x00000231, 0x00000003, 0x000001D1, 0x000000A1, 
+            0x00000232, 0x00000091, 0x00000223, 0x00000003, 0x000001D3, 0x000001BA, 0x0000FFFF, 0x0000FFFF, 
+            0x000001D3, 0x000001BB, 0x0000FFFF, 0x0000FFFF, 0x000001D4, 0x00000081, 0x00000003, 0x000000CC, 
+            0x0000FFFF, 0x00000080, 0x00000003, 0x000001A2, 0x0000FFFF, 0x0000FFFF, 0x00000003, 0x000000CC, 
+            0x0000FFFF, 0x000001A0, 0x0000FFFF, 0x0000FFFF, 0x00000003, 0x000000CC, 0x0000FFFF, 0x00000081, 
+            0x00000003, 0x000000CC, 0x0000FFFF, 0x00000082, 0x00000003, 0x000000CC, 0x0000FFFF, 0x00000083, 
+            0x00000003, 0x000000CC, 0x0000FFFF, 0x000000A2, 0x0000FFFF, 0x0000FFFF, 0x00000003, 0x000000CC, 
+            0x0000FFFF, 0x000000EA, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000009D, 0x00000003, 0x000000CC, 
+            0x0000FFFF, 0x000000EA, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x00000099, 0x00000003, 0x000001D4, 
+            0x000000C8, 0x0000FFFF, 0x000000D7, 0x0000FFFF, 0x0000009D, 0x0000005B, 0x0000FFFF, 0x00000003, 
+            0x0000009A, 0x00000051, 0x0000009A, 0x000000E2, 0x0000FFFF, 0x0000009A, 0x00000051, 0x00000003, 
+            0x00000080, 0x00000230, 0x00000003, 0x00000080, 0x0000022F, 0x00000003, 0x00000080, 0x000001D5, 
+            0x00000003, 0x00000080, 0x000001D7, 0x00000003, 0x00000080, 0x000001D9, 0x00000003, 0x00000080, 
+            0x0000022D, 0x00000003, 0x00000080, 0x0000022E, 0x00000003, 0x000000A1, 0x000001D5, 0x00000003, 
+            0x000000A1, 0x000001D7, 0x00000003, 0x000000A1, 0x0000022E, 0x00000003, 0x000000A1, 0x00000230, 
+            0x00000003, 0x000000A1, 0x0000022F
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000D, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000E, 0x00000012, 
+            0x0000000F, 0x00000011, 0x00000010, 0x00000013, 0x00000017, 0x00000014, 0x00000016, 0x00000015, 
+            0x00000018, 0x0000001A, 0x00000019, 0x0000001B, 0x0000001C, 0x0000001D, 0x0000001E, 0x0000001F, 
+            0x00000025, 0x00000022, 0x00000024, 0x00000023, 0x00000020, 0x00000021, 0x00000026, 0x00000027, 
+            0x00000028, 0x00000029, 0x0000002A, 0x0000002B, 0x0000002D, 0x0000002C, 0x0000002E, 0x0000002F, 
+            0x00000030, 0x00000031, 0x00000033, 0x00000032, 0x00000034, 0x00000035, 0x00000036, 0x00000037, 
+            0x00000038, 0x0000003A, 0x00000039, 0x0000003B, 0x0000003C, 0x0000003E, 0x0000003D, 0x0000003F, 
+            0x00000040, 0x00000042, 0x00000041, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 
+            0x0000004A, 0x0000004B, 0x00000048, 0x00000049, 0x0000004C, 0x0000004D, 0x0000004E, 0x0000004F, 
+            0x00000050, 0x00000050, 0x00000051, 0x00000052, 0x00000053, 0x00000053, 0x00000054, 0x00000055, 
+            0x00000056, 0x00000056, 0x00000057, 0x0000005A, 0x0000005B, 0x00000058, 0x00000059, 0x0000005C, 
+            0x0000005D, 0x0000005E, 0x0000005F, 0x00000060, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 
+            0x00000065, 0x00000066, 0x00000067, 0x00000068, 0x00000069, 0x0000006A, 0x0000006B, 0x0000006C, 
+            0x0000006D, 0x0000006E, 0x0000006F, 0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 
+            0x00000075, 0x00000076, 0x00000077, 0x00000078, 0x00000079, 0x0000007A, 0x0000007B, 0x0000007C, 
+            0x0000007D, 0x0000007E, 0x0000007F, 0x00000080, 0x00000081, 0x00000082, 0x00000083, 0x00000084, 
+            0x00000085, 0x00000086, 0x00000087, 0x00000088, 0x00000089, 0x0000008A, 0x0000008D, 0x0000008B, 
+            0x0000008C, 0x0000008E, 0x00000091, 0x00000092, 0x00000093, 0x0000008F, 0x00000090, 0x00000094, 
+            0x00000095, 0x00000097, 0x00000096, 0x00000098, 0x00000099, 0x0000009A, 0x0000009B, 0x0000009C, 
+            0x0000009D, 0x0000009E, 0x0000009F, 0x000000A0, 0x000000A1, 0x000000A2, 0x000000A3, 0x000000A4, 
+            0x000000A5, 0x000000A6, 0x000000A7, 0x000000A8, 0x000000A9, 0x000000AA, 0x000000AB, 0x000000AC, 
+            0x000000AD, 0x000000AE, 0x000000AF, 0x000000B0, 0x000000B1, 0x000000B2, 0x000000B3, 0x000000B4, 
+            0x000000B5, 0x000000B6, 0x000000B7, 0x000000B8, 0x000000B9, 0x000000BA, 0x000000BB, 0x000000BC, 
+            0x000000BE, 0x000000BD, 0x000000BF, 0x000000C1, 0x000000C0, 0x000000C2, 0x000000C3, 0x000000C4, 
+            0x000000C5, 0x000000C6, 0x000000C7, 0x000000C8, 0x000000CB, 0x000000CC, 0x000000C9, 0x000000CA, 
+            0x000000CD, 0x000000D0, 0x000000CE, 0x000000CF, 0x000000D1, 0x000000D2, 0x000000D3, 0x000000D4, 
+            0x000000D5, 0x000000D6, 0x000000D7, 0x000000D8, 0x000000D9, 0x000000DA, 0x000000DB, 0x000000DC, 
+            0x000000DD, 0x000000DE, 0x000000DF, 0x000000E0, 0x000000E1, 0x000000E2, 0x000000E3, 0x000000E4, 
+            0x000000E5, 0x000000E6, 0x000000E7, 0x000000E8, 0x000000E9, 0x000000EC, 0x000000ED, 0x000000EE, 
+            0x000000EF, 0x000000EA, 0x000000EB, 0x000000F0, 0x000000F1, 0x000000F2, 0x000000F3, 0x000000F4, 
+            0x000000F5, 0x000000F6, 0x000000F7, 0x000000F8, 0x000000F9, 0x000000FA, 0x000000FB, 0x000000FC, 
+            0x000000FD, 0x000000FE, 0x000000FF, 0x00000100, 0x00000101, 0x00000102, 0x00000103, 0x00000104, 
+            0x00000105, 0x00000106, 0x00000107, 0x00000108, 0x00000109, 0x0000010C, 0x0000010A, 0x0000010B, 
+            0x0000010D, 0x0000010E, 0x00000112, 0x00000111, 0x0000010F, 0x00000110, 0x00000113, 0x00000114, 
+            0x00000117, 0x00000118, 0x00000115, 0x00000116, 0x00000119, 0x0000011A, 0x00000120, 0x0000011D, 
+            0x0000011F, 0x0000011E, 0x0000011B, 0x0000011C, 0x00000121, 0x00000122, 0x00000124, 0x00000123, 
+            0x00000125, 0x00000126, 0x00000127, 0x00000128, 0x0000012C, 0x00000129, 0x0000012A, 0x0000012B, 
+            0x00000130, 0x0000012D, 0x0000012E, 0x0000012F, 0x00000132, 0x00000131, 0x00000133, 0x00000134, 
+            0x00000135, 0x00000136, 0x00000137, 0x00000138, 0x00000139, 0x0000013A, 0x0000013B, 0x0000013C, 
+            0x0000013D, 0x0000013E, 0x0000013F, 0x00000140, 0x00000141, 0x00000142, 0x00000143, 0x00000144, 
+            0x00000145, 0x00000146, 0x00000147, 0x00000148, 0x00000149, 0x0000014A, 0x0000014B, 0x0000014C, 
+            0x0000014D, 0x0000014E, 0x0000014F, 0x00000150, 0x00000151, 0x00000152, 0x00000153, 0x00000154, 
+            0x00000155, 0x00000156, 0x00000157, 0x00000158, 0x00000159, 0x0000015A, 0x0000015B, 0x0000015C, 
+            0x0000015D, 0x0000015E, 0x0000015F, 0x00000160, 0x00000161, 0x00000162, 0x00000163, 0x0000016B, 
+            0x00000166, 0x00000167, 0x00000168, 0x00000169, 0x0000016A, 0x00000164, 0x00000165, 0x0000016C, 
+            0x0000016F, 0x00000170, 0x00000171, 0x00000173, 0x00000172, 0x0000016D, 0x0000016E, 0x00000174, 
+            0x00000175, 0x00000176, 0x00000177, 0x00000178, 0x00000179, 0x0000017A, 0x0000017B, 0x0000017C, 
+            0x0000017D, 0x0000017E, 0x0000017F, 0x00000180, 0x00000181, 0x00000182, 0x00000183, 0x00000184, 
+            0x00000185, 0x00000186, 0x00000187, 0x00000188, 0x00000189, 0x0000018A, 0x0000018B, 0x0000018C, 
+            0x0000018D, 0x0000018E, 0x0000018F, 0x00000190, 0x00000191, 0x00000192, 0x00000193, 0x00000194, 
+            0x00000195, 0x00000196, 0x00000197
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 6.515625, 0.000000, 8.121094, 0.000000, 14.121094, 0.000000, 
+            24.861328, -0.451172, 24.996094, 0.000000, 30.996094, 0.000000, 41.871094, 0.000000, 
+            41.871094, 0.000000, 41.871094, 0.000000, 47.871094, 0.000000, 52.230469, 0.000000, 
+            60.949219, 0.000000, 60.949219, 0.000000, 71.824219, 0.000000, 77.824219, 0.000000, 
+            82.183594, 0.000000, 93.058594, 0.000000, 102.720703, -0.451172, 99.574219, 0.000000, 
+            105.574219, 0.000000, 109.933594, 0.000000, 117.902344, 0.000000, 127.564453, -0.451172, 
+            124.417969, 0.000000, 130.417969, 0.000000, 134.777344, 0.000000, 142.746094, 0.000000, 
+            150.011719, 0.000000, 150.011719, 0.000000, 157.980469, 0.000000, 161.636719, 0.000000, 
+            167.636719, 0.000000, 171.996094, 0.000000, 182.871094, 0.000000, 186.621094, 0.000000, 
+            186.621094, 0.000000, 196.283203, -0.451172, 191.613281, 0.439453, 193.136719, 0.000000, 
+            199.136719, 0.000000, 210.011719, 0.000000, 210.011719, 0.000000, 210.011719, 0.000000, 
+            217.980469, 0.000000, 221.730469, 0.000000, 221.730469, 0.000000, 232.605469, 0.000000, 
+            232.605469, 0.000000, 232.605469, 0.000000, 240.574219, 0.000000, 244.324219, 0.000000, 
+            244.324219, 0.000000, 255.199219, 0.000000, 255.199219, 0.000000, 255.199219, 0.000000, 
+            261.199219, 0.000000, 270.667969, 0.000000, 280.330078, -0.451172, 277.183594, 0.000000, 
+            283.183594, 0.000000, 292.652344, 0.000000, 302.314453, -0.451172, 299.167969, 0.000000, 
+            305.167969, 0.000000, 314.636719, 0.000000, 324.298828, -0.451172, 321.152344, 0.000000, 
+            327.152344, 0.000000, 338.027344, 0.000000, 344.783203, 0.263672, 348.902344, 0.000000, 
+            354.902344, 0.000000, 361.658203, 0.263672, 362.279297, 0.263672, 365.777344, 0.000000, 
+            365.777344, 0.000000, 365.777344, 0.000000, 371.777344, 0.000000, 378.533203, 0.263672, 
+            382.652344, 0.000000, 390.193359, 0.000000, 390.193359, 0.000000, 397.916016, -0.011719, 
+            401.068359, 0.000000, 408.609375, 0.000000, 408.609375, 0.000000, 415.365234, 0.263672, 
+            419.484375, 0.000000, 427.025391, 0.000000, 427.025391, 0.000000, 433.025391, 0.000000, 
+            440.748047, -0.011719, 440.929688, 0.263672, 443.900391, 0.000000, 443.900391, 0.000000, 
+            449.900391, 0.000000, 460.775391, 0.000000, 466.775391, 0.000000, 477.650391, 0.000000, 
+            483.650391, 0.000000, 494.390625, -0.451172, 494.525391, 0.000000, 500.525391, 0.000000, 
+            511.400391, 0.000000, 511.400391, 0.000000, 511.400391, 0.000000, 517.400391, 0.000000, 
+            528.275391, 0.000000, 528.275391, 0.000000, 531.457031, -0.451172, 528.275391, 0.000000, 
+            534.275391, 0.000000, 542.994141, 0.000000, 542.994141, 0.000000, 542.994141, 0.000000, 
+            542.994141, 0.000000, 553.869141, 0.000000, 559.869141, 0.000000, 565.869141, 0.000000, 
+            575.337891, 0.000000, 575.337891, 0.000000, 581.337891, 0.000000, 590.806641, 0.000000, 
+            596.806641, 0.000000, 609.597656, -0.451172, 606.275391, 0.000000, 612.275391, 0.000000, 
+            623.150391, 0.000000, 623.150391, 0.000000, 623.150391, 0.000000, 629.150391, 0.000000, 
+            640.025391, 0.000000, 640.025391, 0.000000, 643.207031, -0.451172, 640.025391, 0.000000, 
+            646.025391, 0.000000, 653.994141, 0.000000, 653.994141, 0.000000, 653.994141, 0.000000, 
+            653.994141, 0.000000, 664.869141, 0.000000, 670.869141, 0.000000, 678.773438, 0.263672, 
+            681.744141, 0.000000, 681.744141, 0.000000, 687.744141, 0.000000, 696.462891, 0.000000, 
+            696.462891, 0.000000, 704.367188, 0.263672, 707.337891, 0.000000, 707.337891, 0.000000, 
+            713.337891, 0.000000, 721.306641, 0.000000, 730.968750, -0.451172, 727.822266, 0.000000, 
+            733.822266, 0.000000, 742.541016, 0.000000, 742.541016, 0.000000, 753.416016, 0.000000, 
+            759.416016, 0.000000, 768.134766, 0.000000, 768.134766, 0.000000, 779.009766, 0.000000, 
+            785.009766, 0.000000, 793.728516, 0.000000, 793.728516, 0.000000, 804.603516, 0.000000, 
+            810.603516, 0.000000, 821.343750, -0.451172, 821.478516, 0.000000, 827.478516, 0.000000, 
+            836.197266, 0.000000, 836.197266, 0.000000, 836.197266, 0.000000, 836.197266, 0.000000, 
+            847.072266, 0.000000, 853.072266, 0.000000, 863.947266, 0.000000, 863.947266, 0.000000, 
+            867.128906, -0.451172, 863.947266, 0.000000, 869.947266, 0.000000, 875.876953, 0.000000, 
+            875.876953, 0.000000, 879.626953, 0.000000, 879.626953, 0.000000, 890.501953, 0.000000, 
+            896.501953, 0.000000, 903.064453, 0.000000, 903.064453, 0.000000, 903.064453, 0.000000, 
+            909.064453, 0.000000, 913.423828, 0.000000, 924.298828, 0.000000, 930.298828, 0.000000, 
+            934.658203, 0.000000, 942.626953, 0.000000, 948.626953, 0.000000, 955.142578, 0.000000, 
+            956.748047, 0.000000, 962.748047, 0.000000, 969.263672, 0.000000, 970.623047, 0.000000, 
+            976.623047, 0.000000, 983.378906, 0.263672, 983.853516, 0.164062, 987.498047, 0.000000, 
+            987.498047, 0.000000, 993.498047, 0.000000, 1000.875000, 0.263672, 1004.373047, 0.000000, 
+            1004.373047, 0.000000, 1004.373047, 0.000000, 1010.373047, 0.000000, 1021.113281, -0.451172, 
+            1021.248047, 0.000000, 1027.248047, 0.000000, 1034.947266, -0.011719, 1038.123047, 0.000000, 
+            1044.123047, 0.000000, 1050.878906, 0.263672, 1054.998047, 0.000000, 1060.998047, 0.000000, 
+            1068.966797, 0.000000, 1068.966797, 0.000000, 1075.529297, 0.000000, 1075.529297, 0.000000, 
+            1075.529297, 0.000000, 1081.529297, 0.000000, 1090.248047, 0.000000, 1090.248047, 0.000000, 
+            1098.216797, 0.000000, 1104.216797, 0.000000, 1115.091797, 0.000000, 1115.091797, 0.000000, 
+            1115.091797, 0.000000, 1121.091797, 0.000000, 1131.966797, 0.000000, 1131.966797, 0.000000, 
+            1131.164062, 0.275391, 1131.638672, 0.175781, 1131.966797, 0.000000, 1131.966797, 0.000000, 
+            1137.966797, 0.000000, 1144.529297, 0.000000, 1144.529297, 0.000000, 1144.529297, 0.000000, 
+            1150.458984, 0.000000, 1150.458984, 0.000000, 1154.208984, 0.000000, 1154.208984, 0.000000, 
+            1165.083984, 0.000000, 1171.083984, 0.000000, 1181.958984, 0.000000, 1181.958984, 0.000000, 
+            1181.958984, 0.000000, 1187.958984, 0.000000, 1196.677734, 0.000000, 1196.677734, 0.000000, 
+            1202.607422, 0.000000, 1202.607422, 0.000000, 1210.576172, 0.000000, 1216.576172, 0.000000, 
+            1224.544922, 0.000000, 1224.544922, 0.000000, 1224.544922, 0.000000, 1224.544922, 0.000000, 
+            1235.419922, 0.000000, 1241.419922, 0.000000, 1249.236328, 0.263672, 1252.294922, 0.000000, 
+            1252.294922, 0.000000, 1252.294922, 0.000000, 1258.294922, 0.000000, 1262.654297, 0.000000, 
+            1270.470703, 0.263672, 1273.529297, 0.000000, 1273.529297, 0.000000, 1273.529297, 0.000000, 
+            1279.529297, 0.000000, 1286.285156, 0.263672, 1287.345703, 0.263672, 1290.404297, 0.000000, 
+            1290.404297, 0.000000, 1290.404297, 0.000000, 1296.404297, 0.000000, 1300.763672, 0.000000, 
+            1311.638672, 0.000000, 1315.388672, 0.000000, 1315.388672, 0.000000, 1325.050781, -0.451172, 
+            1323.474609, -0.087891, 1321.904297, 0.000000, 1327.904297, 0.000000, 1332.263672, 0.000000, 
+            1338.767578, 0.439453, 1340.232422, 0.000000, 1348.201172, 0.000000, 1351.857422, 0.000000, 
+            1357.857422, 0.000000, 1362.216797, 0.000000, 1372.388672, 0.000000, 1372.388672, 0.000000, 
+            1372.388672, 0.000000, 1376.748047, 0.000000, 1386.919922, 0.000000, 1386.919922, 0.000000, 
+            1386.919922, 0.000000, 1391.279297, 0.000000, 1402.154297, 0.000000, 1408.154297, 0.000000, 
+            1416.123047, 0.000000, 1416.123047, 0.000000, 1426.998047, 0.000000, 1432.998047, 0.000000, 
+            1446.076172, 0.000000, 1446.076172, 0.000000, 1446.076172, 0.000000, 1452.076172, 0.000000, 
+            1460.044922, 0.000000, 1460.044922, 0.000000, 1471.294922, 0.000000, 1471.294922, 0.000000, 
+            1471.294922, 0.000000, 1477.294922, 0.000000, 1485.263672, 0.000000, 1485.263672, 0.000000, 
+            1496.138672, 0.000000, 1502.138672, 0.000000, 1510.107422, 0.000000, 1510.107422, 0.000000, 
+            1519.576172, 0.000000, 1525.576172, 0.000000, 1533.544922, 0.000000, 1533.544922, 0.000000, 
+            1543.013672, 0.000000, 1549.013672, 0.000000, 1556.982422, 0.000000, 1556.982422, 0.000000, 
+            1567.857422, 0.000000, 1567.857422, 0.000000, 1567.857422, 0.000000, 1573.857422, 0.000000, 
+            1581.826172, 0.000000, 1581.826172, 0.000000, 1590.544922, 0.000000, 1590.544922, 0.000000, 
+            1590.544922, 0.000000, 1590.544922, 0.000000, 1598.513672, 0.000000, 1604.513672, 0.000000, 
+            1612.482422, 0.000000, 1612.482422, 0.000000, 1621.201172, 0.000000, 1621.201172, 0.000000, 
+            1621.201172, 0.000000, 1621.201172, 0.000000, 1630.669922, 0.000000, 1636.669922, 0.000000, 
+            1641.029297, 0.000000, 1649.748047, 0.000000, 1649.748047, 0.000000, 1655.677734, 0.000000, 
+            1655.677734, 0.000000, 1663.939453, 0.263672, 1663.646484, 0.000000, 1663.646484, 0.000000, 
+            1669.646484, 0.000000, 1679.308594, -0.451172, 1676.162109, 0.000000, 1682.677734, 0.000000, 
+            1686.427734, 0.000000, 1686.427734, 0.000000, 1696.089844, -0.451172, 1692.943359, 0.000000, 
+            1698.943359, 0.000000, 1706.314453, 0.263672, 1709.818359, 0.000000, 1715.818359, 0.000000, 
+            1722.574219, 0.263672, 1726.693359, 0.000000, 1732.693359, 0.000000, 1740.392578, -0.011719, 
+            1743.568359, 0.000000, 1749.568359, 0.000000, 1757.291016, -0.011719, 1760.443359, 0.000000, 
+            1766.443359, 0.000000, 1774.376953, -0.011719, 1777.318359, 0.000000, 1783.318359, 0.000000, 
+            1791.738281, -0.439453, 1794.193359, 0.000000, 1800.193359, 0.000000, 1808.121094, 0.263672, 
+            1811.068359, 0.000000, 1817.068359, 0.000000, 1823.085938, -0.011719, 1825.037109, 0.000000, 
+            1831.037109, 0.000000, 1837.078125, -0.011719, 1839.005859, 0.000000, 1845.005859, 0.000000, 
+            1852.529297, 0.263672, 1852.974609, 0.000000, 1858.974609, 0.000000, 1865.941406, 0.263672, 
+            1866.943359, 0.000000, 1872.943359, 0.000000, 1879.294922, 0.263672, 1880.912109, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Japanese Han" script="hani" lang="JAN">
+        <test-font name="Arial Unicode.ttf" version="Version 1.01x" checksum="0x609C497F" rchecksum="0x63451FC0"/>
+
+        <test-text>中华人民共和国 台湾 中華人民共和國 臺灣</test-text>
+
+        <result-glyphs>
+            0x000020BC, 0x000025DD, 0x00002149, 0x00003EA0, 0x00002400, 0x0000271B, 0x0000298C, 0x00000003, 
+            0x0000267F, 0x0000410D, 0x00000003, 0x000020BC, 0x0000567E, 0x00002149, 0x00003EA0, 0x00002400, 
+            0x0000271B, 0x0000299A, 0x00000003, 0x00005489, 0x000042F2
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F, 
+            0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 12.000000, 0.000000, 24.000000, 0.000000, 36.000000, 0.000000, 
+            48.000000, 0.000000, 60.000000, 0.000000, 72.000000, 0.000000, 84.000000, 0.000000, 
+            87.333984, 0.000000, 99.333984, 0.000000, 111.333984, 0.000000, 114.667969, 0.000000, 
+            126.667969, 0.000000, 138.667969, 0.000000, 150.667969, 0.000000, 162.667969, 0.000000, 
+            174.667969, 0.000000, 186.667969, 0.000000, 198.667969, 0.000000, 202.001953, 0.000000, 
+            214.001953, 0.000000, 226.001953, 0.000000
+        </result-positions>
+    </test-case>
+<!-- known to fail in base JDK7, skip
+    <test-case id="Korean Han" script="hani" lang="KOR">
+        <test-font name="Arial Unicode.ttf" version="Version 1.01x" checksum="0x609C497F" rchecksum="0x63451FC0"/>
+
+        <test-text>中华人民共和国 台湾 中華人民共和國 臺灣</test-text>
+
+        <result-glyphs>
+            0x000020BC, 0x000025DD, 0x00002149, 0x00003EA0, 0x00002400, 0x0000271B, 0x0000298C, 0x00000003, 
+            0x0000267F, 0x0000410D, 0x00000003, 0x000020BC, 0x00007492, 0x00002149, 0x00003EA0, 0x00002400, 
+            0x0000271B, 0x0000299A, 0x00000003, 0x00005489, 0x000042F2
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F, 
+            0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 12.000000, 0.000000, 24.000000, 0.000000, 36.000000, 0.000000, 
+            48.000000, 0.000000, 60.000000, 0.000000, 72.000000, 0.000000, 84.000000, 0.000000, 
+            87.333984, 0.000000, 99.333984, 0.000000, 111.333984, 0.000000, 114.667969, 0.000000, 
+            126.667969, 0.000000, 138.667969, 0.000000, 150.667969, 0.000000, 162.667969, 0.000000, 
+            174.667969, 0.000000, 186.667969, 0.000000, 198.667969, 0.000000, 202.001953, 0.000000, 
+            214.001953, 0.000000, 226.001953, 0.000000
+        </result-positions>
+    </test-case>
+-->
+
+<!-- known to fail in base JDK7, skip
+    <test-case id="Traditional Han" script="hani" lang="ZHT">
+        <test-font name="Arial Unicode.ttf" version="Version 1.01x" checksum="0x609C497F" rchecksum="0x63451FC0"/>
+
+        <test-text>中华人民共和国 台湾 中華人民共和國 臺灣</test-text>
+
+        <result-glyphs>
+            0x000020BC, 0x000025DD, 0x00002149, 0x000079EB, 0x00002400, 0x0000271B, 0x0000298C, 0x00000003, 
+            0x00007677, 0x0000410D, 0x00000003, 0x000020BC, 0x00007E26, 0x00002149, 0x000079EB, 0x00002400, 
+            0x0000271B, 0x0000299A, 0x00000003, 0x00007D8F, 0x00007A97
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F, 
+            0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 12.000000, 0.000000, 24.000000, 0.000000, 36.000000, 0.000000, 
+            48.000000, 0.000000, 60.000000, 0.000000, 72.000000, 0.000000, 84.000000, 0.000000, 
+            87.333984, 0.000000, 99.333984, 0.000000, 111.333984, 0.000000, 114.667969, 0.000000, 
+            126.667969, 0.000000, 138.667969, 0.000000, 150.667969, 0.000000, 162.667969, 0.000000, 
+            174.667969, 0.000000, 186.667969, 0.000000, 198.667969, 0.000000, 202.001953, 0.000000, 
+            214.001953, 0.000000, 226.001953, 0.000000
+        </result-positions>
+    </test-case>
+-->
+
+<!-- known to fail in base JDK7, skip
+    <test-case id="Simplified Han" script="hani" lang="ZHS">
+        <test-font name="Arial Unicode.ttf" version="Version 1.01x" checksum="0x609C497F" rchecksum="0x63451FC0"/>
+
+        <test-text>中华人民共和国 台湾 中華人民共和國 臺灣</test-text>
+
+        <result-glyphs>
+            0x000020BC, 0x000025DD, 0x00002149, 0x000079EB, 0x00002400, 0x0000271B, 0x0000298C, 0x00000003, 
+            0x00007677, 0x00008886, 0x00000003, 0x000020BC, 0x0000567E, 0x00002149, 0x000079EB, 0x00002400, 
+            0x0000271B, 0x0000299A, 0x00000003, 0x00007D8F, 0x00007A97
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F, 
+            0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 12.000000, 0.000000, 24.000000, 0.000000, 36.000000, 0.000000, 
+            48.000000, 0.000000, 60.000000, 0.000000, 72.000000, 0.000000, 84.000000, 0.000000, 
+            87.333984, 0.000000, 99.333984, 0.000000, 111.333984, 0.000000, 114.667969, 0.000000, 
+            126.667969, 0.000000, 138.667969, 0.000000, 150.667969, 0.000000, 162.667969, 0.000000, 
+            174.667969, 0.000000, 186.667969, 0.000000, 198.667969, 0.000000, 202.001953, 0.000000, 
+            214.001953, 0.000000, 226.001953, 0.000000
+        </result-positions>
+    </test-case>
+-->
+
+    <test-case id="Deva locl Hindi" script="deva" lang="HIN">
+        <test-font name="TestFont1.otf" version="Version 001.000 " checksum="0x75B4A535" rchecksum="0x0004D80A"/>
+
+        <test-text>शङ़ु</test-text>
+
+        <result-glyphs>
+            0x00000002, 0x00000001, 0x00000006, 0x0000FFFF
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 7.572000, 0.000000, 15.108000, 0.000000, 15.108000, 0.000000, 
+            15.108000, 0.000000
+        </result-positions>
+    </test-case>
+
+<!-- known to fail in base JDK7, skip
+    <test-case id="Deva locl Marathi" script="deva" lang="MAR">
+        <test-font name="TestFont1.otf" version="Version 001.000 " checksum="0x75B4A535" rchecksum="0x0004D80A"/>
+
+        <test-text>शङ़ु</test-text>
+
+        <result-glyphs>
+            0x00000005, 0x00000001, 0x00000006, 0x0000FFFF
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 7.392000, 0.000000, 14.927999, 0.000000, 14.927999, 0.000000, 
+            14.927999, 0.000000
+        </result-positions>
+    </test-case>
+-->
+
+    <test-case id="Deva ZWJ" script="deva">
+        <test-font name="raghu.ttf" version="Original Version 1.00 (2005)" checksum="0x088DB135" rchecksum="0x00803FCE"/>
+
+        <test-text>क्ष र्क क्‍ष र्‍क</test-text>
+
+        <result-glyphs>
+            0x000000A2, 0x0000FFFF, 0x0000FFFF, 0x00000003, 0x00000080, 0x0000005B, 0x0000FFFF, 0x00000003, 
+            0x00000080, 0x00000051, 0x00000001, 0x0000009F, 0x00000003, 0x0000009A, 0x00000051, 0x00000001, 
+            0x00000080
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000006, 0x00000004, 0x00000005, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F, 
+            0x00000010
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 10.875000, 0.000000, 10.875000, 0.000000, 10.875000, 0.000000, 
+            16.875000, 0.000000, 24.779297, 0.263672, 27.750000, 0.000000, 27.750000, 0.000000, 
+            33.750000, 0.000000, 44.490234, -0.451172, 44.625000, 0.000000, 44.625000, 0.000000, 
+            52.593750, 0.000000, 58.593750, 0.000000, 68.255859, -0.451172, 65.109375, 0.000000, 
+            65.109375, 0.000000, 75.984375, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Hangul" script="hang">
+        <test-font name="LucidaSansRegular.ttf" version="Version 1.20 - October 2000" checksum="0xF5D9BA6D" rchecksum="0x029B644F"/>
+
+        <test-text>마만만</test-text>
+
+        <result-glyphs>
+            0x00000000, 0x0000FFFF, 0x00000000, 0x0000FFFF, 0x0000FFFF, 0x00000000, 0x0000FFFF
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 9.000000, 0.000000, 9.000000, 0.000000, 18.000000, 0.000000, 
+            18.000000, 0.000000, 18.000000, 0.000000, 27.000000, 0.000000, 27.000000, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Hebrew Mark Test" script="hebr">
+        <test-font name="SBL_Hbrw.ttf" version="Version 1.51 Build 001" checksum="0x5126B325" rchecksum="0x00F5C25B"/>
+
+        <test-text>מָשְׁכֵנִיאַחֲרֶיךָנָּרוּצָההֱבִיאַנִיהַמֶּלֶךְחֲדָרָיונָגִילָהוְנִשְׂמְחָהבָּךְנַזְכִּירָהדֹדֶיךָמִיַּיִןמֵישָׁרִיםאֲהֵבוּךָ</test-text>
+
+        <result-glyphs>
+            0x0000FFFF, 0x00000055, 0x0000FFFF, 0x0000004B, 0x0000001D, 0x00000097, 0x00000021, 0x00000094, 
+            0x0000001B, 0x0000002D, 0x00000027, 0x00000096, 0x0000003A, 0x0000009A, 0x0000FFFF, 0x00000066, 
+            0x00000027, 0x00000097, 0x0000002F, 0x00000030, 0x00000096, 0x00000027, 0x00000099, 0x0000FFFF, 
+            0x00000051, 0x00000096, 0x0000002F, 0x0000FFFF, 0x00000055, 0x00000027, 0x00000098, 0x0000001F, 
+            0x0000009C, 0x0000001F, 0x00000021, 0x0000009A, 0x0000003A, 0x00000027, 0x00000096, 0x0000FFFF, 
+            0x00000056, 0x00000092, 0x00000024, 0x00000099, 0x00000031, 0x0000FFFF, 0x00000054, 0x0000009A, 
+            0x0000FFFF, 0x00000043, 0x00000021, 0x0000009A, 0x00000025, 0x00000092, 0x0000002F, 0x00000092, 
+            0x0000FFFF, 0x00000067, 0x00000096, 0x00000031, 0x00000092, 0x00000023, 0x00000021, 0x0000009A, 
+            0x0000002B, 0x00000027, 0x00000096, 0x0000001E, 0x0000009A, 0x00000031, 0x00000023, 0x00000027, 
+            0x0000009A, 0x0000003A, 0x0000009A, 0x0000001F, 0x00000094, 0x00000025, 0x0000FFFF, 0x00000054, 
+            0x00000098, 0x0000002B, 0x00000098, 0x0000FFFF, 0x0000005D, 0x00000099, 0x00000021, 0x00000027, 
+            0x00000096, 0x00000031, 0x00000099, 0x0000001B, 0x00000027, 0x00000096, 0x0000001D, 0x00000093, 
+            0x00000021, 0x00000021, 0x0000009A, 0x00000038, 0x0000FFFF, 0x0000004B, 0x0000003A, 0x0000009A, 
+            0x0000FFFF, 0x0000005E, 0x0000FFFF, 0x00000055, 0x00000027, 0x00000098, 0x0000003A, 0x00000094, 
+            0x00000025, 0x00000099, 0x0000001B, 0x00000027, 0x00000096, 0x00000031, 0x00000097, 0x00000029, 
+            0x00000092, 0x0000FFFF, 0x00000066, 0x0000009A, 0x0000002F
+        </result-glyphs>
+
+        <result-indices>
+            0x0000007C, 0x0000007B, 0x0000007A, 0x00000079, 0x00000078, 0x00000077, 0x00000076, 0x00000075, 
+            0x00000074, 0x00000073, 0x00000072, 0x00000071, 0x00000070, 0x0000006F, 0x0000006E, 0x0000006D, 
+            0x0000006C, 0x0000006B, 0x0000006A, 0x00000069, 0x00000068, 0x00000067, 0x00000066, 0x00000065, 
+            0x00000064, 0x00000063, 0x00000062, 0x00000061, 0x00000060, 0x0000005F, 0x0000005E, 0x0000005D, 
+            0x0000005C, 0x0000005B, 0x0000005A, 0x00000059, 0x00000058, 0x00000057, 0x00000056, 0x00000055, 
+            0x00000054, 0x00000053, 0x00000052, 0x00000051, 0x00000050, 0x0000004F, 0x0000004E, 0x0000004D, 
+            0x0000004C, 0x0000004B, 0x0000004A, 0x00000049, 0x00000048, 0x00000047, 0x00000046, 0x00000045, 
+            0x00000044, 0x00000043, 0x00000042, 0x00000041, 0x00000040, 0x0000003F, 0x0000003E, 0x0000003D, 
+            0x0000003C, 0x0000003B, 0x0000003A, 0x00000039, 0x00000038, 0x00000037, 0x00000036, 0x00000035, 
+            0x00000034, 0x00000033, 0x00000032, 0x00000031, 0x00000030, 0x0000002F, 0x0000002E, 0x0000002D, 
+            0x0000002C, 0x0000002B, 0x0000002A, 0x00000029, 0x00000028, 0x00000027, 0x00000026, 0x00000025, 
+            0x00000024, 0x00000023, 0x00000022, 0x00000021, 0x00000020, 0x0000001F, 0x0000001E, 0x0000001D, 
+            0x0000001C, 0x0000001B, 0x0000001A, 0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015, 
+            0x00000014, 0x00000013, 0x00000012, 0x00000011, 0x00000010, 0x0000000F, 0x0000000E, 0x0000000D, 
+            0x0000000C, 0x0000000B, 0x0000000A, 0x00000009, 0x00000008, 0x00000007, 0x00000006, 0x00000005, 
+            0x00000004, 0x00000003, 0x00000002, 0x00000001, 0x00000000
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 0.000000, 0.000000, 5.806641, 0.000000, 5.806641, 0.000000, 
+            9.087891, 0.000000, 18.679688, 0.000000, 15.251953, 0.000000, 25.365234, 0.000000, 
+            21.878906, 0.000000, 28.787109, 0.000000, 35.191406, 0.000000, 42.966797, 0.000000, 
+            38.279297, 0.000000, 47.982422, 0.000000, 44.085938, 0.000000, 44.085938, 0.000000, 
+            52.347656, 0.000000, 58.453125, 0.000000, 55.113281, 0.000000, 62.021484, 0.000000, 
+            66.292969, 0.000000, 64.886719, 0.000000, 69.292969, 0.000000, 67.886719, 0.000000, 
+            67.886719, 0.000000, 74.050781, 0.000000, 70.710938, 0.000000, 77.619141, 0.000000, 
+            77.619141, 0.000000, 83.425781, 0.000000, 90.527344, 0.000000, 86.513672, 0.000000, 
+            91.804688, 0.000000, 92.390625, 0.000000, 98.267578, 0.000000, 109.347656, 0.000000, 
+            104.894531, 0.000000, 110.701172, 0.000000, 116.250000, 0.000000, 113.701172, 0.000000, 
+            113.554688, 0.000000, 121.242188, 0.000000, 119.484375, 0.000000, 124.552734, 0.000000, 
+            122.677734, 0.000000, 126.679688, 0.000000, 126.679688, 0.000000, 135.210938, 0.000000, 
+            132.486328, 0.000000, 132.251953, 0.000000, 138.416016, 0.000000, 148.734375, 0.000000, 
+            145.042969, 0.000000, 155.308594, 0.000000, 151.968750, 0.000000, 162.773438, 0.000000, 
+            158.876953, 0.000000, 158.876953, 0.000000, 168.398438, 0.000000, 166.523438, 0.000000, 
+            172.546875, 0.000000, 170.525391, 0.000000, 173.689453, 0.000000, 182.718750, 0.000000, 
+            180.199219, 0.000000, 185.583984, 0.000000, 190.107422, 0.000000, 187.998047, 0.000000, 
+            194.132812, 0.000000, 192.257812, 0.000000, 196.259766, 0.000000, 199.423828, 0.000000, 
+            206.964844, 0.000000, 202.511719, 0.000000, 212.332031, 0.000000, 208.318359, 0.000000, 
+            217.886719, 0.000000, 214.195312, 0.000000, 221.121094, 0.000000, 221.121094, 0.000000, 
+            229.447266, 0.000000, 226.927734, 0.000000, 235.652344, 0.000000, 232.312500, 0.000000, 
+            232.312500, 0.000000, 242.648438, 0.000000, 239.220703, 0.000000, 245.847656, 0.000000, 
+            250.195312, 0.000000, 248.320312, 0.000000, 255.808594, 0.000000, 252.322266, 0.000000, 
+            259.230469, 0.000000, 265.042969, 0.000000, 262.083984, 0.000000, 271.675781, 0.000000, 
+            268.248047, 0.000000, 274.875000, 0.000000, 284.197266, 0.000000, 281.501953, 0.000000, 
+            287.250000, 0.000000, 287.250000, 0.000000, 290.531250, 0.000000, 298.212891, 0.000000, 
+            296.337891, 0.000000, 296.337891, 0.000000, 300.339844, 0.000000, 300.339844, 0.000000, 
+            306.146484, 0.000000, 313.687500, 0.000000, 309.234375, 0.000000, 318.732422, 0.000000, 
+            315.041016, 0.000000, 325.453125, 0.000000, 321.966797, 0.000000, 328.875000, 0.000000, 
+            333.222656, 0.000000, 331.347656, 0.000000, 338.044922, 0.000000, 335.349609, 0.000000, 
+            345.175781, 0.000000, 341.279297, 0.000000, 341.279297, 0.000000, 352.558594, 0.000000, 
+            349.218750, 0.000000, 356.126953, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Not Language Specific" script="latn">
+        <test-font name="fp9r8a.otf" version="Version 0.9.6 " checksum="0x62C6805F" rchecksum="0x00813376"/>
+
+        <test-text>Ţhiş iş a ţeşţ.</test-text>
+
+        <result-glyphs>
+            0x00000107, 0x00000049, 0x0000004A, 0x00000104, 0x00000001, 0x0000004A, 0x00000104, 0x00000001, 
+            0x00000042, 0x00000001, 0x00000108, 0x00000046, 0x00000104, 0x00000108, 0x0000000F
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 7.356000, 0.000000, 14.340000, 0.000000, 17.832001, 0.000000, 
+            22.920000, 0.000000, 25.920000, 0.000000, 29.412001, 0.000000, 34.500000, 0.000000, 
+            37.500000, 0.000000, 43.500000, 0.000000, 46.500000, 0.000000, 50.411999, 0.000000, 
+            56.160000, 0.000000, 61.248001, 0.000000, 65.160004, 0.000000, 68.160004, 0.000000
+        </result-positions>
+    </test-case>
+
+<!-- known to fail in base JDK7, skip ('lang' not supported)
+    <test-case id="Romanian Language Specific" script="latn" lang="ROM">
+        <test-font name="fp9r8a.otf" version="Version 0.9.6 " checksum="0x62C6805F" rchecksum="0x00813376"/>
+
+        <test-text>Ţhiş iş a ţeşţ.</test-text>
+
+        <result-glyphs>
+            0x00000127, 0x00000049, 0x0000004A, 0x00000126, 0x00000001, 0x0000004A, 0x00000126, 0x00000001, 
+            0x00000042, 0x00000001, 0x00000128, 0x00000046, 0x00000126, 0x00000128, 0x0000000F
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 7.356000, 0.000000, 14.340000, 0.000000, 17.832001, 0.000000, 
+            22.920000, 0.000000, 25.920000, 0.000000, 29.412001, 0.000000, 34.500000, 0.000000, 
+            37.500000, 0.000000, 43.500000, 0.000000, 46.500000, 0.000000, 50.411999, 0.000000, 
+            56.160000, 0.000000, 61.248001, 0.000000, 65.160004, 0.000000, 68.160004, 0.000000
+        </result-positions>
+    </test-case>
+-->
+
+    <test-case id="Nafees Nastaleeq Cursive Positioning Test" script="arab">
+        <test-font name="Nafees Nastaleeq v1.02.ttf" version="Version 1.02" checksum="0x1BD85538" rchecksum="0x0111F234"/>
+
+        <test-text>فتح بینچ خلیج شیخ پہنچ</test-text>
+
+        <result-glyphs>
+            0x0000003B, 0x00000344, 0x000001D5, 0x00000318, 0x00000349, 0x0000007C, 0x00000003, 0x0000003D, 
+            0x00000348, 0x000001D5, 0x00000346, 0x000000B5, 0x00000003, 0x0000003A, 0x00000348, 0x000001D5, 
+            0x000002E3, 0x00000344, 0x00000087, 0x00000003, 0x0000003B, 0x00000344, 0x000001D5, 0x00000348, 
+            0x000001E5, 0x00000347, 0x0000006E, 0x00000003, 0x0000003C, 0x00000345, 0x000001D5, 0x00000344, 
+            0x0000011D
+        </result-glyphs>
+
+        <result-indices>
+            0x00000015, 0x00000014, 0x00000014, 0x00000013, 0x00000012, 0x00000012, 0x00000011, 0x00000010, 
+            0x0000000F, 0x0000000F, 0x0000000E, 0x0000000E, 0x0000000D, 0x0000000C, 0x0000000B, 0x0000000B, 
+            0x0000000A, 0x00000009, 0x00000009, 0x00000008, 0x00000007, 0x00000006, 0x00000006, 0x00000005, 
+            0x00000005, 0x00000004, 0x00000004, 0x00000003, 0x00000002, 0x00000001, 0x00000001, 0x00000000, 
+            0x00000000
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 3.205078, -11.097656, 1.406250, 0.000000, 4.558594, -1.376953, 
+            9.421875, -5.273438, 7.505859, -6.843750, 11.537109, 0.000000, 12.726562, 0.000000, 
+            20.455078, -4.798828, 15.357422, 0.000000, 19.289062, -13.072266, 18.509766, -1.376953, 
+            22.552734, 0.000000, 23.742188, 0.000000, 30.246094, -4.798828, 25.148438, 0.000000, 
+            28.300781, -1.376953, 32.917969, -13.792969, 30.158203, -7.792969, 35.208984, 0.000000, 
+            36.398438, 0.000000, 39.603516, -11.097656, 37.804688, 0.000000, 45.632812, 3.181641, 
+            40.957031, -1.376953, 44.853516, -6.046875, 42.457031, -5.572266, 46.066406, 0.000000, 
+            47.255859, 0.000000, 49.376953, -11.396484, 48.662109, 0.000000, 52.769531, -14.332031, 
+            51.814453, -1.376953, 56.789062, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Malayalam Samvruthokaram Test" script="mlym">
+        <test-font name="lohit_ml.ttf" version="Version 1.00" checksum="0x66CB0B82" rchecksum="0x002EEBD8"/>
+
+        <test-text>ണു്</test-text>
+
+        <result-glyphs>
+            0x00000023, 0x0000003C, 0x00000045
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 15.117188, 0.000000, 18.503906, 0.000000, 18.503906, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Broken Font Test" script="hani" lang="ZHT">
+        <test-font name="BMIN00M.TTF" version="Version 2.00" checksum="0xF16BE0C6" rchecksum="0x15E106D0"/>
+
+        <test-text>中華人民共和國 臺灣</test-text>
+
+        <result-glyphs>
+            0x00000292, 0x000024E8, 0x000002D1, 0x00001582, 0x000004A1, 0x00000650, 0x000007E2, 0x00000021, 
+            0x00002395, 0x00001896
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 12.000000, 0.000000, 24.000000, 0.000000, 36.000000, 0.000000, 
+            48.000000, 0.000000, 60.000000, 0.000000, 72.000000, 0.000000, 84.000000, 0.000000, 
+            90.000000, 0.000000, 102.000000, 0.000000, 114.000000, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Telugu Syllable Boundary Test" script="telu">
+        <test-font name="gautami.ttf" version="Version 5.02" checksum="0x45C66919" rchecksum="0x00DBFA1A"/>
+
+        <test-text>ప్రకాష్</test-text>
+
+        <result-glyphs>
+            0x00000057, 0x0000023B, 0x0000FFFF, 0x00000125, 0x00000066, 0x00000241, 0x0000FFFF
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000002, 0x00000001, 0x00000003, 0x00000004, 0x00000005, 0x00000006
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 8.285156, 0.000000, 14.894531, 0.000000, 14.894531, 0.000000, 
+            21.503906, 0.000000, 25.136719, 0.000000, 33.421875, 0.000000, 33.421875, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Angsana New Mark Test" script="thai">
+        <test-font name="ANGSA.TTF" version="Version 5.00" checksum="0x95F16337" rchecksum="0x00724BC4"/>
+
+        <test-text>บทที่๑พายุไซโคลนโดโรธีอาศัยอยู่ท่ามกลางทุ่งใหญ่ในแคนซัสกับลุงเฮนรีชาวไร่และป้าเอ็มภรรยาชาวไร่บ้านของพวกเขาหลังเล็กเพราะไม้สร้างบ้านต้องขนมาด้วยเกวียนเป็นระยะทางหลายไมล์</test-text>
+
+        <result-glyphs>
+            0x0000009D, 0x0000009A, 0x0000009A, 0x000000B8, 0x000000C9, 0x000000D2, 0x000000A1, 0x000000B5, 
+            0x000000A5, 0x000000BB, 0x000000C5, 0x0000008E, 0x000000C3, 0x00000087, 0x000000A8, 0x0000009C, 
+            0x000000C3, 0x00000097, 0x000000C3, 0x000000A6, 0x0000009B, 0x000000B8, 0x000000B0, 0x000000B5, 
+            0x000000AB, 0x000000B4, 0x000000A5, 0x000000B0, 0x000000A5, 0x000000BC, 0x0000006E, 0x0000009A, 
+            0x0000006E, 0x000000B5, 0x000000A4, 0x00000084, 0x000000A8, 0x000000B5, 0x0000008A, 0x0000009A, 
+            0x000000BB, 0x0000006E, 0x0000008A, 0x000000C4, 0x000000AE, 0x00000090, 0x0000006E, 0x000000C4, 
+            0x0000009C, 0x000000C2, 0x00000087, 0x0000009C, 0x0000008E, 0x000000B4, 0x000000AD, 0x00000084, 
+            0x000000B4, 0x0000009D, 0x000000A8, 0x000000BB, 0x0000008A, 0x000000C1, 0x000000B1, 0x0000009C, 
+            0x000000A6, 0x000000B8, 0x0000008D, 0x000000B5, 0x000000AA, 0x000000C5, 0x000000A6, 0x0000006E, 
+            0x000000C2, 0x000000A8, 0x000000B3, 0x0000009E, 0x0000006F, 0x000000B5, 0x000000C1, 0x000000B0, 
+            0x000000C8, 0x000000A4, 0x000000A3, 0x000000A6, 0x000000A6, 0x000000A5, 0x000000B5, 0x0000008D, 
+            0x000000B5, 0x000000AA, 0x000000C5, 0x000000A6, 0x0000006E, 0x0000009D, 0x0000006F, 0x000000B5, 
+            0x0000009C, 0x00000085, 0x000000B0, 0x0000008A, 0x000000A1, 0x000000AA, 0x00000084, 0x000000C1, 
+            0x00000085, 0x000000B5, 0x000000AE, 0x000000A8, 0x000000B4, 0x0000008A, 0x000000C1, 0x000000A8, 
+            0x000000C8, 0x00000084, 0x000000C1, 0x000000A1, 0x000000A6, 0x000000B5, 0x000000B3, 0x000000C5, 
+            0x000000A4, 0x0000006F, 0x000000AD, 0x000000A6, 0x0000006F, 0x000000B5, 0x0000008A, 0x0000009D, 
+            0x0000006F, 0x000000B5, 0x0000009C, 0x00000098, 0x0000006F, 0x000000B0, 0x0000008A, 0x00000085, 
+            0x0000009C, 0x000000A4, 0x000000B5, 0x00000097, 0x0000006F, 0x000000AA, 0x000000A5, 0x000000C1, 
+            0x00000084, 0x000000AA, 0x000000B8, 0x000000A5, 0x0000009C, 0x000000C1, 0x0000009E, 0x000000C8, 
+            0x0000009C, 0x000000A6, 0x000000B3, 0x000000A5, 0x000000B3, 0x0000009A, 0x000000B5, 0x0000008A, 
+            0x000000AE, 0x000000A8, 0x000000B5, 0x000000A5, 0x000000C5, 0x000000A4, 0x000000A8, 0x00000072
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F, 
+            0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017, 
+            0x00000018, 0x00000019, 0x0000001A, 0x0000001B, 0x0000001C, 0x0000001D, 0x0000001E, 0x0000001F, 
+            0x00000020, 0x00000021, 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x00000026, 0x00000027, 
+            0x00000028, 0x00000029, 0x0000002A, 0x0000002B, 0x0000002C, 0x0000002D, 0x0000002E, 0x0000002F, 
+            0x00000030, 0x00000031, 0x00000032, 0x00000033, 0x00000034, 0x00000035, 0x00000036, 0x00000037, 
+            0x00000038, 0x00000039, 0x0000003A, 0x0000003B, 0x0000003C, 0x0000003D, 0x0000003E, 0x0000003F, 
+            0x00000040, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 
+            0x00000048, 0x00000049, 0x0000004A, 0x0000004B, 0x0000004C, 0x0000004D, 0x0000004E, 0x0000004F, 
+            0x00000050, 0x00000051, 0x00000052, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 
+            0x00000058, 0x00000059, 0x0000005A, 0x0000005B, 0x0000005C, 0x0000005D, 0x0000005E, 0x0000005F, 
+            0x00000060, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 
+            0x00000068, 0x00000069, 0x0000006A, 0x0000006B, 0x0000006C, 0x0000006D, 0x0000006E, 0x0000006F, 
+            0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 
+            0x00000078, 0x00000079, 0x0000007A, 0x0000007B, 0x0000007C, 0x0000007D, 0x0000007E, 0x0000007F, 
+            0x00000080, 0x00000081, 0x00000082, 0x00000083, 0x00000084, 0x00000085, 0x00000086, 0x00000087, 
+            0x00000088, 0x00000089, 0x0000008A, 0x0000008B, 0x0000008C, 0x0000008D, 0x0000008E, 0x0000008F, 
+            0x00000090, 0x00000091, 0x00000092, 0x00000093, 0x00000094, 0x00000095, 0x00000096, 0x00000097, 
+            0x00000098, 0x00000099, 0x0000009A, 0x0000009B, 0x0000009C, 0x0000009D, 0x0000009E, 0x0000009F, 
+            0x000000A0, 0x000000A1, 0x000000A2, 0x000000A3, 0x000000A4, 0x000000A5, 0x000000A6, 0x000000A7
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 5.399414, 0.000000, 10.798828, 0.000000, 15.072266, 0.000000, 
+            15.072266, 0.000000, 16.198242, 0.000000, 21.046875, 0.000000, 26.616211, 0.000000, 
+            30.035156, 0.000000, 31.312500, 0.000000, 34.151367, 0.000000, 38.279297, 0.000000, 
+            43.558594, 0.000000, 47.663086, 0.000000, 52.438477, 0.000000, 57.178711, 0.000000, 
+            62.698242, 0.000000, 66.802734, 0.000000, 71.601562, 0.000000, 75.706055, 0.000000, 
+            79.810547, 0.000000, 84.029297, 0.000000, 84.369141, 0.000000, 89.097656, 0.000000, 
+            92.516602, 0.000000, 97.614258, 0.000000, 97.195312, 0.000000, 101.311523, 0.000000, 
+            106.040039, 0.000000, 107.375977, 0.000000, 108.326172, -0.084961, 110.156250, 0.000000, 
+            113.497070, -0.084961, 115.555664, 0.000000, 118.974609, 0.000000, 124.013672, 0.000000, 
+            128.765625, 0.000000, 133.505859, 0.000000, 136.924805, 0.000000, 140.704102, 0.000000, 
+            143.036133, 0.000000, 144.044922, -0.084961, 146.103516, 0.000000, 149.882812, 0.000000, 
+            153.553711, 0.000000, 159.158203, 0.000000, 163.377930, -0.084961, 165.421875, 0.000000, 
+            169.092773, 0.000000, 174.612305, 0.000000, 179.135742, 0.000000, 183.911133, 0.000000, 
+            189.430664, 0.000000, 194.879883, 0.000000, 194.709961, 0.000000, 199.989258, 0.000000, 
+            204.092773, -0.084961, 204.741211, 0.000000, 210.140625, 0.000000, 212.828125, 0.000000, 
+            214.880859, 0.000000, 218.660156, 0.000000, 220.675781, 0.000000, 225.128906, 0.000000, 
+            230.648438, 0.000000, 234.105469, 0.000000, 234.752930, 0.000000, 239.613281, 0.000000, 
+            243.032227, 0.000000, 247.280273, 0.000000, 251.408203, 0.000000, 253.932617, -0.084961, 
+            255.512695, 0.000000, 260.036133, 0.000000, 264.776367, 0.000000, 269.071289, 0.000000, 
+            272.704102, 0.000000, 274.470703, 0.000000, 277.889648, 0.000000, 279.905273, 0.000000, 
+            284.768555, 0.000000, 284.633789, 0.000000, 289.672852, 0.000000, 294.641602, 0.000000, 
+            298.746094, 0.000000, 302.850586, 0.000000, 306.966797, 0.000000, 310.385742, 0.000000, 
+            315.246094, 0.000000, 318.665039, 0.000000, 322.913086, 0.000000, 327.041016, 0.000000, 
+            329.565430, -0.084961, 331.145508, 0.000000, 335.911133, 0.000000, 336.544922, 0.000000, 
+            339.963867, 0.000000, 345.483398, 0.000000, 350.258789, 0.000000, 354.987305, 0.000000, 
+            358.766602, 0.000000, 364.335938, 0.000000, 368.583984, 0.000000, 373.335938, 0.000000, 
+            375.351562, 0.000000, 380.126953, 0.000000, 383.545898, 0.000000, 389.150391, 0.000000, 
+            394.306641, 0.000000, 393.890625, 0.000000, 397.669922, 0.000000, 399.685547, 0.000000, 
+            404.548828, 0.000000, 404.425781, 0.000000, 409.177734, 0.000000, 411.193359, 0.000000, 
+            416.762695, 0.000000, 420.867188, 0.000000, 424.286133, 0.000000, 428.581055, 0.000000, 
+            432.708984, 0.000000, 438.123047, 0.000000, 437.748047, 0.000000, 443.027344, 0.000000, 
+            446.976562, 0.000000, 447.131836, 0.000000, 450.550781, 0.000000, 454.330078, 0.000000, 
+            459.095703, 0.000000, 459.729492, 0.000000, 463.148438, 0.000000, 468.667969, 0.000000, 
+            473.847656, 0.000000, 473.478516, 0.000000, 478.207031, 0.000000, 481.986328, 0.000000, 
+            486.761719, 0.000000, 492.281250, 0.000000, 497.320312, 0.000000, 500.739258, 0.000000, 
+            505.860352, 0.000000, 505.538086, 0.000000, 509.786133, 0.000000, 513.902344, 0.000000, 
+            515.917969, 0.000000, 520.669922, 0.000000, 523.947266, 0.000000, 524.917969, 0.000000, 
+            529.034180, 0.000000, 534.553711, 0.000000, 536.569336, 0.000000, 540.846680, 0.000000, 
+            541.968750, 0.000000, 547.488281, 0.000000, 551.592773, 0.000000, 555.887695, 0.000000, 
+            560.003906, 0.000000, 564.298828, 0.000000, 569.698242, 0.000000, 573.117188, 0.000000, 
+            576.896484, 0.000000, 582.500977, 0.000000, 587.241211, 0.000000, 590.660156, 0.000000, 
+            594.776367, 0.000000, 598.904297, 0.000000, 603.943359, 0.000000, 608.894531, 0.000000, 
+            608.683594, 0.000000
+        </result-positions>
+    </test-case>
+
+<!-- known to fail in base JDK7, skip  (come back to this later)
+    <test-case id="Sinhala Al-Lakuna Test" script="sinh">
+        <test-font name="lklug.hj.ttf" version="Version 0.6 " checksum="0xA190C2F4" rchecksum="0x00922218"/>
+
+        <test-text>ක්‍රෙ ක්‍යෙ ක්‍ෂෙ ක්‍ෂ්‍යෙ ක්ෂෙ කර්‍මෙ ස්ට්‍රේ ස‍්සෙ ස්ස</test-text>
+
+        <result-glyphs>
+            0x0000004A, 0x000001D5, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x00000003, 0x0000004A, 0x00000018, 
+            0x0000008B, 0x0000FFFF, 0x0000FFFF, 0x00000003, 0x0000004A, 0x0000008A, 0x0000FFFF, 0x0000FFFF, 
+            0x0000FFFF, 0x00000003, 0x0000004A, 0x0000008A, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000008B, 
+            0x0000FFFF, 0x0000FFFF, 0x00000003, 0x000001D6, 0x0000FFFF, 0x0000004A, 0x0000003C, 0x00000003, 
+            0x00000018, 0x0000004A, 0x000001F8, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x00000003, 0x000000A9, 
+            0x0000FFFF, 0x0000004A, 0x0000007A, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x00000003, 
+            0x0000004A, 0x00000203, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x00000003, 0x000000A9, 0x0000FFFF, 
+            0x0000003D
+        </result-glyphs>
+
+        <result-indices>
+            0x00000004, 0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000005, 0x0000000A, 0x00000006, 
+            0x00000007, 0x00000008, 0x00000009, 0x0000000B, 0x00000010, 0x0000000C, 0x0000000D, 0x0000000E, 
+            0x0000000F, 0x00000011, 0x00000019, 0x00000012, 0x00000013, 0x00000014, 0x00000015, 0x00000016, 
+            0x00000017, 0x00000018, 0x0000001A, 0x0000001B, 0x0000001C, 0x0000001E, 0x0000001D, 0x0000001F, 
+            0x00000020, 0x00000025, 0x00000021, 0x00000022, 0x00000023, 0x00000024, 0x00000026, 0x00000027, 
+            0x00000028, 0x0000002D, 0x00000029, 0x0000002A, 0x0000002B, 0x0000002C, 0x0000002D, 0x0000002E, 
+            0x00000033, 0x0000002F, 0x00000030, 0x00000031, 0x00000032, 0x00000034, 0x00000035, 0x00000036, 
+            0x00000037
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 8.520000, 0.000000, 19.224001, 0.000000, 19.224001, 0.000000, 
+            19.224001, 0.000000, 19.224001, 0.000000, 26.640001, 0.000000, 35.160004, 0.000000, 
+            45.864006, 0.000000, 51.936005, 0.000000, 51.936005, 0.000000, 51.936005, 0.000000, 
+            59.352005, 0.000000, 67.872009, 0.000000, 82.704010, 0.000000, 82.704010, 0.000000, 
+            82.704010, 0.000000, 82.704010, 0.000000, 90.120010, 0.000000, 98.640015, 0.000000, 
+            113.472015, 0.000000, 113.472015, 0.000000, 113.472015, 0.000000, 113.472015, 0.000000, 
+            119.544014, 0.000000, 119.544014, 0.000000, 119.544014, 0.000000, 126.960014, 0.000000, 
+            137.664017, 0.000000, 137.664017, 0.000000, 146.184021, 0.000000, 154.296021, 0.000000, 
+            161.712021, 0.000000, 172.416016, 0.000000, 180.936020, 0.000000, 189.552017, 0.000000, 
+            189.552017, 0.000000, 189.552017, 0.000000, 189.552017, 0.000000, 196.968018, 0.000000, 
+            205.584015, 0.000000, 205.584015, 0.000000, 214.104019, 0.000000, 222.720016, 0.000000, 
+            222.720016, 0.000000, 222.720016, 0.000000, 222.720016, 0.000000, 222.720016, 0.000000, 
+            230.136017, 0.000000, 238.656021, 0.000000, 254.784027, 0.000000, 254.784027, 0.000000, 
+            254.784027, 0.000000, 254.784027, 0.000000, 262.200012, 0.000000, 270.816010, 0.000000, 
+            270.816010, 0.000000, 279.432007, 0.000000
+        </result-positions>
+    </test-case>
+-->
+
+    <test-case id="Arabic Presentation Forms LRO Test" script="arab">
+        <test-font name="trado.ttf" version="Version 1.01" checksum="0x7B68B462" rchecksum="0x00708871"/>
+
+        <test-text>‭ﻲﺑﺮﻌﻟﺎﺑ</test-text>
+
+        <result-glyphs>
+            0x0000FFFF, 0x00000206, 0x000001A5, 0x000001C2, 0x000001E0, 0x000001F3, 0x000001A2, 0x000001A5
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 0.000000, 0.000000, 5.759766, 0.000000, 7.980469, 0.000000, 
+            11.748047, 0.000000, 15.298828, 0.000000, 17.302734, 0.000000, 19.763672, 0.000000, 
+            21.984375, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Arabic Presentation Forms No LRO Test" script="arab">
+        <test-font name="trado.ttf" version="Version 1.01" checksum="0x7B68B462" rchecksum="0x00708871"/>
+
+        <test-text>ﻲﺑﺮﻌﻟﺎﺑ</test-text>
+
+        <result-glyphs>
+            0x000001A5, 0x000001A2, 0x000001F3, 0x000001E0, 0x000001C2, 0x000001A5, 0x00000206
+        </result-glyphs>
+
+        <result-indices>
+            0x00000006, 0x00000005, 0x00000004, 0x00000003, 0x00000002, 0x00000001, 0x00000000
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 2.220703, 0.000000, 4.681641, 0.000000, 6.685547, 0.000000, 
+            10.236328, 0.000000, 14.003906, 0.000000, 16.224609, 0.000000, 21.984375, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Canonical Char Indices Test" script="latn">
+        <test-font name="arial.ttf" version="Version 5.01.2x" checksum="0x92F28CF6" rchecksum="0x02CF4C8A"/>
+
+        <test-text>ḤḤ</test-text>
+
+        <result-glyphs>
+            0x000009A3, 0x000009A3
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 8.666016, 0.000000, 17.332031, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="REPH ZWNJ Test" script="deva">
+        <test-font name="raghu.ttf" version="Original Version 1.00 (2005)" checksum="0x088DB135" rchecksum="0x00803FCE"/>
+
+        <test-text>र्य र्‌य</test-text>
+
+        <result-glyphs>
+            0x00000099, 0x0000005B, 0x0000FFFF, 0x00000003, 0x0000009A, 0x00000051, 0x00000001, 0x00000099
+        </result-glyphs>
+
+        <result-indices>
+            0x00000002, 0x00000000, 0x00000001, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 9.726562, 0.263672, 9.468750, 0.000000, 9.468750, 0.000000, 
+            15.468750, 0.000000, 25.130859, -0.451172, 21.984375, 0.000000, 21.984375, 0.000000, 
+            31.453125, 0.000000
+        </result-positions>
+    </test-case>
+
+<!-- known to fail in base JDK7, skip  ( won't load, 'bad font name' )
+    <test-case id="AppleChancery mort" script="latn">
+        <test-font name="Apple Chancery.ttf" version="6.1d4e1" checksum="0xC01C5902" rchecksum="0x014278BD"/>
+
+        <test-text>The quick brown fox jumps over the lazy dog. • Jackdaws love my big sphinx of quartz</test-text>
+
+        <result-glyphs>
+            0x00000157, 0x0000FFFF, 0x00000048, 0x00000003, 0x00000054, 0x00000058, 0x0000004C, 0x00000046, 
+            0x0000004E, 0x00000003, 0x00000045, 0x00000055, 0x00000052, 0x0000005A, 0x00000051, 0x00000003, 
+            0x00000049, 0x00000052, 0x0000005B, 0x00000003, 0x0000004D, 0x00000058, 0x00000050, 0x00000053, 
+            0x00000056, 0x00000003, 0x00000052, 0x00000059, 0x00000048, 0x00000055, 0x00000003, 0x00000152, 
+            0x0000FFFF, 0x00000048, 0x00000003, 0x0000004F, 0x00000044, 0x0000005D, 0x0000005C, 0x00000003, 
+            0x00000047, 0x00000052, 0x0000004A, 0x00000011, 0x00000003, 0x00000087, 0x00000003, 0x0000002D, 
+            0x00000044, 0x00000046, 0x0000004E, 0x00000047, 0x00000044, 0x0000005A, 0x00000056, 0x00000003, 
+            0x0000004F, 0x00000052, 0x00000059, 0x00000048, 0x00000003, 0x00000050, 0x0000005C, 0x00000003, 
+            0x00000045, 0x0000004C, 0x0000004A, 0x00000003, 0x00000056, 0x00000053, 0x0000004B, 0x0000004C, 
+            0x00000051, 0x0000005B, 0x00000003, 0x00000052, 0x00000049, 0x00000003, 0x00000054, 0x00000058, 
+            0x00000044, 0x00000055, 0x00000057, 0x0000005D
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F, 
+            0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017, 
+            0x00000018, 0x00000019, 0x0000001A, 0x0000001B, 0x0000001C, 0x0000001D, 0x0000001E, 0x0000001F, 
+            0x00000020, 0x00000021, 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x00000026, 0x00000027, 
+            0x00000028, 0x00000029, 0x0000002A, 0x0000002B, 0x0000002C, 0x0000002D, 0x0000002E, 0x0000002F, 
+            0x00000030, 0x00000031, 0x00000032, 0x00000033, 0x00000034, 0x00000035, 0x00000036, 0x00000037, 
+            0x00000038, 0x00000039, 0x0000003A, 0x0000003B, 0x0000003C, 0x0000003D, 0x0000003E, 0x0000003F, 
+            0x00000040, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 
+            0x00000048, 0x00000049, 0x0000004A, 0x0000004B, 0x0000004C, 0x0000004D, 0x0000004E, 0x0000004F, 
+            0x00000050, 0x00000051, 0x00000052, 0x00000053
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 13.523438, 0.000000, 13.523438, 0.000000, 17.982422, 0.000000, 
+            21.316406, 0.000000, 27.134766, 0.000000, 33.861328, 0.000000, 37.412109, 0.000000, 
+            42.005859, 0.000000, 47.554688, 0.000000, 50.888672, 0.000000, 56.707031, 0.000000, 
+            61.705078, 0.000000, 66.849609, 0.000000, 74.378906, 0.000000, 81.152344, 0.000000, 
+            84.486328, 0.000000, 88.230469, 0.000000, 93.375000, 0.000000, 99.386719, 0.000000, 
+            102.720703, 0.000000, 105.914062, 0.000000, 112.640625, 0.000000, 122.109375, 0.000000, 
+            128.080078, 0.000000, 132.345703, 0.000000, 135.679688, 0.000000, 140.824219, 0.000000, 
+            146.232422, 0.000000, 150.691406, 0.000000, 155.689453, 0.000000, 159.023438, 0.000000, 
+            168.908203, 0.000000, 168.908203, 0.000000, 173.367188, 0.000000, 176.701172, 0.000000, 
+            179.900391, 0.000000, 186.058594, 0.000000, 190.998047, 0.000000, 197.501953, 0.000000, 
+            200.835938, 0.000000, 206.994141, 0.000000, 212.138672, 0.000000, 217.734375, 0.000000, 
+            220.212891, 0.000000, 223.546875, 0.000000, 230.214844, 0.000000, 233.548828, 0.000000, 
+            239.003906, 0.000000, 245.162109, 0.000000, 249.755859, 0.000000, 255.304688, 0.000000, 
+            261.462891, 0.000000, 267.621094, 0.000000, 275.150391, 0.000000, 279.416016, 0.000000, 
+            282.750000, 0.000000, 285.949219, 0.000000, 291.093750, 0.000000, 296.501953, 0.000000, 
+            300.960938, 0.000000, 304.294922, 0.000000, 313.763672, 0.000000, 320.267578, 0.000000, 
+            323.601562, 0.000000, 329.419922, 0.000000, 332.970703, 0.000000, 338.566406, 0.000000, 
+            341.900391, 0.000000, 346.166016, 0.000000, 352.136719, 0.000000, 358.523438, 0.000000, 
+            362.074219, 0.000000, 368.847656, 0.000000, 374.859375, 0.000000, 378.193359, 0.000000, 
+            383.337891, 0.000000, 387.082031, 0.000000, 390.416016, 0.000000, 396.234375, 0.000000, 
+            402.960938, 0.000000, 409.119141, 0.000000, 414.117188, 0.000000, 418.365234, 0.000000, 
+            423.304688, 0.000000
+        </result-positions>
+    </test-case>
+-->
+
+<!-- known to fail in base JDK7, skip  ( won't load, 'bad font name') 
+    <test-case id="Zapfino morx" script="latn">
+        <test-font name="Zapfino.ttf" version="8.0d1e1" checksum="0x78FF7638" rchecksum="0x00EDBCB6"/>
+
+        <test-text>Pack my bags with six dozen liquor jugs</test-text>
+
+        <result-glyphs>
+            0x00000040, 0x000001F8, 0x00000203, 0x00000230, 0x00000003, 0x00000239, 0x00000274, 0x00000003, 
+            0x000001FE, 0x000001F8, 0x0000021D, 0x00000255, 0x00000003, 0x0000026C, 0x00000228, 0x0000025C, 
+            0x00000223, 0x00000003, 0x00000255, 0x00000228, 0x00000270, 0x00000003, 0x00000207, 0x00000244, 
+            0x0000027A, 0x00000210, 0x0000023D, 0x00000003, 0x00000235, 0x00000228, 0x0000024D, 0x00000264, 
+            0x00000244, 0x00000251, 0x00000003, 0x0000022C, 0x00000264, 0x0000021D, 0x00000255
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F, 
+            0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017, 
+            0x00000018, 0x00000019, 0x0000001A, 0x0000001B, 0x0000001C, 0x0000001D, 0x0000001E, 0x0000001F, 
+            0x00000020, 0x00000021, 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x00000026
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 12.630000, 0.000000, 21.180000, 0.000000, 27.600000, 0.000000, 
+            36.599998, 0.000000, 42.599998, 0.000000, 53.160000, 0.000000, 59.970001, 0.000000, 
+            65.970001, 0.000000, 73.620003, 0.000000, 82.170006, 0.000000, 89.370003, 0.000000, 
+            94.740005, 0.000000, 100.740005, 0.000000, 112.050003, 0.000000, 117.480003, 0.000000, 
+            123.420006, 0.000000, 131.400009, 0.000000, 137.400009, 0.000000, 142.770004, 0.000000, 
+            148.199997, 0.000000, 155.699997, 0.000000, 161.699997, 0.000000, 169.830002, 0.000000, 
+            177.330002, 0.000000, 184.020004, 0.000000, 190.169998, 0.000000, 198.000000, 0.000000, 
+            204.000000, 0.000000, 210.089996, 0.000000, 215.519989, 0.000000, 223.229996, 0.000000, 
+            230.940002, 0.000000, 238.440002, 0.000000, 244.290009, 0.000000, 250.290009, 0.000000, 
+            256.140015, 0.000000, 263.850006, 0.000000, 271.050018, 0.000000, 276.420013, 0.000000
+        </result-positions>
+    </test-case>
+-->
+
+    <test-case id="SourceCodePro-Regular.otf" script="latn">
+        <test-font name="SourceCodePro-Regular.otf" version="Version 1.009;PS 1.000;hotconv 1.0.70;makeotf.lib2.5.5900" checksum="0x9EFE425F" rchecksum="0x0074AEC5"/>
+
+        <test-text>Li kien kien, li kieku kieku.</test-text>
+
+        <result-glyphs>
+            0x0000000D, 0x00000024, 0x00000001, 0x00000026, 0x00000024, 0x00000020, 0x00000029, 0x00000001, 
+            0x00000026, 0x00000024, 0x00000020, 0x00000029, 0x000001D0, 0x00000001, 0x00000027, 0x00000024, 
+            0x00000001, 0x00000026, 0x00000024, 0x00000020, 0x00000026, 0x00000030, 0x00000001, 0x00000026, 
+            0x00000024, 0x00000020, 0x00000026, 0x00000030, 0x000001CF
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F, 
+            0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017, 
+            0x00000018, 0x00000019, 0x0000001A, 0x0000001B, 0x0000001C
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 7.200000, 0.000000, 14.400000, 0.000000, 21.599998, 0.000000, 
+            28.799999, 0.000000, 36.000000, 0.000000, 43.200001, 0.000000, 50.400002, 0.000000, 
+            57.600002, 0.000000, 64.800003, 0.000000, 72.000000, 0.000000, 79.199997, 0.000000, 
+            86.399994, 0.000000, 93.599991, 0.000000, 100.799988, 0.000000, 107.999985, 0.000000, 
+            115.199982, 0.000000, 122.399979, 0.000000, 129.599976, 0.000000, 136.799973, 0.000000, 
+            143.999969, 0.000000, 151.199966, 0.000000, 158.399963, 0.000000, 165.599960, 0.000000, 
+            172.799957, 0.000000, 179.999954, 0.000000, 187.199951, 0.000000, 194.399948, 0.000000, 
+            201.599945, 0.000000, 208.799942, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="SourceSansPro-Regular.otf" script="latn">
+        <test-font name="SourceSansPro-Regular.otf" version="Version 1.036;PS 1.000;hotconv 1.0.70;makeotf.lib2.5.5900" checksum="0x0EDDDCF3" rchecksum="0x008F9D5C"/>
+
+        <test-text>Il-Mistoqsija oħt l-għerf.</test-text>
+
+        <result-glyphs>
+            0x0000000A, 0x00000027, 0x00000210, 0x0000000E, 0x00000024, 0x0000002E, 0x0000002F, 0x0000002A, 
+            0x0000002C, 0x0000002E, 0x00000024, 0x00000025, 0x0000001C, 0x00000001, 0x0000002A, 0x0000011F, 
+            0x0000002F, 0x00000001, 0x00000027, 0x00000210, 0x00000022, 0x0000011F, 0x00000020, 0x0000002D, 
+            0x00000021, 0x000001FB
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F, 
+            0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017, 
+            0x00000018, 0x00000019
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 3.096000, 0.000000, 6.156000, 0.000000, 9.888000, 0.000000, 
+            18.552000, 0.000000, 21.504000, 0.000000, 26.532000, 0.000000, 30.467999, 0.000000, 
+            36.972000, 0.000000, 43.571999, 0.000000, 48.599998, 0.000000, 51.551998, 0.000000, 
+            54.515999, 0.000000, 60.660000, 0.000000, 63.084000, 0.000000, 69.587997, 0.000000, 
+            76.115997, 0.000000, 80.171997, 0.000000, 82.596001, 0.000000, 85.655998, 0.000000, 
+            89.388000, 0.000000, 95.435997, 0.000000, 101.963997, 0.000000, 107.916000, 0.000000, 
+            112.080002, 0.000000, 114.984001, 0.000000, 117.972000, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Tibetan" script="tibt">
+        <test-font name="Jomolhari-alpha3c-0605331.ttf" version="Version alpha 0.003c 2006" checksum="0x0C1F08DC" rchecksum="0x067378EF"/>
+
+        <test-text>༄༅།། ཏིན་ཏིན་གྱི་དཔའ་རྩལ</test-text>
+
+        <result-glyphs>
+            0x00000145, 0x0000FFFF, 0x00000151, 0x00000151, 0x00000003, 0x0000046C, 0x00000BFD, 0x0000059A, 
+            0x0000014E, 0x0000046C, 0x00000BFD, 0x0000059A, 0x0000014E, 0x000002CA, 0x0000FFFF, 0x00000BFD, 
+            0x0000014E, 0x0000050E, 0x00000611, 0x00000848, 0x0000014E, 0x0000093C, 0x0000FFFF, 0x0000098B
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F, 
+            0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 14.906250, 0.000000, 14.906250, 0.000000, 17.648438, 0.000000, 
+            20.390625, 0.000000, 23.906250, 0.000000, 29.109375, 0.000000, 29.109375, 0.000000, 
+            34.171875, 0.000000, 35.929688, 0.000000, 41.132812, 0.000000, 41.132812, 0.000000, 
+            46.195312, 0.000000, 47.953125, 0.000000, 54.773438, 0.000000, 54.773438, 0.000000, 
+            54.773438, 0.000000, 56.531250, 0.000000, 61.875000, 0.000000, 67.570312, 0.000000, 
+            73.195312, 0.000000, 74.953125, 0.000000, 80.437500, 0.000000, 80.437500, 0.000000, 
+            87.328125, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="Old Hangul" script="hang">
+        <test-font name="UnBatangOdal.ttf" version="Version 1.00" checksum="0x4BA78B70" rchecksum="0x0A18D67F"/>
+
+        <test-text>ᄊᆞᆷ ᄒᆞᆫ글 ᄀᆞᇹ ᄫᆞᆼ</test-text>
+
+        <result-glyphs>
+            0x000044FF, 0x00004707, 0x00004859, 0x00000005, 0x0000462B, 0x00004707, 0x00004785, 0x000019B2, 
+            0x00000005, 0x00004361, 0x00004707, 0x0000498D, 0x00000005, 0x000044C3, 0x00004707, 0x00004911
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 12.000000, 0.000000, 12.000000, 0.000000, 12.000000, 0.000000, 
+            14.700000, 0.000000, 26.700001, 0.000000, 26.700001, 0.000000, 26.700001, 0.000000, 
+            38.700001, 0.000000, 41.400002, 0.000000, 53.400002, 0.000000, 53.400002, 0.000000, 
+            53.400002, 0.000000, 56.100002, 0.000000, 68.100006, 0.000000, 68.100006, 0.000000, 
+            68.100006, 0.000000
+        </result-positions>
+    </test-case>
+
+    <test-case id="DevaRotate" script="deva">
+        <test-font name="LucidaSansRegular.ttf" version="Version 1.20 - October 2000" checksum="0xF5D9BA6D" rchecksum="0x029B644F"/>
+
+        <test-text>के े</test-text>
+
+        <result-glyphs>
+            0x00000901, 0x00000931, 0x00000003, 0x00000956, 0x00000931
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000003
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 5.935547, 0.000000, 8.548828, 0.000000, 12.345703, 0.000000, 
+            17.085938, 0.000000, 18.345703, 0.000000
+        </result-positions>
+    </test-case>
+
+
+    <test-case id="DevaGASP" script="deva">
+        <test-font name="LucidaSansRegular.ttf" version="Version 1.20 - October 2000" checksum="0xF5D9BA6D" rchecksum="0x029B644F"/>
+
+        <test-text>अँग्रेज़ी</test-text>
+
+        <result-glyphs>
+            0x000008F1, 0x000008EE, 0x000009CB, 0x0000FFFF, 0x0000FFFF, 0x00000931, 0x00000940, 0x0000FFFF, 
+            0x0000092A
+        </result-glyphs>
+
+        <result-indices>
+            0x00000000, 0x00000001, 0x00000002, 0x00000004, 0x00000003, 0x00000005, 0x00000006, 0x00000007, 
+            0x00000008
+        </result-indices>
+
+        <result-positions>
+            0.000000, 0.000000, 9.076172, 0.000000, 9.076172, 0.000000, 16.025391, 0.000000, 
+            16.025391, 0.000000, 16.025391, 0.000000, 16.025391, 0.000000, 23.976562, 0.000000, 
+            23.976562, 0.000000, 27.304688, 0.000000
+        </result-positions>
+    </test-case>
+
+</layout-tests>
diff --git a/test/java/awt/font/TextLayout/VisibleAdvance.java b/test/java/awt/font/TextLayout/VisibleAdvance.java
index c0ed438..4598dfd 100644
--- a/test/java/awt/font/TextLayout/VisibleAdvance.java
+++ b/test/java/awt/font/TextLayout/VisibleAdvance.java
@@ -29,7 +29,7 @@
 
 /* @test
  * @summary verify TextLine advance
- * @bug 6582460
+ * @bug 6582460 8164818
  */
 
 /*
diff --git a/test/java/awt/hidpi/properties/HiDPIPropertiesWindowsTest.java b/test/java/awt/hidpi/properties/HiDPIPropertiesWindowsTest.java
new file mode 100644
index 0000000..7feb722
--- /dev/null
+++ b/test/java/awt/hidpi/properties/HiDPIPropertiesWindowsTest.java
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import java.awt.Dialog;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
+import javax.swing.UIManager;
+
+/* @test
+ * @bug 8073320
+ * @summary  Windows HiDPI support
+ * @author Alexander Scherbatiy
+ * @requires (os.family == "windows")
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=false
+ *                   -Dsun.java2d.win.uiScaleX=3 -Dsun.java2d.win.uiScaleY=2
+ *                    HiDPIPropertiesWindowsTest UISCALE_DISABLED
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=false
+ *                   -Dsun.java2d.uiScale=3
+ *                    HiDPIPropertiesWindowsTest UISCALE_DISABLED
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=false
+ *                   -Dsun.java2d.uiScale=3
+ *                   -Dsun.java2d.win.uiScaleX=5 -Dsun.java2d.win.uiScaleY=6
+ *                    HiDPIPropertiesWindowsTest UISCALE_DISABLED
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ *                   -Dsun.java2d.uiScale=3
+ *                    HiDPIPropertiesWindowsTest UISCALE_3
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ *                   -Dsun.java2d.uiScale=4
+ *                   -Dsun.java2d.win.uiScaleX=2 -Dsun.java2d.win.uiScaleY=3
+ *                    HiDPIPropertiesWindowsTest UISCALE_2X3
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ *                   -Dsun.java2d.win.uiScaleX=3 -Dsun.java2d.win.uiScaleY=2
+ *                    HiDPIPropertiesWindowsTest UISCALE_3X2
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ *                   -Dsun.java2d.uiScale=4
+ *                    HiDPIPropertiesWindowsTest UISCALE_4
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ *                   -Dsun.java2d.uiScale=4
+ *                   -Dsun.java2d.win.uiScaleX=2 -Dsun.java2d.win.uiScaleY=3
+ *                    HiDPIPropertiesWindowsTest UISCALE_2X3
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ *                   -Dsun.java2d.win.uiScaleX=4 -Dsun.java2d.win.uiScaleY=5
+ *                    HiDPIPropertiesWindowsTest UISCALE_4X5
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ *                   -Dsun.java2d.uiScale=3
+ *                   -Dsun.java2d.win.uiScaleX=0 -Dsun.java2d.win.uiScaleY=0
+ *                    HiDPIPropertiesWindowsTest UISCALE_3
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ *                   -Dsun.java2d.uiScale=4
+ *                   -Dsun.java2d.win.uiScaleX=-7 -Dsun.java2d.win.uiScaleY=-8
+ *                    HiDPIPropertiesWindowsTest UISCALE_4
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ *                   -Dsun.java2d.uiScale=4x
+ *                    HiDPIPropertiesWindowsTest UISCALE_4
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ *                   -Dsun.java2d.win.uiScaleX=4x -Dsun.java2d.win.uiScaleY=5x
+ *                    HiDPIPropertiesWindowsTest UISCALE_4X5
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ *                   -Dsun.java2d.uiScale=384dpi
+ *                    HiDPIPropertiesWindowsTest UISCALE_4
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ *                   -Dsun.java2d.uiScale=300%
+ *                    HiDPIPropertiesWindowsTest UISCALE_3
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ *                   -Dsun.java2d.win.uiScaleX=400% -Dsun.java2d.win.uiScaleY=500%
+ *                    HiDPIPropertiesWindowsTest UISCALE_4X5
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ *                   -Dsun.java2d.win.uiScaleX=288dpi -Dsun.java2d.win.uiScaleY=192dpi
+ *                    HiDPIPropertiesWindowsTest UISCALE_3X2
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ *                   -Dsun.java2d.win.uiScaleX=200% -Dsun.java2d.win.uiScaleY=288dpi
+ *                    HiDPIPropertiesWindowsTest UISCALE_2X3
+ */
+public class HiDPIPropertiesWindowsTest {
+
+    public static void main(String[] args) throws Exception {
+
+        try {
+            UIManager.setLookAndFeel(
+                    "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
+        } catch (Exception e) {
+            return;
+        }
+
+        String testCase = args[0];
+        switch (testCase) {
+            case "UISCALE_DISABLED":
+                testScale(1.0, 1.0);
+                break;
+            case "UISCALE_3":
+                testScale(3.0, 3.0);
+                break;
+            case "UISCALE_4":
+                testScale(4.0, 4.0);
+                break;
+            case "UISCALE_2X3":
+                testScale(2.0, 3.0);
+                break;
+            case "UISCALE_3X2":
+                testScale(3.0, 2.0);
+                break;
+            case "UISCALE_4X5":
+                testScale(4.0, 5.0);
+                break;
+            default:
+                throw new RuntimeException("Unknown test case: " + testCase);
+        }
+    }
+
+    private static void testScale(double scaleX, double scaleY) {
+
+        Dialog dialog = new Dialog((Frame) null, true) {
+
+            @Override
+            public void paint(Graphics g) {
+                super.paint(g);
+                AffineTransform tx = ((Graphics2D) g).getTransform();
+                dispose();
+                if (scaleX != tx.getScaleX() || scaleY != tx.getScaleY()) {
+                    throw new RuntimeException(String.format("Wrong scale:"
+                            + "[%f, %f] instead of [%f, %f].",
+                            tx.getScaleX(), tx.getScaleY(), scaleX, scaleY));
+                }
+            }
+        };
+        dialog.setSize(200, 300);
+        dialog.setVisible(true);
+    }
+}
diff --git a/test/java/awt/image/MultiResolutionImage/MultiResolutionDisabledImageTest.java b/test/java/awt/image/MultiResolutionImage/MultiResolutionDisabledImageTest.java
new file mode 100644
index 0000000..ce5c44d
--- /dev/null
+++ b/test/java/awt/image/MultiResolutionImage/MultiResolutionDisabledImageTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+import java.awt.Color;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.MediaTracker;
+import java.awt.Toolkit;
+import java.awt.image.BaseMultiResolutionImage;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import javax.imageio.ImageIO;
+import javax.swing.GrayFilter;
+import java.awt.image.MultiResolutionImage;
+import javax.swing.JLabel;
+
+/**
+ * @test
+ * @bug 8156182
+ * @summary [macosx] HiDPI/Retina icons do not work for disabled
+ * JButton/JMenuItem etc.
+ * @run main/othervm -Dsun.java2d.uiScale=2 MultiResolutionDisabledImageTest
+ */
+public class MultiResolutionDisabledImageTest {
+
+    private static final String IMAGE_NAME_1X = "image.png";
+    private static final String IMAGE_NAME_2X = "image@2x.png";
+    private static final int IMAGE_SIZE = 100;
+    private static final Color COLOR_1X = Color.GREEN;
+    private static final Color COLOR_2X = Color.BLUE;
+
+    public static void main(String[] args) throws Exception {
+
+        Image baseMRImage = new BaseMultiResolutionImage(createImage(1),
+                                                         createImage(2));
+        testMRDisabledImage(baseMRImage);
+
+        saveImages();
+        Image toolkitMRImage = Toolkit.getDefaultToolkit().getImage(IMAGE_NAME_1X);
+
+        if (toolkitMRImage instanceof MultiResolutionImage) {
+            testMRDisabledImage(toolkitMRImage);
+        }
+    }
+
+    private static void testMRDisabledImage(Image image) throws Exception {
+
+        Image disabledImage = GrayFilter.createDisabledImage(image);
+        MediaTracker mediaTracker = new MediaTracker(new JLabel());
+        mediaTracker.addImage(disabledImage, 0);
+        mediaTracker.waitForID(0);
+
+        BufferedImage buffImage = new BufferedImage(IMAGE_SIZE,
+                                                    IMAGE_SIZE,
+                                                    BufferedImage.TYPE_INT_RGB);
+
+        int x = IMAGE_SIZE / 2;
+        int y = IMAGE_SIZE / 2;
+
+        Graphics2D g = buffImage.createGraphics();
+
+        g.scale(1, 1);
+        g.drawImage(disabledImage, 0, 0, null);
+        int rgb1x = buffImage.getRGB(x, y);
+
+        g.scale(2, 2);
+        g.drawImage(disabledImage, 0, 0, null);
+        int rgb2x = buffImage.getRGB(x, y);
+
+        g.dispose();
+
+        if (rgb1x == rgb2x) {
+            throw new RuntimeException("Disabled image is the same for the base"
+                    + "image and the resolution variant");
+        }
+
+    }
+
+    private static BufferedImage createImage(int scale) throws Exception {
+        BufferedImage image = new BufferedImage(scale * 200, scale * 300,
+                                                BufferedImage.TYPE_INT_RGB);
+        Graphics g = image.createGraphics();
+        g.setColor(scale == 1 ? COLOR_1X : COLOR_2X);
+        g.fillRect(0, 0, scale * 200, scale * 300);
+        g.dispose();
+        return image;
+    }
+
+    private static void saveImages() throws Exception {
+        saveImage(createImage(1), IMAGE_NAME_1X);
+        saveImage(createImage(2), IMAGE_NAME_2X);
+    }
+
+    private static void saveImage(BufferedImage image, String name) throws Exception {
+        ImageIO.write(image, "png", new File(name));
+    }
+}
diff --git a/test/java/awt/image/MultiResolutionImage/MultiResolutionDrawImageWithTransformTest.java b/test/java/awt/image/MultiResolutionImage/MultiResolutionDrawImageWithTransformTest.java
new file mode 100644
index 0000000..aa4a932
--- /dev/null
+++ b/test/java/awt/image/MultiResolutionImage/MultiResolutionDrawImageWithTransformTest.java
@@ -0,0 +1,248 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import java.awt.Color;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.awt.image.BaseMultiResolutionImage;
+import static java.awt.RenderingHints.KEY_RESOLUTION_VARIANT;
+import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_SIZE_FIT;
+import java.awt.geom.AffineTransform;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import sun.java2d.StateTrackable;
+import sun.java2d.SunGraphics2D;
+import sun.java2d.SurfaceData;
+import sun.java2d.loops.SurfaceType;
+
+/**
+ * @test
+ * @bug 8073320
+ * @author Alexander Scherbatiy
+ * @summary Windows HiDPI support
+ * @modules java.desktop/sun.java2d java.desktop/sun.java2d.loops
+ * @run main MultiResolutionDrawImageWithTransformTest
+ */
+public class MultiResolutionDrawImageWithTransformTest {
+
+    private static final int SCREEN_SIZE = 400;
+    private static final int IMAGE_SIZE = SCREEN_SIZE / 4;
+    private static final Color BACKGROUND_COLOR = Color.PINK;
+    private static final Color[] COLORS = {
+        Color.CYAN, Color.GREEN, Color.BLUE, Color.ORANGE
+    };
+
+    public static void main(String[] args) throws Exception {
+
+        int length = COLORS.length;
+        BufferedImage[] resolutionVariants = new BufferedImage[length];
+        for (int i = 0; i < length; i++) {
+            resolutionVariants[i] = createRVImage(getSize(i), COLORS[i]);
+        }
+
+        BaseMultiResolutionImage mrImage = new BaseMultiResolutionImage(
+                resolutionVariants);
+
+        // scale 1, transform 1, resolution variant 1
+        Color color = getImageColor(mrImage, 1, 1);
+        if (!getColorForScale(1).equals(color)) {
+            throw new RuntimeException("Wrong resolution variant!");
+        }
+
+        // scale 1, transform 2, resolution variant 2
+        color = getImageColor(mrImage, 1, 2);
+        if (!getColorForScale(2).equals(color)) {
+            throw new RuntimeException("Wrong resolution variant!");
+        }
+
+        // scale 2, transform 1, resolution variant 2
+        color = getImageColor(mrImage, 2, 1);
+        if (!getColorForScale(2).equals(color)) {
+            throw new RuntimeException("Wrong resolution variant!");
+        }
+
+        // scale 2, transform 2, resolution variant 4
+        color = getImageColor(mrImage, 2, 2);
+        if (!getColorForScale(4).equals(color)) {
+            throw new RuntimeException("Wrong resolution variant!");
+        }
+    }
+
+    private static Color getColorForScale(int scale) {
+        return COLORS[scale - 1];
+    }
+
+    private static Color getImageColor(Image image, double configScale,
+            double transformScale) {
+
+        TestSurfaceData surface = new TestSurfaceData(SCREEN_SIZE, SCREEN_SIZE,
+                configScale);
+        SunGraphics2D g2d = new SunGraphics2D(surface,
+                Color.BLACK, Color.BLACK, null);
+        g2d.setRenderingHint(KEY_RESOLUTION_VARIANT,
+                VALUE_RESOLUTION_VARIANT_SIZE_FIT);
+        AffineTransform tx = AffineTransform.getScaleInstance(transformScale,
+                transformScale);
+        g2d.drawImage(image, tx, null);
+        g2d.dispose();
+
+        int backgroundX = (int) (1.5 * image.getWidth(null) * transformScale);
+        int backgroundY = (int) (1.5 * image.getHeight(null) * transformScale);
+        Color backgroundColor = surface.getColor(backgroundX, backgroundY);
+        //surface.show(String.format("Config: %f, transform: %f", configScale, transformScale));
+        if (!BACKGROUND_COLOR.equals(backgroundColor)) {
+            throw new RuntimeException("Wrong background color!");
+        }
+        return surface.getColor(IMAGE_SIZE / 4, IMAGE_SIZE / 4);
+    }
+
+    private static int getSize(int i) {
+        return (i + 1) * IMAGE_SIZE;
+    }
+
+    private static BufferedImage createRVImage(int size, Color color) {
+        BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
+        Graphics g = image.createGraphics();
+        g.setColor(color);
+        g.fillRect(0, 0, size, size);
+        g.dispose();
+        return image;
+    }
+
+    static class TestGraphicsConfig extends GraphicsConfiguration {
+
+        private final double scale;
+
+        TestGraphicsConfig(double scale) {
+            this.scale = scale;
+        }
+
+        @Override
+        public GraphicsDevice getDevice() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public ColorModel getColorModel() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public ColorModel getColorModel(int transparency) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public AffineTransform getDefaultTransform() {
+            return AffineTransform.getScaleInstance(scale, scale);
+        }
+
+        @Override
+        public AffineTransform getNormalizingTransform() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public Rectangle getBounds() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+    }
+
+    static class TestSurfaceData extends SurfaceData {
+
+        private final int width;
+        private final int height;
+        private final GraphicsConfiguration gc;
+        private final BufferedImage buffImage;
+        private final double scale;
+
+        public TestSurfaceData(int width, int height, double scale) {
+            super(StateTrackable.State.DYNAMIC, SurfaceType.Custom, ColorModel.getRGBdefault());
+            this.scale = scale;
+            gc = new TestGraphicsConfig(scale);
+            this.width = (int) Math.ceil(scale * width);
+            this.height = (int) Math.ceil(scale * height);
+            buffImage = new BufferedImage(this.width, this.height,
+                    BufferedImage.TYPE_INT_RGB);
+
+            Graphics imageGraphics = buffImage.createGraphics();
+            imageGraphics.setColor(BACKGROUND_COLOR);
+            imageGraphics.fillRect(0, 0, this.width, this.height);
+            imageGraphics.dispose();
+        }
+
+        Color getColor(int x, int y) {
+            int sx = (int) Math.ceil(x * scale);
+            int sy = (int) Math.ceil(y * scale);
+            return new Color(buffImage.getRGB(sx, sy));
+        }
+
+        @Override
+        public SurfaceData getReplacement() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public GraphicsConfiguration getDeviceConfiguration() {
+            return gc;
+        }
+
+        @Override
+        public Raster getRaster(int x, int y, int w, int h) {
+            return buffImage.getRaster();
+        }
+
+        @Override
+        public Rectangle getBounds() {
+            return new Rectangle(0, 0, width, height);
+        }
+
+        @Override
+        public Object getDestination() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        private void show(String title) {
+            Frame frame = new Frame() {
+
+                @Override
+                public void paint(Graphics g) {
+                    super.paint(g);
+                    g.drawImage(buffImage, 0, 0, this);
+                    g.setColor(Color.GRAY);
+                    g.drawRect(0, 0, width, height);
+                    g.drawRect(0, height / 2, width, height / 2);
+                    g.drawRect(width / 2, 0, width / 2, height);
+                }
+            };
+            frame.setTitle(title);
+            frame.setSize(width, height);
+            frame.setVisible(true);
+        }
+    }
+}
diff --git a/test/java/awt/image/MultiResolutionImage/NSImageToMultiResolutionImageTest.java b/test/java/awt/image/MultiResolutionImage/NSImageToMultiResolutionImageTest.java
index af80924..33d8ab7 100644
--- a/test/java/awt/image/MultiResolutionImage/NSImageToMultiResolutionImageTest.java
+++ b/test/java/awt/image/MultiResolutionImage/NSImageToMultiResolutionImageTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -23,13 +23,17 @@
 
 import java.awt.Image;
 import java.awt.Toolkit;
-import sun.awt.OSInfo;
-import sun.awt.image.MultiResolutionImage;
+import java.awt.image.MultiResolutionImage;
+import jdk.testlibrary.OSInfo;
+
 /*
  * @test
  * @bug 8033534 8035069
  * @summary [macosx] Get MultiResolution image from native system
  * @author Alexander Scherbatiy
+ * @modules java.desktop/sun.awt.image
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.OSInfo
  * @run main NSImageToMultiResolutionImageTest
  */
 
diff --git a/test/java/awt/image/MultiResolutionImageCommonTest.java b/test/java/awt/image/MultiResolutionImageCommonTest.java
new file mode 100644
index 0000000..d509da7
--- /dev/null
+++ b/test/java/awt/image/MultiResolutionImageCommonTest.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2013, 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.
+ *
+ * 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.
+ */
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+import sun.awt.SunHints;
+import java.awt.geom.AffineTransform;
+import java.util.Arrays;
+import java.util.List;
+import java.awt.image.MultiResolutionImage;
+
+/**
+ * @test
+ * @bug 8011059
+ * @author Alexander Scherbatiy
+ * @summary Test MultiResolution image loading and painting with various scaling
+ *          combinations
+ * @modules java.desktop/sun.awt
+ *          java.desktop/sun.awt.image
+ */
+public class MultiResolutionImageCommonTest {
+
+    private static final int IMAGE_WIDTH = 300;
+    private static final int IMAGE_HEIGHT = 200;
+    private static final Color COLOR_1X = Color.GREEN;
+    private static final Color COLOR_2X = Color.BLUE;
+
+    public static void main(String[] args) throws Exception {
+        testCustomMultiResolutionImage();
+        System.out.println("Test passed.");
+    }
+
+    public static void testCustomMultiResolutionImage() {
+        testCustomMultiResolutionImage(false);
+        testCustomMultiResolutionImage(true);
+    }
+
+    public static void testCustomMultiResolutionImage(
+            boolean enableImageScaling) {
+
+        Image image = new MultiResolutionBufferedImage();
+
+        // Same image size
+        BufferedImage bufferedImage = new BufferedImage(
+                IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
+        Graphics2D g2d = (Graphics2D) bufferedImage.getGraphics();
+        setImageScalingHint(g2d, enableImageScaling);
+        g2d.drawImage(image, 0, 0, null);
+        checkColor(bufferedImage.getRGB(
+                3 * IMAGE_WIDTH / 4, 3 * IMAGE_HEIGHT / 4), false);
+
+        // Twice image size
+        bufferedImage = new BufferedImage(2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT,
+                BufferedImage.TYPE_INT_RGB);
+        g2d = (Graphics2D) bufferedImage.getGraphics();
+        setImageScalingHint(g2d, enableImageScaling);
+        g2d.drawImage(image, 0, 0, 2 * IMAGE_WIDTH,
+                2 * IMAGE_HEIGHT, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);
+        checkColor(bufferedImage.getRGB(3 * IMAGE_WIDTH / 2,
+                3 * IMAGE_HEIGHT / 2), enableImageScaling);
+
+        // Scale 2x
+        bufferedImage = new BufferedImage(
+                2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
+        g2d = (Graphics2D) bufferedImage.getGraphics();
+        setImageScalingHint(g2d, enableImageScaling);
+        g2d.scale(2, 2);
+        g2d.drawImage(image, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);
+        checkColor(bufferedImage.getRGB(
+                3 * IMAGE_WIDTH / 2, 3 * IMAGE_HEIGHT / 2), enableImageScaling);
+
+        // Rotate
+        bufferedImage = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT,
+                BufferedImage.TYPE_INT_RGB);
+        g2d = (Graphics2D) bufferedImage.getGraphics();
+        setImageScalingHint(g2d, enableImageScaling);
+        g2d.drawImage(image, 0, 0, null);
+        g2d.rotate(Math.PI / 4);
+        checkColor(bufferedImage.getRGB(
+                3 * IMAGE_WIDTH / 4, 3 * IMAGE_HEIGHT / 4), false);
+
+        // Scale 2x and Rotate
+        bufferedImage = new BufferedImage(
+                2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
+        g2d = (Graphics2D) bufferedImage.getGraphics();
+        setImageScalingHint(g2d, enableImageScaling);
+        g2d.scale(-2, 2);
+        g2d.rotate(-Math.PI / 10);
+        g2d.drawImage(image, -IMAGE_WIDTH, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);
+        checkColor(bufferedImage.getRGB(
+                3 * IMAGE_WIDTH / 2, 3 * IMAGE_HEIGHT / 2), enableImageScaling);
+
+        // General Transform
+        bufferedImage = new BufferedImage(
+                2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
+        g2d = (Graphics2D) bufferedImage.getGraphics();
+        setImageScalingHint(g2d, enableImageScaling);
+        float delta = 0.05f;
+        float cos = 1 - delta * delta / 2;
+        float sin = 1 + delta;
+        AffineTransform transform
+                = new AffineTransform(2 * cos, 0.1, 0.3, -2 * sin, 10, -5);
+        g2d.setTransform(transform);
+        g2d.drawImage(image, 0, -IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_HEIGHT, null);
+        checkColor(bufferedImage.getRGB(
+                3 * IMAGE_WIDTH / 2, 3 * IMAGE_HEIGHT / 2), enableImageScaling);
+
+        int D = 10;
+        // From Source to small Destination region
+        bufferedImage = new BufferedImage(
+                IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
+        g2d = (Graphics2D) bufferedImage.getGraphics();
+        setImageScalingHint(g2d, enableImageScaling);
+        g2d.drawImage(image, IMAGE_WIDTH / 2, IMAGE_HEIGHT / 2,
+                IMAGE_WIDTH - D, IMAGE_HEIGHT - D,
+                D, D, IMAGE_WIDTH - D, IMAGE_HEIGHT - D, null);
+        checkColor(bufferedImage.getRGB(
+                3 * IMAGE_WIDTH / 4, 3 * IMAGE_HEIGHT / 4), false);
+
+        // From Source to large Destination region
+        bufferedImage = new BufferedImage(
+                2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
+        g2d = (Graphics2D) bufferedImage.getGraphics();
+        setImageScalingHint(g2d, enableImageScaling);
+        g2d.drawImage(image, D, D, 2 * IMAGE_WIDTH - D, 2 * IMAGE_HEIGHT - D,
+                IMAGE_WIDTH / 2, IMAGE_HEIGHT / 2,
+                IMAGE_WIDTH - D, IMAGE_HEIGHT - D, null);
+        checkColor(bufferedImage.getRGB(
+                3 * IMAGE_WIDTH / 2, 3 * IMAGE_HEIGHT / 2), enableImageScaling);
+    }
+
+    static class MultiResolutionBufferedImage extends BufferedImage
+            implements MultiResolutionImage {
+
+        Image highResolutionImage;
+
+        public MultiResolutionBufferedImage() {
+            super(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
+            highResolutionImage = new BufferedImage(
+                    2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT,
+                    BufferedImage.TYPE_INT_RGB);
+            draw(getGraphics(), 1);
+            draw(highResolutionImage.getGraphics(), 2);
+        }
+
+        final void draw(Graphics graphics, float resolution) {
+            Graphics2D g2 = (Graphics2D) graphics;
+            g2.scale(resolution, resolution);
+            g2.setColor((resolution == 1) ? COLOR_1X : COLOR_2X);
+            g2.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
+        }
+
+        @Override
+        public Image getResolutionVariant(
+                double destImageWidth, double destImageHeight) {
+            return ((destImageWidth <= getWidth() && destImageHeight <= getHeight()))
+                    ? this : highResolutionImage;
+        }
+
+        @Override
+        public List<Image> getResolutionVariants() {
+            return Arrays.asList(this, highResolutionImage);
+        }
+    }
+
+    static void setImageScalingHint(
+            Graphics2D g2d, boolean enableImageScaling) {
+        g2d.setRenderingHint(SunHints.KEY_RESOLUTION_VARIANT, enableImageScaling
+                ? RenderingHints.VALUE_RESOLUTION_VARIANT_DEFAULT
+                : RenderingHints.VALUE_RESOLUTION_VARIANT_BASE);
+    }
+
+    static void checkColor(int rgb, boolean isImageScaled) {
+
+        if (!isImageScaled && COLOR_1X.getRGB() != rgb) {
+            throw new RuntimeException("Wrong 1x color: " + new Color(rgb));
+        }
+
+        if (isImageScaled && COLOR_2X.getRGB() != rgb) {
+            throw new RuntimeException("Wrong 2x color" + new Color(rgb));
+        }
+    }
+
+}
diff --git a/test/java/awt/image/MultiResolutionImageTest.java b/test/java/awt/image/MultiResolutionImageTest.java
index 21864f9..2238f6a 100644
--- a/test/java/awt/image/MultiResolutionImageTest.java
+++ b/test/java/awt/image/MultiResolutionImageTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -31,23 +31,25 @@
 import java.lang.reflect.Method;
 import java.net.URL;
 import javax.imageio.ImageIO;
-import sun.awt.OSInfo;
 import sun.awt.SunHints;
 import java.awt.MediaTracker;
-import java.awt.geom.AffineTransform;
+import java.awt.RenderingHints;
 import java.awt.image.ImageObserver;
-import java.util.Arrays;
-import java.util.List;
 import javax.swing.JPanel;
-import sun.awt.SunToolkit;
-import sun.awt.image.MultiResolutionImage;
+import jdk.testlibrary.Platform;
+import java.awt.image.MultiResolutionImage;
 
 /**
  * @test
  * @bug 8011059
  * @author Alexander Scherbatiy
  * @summary [macosx] Make JDK demos look perfect on retina displays
- * @run main MultiResolutionImageTest CUSTOM
+ * @library /lib/testlibrary/
+ * @build jdk.testlibrary.Platform
+ * @requires (os.family == "mac")
+ * @modules java.desktop/sun.awt
+ *          java.desktop/sun.awt.image
+ *          java.desktop/sun.lwawt.macosx
  * @run main MultiResolutionImageTest TOOLKIT_PREPARE
  * @run main MultiResolutionImageTest TOOLKIT_LOAD
  * @run main MultiResolutionImageTest TOOLKIT
@@ -68,149 +70,29 @@
         if (args.length == 0) {
             throw new RuntimeException("Not found a test");
         }
-
         String test = args[0];
-
         System.out.println("TEST: " + test);
-        System.out.println("CHECK OS: " + checkOS());
 
-        if ("CUSTOM".equals(test)) {
-            testCustomMultiResolutionImage();
-        } else if (checkOS()) {
-            switch (test) {
-                case "CUSTOM":
-                    break;
-                case "TOOLKIT_PREPARE":
-                    testToolkitMultiResolutionImagePrepare();
-                    break;
-                case "TOOLKIT_LOAD":
-                    testToolkitMultiResolutionImageLoad();
-                    break;
-                case "TOOLKIT":
-                    testToolkitMultiResolutionImage();
-                    testImageNameTo2xParsing();
-                    break;
-                default:
-                    throw new RuntimeException("Unknown test: " + test);
-            }
+        // To automatically pass the test if the test is not run using JTReg.
+        if (!Platform.isOSX()) {
+            System.out.println("Non-Mac platform detected. Passing the test");
+            return;
         }
-    }
-
-    static boolean checkOS() {
-        return OSInfo.getOSType() == OSInfo.OSType.MACOSX;
-    }
-
-    public static void testCustomMultiResolutionImage() {
-        testCustomMultiResolutionImage(false);
-        testCustomMultiResolutionImage(true);
-    }
-
-    public static void testCustomMultiResolutionImage(boolean enableImageScaling) {
-
-        Image image = new MultiResolutionBufferedImage();
-
-        // Same image size
-        BufferedImage bufferedImage = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT,
-                BufferedImage.TYPE_INT_RGB);
-        Graphics2D g2d = (Graphics2D) bufferedImage.getGraphics();
-        setImageScalingHint(g2d, enableImageScaling);
-        g2d.drawImage(image, 0, 0, null);
-        checkColor(bufferedImage.getRGB(3 * IMAGE_WIDTH / 4, 3 * IMAGE_HEIGHT / 4), false);
-
-        // Twice image size
-        bufferedImage = new BufferedImage(2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT,
-                BufferedImage.TYPE_INT_RGB);
-        g2d = (Graphics2D) bufferedImage.getGraphics();
-        setImageScalingHint(g2d, enableImageScaling);
-        g2d.drawImage(image, 0, 0, 2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);
-        checkColor(bufferedImage.getRGB(3 * IMAGE_WIDTH / 2, 3 * IMAGE_HEIGHT / 2), enableImageScaling);
-
-        // Scale 2x
-        bufferedImage = new BufferedImage(2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
-        g2d = (Graphics2D) bufferedImage.getGraphics();
-        setImageScalingHint(g2d, enableImageScaling);
-        g2d.scale(2, 2);
-        g2d.drawImage(image, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);
-        checkColor(bufferedImage.getRGB(3 * IMAGE_WIDTH / 2, 3 * IMAGE_HEIGHT / 2), enableImageScaling);
-
-        // Rotate
-        bufferedImage = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT,
-                BufferedImage.TYPE_INT_RGB);
-        g2d = (Graphics2D) bufferedImage.getGraphics();
-        setImageScalingHint(g2d, enableImageScaling);
-        g2d.drawImage(image, 0, 0, null);
-        g2d.rotate(Math.PI / 4);
-        checkColor(bufferedImage.getRGB(3 * IMAGE_WIDTH / 4, 3 * IMAGE_HEIGHT / 4), false);
-
-        // Scale 2x and Rotate
-        bufferedImage = new BufferedImage(2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
-        g2d = (Graphics2D) bufferedImage.getGraphics();
-        setImageScalingHint(g2d, enableImageScaling);
-        g2d.scale(-2, 2);
-        g2d.rotate(-Math.PI / 10);
-        g2d.drawImage(image, -IMAGE_WIDTH, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);
-        checkColor(bufferedImage.getRGB(3 * IMAGE_WIDTH / 2, 3 * IMAGE_HEIGHT / 2), enableImageScaling);
-
-        // General Transform
-        bufferedImage = new BufferedImage(2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
-        g2d = (Graphics2D) bufferedImage.getGraphics();
-        setImageScalingHint(g2d, enableImageScaling);
-        float delta = 0.05f;
-        float cos = 1 - delta * delta / 2;
-        float sin = 1 + delta;
-        AffineTransform transform = new AffineTransform(2 * cos, 0.1, 0.3, -2 * sin, 10, -5);
-        g2d.setTransform(transform);
-        g2d.drawImage(image, 0, -IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_HEIGHT, null);
-        checkColor(bufferedImage.getRGB(3 * IMAGE_WIDTH / 2, 3 * IMAGE_HEIGHT / 2), enableImageScaling);
-
-        int D = 10;
-        // From Source to small Destination region
-        bufferedImage = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
-        g2d = (Graphics2D) bufferedImage.getGraphics();
-        setImageScalingHint(g2d, enableImageScaling);
-        g2d.drawImage(image, IMAGE_WIDTH / 2, IMAGE_HEIGHT / 2, IMAGE_WIDTH - D, IMAGE_HEIGHT - D,
-                D, D, IMAGE_WIDTH - D, IMAGE_HEIGHT - D, null);
-        checkColor(bufferedImage.getRGB(3 * IMAGE_WIDTH / 4, 3 * IMAGE_HEIGHT / 4), false);
-
-        // From Source to large Destination region
-        bufferedImage = new BufferedImage(2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
-        g2d = (Graphics2D) bufferedImage.getGraphics();
-        setImageScalingHint(g2d, enableImageScaling);
-        g2d.drawImage(image, D, D, 2 * IMAGE_WIDTH - D, 2 * IMAGE_HEIGHT - D,
-                IMAGE_WIDTH / 2, IMAGE_HEIGHT / 2, IMAGE_WIDTH - D, IMAGE_HEIGHT - D, null);
-        checkColor(bufferedImage.getRGB(3 * IMAGE_WIDTH / 2, 3 * IMAGE_HEIGHT / 2), enableImageScaling);
-    }
-
-    static class MultiResolutionBufferedImage extends BufferedImage
-            implements MultiResolutionImage {
-
-        Image highResolutionImage;
-
-        public MultiResolutionBufferedImage() {
-            super(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
-            highResolutionImage = new BufferedImage(
-                    2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
-            draw(getGraphics(), 1);
-            draw(highResolutionImage.getGraphics(), 2);
+        switch (test) {
+            case "TOOLKIT_PREPARE":
+                testToolkitMultiResolutionImagePrepare();
+                break;
+            case "TOOLKIT_LOAD":
+                testToolkitMultiResolutionImageLoad();
+                break;
+            case "TOOLKIT":
+                testToolkitMultiResolutionImage();
+                testImageNameTo2xParsing();
+                break;
+            default:
+                throw new RuntimeException("Unknown test: " + test);
         }
-
-        void draw(Graphics graphics, float resolution) {
-            Graphics2D g2 = (Graphics2D) graphics;
-            g2.scale(resolution, resolution);
-            g2.setColor((resolution == 1) ? COLOR_1X : COLOR_2X);
-            g2.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
-        }
-
-        @Override
-        public Image getResolutionVariant(int width, int height) {
-            return ((width <= getWidth() && height <= getHeight()))
-                    ? this : highResolutionImage;
-        }
-
-        @Override
-        public List<Image> getResolutionVariants() {
-            return Arrays.asList(this, highResolutionImage);
-        }
+        System.out.println("Test passed.");
     }
 
     static void testToolkitMultiResolutionImagePrepare() throws Exception {
@@ -222,8 +104,9 @@
 
         Image image = Toolkit.getDefaultToolkit().getImage(fileName);
 
-        SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit();
-        toolkit.prepareImage(image, IMAGE_WIDTH, IMAGE_HEIGHT, new LoadImageObserver(image));
+        Toolkit toolkit = Toolkit.getDefaultToolkit();
+        toolkit.prepareImage(image, IMAGE_WIDTH, IMAGE_HEIGHT,
+            new LoadImageObserver(image));
 
         testToolkitMultiResolutionImageLoad(image);
     }
@@ -238,7 +121,8 @@
         testToolkitMultiResolutionImageLoad(image);
     }
 
-    static void testToolkitMultiResolutionImageLoad(Image image) throws Exception {
+    static void testToolkitMultiResolutionImageLoad(Image image)
+        throws Exception {
 
         MediaTracker tracker = new MediaTracker(new JPanel());
         tracker.addImage(image, 0);
@@ -254,7 +138,7 @@
         int h = image.getHeight(null);
 
         Image resolutionVariant = ((MultiResolutionImage) image)
-                .getResolutionVariant(2 * w, 2 * h);
+            .getResolutionVariant(2 * w, 2 * h);
 
         if (image == resolutionVariant) {
             throw new RuntimeException("Resolution variant is not loaded");
@@ -265,9 +149,10 @@
 
     static void testImageLoaded(Image image) {
 
-        SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit();
+        Toolkit toolkit = Toolkit.getDefaultToolkit();
 
-        int flags = toolkit.checkImage(image, IMAGE_WIDTH, IMAGE_WIDTH, new SilentImageObserver());
+        int flags = toolkit.checkImage(image, IMAGE_WIDTH, IMAGE_WIDTH,
+            new SilentImageObserver());
         if ((flags & (ImageObserver.FRAMEBITS | ImageObserver.ALLBITS)) == 0) {
             throw new RuntimeException("Image is not loaded!");
         }
@@ -276,7 +161,8 @@
     static class SilentImageObserver implements ImageObserver {
 
         @Override
-        public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
+        public boolean imageUpdate(Image img, int infoflags, int x, int y,
+            int width, int height) {
             throw new RuntimeException("Observer should not be called!");
         }
     }
@@ -290,21 +176,25 @@
         }
 
         @Override
-        public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
+        public boolean imageUpdate(Image img, int infoflags, int x, int y,
+            int width, int height) {
 
             if (image != img) {
-                throw new RuntimeException("Original image is not passed to the observer");
+                throw new RuntimeException("Original image is not passed "
+                    + "to the observer");
             }
 
             if ((infoflags & ImageObserver.WIDTH) != 0) {
                 if (width != IMAGE_WIDTH) {
-                    throw new RuntimeException("Original width is not passed to the observer");
+                    throw new RuntimeException("Original width is not passed "
+                        + "to the observer");
                 }
             }
 
             if ((infoflags & ImageObserver.HEIGHT) != 0) {
                 if (height != IMAGE_HEIGHT) {
-                    throw new RuntimeException("Original height is not passed to the observer");
+                    throw new RuntimeException("Original height is not passed "
+                        + "to the observer");
                 }
             }
 
@@ -333,7 +223,8 @@
         testToolkitMultiResolutionImage(image, true);
     }
 
-    static void testToolkitMultiResolutionImageChache(String fileName, URL url) {
+    static void testToolkitMultiResolutionImageChache(String fileName,
+        URL url) {
 
         Image img1 = Toolkit.getDefaultToolkit().getImage(fileName);
         if (!(img1 instanceof MultiResolutionImage)) {
@@ -356,8 +247,8 @@
         }
     }
 
-    static void testToolkitMultiResolutionImage(Image image, boolean enableImageScaling)
-            throws Exception {
+    static void testToolkitMultiResolutionImage(Image image,
+        boolean enableImageScaling) throws Exception {
 
         MediaTracker tracker = new MediaTracker(new JPanel());
         tracker.addImage(image, 0);
@@ -366,15 +257,16 @@
             throw new RuntimeException("Error during image loading");
         }
 
-        final BufferedImage bufferedImage1x = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT,
-                BufferedImage.TYPE_INT_RGB);
+        final BufferedImage bufferedImage1x = new BufferedImage(IMAGE_WIDTH,
+            IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
         Graphics2D g1x = (Graphics2D) bufferedImage1x.getGraphics();
         setImageScalingHint(g1x, false);
         g1x.drawImage(image, 0, 0, null);
-        checkColor(bufferedImage1x.getRGB(3 * IMAGE_WIDTH / 4, 3 * IMAGE_HEIGHT / 4), false);
+        checkColor(bufferedImage1x.getRGB(3 * IMAGE_WIDTH / 4,
+            3 * IMAGE_HEIGHT / 4), false);
 
         Image resolutionVariant = ((MultiResolutionImage) image).
-                getResolutionVariant(2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT);
+            getResolutionVariant(2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT);
 
         if (resolutionVariant == null) {
             throw new RuntimeException("Resolution variant is null");
@@ -388,23 +280,28 @@
         }
 
         final BufferedImage bufferedImage2x = new BufferedImage(2 * IMAGE_WIDTH,
-                2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
+            2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
         Graphics2D g2x = (Graphics2D) bufferedImage2x.getGraphics();
         setImageScalingHint(g2x, enableImageScaling);
-        g2x.drawImage(image, 0, 0, 2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);
-        checkColor(bufferedImage2x.getRGB(3 * IMAGE_WIDTH / 2, 3 * IMAGE_HEIGHT / 2), enableImageScaling);
+        g2x.drawImage(image, 0, 0, 2 * IMAGE_WIDTH,
+            2 * IMAGE_HEIGHT, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);
+        checkColor(bufferedImage2x.getRGB(3 * IMAGE_WIDTH / 2,
+            3 * IMAGE_HEIGHT / 2), enableImageScaling);
 
         if (!(image instanceof MultiResolutionImage)) {
             throw new RuntimeException("Not a MultiResolutionImage");
         }
 
-        MultiResolutionImage multiResolutionImage = (MultiResolutionImage) image;
+        MultiResolutionImage multiResolutionImage
+            = (MultiResolutionImage) image;
 
-        Image image1x = multiResolutionImage.getResolutionVariant(IMAGE_WIDTH, IMAGE_HEIGHT);
-        Image image2x = multiResolutionImage.getResolutionVariant(2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT);
+        Image image1x = multiResolutionImage.getResolutionVariant(
+            IMAGE_WIDTH, IMAGE_HEIGHT);
+        Image image2x = multiResolutionImage.getResolutionVariant(
+            2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT);
 
         if (image1x.getWidth(null) * 2 != image2x.getWidth(null)
-                || image1x.getHeight(null) * 2 != image2x.getHeight(null)) {
+            || image1x.getHeight(null) * 2 != image2x.getHeight(null)) {
             throw new RuntimeException("Wrong resolution variant size");
         }
     }
@@ -414,13 +311,15 @@
         ImageObserver observer = new ImageObserver() {
 
             @Override
-            public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
+            public boolean imageUpdate(Image img, int infoflags, int x, int y,
+                int width, int height) {
 
                 if (img != image) {
                     throw new RuntimeException("Wrong image in observer");
                 }
 
-                if ((infoflags & (ImageObserver.ERROR | ImageObserver.ABORT)) != 0) {
+                if ((infoflags & (ImageObserver.ERROR | ImageObserver.ABORT))
+                    != 0) {
                     throw new RuntimeException("Error during image loading");
                 }
 
@@ -430,18 +329,20 @@
         };
 
         final BufferedImage bufferedImage2x = new BufferedImage(2 * IMAGE_WIDTH,
-                2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
+            2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
         Graphics2D g2x = (Graphics2D) bufferedImage2x.getGraphics();
         setImageScalingHint(g2x, true);
 
-        g2x.drawImage(image, 0, 0, 2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, observer);
+        g2x.drawImage(image, 0, 0, 2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, 0, 0,
+            IMAGE_WIDTH, IMAGE_HEIGHT, observer);
 
     }
 
-    static void setImageScalingHint(Graphics2D g2d, boolean enableImageScaling) {
+    static void setImageScalingHint(Graphics2D g2d,
+        boolean enableImageScaling) {
         g2d.setRenderingHint(SunHints.KEY_RESOLUTION_VARIANT, enableImageScaling
-                ? SunHints.VALUE_RESOLUTION_VARIANT_ON
-                : SunHints.VALUE_RESOLUTION_VARIANT_OFF);
+            ? RenderingHints.VALUE_RESOLUTION_VARIANT_DEFAULT
+            : RenderingHints.VALUE_RESOLUTION_VARIANT_BASE);
     }
 
     static void checkColor(int rgb, boolean isImageScaled) {
@@ -466,8 +367,9 @@
     }
 
     static void generateImage(int scale) throws Exception {
-        BufferedImage image = new BufferedImage(scale * IMAGE_WIDTH, scale * IMAGE_HEIGHT,
-                BufferedImage.TYPE_INT_RGB);
+        BufferedImage image = new BufferedImage(
+            scale * IMAGE_WIDTH, scale * IMAGE_HEIGHT,
+            BufferedImage.TYPE_INT_RGB);
         Graphics g = image.getGraphics();
         g.setColor(scale == 1 ? COLOR_1X : COLOR_2X);
         g.fillRect(0, 0, scale * IMAGE_WIDTH, scale * IMAGE_HEIGHT);
@@ -491,7 +393,7 @@
             }
 
             throw new RuntimeException("Test name " + testName
-                    + ", result name: " + resultName);
+                + ", result name: " + resultName);
         }
 
         for (URL[] testURLs : TEST_URLS) {
@@ -508,7 +410,7 @@
             }
 
             throw new RuntimeException("Test url: " + testURL
-                    + ", result url: " + resultURL);
+                + ", result url: " + resultURL);
         }
 
     }
@@ -519,19 +421,22 @@
     }
 
     static String getTestScaledImageName(String name) throws Exception {
-        Method method = getScalableImageMethod("getScaledImageName", String.class);
+        Method method = getScalableImageMethod(
+            "getScaledImageName", String.class);
         return (String) method.invoke(null, name);
     }
 
     private static boolean isValidPath(String path) {
         return !path.isEmpty() && !path.endsWith("/") && !path.endsWith(".")
-                && !path.contains("@2x");
+            && !path.contains("@2x");
     }
 
     private static Method getScalableImageMethod(String name,
-            Class... parameterTypes) throws Exception {
+        Class... parameterTypes) throws Exception {
         Toolkit toolkit = Toolkit.getDefaultToolkit();
-        Method method = toolkit.getClass().getDeclaredMethod(name, parameterTypes);
+        Method method = toolkit.getClass()
+            .
+            getDeclaredMethod(name, parameterTypes);
         method.setAccessible(true);
         return method;
     }
@@ -602,9 +507,11 @@
                 {new URL("jar:file:/dir/Java2D.jar!/images/image.ext"),
                     new URL("jar:file:/dir/Java2D.jar!/images/image@2x.ext")},
                 {new URL("jar:file:/aaa.bbb/Java2D.jar!/images/image.ext"),
-                    new URL("jar:file:/aaa.bbb/Java2D.jar!/images/image@2x.ext")},
+                    new URL("jar:file:/aaa.bbb/Java2D.jar!/"
+                    + "images/image@2x.ext")},
                 {new URL("jar:file:/dir/Java2D.jar!/aaa.bbb/image.ext"),
-                    new URL("jar:file:/dir/Java2D.jar!/aaa.bbb/image@2x.ext")},};
+                    new URL("jar:file:/dir/Java2D.jar!/"
+                    + "aaa.bbb/image@2x.ext")},};
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
@@ -613,7 +520,8 @@
     static class PreloadedImageObserver implements ImageObserver {
 
         @Override
-        public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
+        public boolean imageUpdate(Image img, int infoflags, int x, int y,
+            int width, int height) {
             throw new RuntimeException("Image should be already preloaded");
         }
     }
diff --git a/test/java/awt/image/multiresolution/BaseMultiResolutionImageTest.java b/test/java/awt/image/multiresolution/BaseMultiResolutionImageTest.java
new file mode 100644
index 0000000..02ba9d6
--- /dev/null
+++ b/test/java/awt/image/multiresolution/BaseMultiResolutionImageTest.java
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+import java.awt.Dimension;
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+import java.awt.image.BaseMultiResolutionImage;
+import java.awt.image.MultiResolutionImage;
+import java.util.List;
+
+/**
+ * @test
+ * @bug 8029339
+ * @author Alexander Scherbatiy
+ * @summary Custom MultiResolution image support on HiDPI displays
+ * @run main BaseMultiResolutionImageTest
+ */
+public class BaseMultiResolutionImageTest {
+
+    public static void main(String[] args) {
+        testZeroRVIMages();
+        testNullRVIMages();
+        testNullRVIMage();
+        testIOOBException();
+        testRVSizes();
+        testBaseMRImage();
+    }
+
+    static void testZeroRVIMages() {
+        try {
+            new BaseMultiResolutionImage();
+        } catch (IllegalArgumentException ignored) {
+            return;
+        }
+        throw new RuntimeException("IllegalArgumentException is not thrown!");
+    }
+
+    static void testNullRVIMages() {
+        try {
+            new BaseMultiResolutionImage(null);
+        } catch (IllegalArgumentException ignored) {
+            return;
+        }
+        throw new RuntimeException("IllegalArgumentException is not thrown!");
+    }
+
+    static void testNullRVIMage() {
+
+        Image baseImage = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB);
+
+        try {
+            new BaseMultiResolutionImage(baseImage, null);
+        } catch (NullPointerException ignored) {
+            return;
+        }
+        throw new RuntimeException("NullPointerException is not thrown!");
+    }
+
+    static void testIOOBException() {
+
+        for (int baseImageIndex : new int[]{-3, 2, 4}) {
+            try {
+                new BaseMultiResolutionImage(baseImageIndex,
+                        createRVImage(0), createRVImage(1));
+            } catch (IndexOutOfBoundsException ignored) {
+                continue;
+            }
+
+            throw new RuntimeException("IndexOutOfBoundsException is not thrown!");
+        }
+    }
+
+    static void testRVSizes() {
+
+        int imageSize = getSize(1);
+
+        double[][] sizeArray = {
+            {-imageSize, imageSize},
+            {2 * imageSize, -2 * imageSize},
+            {Double.POSITIVE_INFINITY, imageSize},
+            {Double.POSITIVE_INFINITY, -imageSize},
+            {imageSize, Double.NEGATIVE_INFINITY},
+            {-imageSize, Double.NEGATIVE_INFINITY},
+            {Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY},
+            {Double.NaN, imageSize},
+            {imageSize, Double.NaN},
+            {Double.NaN, Double.NaN},
+            {Double.POSITIVE_INFINITY, Double.NaN}
+        };
+
+        for (double[] sizes : sizeArray) {
+            try {
+                MultiResolutionImage mrImage = new BaseMultiResolutionImage(
+                        0, createRVImage(0), createRVImage(1));
+                mrImage.getResolutionVariant(sizes[0], sizes[1]);
+            } catch (IllegalArgumentException ignored) {
+                continue;
+            }
+
+            throw new RuntimeException("IllegalArgumentException is not thrown!");
+        }
+    }
+
+    static void testBaseMRImage() {
+        int baseIndex = 1;
+        int length = 3;
+        BufferedImage[] resolutionVariants = new BufferedImage[length];
+        for (int i = 0; i < length; i++) {
+            resolutionVariants[i] = createRVImage(i);
+        }
+
+        BaseMultiResolutionImage mrImage = new BaseMultiResolutionImage(baseIndex,
+                resolutionVariants);
+
+        List<Image> rvImageList = mrImage.getResolutionVariants();
+        if (rvImageList.size() != length) {
+            throw new RuntimeException("Wrong size of resolution variants list!");
+        }
+
+        for (int i = 0; i < length; i++) {
+            int imageSize = getSize(i);
+            Image testRVImage = mrImage.getResolutionVariant(imageSize, imageSize);
+
+            if (testRVImage != resolutionVariants[i]) {
+                throw new RuntimeException("Wrong resolution variant!");
+            }
+
+            if (rvImageList.get(i) != resolutionVariants[i]) {
+                throw new RuntimeException("Wrong resolution variant!");
+            }
+        }
+
+        BufferedImage baseImage = resolutionVariants[baseIndex];
+
+        if (baseImage.getWidth() != mrImage.getWidth(null)
+                || baseImage.getHeight() != mrImage.getHeight(null)) {
+            throw new RuntimeException("Base image is wrong!");
+        }
+
+        boolean passed = false;
+
+        try {
+            rvImageList.set(0, createRVImage(10));
+        } catch (Exception e) {
+            passed = true;
+        }
+
+        if (!passed) {
+            throw new RuntimeException("Resolution variants list is modifiable!");
+        }
+
+        passed = false;
+
+        try {
+            rvImageList.remove(0);
+        } catch (Exception e) {
+            passed = true;
+        }
+
+        if (!passed) {
+            throw new RuntimeException("Resolution variants list is modifiable!");
+        }
+
+        passed = false;
+
+        try {
+            rvImageList.add(0, createRVImage(10));
+        } catch (Exception e) {
+            passed = true;
+        }
+
+        if (!passed) {
+            throw new RuntimeException("Resolution variants list is modifiable!");
+        }
+
+        passed = false;
+        try {
+            mrImage.getGraphics();
+        } catch (UnsupportedOperationException e) {
+            passed = true;
+        }
+
+        if (!passed) {
+            throw new RuntimeException("getGraphics() method shouldn't be supported!");
+        }
+    }
+
+    private static int getSize(int i) {
+        return 8 * (i + 1);
+    }
+
+    private static BufferedImage createRVImage(int i) {
+        return new BufferedImage(getSize(i), getSize(i),
+                BufferedImage.TYPE_INT_RGB);
+    }
+}
diff --git a/test/java/awt/image/multiresolution/Corrupted2XImageTest.java b/test/java/awt/image/multiresolution/Corrupted2XImageTest.java
new file mode 100644
index 0000000..ba0f7b3
--- /dev/null
+++ b/test/java/awt/image/multiresolution/Corrupted2XImageTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8142406
+ * @author a.stepanov
+ * @summary [HiDPI] [macosx] check that for a pair of images
+ *          (image.ext, image@2x.ext) the 1st one is loaded
+ *          in case if the 2nd is corrupted
+ *
+ * @requires (os.family == "mac")
+ *
+ * @library ../../../../lib/testlibrary/
+ * @build ExtendedRobot
+ * @run main Corrupted2XImageTest
+ */
+
+import java.awt.*;
+import java.awt.image.*;
+import java.io.*;
+
+import javax.imageio.ImageIO;
+
+public class Corrupted2XImageTest extends Frame {
+
+    private static final int SZ = 200;
+    private static final Color C = Color.BLUE;
+
+    private final String format, name1x, name2x;
+
+    public Corrupted2XImageTest(String format) throws IOException {
+
+        this.format = format;
+        name1x = "test." + format;
+        name2x = "test@2x." + format;
+        createFiles();
+    }
+
+    private void UI() {
+
+        setTitle(format);
+        setSize(SZ, SZ);
+        setResizable(false);
+        setLocation(50, 50);
+        setVisible(true);
+    }
+
+    @Override
+    public void paint(Graphics g) {
+
+        Image img = Toolkit.getDefaultToolkit().getImage(
+            new File(name1x).getAbsolutePath());
+        g.drawImage(img, 0, 0, this);
+    }
+
+    private void createFiles() throws IOException {
+
+        BufferedImage img =
+            new BufferedImage(SZ, SZ, BufferedImage.TYPE_INT_RGB);
+        Graphics g = img.getGraphics();
+        g.setColor(C);
+        g.fillRect(0, 0, SZ, SZ);
+        ImageIO.write(img, format, new File(name1x));
+
+        // corrupted @2x "image" - just a text file
+        Writer writer = new BufferedWriter(new OutputStreamWriter(
+            new FileOutputStream(new File(name2x)), "utf-8"));
+        writer.write("corrupted \"image\"");
+        writer.close();
+    }
+
+    // need this for jpg
+    private static boolean cmpColors(Color c1, Color c2) {
+
+        int tol = 10;
+        return (
+            Math.abs(c2.getRed()   - c1.getRed()  ) < tol &&
+            Math.abs(c2.getGreen() - c1.getGreen()) < tol &&
+            Math.abs(c2.getBlue()  - c1.getBlue() ) < tol);
+    }
+
+    private void doTest() throws Exception {
+
+        ExtendedRobot r = new ExtendedRobot();
+        System.out.println("format: " + format);
+        r.waitForIdle(1000);
+        EventQueue.invokeAndWait(this::UI);
+        r.waitForIdle(1000);
+        Point loc = getLocationOnScreen();
+        Color c = r.getPixelColor(loc.x + SZ / 2, loc.y + SZ / 2);
+        if (!cmpColors(c, C)) {
+            throw new RuntimeException("test failed, color = " + c); }
+        System.out.println("ok");
+        dispose();
+    }
+
+    public static void main(String[] args) throws Exception {
+
+        // formats supported by Toolkit.getImage()
+        for (String format : new String[]{"gif", "jpg", "png"}) {
+            (new Corrupted2XImageTest(format)).doTest();
+        }
+    }
+}
diff --git a/test/java/awt/image/multiresolution/MenuMultiresolutionIconTest.java b/test/java/awt/image/multiresolution/MenuMultiresolutionIconTest.java
new file mode 100644
index 0000000..a50940c
--- /dev/null
+++ b/test/java/awt/image/multiresolution/MenuMultiresolutionIconTest.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @key headful
+ * @bug 8150258
+ * @author a.stepanov
+ * @summary Check that correct resolution variants are chosen for menu icons
+ *          when multiresolution image is used for their construction.
+ *
+ * @library ../../../../lib/testlibrary/
+ * @build ExtendedRobot
+ * @run main/othervm -Dsun.java2d.uiScale=1 MenuMultiresolutionIconTest
+ * @run main/othervm -Dsun.java2d.uiScale=2 MenuMultiresolutionIconTest
+ */
+
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.*;
+import javax.swing.*;
+
+public class MenuMultiresolutionIconTest extends JPanel {
+
+    private final static int DELAY = 1000;
+    private final static int SZ = 50;
+    private final static String SCALE = "sun.java2d.uiScale";
+    private final static Color C1X = Color.RED, C2X = Color.BLUE;
+    private final ExtendedRobot r;
+
+    private static BufferedImage generateImage(int scale, Color c) {
+
+        int x = SZ * scale;
+        BufferedImage img = new BufferedImage(x, x, BufferedImage.TYPE_INT_RGB);
+        Graphics g = img.getGraphics();
+        g.setColor(c);
+        g.fillRect(0, 0, x, x);
+        return img;
+    }
+
+    private static BaseMultiResolutionImage createIcon() {
+
+        return new BaseMultiResolutionImage(new BufferedImage[] {
+            generateImage(1, C1X), generateImage(2, C2X)});
+    }
+
+    private JFrame     frame;
+    private JPopupMenu popup;
+    private JMenuItem  popupItem;
+    private JMenu      menu;
+
+    public MenuMultiresolutionIconTest() throws Exception {
+
+        r = new ExtendedRobot();
+        SwingUtilities.invokeAndWait(this::createUI);
+    }
+
+    private void createUI() {
+
+        ImageIcon ii = new ImageIcon(createIcon());
+
+        popup = new JPopupMenu();
+        popupItem = new JMenuItem("test", ii);
+        popup.add(popupItem);
+        popupItem.setHorizontalTextPosition(JMenuItem.RIGHT);
+        addMouseListener(new MousePopupListener());
+
+        frame = new JFrame();
+        JMenuBar menuBar = new JMenuBar();
+        menu = new JMenu("test");
+        menuBar.add(menu);
+        menu.add(new JMenuItem("test", ii));
+        menu.add(new JRadioButtonMenuItem("test", ii, true));
+        menu.add(new JCheckBoxMenuItem("test", ii, true));
+
+        frame.setJMenuBar(menuBar);
+        frame.setContentPane(this);
+        frame.setSize(300, 300);
+        frame.setVisible(true);
+    }
+
+    private class MousePopupListener extends MouseAdapter {
+
+        @Override
+        public void mousePressed(MouseEvent e)  { showPopup(e); }
+        @Override
+        public void mouseClicked(MouseEvent e)  { showPopup(e); }
+        @Override
+        public void mouseReleased(MouseEvent e) { showPopup(e); }
+
+        private void showPopup(MouseEvent e) {
+            if (e.isPopupTrigger()) {
+                popup.show(MenuMultiresolutionIconTest.this, e.getX(), e.getY());
+            }
+        }
+    }
+
+    private boolean eqColors(Color c1, Color c2) {
+
+        int tol = 15;
+        return (
+            Math.abs(c2.getRed()   - c1.getRed()  ) < tol &&
+            Math.abs(c2.getGreen() - c1.getGreen()) < tol &&
+            Math.abs(c2.getBlue()  - c1.getBlue() ) < tol);
+    }
+
+    private void checkIconColor(Point p, String what) {
+
+        String scale = System.getProperty(SCALE);
+        Color expected = "2".equals(scale) ? C2X : C1X;
+        Color c = r.getPixelColor(p.x + SZ / 2, p.y + SZ / 2);
+        if (!eqColors(c, expected)) {
+            frame.dispose();
+            throw new RuntimeException("invalid " + what + "menu item icon " +
+                "color, expected: " + expected + ", got: " + c);
+        }
+        System.out.println(what + "item icon check passed");
+    }
+
+    private void doTest() {
+
+        r.waitForIdle(2 * DELAY);
+
+        Point p = getLocationOnScreen();
+        r.mouseMove(p.x + getWidth() / 4, p.y + getHeight() / 4);
+        r.waitForIdle(DELAY);
+        r.click(InputEvent.BUTTON3_DOWN_MASK);
+        r.waitForIdle(DELAY);
+        p = popupItem.getLocationOnScreen();
+        checkIconColor(p, "popup ");
+        r.waitForIdle(DELAY);
+
+        p = menu.getLocationOnScreen();
+        r.mouseMove(p.x + menu.getWidth() / 2, p.y + menu.getHeight() / 2);
+        r.waitForIdle(DELAY);
+        r.click();
+        p = menu.getItem(0).getLocationOnScreen();
+        checkIconColor(p, "");
+        r.waitForIdle(DELAY);
+
+        p = menu.getItem(1).getLocationOnScreen();
+        checkIconColor(p, "radiobutton ");
+        r.waitForIdle(DELAY);
+
+        p = menu.getItem(2).getLocationOnScreen();
+        checkIconColor(p, "checkbox ");
+        r.waitForIdle(DELAY);
+
+        frame.dispose();
+    }
+
+    public static void main(String s[]) throws Exception {
+
+        (new MenuMultiresolutionIconTest()).doTest();
+    }
+}
diff --git a/test/java/awt/image/multiresolution/MultiDisplayTest/MultiDisplayTest.html b/test/java/awt/image/multiresolution/MultiDisplayTest/MultiDisplayTest.html
new file mode 100644
index 0000000..49989cd
--- /dev/null
+++ b/test/java/awt/image/multiresolution/MultiDisplayTest/MultiDisplayTest.html
@@ -0,0 +1,62 @@
+<!--
+ Copyright (c) 2016, 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.
+
+ 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.
+-->
+
+<html>
+<head>
+<title> MultiDisplayTest </title>
+</head>
+<body>
+<applet code="MultiDisplayTest.class" width=100 height=30></applet>
+
+This test is for OS X or Windows only.
+For other OSes please simply push "Pass".
+
+The test requires two-display configuration, where
+
+- 1st display is operating in HiDPI mode;
+- 2nd display is non-HiDPI.
+
+In other cases please simply push "Pass".
+
+
+To run test please push "Start".
+
+Then drag parent / child to different displays and check
+that the proper image is shown for every window
+(must be "black 1x" for non-HiDPI and "blue 2x" for HiDPI).
+
+Please try to drag both parent and child,
+do it fast several times and check if no artefacts occur.
+
+Try to switch display resolution (high to low and back).
+
+For Mac OS X please check also the behavior for
+translucent windows appearing on the 2nd (non-active) display
+and Mission Control behavior.
+
+Close the windows.
+
+In case if no issues occur please push "Pass", otherwise "Fail".
+
+</body>
+</html>
diff --git a/test/java/awt/image/multiresolution/MultiDisplayTest/MultiDisplayTest.java b/test/java/awt/image/multiresolution/MultiDisplayTest/MultiDisplayTest.java
new file mode 100644
index 0000000..19136c1
--- /dev/null
+++ b/test/java/awt/image/multiresolution/MultiDisplayTest/MultiDisplayTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+
+/*
+  @test
+  @bug 8142861 8143062 8147016
+  @summary Check if multiresolution image behaves properly
+           on HiDPI + non-HiDPI display pair.
+  @author a.stepanov
+  @library /lib/testlibrary
+  @build jdk.testlibrary.OSInfo
+  @run applet/manual=yesno MultiDisplayTest.html
+*/
+
+
+import java.applet.Applet;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.*;
+import jdk.testlibrary.OSInfo;
+
+
+public class MultiDisplayTest extends Applet {
+
+    private static final int W = 200, H = 200;
+
+    private static final BaseMultiResolutionImage IMG =
+        new BaseMultiResolutionImage(new BufferedImage[]{
+        generateImage(1, Color.BLACK), generateImage(2, Color.BLUE)});
+
+    private static boolean checkOS() {
+        OSInfo.OSType os = OSInfo.getOSType();
+        return (os.equals(OSInfo.OSType.WINDOWS) ||
+            os.equals(OSInfo.OSType.MACOSX));
+    }
+
+    public void init() { this.setLayout(new BorderLayout()); }
+
+    public void start() {
+
+        Button b = new Button("Start");
+        b.setEnabled(checkOS());
+
+        b.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+
+                ParentFrame p = new ParentFrame();
+                new ChildDialog(p);
+            }
+        });
+
+        add(b, BorderLayout.CENTER);
+
+        validate();
+        setVisible(true);
+    }
+
+
+    private static BufferedImage generateImage(int scale, Color c) {
+
+        BufferedImage image = new BufferedImage(
+            scale * W, scale * H, BufferedImage.TYPE_INT_RGB);
+        Graphics g = image.getGraphics();
+        g.setColor(c);
+        g.fillRect(0, 0, scale * W, scale * H);
+
+        g.setColor(Color.WHITE);
+        Font f = g.getFont();
+        g.setFont(new Font(f.getName(), Font.BOLD, scale * 48));
+        g.drawChars((scale + "X").toCharArray(), 0, 2, scale * W / 2, scale * H / 2);
+
+        return image;
+    }
+
+    private static class ParentFrame extends Frame {
+
+        public ParentFrame() {
+            EventQueue.invokeLater(this::CreateUI);
+        }
+
+        private void CreateUI() {
+
+            addWindowListener(new WindowAdapter() {
+                @Override
+                public void windowClosing(WindowEvent e) { dispose(); }
+            });
+            setSize(W, H);
+            setLocation(50, 50);
+            setTitle("parent");
+            setResizable(false);
+            setVisible(true);
+        }
+
+        @Override
+        public void paint(Graphics gr) {
+            gr.drawImage(IMG, 0, 0, this);
+        }
+    }
+
+    private static class ChildDialog extends Dialog {
+
+        public ChildDialog(Frame f) {
+            super(f);
+            EventQueue.invokeLater(this::CreateUI);
+        }
+
+        private void CreateUI() {
+
+            addWindowListener(new WindowAdapter() {
+                @Override
+                public void windowClosing(WindowEvent e) { dispose(); }
+            });
+            setSize(W, H);
+            setTitle("child");
+            setResizable(false);
+            setModal(true);
+            setVisible(true);
+        }
+
+        @Override
+        public void paint(Graphics gr) {
+            gr.drawImage(IMG, 0, 0, this);
+        }
+    }
+}
diff --git a/test/java/awt/image/multiresolution/MultiResolutionCachedImageTest.java b/test/java/awt/image/multiresolution/MultiResolutionCachedImageTest.java
new file mode 100644
index 0000000..c5d622d
--- /dev/null
+++ b/test/java/awt/image/multiresolution/MultiResolutionCachedImageTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.geom.Dimension2D;
+import java.awt.image.BufferedImage;
+import sun.awt.image.MultiResolutionCachedImage;
+
+/**
+ * @test
+ * @bug 8132123
+ * @author Alexander Scherbatiy
+ * @summary MultiResolutionCachedImage unnecessarily creates base image to get
+ *          its size
+ * @modules java.desktop/sun.awt.image
+ * @run main MultiResolutionCachedImageTest
+ */
+public class MultiResolutionCachedImageTest {
+
+    private static final Color TEST_COLOR = Color.BLUE;
+
+    public static void main(String[] args) {
+
+        Image image = new TestMultiResolutionCachedImage(100);
+
+        image.getWidth(null);
+        image.getHeight(null);
+        image.getProperty("comment", null);
+
+        int scaledSize = 50;
+        Image scaledImage = image.getScaledInstance(scaledSize, scaledSize,
+                Image.SCALE_SMOOTH);
+
+        if (!(scaledImage instanceof BufferedImage)) {
+            throw new RuntimeException("Wrong scaled image!");
+        }
+
+        BufferedImage buffScaledImage = (BufferedImage) scaledImage;
+
+        if (buffScaledImage.getWidth() != scaledSize
+                || buffScaledImage.getHeight() != scaledSize) {
+            throw new RuntimeException("Wrong scaled image!");
+        }
+
+        if (buffScaledImage.getRGB(scaledSize / 2, scaledSize / 2) != TEST_COLOR.getRGB()) {
+            throw new RuntimeException("Wrong scaled image!");
+        }
+    }
+
+    private static Dimension2D getDimension(int size) {
+        return new Dimension(size, size);
+    }
+
+    private static Dimension2D[] getSizes(int size) {
+        return new Dimension2D[]{getDimension(size), getDimension(2 * size)};
+    }
+
+    private static Image createImage(int width, int height) {
+        BufferedImage buffImage = new BufferedImage(width, height,
+                BufferedImage.TYPE_INT_RGB);
+        Graphics g = buffImage.createGraphics();
+        g.setColor(TEST_COLOR);
+        g.fillRect(0, 0, width, height);
+        return buffImage;
+    }
+
+    private static class TestMultiResolutionCachedImage
+            extends MultiResolutionCachedImage {
+
+        private final int size;
+
+        public TestMultiResolutionCachedImage(int size) {
+            super(size, size, getSizes(size), (w, h) -> createImage(w, h));
+            this.size = size;
+        }
+
+        @Override
+        public Image getResolutionVariant(double width, double height) {
+            if (width == size || height == size) {
+                throw new RuntimeException("Base image is requested!");
+            }
+            return super.getResolutionVariant(width, height);
+        }
+
+        @Override
+        protected Image getBaseImage() {
+            throw new RuntimeException("Base image is used");
+        }
+    }
+}
diff --git a/test/java/awt/image/multiresolution/MultiResolutionIcon/IconTest.java b/test/java/awt/image/multiresolution/MultiResolutionIcon/IconTest.java
new file mode 100644
index 0000000..6083366
--- /dev/null
+++ b/test/java/awt/image/multiresolution/MultiResolutionIcon/IconTest.java
@@ -0,0 +1,164 @@
+/**
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8147648 8163160
+ * @summary [hidpi] multiresolution image: wrong resolution variant is used as
+ * icon in the Unity panel
+ * @run main/manual/othervm -Dsun.java2d.uiScale=2 IconTest
+ */
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.image.BaseMultiResolutionImage;
+import java.awt.image.BufferedImage;
+import java.util.concurrent.CountDownLatch;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+
+public class IconTest {
+
+    private final static int SZ = 8;
+    private static GridBagLayout layout;
+    private static JPanel mainControlPanel;
+    private static JPanel resultButtonPanel;
+    private static JLabel instructionText;
+    private static JButton passButton;
+    private static JButton failButton;
+    private static JButton testButton;
+    private static JFrame f;
+    private static CountDownLatch latch;
+
+    private static BufferedImage generateImage(int scale, Color c) {
+        int x = SZ * scale;
+        BufferedImage img = new BufferedImage(x, x, BufferedImage.TYPE_INT_RGB);
+        Graphics g = img.getGraphics();
+        try {
+            if (g != null) {
+                g.setColor(c);
+                g.fillRect(0, 0, x, x);
+                g.setColor(Color.GREEN);
+                g.drawRect(0, 0, x-1, x-1);
+            }
+        } finally {
+            g.dispose();
+        }
+        return img;
+    }
+
+
+    private static void createUI() throws Exception {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            public void run() {
+                f = new JFrame("TrayIcon Test");
+
+                final BaseMultiResolutionImage IMG = new BaseMultiResolutionImage(
+                        new BufferedImage[]{generateImage(1, Color.RED), generateImage(2, Color.BLUE)});
+                layout = new GridBagLayout();
+                mainControlPanel = new JPanel(layout);
+                resultButtonPanel = new JPanel(layout);
+                f.setIconImage(IMG);
+                GridBagConstraints gbc = new GridBagConstraints();
+                String instructions
+                        = "<html>INSTRUCTIONS:<br>"
+                        + "Check if test button icon and unity icon are both "
+                        + "blue with green border.<br><br>"
+                        + "If Icon color is blue press pass"
+                        + " else press fail.<br><br></html>";
+
+                instructionText = new JLabel();
+                instructionText.setText(instructions);
+
+                gbc.gridx = 0;
+                gbc.gridy = 0;
+                gbc.fill = GridBagConstraints.HORIZONTAL;
+                mainControlPanel.add(instructionText, gbc);
+                testButton = new JButton("Test");
+                testButton.setActionCommand("Test");
+                mainControlPanel.add(testButton, gbc);
+
+                testButton.setIcon(new ImageIcon(IMG));
+                gbc.gridx = 0;
+                gbc.gridy = 0;
+                resultButtonPanel.add(testButton, gbc);
+
+                passButton = new JButton("Pass");
+                passButton.setActionCommand("Pass");
+                passButton.addActionListener((ActionEvent e) -> {
+                    latch.countDown();
+                    f.dispose();
+                });
+                failButton = new JButton("Fail");
+                failButton.setActionCommand("Fail");
+                failButton.addActionListener(new ActionListener() {
+                    @Override
+                    public void actionPerformed(ActionEvent e) {
+                        latch.countDown();
+                        f.dispose();
+                        throw new RuntimeException("Test Failed");
+                    }
+                });
+                gbc.gridx = 1;
+                gbc.gridy = 0;
+                resultButtonPanel.add(passButton, gbc);
+                gbc.gridx = 2;
+                gbc.gridy = 0;
+                resultButtonPanel.add(failButton, gbc);
+
+                gbc.gridx = 0;
+                gbc.gridy = 1;
+                mainControlPanel.add(resultButtonPanel, gbc);
+
+                f.add(mainControlPanel);
+                f.setSize(400, 200);
+                f.setLocationRelativeTo(null);
+                f.setVisible(true);
+
+                f.addWindowListener(new WindowAdapter() {
+                    @Override
+                    public void windowClosing(WindowEvent e) {
+                        latch.countDown();
+                        f.dispose();
+                    }
+                });
+            }
+        });
+    }
+
+    public static void main(String[] args) throws Exception {
+        latch = new CountDownLatch(1);
+        createUI();
+        latch.await();
+    }
+}
+
diff --git a/test/java/awt/image/multiresolution/MultiResolutionIcon/MultiResIconTest.java b/test/java/awt/image/multiresolution/MultiResolutionIcon/MultiResIconTest.java
new file mode 100644
index 0000000..1f1cd31
--- /dev/null
+++ b/test/java/awt/image/multiresolution/MultiResolutionIcon/MultiResIconTest.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @key headful
+ * @bug 8149371 8169043
+ * @summary multi-res. image: -Dsun.java2d.uiScale does not work for Window
+ * icons (some ambiguity for Window.setIconImages()?)
+ * @requires (os.family == "windows")
+ * @run main/othervm/manual -Dsun.java2d.uiScale=2 MultiResIconTest
+ */
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.image.BaseMultiResolutionImage;
+import java.awt.image.BufferedImage;
+import java.util.concurrent.CountDownLatch;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+
+public class MultiResIconTest {
+
+    private static GridBagLayout layout;
+    private static JPanel mainControlPanel;
+    private static JPanel resultButtonPanel;
+    private static JLabel instructionText;
+    private static JButton passButton;
+    private static JButton failButton;
+    private static JDialog f;
+    private static CountDownLatch latch;
+    private static TestFrame frame;
+    private static boolean testPassed;
+
+    private static BufferedImage generateImage(int x, Color c) {
+
+        BufferedImage img = new BufferedImage(x, x, BufferedImage.TYPE_INT_RGB);
+        Graphics g = img.getGraphics();
+        g.setColor(c);
+        g.fillRect(0, 0, x, x);
+        g.setColor(Color.WHITE);
+        g.fillRect(x / 3, x / 3, x / 3, x / 3);
+        return img;
+    }
+
+    public MultiResIconTest() throws Exception {
+        latch = new CountDownLatch(1);
+        createUI();
+        latch.await();
+
+        if (!testPassed) {
+            throw new RuntimeException("User Pressed Failed Button");
+        }
+    }
+
+    private static void createUI() throws Exception {
+        SwingUtilities.invokeAndWait(() -> {
+            frame = new TestFrame();
+            f = new JDialog(frame);
+            f.setTitle("Instruction Dialog");
+            layout = new GridBagLayout();
+            mainControlPanel = new JPanel(layout);
+            resultButtonPanel = new JPanel(layout);
+            GridBagConstraints gbc = new GridBagConstraints();
+            String instructions
+                    = "<html>    INSTRUCTIONS:<br>"
+                    + "This test is for Windows OS only.<br>"
+                    + "Make sure that 'Use Small Icons' setting is not set<br>"
+                    + "on Windows Taskbar Properties <br>"
+                    + "1) Test frame title icon and frame color should be green."
+                    + "<br>"
+                    + "2) Test frame task bar icon should be blue<br>"
+                    + "3) If color are same as mentioned in 1 and 2 press pass<br>"
+                    + "   else press fail.<br><br></html>";
+
+            instructionText = new JLabel();
+            instructionText.setText(instructions);
+
+            gbc.gridx = 0;
+            gbc.gridy = 0;
+            gbc.fill = GridBagConstraints.HORIZONTAL;
+            mainControlPanel.add(instructionText, gbc);
+            passButton = new JButton("Pass");
+            passButton.setActionCommand("Pass");
+            passButton.addActionListener((ActionEvent e) -> {
+                testPassed = true;
+                latch.countDown();
+                f.dispose();
+                frame.dispose();
+            });
+            failButton = new JButton("Fail");
+            failButton.setActionCommand("Fail");
+            failButton.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    testPassed = false;
+                    latch.countDown();
+                    f.dispose();
+                    frame.dispose();
+                    throw new RuntimeException("Test Failed");
+                }
+            });
+            gbc.gridx = 1;
+            gbc.gridy = 0;
+            resultButtonPanel.add(passButton, gbc);
+            gbc.gridx = 2;
+            gbc.gridy = 0;
+            resultButtonPanel.add(failButton, gbc);
+
+            gbc.gridx = 0;
+            gbc.gridy = 1;
+            mainControlPanel.add(resultButtonPanel, gbc);
+
+            f.add(mainControlPanel);
+            f.setSize(400, 200);
+            f.setLocationRelativeTo(null);
+            f.setVisible(true);
+
+            f.addWindowListener(new WindowAdapter() {
+                @Override
+                public void windowClosing(WindowEvent e) {
+                    testPassed = false;
+                    latch.countDown();
+                    f.dispose();
+                    frame.dispose();
+                }
+            });
+        });
+    }
+
+    private static class TestFrame extends JFrame {
+
+        private static final int W = 200;
+
+        private static final BaseMultiResolutionImage IMG
+                = new BaseMultiResolutionImage(
+                        new BufferedImage[]{generateImage(W, Color.RED),
+                            generateImage(2 * W, Color.GREEN),
+                            generateImage(4 * W, Color.BLUE)});
+
+        private static final BaseMultiResolutionImage ICON
+                = new BaseMultiResolutionImage(
+                        new BufferedImage[]{generateImage(16, Color.RED),
+                            generateImage(32, Color.GREEN),
+                            generateImage(64, Color.BLUE),
+                            generateImage(128, Color.BLACK),
+                            generateImage(256, Color.GRAY)});
+
+        public TestFrame() {
+            createUI();
+        }
+
+        private void createUI() {
+            setTitle("Test Frame");
+            setIconImage(ICON);
+            addWindowListener(new WindowAdapter() {
+                @Override
+                public void windowClosing(WindowEvent e) {
+                    dispose();
+                }
+            });
+            setSize(W, W);
+            setLocation(50, 50);
+            setResizable(false);
+            setVisible(true);
+        }
+
+        @Override
+        public void paint(Graphics gr) {
+            gr.drawImage(IMG, 0, 0, this);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        new MultiResIconTest();
+    }
+}
+
diff --git a/test/java/awt/image/multiresolution/MultiResolutionImageObserverTest.java b/test/java/awt/image/multiresolution/MultiResolutionImageObserverTest.java
new file mode 100644
index 0000000..50ba763
--- /dev/null
+++ b/test/java/awt/image/multiresolution/MultiResolutionImageObserverTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2014, 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.
+ *
+ * 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.
+ */
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.image.BufferedImage;
+import java.awt.image.ImageObserver;
+import static java.awt.image.ImageObserver.*;
+import java.io.File;
+import javax.imageio.ImageIO;
+/*
+ * @test
+ * @bug 8065627
+ * @summary Animated GIFs fail to display on a HiDPI display
+ * @author Alexander Scherbatiy
+ * @run main MultiResolutionImageObserverTest
+ */
+
+public class MultiResolutionImageObserverTest {
+
+    private static final int TIMEOUT = 500;
+
+    public static void main(String[] args) throws Exception {
+
+        generateImages();
+        Toolkit toolkit = Toolkit.getDefaultToolkit();
+        Image image = Toolkit.getDefaultToolkit().getImage(IMAGE_NAME_1X);
+
+        LoadImageObserver sizeObserver
+                = new LoadImageObserver(WIDTH | HEIGHT);
+        toolkit.prepareImage(image, -1, -1, sizeObserver);
+        waitForImageLoading(sizeObserver, "The first observer is not called");
+
+        LoadImageObserver bitsObserver
+                = new LoadImageObserver(SOMEBITS | FRAMEBITS | ALLBITS);
+
+        BufferedImage buffImage = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
+        Graphics2D g2d = (Graphics2D) buffImage.createGraphics();
+        g2d.scale(2, 2);
+        g2d.drawImage(image, 0, 0, bitsObserver);
+        waitForImageLoading(bitsObserver, "The second observer is not called!");
+        g2d.dispose();
+    }
+
+    private static void waitForImageLoading(LoadImageObserver observer,
+            String errorMessage) throws Exception {
+
+        long endTime = System.currentTimeMillis() + TIMEOUT;
+
+        while (!observer.loaded && System.currentTimeMillis() < endTime) {
+            Thread.sleep(TIMEOUT / 10);
+        }
+
+        if (!observer.loaded) {
+            throw new RuntimeException(errorMessage);
+        }
+    }
+
+    private static final String IMAGE_NAME_1X = "image.png";
+    private static final String IMAGE_NAME_2X = "image@2x.png";
+
+    private static void generateImages() throws Exception {
+        generateImage(1);
+        generateImage(2);
+    }
+
+    private static void generateImage(int scale) throws Exception {
+        BufferedImage image = new BufferedImage(
+                scale * 200, scale * 300,
+                BufferedImage.TYPE_INT_RGB);
+        Graphics g = image.createGraphics();
+        g.setColor(scale == 1 ? Color.GREEN : Color.BLUE);
+        g.fillRect(0, 0, scale * 200, scale * 300);
+        File file = new File(scale == 1 ? IMAGE_NAME_1X : IMAGE_NAME_2X);
+        ImageIO.write(image, "png", file);
+        g.dispose();
+    }
+
+    private static class LoadImageObserver implements ImageObserver {
+
+        private final int infoflags;
+        private boolean loaded;
+
+        public LoadImageObserver(int flags) {
+            this.infoflags = flags;
+        }
+
+        @Override
+        public boolean imageUpdate(Image img, int flags, int x, int y, int width, int height) {
+
+            if ((flags & infoflags) != 0) {
+                loaded = true;
+            }
+
+            return !loaded;
+        }
+    }
+}
diff --git a/test/java/awt/image/multiresolution/MultiResolutionImagePropertiesTest.java b/test/java/awt/image/multiresolution/MultiResolutionImagePropertiesTest.java
new file mode 100644
index 0000000..67bdf08
--- /dev/null
+++ b/test/java/awt/image/multiresolution/MultiResolutionImagePropertiesTest.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+import java.awt.*;
+import java.awt.image.*;
+import java.util.*;
+
+/* @test
+ * @bug 8147966
+ * @summary test multiresolution image properties
+ * @author a.stepanov
+ *
+ * @run main MultiResolutionImagePropertiesTest
+ */
+
+public class MultiResolutionImagePropertiesTest {
+
+    private final static Map<String, String> PROPS;
+    static {
+        PROPS = new HashMap<>();
+        PROPS.put("one",   "ONE");
+        PROPS.put("two",   "TWO");
+        PROPS.put("three", "THREE");
+        PROPS.put("other", "OTHER");
+        PROPS.put("test",  "TEST");
+    }
+
+    private final static int SZ = 100;
+    private final static Object UNDEF = Image.UndefinedProperty;
+
+    private static BufferedImage generateImage(int scale, Properties p) {
+
+        int x = (int) (SZ * scale);
+        BufferedImage tmp = new BufferedImage(x, x, BufferedImage.TYPE_INT_RGB);
+
+        return new BufferedImage(tmp.getColorModel(),
+                                 tmp.getRaster(),
+                                 tmp.isAlphaPremultiplied(),
+                                 p);
+    }
+
+    private static void checkProperties(BufferedImage img,
+                                        String keys[],
+                                        String undefined[]) {
+        boolean numOK = true;
+
+        if (keys.length == 0) {
+            numOK = (img.getPropertyNames() == null);
+        } else {
+            numOK = (img.getPropertyNames().length == keys.length);
+        }
+
+        if (!numOK) {
+            throw new RuntimeException("invalid number of properties");
+        }
+
+        for (String k: keys) {
+            if (!img.getProperty(k).equals(PROPS.get(k))) {
+                throw new RuntimeException("invalid property for name " + k);
+            }
+        }
+
+        for (String k: undefined) {
+            if (!img.getProperty(k).equals(UNDEF)) {
+                throw new RuntimeException("property for name " + k +
+                    " must be undefined");
+            }
+        }
+    }
+
+    private static void checkProperties(BaseMultiResolutionImage img,
+                                        String keys[],
+                                        String undefined[]) {
+        for (String k: keys) {
+            if (!img.getProperty(k, null).equals(PROPS.get(k))) {
+                throw new RuntimeException("invalid property for name " + k);
+            }
+        }
+
+        for (String k: undefined) {
+            if (!img.getProperty(k, null).equals(UNDEF)) {
+                throw new RuntimeException("property for name " + k +
+                    " must be undefined");
+            }
+        }
+    }
+
+
+    public static void main(String[] args) throws Exception {
+
+        String keys[] = new String[]{"one", "two", "three"};
+        String otherKeys[] = new String[]{"other", "test"};
+        String empty[] = new String[]{};
+
+        Properties props = new Properties();
+        for (String k: keys) { props.setProperty(k, PROPS.get(k)); }
+
+        Properties otherProps = new Properties();
+        for (String k: otherKeys) { otherProps.setProperty(k, PROPS.get(k)); }
+
+        Properties defaultProps = new Properties();
+
+
+        // === check the default state ===
+        BaseMultiResolutionImage image =
+            new BaseMultiResolutionImage(new BufferedImage[]{
+                generateImage(1, defaultProps),
+                generateImage(2, defaultProps),
+                generateImage(3, defaultProps)
+            });
+
+        for (Image var: image.getResolutionVariants()) {
+            if (((BufferedImage) var).getPropertyNames() != null) {
+                throw new RuntimeException("PropertyNames should be null");
+            }
+        }
+
+        // === default: base image is the 1st one ===
+        image =
+            new BaseMultiResolutionImage(new BufferedImage[]{
+                generateImage(1, props),
+                generateImage(2, otherProps),
+                generateImage(3, defaultProps)
+            });
+
+        checkProperties(image, keys, otherKeys);
+
+        BufferedImage var = (BufferedImage) image.getResolutionVariant(SZ, SZ);
+        checkProperties(var, keys, otherKeys);
+
+        var = (BufferedImage) image.getResolutionVariant(2 * SZ, 2 * SZ);
+        checkProperties(var, otherKeys, keys);
+
+        var = (BufferedImage) image.getResolutionVariant(3 * SZ, 3 * SZ);
+        checkProperties(var, empty, keys);
+        checkProperties(var, empty, otherKeys);
+
+        // === let the 2nd image be a base one ===
+        image =
+            new BaseMultiResolutionImage(1, new BufferedImage[]{
+                generateImage(1, props),
+                generateImage(2, otherProps),
+                generateImage(3, defaultProps)
+            });
+
+        checkProperties(image, otherKeys, keys);
+
+        var = (BufferedImage) image.getResolutionVariant(SZ, SZ);
+        checkProperties(var, keys, otherKeys);
+
+        var = (BufferedImage) image.getResolutionVariant(2 * SZ, 2 * SZ);
+        checkProperties(var, otherKeys, keys);
+
+        var = (BufferedImage) image.getResolutionVariant(3 * SZ, 3 * SZ);
+        checkProperties(var, empty, keys);
+        checkProperties(var, empty, otherKeys);
+
+        // === let the 3rd image be a base one ===
+        image =
+            new BaseMultiResolutionImage(2, new BufferedImage[]{
+                generateImage(1, defaultProps),
+                generateImage(2, defaultProps),
+                generateImage(3, props)
+            });
+
+        checkProperties(image, keys, otherKeys);
+
+        var = (BufferedImage) image.getResolutionVariant(SZ, SZ);
+        checkProperties(var, empty, keys);
+        checkProperties(var, empty, otherKeys);
+
+        var = (BufferedImage) image.getResolutionVariant(2 * SZ, 2 * SZ);
+        checkProperties(var, empty, keys);
+        checkProperties(var, empty, otherKeys);
+
+        var = (BufferedImage) image.getResolutionVariant(3 * SZ, 3 * SZ);
+        checkProperties(var, keys, otherKeys);
+
+        // === check the other properties don't affect base ===
+        checkProperties(
+            new BaseMultiResolutionImage(new BufferedImage[]{
+                generateImage(1, defaultProps),
+                generateImage(2, props),
+                generateImage(3, props)
+            }),
+            empty, keys);
+
+        checkProperties(
+            new BaseMultiResolutionImage(2, new BufferedImage[]{
+                generateImage(1, props),
+                generateImage(2, props),
+                generateImage(3, defaultProps)
+            }),
+            empty, keys);
+    }
+}
diff --git a/test/java/awt/image/multiresolution/MultiResolutionJOptionPaneIconTest.java b/test/java/awt/image/multiresolution/MultiResolutionJOptionPaneIconTest.java
new file mode 100644
index 0000000..4f82914
--- /dev/null
+++ b/test/java/awt/image/multiresolution/MultiResolutionJOptionPaneIconTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+  @test
+  @key headful
+  @bug 8150176 8150844
+  @author a.stepanov
+  @summary Check if correct resolution variant is used
+           for JOptionPane dialog / internal frame icons.
+  @library ../../../../lib/testlibrary/
+  @build ExtendedRobot
+  @run main/othervm/timeout=300 -Dsun.java2d.uiScale=1 MultiResolutionJOptionPaneIconTest
+  @run main/othervm/timeout=300 -Dsun.java2d.uiScale=2 MultiResolutionJOptionPaneIconTest
+*/
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.*;
+import javax.swing.*;
+
+public class MultiResolutionJOptionPaneIconTest implements ActionListener {
+
+    private final static Color C1X = Color.ORANGE, C2X = Color.CYAN;
+
+    private final boolean isInternal;
+
+    private volatile JFrame test;
+    private volatile JDialog dialog;
+    private volatile JInternalFrame frame;
+    private final JDesktopPane parentPane = new JDesktopPane();
+    private final JButton run = new JButton("run");
+
+    private final ExtendedRobot robot = new ExtendedRobot();
+
+    private static BufferedImage getSquare(int sz, Color c) {
+
+        BufferedImage img = new BufferedImage(sz, sz, BufferedImage.TYPE_INT_RGB);
+        Graphics g = img.getGraphics();
+        g.setColor(c);
+        g.fillRect(0, 0, sz, sz);
+        return img;
+    }
+
+    private static Icon getIcon() {
+
+        BaseMultiResolutionImage mri = new BaseMultiResolutionImage(
+            new BufferedImage[]{getSquare(16, C1X), getSquare(32, C2X)});
+        return new ImageIcon(mri);
+    }
+
+    public MultiResolutionJOptionPaneIconTest(boolean internal,
+        UIManager.LookAndFeelInfo lf) throws Exception {
+
+        UIManager.setLookAndFeel(lf.getClassName());
+
+        isInternal = internal;
+        robot.setAutoDelay(50);
+        SwingUtilities.invokeAndWait(this::UI);
+    }
+
+    private void UI() {
+
+        test = new JFrame();
+        test.setLayout(new BorderLayout());
+        test.add(parentPane, BorderLayout.CENTER);
+        run.addActionListener(this);
+        test.add(run, BorderLayout.SOUTH);
+        test.setUndecorated(true);
+        test.setSize(400, 300);
+        test.setLocation(50, 50);
+        test.setVisible(true);
+    }
+
+    private void disposeAll() {
+
+        if (dialog != null) { dialog.dispose(); }
+        if (frame  != null) {  frame.dispose(); }
+        if (test   != null) {   test.dispose(); }
+    }
+
+    public void doTest() throws Exception {
+
+        robot.waitForIdle(1000);
+        clickButton(robot);
+        robot.waitForIdle(2000);
+
+        Component c = isInternal ?
+            frame.getContentPane() : dialog.getContentPane();
+
+        System.out.println("\ncheck " + (isInternal ? "internal frame" :
+            "dialog") + " icon:");
+
+        Point pt = c.getLocationOnScreen();
+        checkColors(pt.x, c.getWidth(), pt.y, c.getHeight());
+        System.out.println("ok");
+        robot.waitForIdle();
+        SwingUtilities.invokeAndWait(this::disposeAll);
+        robot.waitForIdle();
+    }
+
+    private void checkColors(int x0, int w, int y0, int h) {
+
+        boolean is2x = "2".equals(System.getProperty("sun.java2d.uiScale"));
+        Color
+            expected   = is2x ? C2X : C1X,
+            unexpected = is2x ? C1X : C2X;
+
+        for (int y = y0; y < y0 + h; y += 5) {
+            for (int x = x0; x < x0 + w; x += 5) {
+
+                Color c = robot.getPixelColor(x, y);
+                if (c.equals(unexpected)) {
+                    throw new RuntimeException(
+                        "invalid color was found, test failed");
+                } else if (c.equals(expected)) { return; }
+            }
+        }
+
+        // no icon found at all
+        throw new RuntimeException("the icon wasn't found");
+    }
+
+    private void showDialogOrFrame() {
+
+        JOptionPane pane = new JOptionPane("",
+                                           JOptionPane.DEFAULT_OPTION,
+                                           JOptionPane.INFORMATION_MESSAGE,
+                                           getIcon());
+        pane.setOptions(new Object[]{}); // no buttons
+
+        if (isInternal) {
+            frame = pane.createInternalFrame(parentPane, "");
+            frame.setLocation(0, 0);
+            frame.setVisible(true);
+        } else {
+            dialog = pane.createDialog(parentPane, "");
+            dialog.setVisible(true);
+        }
+    }
+
+    public void clickButton(ExtendedRobot robot) {
+
+        Point pt = run.getLocationOnScreen();
+        robot.mouseMove(pt.x + run.getWidth() / 2, pt.y + run.getHeight() / 2);
+        robot.waitForIdle();
+        robot.click();
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent event) { showDialogOrFrame(); }
+
+
+    public static void main(String[] args) throws Exception {
+
+        for (UIManager.LookAndFeelInfo LF: UIManager.getInstalledLookAndFeels()) {
+            System.out.println("\nL&F: " + LF.getName());
+            (new MultiResolutionJOptionPaneIconTest(false, LF)).doTest();
+            (new MultiResolutionJOptionPaneIconTest(true , LF)).doTest();
+        }
+    }
+}
diff --git a/test/java/awt/image/multiresolution/MultiResolutionRenderingHintsTest.java b/test/java/awt/image/multiresolution/MultiResolutionRenderingHintsTest.java
new file mode 100644
index 0000000..c6a6f84
--- /dev/null
+++ b/test/java/awt/image/multiresolution/MultiResolutionRenderingHintsTest.java
@@ -0,0 +1,219 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.awt.image.BaseMultiResolutionImage;
+import static java.awt.RenderingHints.KEY_RESOLUTION_VARIANT;
+import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_BASE;
+import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_DPI_FIT;
+import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_SIZE_FIT;
+import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_DEFAULT;
+import java.awt.geom.AffineTransform;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import sun.java2d.StateTrackable;
+import sun.java2d.SunGraphics2D;
+import sun.java2d.SurfaceData;
+import sun.java2d.loops.SurfaceType;
+
+/**
+ * @test
+ * @bug 8029339
+ * @author Alexander Scherbatiy
+ * @summary Custom MultiResolution image support on HiDPI displays
+ * @modules java.desktop/sun.java2d
+ * @modules java.desktop/sun.java2d.loops
+ * @run main MultiResolutionRenderingHintsTest
+ */
+public class MultiResolutionRenderingHintsTest {
+
+    private static final int BASE_SIZE = 200;
+    private static final Color[] COLORS = {
+        Color.CYAN, Color.GREEN, Color.BLUE, Color.ORANGE, Color.RED, Color.PINK
+    };
+
+    public static void main(String[] args) throws Exception {
+
+        int length = COLORS.length;
+        BufferedImage[] resolutionVariants = new BufferedImage[length];
+        for (int i = 0; i < length; i++) {
+            resolutionVariants[i] = createRVImage(getSize(i), COLORS[i]);
+        }
+
+        BaseMultiResolutionImage mrImage = new BaseMultiResolutionImage(
+                resolutionVariants);
+
+        // base
+        Color color = getImageColor(VALUE_RESOLUTION_VARIANT_BASE, mrImage, 2, 3);
+        if (!getColorForScale(1).equals(color)) {
+            throw new RuntimeException("Wrong base resolution variant!");
+        }
+
+        // dpi fit
+        color = getImageColor(VALUE_RESOLUTION_VARIANT_DPI_FIT, mrImage, 2, 3);
+        if (!getColorForScale(2).equals(color)) {
+            throw new RuntimeException("Resolution variant is not based on dpi!");
+        }
+
+        // size fit
+        color = getImageColor(VALUE_RESOLUTION_VARIANT_SIZE_FIT, mrImage, 2, 3);
+        if (!getColorForScale(6).equals(color)) {
+            throw new RuntimeException("Resolution variant is not based on"
+                    + " rendered size!");
+        }
+
+        // default
+        // depends on the policies of the platform
+        // just check that exception is not thrown
+        getImageColor(VALUE_RESOLUTION_VARIANT_DEFAULT, mrImage, 2, 3);
+    }
+
+    private static Color getColorForScale(int scale) {
+        return COLORS[scale - 1];
+    }
+
+    private static Color getImageColor(final Object renderingHint, Image image,
+            double configScale, double graphicsScale) {
+
+        int width = image.getWidth(null);
+        int height = image.getHeight(null);
+
+        TestSurfaceData surface = new TestSurfaceData(width, height, configScale);
+        SunGraphics2D g2d = new SunGraphics2D(surface,
+                Color.BLACK, Color.BLACK, null);
+        g2d.setRenderingHint(KEY_RESOLUTION_VARIANT, renderingHint);
+        g2d.scale(graphicsScale, graphicsScale);
+        g2d.drawImage(image, 0, 0, null);
+        g2d.dispose();
+        return surface.getColor(width / 2, height / 2);
+    }
+
+    private static int getSize(int i) {
+        return (i + 1) * BASE_SIZE;
+    }
+
+    private static BufferedImage createRVImage(int size, Color color) {
+        BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
+        Graphics g = image.createGraphics();
+        g.setColor(Color.BLACK);
+        g.fillRect(0, 0, size, size);
+        g.setColor(color);
+        g.fillOval(0, 0, size, size);
+        g.dispose();
+        return image;
+    }
+
+    static class TestGraphicsConfig extends GraphicsConfiguration {
+
+        private final double scale;
+
+        TestGraphicsConfig(double scale) {
+            this.scale = scale;
+        }
+
+        @Override
+        public GraphicsDevice getDevice() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public ColorModel getColorModel() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public ColorModel getColorModel(int transparency) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public AffineTransform getDefaultTransform() {
+            return AffineTransform.getScaleInstance(scale, scale);
+        }
+
+        @Override
+        public AffineTransform getNormalizingTransform() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public Rectangle getBounds() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+    }
+
+    static class TestSurfaceData extends SurfaceData {
+
+        private final int width;
+        private final int height;
+        private final GraphicsConfiguration gc;
+        private final BufferedImage buffImage;
+        private final double scale;
+
+        public TestSurfaceData(int width, int height, double scale) {
+            super(StateTrackable.State.DYNAMIC, SurfaceType.Custom, ColorModel.getRGBdefault());
+            this.scale = scale;
+            gc = new TestGraphicsConfig(scale);
+            this.width = (int) Math.ceil(scale * width);
+            this.height = (int) Math.ceil(scale * height);
+            buffImage = new BufferedImage(this.width, this.height,
+                    BufferedImage.TYPE_INT_RGB);
+        }
+
+        Color getColor(int x, int y) {
+            int sx = (int) Math.ceil(x * scale);
+            int sy = (int) Math.ceil(y * scale);
+            return new Color(buffImage.getRGB(sx, sy));
+        }
+
+        @Override
+        public SurfaceData getReplacement() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public GraphicsConfiguration getDeviceConfiguration() {
+            return gc;
+        }
+
+        @Override
+        public Raster getRaster(int x, int y, int w, int h) {
+            return buffImage.getRaster();
+        }
+
+        @Override
+        public Rectangle getBounds() {
+            return new Rectangle(0, 0, width, height);
+        }
+
+        @Override
+        public Object getDestination() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+    }
+}
diff --git a/test/java/awt/image/multiresolution/MultiResolutionToolkitImageTest.java b/test/java/awt/image/multiresolution/MultiResolutionToolkitImageTest.java
index 57a5438..613a6d3 100644
--- a/test/java/awt/image/multiresolution/MultiResolutionToolkitImageTest.java
+++ b/test/java/awt/image/multiresolution/MultiResolutionToolkitImageTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -39,6 +39,8 @@
  * @bug 8040291
  * @author Alexander Scherbatiy
  * @summary [macosx] Http-Images are not fully loaded when using ImageIcon
+ * @modules java.desktop/sun.awt
+ *          java.desktop/sun.awt.image
  * @run main MultiResolutionToolkitImageTest
  */
 public class MultiResolutionToolkitImageTest {
diff --git a/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java b/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java
new file mode 100644
index 0000000..3f3627f
--- /dev/null
+++ b/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+
+/**
+ * @test
+ * @key headful
+ * @bug 8150176 8151773 8150176
+ * @summary Check if correct resolution variant is used for tray icon.
+ * @run main/manual/othervm -Dsun.java2d.uiScale=2 MultiResolutionTrayIconTest
+ */
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.GridBagLayout;
+import java.awt.GridBagConstraints;
+import java.awt.SystemTray;
+import java.awt.TrayIcon;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.image.BaseMultiResolutionImage;
+import java.awt.image.BufferedImage;
+import javax.swing.JFrame;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class MultiResolutionTrayIconTest {
+    private static SystemTray tray;
+    private static TrayIcon icon;
+    private static GridBagLayout layout;
+    private static JPanel mainControlPanel;
+    private static JPanel resultButtonPanel;
+    private static JLabel instructionText;
+    private static JButton passButton;
+    private static JButton failButton;
+    private static JButton startButton;
+    private static JFrame mainFrame;
+    private static CountDownLatch latch;
+
+    public static void main(String[] args) throws Exception {
+        latch = new CountDownLatch(1);
+        createUI();
+        latch.await(200, TimeUnit.SECONDS);
+    }
+
+    public static void createUI() throws Exception {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            public void run() {
+                mainFrame = new JFrame("TrayIcon Test");
+                boolean trayIsSupported = SystemTray.isSupported();
+                tray = SystemTray.getSystemTray();
+                Dimension d = tray.getTrayIconSize();
+                icon = new TrayIcon(createIcon(d.width, d.height));
+                icon.setImageAutoSize(true);
+                layout = new GridBagLayout();
+                mainControlPanel = new JPanel(layout);
+                resultButtonPanel = new JPanel(layout);
+
+                GridBagConstraints gbc = new GridBagConstraints();
+                String instructions
+                        = "<html>INSTRUCTIONS:<br>"
+                        + "Press start button to add icon to system tray.<br><br>"
+                        + "If Icon color is green test"
+                        + " passes else failed.<br><br></html>";
+
+                instructionText = new JLabel();
+                instructionText.setText(instructions);
+
+                gbc.gridx = 0;
+                gbc.gridy = 0;
+                gbc.fill = GridBagConstraints.HORIZONTAL;
+                mainControlPanel.add(instructionText, gbc);
+                startButton = new JButton("Start");
+                startButton.setActionCommand("Start");
+                if (trayIsSupported) {
+
+                    startButton.addActionListener((ActionEvent e) -> {
+                        doTest();
+                    });
+                } else {
+                    startButton.setEnabled(false);
+                    System.out.println("system tray is not supported");
+                    latch.countDown();
+                }
+                gbc.gridx = 0;
+                gbc.gridy = 0;
+                resultButtonPanel.add(startButton, gbc);
+
+                passButton = new JButton("Pass");
+                passButton.setActionCommand("Pass");
+                passButton.addActionListener((ActionEvent e) -> {
+                    latch.countDown();
+                    removeIcon();
+                    mainFrame.dispose();
+                });
+                failButton = new JButton("Fail");
+                failButton.setActionCommand("Fail");
+                failButton.addActionListener(new ActionListener() {
+                    @Override
+                    public void actionPerformed(ActionEvent e) {
+                        removeIcon();
+                        latch.countDown();
+                        mainFrame.dispose();
+                        throw new RuntimeException("Test Failed");
+                    }
+                });
+                gbc.gridx = 1;
+                gbc.gridy = 0;
+                resultButtonPanel.add(passButton, gbc);
+                gbc.gridx = 2;
+                gbc.gridy = 0;
+                resultButtonPanel.add(failButton, gbc);
+
+                gbc.gridx = 0;
+                gbc.gridy = 1;
+                mainControlPanel.add(resultButtonPanel, gbc);
+
+                mainFrame.add(mainControlPanel);
+                mainFrame.setSize(400, 200);
+                mainFrame.setLocationRelativeTo(null);
+                mainFrame.setVisible(true);
+
+                mainFrame.addWindowListener(new WindowAdapter() {
+                    @Override
+                    public void windowClosing(WindowEvent e) {
+                        removeIcon();
+                        latch.countDown();
+                        mainFrame.dispose();
+                    }
+                });
+            }
+        });
+
+    }
+
+    private static BaseMultiResolutionImage createIcon(int w, int h) {
+        return new BaseMultiResolutionImage(
+                new BufferedImage[]{generateImage(w, h, 1, Color.RED),
+                    generateImage(w, h, 2, Color.GREEN)});
+    }
+
+    private static BufferedImage generateImage(int w, int h, int scale, Color c) {
+
+        int x = w * scale, y = h * scale;
+        BufferedImage img = new BufferedImage(x, y, BufferedImage.TYPE_INT_RGB);
+        Graphics g = img.getGraphics();
+        g.setColor(c);
+        g.fillRect(0, 0, x, y);
+        g.setColor(Color.WHITE);
+        g.fillRect(x / 3, y / 3, x / 3, y / 3);
+        return img;
+    }
+
+    private static void doTest() {
+
+        if (tray.getTrayIcons().length > 0) {
+            return;
+        }
+        try {
+            tray.add(icon);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static void removeIcon() {
+        if (tray != null) {
+            tray.remove(icon);
+        }
+    }
+}
+
diff --git a/test/java/awt/image/multiresolution/MultiresolutionIconTest.java b/test/java/awt/image/multiresolution/MultiresolutionIconTest.java
new file mode 100644
index 0000000..f83d945
--- /dev/null
+++ b/test/java/awt/image/multiresolution/MultiresolutionIconTest.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2016, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @key headful
+ * @bug 8150724 8151303
+ * @author a.stepanov
+ * @summary Check that correct resolution variants are chosen for icons
+ *          when multiresolution image is used for their construction.
+ *
+ * @library ../../../../lib/testlibrary/
+ * @build ExtendedRobot
+ * @run main/othervm/timeout=240 -Dsun.java2d.uiScale=1 MultiresolutionIconTest
+ * @run main/othervm/timeout=240 -Dsun.java2d.uiScale=2 MultiresolutionIconTest
+ */
+
+
+// TODO: please remove the "@requires" tag after 8151303 fix
+
+
+import java.awt.*;
+import java.awt.event.InputEvent;
+import java.awt.image.BaseMultiResolutionImage;
+import java.awt.image.BufferedImage;
+import javax.swing.*;
+
+public class MultiresolutionIconTest extends JFrame {
+
+    private final static int SZ = 100;
+    private final static int N = 5; // number of components
+
+    private final static String SCALE = "sun.java2d.uiScale";
+    private final static Color C1X = Color.RED;
+    private final static Color C2X = Color.BLUE;
+
+    private JLabel lbl;
+    private JTabbedPane tabbedPane;
+
+    private final ExtendedRobot r;
+
+    private static BufferedImage generateImage(int sz, Color c) {
+
+        BufferedImage img = new BufferedImage(sz, sz, BufferedImage.TYPE_INT_RGB);
+        Graphics g = img.getGraphics();
+        g.setColor(c);
+        g.fillRect(0, 0, sz, sz);
+        return img;
+    }
+
+    public MultiresolutionIconTest(UIManager.LookAndFeelInfo lf) throws Exception {
+
+        UIManager.setLookAndFeel(lf.getClassName());
+        r = new ExtendedRobot();
+        SwingUtilities.invokeAndWait(this::UI);
+    }
+
+    private void UI() {
+
+        setUndecorated(true);
+
+        BufferedImage img1x = generateImage(SZ / 2, C1X);
+        BufferedImage img2x = generateImage(SZ, C2X);
+        BaseMultiResolutionImage mri = new BaseMultiResolutionImage(
+            new BufferedImage[]{img1x, img2x});
+        Icon icon = new ImageIcon(mri);
+
+        // hardcoded icon size for OS X (Mac OS X L&F) - see JDK-8151060
+        BufferedImage tab1x = generateImage(16, C1X);
+        BufferedImage tab2x = generateImage(32, C2X);
+        BaseMultiResolutionImage tabMRI = new BaseMultiResolutionImage(
+            new BufferedImage[]{tab1x, tab2x});
+        Icon tabIcon = new ImageIcon(tabMRI);
+
+        setSize((N + 1) * SZ, SZ);
+        setLocation(50, 50);
+
+        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        getContentPane().setLayout(new GridLayout(1, 1));
+
+        JPanel p = new JPanel();
+        p.setLayout(new GridLayout(1, N));
+
+        JButton btn = new JButton(icon);
+        p.add(btn);
+
+        JToggleButton tbn = new JToggleButton(icon);
+        p.add(tbn);
+
+        JRadioButton rbn = new JRadioButton(icon);
+        rbn.setHorizontalAlignment(SwingConstants.CENTER);
+        p.add(rbn);
+
+        JCheckBox cbx = new JCheckBox(icon);
+        cbx.setHorizontalAlignment(SwingConstants.CENTER);
+        p.add(cbx);
+
+        lbl = new JLabel(icon);
+        p.add(lbl);
+
+        tabbedPane = new JTabbedPane(JTabbedPane.LEFT);
+        tabbedPane.addTab("", tabIcon, p);
+        getContentPane().add(tabbedPane);
+
+        setResizable(false);
+        setVisible(true);
+    }
+
+    private boolean checkPressedColor(int x, int y, Color ok) {
+
+        r.mouseMove(x, y);
+        r.waitForIdle();
+        r.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+        r.waitForIdle(100);
+        Color c = r.getPixelColor(x, y);
+        r.waitForIdle(100);
+        r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+        r.waitForIdle(100);
+        if (!c.equals(ok)) { return false; }
+        // check the icon's color hasn't changed
+        // after the mouse was released
+        c = r.getPixelColor(x, y);
+        return c.equals(ok);
+    }
+
+    private boolean checkTabIcon(
+        int xStart, int xEnd, int yStart, int yEnd, Color ok, Color nok) {
+
+        for (int y = yStart; y < yEnd; y += 2) {
+            for (int x = xStart; x < xEnd; x += 2) {
+                Color c = r.getPixelColor(x, y);
+                if (c.equals(nok)) { return false; }
+                else if (c.equals(ok)) {
+                    // shift a bit to avoid the selection effects
+                    return checkPressedColor(x + 5, y + 5, ok);
+                }
+            }
+        }
+
+        return false; // didn't find the icon
+    }
+
+
+    private void doTest() {
+
+        r.waitForIdle(2000);
+        String scale = System.getProperty(SCALE);
+        boolean is2x = "2".equals(scale);
+        Color expected = is2x ? C2X : C1X;
+        Color unexpected = is2x ? C1X : C2X;
+
+        Point p = lbl.getLocationOnScreen();
+        int x = p.x + lbl.getWidth() / 2;
+        int y = p.y + lbl.getHeight() / 2;
+        int w = lbl.getWidth();
+
+        boolean ok = true, curr;
+        Color c;
+        String components[] = new String[]{
+            "JLabel", "JCheckBox", "JRadioButton", "JToggleButton", "JButton"};
+        for (int i = 0; i < N; i++) {
+
+            curr = true;
+            int t = x - i * w;
+
+            // check icon color
+            c = r.getPixelColor(t, y);
+            System.out.print(components[i] + " icon: ");
+            if (!c.equals(expected)) {
+                curr = false;
+            } else {
+                // check icon color when mouse button pressed - see JDK-8151303
+                curr = checkPressedColor(t, y, expected);
+            }
+
+            System.out.println(curr ? "ok" : "nok");
+            ok = ok && curr;
+
+            r.waitForIdle();
+        }
+
+        int x0 = tabbedPane.getLocationOnScreen().x;
+        int x1 = x - ((N - 1) * w + w / 2);
+        int y0 = getLocationOnScreen().y;
+        int y1 = y0 + getHeight();
+        curr = checkTabIcon(x0, x1, y0, y1, expected, unexpected);
+
+        System.out.println("JTabbedPane icon: " + (curr ? "ok" : "nok"));
+        ok = ok && curr;
+
+        if (!ok) { throw new RuntimeException("test failed"); }
+
+        r.waitForIdle();
+        dispose();
+    }
+
+    public static void main(String[] args) throws Exception {
+
+        for (UIManager.LookAndFeelInfo LF: UIManager.getInstalledLookAndFeels()) {
+            System.out.println("\nL&F: " + LF.getName());
+            (new MultiresolutionIconTest(LF)).doTest();
+        }
+    }
+}
diff --git a/test/java/awt/image/multiresolution/MultiresolutionSourceTest.java b/test/java/awt/image/multiresolution/MultiresolutionSourceTest.java
new file mode 100644
index 0000000..e9aebf4
--- /dev/null
+++ b/test/java/awt/image/multiresolution/MultiresolutionSourceTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8151269
+ * @author a.stepanov
+ * @summary Multiresolution image: check that the base resolution variant
+ *          source is passed to the corresponding ImageConsumer
+ * @run main MultiresolutionSourceTest
+ */
+
+import java.awt.*;
+import java.awt.image.*;
+
+public class MultiresolutionSourceTest {
+
+    private static class Checker implements ImageConsumer {
+
+        private final int refW, refH, refType;
+        private final boolean refHasAlpha;
+        private final Color refColor;
+
+        public Checker(int     w,
+                       int     h,
+                       Color   c,
+                       boolean hasAlpha,
+                       int     transferType) {
+            refW = w;
+            refH = h;
+            refColor = c;
+            refHasAlpha = hasAlpha;
+            refType = transferType;
+        }
+
+        @Override
+        public void imageComplete(int status) {}
+
+        @Override
+        public void setColorModel(ColorModel model) {
+
+            boolean a = model.hasAlpha();
+            if (a != refHasAlpha) {
+                throw new RuntimeException("invalid hasAlpha: " + a);
+            }
+
+            int tt = model.getTransferType();
+            if (tt != refType) {
+                throw new RuntimeException("invalid transfer type: " + tt);
+            }
+        }
+
+        @Override
+        public void setDimensions(int w, int h) {
+
+            if (w != refW) { throw new RuntimeException("invalid width: " + w +
+                ", expected: " + refW); }
+
+            if (h != refH) { throw new RuntimeException("invalid height: " + h +
+                ", expected: " + refH); }
+        }
+
+        @Override
+        public void setHints(int flags) {}
+
+        @Override
+        public void setPixels(int x, int y, int w, int h, ColorModel model,
+                              byte pixels[], int offset, int scansize) {
+
+            for (int i = 0; i < pixels.length; i++) {
+                int p = pixels[i];
+                // just in case...
+                Color c = model.hasAlpha() ?
+                    new Color(model.getRed  (p),
+                              model.getGreen(p),
+                              model.getBlue (p),
+                              model.getAlpha(p)) :
+                    new Color(model.getRGB(p));
+
+                if (!c.equals(refColor)) {
+                    throw new RuntimeException("invalid color: " + c +
+                        ", expected: " + refColor);
+                }
+            }
+        }
+
+        @Override
+        public void setPixels(int x, int y, int w, int h, ColorModel model,
+                              int pixels[], int offset, int scansize) {
+
+            for (int i = 0; i < pixels.length; i++) {
+                int p = pixels[i];
+                Color c = model.hasAlpha() ?
+                    new Color(model.getRed  (p),
+                              model.getGreen(p),
+                              model.getBlue (p),
+                              model.getAlpha(p)) :
+                    new Color(model.getRGB(p));
+
+                if (!c.equals(refColor)) {
+                    throw new RuntimeException("invalid color: " + c +
+                        ", expected: " + refColor);
+                }
+            }
+        }
+
+        @Override
+        public void setProperties(java.util.Hashtable props) {}
+    }
+
+    private static BufferedImage generateImage(int w, int h, Color c, int type) {
+
+        BufferedImage img = new BufferedImage(w, h, type);
+        Graphics g = img.getGraphics();
+        g.setColor(c);
+        g.fillRect(0, 0, w, h);
+        return img;
+    }
+
+    public static void main(String[] args) {
+
+        final int w1 = 20, w2 = 100, h1 = 30, h2 = 50;
+        final Color
+            c1 = new Color(255, 0, 0, 100), c2 = Color.BLACK, gray = Color.GRAY;
+
+        BufferedImage img1 =
+            generateImage(w1, h1, c1, BufferedImage.TYPE_INT_ARGB);
+
+        BufferedImage dummy =
+            generateImage(w1 + 5, h1 + 5, gray, BufferedImage.TYPE_BYTE_GRAY);
+
+        BufferedImage img2 =
+            generateImage(w2, h2, c2, BufferedImage.TYPE_BYTE_BINARY);
+
+        BufferedImage vars[] = new BufferedImage[] {img1, dummy, img2};
+
+        // default base image index (zero)
+        BaseMultiResolutionImage mri1 = new BaseMultiResolutionImage(vars);
+        // base image index = 2
+        BaseMultiResolutionImage mri2 = new BaseMultiResolutionImage(2, vars);
+
+        // do checks
+        mri1.getSource().startProduction(
+                new Checker(w1, h1, c1, true, DataBuffer.TYPE_INT));
+
+        mri2.getSource().startProduction(
+                new Checker(w2, h2, c2, false, DataBuffer.TYPE_BYTE));
+    }
+}
diff --git a/test/java/util/WeakHashMap/GCDuringIteration.java b/test/java/util/WeakHashMap/GCDuringIteration.java
index 4744ecc..5228fa8 100644
--- a/test/java/util/WeakHashMap/GCDuringIteration.java
+++ b/test/java/util/WeakHashMap/GCDuringIteration.java
@@ -115,7 +115,7 @@
             it.next();          // protects first entry
             System.out.println(map.values());
             foos[first] = null;
-            tryWaitForFinalizersToRun()
+            tryWaitForFinalizersToRun();
             equal(map.size(), first+1);
             System.out.println(map.values());
             checkIterator(it, first-1);
diff --git a/test/javax/swing/text/DevanagariEditor.java b/test/javax/swing/text/DevanagariEditor.java
new file mode 100644
index 0000000..3781a1b
--- /dev/null
+++ b/test/javax/swing/text/DevanagariEditor.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8151725
+ * @summary Tests no exception creating a JEditorPane with Devanagari
+ */
+
+import javax.swing.JEditorPane;
+
+public class DevanagariEditor {
+    public static void main(String[] args) {
+        new JEditorPane().setText("\u0930\u093E\u0915\u094D\u0937\u0938");
+    }
+}
diff --git a/test/javax/swing/text/GlyphPainter2/6427244/bug6427244.java b/test/javax/swing/text/GlyphPainter2/6427244/bug6427244.java
new file mode 100644
index 0000000..cc32aeb
--- /dev/null
+++ b/test/javax/swing/text/GlyphPainter2/6427244/bug6427244.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2011, 2016, 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.
+ *
+ * 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.
+ *
+ */
+
+/* @test
+   @bug 6427244 8144240
+   @summary Test that pressing HOME correctly moves caret in I18N document.
+   @author Sergey Groznyh
+   @library ../../../regtesthelpers
+   @build JRobot Util TestCase
+   @run main bug6427244
+*/
+
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Point;
+import java.awt.Shape;
+import java.awt.event.KeyEvent;
+import javax.swing.JFrame;
+import javax.swing.JTextPane;
+import javax.swing.SwingUtilities;
+import javax.swing.text.Position;
+
+public class bug6427244 extends TestCase {
+    private static final JRobot ROBOT = JRobot.getRobot();
+
+    final static int TP_SIZE = 200;
+    final static String[] SPACES = new String[] {
+        "\u0020", // ASCII space
+        "\u2002", // EN space
+        "\u2003", // EM space
+        "\u2004", // THREE-PER-EM space
+        "\u2005", // ... etc.
+        "\u2006",
+        //"\u2007",
+        "\u2008",
+        "\u2009",
+        "\u200a",
+        "\u200b",
+        "\u205f",
+        "\u3000",
+    };
+    final static String[] WORDS = new String[] {
+        "It", "is", "a", "long", "paragraph", "for", "testing", "GlyphPainter2\n\n",
+    };
+
+    public static void main(String[] args) {
+        bug6427244 t = new bug6427244();
+        for (String space: SPACES) {
+            t.init(space);
+            t.runAllTests();
+        }
+
+        System.out.println("OK");
+    }
+
+    void init(final String space) {
+        try {
+            SwingUtilities.invokeAndWait(new Runnable() {
+                public void run() {
+                    String text = null;
+                    for (String word: WORDS) {
+                        if (text == null) {
+                            text = "";
+                        } else {
+                            text += space;
+                        }
+                        text += word;
+                    }
+                    tp = new JTextPane();
+                    tp.setText(text +
+                            "Some arabic: \u062a\u0641\u0627\u062d and some not.");
+                    if (jf == null) {
+                        jf = new JFrame();
+                        jf.setTitle("bug6427244");
+                        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+                        jf.setSize(TP_SIZE, TP_SIZE);
+                        jf.setVisible(true);
+                    }
+                    Container c = jf.getContentPane();
+                    c.removeAll();
+                    c.add(tp);
+                    c.invalidate();
+                    c.validate();
+                    dim = c.getSize();
+                }
+            });
+            Util.blockTillDisplayed(tp);
+            ROBOT.waitForIdle();
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    public void testCaretPosition() {
+        Point p = tp.getLocationOnScreen();
+        // the right-top corner position
+        p.x += (dim.width - 5);
+        p.y += 5;
+        ROBOT.mouseMove(p.x, p.y);
+        ROBOT.clickMouse();
+        ROBOT.hitKey(KeyEvent.VK_HOME);
+        ROBOT.waitForIdle();
+        // this will fail if caret moves out of the 1st line.
+        assertEquals(0, getCaretOrdinate());
+    }
+
+    int getCaretOrdinate() {
+        final int[] y = new int[1];
+        try {
+            SwingUtilities.invokeAndWait(new Runnable() {
+                public void run() {
+                    Shape s;
+                    try {
+                        s = tp.getUI().getRootView(tp).modelToView(
+                                        tp.getCaretPosition(), tp.getBounds(),
+                                        Position.Bias.Forward);
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                    y[0] = s.getBounds().y;
+                }
+            });
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return y[0];
+    }
+
+    JFrame jf;
+    JTextPane tp;
+    Dimension dim;
+}
diff --git a/test/javax/swing/text/Utilities/8142966/SwingFontMetricsTest.java b/test/javax/swing/text/Utilities/8142966/SwingFontMetricsTest.java
new file mode 100644
index 0000000..98a0206
--- /dev/null
+++ b/test/javax/swing/text/Utilities/8142966/SwingFontMetricsTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+import java.awt.Font;
+import java.awt.Graphics;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.SwingUtilities;
+
+/**
+ * @test
+ * @bug 8142966
+ * @summary Wrong cursor position in text components on HiDPI display
+ * @run main/othervm -Dsun.java2d.uiScale=2 SwingFontMetricsTest
+ */
+public class SwingFontMetricsTest {
+
+    private static final String LOWER_CASE_TEXT = "the quick brown fox jumps over the lazy dog";
+    private static final String UPPER_CASE_TEXT = LOWER_CASE_TEXT.toUpperCase();
+    private static final String TEXT = LOWER_CASE_TEXT + UPPER_CASE_TEXT;
+    private static boolean passed = false;
+    private static CountDownLatch latch = new CountDownLatch(1);
+
+    public static void main(String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(SwingFontMetricsTest::createAndShowGUI);
+        latch.await(5, TimeUnit.SECONDS);
+
+        if (!passed) {
+            throw new RuntimeException("Test Failed!");
+        }
+    }
+
+    private static void createAndShowGUI() {
+        final JFrame frame = new JFrame();
+        frame.setSize(300, 300);
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        JLabel label = new JLabel(TEXT) {
+            @Override
+            public void paint(Graphics g) {
+                super.paint(g);
+                Font font = getFont();
+                int width1 = getFontMetrics(font).stringWidth(TEXT);
+                int width2 = g.getFontMetrics(font).stringWidth(TEXT);
+                passed = (width1 == width2);
+                latch.countDown();
+                frame.dispose();
+            }
+        };
+        frame.add(label);
+        frame.setVisible(true);
+    }
+}
+
diff --git a/test/jb/javax/swing/JEditorPane/LargeQuickDoc.java b/test/jb/javax/swing/JEditorPane/LargeQuickDoc.java
new file mode 100644
index 0000000..4348f20
--- /dev/null
+++ b/test/jb/javax/swing/JEditorPane/LargeQuickDoc.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import javax.swing.JEditorPane;
+import javax.swing.JFrame;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+import javax.swing.text.html.HTMLEditorKit;
+import java.io.IOException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+
+/* @test
+ * @bug 8151725
+ * @summary regression test on JRE-9
+ */
+
+public class LargeQuickDoc {
+
+    static private String getText() throws IOException {
+        return new String(
+                Files.readAllBytes(
+                        FileSystems.getDefault().getPath(
+                                System.getProperty("test.src", "."), "LargeQuickDoc.txt")));
+    }
+
+
+    public static void main(String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(() -> {
+
+            JFrame f = new JFrame();
+            JEditorPane editorPane = new javax.swing.JEditorPane("text/html", "");
+            editorPane.setEditorKit(new HTMLEditorKit());
+            editorPane.setEditable(false);
+
+            JScrollPane scrollPane = new JScrollPane(editorPane);
+            scrollPane.setBorder(null);
+
+            try {
+                editorPane.setText(getText());
+            } catch (IOException | ArrayIndexOutOfBoundsException e) {
+                throw new RuntimeException(e);
+            }
+
+            f.getContentPane().add(scrollPane);
+            f.setSize(500, 500);
+            f.setVisible(true);
+        });
+    }
+}
\ No newline at end of file
diff --git a/test/jb/javax/swing/JEditorPane/LargeQuickDoc.txt b/test/jb/javax/swing/JEditorPane/LargeQuickDoc.txt
new file mode 100644
index 0000000..83c4a78
--- /dev/null
+++ b/test/jb/javax/swing/JEditorPane/LargeQuickDoc.txt
@@ -0,0 +1,6500 @@
+<b>System</b><br/><pre>global class <b>String</b><br/>extends <a href="psi_element://Object">Object</a><br/></pre><br/>
+<span>
+<span>
+<a name="apex_methods_system_string"><!– –></a><div class="nested0">
+<h1 class="helpHead1"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a>String Class</span></h1>
+
+
+
+<div class="body">
+<div class="shortdesc">Contains methods for the String primitive data type.</div>
+
+<div class="section">
+<h2 class="helpHead2">Namespace</h2>
+<p class="p"><a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_namespace_System.htm" title="The System namespace provides classes and methods for core Apex functionality.">System</a></p>
+</div>
+
+<div class="section">
+<h2 class="helpHead2">Usage</h2>
+<p class="p">For more information on Strings, see <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/langCon_apex_primitives.htm" title="Apex uses the same primitive data types as the SOAP API. All primitive data types are passed by value.">Primitive Data Types</a>.</p>
+</div>
+
+</div>
+
+<div class="topic reference nested1" lang="en-us" lang="en-us" id="apex_System_String_methods">
+<a name="apex_System_String_methods"><!– –></a>
+<h2 class="helpHead2"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a>String Methods</span></h2>
+
+
+<div class="body refbody">
+<div class="section">
+<p class="p">The following are methods for <samp class="codeph apex_code"><span class="keyword">String</span></samp>.</p>
+</div>
+
+</div>
+
+<div id="sfdc:seealso" class="related-links">
+<ul class="ullinks">
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_abbreviate">abbreviate(maxWidth)</a></strong><br>
+Returns an abbreviated version of the String, of the specified length and with ellipses appended if the current String is longer than the specified length; otherwise, returns the original String without ellipses.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_abbreviate_2">abbreviate(maxWidth, offset)</a></strong><br>
+Returns an abbreviated version of the String, starting at the specified character offset and of the specified length. The returned String has ellipses appended at the start and the end if characters have been removed at these locations.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_capitalize">capitalize()</a></strong><br>
+Returns the current String with the first letter changed to title case.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_center">center(size)</a></strong><br>
+Returns a version of the current String of the specified size padded with spaces on the left and right, so that it appears in the center. If the specified size is smaller than the current String size, the entire String is returned without added spaces.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_center_2">center(size, paddingString)</a></strong><br>
+Returns a version of the current String of the specified size padded with the specified String on the left and right, so that it appears in the center. If the specified size is smaller than the current String size, the entire String is returned without padding.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_charAt">charAt(index)</a></strong><br>
+Returns the value of the character at the specified index.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_codePointAt">codePointAt(index)</a></strong><br>
+Returns the Unicode code point value at the specified index.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_codePointBefore">codePointBefore(index)</a></strong><br>
+Returns the Unicode code point value that occurs before the specified index.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_codePointCount">codePointCount(beginIndex, endIndex)</a></strong><br>
+Returns the number of Unicode code points within the specified text range.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_compareTo">compareTo(secondString)</a></strong><br>
+Compares two strings lexicographically, based on the Unicode value of each character in the Strings.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_contains">contains(substring)</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if and only if the String that       called the method contains the specified sequence of characters in          <var class="keyword varname">substring</var>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_containsAny">containsAny(inputString)</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the current String contains any of the characters in the specified String; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_containsIgnoreCase">containsIgnoreCase(substring)</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the current String contains the specified sequence of characters without regard to case; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_containsNone">containsNone(inputString)</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the current String doesn’t     contain any of the characters in the specified String; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_containsOnly">containsOnly(inputString)</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the current String contains characters only from the specified sequence of characters and not any other characters; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_containsWhitespace">containsWhitespace()</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the current String contains any white space characters; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_countMatches">countMatches(substring)</a></strong><br>
+Returns the number of times the specified substring occurs in the current String.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_deleteWhitespace">deleteWhitespace()</a></strong><br>
+Returns a version of the current String with all white space characters removed.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_difference">difference(secondString)</a></strong><br>
+Returns the difference between the current String and the specified String.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_endsWith">endsWith(suffix)</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the String that called the method ends with the specified <var class="keyword varname">suffix</var>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_endsWithIgnoreCase">endsWithIgnoreCase(suffix)</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the current String ends with the specified suffix; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_equals">equals(secondString)</a></strong><br>
+Deprecated. This method is replaced by <samp class="codeph apex_code">equals(stringOrId)</samp>. Returns          <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the passed-in string is not null and       represents the same binary sequence of characters as the current string. Use this method to       perform case-sensitive comparisons.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_equals_2">equals(stringOrId)</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the          passed-in object is not null and represents the same binary sequence of characters as the          current string. Use this method to compare a string to an object that represents a string          or an ID.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_equalsIgnoreCase">equalsIgnoreCase(secondString)</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the    <var class="keyword varname">secondString</var> is not null and represents the same sequence of characters as the   String that called the method, ignoring case.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_escapeCsv">escapeCsv()</a></strong><br>
+Returns a String for a CSV column enclosed in double quotes, if required.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_escapeEcmaScript">escapeEcmaScript()</a></strong><br>
+Escapes the characters in the String using EcmaScript String rules.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_escapeHtml3">escapeHtml3()</a></strong><br>
+Escapes the characters in a String using HTML 3.0 entities.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_escapeHtml4">escapeHtml4()</a></strong><br>
+Escapes the characters in a String using HTML 4.0 entities.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_escapeJava">escapeJava()</a></strong><br>
+Returns a String whose characters are escaped using Java String rules. Characters escaped include quotes and control characters, such as tab, backslash, and carriage return characters.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_escapeSingleQuotes">escapeSingleQuotes(stringToEscape)</a></strong><br>
+Returns a String with the escape character () added before any single quotation marks in the String <var class="keyword varname">s</var>. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_escapeUnicode">escapeUnicode()</a></strong><br>
+Returns a String whose Unicode characters are escaped to a Unicode escape sequence.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_escapeXml">escapeXml()</a></strong><br>
+Escapes the characters in a String using XML entities.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_format">format(stringToFormat, formattingArguments)</a></strong><br>
+Treat the current string as a pattern that should be used for substitution in the same manner as <samp class="codeph apex_code">apex:outputText</samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_fromCharArray">fromCharArray(charArray)</a></strong><br>
+Returns a String from the values of the list of integers. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_getChars">getChars()</a></strong><br>
+Returns an array of character values that represent the characters in this string.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_getCommonPrefix">getCommonPrefix(strings)</a></strong><br>
+Returns the initial sequence of characters as a String that is common to all the specified Strings.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_getLevenshteinDistance">getLevenshteinDistance(stringToCompare)</a></strong><br>
+Returns the Levenshtein distance between the current String and the specified String.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_getLevenshteinDistance_2">getLevenshteinDistance(stringToCompare, threshold)</a></strong><br>
+Returns the Levenshtein distance between the current String and the specified String if it is less than or equal than the given threshold; otherwise, returns -1.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_hashCode">hashCode()</a></strong><br>
+Returns a hash code value for this string. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_indexOf">indexOf(substring)</a></strong><br>
+Returns the index of the first occurrence of the specified substring. If the substring does not occur, this method returns -1.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_indexOf_2">indexOf(substring, index)</a></strong><br>
+Returns the zero-based index of the first occurrence of the specified substring from the point of the given index. If the substring does not occur, this method returns -1.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_indexOfAny">indexOfAny(substring)</a></strong><br>
+Returns the zero-based index of the first occurrence of any character specified in the substring. If none of the characters occur, returns -1. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_indexOfAnyBut">indexOfAnyBut(substring)</a></strong><br>
+Returns the zero-based index of the first occurrence of a character that is not in the specified substring. Otherwise, returns -1. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_indexOfChar">indexOfChar(character)</a></strong><br>
+Returns the index of the first occurrence of the character that corresponds to the specified character value.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_indexOfChar_2">indexOfChar(character, startIndex)</a></strong><br>
+Returns the index of the first occurrence of the character that corresponds to the specified character value, starting from the specified index.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_indexOfDifference">indexOfDifference(stringToCompare)</a></strong><br>
+Returns the zero-based index of the character where the current String begins to differ from the specified String.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_indexOfIgnoreCase">indexOfIgnoreCase(substring)</a></strong><br>
+Returns the zero-based index of the first occurrence of the specified substring without regard to case. If the substring does not occur, this method returns -1.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_indexOfIgnoreCase_2">indexOfIgnoreCase(substring, startPosition)</a></strong><br>
+Returns the zero-based index of the first occurrence of the specified substring from the point of index <var class="keyword varname">i</var>, without regard to case. If the substring does not occur, this method returns -1. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_isAllLowerCase">isAllLowerCase()</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if all characters in the current String are lowercase; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_isAllUpperCase">isAllUpperCase()</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if all characters in the current String are uppercase; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_isAlpha">isAlpha()</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if all characters in the current String are Unicode letters only; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_isAlphaSpace">isAlphaSpace()</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if all characters in the current String are Unicode letters or spaces only; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_isAlphanumeric">isAlphanumeric()</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if all characters in the current String are Unicode letters or numbers only; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_isAlphanumericSpace">isAlphanumericSpace()</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if all characters in the current String are Unicode letters, numbers, or spaces only; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_isAsciiPrintable">isAsciiPrintable()</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the current String contains only ASCII printable characters; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_isBlank">isBlank(inputString)</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the specified String is white space, empty (), or null; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_isEmpty">isEmpty(inputString)</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the specified String is empty () or null; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_isNotBlank">isNotBlank(inputString)</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the specified String is not whitespace, not empty (), and not null; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_isNotEmpty">isNotEmpty(inputString)</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the specified String is not empty () and not null; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_isNumeric">isNumeric()</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the current String contains only Unicode digits; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_isNumericSpace">isNumericSpace()</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the current String contains only Unicode digits or spaces; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_isWhitespace">isWhitespace()</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the current String contains only     white space characters or is empty; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_join">join(iterableObj, separator)</a></strong><br>
+Joins the elements of the specified iterable object, such as a List, into a single String separated by the specified separator.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_lastIndexOf">lastIndexOf(substring)</a></strong><br>
+Returns the index of the last occurrence of the specified substring. If the substring does not occur, this method returns -1.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_lastIndexOf_2">lastIndexOf(substring, endPosition)</a></strong><br>
+Returns the index of the last occurrence of the specified substring, starting from the character at index 0 and ending at the specified index. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_lastIndexOfChar">indexOfChar(character)</a></strong><br>
+Returns the index of the last occurrence of the character that corresponds to the specified character value.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_lastIndexOfChar_2">lastIndexOfChar(character, endIndex)</a></strong><br>
+Returns the index of the last occurrence of the character that corresponds to the specified character value, starting from the specified index.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_lastIndexOfIgnoreCase">lastIndexOfIgnoreCase(substring)</a></strong><br>
+Returns the index of the last occurrence of the specified substring regardless of case. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_lastIndexOfIgnoreCase_2">lastIndexOfIgnoreCase(substring, endPosition)</a></strong><br>
+Returns the index of the last occurrence of the specified substring regardless of case, starting from the character at index 0 and ending at the specified index. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_left">left(length)</a></strong><br>
+Returns the leftmost characters of the current String of the specified length.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_leftPad">leftPad(length)</a></strong><br>
+Returns the current String padded with spaces on the left and of the specified length. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_length">length()</a></strong><br>
+Returns the number of 16-bit Unicode characters contained in the String.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_mid">mid(startIndex, length)</a></strong><br>
+Returns a new String that begins with the character at the specified zero-based <var class="keyword varname">startIndex</var> with the number of characters specified by <var class="keyword varname">length</var>. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_normalizeSpace">normalizeSpace()</a></strong><br>
+Returns the current String with leading, trailing, and repeating white space characters removed. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_offsetByCodePoints">offsetByCodePoints(index, codePointOffset)</a></strong><br>
+Returns the index of the Unicode code point that is offset by the specified number of code points, starting from the given index.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_remove">remove(substring)</a></strong><br>
+Removes all occurrences of the specified substring and returns the String result.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_removeEnd">removeEnd(substring)</a></strong><br>
+Removes the specified substring only if it occurs at the end of the String.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_removeEndIgnoreCase">removeEndIgnoreCase(substring)</a></strong><br>
+Removes the specified substring only if it occurs at the end of the String using a case-insensitive match.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_removeStart">removeStart(substring)</a></strong><br>
+Removes the specified substring only if it occurs at the beginning of the String.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_removeStartIgnoreCase">removeStartIgnoreCase(substring)</a></strong><br>
+Removes the specified substring only if it occurs at the beginning of the String using a case-insensitive match.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_repeat">repeat(numberOfTimes)</a></strong><br>
+Returns the current String repeated the specified number of times. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_repeat_2">repeat(separator, numberOfTimes)</a></strong><br>
+Returns the current String repeated the specified number of times using the specified separator to separate the repeated Strings. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_replace">replace(target, replacement)</a></strong><br>
+Replaces each substring of a string that matches the literal target sequence <var class="keyword varname">target</var> with the specified literal replacement sequence <var class="keyword varname">replacement</var>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_replaceAll">replaceAll(regExp, replacement)</a></strong><br>
+Replaces each substring of a string that matches the regular expression <var class="keyword varname">regExp</var> with the replacement sequence <var class="keyword varname">replacement</var>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_replaceFirst">replaceFirst(regExp, replacement)</a></strong><br>
+Replaces the first substring of a string that matches the regular expression <var class="keyword varname">regExp</var> with the replacement sequence <var class="keyword varname">replacement</var>. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_reverse">reverse()</a></strong><br>
+Returns a String with all the characters reversed.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_right">right(length)</a></strong><br>
+Returns the rightmost characters of the current String of the specified length.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_rightPad">rightPad(length)</a></strong><br>
+Returns the current String padded with spaces on the right and of the specified length. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_split">split(regExp)</a></strong><br>
+Returns a list that contains each substring of                                 the String that is terminated by either the regular expression                                 <var class="keyword varname">regExp</var> or the end of the String.         </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_split_2">split(regExp, limit)</a></strong><br>
+Returns a list that contains each substring of                                 the String that is terminated by either the regular expression                                 <var class="keyword varname">regExp</var> or the end of the String.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_splitByCharacterType">splitByCharacterType()</a></strong><br>
+Splits the current String by character type and returns a list of contiguous character groups of the same type as complete tokens.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_splitByCharacterTypeCamelCase">splitByCharacterTypeCamelCase()</a></strong><br>
+Splits the current String by character type and returns a list of contiguous character groups of the same type as complete tokens, with the following exception: the uppercase character, if any, immediately preceding a lowercase character token belongs to the following character token rather than to the preceding.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_startsWith">startsWith(prefix)</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the String that called the method begins with the specified <var class="keyword varname">prefix</var>.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_startsWithIgnoreCase">startsWithIgnoreCase(prefix)</a></strong><br>
+Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the current String begins with the specified prefix regardless of the prefix case.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_stripHtmlTags">stripHtmlTags(htmlInput)</a></strong><br>
+Removes HTML markup from the input string and returns the plain text.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_substring">substring(startIndex)</a></strong><br>
+Returns a new String that begins with the character at the specified zero-based <var class="keyword varname">startIndex</var> and extends to the end of the String. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_substring_2">substring(startIndex, endIndex)</a></strong><br>
+Returns a new String that begins with the character at the specified zero-based <var class="keyword varname">startIndex</var> and extends to the character at <var class="keyword varname">endIndex</var> - 1.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_substringAfter">substringAfter(separator)</a></strong><br>
+Returns the substring that occurs after the first occurrence of the specified separator.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_substringAfterLast">substringAfterLast(separator)</a></strong><br>
+Returns the substring that occurs after the last occurrence of the specified separator.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_substringBefore">substringBefore(separator)</a></strong><br>
+Returns the substring that occurs before the first occurrence of the specified separator.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_substringBeforeLast">substringBeforeLast(separator)</a></strong><br>
+Returns the substring that occurs before the last occurrence of the specified separator.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_substringBetween">substringBetween(tag)</a></strong><br>
+Returns the substring that occurs between two instances of the specified          <var class="keyword varname">tag</var> String.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_substringBetween_2">substringBetween(open, close)</a></strong><br>
+Returns the substring that occurs between the two specified Strings.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_swapCase">swapCase()</a></strong><br>
+Swaps the case of all characters and returns the resulting String by using the default   (English US) locale. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_toLowerCase">toLowerCase()</a></strong><br>
+Converts all of the characters in the String to lowercase using the rules of the default     (English US) locale.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_toLowerCase_2">toLowerCase(locale)</a></strong><br>
+Converts all of the characters in the String to lowercase using the rules of the specified locale.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_toUpperCase">toUpperCase()</a></strong><br>
+Converts all of the characters in the String to uppercase using the rules of the default       (English US) locale.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_toUpperCase_2">toUpperCase(locale)</a></strong><br>
+Converts all of the characters in the String to the uppercase using the rules of the specified locale. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_trim">trim()</a></strong><br>
+Returns a copy of the string that no longer contains any leading or trailing white space characters. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_uncapitalize">uncapitalize()</a></strong><br>
+Returns the current String with the first letter in lowercase.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_unescapeCsv">unescapeCsv()</a></strong><br>
+Returns a String representing an unescaped CSV column.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_unescapeEcmaScript">unescapeEcmaScript()</a></strong><br>
+Unescapes any EcmaScript literals found in the String.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_unescapeHtml3">unescapeHtml3()</a></strong><br>
+Unescapes the characters in a String using HTML 3.0 entities.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_unescapeHtml4">unescapeHtml4()</a></strong><br>
+Unescapes the characters in a String using HTML 4.0 entities.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_unescapeJava">unescapeJava()</a></strong><br>
+Returns a String whose Java literals are unescaped. Literals unescaped include escape sequences for quotes (\\") and control characters, such as tab (\\t), and carriage return (\\n).</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_unescapeUnicode">unescapeUnicode()</a></strong><br>
+Returns a String whose escaped Unicode characters are unescaped.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_unescapeXml">unescapeXml()</a></strong><br>
+Unescapes the characters in a String using XML entities.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_valueOf">valueOf(dateToConvert)</a></strong><br>
+Returns a String that represents the specified Date in the standard “yyyy-MM-dd” format.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_valueOf_2">valueOf(datetimeToConvert)</a></strong><br>
+Returns a String that represents the specified Datetime in the standard “yyyy-MM-dd HH:mm:ss” format for the local time zone.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_valueOf_3">valueOf(decimalToConvert)</a></strong><br>
+Returns a String that represents the specified Decimal.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_valueOf_4">valueOf(doubleToConvert)</a></strong><br>
+Returns a String that represents the specified Double.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_valueOf_5">valueOf(integerToConvert)</a></strong><br>
+Returns a String that represents the specified Integer.</li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_valueOf_6">valueOf(longToConvert)</a></strong><br>
+Returns a String that represents the specified Long. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_valueOf_7">valueOf(toConvert)</a></strong><br>
+Returns a string representation of the specified object argument. </li>
+<li class="link ulchildlink">
+<strong><a href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm#apex_System_String_valueOfGmt">valueOfGmt(datetimeToConvert)</a></strong><br>
+Returns a String that represents the specified Datetime in the standard “yyyy-MM-dd HH:mm:ss” format for the GMT time zone.</li>
+</ul>
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_abbreviate">
+<a name="apex_System_String_abbreviate"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">abbreviate(maxWidth)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns an abbreviated version of the String, of the specified
+length and with ellipses appended if the current String is longer
+than the specified length; otherwise, returns the original String
+without ellipses.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> abbreviate(<span class="keyword">Integer</span> maxWidth)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">maxWidth</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">If <var class="keyword varname">maxWidth</var> is less than four, this method
+throws a run-time exception.</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'Hello Maximillian'</span>;
+<span class="keyword">String</span> s2 = s.abbreviate(8);
+System.assertEquals(<span class="string">'Hello...'</span>, s2);
+System.assertEquals(8, s2.length());</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_abbreviate_2">
+<a name="apex_System_String_abbreviate_2"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">abbreviate(maxWidth, offset)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns an abbreviated version of the String, starting
+at the specified character offset and of the specified length. The
+returned String has ellipses appended at the start and the end if
+characters have been removed at these locations.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> abbreviate(<span class="keyword">Integer</span> maxWidth,
+<span class="keyword">Integer</span> offset)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">maxWidth</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">Note that the offset is not necessarily the leftmost character
+in the returned String or the first character following the ellipses,
+but it appears somewhere in the result.  Regardless, <samp class="codeph apex_code">abbreviate</samp> won’t return a
+String of length greater than <var class="keyword varname">maxWidth</var>.If <var class="keyword varname">maxWidth</var> is too small, this method throws a run-time exception.</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">offset</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'Hello Maximillian'</span>;
+<span class="onelineComment">// Start at M</span>
+<span class="keyword">String</span> s2 = s.abbreviate(9,6);
+System.assertEquals(<span class="string">'...Max...'</span>, s2);
+System.assertEquals(9, s2.length());</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_capitalize">
+<a name="apex_System_String_capitalize"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">capitalize()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the current String with the first letter changed
+to title case.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> capitalize()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">This method is based on the <a class="xref" href="http://docs.oracle.com/javase/6/docs/api/java/lang/Character.html?is-external=true#toTitleCase%28char%29" target="_blank" title="HTML (New Window)"><samp class="codeph nolang">Character.toTitleCase(char)</samp></a> Java method.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'hello maximillian'</span>;
+<span class="keyword">String</span> s2 = s.capitalize();
+System.assertEquals(<span class="string">'Hello maximillian'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_center">
+<a name="apex_System_String_center"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">center(size)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a version of the current String of the specified
+size padded with spaces on the left and right, so that it appears
+in the center. If the specified size is smaller than the current String
+size, the entire String is returned without added spaces.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> center(<span class="keyword">Integer</span> size)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">size</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'hello'</span>;
+<span class="keyword">String</span> s2 = s.center(9);
+System.assertEquals(
+   <span class="string">'  hello  '</span>,
+   s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_center_2">
+<a name="apex_System_String_center_2"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">center(size, paddingString)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a version of the current String of the specified
+size padded with the specified String on the left and right, so that
+it appears in the center. If the specified size is smaller than the
+current String size, the entire String is returned without padding.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> center(<span class="keyword">Integer</span> size, <span class="keyword">String</span>
+    paddingString)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">size</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">paddingString</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'hello'</span>;
+<span class="keyword">String</span> s2 = s.center(9, <span class="string">'-'</span>);
+System.assertEquals(<span class="string">'hello'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_charAt">
+<a name="apex_System_String_charAt"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">charAt(index)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc"><span class="ph" id="shortdesc"><a name="shortdesc"><!– –></a>Returns the value of the character at
+the specified index.</span></div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> charAt(<span class="keyword">Integer</span> index)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">index</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">The index of the character to get the value of.</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+<p class="p">The integer value of the character.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">The <samp class="codeph apex_code">charAt</samp> method returns the value of
+the character pointed to by the specified index. If the index points
+to the beginning of a surrogate pair (the high-surrogate code point),
+this method returns only the high-surrogate code point. To return
+the supplementary code point corresponding to a surrogate pair, call <samp class="codeph apex_code">codePointAt</samp> instead.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<p class="p">This example gets the value of the
+first character at index 0.</p>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> str = <span class="string">'Ω is Omega.'</span>;
+System.assertEquals(937, str.charAt(0));</pre></div>
+<p class="p">This example
+shows the difference between <samp class="codeph apex_code">charAt</samp> and <samp class="codeph apex_code">codePointAt</samp>. The example
+calls these methods on escaped supplementary Unicode characters. <samp class="codeph apex_code">charAt(0)</samp> returns the high surrogate
+value, which corresponds to <span class="keyword parmname">\uD835</span>. <samp class="codeph apex_code">codePointAt(0)</samp> returns the value for
+the entire surrogate pair.</p>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> str = <span class="string">'\uD835\uDD0A'</span>;
+System.assertEquals(55349, str.charAt(0),
+    <span class="string">'charAt(0) didn\'t return the high surrogate.'</span>);
+System.assertEquals(120074, str.codePointAt(0),
+    <span class="string">'codePointAt(0) didn\'t return the entire two-character supplementary value.'</span>);
+</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_codePointAt">
+<a name="apex_System_String_codePointAt"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">codePointAt(index)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc"><span class="ph" id="shortdesc"><a name="shortdesc"><!– –></a>Returns the Unicode code point value
+at the specified index.</span></div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> codePointAt(<span class="keyword">Integer</span> index)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">index</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">The index of the characters (Unicode code units) in the string.
+The index range is from zero to the string length minus one.</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+<p class="p">The Unicode code point value at the specified index.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">If the <var class="keyword varname">index</var> points to the beginning of a surrogate pair (the high-surrogate
+code point), and the character value at the following index points
+to the low-surrogate code point, this method returns the supplementary
+code point corresponding to this surrogate pair. Otherwise, this method
+returns the character value at the given index.</p>
+<p class="p">For more information
+on Unicode and surrogate pairs, see <a class="xref" href="http://www.unicode.org" target="_blank" title="HTML (New Window)">The Unicode Consortium</a>.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<p class="p">This example gets the code point
+value of the first character at index 0, which is the escaped Omega
+character. Also, the example gets the code point at index 20, which
+corresponds to the escaped supplementary Unicode characters (a pair
+of characters). Finally, it verifies that the escaped and unescaped
+forms of Omega have the same code point values.</p>
+<p class="p">The supplementary
+characters in this example (<span class="keyword parmname">\\uD835\\uDD0A</span>) correspond
+to mathematical fraktur capital G: <img class="image" src="/docs/resources/img/en-us/202.0?doc_id=dev_guides%2Fapex%2Fimages%2FfrakturG.png&folder=apexcode" alt="Mathemtical Fraktur Capital G symbol"></p>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> str = <span class="string">'\u03A9 is Ω (Omega), and \uD835\uDD0A '</span> +
+    <span class="string">' is Fraktur Capital G.'</span>;
+System.assertEquals(937, str.codePointAt(0));
+System.assertEquals(120074, str.codePointAt(20));
+<span class="onelineComment">// Escaped or unescaped forms of the same character have the same code point</span>
+System.assertEquals(str.codePointAt(0), str.codePointAt(5));
+</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_codePointBefore">
+<a name="apex_System_String_codePointBefore"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">codePointBefore(index)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc"><span class="ph" id="shortdesc"><a name="shortdesc"><!– –></a>Returns the Unicode code point value
+that occurs before the specified index.</span></div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> codePointBefore(<span class="keyword">Integer</span> index)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">index</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">The index before the Unicode code point that is to be returned.
+The index range is from one to the string length.</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+<p class="p">The character or Unicode code point value that occurs before the
+specified index.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">If the character value at <samp class="codeph nolang"><var class="keyword varname">index</var>-1</samp> is the low-surrogate
+code point, and <samp class="codeph nolang"><var class="keyword varname">index</var>-2</samp> is not negative and the character at this index location
+is the high-surrogate code point, this method returns the supplementary
+code point corresponding to this surrogate pair. If the character
+value at <samp class="codeph nolang"><var class="keyword varname">index</var>-1</samp> is an unpaired low-surrogate or high-surrogate code point, the surrogate
+value is returned.</p>
+<p class="p">For more information on Unicode and surrogate
+pairs, see <a class="xref" href="http://www.unicode.org" target="_blank" title="HTML (New Window)">The Unicode Consortium</a>.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<p class="p">This example gets the code point
+value of the first character (before index 1), which is the escaped
+Omega character. Also, the example gets the code point at index 20,
+which corresponds to the escaped supplementary characters (the two
+characters before index 22).</p>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> str = <span class="string">'\u03A9 is Ω (Omega), and \uD835\uDD0A '</span> +
+    <span class="string">' is Fraktur Capital G.'</span>;
+System.assertEquals(937, str.codePointBefore(1));
+System.assertEquals(120074, str.codePointBefore(22));</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_codePointCount">
+<a name="apex_System_String_codePointCount"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">codePointCount(beginIndex, endIndex)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc"><span class="ph" id="shortdesc"><a name="shortdesc"><!– –></a>Returns the number of Unicode code points
+within the specified text range.</span></div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> codePointCount(<span class="keyword">Integer</span> beginIndex,
+<span class="keyword">Integer</span> endIndex)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">beginIndex</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">The index of the first character in the range.</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">endIndex</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">The index after the last character in the range.</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+<p class="p">The number of Unicode code points within the specified range.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">The specified range begins
+at <var class="keyword varname">beginIndex</var> and ends at <samp class="codeph nolang"><var class="keyword varname">endIndex</var>—1</samp>. Unpaired surrogates
+within the text range count as one code point each.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<p class="p">This example writes the count of
+code points in a substring that contains an escaped Unicode character
+and another substring that contains Unicode supplementary characters,
+which count as one code point.</p>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> str = <span class="string">'\u03A9 and \uD835\uDD0A characters.'</span>;
+System.debug(<span class="string">'Count of code points for '</span> + str.substring(0,1)
+             + <span class="string">': '</span> + str.codePointCount(0,1));
+System.debug(<span class="string">'Count of code points for '</span> + str.substring(6,8)
+             + <span class="string">': '</span> + str.codePointCount(6,8));
+
+<span class="onelineComment">// Output:</span>
+<span class="onelineComment">// Count of code points for Ω: 1</span>
+<span class="onelineComment">// Count of code points for 𝔊: 1</span></pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_compareTo">
+<a name="apex_System_String_compareTo"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">compareTo(secondString)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Compares two strings lexicographically, based on the Unicode
+value of each character in the Strings.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> compareTo(<span class="keyword">String</span> secondString)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">secondString</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p"> The result is:</p>
+<ul class="ul bulletList">
+<li class="li">A negative Integer if the String that called the method lexicographically precedes
+                  <var class="keyword varname">secondString</var>
+</li>
+
+<li class="li">A positive Integer if the String that called the method lexicographically follows
+                  <var class="keyword varname">compsecondStringString</var>
+</li>
+
+<li class="li">Zero if the Strings are equal</li>
+
+</ul>
+<p class="p">If there is no index position at which the Strings differ,
+then the shorter String lexicographically precedes the longer String. </p>
+<p class="p">Note that this method returns 0 whenever the <samp class="codeph apex_code">equals</samp> method returns true.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> myString1 = <span class="string">'abcde'</span>;
+<span class="keyword">String</span> myString2 = <span class="string">'abcd'</span>;
+<span class="keyword">Integer</span> result =
+   myString1.compareTo(myString2);
+System.assertEquals(result, 1);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_contains">
+<a name="apex_System_String_contains"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">contains(substring)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if and only if the String that
+      called the method contains the specified sequence of characters in
+         <var class="keyword varname">substring</var>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> contains(<span class="keyword">String</span> substring)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> myString1 = <span class="string">'abcde'</span>;
+<span class="keyword">String</span> myString2 = <span class="string">'abcd'</span>;
+<span class="keyword">Boolean</span> result =
+   myString1.contains(myString2);
+System.assertEquals(result, <span class="keyword">true</span>);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_containsAny">
+<a name="apex_System_String_containsAny"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">containsAny(inputString)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+the current String contains any of the characters in the specified
+String; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> containsAny(<span class="keyword">String</span> inputString)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">inputString</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'hello'</span>;
+<span class="keyword">Boolean</span> b1 = s.containsAny(<span class="string">'hx'</span>);
+<span class="keyword">Boolean</span> b2 = s.containsAny(<span class="string">'x'</span>);
+System.assertEquals(<span class="keyword">true</span>, b1);
+System.assertEquals(<span class="keyword">false</span>, b2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_containsIgnoreCase">
+<a name="apex_System_String_containsIgnoreCase"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">containsIgnoreCase(substring)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+the current String contains the specified sequence of characters without
+regard to case; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> containsIgnoreCase(<span class="keyword">String</span> substring)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'hello'</span>;
+<span class="keyword">Boolean</span> b = s.containsIgnoreCase(<span class="string">'HE'</span>);
+System.assertEquals(
+   <span class="keyword">true</span>,
+   b);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_containsNone">
+<a name="apex_System_String_containsNone"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">containsNone(inputString)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the current String doesn’t
+    contain any of the characters in the specified String; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> containsNone(<span class="keyword">String</span> inputString)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">inputString</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+<dd class="dd">If <var class="keyword varname">inputString</var> is an empty string or the current String is empty, this method
+            returns <samp class="codeph apex_code"><span class="keyword">true</span></samp>. If <var class="keyword varname">inputString</var>
+            is null, this method returns a run-time exception.</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'abcde'</span>;
+System.assert(s1.containsNone(<span class="string">'fg'</span>));</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_containsOnly">
+<a name="apex_System_String_containsOnly"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">containsOnly(inputString)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+the current String contains characters only from the specified sequence
+of characters and not any other characters; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> containsOnly(<span class="keyword">String</span> inputString)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">inputString</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'abba'</span>;
+<span class="keyword">String</span> s2 = <span class="string">'abba xyz'</span>;
+<span class="keyword">Boolean</span> b1 =
+   s1.containsOnly(<span class="string">'abcd'</span>);
+System.assertEquals(
+   <span class="keyword">true</span>,
+   b1);
+<span class="keyword">Boolean</span> b2 =
+   s2.containsOnly(<span class="string">'abcd'</span>);
+System.assertEquals(
+   <span class="keyword">false</span>,
+   b2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_containsWhitespace">
+<a name="apex_System_String_containsWhitespace"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">containsWhitespace()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+the current String contains any white space characters; otherwise,
+returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> containsWhitespace()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'Hello Jane'</span>;
+System.assert(s.containsWhitespace()); <span class="onelineComment">//true</span>
+s = <span class="string">'HelloJane '</span>;
+System.assert(s.containsWhitespace()); <span class="onelineComment">//true</span>
+s = <span class="string">' HelloJane'</span>;
+System.assert(s.containsWhitespace()); <span class="onelineComment">//true</span>
+s = <span class="string">'HelloJane'</span>;
+System.assert(!s.containsWhitespace()); <span class="onelineComment">//false</span></pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_countMatches">
+<a name="apex_System_String_countMatches"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">countMatches(substring)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the number of times the specified substring occurs
+in the current String.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> countMatches(<span class="keyword">String</span> substring)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'Hello Jane'</span>;
+System.assertEquals(1, s.countMatches(<span class="string">'Hello'</span>));
+s = <span class="string">'Hello Hello'</span>;
+System.assertEquals(2, s.countMatches(<span class="string">'Hello'</span>));
+s = <span class="string">'Hello hello'</span>;
+System.assertEquals(1, s.countMatches(<span class="string">'Hello'</span>));</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_deleteWhitespace">
+<a name="apex_System_String_deleteWhitespace"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">deleteWhitespace()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a version of the current String with all white
+space characters removed.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> deleteWhitespace()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">' Hello Jane '</span>;
+<span class="keyword">String</span> s2 = <span class="string">'HelloJane'</span>;
+System.assertEquals(s2, s1.deleteWhitespace());</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_difference">
+<a name="apex_System_String_difference"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">difference(secondString)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the difference between the current String and the
+specified String.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> difference(<span class="keyword">String</span> secondString)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">secondString</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+<dd class="dd">If <var class="keyword varname">secondString</var> is an empty string, this method returns an empty string.If
+                     <var class="keyword varname">secondString</var> is null, this method throws a run-time
+                  exception.</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'Hello Jane'</span>;
+<span class="keyword">String</span> d1 =
+   s.difference(<span class="string">'Hello Max'</span>);
+System.assertEquals(
+   <span class="string">'Max'</span>,
+   d1);
+<span class="keyword">String</span> d2 =
+   s.difference(<span class="string">'Goodbye'</span>);
+System.assertEquals(
+   <span class="string">'Goodbye'</span>,
+   d2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_endsWith">
+<a name="apex_System_String_endsWith"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">endsWith(suffix)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+the String that called the method ends with the specified <var class="keyword varname">suffix</var>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> endsWith(<span class="keyword">String</span> suffix)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">suffix</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'Hello Jason'</span>;
+System.assert(s.endsWith(<span class="string">'Jason'</span>));</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_endsWithIgnoreCase">
+<a name="apex_System_String_endsWithIgnoreCase"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">endsWithIgnoreCase(suffix)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+the current String ends with the specified suffix; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> endsWithIgnoreCase(<span class="keyword">String</span> suffix)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">suffix</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'Hello Jason'</span>;
+System.assert(s.endsWithIgnoreCase(<span class="string">'jason'</span>));</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_equals">
+<a name="apex_System_String_equals"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">equals(secondString)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Deprecated. This method is replaced by <samp class="codeph apex_code">equals(stringOrId)</samp>. Returns
+         <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the passed-in string is not null and
+      represents the same binary sequence of characters as the current string. Use this method to
+      perform case-sensitive comparisons.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> equals(<span class="keyword">String</span> secondString)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">secondString</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+
+         <p class="p">This method returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> when the <samp class="codeph apex_code">compareTo</samp> method returns 0.</p>
+<p class="p"><span class="ph" id="equals_note"><a name="equals_note"><!– –></a>Use this method to perform case-sensitive comparisons. In contrast, the
+                  <samp class="codeph apex_code">==</samp> operator performs case-insensitive
+               string comparisons to match Apex
+               semantics.</span></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> myString1 = <span class="string">'abcde'</span>;
+<span class="keyword">String</span> myString2 = <span class="string">'abcd'</span>;
+<span class="keyword">Boolean</span> result = myString1.equals(myString2);
+System.assertEquals(result, <span class="keyword">false</span>);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_equals_2">
+<a name="apex_System_String_equals_2"><!– –></a>
+   <h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">equals(stringOrId)</span></span></h3>
+
+
+
+   <div class="body refbody">
+<div class="shortdesc"><span class="ph" id="shortdesc"><a name="shortdesc"><!– –></a>Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the
+         passed-in object is not null and represents the same binary sequence of characters as the
+         current string. Use this method to compare a string to an object that represents a string
+         or an ID.</span></div>
+
+      <div class="section">
+<h4 class="helpHead4">Signature</h4>
+
+
+         <p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> equals(<span class="keyword">Object</span> stringOrId)</samp></p>
+
+
+      </div>
+
+      <div class="section">
+<h4 class="helpHead4">Parameters</h4>
+
+
+         <dl class="dl detailList">
+
+               <dt class="dt dlterm"><var class="keyword varname">stringOrId</var></dt>
+
+               <dd class="dd">Type: Object</dd>
+
+
+         </dl>
+
+      </div>
+
+      <div class="section">
+<h4 class="helpHead4">Return Value</h4>
+
+
+         <p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+
+      </div>
+
+      <div class="section">
+<h4 class="helpHead4">Usage</h4>
+
+
+         <p class="p">If you compare ID values, the lengths of IDs don’t need to be equal. For example, if you
+            compare a 15-character ID string to an object that represents the equivalent
+            18-character ID value, this method returns <samp class="codeph apex_code"><span class="keyword">true</span></samp>.
+            For more information about 15-character and 18-character IDs, see the <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/langCon_apex_primitives.htm#id_type">ID data type</a>.</p>
+
+         <p class="p">Use this method to perform case-sensitive comparisons. In contrast, the
+                  <samp class="codeph apex_code">==</samp> operator performs case-insensitive
+               string comparisons to match Apex
+               semantics.</p>
+
+      </div>
+
+      <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+         <p class="p">These examples show comparisons between different types of variables with both equal and
+            unequal values. The examples also show how Apex automatically
+            converts certain values before comparing them. </p>
+
+         <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="onelineComment">// Compare a string to an object containing a string</span>
+<span class="keyword">Object</span> obj1 = <span class="string">'abc'</span>;
+<span class="keyword">String</span> str = <span class="string">'abc'</span>;
+<span class="keyword">Boolean</span> result1 = str.equals(obj1);
+System.assertEquals(<span class="keyword">true</span>, result1);
+
+<span class="onelineComment">// Compare a string to an object containing a number</span>
+<span class="keyword">Integer</span> obj2 = 100;
+<span class="keyword">Boolean</span> result2 = str.equals(obj2);
+System.assertEquals(<span class="keyword">false</span>, result2);
+
+<span class="onelineComment">// Compare a string to an ID of the same length.</span>
+<span class="onelineComment">// 15-character ID</span>
+Id idValue15 = <span class="string">'001D000000Ju1zH'</span>;
+<span class="onelineComment">// 15-character ID string value</span>
+<span class="keyword">String</span> stringValue15 = <span class="string">'001D000000Ju1zH'</span>;
+<span class="keyword">Boolean</span> result3 = stringValue15.equals(IdValue15);
+System.assertEquals(<span class="keyword">true</span>, result3);
+
+<span class="onelineComment">// Compare two equal ID values of different lengths:</span>
+<span class="onelineComment">//  15-character ID and 18-character ID</span>
+Id idValue18 = <span class="string">'001D000000Ju1zHIAR'</span>;
+<span class="keyword">Boolean</span> result4 = stringValue15.equals(IdValue18);
+System.assertEquals(<span class="keyword">true</span>, result4);
+</pre></div>
+
+      </div>
+
+   </div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_equalsIgnoreCase">
+<a name="apex_System_String_equalsIgnoreCase"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">equalsIgnoreCase(secondString)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the
+   <var class="keyword varname">secondString</var> is not null and represents the same sequence of characters as the
+  String that called the method, ignoring case.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> equalsIgnoreCase(<span class="keyword">String</span> secondString)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">secondString</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> myString1 = <span class="string">'abcd'</span>;
+<span class="keyword">String</span> myString2 = <span class="string">'ABCD'</span>;
+<span class="keyword">Boolean</span> result =
+myString1.equalsIgnoreCase(myString2);
+System.assertEquals(result, <span class="keyword">true</span>);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_escapeCsv">
+<a name="apex_System_String_escapeCsv"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">escapeCsv()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a String for a CSV column enclosed in double quotes,
+if required.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> escapeCsv()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">If the String contains a
+comma, newline or double quote, the returned String is enclosed in
+double quotes. Also, any double quote characters in the String are
+escaped with another double quote.</p>
+<p class="p">If the String doesn’t
+contain a comma, newline or double quote, it is returned unchanged.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'Max1, "Max2"'</span>;
+<span class="keyword">String</span> s2 = s1.escapeCsv();
+System.assertEquals(<span class="string">'"Max1, ""Max2"""'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_escapeEcmaScript">
+<a name="apex_System_String_escapeEcmaScript"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">escapeEcmaScript()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Escapes the characters in the String using EcmaScript String
+rules.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> escapeEcmaScript()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+
+
+      <p class="p">The only difference between Apex strings and
+        EcmaScript strings is that in EcmaScript, a single quote and forward-slash (/) are
+        escaped.</p>
+
+    </div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'"grade": 3.9/4.0'</span>;
+<span class="keyword">String</span> s2 = s1.escapeEcmaScript();
+System.debug(s2);
+<span class="onelineComment">// Output is:</span>
+<span class="onelineComment">// \"grade\": 3.9\/4.0</span>
+System.assertEquals(
+   <span class="string">'\\"grade\\": 3.9\\/4.0'</span>,
+    s2);
+</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_escapeHtml3">
+<a name="apex_System_String_escapeHtml3"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">escapeHtml3()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Escapes the characters in a String using HTML 3.0 entities.</div>
+
+      <div class="section">
+<h4 class="helpHead4">Signature</h4>
+
+
+         <p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> escapeHtml3()</samp></p>
+
+
+      </div>
+
+      <div class="section">
+<h4 class="helpHead4">Return Value</h4>
+
+
+         <p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+
+      </div>
+
+      <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+         <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 =
+   <span class="string">'"&lt;Black&amp;White&gt;"'</span>;
+<span class="keyword">String</span> s2 =
+   s1.escapeHtml3();
+System.debug(s2);
+<span class="onelineComment">// Output:</span>
+<span class="onelineComment">// &amp;quot;&amp;lt;Black&amp;amp;</span>
+<span class="onelineComment">// White&amp;gt;&amp;quot;</span></pre></div>
+
+      </div>
+
+   </div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_escapeHtml4">
+<a name="apex_System_String_escapeHtml4"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">escapeHtml4()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Escapes the characters in a String using HTML 4.0 entities.</div>
+
+      <div class="section">
+<h4 class="helpHead4">Signature</h4>
+
+
+         <p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> escapeHtml4()</samp></p>
+
+
+      </div>
+
+      <div class="section">
+<h4 class="helpHead4">Return Value</h4>
+
+
+         <p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+
+      </div>
+
+      <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+         <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 =
+   <span class="string">'"&lt;Black&amp;White&gt;"'</span>;
+<span class="keyword">String</span> s2 =
+   s1.escapeHtml4();
+System.debug(s2);
+<span class="onelineComment">// Output:</span>
+<span class="onelineComment">// &amp;quot;&amp;lt;Black&amp;amp;</span>
+<span class="onelineComment">// White&amp;gt;&amp;quot;</span></pre></div>
+
+      </div>
+
+   </div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_escapeJava">
+<a name="apex_System_String_escapeJava"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">escapeJava()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a String whose characters are escaped using Java
+String rules. Characters escaped include quotes and control characters,
+such as tab, backslash, and carriage return characters.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> escapeJava()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+<p class="p">The escaped string.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="onelineComment">// Input string contains quotation marks</span>
+<span class="keyword">String</span> s = <span class="string">'Company: "Salesforce.com"'</span>;
+<span class="keyword">String</span> escapedStr = s.escapeJava();
+<span class="onelineComment">// Output string has the quotes escpaded</span>
+System.assertEquals(<span class="string">'Company: \\"Salesforce.com\\"'</span>, escapedStr);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_escapeSingleQuotes">
+<a name="apex_System_String_escapeSingleQuotes"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">escapeSingleQuotes(stringToEscape)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a String with the escape character () added before
+any single quotation marks in the String <var class="keyword varname">s</var>. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">String</span> escapeSingleQuotes(<span class="keyword">String</span>
+stringToEscape)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">stringToEscape</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">This method is useful when creating
+a dynamic SOQL statement, to help prevent SOQL injection. For more
+information on dynamic SOQL, see <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_dynamic_soql.htm">Dynamic SOQL</a>.</p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'\'Hello Jason\</span>;
+system.debug(s); <span class="onelineComment">// Outputs 'Hello Jason'</span>
+<span class="keyword">String</span> escapedStr = <span class="keyword">String</span>.escapeSingleQuotes(s);
+<span class="onelineComment">// Outputs \'Hello Jason\'</span>
+system.debug(escapedStr);
+<span class="onelineComment">// Escapes the string \\\' to string \'</span>
+system.assertEquals(<span class="string">'\\\'Hello Jason\\\</span>, escapedStr); </pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_escapeUnicode">
+<a name="apex_System_String_escapeUnicode"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">escapeUnicode()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a String whose Unicode characters are escaped to
+a Unicode escape sequence.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> escapeUnicode()</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+<p class="p">The escaped string.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'De onde você é?'</span>;
+<span class="keyword">String</span> escapedStr = s.escapeUnicode();
+System.assertEquals(<span class="string">'De onde voc\\u00EA \\u00E9?'</span>, escapedStr);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_escapeXml">
+<a name="apex_System_String_escapeXml"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">escapeXml()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Escapes the characters in a String using XML entities.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> escapeXml()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">Supports only the five basic
+XML entities (gt, lt, quot, amp, apos). Does not support DTDs or external
+entities. Unicode characters greater than 0x7f are not escaped.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 =
+   <span class="string">'"&lt;Black&amp;White&gt;"'</span>;
+<span class="keyword">String</span> s2 =
+   s1.escapeXml();
+System.debug(s2);
+<span class="onelineComment">// Output:</span>
+<span class="onelineComment">// &amp;quot;&amp;lt;Black&amp;amp;</span>
+<span class="onelineComment">// White&amp;gt;&amp;quot;</span></pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_format">
+<a name="apex_System_String_format"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">format(stringToFormat, formattingArguments)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Treat the current string as a pattern that should be used
+for substitution in the same manner as <samp class="codeph apex_code">apex:outputText</samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">String</span> format(<span class="keyword">String</span> stringToFormat,
+List&lt;<span class="keyword">String</span>&gt; formattingArguments)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">stringToFormat</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">formattingArguments</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_list.htm#apex_methods_system_list" title="Contains methods for the List collection type.">List</a>&lt;<a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>&gt;</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> placeholder = <span class="string">'Hello {0}, {1} is cool!'</span>;
+List&lt;<span class="keyword">String</span>&gt; fillers = <span class="keyword">new</span> <span class="keyword">String</span>[]{<span class="string">'Jason'</span>,<span class="string">'Apex'</span>};
+<span class="keyword">String</span> formatted = <span class="keyword">String</span>.format(placeholder, fillers);
+System.assertEquals(<span class="string">'Hello Jason, Apex is cool!'</span>, formatted);</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_fromCharArray">
+<a name="apex_System_String_fromCharArray"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">fromCharArray(charArray)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a String from the values of the list of integers. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">String</span> fromCharArray(List&lt;<span class="keyword">Integer</span>&gt;
+charArray)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">charArray</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_list.htm#apex_methods_system_list" title="Contains methods for the List collection type.">List</a>&lt;<a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>&gt;</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex">List&lt;<span class="keyword">Integer</span>&gt; charArr= <span class="keyword">new</span> <span class="keyword">Integer</span>[]{74};
+<span class="keyword">String</span> convertedChar = <span class="keyword">String</span>.fromCharArray(charArr);
+System.assertEquals(<span class="string">'J'</span>, convertedChar);</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_getChars">
+<a name="apex_System_String_getChars"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">getChars()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc"><span class="ph" id="shortdesc"><a name="shortdesc"><!– –></a>Returns an array of character values
+that represent the characters in this string.</span></div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> List&lt;<span class="keyword">Integer</span>&gt; getChars()</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_list.htm#apex_methods_system_list" title="Contains methods for the List collection type.">List</a>&lt;<a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>&gt;</p>
+<p class="p">A list of integers, each corresponding to a character value in the
+string.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<p class="p">This sample converts a string to
+a character array and then gets the first array element, which corresponds
+to the value of 'J'.</p>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> str = <span class="string">'Jane goes fishing.'</span>;
+<span class="keyword">Integer</span>[] chars = str.getChars();
+<span class="onelineComment">// Get the value of 'J'</span>
+System.assertEquals(74, chars[0]);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_getCommonPrefix">
+<a name="apex_System_String_getCommonPrefix"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">getCommonPrefix(strings)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the initial sequence of characters as a String
+that is common to all the specified Strings.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">String</span> getCommonPrefix(List&lt;<span class="keyword">String</span>&gt;
+strings)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">strings</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_list.htm#apex_methods_system_list" title="Contains methods for the List collection type.">List</a>&lt;<a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>&gt;</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex">List&lt;<span class="keyword">String</span>&gt; ls = <span class="keyword">new</span> List&lt;<span class="keyword">String</span>&gt;{<span class="string">'SFDCApex'</span>, <span class="string">'SFDCVisualforce'</span>};
+<span class="keyword">String</span> prefix = <span class="keyword">String</span>.getCommonPrefix(ls);
+System.assertEquals(<span class="string">'SFDC'</span>, prefix);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_getLevenshteinDistance">
+<a name="apex_System_String_getLevenshteinDistance"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">getLevenshteinDistance(stringToCompare)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the Levenshtein distance between the current String
+and the specified String.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> getLevenshteinDistance(<span class="keyword">String</span>
+stringToCompare)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">stringToCompare</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">The Levenshtein distance
+is the number of changes needed to change one String into another.
+Each change is a single character modification (deletion, insertion
+or substitution).</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'Hello Joe'</span>;
+<span class="keyword">Integer</span> i = s.getLevenshteinDistance(<span class="string">'Hello Max'</span>);
+System.assertEquals(3, i);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_getLevenshteinDistance_2">
+<a name="apex_System_String_getLevenshteinDistance_2"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">getLevenshteinDistance(stringToCompare, threshold)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the Levenshtein distance between the current String
+and the specified String if it is less than or equal than the given
+threshold; otherwise, returns -1.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> getLevenshteinDistance(<span class="keyword">String</span>
+stringToCompare, <span class="keyword">Integer</span> threshold)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">stringToCompare</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">threshold</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">The Levenshtein distance
+is the number of changes needed to change one String into another.
+Each change is a single character modification (deletion, insertion
+or substitution).</p>
+<p class="p">Example:</p>
+<p class="p">In this example, the Levenshtein
+distance is 3, but the threshold argument is 2, which is less than
+the distance, so this method returns -1.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'Hello Jane'</span>;
+<span class="keyword">Integer</span> i = s.getLevenshteinDistance(<span class="string">'Hello Max'</span>, 2);
+System.assertEquals(-1, i);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_hashCode">
+<a name="apex_System_String_hashCode"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">hashCode()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a hash code value for this string. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> hashCode()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">This value is based on the
+hash code computed by the Java <a class="xref" href="http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#hashCode%28%29" target="_blank" title="HTML (New Window)"><samp class="codeph nolang">String.hashCode</samp></a> counterpart method.</p>
+<p class="p">You can
+use this method to simplify the computation of a hash code for a custom
+type that contains String member variables. You can compute your type’s
+hash code value based on the hash code of each String variable. For
+example:</p>
+<p class="p">For more details about the use of hash code methods
+with custom types, see <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/langCon_apex_collections_maps_keys_userdefined.htm" title="You can add instances of your own Apex classes to maps and sets.">Using Custom Types in Map Keys and Sets</a>.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">public</span> <span class="keyword">class</span> MyCustomClass {
+   <span class="keyword">String</span> x,y;
+   <span class="onelineComment">// Provide a custom hash code</span>
+   <span class="keyword">public</span> <span class="keyword">Integer</span> hashCode() {
+    <span class="statement">return</span>
+    (31*x.hashCode())^(y.hashCode());
+   }
+}</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_indexOf">
+<a name="apex_System_String_indexOf"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">indexOf(substring)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the index of the first occurrence of the specified
+substring. If the substring does not occur, this method returns -1.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> indexOf(<span class="keyword">String</span> substring)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> myString1 = <span class="string">'abcde'</span>;
+<span class="keyword">String</span> myString2 = <span class="string">'cd'</span>;
+<span class="keyword">Integer</span> result = myString1.indexOf(mystring2);
+System.assertEquals(2, result);</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_indexOf_2">
+<a name="apex_System_String_indexOf_2"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">indexOf(substring, index)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the zero-based index of the first occurrence of
+the specified substring from the point of the given index. If the
+substring does not occur, this method returns -1.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> indexOf(<span class="keyword">String</span> substring, <span class="keyword">Integer</span>
+index)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">index</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> myString1 = <span class="string">'abcdabcd'</span>;
+<span class="keyword">String</span> myString2 = <span class="string">'ab'</span>;
+<span class="keyword">Integer</span> result = myString1.indexOf(mystring2, 1);
+System.assertEquals(4, result);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_indexOfAny">
+<a name="apex_System_String_indexOfAny"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">indexOfAny(substring)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the zero-based index of the first occurrence of
+any character specified in the substring. If none of the characters
+occur, returns -1. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> indexOfAny(<span class="keyword">String</span> substring)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'abcd'</span>;
+<span class="keyword">String</span> s2 = <span class="string">'xc'</span>;
+<span class="keyword">Integer</span> result = s1.indexOfAny(s2);
+System.assertEquals(2, result);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_indexOfAnyBut">
+<a name="apex_System_String_indexOfAnyBut"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">indexOfAnyBut(substring)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the zero-based index of the first occurrence of
+a character that is not in the specified substring. Otherwise, returns
+1. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> indexOfAnyBut(<span class="keyword">String</span> substring)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'abcd'</span>;
+<span class="keyword">String</span> s2 = <span class="string">'xc'</span>;
+<span class="keyword">Integer</span> result = s1.indexOfAnyBut(s2);
+System.assertEquals(0, result);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_indexOfChar">
+<a name="apex_System_String_indexOfChar"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">indexOfChar(character)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc"><span class="ph" id="shortdesc"><a name="shortdesc"><!– –></a>Returns the index of the first occurrence
+of the character that corresponds to the specified character value.</span></div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> indexOfChar(<span class="keyword">Integer</span> character)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">character</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">The integer value of the character in the string.</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+<p class="p">The index of the first occurrence of the specified character, -1
+if the character is not found.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">The index that this method
+returns is in Unicode code units.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> str = <span class="string">'\\u03A9 is Ω (Omega)'</span>;
+<span class="onelineComment">// Returns 0, which is the first character.</span>
+System.debug(<span class="string">'indexOfChar(937)='</span> + str.indexOfChar(937));
+
+<span class="onelineComment">// Output:</span>
+<span class="onelineComment">// indexOfChar(937)=0</span>
+</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_indexOfChar_2">
+<a name="apex_System_String_indexOfChar_2"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">indexOfChar(character, startIndex)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc"><span class="ph" id="shortdesc"><a name="shortdesc"><!– –></a>Returns the index of the first occurrence
+of the character that corresponds to the specified character value,
+starting from the specified index.</span></div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> indexOfChar(<span class="keyword">Integer</span> character,
+<span class="keyword">Integer</span> startIndex)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">character</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">The integer value of the character to look for.</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">startIndex</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">The index to start the search from.</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+<p class="p">The index, starting from the specified start index, of the first
+occurrence of the specified character, -1 if the character is not
+found.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">The index that this method
+returns is in Unicode code units.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<p class="p">This example shows different ways
+of searching for the index of the Omega character. The first call
+to <samp class="codeph apex_code">indexOfChar</samp> doesn’t
+specify a start index and therefore the returned index is 0, which
+is the first occurrence of Omega in the entire string. The subsequent
+calls specify a start index to find the occurrence of Omega in substrings
+that start at the specified index.</p>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> str = <span class="string">'Ω and \\u03A9 and Ω'</span>;
+System.debug(<span class="string">'indexOfChar(937)='</span> + str.indexOfChar(937));
+System.debug(<span class="string">'indexOfChar(937,1)='</span> + str.indexOfChar(937,1));
+System.debug(<span class="string">'indexOfChar(937,10)='</span> + str.indexOfChar(937,10));
+
+<span class="onelineComment">// Output:</span>
+<span class="onelineComment">// indexOfChar(937)=0</span>
+<span class="onelineComment">// indexOfChar(937,1)=6, (corresponds to the escaped form \\u03A9)</span>
+<span class="onelineComment">// indexOfChar(937,10)=12</span>
+</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_indexOfDifference">
+<a name="apex_System_String_indexOfDifference"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">indexOfDifference(stringToCompare)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the zero-based index of the character where the
+current String begins to differ from the specified String.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> indexOfDifference(<span class="keyword">String</span> stringToCompare)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">stringToCompare</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'abcd'</span>;
+<span class="keyword">String</span> s2 = <span class="string">'abxc'</span>;
+<span class="keyword">Integer</span> result = s1.indexOfDifference(s2);
+System.assertEquals(2, result);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_indexOfIgnoreCase">
+<a name="apex_System_String_indexOfIgnoreCase"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">indexOfIgnoreCase(substring)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the zero-based index of the first occurrence of
+the specified substring without regard to case. If the substring does
+not occur, this method returns -1.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> indexOfIgnoreCase(<span class="keyword">String</span> substring)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'abcd'</span>;
+<span class="keyword">String</span> s2 = <span class="string">'BC'</span>;
+<span class="keyword">Integer</span> result = s1.indexOfIgnoreCase(s2, 0);
+System.assertEquals(1, result);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_indexOfIgnoreCase_2">
+<a name="apex_System_String_indexOfIgnoreCase_2"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">indexOfIgnoreCase(substring, startPosition)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the zero-based index of the first occurrence of
+the specified substring from the point of index <var class="keyword varname">i</var>, without regard to case. If the substring does not occur, this method
+returns -1. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> indexOfIgnoreCase(<span class="keyword">String</span> substring,
+<span class="keyword">Integer</span> startPosition)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">startPosition</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_isAllLowerCase">
+<a name="apex_System_String_isAllLowerCase"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">isAllLowerCase()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+all characters in the current String are lowercase; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> isAllLowerCase()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> allLower = <span class="string">'abcde'</span>;
+System.assert(allLower.isAllLowerCase());</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_isAllUpperCase">
+<a name="apex_System_String_isAllUpperCase"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">isAllUpperCase()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+all characters in the current String are uppercase; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> isAllUpperCase()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> allUpper = <span class="string">'ABCDE'</span>;
+System.assert(allUpper.isAllUpperCase());</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_isAlpha">
+<a name="apex_System_String_isAlpha"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">isAlpha()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+all characters in the current String are Unicode letters only; otherwise,
+returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> isAlpha()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="onelineComment">// Letters only</span>
+<span class="keyword">String</span> s1 = <span class="string">'abc'</span>;
+<span class="onelineComment">// Returns true</span>
+<span class="keyword">Boolean</span> b1 =
+   s1.isAlpha();
+System.assertEquals(
+   <span class="keyword">true</span>, b1);
+
+<span class="onelineComment">// Letters and numbers</span>
+<span class="keyword">String</span> s2 = <span class="string">'abc 21'</span>;
+<span class="onelineComment">// Returns false</span>
+<span class="keyword">Boolean</span> b2 =
+   s2.isAlpha();
+System.assertEquals(
+   <span class="keyword">false</span>, b2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_isAlphaSpace">
+<a name="apex_System_String_isAlphaSpace"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">isAlphaSpace()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+all characters in the current String are Unicode letters or spaces
+only; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> isAlphaSpace()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> alphaSpace = <span class="string">'aA Bb'</span>;
+System.assert(alphaSpace.isAlphaSpace());
+<span class="keyword">String</span> notAlphaSpace = <span class="string">'ab 12'</span>;
+System.assert(!notAlphaSpace.isAlphaSpace());
+notAlphaSpace = <span class="string">'aA$Bb'</span>;
+System.assert(!notAlphaSpace.isAlphaSpace());</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_isAlphanumeric">
+<a name="apex_System_String_isAlphanumeric"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">isAlphanumeric()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+all characters in the current String are Unicode letters or numbers
+only; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> isAlphanumeric()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="onelineComment">// Letters only</span>
+<span class="keyword">String</span> s1 = <span class="string">'abc'</span>;
+<span class="onelineComment">// Returns true</span>
+<span class="keyword">Boolean</span> b1 =
+   s1.isAlphanumeric();
+System.assertEquals(
+   <span class="keyword">true</span>, b1);
+
+<span class="onelineComment">// Letters and numbers</span>
+<span class="keyword">String</span> s2 = <span class="string">'abc021'</span>;
+<span class="onelineComment">// Returns true</span>
+<span class="keyword">Boolean</span> b2 =
+   s2.isAlphanumeric();
+System.assertEquals(
+   <span class="keyword">true</span>, b2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_isAlphanumericSpace">
+<a name="apex_System_String_isAlphanumericSpace"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">isAlphanumericSpace()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+all characters in the current String are Unicode letters, numbers,
+or spaces only; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> isAlphanumericSpace()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> alphanumSpace = <span class="string">'AE 86'</span>;
+System.assert(alphanumSpace.isAlphanumericSpace());
+<span class="keyword">String</span> notAlphanumSpace = <span class="string">'aA$12'</span>;
+System.assert(!notAlphanumSpace.isAlphaSpace());</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_isAsciiPrintable">
+<a name="apex_System_String_isAsciiPrintable"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">isAsciiPrintable()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+the current String contains only ASCII printable characters; otherwise,
+returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> isAsciiPrintable()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> ascii = <span class="string">'abcd1234!@#$%^&amp;*()`~-_+={[}]|:&lt;,&gt;.?'</span>;
+System.assert(ascii.isAsciiPrintable());
+<span class="keyword">String</span> notAscii = <span class="string">'√'</span>;
+System.assert(!notAscii.isAsciiPrintable());</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_isBlank">
+<a name="apex_System_String_isBlank"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">isBlank(inputString)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+the specified String is white space, empty (), or null; otherwise,
+returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">Boolean</span> isBlank(<span class="keyword">String</span> inputString)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">inputString</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> blank = <span class="string"></span>;
+<span class="keyword">String</span> nullString = <span class="keyword">null</span>;
+<span class="keyword">String</span> whitespace = <span class="string">'  '</span>;
+System.assert(<span class="keyword">String</span>.isBlank(blank));
+System.assert(<span class="keyword">String</span>.isBlank(nullString));
+System.assert(<span class="keyword">String</span>.isBlank(whitespace));
+<span class="keyword">String</span> alpha = <span class="string">'Hello'</span>;
+System.assert(!<span class="keyword">String</span>.isBlank(alpha));</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_isEmpty">
+<a name="apex_System_String_isEmpty"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">isEmpty(inputString)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+the specified String is empty () or null; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">Boolean</span> isEmpty(<span class="keyword">String</span> inputString)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">inputString</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> empty = <span class="string"></span>;
+<span class="keyword">String</span> nullString = <span class="keyword">null</span>;
+System.assert(<span class="keyword">String</span>.isEmpty(empty));
+System.assert(<span class="keyword">String</span>.isEmpty(nullString));
+<span class="keyword">String</span> whitespace = <span class="string">'  '</span>;
+<span class="keyword">String</span> alpha = <span class="string">'Hello'</span>;
+System.assert(!<span class="keyword">String</span>.isEmpty(whitespace));
+System.assert(!<span class="keyword">String</span>.isEmpty(alpha));</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_isNotBlank">
+<a name="apex_System_String_isNotBlank"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">isNotBlank(inputString)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+the specified String is not whitespace, not empty (), and not null;
+otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">Boolean</span> isNotBlank(<span class="keyword">String</span> inputString)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">inputString</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> alpha = <span class="string">'Hello world!'</span>;
+System.assert(<span class="keyword">String</span>.isNotBlank(alpha));
+<span class="keyword">String</span> blank = <span class="string"></span>;
+<span class="keyword">String</span> nullString = <span class="keyword">null</span>;
+<span class="keyword">String</span> whitespace = <span class="string">'  '</span>;
+System.assert(!<span class="keyword">String</span>.isNotBlank(blank));
+System.assert(!<span class="keyword">String</span>.isNotBlank(nullString));
+System.assert(!<span class="keyword">String</span>.isNotBlank(whitespace));</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_isNotEmpty">
+<a name="apex_System_String_isNotEmpty"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">isNotEmpty(inputString)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+the specified String is not empty () and not null; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">Boolean</span> isNotEmpty(<span class="keyword">String</span> inputString)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">inputString</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> whitespace = <span class="string">'  '</span>;
+<span class="keyword">String</span> alpha = <span class="string">'Hello world!'</span>;
+System.assert(<span class="keyword">String</span>.isNotEmpty(whitespace));
+System.assert(<span class="keyword">String</span>.isNotEmpty(alpha));
+<span class="keyword">String</span> empty = <span class="string"></span>;
+<span class="keyword">String</span> nullString = <span class="keyword">null</span>;
+System.assert(!<span class="keyword">String</span>.isNotEmpty(empty));
+System.assert(!<span class="keyword">String</span>.isNotEmpty(nullString));</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_isNumeric">
+<a name="apex_System_String_isNumeric"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">isNumeric()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+the current String contains only Unicode digits; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> isNumeric()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p" id="decimalPoint"><a name="decimalPoint"><!– –></a>A decimal
+point (1.2) is not a Unicode digit.</p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> numeric = <span class="string">'1234567890'</span>;
+System.assert(numeric.isNumeric());
+<span class="keyword">String</span> alphanumeric = <span class="string">'R32'</span>;
+<span class="keyword">String</span> decimalPoint = <span class="string">'1.2'</span>;
+System.assert(!alphanumeric.isNumeric());
+System.assert(!decimalpoint.isNumeric());</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_isNumericSpace">
+<a name="apex_System_String_isNumericSpace"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">isNumericSpace()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+the current String contains only Unicode digits or spaces; otherwise,
+returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> isNumericSpace()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">A decimal point (1.2) is
+not a Unicode digit.</p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> numericSpace = <span class="string">'1 2 3'</span>;
+System.assert(numericSpace.isNumericspace());
+<span class="keyword">String</span> notNumericspace = <span class="string">'FD3S FC3S'</span>;
+System.assert(!notNumericspace.isNumericspace());</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_isWhitespace">
+<a name="apex_System_String_isWhitespace"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">isWhitespace()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if the current String contains only
+    white space characters or is empty; otherwise, returns <samp class="codeph apex_code"><span class="keyword">false</span></samp>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> isWhitespace()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> whitespace = <span class="string">' '</span>;
+<span class="keyword">String</span> blank = <span class="string"></span>;
+System.assert(whitespace.isWhitespace());
+System.assert(blank.isWhitespace());
+<span class="keyword">String</span> alphanum = <span class="string">'SIL80'</span>;
+System.assert(!alphanum.isWhitespace());</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_join">
+<a name="apex_System_String_join"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">join(iterableObj, separator)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Joins the elements of the specified iterable object, such
+as a List, into a single String separated by the specified separator.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">String</span> join(<span class="keyword">Object</span> iterableObj,
+<span class="keyword">String</span> separator)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">iterableObj</var></dt>
+
+<dd class="dd">Type: Object</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">separator</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex">List&lt;<span class="keyword">Integer</span>&gt; li = <span class="keyword">new</span>
+   List&lt;<span class="keyword">Integer</span>&gt;
+   {10, 20, 30};
+<span class="keyword">String</span> s = <span class="keyword">String</span>.join(
+   li, <span class="string">'/'</span>);
+System.assertEquals(
+   <span class="string">'10/20/30'</span>, s);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_lastIndexOf">
+<a name="apex_System_String_lastIndexOf"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">lastIndexOf(substring)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the index of the last occurrence of the specified
+substring. If the substring does not occur, this method returns -1.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> lastIndexOf(<span class="keyword">String</span> substring)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'abcdefgc'</span>;
+<span class="keyword">Integer</span> i1 = s1.lastIndexOf(<span class="string">'c'</span>);
+System.assertEquals(7, i1);</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_lastIndexOf_2">
+<a name="apex_System_String_lastIndexOf_2"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">lastIndexOf(substring, endPosition)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the index of the last occurrence of the specified
+substring, starting from the character at index 0 and ending at the
+specified index. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> lastIndexOf(<span class="keyword">String</span> substring,
+<span class="keyword">Integer</span> endPosition)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">endPosition</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">If the substring doesn’t occur
+or <var class="keyword varname">endPosition</var> is negative, this method returns
+1. If <var class="keyword varname">endPosition</var> is larger than the last index
+in the current String, the entire String is searched.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'abcdaacd'</span>;
+<span class="keyword">Integer</span> i1 =
+   s1.lastIndexOf(<span class="string">'c'</span>, 7);
+System.assertEquals(
+   6, i1);
+<span class="keyword">Integer</span> i2 =
+   s1.lastIndexOf(<span class="string">'c'</span>, 3);
+System.assertEquals(
+   2, i2);
+</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_lastIndexOfChar">
+<a name="apex_System_String_lastIndexOfChar"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">indexOfChar(character)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc"><span class="ph" id="shortdesc"><a name="shortdesc"><!– –></a>Returns the index of the last occurrence
+of the character that corresponds to the specified character value.</span></div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> indexOfChar(<span class="keyword">Integer</span> character)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">character</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">The integer value of the character in the string.</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+<p class="p">The index of the last occurrence of the specified character, -1 if
+the character is not found.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">The index that this method
+returns is in Unicode code units.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> str = <span class="string">'\u03A9 is Ω (Omega)'</span>;
+<span class="onelineComment">// Get the last occurrence of Omega.</span>
+System.assertEquals(5, str.lastIndexOfChar(937));</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_lastIndexOfChar_2">
+<a name="apex_System_String_lastIndexOfChar_2"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">lastIndexOfChar(character, endIndex)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc"><span class="ph" id="shortdesc"><a name="shortdesc"><!– –></a>Returns the index of the last occurrence
+of the character that corresponds to the specified character value,
+starting from the specified index.</span></div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> lastIndexOfChar(<span class="keyword">Integer</span> character,
+<span class="keyword">Integer</span> endIndex)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">character</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">The integer value of the character to look for.</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">endIndex</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">The index to end the search at.</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+<p class="p">The index, starting from the specified start index, of the last occurrence
+of the specified character. -1 if the character is not found.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">The index that this method
+returns is in Unicode code units.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<p class="p">This example shows different ways
+of searching for the index of the last occurrence of the Omega character.
+The first call to <samp class="codeph apex_code">lastIndexOfChar</samp> doesn’t specify an end index and therefore the returned index
+is 12, which is the last occurrence of Omega in the entire string.
+The subsequent calls specify an end index to find the last occurrence
+of Omega in substrings.</p>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> str = <span class="string">'Ω and \u03A9 and Ω'</span>;
+System.assertEquals(12, str.lastIndexOfChar(937));
+System.assertEquals(6, str.lastIndexOfChar(937,11));
+System.assertEquals(0, str.lastIndexOfChar(937,5));</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_lastIndexOfIgnoreCase">
+<a name="apex_System_String_lastIndexOfIgnoreCase"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">lastIndexOfIgnoreCase(substring)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the index of the last occurrence of the specified
+substring regardless of case. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> lastIndexOfIgnoreCase(<span class="keyword">String</span>
+substring)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">If the substring doesn’t
+occur, this method returns -1.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'abcdaacd'</span>;
+<span class="keyword">Integer</span> i1 =
+   s1.lastIndexOfIgnoreCase(<span class="string">'DAAC'</span>);
+System.assertEquals(
+   3, i1);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_lastIndexOfIgnoreCase_2">
+<a name="apex_System_String_lastIndexOfIgnoreCase_2"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">lastIndexOfIgnoreCase(substring, endPosition)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the index of the last occurrence of the specified
+substring regardless of case, starting from the character at index
+0 and ending at the specified index. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> lastIndexOfIgnoreCase(<span class="keyword">String</span>
+substring, <span class="keyword">Integer</span> endPosition)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">endPosition</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">If the substring doesn’t occur
+or <var class="keyword varname">endPosition</var> is negative, this method returns
+1. If <var class="keyword varname">endPosition</var> is larger than the last index
+in the current String, the entire String is searched.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'abcdaacd'</span>;
+<span class="keyword">Integer</span> i1 =
+   s1.lastIndexOfIgnoreCase(<span class="string">'C'</span>, 7);
+System.assertEquals(
+   6, i1);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_left">
+<a name="apex_System_String_left"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">left(length)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the leftmost characters of the current String of
+the specified length.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> left(<span class="keyword">Integer</span> length)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">length</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">If <var class="keyword varname">length</var> is greater
+than the String size, the entire String is returned.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'abcdaacd'</span>;
+<span class="keyword">String</span> s2 =
+   s1.left(3);
+System.assertEquals(
+   <span class="string">'abc'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_leftPad">
+<a name="apex_System_String_leftPad"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">leftPad(length)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the current String padded with spaces on the left
+and of the specified length. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> leftPad(<span class="keyword">Integer</span> length)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">length</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">If <var class="keyword varname">length</var> is less
+than or equal to the current String size, the entire String is returned
+without space padding.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'abc'</span>;
+<span class="keyword">String</span> s2 =
+   s1.leftPad(5);
+System.assertEquals(
+   <span class="string">'  abc'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_length">
+<a name="apex_System_String_length"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">length()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the number of 16-bit Unicode characters contained
+in the String.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> length()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> myString = <span class="string">'abcd'</span>;
+<span class="keyword">Integer</span> result = myString.length();
+System.assertEquals(result, 4);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_mid">
+<a name="apex_System_String_mid"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">mid(startIndex, length)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a new String that begins with the character at
+the specified zero-based <var class="keyword varname">startIndex</var> with the number
+of characters specified by <var class="keyword varname">length</var>. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> mid(<span class="keyword">Integer</span> startIndex, <span class="keyword">Integer</span>
+length)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">startIndex</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">If <var class="keyword varname">startIndex</var> is negative, it is considered
+to be zero.</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">length</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">If <var class="keyword varname">length</var> is negative or zero, an empty String
+is returned. If <var class="keyword varname">length</var> is greater than the remaining
+characters, the remainder of the String is returned.</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">This method is similar to
+the <samp class="codeph apex_code">substring(startIndex)</samp> and <samp class="codeph apex_code">substring(startIndex, endIndex)</samp> methods,
+except that the second argument is the number of characters to return.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'abcde'</span>;
+<span class="keyword">String</span> s2 = s.mid(2, 3);
+System.assertEquals(
+   <span class="string">'cde'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_normalizeSpace">
+<a name="apex_System_String_normalizeSpace"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">normalizeSpace()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the current String with leading, trailing, and
+repeating white space characters removed. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> normalizeSpace()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">This method normalizes the
+following white space characters: space, tab (\t), new line (\n),
+carriage return (\r), and form feed (\f).</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 =
+   <span class="string">'Salesforce \t     force.com'</span>;
+<span class="keyword">String</span> s2 =
+   s1.normalizeSpace();
+System.assertEquals(
+   <span class="string">'Salesforce force.com'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_offsetByCodePoints">
+<a name="apex_System_String_offsetByCodePoints"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">offsetByCodePoints(index, codePointOffset)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc"><span class="ph" id="shortdesc"><a name="shortdesc"><!– –></a>Returns the index of the Unicode code
+point that is offset by the specified number of code points, starting
+from the given index.</span></div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Integer</span> offsetByCodePoints(<span class="keyword">Integer</span> index,
+<span class="keyword">Integer</span> codePointOffset)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">index</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">The start index in the string.</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">codePointOffset</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">The number of code points to be offset.</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a></p>
+<p class="p">The index that corresponds to the start index that is added to the
+offset.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">Unpaired surrogates within
+the text range that is specified by <var class="keyword varname">index</var> and <var class="keyword varname">codePointOffset</var> count as one code point each.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<p class="p">This example calls <samp class="codeph apex_code">offsetByCodePoints</samp> on a string with
+a start index of 0 (to start from the first character) and an offset
+of threee code points. The string contains one sequence of supplementary
+characters in escaped form (a pair of characters). After an offset
+of three code points when counting from the beginning of the string,
+the returned code point index is four.</p>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> str = <span class="string">'A \uD835\uDD0A BC'</span>;
+System.assertEquals(4, str.offsetByCodePoints(0,3));</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_remove">
+<a name="apex_System_String_remove"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">remove(substring)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Removes all occurrences of the specified substring and
+returns the String result.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> remove(<span class="keyword">String</span> substring)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'Salesforce and force.com'</span>;
+<span class="keyword">String</span> s2 =
+   s1.remove(<span class="string">'force'</span>);
+System.assertEquals(
+   <span class="string">'Sales and .com'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_removeEnd">
+<a name="apex_System_String_removeEnd"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">removeEnd(substring)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Removes the specified substring only if it occurs at the
+end of the String.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> removeEnd(<span class="keyword">String</span> substring)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'Salesforce and force.com'</span>;
+<span class="keyword">String</span> s2 =
+   s1.removeEnd(<span class="string">'.com'</span>);
+System.assertEquals(
+   <span class="string">'Salesforce and force'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_removeEndIgnoreCase">
+<a name="apex_System_String_removeEndIgnoreCase"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">removeEndIgnoreCase(substring)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Removes the specified substring only if it occurs at the
+end of the String using a case-insensitive match.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> removeEndIgnoreCase(<span class="keyword">String</span> substring)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'Salesforce and force.com'</span>;
+<span class="keyword">String</span> s2 =
+   s1.removeEndIgnoreCase(<span class="string">'.COM'</span>);
+System.assertEquals(
+   <span class="string">'Salesforce and force'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_removeStart">
+<a name="apex_System_String_removeStart"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">removeStart(substring)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Removes the specified substring only if it occurs at the
+beginning of the String.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> removeStart(<span class="keyword">String</span> substring)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'Salesforce and force.com'</span>;
+<span class="keyword">String</span> s2 =
+   s1.removeStart(<span class="string">'Sales'</span>);
+System.assertEquals(
+   <span class="string">'force and force.com'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_removeStartIgnoreCase">
+<a name="apex_System_String_removeStartIgnoreCase"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">removeStartIgnoreCase(substring)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Removes the specified substring only if it occurs at the
+beginning of the String using a case-insensitive match.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> removeStartIgnoreCase(<span class="keyword">String</span>
+substring)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">substring</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'Salesforce and force.com'</span>;
+<span class="keyword">String</span> s2 =
+   s1.removeStartIgnoreCase(<span class="string">'SALES'</span>);
+System.assertEquals(
+   <span class="string">'force and force.com'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_repeat">
+<a name="apex_System_String_repeat"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">repeat(numberOfTimes)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the current String repeated the specified number
+of times. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> repeat(<span class="keyword">Integer</span> numberOfTimes)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">numberOfTimes</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'SFDC'</span>;
+<span class="keyword">String</span> s2 =
+   s1.repeat(2);
+System.assertEquals(
+   <span class="string">'SFDCSFDC'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_repeat_2">
+<a name="apex_System_String_repeat_2"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">repeat(separator, numberOfTimes)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the current String repeated the specified number
+of times using the specified separator to separate the repeated Strings. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> repeat(<span class="keyword">String</span> separator, <span class="keyword">Integer</span>
+               numberOfTimes)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">separator</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">numberOfTimes</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'SFDC'</span>;
+<span class="keyword">String</span> s2 =
+   s1.repeat(<span class="string">'-'</span>, 2);
+System.assertEquals(
+   <span class="string">'SFDC-SFDC'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_replace">
+<a name="apex_System_String_replace"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">replace(target, replacement)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Replaces each substring of a string that matches the literal
+target sequence <var class="keyword varname">target</var> with the specified literal
+replacement sequence <var class="keyword varname">replacement</var>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> replace(<span class="keyword">String</span> target, <span class="keyword">String</span>
+replacement)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">target</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">replacement</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'abcdbca'</span>;
+<span class="keyword">String</span> target = <span class="string">'bc'</span>;
+<span class="keyword">String</span> replacement = <span class="string">'xy'</span>;
+<span class="keyword">String</span> s2 = s1.replace(target, replacement);
+System.assertEquals(<span class="string">'axydxya'</span>, s2);</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_replaceAll">
+<a name="apex_System_String_replaceAll"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">replaceAll(regExp, replacement)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Replaces each substring of a string that matches the regular
+expression <var class="keyword varname">regExp</var> with the replacement sequence <var class="keyword varname">replacement</var>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> replaceAll(<span class="keyword">String</span> regExp, <span class="keyword">String</span>
+replacement)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">regExp</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">replacement</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p"><span class="ph" id="reg_exp_link"><a name="reg_exp_link"><!– –></a>See the Java <a class="xref" href="http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html" target="_blank" title="html (New Window)"><samp class="codeph nolang">Pattern</samp></a> class for information on regular expressions.</span></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'a b c 5 xyz'</span>;
+<span class="keyword">String</span> regExp = <span class="string">'[a-zA-Z]'</span>;
+<span class="keyword">String</span> replacement = <span class="string">'1'</span>;
+<span class="keyword">String</span> s2 = s1.replaceAll(regExp, replacement);
+System.assertEquals(<span class="string">'1 1 1 5 111'</span>, s2);</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_replaceFirst">
+<a name="apex_System_String_replaceFirst"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">replaceFirst(regExp, replacement)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Replaces the first substring of a string that matches the
+regular expression <var class="keyword varname">regExp</var> with the replacement
+sequence <var class="keyword varname">replacement</var>. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> replaceFirst(<span class="keyword">String</span> regExp, <span class="keyword">String</span>
+replacement)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">regExp</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">replacement</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">See the Java <a class="xref" href="http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html" target="_blank" title="html (New Window)"><samp class="codeph nolang">Pattern</samp></a> class for information on regular expressions.</p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'a b c 11 xyz'</span>;
+<span class="keyword">String</span> regExp = <span class="string">'[a-zA-Z]{2}'</span>;
+<span class="keyword">String</span> replacement = <span class="string">'2'</span>;
+<span class="keyword">String</span> s2 = s1.replaceFirst(regExp, replacement);
+System.assertEquals(<span class="string">'a b c 11 2z'</span>, s2);</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_reverse">
+<a name="apex_System_String_reverse"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">reverse()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a String with all the characters reversed.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> reverse()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_right">
+<a name="apex_System_String_right"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">right(length)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the rightmost characters of the current String
+of the specified length.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> right(<span class="keyword">Integer</span> length)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">length</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">If <var class="keyword varname">length</var> is greater than the String size,
+the entire String is returned.</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'Hello Max'</span>;
+<span class="keyword">String</span> s2 =
+   s1.right(3);
+System.assertEquals(
+   <span class="string">'Max'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_rightPad">
+<a name="apex_System_String_rightPad"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">rightPad(length)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the current String padded with spaces on the right
+and of the specified length. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> rightPad(<span class="keyword">Integer</span> length)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">length</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+<dd class="dd">If <var class="keyword varname">length</var> is less than or equal to the current
+String size, the entire String is returned without space padding.</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'abc'</span>;
+<span class="keyword">String</span> s2 =
+   s1.rightPad(5);
+System.assertEquals(
+   <span class="string">'abc  '</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_split">
+<a name="apex_System_String_split"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">split(regExp)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">
+<span class="ph" id="split_desc"><a name="split_desc"><!– –></a><span class="ph" id="SplitDescr1"><a name="SplitDescr1"><!– –></a>Returns a list that contains each substring of
+                                the String</span> that is terminated by either the regular expression
+                                <var class="keyword varname">regExp</var> or the end of the String.</span>
+        </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+
+
+                        <p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span>[] split(<span class="keyword">String</span>
+                                        regExp)</samp></p>
+
+
+
+                </div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+                                        <dt class="dt dlterm"><var class="keyword varname">regExp</var></dt>
+
+                                        <dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+                        </dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+
+
+            <p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>[]</p>
+
+            <div class="box message info"><div class="inner"><div class="bd"><div class="media">
+<img class="img mtm" src="//res.cloudinary.com/hy4kyit2a/image/upload/img/msg_icons/helpNote_icon.gif" alt="Note"><div class="mediaBd">
+<h4 class="mbs">Note</h4>
+<p><span class="ph" id="split_jdk8_bug"><a name="split_jdk8_bug"><!– –></a>In API version 34.0 and earlier, a zero-width
+                                                <var class="keyword varname">regExp</var> value produces an empty
+                                        list item at the beginning of the method’s
+                                output.</span></p>
+</div>
+</div></div></div></div>
+
+        </div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+
+
+                        <p class="p">See the Java <samp class="codeph nolang">Pattern</samp> class for information on
+                                regular expressions.</p>
+
+                        <p class="p"><span class="ph" id="SplitDescr2"><a name="SplitDescr2"><!– –></a>The substrings are placed in the list in the order
+                                        in which they occur in the String.</span><span class="ph" id="SplitDescr3"><a name="SplitDescr3"><!– –></a>If <var class="keyword varname">regExp</var> does not match any part of the
+                                        String, the resulting list has just one element containing
+                                        the original String.</span></p>
+
+
+                        <div class="p">For example, for <samp class="codeph apex_code"><span class="keyword">String</span> s =
+                                        <span class="string">'boo:and:foo'</span></samp>:<ul class="ul bulletList">
+                                        <li class="li">
+<samp class="codeph apex_code">s.split(<span class="string">':'</span>, 2)</samp>
+                                                results in <samp class="codeph apex_code">{<span class="string">'boo'</span>,
+                                                  <span class="string">'and:foo'</span>}</samp>
+</li>
+
+                                        <li class="li">
+<samp class="codeph apex_code">s.split(<span class="string">':'</span>, 5)</samp>
+                                                results in <samp class="codeph apex_code">{<span class="string">'boo'</span>,
+                                                  <span class="string">'and'</span>, <span class="string">'foo'</span>}</samp>
+</li>
+
+                                        <li class="li">
+<samp class="codeph apex_code">s.split(<span class="string">':'</span>,
+                                                  -2)</samp> results in <samp class="codeph apex_code">{<span class="string">'boo'</span>, <span class="string">'and'</span>,
+                                                  <span class="string">'foo'</span>}</samp>
+</li>
+
+                                        <li class="li">
+<samp class="codeph apex_code">s.split(<span class="string">'o'</span>, 5)</samp>
+                                                results in <samp class="codeph apex_code">{<span class="string">'b'</span>, <span class="string"></span>,
+                                                  <span class="string">':and:f'</span>, <span class="string"></span>, <span class="string"></span>}</samp>
+</li>
+
+                                        <li class="li">
+<samp class="codeph apex_code">s.split(<span class="string">'o'</span>,
+                                                  -2)</samp> results in <samp class="codeph apex_code">{<span class="string">'b'</span>, <span class="string"></span>, <span class="string">':and:f'</span>, <span class="string"></span>,
+                                                  <span class="string"></span>}</samp>
+</li>
+
+                                        <li class="li">
+<samp class="codeph apex_code">s.split(<span class="string">'o'</span>, 0)</samp>
+                                                results in <samp class="codeph apex_code"> {<span class="string">'b'</span>,
+                                                  <span class="string"></span>, <span class="string">':and:f'</span>}</samp>
+</li>
+
+                                </ul>
+</div>
+
+                </div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<p class="p">In the following example, a string is split using a backslash as a delimiter.</p>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">public</span> <span class="keyword">String</span> splitPath(<span class="keyword">String</span> filename) {
+    <span class="statement">if</span> (filename == <span class="keyword">null</span>)
+        <span class="statement">return</span> <span class="keyword">null</span>;
+    List&lt;<span class="keyword">String</span>&gt; parts = filename.split(<span class="string">'\\\\'</span>);
+    filename = parts[parts.size()-1];
+    <span class="statement">return</span> filename;
+}
+
+<span class="onelineComment">// For example, if the file path is e:\\processed\\PPDSF100111.csv</span>
+<span class="onelineComment">// This method splits the path and returns the last part.</span>
+<span class="onelineComment">// Returned filename is PPDSF100111.csv</span>
+</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_split_2">
+<a name="apex_System_String_split_2"><!– –></a><h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">split(regExp,
+    limit)</span></span></h3>
+<div class="body refbody">
+<div class="shortdesc"><span class="ph" id="shortdesc"><a name="shortdesc"><!– –></a><span class="ph" id="d80221e12-d80235e14"><a name="d80221e12-d80235e14"><!– –></a>Returns a list that contains each substring of
+                                the String</span> that is terminated by either the regular expression
+                                <var class="keyword varname">regExp</var> or the end of the String.</span></div>
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span>[] split(<span class="keyword">String</span> regExp, <span class="keyword">Integer</span> limit)</samp></p>
+
+      </div>
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+<dt class="dt dlterm"><var class="keyword varname">regExp</var></dt>
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+<dd class="dd">A regular expression.</dd>
+
+
+          <dt class="dt dlterm"><var class="keyword varname">limit</var></dt>
+
+          <dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+        </dl>
+</div>
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+
+      <p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>[]</p>
+
+      <div class="box message info"><div class="inner"><div class="bd"><div class="media">
+<img class="img mtm" src="//res.cloudinary.com/hy4kyit2a/image/upload/img/msg_icons/helpNote_icon.gif" alt="Note"><div class="mediaBd">
+<h4 class="mbs">Note</h4>
+<p>In API version 34.0 and earlier, a zero-width
+                                                <var class="keyword varname">regExp</var> value produces an empty
+                                        list item at the beginning of the method’s
+                                output.</p>
+</div>
+</div></div></div></div>
+</div>
+
+    <div class="section">
+<h4 class="helpHead4">Usage</h4>
+
+
+      <div class="p">
+<span class="ph" id="SplitDescr4"><a name="SplitDescr4"><!– –></a>The optional <var class="keyword varname">limit</var> parameter controls the number of
+          times the pattern is applied and therefore affects the length of the list.</span><ul class="ul bulletList">
+              <li class="li">If <var class="keyword varname">limit</var> is greater than zero:<ul class="ul bulletList">
+                  <li class="li">The pattern is applied a maximum of (<var class="keyword varname">limit</var> – 1) times.</li>
+
+                  <li class="li">The list’s length is no greater than <var class="keyword varname">limit</var>.</li>
+
+                  <li class="li">The list’s last entry contains all input beyond the last matched
+                    delimiter.</li>
+
+                </ul>
+</li>
+
+              <li class="li">If <var class="keyword varname">limit</var> is non-positive, the pattern is applied as many times
+                as possible, and the list can have any length.</li>
+
+              <li class="li">If <var class="keyword varname">limit</var> is zero, the pattern is applied as many times as
+                possible, the list can have any length, and trailing empty strings are discarded.
+              </li>
+
+            </ul>
+</div>
+
+    </div>
+</div>
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_splitByCharacterType">
+<a name="apex_System_String_splitByCharacterType"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">splitByCharacterType()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Splits the current String by character type and returns
+a list of contiguous character groups of the same type as complete
+tokens.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> List&lt;<span class="keyword">String</span>&gt; splitByCharacterType()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_list.htm#apex_methods_system_list" title="Contains methods for the List collection type.">List</a>&lt;<a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>&gt;</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">For more information about
+the character types used, see <a class="xref" href="http://docs.oracle.com/javase/7/docs/api/java/lang/Character.html#getType%28char%29" target="_blank" title="HTML (New Window)">java.lang.Character.getType(char)</a>.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'Force.com platform'</span>;
+List&lt;<span class="keyword">String</span>&gt; ls =
+   s1.splitByCharacterType();
+System.debug(ls);
+<span class="onelineComment">// Writes this output:</span>
+<span class="onelineComment">// (F, orce, ., com,  , platform)</span></pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_splitByCharacterTypeCamelCase">
+<a name="apex_System_String_splitByCharacterTypeCamelCase"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">splitByCharacterTypeCamelCase()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Splits the current String by character type and returns
+a list of contiguous character groups of the same type as complete
+tokens, with the following exception: the uppercase character, if
+any, immediately preceding a lowercase character token belongs to
+the following character token rather than to the preceding.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> List&lt;<span class="keyword">String</span>&gt; splitByCharacterTypeCamelCase()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_list.htm#apex_methods_system_list" title="Contains methods for the List collection type.">List</a>&lt;<a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>&gt;</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">For more information about
+the character types used, see <a class="xref" href="http://docs.oracle.com/javase/7/docs/api/java/lang/Character.html#getType%28char%29" target="_blank" title="HTML (New Window)">java.lang.Character.getType(char)</a>.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'Force.com platform'</span>;
+List&lt;<span class="keyword">String</span>&gt; ls =
+   s1.splitByCharacterTypeCamelCase();
+System.debug(ls);
+<span class="onelineComment">// Writes this output:</span>
+<span class="onelineComment">// (Force, ., com,  , platform)</span></pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_startsWith">
+<a name="apex_System_String_startsWith"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">startsWith(prefix)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+the String that called the method begins with the specified <var class="keyword varname">prefix</var>.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> startsWith(<span class="keyword">String</span> prefix)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">prefix</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'AE86 vs EK9'</span>;
+System.assert(s1.startsWith(<span class="string">'AE86'</span>));</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_startsWithIgnoreCase">
+<a name="apex_System_String_startsWithIgnoreCase"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">startsWithIgnoreCase(prefix)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns <samp class="codeph apex_code"><span class="keyword">true</span></samp> if
+the current String begins with the specified prefix regardless of
+the prefix case.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">Boolean</span> startsWithIgnoreCase(<span class="keyword">String</span>
+prefix)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">prefix</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_boolean.htm#apex_methods_system_boolean" title="Contains methods for the Boolean primitive data type.">Boolean</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'AE86 vs EK9'</span>;
+System.assert(s1.startsWithIgnoreCase(<span class="string">'ae86'</span>));</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_stripHtmlTags">
+<a name="apex_System_String_stripHtmlTags"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">stripHtmlTags(htmlInput)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Removes HTML markup from the input string and returns the
+plain text.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> stripHtmlTags(<span class="keyword">String</span> htmlInput)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">htmlInput</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'&lt;b&gt;hello world&lt;/b&gt;'</span>;
+<span class="keyword">String</span> s2 = s1.stripHtmlTags();
+System.assertEquals(
+   <span class="string">'hello world'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_substring">
+<a name="apex_System_String_substring"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">substring(startIndex)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a new String that begins with the character at
+the specified zero-based <var class="keyword varname">startIndex</var> and extends
+to the end of the String. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> substring(<span class="keyword">Integer</span> startIndex)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">startIndex</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'hamburger'</span>;
+System.assertEquals(<span class="string">'burger'</span>, s1.substring(3));</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_substring_2">
+<a name="apex_System_String_substring_2"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">substring(startIndex, endIndex)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a new String that begins with the character at
+the specified zero-based <var class="keyword varname">startIndex</var> and extends
+to the character at <var class="keyword varname">endIndex</var> - 1.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> substring(<span class="keyword">Integer</span> startIndex,
+<span class="keyword">Integer</span> endIndex)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">startIndex</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">endIndex</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="string">'hamburger'</span>.substring(4, 8);
+<span class="onelineComment">// Returns "urge"</span>
+
+<span class="string">'smiles'</span>.substring(1, 5);
+<span class="onelineComment">// Returns "mile"</span>
+</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_substringAfter">
+<a name="apex_System_String_substringAfter"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">substringAfter(separator)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the substring that occurs after the first occurrence
+of the specified separator.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> substringAfter(<span class="keyword">String</span> separator)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">separator</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'Force.com.platform'</span>;
+<span class="keyword">String</span> s2 =
+   s1.substringAfter(<span class="string">'.'</span>);
+System.assertEquals(
+   <span class="string">'com.platform'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_substringAfterLast">
+<a name="apex_System_String_substringAfterLast"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">substringAfterLast(separator)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the substring that occurs after the last occurrence
+of the specified separator.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> substringAfterLast(<span class="keyword">String</span> separator)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">separator</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'Force.com.platform'</span>;
+<span class="keyword">String</span> s2 =
+   s1.substringAfterLast(<span class="string">'.'</span>);
+System.assertEquals(
+   <span class="string">'platform'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_substringBefore">
+<a name="apex_System_String_substringBefore"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">substringBefore(separator)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the substring that occurs before the first occurrence
+of the specified separator.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> substringBefore(<span class="keyword">String</span> separator)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">separator</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'Force.com.platform'</span>;
+<span class="keyword">String</span> s2 =
+   s1.substringBefore(<span class="string">'.'</span>);
+System.assertEquals(
+   <span class="string">'Force'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_substringBeforeLast">
+<a name="apex_System_String_substringBeforeLast"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">substringBeforeLast(separator)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the substring that occurs before the last occurrence
+of the specified separator.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> substringBeforeLast(<span class="keyword">String</span> separator)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">separator</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'Force.com.platform'</span>;
+<span class="keyword">String</span> s2 =
+   s1.substringBeforeLast(<span class="string">'.'</span>);
+System.assertEquals(
+   <span class="string">'Force.com'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_substringBetween">
+<a name="apex_System_String_substringBetween"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">substringBetween(tag)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the substring that occurs between two instances of the specified
+         <var class="keyword varname">tag</var> String.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> substringBetween(<span class="keyword">String</span> tag)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">tag</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'tagYellowtag'</span>;
+<span class="keyword">String</span> s2 = s1.substringBetween(<span class="string">'tag'</span>);
+System.assertEquals(<span class="string">'Yellow'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_substringBetween_2">
+<a name="apex_System_String_substringBetween_2"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">substringBetween(open, close)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the substring that occurs between the two specified
+Strings.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> substringBetween(<span class="keyword">String</span> open,
+<span class="keyword">String</span> close)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">open</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+
+<dt class="dt dlterm"><var class="keyword varname">close</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'xYellowy'</span>;
+<span class="keyword">String</span> s2 =
+   s1.substringBetween(<span class="string">'x'</span>,<span class="string">'y'</span>);
+System.assertEquals(
+   <span class="string">'Yellow'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_swapCase">
+<a name="apex_System_String_swapCase"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">swapCase()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Swaps the case of all characters and returns the resulting String by using the default
+  (English US) locale. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> swapCase()</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">Upper case and title case
+converts to lower case, and lower case converts to upper case.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'Force.com'</span>;
+<span class="keyword">String</span> s2 = s1.swapCase();
+System.assertEquals(<span class="string">'fORCE.COM'</span>, s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_toLowerCase">
+<a name="apex_System_String_toLowerCase"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">toLowerCase()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Converts all of the characters in the String to lowercase using the rules of the default
+    (English US) locale.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> toLowerCase()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'ThIs iS hArD tO rEaD'</span>;
+System.assertEquals(<span class="string">'this is hard to read'</span>,
+   s1.toLowerCase());</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_toLowerCase_2">
+<a name="apex_System_String_toLowerCase_2"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">toLowerCase(locale)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Converts all of the characters in the String to lowercase
+using the rules of the specified locale.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> toLowerCase(<span class="keyword">String</span> locale)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">locale</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="onelineComment">// Example in Turkish</span>
+<span class="onelineComment">// An uppercase dotted "i", \u0304, which is İ</span>
+<span class="onelineComment">// Note this contains both a İ as well as a I</span>
+<span class="keyword">String</span> s1 = <span class="string">'KIYMETLİ'</span>;
+<span class="keyword">String</span> s1Lower = s1.toLowerCase(<span class="string">'tr'</span>);
+<span class="onelineComment">// Dotless lowercase "i", \u0131, which is ı</span>
+<span class="onelineComment">// Note this has both a i and ı</span>
+<span class="keyword">String</span> expected = <span class="string">'kıymetli'</span>;
+System.assertEquals(expected, s1Lower);
+<span class="onelineComment">// Note if this was done in toLowerCase(‘en’), it would output ‘kiymetli’</span></pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_toUpperCase">
+<a name="apex_System_String_toUpperCase"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">toUpperCase()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Converts all of the characters in the String to uppercase using the rules of the default
+      (English US) locale.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> toUpperCase()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> myString1 = <span class="string">'abcd'</span>;
+<span class="keyword">String</span> myString2 = <span class="string">'ABCD'</span>;
+myString1 =
+   myString1.toUpperCase();
+<span class="keyword">Boolean</span> result =
+   myString1.equals(myString2);
+System.assertEquals(result, <span class="keyword">true</span>);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_toUpperCase_2">
+<a name="apex_System_String_toUpperCase_2"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">toUpperCase(locale)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Converts all of the characters in the String to the uppercase
+using the rules of the specified locale. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> toUpperCase(<span class="keyword">String</span> locale)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">locale</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="onelineComment">// Example in Turkish</span>
+<span class="onelineComment">// Dotless lowercase "i", \u0131, which is ı</span>
+<span class="onelineComment">// Note this has both a i and ı</span>
+<span class="keyword">String</span> s1 = <span class="string">'imkansız'</span>;
+<span class="keyword">String</span> s1Upper = s1.toUpperCase(<span class="string">'tr'</span>);
+<span class="onelineComment">// An uppercase dotted "i", \u0304, which is İ</span>
+<span class="onelineComment">// Note this contains both a İ as well as a I</span>
+<span class="keyword">String</span> expected = <span class="string">'İMKANSIZ'</span>;
+System.assertEquals(expected, s1Upper);</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_trim">
+<a name="apex_System_String_trim"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">trim()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a copy of the string that no longer contains any
+leading or trailing white space characters. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> trim()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">Leading and trailing ASCII
+control characters such as tabs and newline characters are also removed.
+White space and control characters that aren’t at the beginning
+or end of the sentence aren’t removed.</p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 = <span class="string">'   Hello!   '</span>;
+<span class="keyword">String</span> trimmed = s1.trim();
+system.assertEquals(<span class="string">'Hello!'</span>, trimmed);</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_uncapitalize">
+<a name="apex_System_String_uncapitalize"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">uncapitalize()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns the current String with the first letter in lowercase.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> uncapitalize()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 =
+   <span class="string">'Hello max'</span>;
+<span class="keyword">String</span> s2 =
+   s1.uncapitalize();
+System.assertEquals(
+   <span class="string">'hello max'</span>,
+    s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_unescapeCsv">
+<a name="apex_System_String_unescapeCsv"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">unescapeCsv()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a String representing an unescaped CSV column.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> unescapeCsv()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">If the String is enclosed
+in double quotes and contains a comma, newline or double quote, quotes
+are removed. Also, any double quote escaped characters (a pair of
+double quotes) are unescaped to just one double quote.</p>
+<p class="p">If the
+String is not enclosed in double quotes, or is and does not contain
+a comma, newline or double quote, it is returned unchanged.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 =
+   <span class="string">'"Max1, ""Max2"""'</span>;
+<span class="keyword">String</span> s2 =
+   s1.unescapeCsv();
+System.assertEquals(
+   <span class="string">'Max1, "Max2"'</span>,
+    s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_unescapeEcmaScript">
+<a name="apex_System_String_unescapeEcmaScript"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">unescapeEcmaScript()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Unescapes any EcmaScript literals found in the String.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> unescapeEcmaScript()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 =
+   <span class="string">'\"3.8\",\"3.9\"'</span>;
+<span class="keyword">String</span> s2 =
+   s1.unescapeEcmaScript();
+System.assertEquals(
+   <span class="string">'"3.8","3.9"'</span>,
+   s2);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_unescapeHtml3">
+<a name="apex_System_String_unescapeHtml3"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">unescapeHtml3()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Unescapes the characters in a String using HTML 3.0 entities.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> unescapeHtml3()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 =
+   <span class="string">'&amp;quot;&amp;lt;Black&amp;amp;White&amp;gt;&amp;quot;'</span>;
+<span class="keyword">String</span> s2 =
+   s1.unescapeHtml3();
+System.assertEquals(
+   <span class="string">'"&lt;Black&amp;White&gt;"'</span>,
+   s2);
+</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_unescapeHtml4">
+<a name="apex_System_String_unescapeHtml4"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">unescapeHtml4()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Unescapes the characters in a String using HTML 4.0 entities.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> unescapeHtml4()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">If an entity isn’t
+recognized, it is kept as is in the returned string.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 =
+   <span class="string">'&amp;quot;&amp;lt;Black&amp;amp;White&amp;gt;&amp;quot;'</span>;
+<span class="keyword">String</span> s2 =
+   s1.unescapeHtml4();
+System.assertEquals(
+   <span class="string">'"&lt;Black&amp;White&gt;"'</span>,
+   s2);
+</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_unescapeJava">
+<a name="apex_System_String_unescapeJava"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">unescapeJava()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a String whose Java literals are unescaped. Literals
+unescaped include escape sequences for quotes (\\") and control characters,
+such as tab (\\t), and carriage return (\\n).</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> unescapeJava()</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+<p class="p">The unescaped string.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'Company: \\"Salesforce.com\\"'</span>;
+<span class="keyword">String</span> unescapedStr = s.unescapeJava();
+System.assertEquals(<span class="string">'Company: "Salesforce.com"'</span>, unescapedStr);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_unescapeUnicode">
+<a name="apex_System_String_unescapeUnicode"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">unescapeUnicode()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a String whose escaped Unicode characters are unescaped.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> unescapeUnicode()</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+<p class="p">The unescaped string.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s = <span class="string">'De onde voc\u00EA \u00E9?'</span>;
+<span class="keyword">String</span> unescapedStr = s.unescapeUnicode();
+System.assertEquals(<span class="string">'De onde você é?'</span>, unescapedStr);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_unescapeXml">
+<a name="apex_System_String_unescapeXml"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">unescapeXml()</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Unescapes the characters in a String using XML entities.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">String</span> unescapeXml()</samp></p>
+</div>
+
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">Supports only the five basic
+XML entities (gt, lt, quot, amp, apos). Does not support DTDs or external
+entities.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">String</span> s1 =
+   <span class="string">'&amp;quot;&amp;lt;Black&amp;amp;White&amp;gt;&amp;quot;'</span>;
+<span class="keyword">String</span> s2 =
+   s1.unescapeXml();
+System.assertEquals(
+   <span class="string">'"&lt;Black&amp;White&gt;"'</span>,
+   s2);
+</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_valueOf">
+<a name="apex_System_String_valueOf"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">valueOf(dateToConvert)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a String that represents the specified Date in
+the standard “yyyy-MM-dd” format.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">String</span> valueOf(<span class="keyword">Date</span> dateToConvert)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">dateToConvert</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_date.htm#apex_methods_system_date" title="Contains methods for the Date primitive data type.">Date</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">Date</span> myDate = <span class="keyword">Date</span>.Today();
+<span class="keyword">String</span> sDate = <span class="keyword">String</span>.valueOf(myDate);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_valueOf_2">
+<a name="apex_System_String_valueOf_2"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">valueOf(datetimeToConvert)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a String that represents the specified Datetime
+in the standard “yyyy-MM-dd HH:mm:ss” format for the
+local time zone.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">String</span> valueOf(<span class="keyword">Datetime</span> datetimeToConvert)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">datetimeToConvert</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_datetime.htm#apex_methods_system_datetime" title="Contains methods for the Datetime primitive data type.">Datetime</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex">DateTime dt = datetime.newInstance(1996, 6, 23);
+<span class="keyword">String</span> sDateTime = <span class="keyword">String</span>.valueOf(dt);
+System.assertEquals(<span class="string">'1996-06-23 00:00:00'</span>, sDateTime);</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_valueOf_3">
+<a name="apex_System_String_valueOf_3"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">valueOf(decimalToConvert)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a String that represents the specified Decimal.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">String</span> valueOf(<span class="keyword">Decimal</span> decimalToConvert)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">decimalToConvert</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_decimal.htm#apex_methods_system_decimal" title="Contains methods for the Decimal primitive data type.">Decimal</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">Decimal</span> dec = 3.14159265;
+<span class="keyword">String</span> sDecimal = <span class="keyword">String</span>.valueOf(dec);
+System.assertEquals(<span class="string">'3.14159265'</span>, sDecimal);</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_valueOf_4">
+<a name="apex_System_String_valueOf_4"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">valueOf(doubleToConvert)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a String that represents the specified Double.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">String</span> valueOf(<span class="keyword">Double</span> doubleToConvert)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">doubleToConvert</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_double.htm#apex_methods_system_double" title="Contains methods for the Double primitive data type.">Double</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">Double</span> myDouble = 12.34;
+<span class="keyword">String</span> myString =
+   <span class="keyword">String</span>.valueOf(myDouble);
+System.assertEquals(
+  <span class="string">'12.34'</span>, myString);</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_valueOf_5">
+<a name="apex_System_String_valueOf_5"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">valueOf(integerToConvert)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a String that represents the specified Integer.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">String</span> valueOf(<span class="keyword">Integer</span> integerToConvert)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">integerToConvert</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_integer.htm#apex_methods_system_integer" title="Contains methods for the Integer primitive data type.">Integer</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">Integer</span> myInteger = 22;
+<span class="keyword">String</span> sInteger = <span class="keyword">String</span>.valueOf(myInteger);
+System.assertEquals(<span class="string">'22'</span>, sInteger);</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_valueOf_6">
+<a name="apex_System_String_valueOf_6"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">valueOf(longToConvert)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a String that represents the specified Long. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">String</span> valueOf(<span class="keyword">Long</span> longToConvert)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">longToConvert</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_long.htm#apex_methods_system_long" title="Contains methods for the Long primitive data type.">Long</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="keyword">Long</span> myLong = 123456789;
+<span class="keyword">String</span> sLong = <span class="keyword">String</span>.valueOf(myLong);
+System.assertEquals(<span class="string">'123456789'</span>, sLong);</pre></div>
+
+  </div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_valueOf_7">
+<a name="apex_System_String_valueOf_7"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">valueOf(toConvert)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a string representation of the specified object
+argument. </div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">String</span> valueOf(<span class="keyword">Object</span> toConvert)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">toConvert</var></dt>
+
+<dd class="dd">Type: Object</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Usage</h4>
+<p class="p">If the argument is not a
+String, the <samp class="codeph apex_code">valueOf</samp> method
+converts it into a String by calling the <samp class="codeph apex_code">toString</samp> method on the argument, if available, or any overridden <samp class="codeph apex_code">toString</samp> method if the argument is
+a user-defined type. Otherwise, if no <samp class="codeph apex_code">toString</samp> method is available, it returns a String representation
+of the argument.</p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Example</h4>
+<div class="codeSection apex_code"><pre class="codeblock brush:apex">List&lt;<span class="keyword">Integer</span>&gt; ls =
+  <span class="keyword">new</span> List&lt;<span class="keyword">Integer</span>&gt;();
+ls.add(10);
+ls.add(20);
+<span class="keyword">String</span> strList =
+   <span class="keyword">String</span>.valueOf(ls);
+System.assertEquals(
+  <span class="string">'(10, 20)'</span>, strList);
+</pre></div>
+</div>
+
+</div>
+
+</div>
+<div class="topic reference nested2" lang="en-us" lang="en-us" id="apex_System_String_valueOfGmt">
+<a name="apex_System_String_valueOfGmt"><!– –></a>
+<h3 class="helpHead3"><span class="ph" id="topic-title"><a name="topic-title"><!– –></a><span class="titlecodeph">valueOfGmt(datetimeToConvert)</span></span></h3>
+
+
+
+<div class="body refbody">
+<div class="shortdesc">Returns a String that represents the specified Datetime
+in the standard “yyyy-MM-dd HH:mm:ss” format for the
+GMT time zone.</div>
+
+<div class="section">
+<h4 class="helpHead4">Signature</h4>
+<p class="p"><samp class="codeph apex_code"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">String</span> valueOfGmt(<span class="keyword">Datetime</span> datetimeToConvert)</samp></p>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Parameters</h4>
+<dl class="dl detailList">
+
+<dt class="dt dlterm"><var class="keyword varname">datetimeToConvert</var></dt>
+
+<dd class="dd">Type: <a class="xref" href="atlas.en-us.apexcode.meta/apexcode/apex_methods_system_datetime.htm#apex_methods_system_datetime" title="Contains methods for the Datetime primitive data type.">Datetime</a>
+</dd>
+
+
+</dl>
+</div>
+
+<div class="section">
+<h4 class="helpHead4">Return Value</h4>
+<p class="p">Type: <a class="xref" href="#apex_methods_system_string" title="Contains methods for the String primitive data type.">String</a></p>
+</div>
+
+  <div class="section">
+<h4 class="helpHead4">Example</h4>
+
+
+   <div class="codeSection apex_code"><pre class="codeblock brush:apex"><span class="onelineComment">// For a PST timezone:</span>
+DateTime dt = datetime.newInstance(2001, 9, 14);
+<span class="keyword">String</span> sDateTime = <span class="keyword">String</span>.valueOfGmt(dt);
+System.assertEquals(<span class="string">'2001-09-14 07:00:00'</span>, sDateTime);</pre>
diff --git a/test/jbProblemsList.txt b/test/jbProblemsList.txt
new file mode 100644
index 0000000..fc9c89a
--- /dev/null
+++ b/test/jbProblemsList.txt
@@ -0,0 +1,1364 @@
+###########################################################################
+#
+# List of tests that should not be run by test/Makefile, for various reasons:
+#   1. Does not run with jtreg -samevm mode
+#   2. Causes problems in jtreg -samevm mode for jtreg or tests that follow it
+#   3. The test is too slow or consumes too many system resources
+#   4. The test fails when run on any official build systems
+#
+# It is possible that a test being on this list is a mistake, and that some
+#   other test in samevm mode caused tests to fail, mistakes happen.
+#
+# Tests marked @ignore are not run by test/Makefile, but harmless to be listed.
+#
+# Tests that explicitly state "@run main/othervm ...", and are not listed here,
+#   will be run in the same batch as the samevm tests.
+#
+# Shell tests are othervm by default.
+#
+# List items  are testnames followed by labels, all MUST BE commented
+#   as to why they are here and use a label:
+#     generic-all   Problems on all platforms
+#     generic-ARCH  Where ARCH is one of: sparc, sparcv9, x64, i586, etc.
+#     OSNAME-all    Where OSNAME is one of: solaris, linux, windows, macosx, aix
+#     OSNAME-ARCH   Specific on to one OSNAME and ARCH, e.g. solaris-amd64
+#     OSNAME-REV    Specific on to one OSNAME and REV, e.g. solaris-5.8
+#
+# More than one label is allowed but must be on the same line.
+#
+#############################################################################
+#
+# Running the tests:
+#    cd test && make JT_HOME=jtreg_home PRODUCT_HOME=jdk_home jdk_all
+#  Or instead of jdk_all, use any of the jdk_* targets.
+#
+# Samevm Notes:
+#  * Although some tests may have only been seen to fail on some platforms,
+#    they might be flagged as 'generic-all' because the problem they have
+#    could cause hidden slowdowns on other platforms.
+#    Most samevm problems will be generic-all, but windows usually dislikes
+#    them the most.
+#    Address already in use or connection errors indicate a generic port issue.
+#    (this is not necessarily a samevm issue, but an issue for running the tests
+#     on shared machines, two people or two test runs will collide).
+#  * Samevm problem (windows in particular) is not closing all input/output
+#  * Samevm problem when a test calls setSecurityManager()
+#  * Samevm problem with setHttps*() is used? (not exactly sure here)
+#  * Samevm problem when stuffing system properties with non Strings or anything
+#  * Samevm problem when changing vm settings, or registering any vm actions
+#  * Samevm problems with deleteOnExit(), if it must happen at end of test
+#  * Samevm problems with URLClassLoader? (no details here)
+#  * Samevm problems with dependence on predictable GC or finalizations
+#
+# Any of the above problems may mean the test needs to be flagged as "othervm".
+#
+#############################################################################
+#
+# Fixing the tests:
+#
+# Some tests just may need to be run with "othervm", and that can easily be
+#   done my adding a @run line (or modifying any existing @run):
+#      @run main/othervm NameOfMainClass
+#   Make sure this @run follows any use of @library.
+#   Otherwise, if the test is a samevm possibility, make sure the test is
+#     cleaning up after itself, closing all streams, deleting temp files, etc.
+#
+# Keep in mind that the bug could be in many places, and even different per
+#   platform, it could be a bug in any one of:
+#      - the testcase
+#      - the jdk (jdk classes, native code, or hotspot)
+#      - the native compiler
+#      - the javac compiler
+#      - the OS (depends on what the testcase does)
+#
+# If you managed to really fix one of these tests, here is how you can
+#    remove tests from this list:
+#  1. Make sure test passes on all platforms with samevm, or mark it othervm
+#  2. Make sure test passes on all platforms when run with it's entire group
+#  3. Make sure both VMs are tested, -server and -client, if possible
+#  4. Make sure you try the -d64 option on Solaris
+#  5. Use a tool like JPRT or something to verify these results
+#  6. Delete lines in this file, include the changes with your test changes
+#
+# You may need to repeat your testing 2 or even 3 times to verify good
+#   results, some of these samevm failures are not very predictable.
+#
+#############################################################################
+
+############################################################################
+
+# jdk_awt
+
+# https://bugs.openjdk.java.net/browse/JDK-8169106
+java/awt/Choice/ChoiceKeyEventReaction/ChoiceKeyEventReaction.html       generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7100044
+java/awt/Choice/ChoiceMouseWheelTest/ChoiceMouseWheelTest.java           generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169108
+java/awt/Choice/ItemStateChangeTest/ItemStateChangeTest.java             windows-all
+
+## https://bugs.openjdk.java.net/browse/JDK-8022152
+# java/awt/Choice/RemoveAllShrinkTest/RemoveAllShrinkTest.java             generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169104
+java/awt/Component/PaintAll/PaintAll.java                                windows-all
+
+https://bugs.openjdk.java.net/browse/JDK-6857809
+java/awt/Component/PrintAllXcheckJNI/PrintAllXcheckJNI.java              linux-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8165863
+java/awt/Component/SetEnabledPerformance/SetEnabledPerformance.java      macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8170261
+java/awt/Component/TreeLockDeadlock/TreeLockDeadlock.java                generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8017456
+java/awt/DataFlavor/MissedHtmlAndRtfBug/MissedHtmlAndRtfBug.html         generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8081469
+java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java         generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6990210
+java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8073636
+java/awt/EventDispatchThread/LoopRobustness/LoopRobustness.html          generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8168390
+java/awt/EventDispatchThread/PreserveDispathThread/PreserveDispatchThread.java windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8029675
+java/awt/Focus/6981400/Test1.java                                        generic-all
+
+## https://bugs.openjdk.java.net/browse/JDK-6458497
+#java/awt/Focus/6981400/Test3.java                                        windows-all
+
+## https://bugs.openjdk.java.net/browse/JDK-8013611
+#java/awt/Focus/8013611/JDK8013611.java                                   windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8136517
+java/awt/Focus/8073453/AWTFocusTransitionTest.java                       generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8081301
+java/awt/Focus/8073453/SwingFocusTransitionTest.java                     generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8168408
+java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowBlockingTest.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6862004
+java/awt/Focus/AppletInitialFocusTest/AppletInitialFocusTest.html        generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6849367
+java/awt/Focus/AppletInitialFocusTest/AppletInitialFocusTest1.html       generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6848407
+java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusSetVisibleTest.java  generic-all
+
+# similar to
+# http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6848406
+java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java     generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6829264
+java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowRetaining.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169103
+java/awt/Focus/ChoiceFocus/ChoiceFocus.java                              windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8078413
+java/awt/Focus/ClearLwQueueBreakTest/ClearLwQueueBreakTest.java          generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7124555
+java/awt/Focus/CloseDialogActivateOwnerTest/CloseDialogActivateOwnerTest.java macosx-all, linux-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6986252
+java/awt/Focus/ConsumeNextKeyTypedOnModalShowTest/ConsumeNextKeyTypedOnModalShowTest.java generic-all
+
+## https://bugs.openjdk.java.net/browse/JDK-8169101
+# java/awt/Focus/FocusEmbeddedFrameTest/FocusEmbeddedFrameTest.java        windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8081489
+java/awt/Focus/FocusOwnerFrameOnClick/FocusOwnerFrameOnClick.java        generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6849364
+java/awt/Focus/IconifiedFrameFocusChangeTest/IconifiedFrameFocusChangeTest.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8053932
+java/awt/Focus/KeyEventForBadFocusOwnerTest/KeyEventForBadFocusOwnerTest.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7152980
+java/awt/Focus/NoAutotransferToDisabledCompTest/NoAutotransferToDisabledCompTest.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8151979
+java/awt/Focus/NonFocusableWindowTest/NonfocusableOwnerTest.java         generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169110
+java/awt/Focus/OwnedWindowFocusIMECrashTest/OwnedWindowFocusIMECrashTest.java  windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8168294
+java/awt/Focus/ResetMostRecentFocusOwnerTest/ResetMostRecentFocusOwnerTest.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8028701
+java/awt/Focus/ShowFrameCheckForegroundTest/ShowFrameCheckForegroundTest.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8159599
+java/awt/Focus/SimpleWindowActivationTest/SimpleWindowActivationTest.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7156130
+java/awt/Focus/ToFrontFocusTest/ToFrontFocus.html                        generic-all
+
+# http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6848810
+# https://bugs.openjdk.java.net/browse/JDK-7035459
+java/awt/Focus/TranserFocusToWindow/TranserFocusToWindow.java        generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6986253
+java/awt/Focus/TypeAhead/TestFocusFreeze.java                        windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169100
+java/awt/Focus/WindowInitialFocusTest/WindowInitialFocusTest.html    windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169099
+java/awt/Focus/WindowIsFocusableAccessByThreadsTest/WindowIsFocusableAccessByThreadsTest.java windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169096
+java/awt/Focus/WrongKeyTypedConsumedTest/WrongKeyTypedConsumedTest.java windows-all
+
+# http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6868690
+java/awt/FontClass/CreateFont/bigfont.html                           generic-all
+
+#http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8076151
+java/awt/FontClass/CreateFont/fileaccess/FontFile.java               generic-all
+
+# http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8080953
+java/awt/FontClass/DebugFonts.java                                   generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169111
+java/awt/Frame/InvisibleOwner/InvisibleOwner.java                    generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169472
+java/awt/Frame/LayoutOnMaximizeTest/LayoutOnMaximizeTest.java        windows-all
+
+# excluded from regular runs since the test was not run
+# see http://download.java.net/openjdk/testresults/8/
+java/awt/Frame/UnfocusableMaximizedFrameResizablity/UnfocusableMaximizedFrameResizablity.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169470
+java/awt/Frame/WindowDragTest/WindowDragTest.java                    windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169471
+java/awt/FullScreen/8013581/bug8013581.java                          windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8047218
+java/awt/FullScreen/AltTabCrashTest/AltTabCrashTest.java             generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169469
+java/awt/FullScreen/DisplayChangeVITest/DisplayChangeVITest.java     windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7019055
+java/awt/FullScreen/FullScreenInsets/FullScreenInsets.java           windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169468
+java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8012224
+java/awt/Frame/MaximizedToIconified/MaximizedToIconified.java        generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8144030
+java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java        generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7019055
+java/awt/FullScreen/FullScreenInsets/FullScreenInsets.java           generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8016241
+java/awt/FullScreen/SetFSWindow/FSFrame.java                         generic-all
+
+## https://bugs.openjdk.java.net/browse/JDK-7179526
+#java/awt/Graphics/LineClipTest.java                                  generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8080084
+java/awt/Graphics2D/DrawString/DrawStringCrash.java                  generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7043153
+java/awt/Graphics2D/DrawString/RotTransText.java                     generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169464
+java/awt/Graphics2D/DrawString/TextRenderingTest.java                windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169463
+java/awt/Graphics2D/FillTexturePaint/FillTexturePaint.java           windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169462
+java/awt/Graphics2D/FlipDrawImage/FlipDrawImage.java                 windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8145808
+java/awt/Graphics2D/MTGraphicsAccessTest/MTGraphicsAccessTest.java   generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8054638
+java/awt/Graphics2D/WhiteTextColorTest.java                          generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8170729
+java/awt/JAWT/JAWT.sh                                                windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8158380
+java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.html generic-all
+
+## https://bugs.openjdk.java.net/browse/JDK-8073639
+# https://bugs.openjdk.java.net/browse/JDK-8074807
+java/awt/KeyboardFocusmanager/TypeAhead/TestDialogTypeAhead.html     generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8163261
+java/awt/LightweightDispatcher/LWDispatcherMemoryLeakTest.java       generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169461
+java/awt/List/FirstItemRemoveTest/FirstItemRemoveTest.html           windows-all
+
+## https://bugs.openjdk.java.net/browse/JDK-6561487
+# java/awt/List/NofocusListDblClickTest/NofocusListDblClickTest.java   generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8068305
+java/awt/Mixing/HWDisappear.java                                     generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8143295
+java/awt/Mixing/LWPopupMenu.java                                     generic-all
+
+## https://bugs.openjdk.java.net/browse/JDK-6885735
+#java/awt/Mixing/MixingInHwPanel.java                                 generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-4049668
+java/awt/Mixing/MixingOnDialog.java                                  generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169460
+java/awt/Mixing/MixingOnShrinkingHWButton.java                       windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7124549
+java/awt/Mixing/NonOpaqueInternalFrame.java                          macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169457
+java/awt/Mixing/OpaqueTest.java                                      windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7124549
+java/awt/Mixing/OverlappingButtons.java                              generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8165619
+java/awt/Mixing/ValidBounds.java                                     generic-all
+java/awt/Mixing/Validating.java                                      generic-all
+
+## https://bugs.openjdk.java.net/browse/JDK-8029024
+# https://bugs.openjdk.java.net/browse/JDK-8066259
+java/awt/Modal/ModalDialogOrderingTest/ModalDialogOrderingTest.java  generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8159599
+java/awt/Modal/ModalInternalFrameTest/ModalInternalFrameTest.java    generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8052166
+java/awt/Mouse/MouseComboBoxTest/MouseComboBoxTest.java              generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8023562
+java/awt/Mouse/EnterExitEvents/DragWindowOutOfFrameTest.java         generic-all
+java/awt/Mouse/EnterExitEvents/DragWindowTest.java                   generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7087869
+# https://bugs.openjdk.java.net/browse/JDK-8169534
+java/awt/Mouse/ExtraMouseClick/ExtraMouseClick.html                  generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8051455
+java/awt/Mouse/EnterExitEvents/FullscreenEnterEventTest.java         macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8144042
+java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java                generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8168388
+java/awt/Mouse/GetMousePositionTest/GetMousePositionWithOverlay.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8027154
+java/awt/Mouse/GetMousePositionTest/GetMousePositionWithPopup.java   generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8132766
+java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.html            macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8129775
+java/awt/Mouse/MouseDragEvent/MouseDraggedTest.java                  generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8013428
+java/awt/Mouse/MouseModifiersUnitTest/ExtraButtonDrag.java           generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8130471
+java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersUnitTest_Extra.java linux-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7124407
+java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersUnitTest_Standard.java macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8157170
+java/awt/Mouse/RemovedComponentMouseListener/RemovedComponentMouseListener.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8148041
+java/awt/Mouse/TitleBarDoubleClick/TitleBarDoubleClick.html          generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8012577
+java/awt/MouseAdapter/MouseAdapterUnitTest/MouseAdapterUnitTest.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8028484
+java/awt/MouseInfo/JContainerMousePositionTest.java                  generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7124230
+java/awt/Multiscreen/LocationRelativeToTest/LocationRelativeToTest.java macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8139581
+java/awt/Paint/ComponentIsNotDrawnAfterRemoveAddTest/ComponentIsNotDrawnAfterRemoveAddTest.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169104
+java/awt/Paint/ExposeOnEDT.java                                      windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8028000
+java/awt/Paint/PaintNativeOnUpdate.java                              generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8031422
+java/awt/Paint/bug8024864.java                                       generic-all
+
+# excluded from regular runs since the test was not run
+# see http://download.java.net/openjdk/testresults/8/
+java/awt/ScrollPane/ScrollPanePreferredSize/ScrollPanePreferredSize.java  generic-all
+java/awt/ScrollPane/bug8077409Test.java                              generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8140329
+java/awt/SplashScreen/FullscreenAfterSplash/FullScreenAfterSplash.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8159592
+java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java generic-all
+
+# excluded from regular runs since the test was not run
+# see http://download.java.net/openjdk/testresults/8/
+java/awt/TextArea/Mixing/TextAreaMixing.java                         generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169533
+java/awt/TextField/SelectionInvisibleTest/SelectionInvisibleTest.java windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6734341
+java/awt/TextArea/UsingWithMouse/SelectionAutoscrollTest.html        generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6829250
+java/awt/Toolkit/ScreenInsetsTest/ScreenInsetsTest.java              generic-all
+
+## https://bugs.openjdk.java.net/browse/JDK-6829267
+# https://bugs.openjdk.java.net/browse/JDK-6847163
+java/awt/Toolkit/ToolkitPropertyTest/ToolkitPropertyTest_Enable.java generic-all
+
+# http://bugs.java.com/view_bug.do?bug_id=8039081
+java/awt/TrayIcon/PopupMenuLeakTest/PopupMenuLeakTest.java           generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7107528
+java/awt/Robot/AcceptExtraMouseButtons/AcceptExtraMouseButtons.java  generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169530
+java/awt/Window/AlwaysOnTop/TestAlwaysOnTopBeforeShow.java           windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8142536
+java/awt/Window/BackgroundIsNotUpdated/BackgroundIsNotUpdated.java   generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8047703
+java/awt/Window/Grab/GrabTest.java                                   generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6848409
+java/awt/Window/GrabSequence/GrabSequence.java                       generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8051857
+java/awt/Window/WindowType/WindowType.java                           linux-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8137087
+java/awt/appletviewer/IOExceptionIfEncodedURLTest/IOExceptionIfEncodedURLTest.sh windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8080982
+java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java    generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8017457
+java/awt/datatransfer/DragUnicodeBetweenJVMTest/DragUnicodeBetweenJVMTest.html windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8039082
+java/awt/dnd/BadSerializaionTest/BadSerializationTest.java           generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8144056
+java/awt/dnd/Button2DragTest/Button2DragTest.html                    generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8066096
+java/awt/dnd/DragInterceptorAppletTest/DragInterceptorAppletTest.html generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8029680
+java/awt/dnd/DropTargetEnterExitTest/ExtraDragEnterTest.java         generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8029680
+java/awt/dnd/DropTargetEnterExitTest/MissedDragExitTest.java         generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7098447
+java/awt/dnd/ImageTransferTest/ImageTransferTest.java                generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7124379
+java/awt/dnd/FileListBetweenJVMsTest/FileListBetweenJVMsTest.html    generic-all
+java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.html      generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8030121
+java/awt/dnd/MissingDragExitEventTest/MissingDragExitEventTest.java  generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8164464
+java/awt/dnd/MissingEventsOnModalDialog/MissingEventsOnModalDialogTest.java generic-all
+
+## https://bugs.openjdk.java.net/browse/JDK-7109239
+#java/awt/dnd/NoFormatsCrashTest/NoFormatsCrashTest.html              generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8072088
+java/awt/dnd/ImageDecoratedDnDNegative/ImageDecoratedDnDNegative.html generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8011614
+java/awt/dnd/InterJVMGetDropSuccessTest/InterJVMGetDropSuccessTest.html generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8041431
+java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.html generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6618538
+java/awt/event/HierarchyEvent/AncestorResized/AncestorResized.java   generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8168646
+java/awt/event/InputEvent/EventWhenTest/EventWhenTest.java           generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8158362
+java/awt/event/KeyEvent/AltCharAcceleratorTest/AltCharAcceleratorTest.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8145652
+java/awt/event/KeyEvent/DeadKey/DeadKeySystemAssertionDialog.java    generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6626492
+java/awt/event/KeyEvent/CorrectTime/CorrectTime.java                 generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169476
+java/awt/event/KeyEvent/ExtendedKeyCode/ExtendedKeyCodeTest.java     generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169474
+java/awt/event/KeyEvent/KeyChar/KeyCharTest.java                     windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7156316
+# https://bugs.openjdk.java.net/browse/JDK-8160623
+java/awt/event/KeyEvent/KeyTyped/CtrlASCII.html                      generic-all
+
+## https://bugs.openjdk.java.net/browse/JDK-7124391
+#java/awt/event/MouseEvent/EnterAsGrabbedEvent/EnterAsGrabbedEvent.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8032254
+java/awt/event/MouseEvent/EventTimeInFuture/EventTimeInFuture.java   linux-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8168389
+java/awt/event/MouseEvent/MouseClickTest/MouseClickTest.html         generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6854300
+java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_3.java generic-all
+
+## https://bugs.openjdk.java.net/browse/JDK-4391548
+#java/awt/event/MouseEvent/RobotLWTest/RobotLWTest.html               generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8060176
+java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion.java   generic-all
+java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_1.java generic-all
+java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_2.html generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6956646
+java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_4.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6956646
+java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_3.html generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169475
+java/awt/event/MouseWheelEvent/WheelModifier/WheelModifier.java       windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7043170
+java/awt/font/TextLayout/CombiningPerf.java                          generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7162125
+java/awt/font/TextLayout/OSXLigatureTest.java                        macosx-all
+
+# Test ignored: Requires a special font installed
+java/awt/font/TextLayout/TestOldHangul.java                          generic-all
+java/awt/font/TextLayout/TestTibetan.java                            generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8164818
+java/awt/font/TextLayout/VisibleAdvance.java                         generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7080150
+java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java             generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169109
+java/awt/grab/GrabOnUnfocusableToplevel/GrabOnUnfocusableToplevel.java windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8028000
+java/awt/image/DrawImage/EABlitTest.java                             generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8056077
+java/awt/image/DrawImage/IncorrectAlphaSurface2SW.java               linux-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169473
+java/awt/image/DrawImage/IncorrectBounds.java                        windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8130400
+java/awt/image/DrawImage/IncorrectClipXorModeSW2Surface.java         linux-all
+java/awt/image/DrawImage/IncorrectClipXorModeSurface2Surface.java    linux-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169951
+java/awt/image/DrawImage/IncorrectOffset.java                        windows-all
+java/awt/image/DrawImage/IncorrectDestinationOffset.java             windows-all
+java/awt/image/DrawImage/IncorrectSourceOffset.java                  windows-all
+
+# no printer found
+java/awt/print/PrinterJob/ExceptionTest.java                         generic-all
+java/awt/print/PrinterJob/ImagePrinting/NullClipARGB.java            generic-all
+java/awt/print/PrinterJob/PrtException.java                          generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8172009
+java/awt/print/PaintSetEnabledDeadlock/PaintSetEnabledDeadlock.java  macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8152944
+https://bugs.openjdk.java.net/browse/JDK-8152944
+excluded from regular runs
+java/time/tck/java/time/TCKDayOfWeek.java                            generic-all
+java/time/tck/java/time/TCKDuration.java                             generic-all
+java/time/tck/java/time/TCKInstant.java                              generic-all
+java/time/tck/java/time/TCKLocalDate.java                            generic-all
+java/time/tck/java/time/TCKLocalDateTime.java                        generic-all
+java/time/tck/java/time/TCKLocalTime.java                            generic-all
+java/time/tck/java/time/TCKMonth.java                                generic-all
+java/time/tck/java/time/TCKOffsetDateTime.java                       generic-all
+java/time/tck/java/time/TCKOffsetTime.java                           generic-all
+java/time/tck/java/time/TCKPeriod.java                               generic-all
+java/time/tck/java/time/TCKYear.java                                 generic-all
+java/time/tck/java/time/TCKYearMonth.java                            generic-all
+java/time/tck/java/time/TCKZonedDateTime.java                        generic-all
+java/time/tck/java/time/format/TCKDateTimeFormatters.java            generic-all
+java/time/tck/java/time/format/TCKDateTimeParseResolver.java         generic-all
+java/time/tck/java/time/format/TCKInstantPrinterParser.java          generic-all
+java/time/tck/java/time/format/TCKLocalizedFieldParser.java          generic-all
+java/time/tck/java/time/temporal/TCKChronoField.java                 generic-all
+java/time/tck/java/time/temporal/TCKChronoUnit.java                  generic-all
+java/time/tck/java/time/temporal/TCKIsoFields.java                   generic-all
+java/time/tck/java/time/temporal/TCKJulianFields.java                generic-all
+java/time/test/java/time/chrono/TestUmmAlQuraChronology.java         generic-all
+java/time/test/java/time/format/TestNumberParser.java                generic-all
+java/time/test/java/time/format/TestNumberPrinter.java               generic-all
+java/time/test/java/time/format/TestZoneOffsetParser.java            generic-all
+java/time/test/java/time/temporal/TestChronoUnit.java                generic-all
+java/time/test/java/time/temporal/TestDateTimeValueRange.java        generic-all
+
+
+## https://bugs.openjdk.java.net/browse/JDK-6560348
+# https://bugs.openjdk.java.net/browse/JDK-7146533
+java/awt/xembed/server/RunTestXEmbed.java                            macosx-all
+
+############################################################################
+
+# jdk_sound
+
+## https://bugs.openjdk.java.net/browse/JDK-8134632 (fixed in jdk9)
+# MidiSystem not available
+javax/sound/midi/Devices/InitializationHang.java                     generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8148915
+javax/sound/sampled/DirectAudio/bug6400879.java                      generic-all
+
+############################################################################
+
+# jdk_beans
+
+# https://bugs.openjdk.java.net/browse/JDK-8015593
+java/beans/XMLEncoder/Test6570354.java                               macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8030123
+java/beans/Introspector/Test8027648.java                             linux-all
+
+############################################################################
+
+# jdk_io
+
+# Test ignored: This test has huge memory requirements
+java/io/ByteArrayOutputStream/MaxCapacity.java                       generic-all
+
+# Test ignored: until 6492634 and 6501010 is fixed
+# http://bugs.java.com/view_bug.do?bug_id=6492634
+# http://bugs.java.com/view_bug.do?bug_id=6501010
+java/io/File/GetXSpace.java                                          generic-all
+
+# Test ignored: Test truncates system files when run as root, see 7042603
+# http://bugs.java.com/view_bug.do?bug_id=7042603
+java/io/IOException/LastErrorString.java                             generic-all
+
+# Test ignored: This test requires console (/dev/tty) input, which is not supported by the current harness
+java/io/SystemInAvailable.java                                       generic-all
+
+############################################################################
+
+# jdk_lang
+
+# Test ignored: This test has huge memory requirements
+java/lang/StringBuilder/HugeCapacity.java                            generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8072130
+java/lang/instrument/BootClassPath/BootClassPathTest.sh              macosx-all
+
+# Test ignored: until bug 6835233 dealt with
+# http://bugs.java.com/view_bug.do?bug_id=6835233
+java/lang/instrument/ParallelTransformerLoader.sh                    generic-all
+
+# Test ignored: 8078602
+# http://bugs.java.com/view_bug.do?bug_id=8078602
+java/lang/invoke/LFCaching/LFGarbageCollectedTest.java               generic-all
+
+############################################################################
+
+# jdk_management
+
+# https://bugs.openjdk.java.net/browse/JDK-8038822
+java/lang/management/MemoryMXBean/LowMemoryTest2.sh                  generic-all
+
+## https://bugs.openjdk.java.net/browse/JDK-8170303
+# java/lang/management/ThreadMXBean/ThreadInfoArray.java               generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8160913
+javax/management/security/SecurityTest.java                          generic-all
+
+# 8028150
+sun/management/jmxremote/bootstrap/RmiSslBootstrapTest.sh	         windows-all
+
+############################################################################
+
+# jdk_jmx
+
+# 8030957
+com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.java aix-all
+com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java  aix-all
+javax/management/MBeanServer/OldMBeanServerTest.java            aix-all
+
+############################################################################
+
+# jdk_math
+
+############################################################################
+
+# jdk_other
+
+# 6988950
+demo/jvmti/compiledMethodLoad/CompiledMethodLoadTest.java	generic-all
+
+# 7027502
+demo/jvmti/hprof/MonitorTest.java                               generic-all
+
+# 8027973
+javax/xml/jaxp/transform/jdk8004476/XSLTExFuncTest.java		windows-all
+
+# no printer found
+javax/print/CheckDupFlavor.java                                      generic-all
+javax/print/PrintServiceLookup/CountPrintServices.java               generic-all
+javax/print/attribute/AttributeTest.java                             generic-all
+javax/print/attribute/GetCopiesSupported.java                        generic-all
+javax/print/attribute/SidesPageRangesTest.java                       generic-all
+javax/print/attribute/SupportedPrintableAreas.java                   generic-all
+
+# it looks like the tests spend a lot of time on Windows
+javax/print/attribute/Chroma.java                                    generic-all
+javax/print/attribute/ChromaticityValues.java                        generic-all
+javax/print/attribute/CollateAttr.java                               generic-all
+javax/print/attribute/MediaMappingsTest.java                         generic-all
+javax/print/attribute/PSCopiesFlavorTest.java                        generic-all
+javax/print/attribute/autosense/PrintAutoSenseData.java              generic-all
+
+# hangs on Windows
+javax/print/PrintSE/PrintSE.sh                                  windows-all
+
+############################################################################
+
+# jdk_net
+
+# Filed 7052625
+com/sun/net/httpserver/bugs/6725892/Test.java                   generic-all
+
+# failing on vista 32/64 on nightly
+# 7102702
+java/net/PortUnreachableException/OneExceptionOnly.java         windows-all
+
+# 7148829
+sun/net/InetAddress/nameservice/simple/CacheTest.java		generic-all
+sun/net/InetAddress/nameservice/simple/DefaultCaching.java	generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6602831
+java/net/Inet6Address/B6206527.java                             generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8065419
+java/net/Inet4Address/textToNumericFormat.java                  generic-all
+
+# 7122846
+java/net/MulticastSocket/NoLoopbackPackets.java                  macosx-all
+java/net/MulticastSocket/SetLoopbackMode.java                    macosx-all
+
+# 7145658
+java/net/MulticastSocket/Test.java                               macosx-all
+
+# 7143960
+java/net/DatagramSocket/SendDatagramToBadAddress.java            macosx-all
+
+############################################################################
+
+# jdk_nio
+
+# https://bugs.openjdk.java.net/browse/JDK-8068693
+java/nio/channels/AsyncCloseAndInterrupt.java                   generic-all
+
+# 6963118
+java/nio/channels/Selector/Wakeup.java                          windows-all
+
+# 7141822
+java/nio/channels/DatagramChannel/ChangingAddress.java          macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8137230
+java/nio/channels/FileChannel/LoopingTruncate.java              generic-all
+
+# 7132677
+java/nio/channels/Selector/OutOfBand.java                       macosx-all
+
+# 7158947, Solaris 11
+java/nio/file/WatchService/Basic.java				solaris-all
+java/nio/file/WatchService/LotsOfEvents.java			solaris-all
+
+############################################################################
+
+# jdk_rmi
+
+# 7140992
+java/rmi/server/Unreferenced/finiteGCLatency/FiniteGCLatency.java  generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8029360
+java/rmi/transport/dgcDeadLock/DGCDeadLock.java                 generic-all
+
+# 7146541
+java/rmi/transport/rapidExportUnexport/RapidExportUnexport.java	linux-all
+
+# 7191877
+java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java       generic-all
+
+# 7195095
+sun/rmi/transport/proxy/EagerHttpFallback.java                  generic-all
+
+############################################################################
+
+# jdk_security
+
+## https://bugs.openjdk.java.net/browse/JDK-7054428
+#java/security/SecureClassLoader/DefineClassByteBuffer.java      generic-all
+
+# Test ignored: Must set up KDC and setup Kerberos configuration file
+javax/security/auth/kerberos/KerberosHashEqualsTest.java             generic-all
+javax/security/auth/kerberos/KerberosTixDateTest.java                generic-all
+
+# Test ignored: run these by hand
+com/sun/security/auth/callback/TextCallbackHandler/Password.java     generic-all
+com/sun/security/auth/callback/TextCallbackHandler/Default.java      generic-all
+
+# Test ignored: see runwjaas.csh for instructions for how to run this test
+com/sun/security/sasl/gsskerb/NoSecurityLayer.java              generic-all
+com/sun/security/sasl/gsskerb/ConfSecurityLayer.java            generic-all
+com/sun/security/sasl/gsskerb/AuthOnly.java                     generic-all
+
+# 7157786
+sun/security/pkcs11/ec/TestKeyFactory.java                      generic-all
+
+# 7164518: no PortUnreachableException on Mac
+sun/security/krb5/auto/Unreachable.java                         macosx-all
+
+# 7147060
+com/sun/org/apache/xml/internal/security/transforms/ClassLoaderTest.java	generic-all
+
+# 6988842: 4 tests failing on Solaris 5.10
+sun/security/pkcs11/Secmod/AddPrivateKey.java                   solaris-all
+sun/security/pkcs11/ec/ReadCertificates.java                    solaris-all
+sun/security/pkcs11/ec/ReadPKCS12.java                          solaris-all
+sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java            solaris-all
+
+# 7041639, Solaris DSA keypair generation bug
+java/security/KeyPairGenerator/SolarisShortDSA.java             solaris-all
+sun/security/tools/keytool/standard.sh                          solaris-all
+
+# 8026393
+sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java      generic-all
+
+# 8158827
+sun/security/krb5/auto/tools/KinitConfPlusProps.java                       windows-all
+
+############################################################################
+
+# jdk_swing
+
+# https://bugs.openjdk.java.net/browse/JDK-8060765
+javax/swing/AbstractButton/6711682/bug6711682.java                   generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8143021
+javax/swing/JColorChooser/Test6541987.java                           generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8076178
+javax/swing/JColorChooser/Test7194184.java                           generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8171302
+javax/swing/JComboBox/4743225/bug4743225.java                        generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8028707
+javax/swing/JComboBox/6236162/bug6236162.java                        generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8040797
+javax/swing/JComboBox/8032878/bug8032878.java                        generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8033069
+javax/swing/JComboBox/8033069/bug8033069NoScrollBar.java             generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8163367
+javax/swing/JComboBox/8033069/bug8033069ScrollBar.java               generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169953
+javax/swing/JComboBox/8057893/bug8057893.java                        windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8136998
+javax/swing/JComboBox/8136998/bug8136998.java                        generic-all
+
+# http://bugs.java.com/view_bug.do?bug_id=8067986
+javax/swing/JComboBox/ConsumedKeyTest/ConsumedKeyTest.java           generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8172337
+javax/swing/JComponent/6683775/bug6683775.java                       generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7190978
+javax/swing/JComponent/7154030/bug7154030.java                       generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8042380
+javax/swing/JFileChooser/4524490/bug4524490.java                     generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8058231
+javax/swing/JFileChooser/6396844/TwentyThousandTest.java             generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8087110
+javax/swing/JFileChooser/8002077/bug8002077.java                     generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169954
+javax/swing/JFileChooser/8021253/bug8021253.java                     windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8064715
+javax/swing/JFileChooser/8062561/bug8062561.java                     generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8170721
+javax/swing/JFrame/4962534/bug4962534.html                           macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169955
+javax/swing/JFrame/8016356/bug8016356.java                           windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8007719
+javax/swing/JInternalFrame/5066752/bug5066752.java                   generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8032568
+javax/swing/JInternalFrame/8020708/bug8020708.java                   generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8160880
+javax/swing/JInternalFrame/Test6325652.java                          generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8172535
+javax/swing/JInternalFrame/Test6505027.java                          generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8040914
+javax/swing/JLabel/6596966/bug6596966.java                           generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8003972
+javax/swing/JList/6462008/bug6462008.java                            generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8040915
+javax/swing/JMenu/4515762/bug4515762.java                            generic-all
+
+https://bugs.openjdk.java.net/browse/JDK-8171998
+javax/swing/JMenu/4692443/bug4692443.java                            windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8142534
+javax/swing/JMenu/8072900/WrongSelectionOnMouseOver.java             generic-all
+
+## https://bugs.openjdk.java.net/browse/JDK-8015597
+#javax/swing/JMenuBar/4750590/bug4750590.java                         generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8040916
+javax/swing/JMenuItem/4171437/bug4171437.java                        generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8172536
+javax/swing/JMenuItem/4654927/bug4654927.java                        windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8025083
+javax/swing/JMenuItem/6209975/bug6209975.java                        generic-all
+
+https://bugs.openjdk.java.net/browse/JDK-8139169
+javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7124548
+javax/swing/JOptionPane/6464022/bug6464022.java                      macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8040917
+javax/swing/JPopupMenu/4458079/bug4458079.java                       generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8064915
+# https://bugs.openjdk.java.net/browse/JDK-8074385
+javax/swing/JPopupMenu/4966112/bug4966112.java                       generic-all
+
+# https://bugs. openjdk.java.net/browse/JDK-7184956
+javax/swing/JPopupMenu/6800513/bug6800513.java                       generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8042378
+# https://bugs.openjdk.java.net/browse/JDK-8156460
+javax/swing/JPopupMenu/6827786/bug6827786.java                       generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169956
+javax/swing/JPopupMenu/6987844/bug6987844.java                       windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7185563
+# https://bugs.openjdk.java.net/browse/JDK-8171381
+javax/swing/JPopupMenu/7156657/bug7156657.java                       generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8064920
+javax/swing/JRadioButton/8033699/bug8033699.java                     generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8130430
+javax/swing/JRadioButton/8075609/bug8075609.java                     generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8042381
+javax/swing/JRootPane/4670486/bug4670486.java                        generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8145647                   linux
+# https://bugs.openjdk.java.net/browse/JDK-8169957
+javax/swing/JScrollBar/4708809/bug4708809.java                       generic-all
+
+## https://bugs.openjdk.java.net/browse/JDK-8024407
+#javax/swing/JScrollBar/7163696/Test7163696.java                      macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8028618
+javax/swing/JScrollBar/bug4202954/bug4202954.java                    windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169960
+javax/swing/JScrollPane/HorizontalMouseWheelOnShiftPressed/HorizontalMouseWheelOnShiftPressed.java windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8172539
+javax/swing/JSlider/6348946/bug6348946.java                          windows -all
+
+# https://bugs.openjdk.java.net/browse/JDK-8172408
+javax/swing/JSpinner/4973721/bug4973721.java                         generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169958
+javax/swing/JSpinner/5012888/bug5012888.java                         windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8019935
+javax/swing/JSplitPane/4885629/bug4885629.java                       generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8171997
+javax/swing/JTabbedPane/4624207/bug4624207.java                      windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7033533
+javax/swing/JTable/4220171/bug4220171.java                           generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169959
+javax/swing/JTable/6263446/bug6263446.java                           windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8169952
+javax/swing/JTableHeader/6884066/bug6884066.java                     windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7179842
+javax/swing/JTableHeader/6889007/bug6889007.java                     generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8170260
+javax/swing/JTabbedPane/4361477/bug4361477.java                      generic-all
+
+## https://bugs.openjdk.java.net/browse/JDK-7112925
+#javax/swing/JTabbedPane/4624207/bug4624207.java                      macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8028281
+javax/swing/JTabbedPane/7024235/Test7024235.java                     macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8051591
+javax/swing/JTabbedPane/8007563/Test8007563.java                     generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8145645
+javax/swing/JTextField/8036819/bug8036819.java                       generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8172407
+javax/swing/JToolTip/4846413/bug4846413.java                         generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8029682
+javax/swing/JTree/4330357/bug4330357.java                            windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8172065
+javax/swing/JTree/4908142/bug4908142.java                            windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8172063
+javax/swing/JTree/4927934/bug4927934.java                            windows-all
+
+# http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8011259
+javax/swing/JTree/8003400/Test8003400.java                           generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7105119
+javax/swing/MultiUIDefaults/4300666/bug4300666.java                  macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8065099
+javax/swing/PopupFactory/6276087/NonOpaquePopupMenuTest.java         macosx-all
+
+# http://bugs.java.com/view_bug.do?bug_id=8008119
+javax/swing/RepaintManager/IconifyTest/IconifyTest.java              generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8015602
+javax/swing/SpringLayout/4726194/bug4726194.java                     macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8172064
+javax/swing/SwingUtilities/4917669/bug4917669.java                   windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7195187
+javax/swing/SwingUtilities/7088744/bug7088744.java                   generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8079253
+javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java            linux-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8159454
+javax/swing/ToolTipManager/7123767/bug7123767.java                   generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8167009
+javax/swing/ToolTipManager/Test6256140.java                          generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8081764
+javax/swing/plaf/aqua/CustomComboBoxFocusTest.java                   generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8042383
+javax/swing/plaf/basic/BasicMenuUI/4983388/bug4983388.java           generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8079450
+javax/swing/plaf/nimbus/8041642/bug8041642.java                      generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8160438
+javax/swing/plaf/nimbus/8057791/bug8057791.java                      macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8170722
+javax/swing/plaf/synth/7158712/bug7158712.java                       generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8081478
+javax/swing/plaf/synth/SynthButtonUI/6276188/bug6276188.java         generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8172071
+javax/swing/plaf/windows/WindowsRootPaneUI/WrongAltProcessing/WrongAltProcessing.java windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8130895
+javax/swing/system/6799345/TestShutdown.java                         linux-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8003533
+javax/swing/text/CSSBorder/6796710/bug6796710.java                   generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8063107
+javax/swing/text/DefaultEditorKit/4278839/bug4278839.java            generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8050988
+javax/swing/text/GlyphPainter2/6427244/bug6427244.java               generic-all
+
+## https://bugs.openjdk.java.net/browse/JDK-7147408
+#javax/swing/text/StyledEditorKit/4506788/bug4506788.java             generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8041944
+javax/swing/text/View/8014863/bug8014863.java                        generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7033533
+javax/swing/text/html/CSS/4530474/bug4530474.java                    generic-all
+
+# http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8076178
+javax/swing/text/html/HTMLEditorKit/5043626/bug5043626.java          generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8022535
+javax/swing/text/html/parser/Test8017492.java                        generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6962725
+javax/swing/JFileChooser/6738668/bug6738668.java                     generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8049313
+javax/swing/JTable/7068740/bug7068740.java                           generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8032895
+javax/swing/JTextArea/4697612/bug4697612.java                        linux-all
+
+############################################################################
+
+# jdk_text
+
+############################################################################
+
+# jdk_time
+
+############################################################################
+
+# jdk_tools
+
+# Tests take too long, on sparcs see 7143279
+tools/pack200/CommandLineTests.java                             solaris-all, macosx-all
+tools/pack200/Pack200Test.java                                  solaris-all, macosx-all
+
+# 8007410
+tools/launcher/FXLauncherTest.java                              linux-all
+
+############################################################################
+
+# jdk_jdi
+
+############################################################################
+
+# jdk_util
+
+# Filed 6772009
+java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java generic-all
+
+# Test ignored: Bug fix temporarily removed as it uncovered other bugs (4992226)
+java/util/AbstractList/CheckForComodification.java                   generic-all
+
+## https://bugs.openjdk.java.net/browse/JDK-8060093
+# java/util/Currency/CurrencyTest.java                                 generic-all
+# java/util/Currency/ValidateISO4217.java                              generic-all
+
+# Test ignored: until 6842022 is resolved
+java/util/ResourceBundle/RestrictedBundleTest.java                   generic-all
+
+#Test ignored: 6876961
+java/util/ResourceBundle/Test4300693.java                            generic-all
+
+Test ignored: until 6842353 is resolved
+java/util/WeakHashMap/GCDuringIteration.java                         generic-all
+
+# Test ignored: runs for hours and eats up 7 Gigabytes of disk space
+java/util/zip/3GBZipFiles.sh                                         generic-all
+
+############################################################################
+
+# svc_tools
+
+# 8031482
+sun/tools/jcmd/TestJcmdSanity.java				windows-all
+
+# 6456333
+sun/tools/jps/TestJpsJarRelative.java				generic-all
+
+############################################################################
+
+# 1. cannot be executed under TC against Oracle JDK
+# located at directory containing spaces in its name
+# 2. it requires jar which does not exist in our OpenJDK builds
+# 3.
+javax/imageio/stream/StreamCloserLeak/run_test.sh                    generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8011371
+sun/awt/datatransfer/SuplementaryCharactersTransferTest.java         generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8142540
+sun/awt/dnd/8024061/bug8024061.java                                  linux-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8042098
+sun/java2d/AcceleratedXORModeTest.java                               windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8022403
+sun/java2d/DirectX/OnScreenRenderingResizeTest/OnScreenRenderingResizeTest.java macosx-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7148533
+sun/java2d/DirectX/OverriddenInsetsTest/OverriddenInsetsTest.java    generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8031433
+sun/java2d/OpenGL/GradientPaints.java                                generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8144033
+sun/java2d/DirectX/RenderingToCachedGraphicsTest/RenderingToCachedGraphicsTest.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8047703
+sun/java2d/SunGraphics2D/DrawImageBilinear.java                      generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-6258137
+# https://bugs.openjdk.java.net/browse/JDK-6986565
+sun/java2d/SunGraphics2D/PolyVertTest.java                           generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7124403
+# https://bugs.openjdk.java.net/browse/JDK-6992007
+sun/java2d/SunGraphics2D/SimplePrimQuality.java                      generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8159142
+sun/java2d/SunGraphics2D/SourceClippingBlitTest/SourceClippingBlitTest.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7184899
+# it blocks jtreg on Windows
+sun/java2d/X11SurfaceData/SharedMemoryPixmapsTest/SharedMemoryPixmapsTest.sh generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8171303
+sun/java2d/pipe/InterpolationQualityTest.java                        generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8046046
+sun/security/pkcs11/Signature/TestDSAKeyLength.java                  generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8142541
+sun/security/pkcs11/ec/TestECDH.java                                 linux-all
+sun/security/pkcs11/ec/TestECDSA.java                                linux-all
+sun/security/pkcs11/ec/TestECGenSpec.java                            linux-all
+
+# https://bugs.openjdk.java.net/browse/JDK-7057022
+sun/security/pkcs11/fips/ClientJSSEServerJSSE.java                   generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8160071
+sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java                 generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8039280
+sun/security/provider/PolicyFile/GrantAllPermToExtWhenNoPolicy.java  generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8033271
+sun/security/provider/PolicyParser/ExtDirs.java                      generic-all
+sun/security/provider/PolicyParser/ExtDirsChange.java                generic-all
+sun/security/provider/PolicyParser/ExtDirsDefaultPolicy.java         generic-all
+sun/security/provider/PolicyParser/PrincipalExpansionError.java      generic-all
+sun/security/tools/keytool/i18n.sh                                   generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8130151
+sun/security/provider/SecureRandom/StrongSecureRandom.java           macosx-all
+
+## https://bugs.openjdk.java.net/browse/JDK-7083664
+#sun/security/tools/jarsigner/diffend.sh                              windows-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8011134
+sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/ClientServer.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8039130
+sun/security/ssl/javax/net/ssl/NewAPIs/CheckMyTrustedKeystore.java   generic-all
+sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/Basics.java         generic-all
+sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/TestAllSuites.java  generic-all
+sun/security/ssl/sanity/ciphersuites/CheckCipherSuites.java          generic-all
+sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/CloseKeepAliveCached.java generic-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8171489
+sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/B6216082.java linux-all
+
+# https://bugs.openjdk.java.net/browse/JDK-8160624
+sun/security/tools/keytool/printssl.sh                               windows-all
+
+# expected failure on JBRE
+sun/misc/Version/Version.java                                        generic-all
+
+# https://youtrack.jetbrains.com/issue/JRE-128
+java/awt/image/multiresolution/MultiDisplayTest/MultiDisplayTest.java                           generic-all
+java/awt/image/multiresolution/MultiResolutionIcon/IconTest.java                                generic-all
+java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java     generic-all
+java/awt/image/multiresolution/BaseMultiResolutionImageTest.java                                generic-all
+java/awt/image/multiresolution/Corrupted2XImageTest.java                                        generic-all
+java/awt/image/multiresolution/MenuMultiresolutionIconTest.java                                 generic-all
+java/awt/image/multiresolution/MultiResolutionIcon/MultiResIconTest.java                        generic-all
+java/awt/image/multiresolution/MultiResolutionCachedImageTest.java                              generic-all
+java/awt/image/multiresolution/MultiresolutionIconTest.java                                     generic-all
+java/awt/image/multiresolution/MultiResolutionImagePropertiesTest.java                          generic-all
+java/awt/image/multiresolution/MultiResolutionJOptionPaneIconTest.java                          generic-all
+java/awt/image/multiresolution/MultiResolutionRenderingHintsTest.java                           generic-all
+java/awt/image/multiresolution/MultiresolutionSourceTest.java                                   generic-all
+java/awt/image/multiresolution/MultiResolutionToolkitImageTest.java                             generic-all
+java/awt/image/multiresolution/MultiResolutionImageObserverTest.java                            gereric-all
+java/awt/image/multiresolution/MultiResolutionDrawImageWithTransformTest.java                   gereric-all
+java/awt/image/MultiResolutionImage/MultiResolutionDisabledImageTest.java                       generic-all
+java/awt/image/MultiResolutionImage/MultiResolutionDrawImageWithTransformTest.java              generic-all
+java/awt/image/MultiResolutionImage/NSImageToMultiResolutionImageTest.java                      generic-all
+java/awt/image/MultiResolutionImageCommonTest.java                                              generic-all
+java/awt/image/MultiResolutionImageTest.java                                                    generic-all
+
+# ignored
+# Uses certutil.exe that isn't guaranteed to be installed
+sun/security/mscapi/nonUniqueAliases/NonUniqueAliases.sh                                        generic-all
\ No newline at end of file
diff --git a/test/regtests.iml b/test/regtests.iml
new file mode 100644
index 0000000..39c5723
--- /dev/null
+++ b/test/regtests.iml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$/../idea/java/tests/src">
+      <sourceFolder url="file://$MODULE_DIR$/../idea/java/tests/src" isTestSource="false" />
+    </content>
+    <content url="file://$MODULE_DIR$/sun/java2d">
+      <sourceFolder url="file://$MODULE_DIR$/sun/java2d" isTestSource="false" />
+    </content>
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="macosx" />
+    <orderEntry type="inheritedJdk" />
+  </component>
+</module>
\ No newline at end of file