[Usp10] - Sync to Wine 1.3.37.
authorJames Tabor <james.tabor@reactos.org>
Thu, 26 Jan 2012 15:07:46 +0000 (15:07 +0000)
committerJames Tabor <james.tabor@reactos.org>
Thu, 26 Jan 2012 15:07:46 +0000 (15:07 +0000)
svn path=/trunk/; revision=55201

reactos/dll/win32/usp10/CMakeLists.txt
reactos/dll/win32/usp10/opentype.c [new file with mode: 0644]
reactos/dll/win32/usp10/shape.c
reactos/dll/win32/usp10/usp10.c
reactos/dll/win32/usp10/usp10.rbuild
reactos/dll/win32/usp10/usp10.spec
reactos/dll/win32/usp10/usp10_internal.h

index 6d2ac1d..e073295 100644 (file)
@@ -12,6 +12,7 @@ list(APPEND SOURCE
     linebreak.c
     usp10.c
     mirror.c
+    opentype.c
     shape.c
     shaping.c
     ${CMAKE_CURRENT_BINARY_DIR}/usp10_stubs.c
diff --git a/reactos/dll/win32/usp10/opentype.c b/reactos/dll/win32/usp10/opentype.c
new file mode 100644 (file)
index 0000000..c30d513
--- /dev/null
@@ -0,0 +1,1117 @@
+/*
+ * Opentype font interfaces for the Uniscribe Script Processor (usp10.dll)
+ *
+ * Copyright 2012 CodeWeavers, Aric Stewart
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "usp10.h"
+#include "winternl.h"
+
+#include "usp10_internal.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
+
+#ifdef WORDS_BIGENDIAN
+#define GET_BE_WORD(x) (x)
+#define GET_BE_DWORD(x) (x)
+#else
+#define GET_BE_WORD(x) RtlUshortByteSwap(x)
+#define GET_BE_DWORD(x) RtlUlongByteSwap(x)
+#endif
+
+/* These are all structures needed for the cmap format 12 table */
+#define CMAP_TAG MS_MAKE_TAG('c', 'm', 'a', 'p')
+
+typedef struct {
+    WORD platformID;
+    WORD encodingID;
+    DWORD offset;
+} CMAP_EncodingRecord;
+
+typedef struct {
+    WORD version;
+    WORD numTables;
+    CMAP_EncodingRecord tables[1];
+} CMAP_Header;
+
+typedef struct {
+    DWORD startCharCode;
+    DWORD endCharCode;
+    DWORD startGlyphID;
+} CMAP_SegmentedCoverage_group;
+
+typedef struct {
+    WORD format;
+    WORD reserved;
+    DWORD length;
+    DWORD language;
+    DWORD nGroups;
+    CMAP_SegmentedCoverage_group groups[1];
+} CMAP_SegmentedCoverage;
+
+/* These are all structures needed for the GDEF table */
+#define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
+
+enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
+
+typedef struct {
+    DWORD Version;
+    WORD GlyphClassDef;
+    WORD AttachList;
+    WORD LigCaretList;
+    WORD MarkAttachClassDef;
+} GDEF_Header;
+
+typedef struct {
+    WORD ClassFormat;
+    WORD StartGlyph;
+    WORD GlyphCount;
+    WORD ClassValueArray[1];
+} GDEF_ClassDefFormat1;
+
+typedef struct {
+    WORD Start;
+    WORD End;
+    WORD Class;
+} GDEF_ClassRangeRecord;
+
+typedef struct {
+    WORD ClassFormat;
+    WORD ClassRangeCount;
+    GDEF_ClassRangeRecord ClassRangeRecord[1];
+} GDEF_ClassDefFormat2;
+
+/* These are all structures needed for the GSUB table */
+
+typedef struct {
+    DWORD version;
+    WORD ScriptList;
+    WORD FeatureList;
+    WORD LookupList;
+} GSUB_Header;
+
+typedef struct {
+    CHAR ScriptTag[4];
+    WORD Script;
+} GSUB_ScriptRecord;
+
+typedef struct {
+    WORD ScriptCount;
+    GSUB_ScriptRecord ScriptRecord[1];
+} GSUB_ScriptList;
+
+typedef struct {
+    CHAR LangSysTag[4];
+    WORD LangSys;
+} GSUB_LangSysRecord;
+
+typedef struct {
+    WORD DefaultLangSys;
+    WORD LangSysCount;
+    GSUB_LangSysRecord LangSysRecord[1];
+} GSUB_Script;
+
+typedef struct {
+    WORD LookupOrder; /* Reserved */
+    WORD ReqFeatureIndex;
+    WORD FeatureCount;
+    WORD FeatureIndex[1];
+} GSUB_LangSys;
+
+typedef struct {
+    CHAR FeatureTag[4];
+    WORD Feature;
+} GSUB_FeatureRecord;
+
+typedef struct {
+    WORD FeatureCount;
+    GSUB_FeatureRecord FeatureRecord[1];
+} GSUB_FeatureList;
+
+typedef struct {
+    WORD FeatureParams; /* Reserved */
+    WORD LookupCount;
+    WORD LookupListIndex[1];
+} GSUB_Feature;
+
+typedef struct {
+    WORD LookupCount;
+    WORD Lookup[1];
+} GSUB_LookupList;
+
+typedef struct {
+    WORD LookupType;
+    WORD LookupFlag;
+    WORD SubTableCount;
+    WORD SubTable[1];
+} GSUB_LookupTable;
+
+typedef struct {
+    WORD CoverageFormat;
+    WORD GlyphCount;
+    WORD GlyphArray[1];
+} GSUB_CoverageFormat1;
+
+typedef struct {
+    WORD Start;
+    WORD End;
+    WORD StartCoverageIndex;
+} GSUB_RangeRecord;
+
+typedef struct {
+    WORD CoverageFormat;
+    WORD RangeCount;
+    GSUB_RangeRecord RangeRecord[1];
+} GSUB_CoverageFormat2;
+
+typedef struct {
+    WORD SubstFormat; /* = 1 */
+    WORD Coverage;
+    WORD DeltaGlyphID;
+} GSUB_SingleSubstFormat1;
+
+typedef struct {
+    WORD SubstFormat; /* = 2 */
+    WORD Coverage;
+    WORD GlyphCount;
+    WORD Substitute[1];
+}GSUB_SingleSubstFormat2;
+
+typedef struct {
+    WORD SubstFormat; /* = 1 */
+    WORD Coverage;
+    WORD SequenceCount;
+    WORD Sequence[1];
+}GSUB_MultipleSubstFormat1;
+
+typedef struct {
+    WORD GlyphCount;
+    WORD Substitute[1];
+}GSUB_Sequence;
+
+typedef struct {
+    WORD SubstFormat; /* = 1 */
+    WORD Coverage;
+    WORD LigSetCount;
+    WORD LigatureSet[1];
+}GSUB_LigatureSubstFormat1;
+
+typedef struct {
+    WORD LigatureCount;
+    WORD Ligature[1];
+}GSUB_LigatureSet;
+
+typedef struct{
+    WORD LigGlyph;
+    WORD CompCount;
+    WORD Component[1];
+}GSUB_Ligature;
+
+typedef struct{
+    WORD SequenceIndex;
+    WORD LookupListIndex;
+
+}GSUB_SubstLookupRecord;
+
+typedef struct{
+    WORD SubstFormat; /* = 1 */
+    WORD Coverage;
+    WORD ChainSubRuleSetCount;
+    WORD ChainSubRuleSet[1];
+}GSUB_ChainContextSubstFormat1;
+
+typedef struct {
+    WORD SubstFormat; /* = 3 */
+    WORD BacktrackGlyphCount;
+    WORD Coverage[1];
+}GSUB_ChainContextSubstFormat3_1;
+
+typedef struct{
+    WORD InputGlyphCount;
+    WORD Coverage[1];
+}GSUB_ChainContextSubstFormat3_2;
+
+typedef struct{
+    WORD LookaheadGlyphCount;
+    WORD Coverage[1];
+}GSUB_ChainContextSubstFormat3_3;
+
+typedef struct{
+    WORD SubstCount;
+    GSUB_SubstLookupRecord SubstLookupRecord[1];
+}GSUB_ChainContextSubstFormat3_4;
+
+typedef struct {
+    WORD SubstFormat; /* = 1 */
+    WORD Coverage;
+    WORD AlternateSetCount;
+    WORD AlternateSet[1];
+} GSUB_AlternateSubstFormat1;
+
+typedef struct{
+    WORD GlyphCount;
+    WORD Alternate[1];
+} GSUB_AlternateSet;
+
+/**********
+ * CMAP
+ **********/
+
+static VOID *load_CMAP_format12_table(HDC hdc, ScriptCache *psc)
+{
+    CMAP_Header *CMAP_Table = NULL;
+    int length;
+    int i;
+
+    if (!psc->CMAP_Table)
+    {
+        length = GetFontData(hdc, CMAP_TAG , 0, NULL, 0);
+        if (length != GDI_ERROR)
+        {
+            psc->CMAP_Table = HeapAlloc(GetProcessHeap(),0,length);
+            GetFontData(hdc, CMAP_TAG , 0, psc->CMAP_Table, length);
+            TRACE("Loaded cmap table of %i bytes\n",length);
+        }
+        else
+            return NULL;
+    }
+
+    CMAP_Table = psc->CMAP_Table;
+
+    for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++)
+    {
+        if ( (GET_BE_WORD(CMAP_Table->tables[i].platformID) == 3) &&
+             (GET_BE_WORD(CMAP_Table->tables[i].encodingID) == 10) )
+        {
+            CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
+            if (GET_BE_WORD(format->format) == 12)
+                return format;
+        }
+    }
+    return NULL;
+}
+
+static int compare_group(const void *a, const void* b)
+{
+    const DWORD *chr = a;
+    const CMAP_SegmentedCoverage_group *group = b;
+
+    if (*chr < GET_BE_DWORD(group->startCharCode))
+        return -1;
+    if (*chr > GET_BE_DWORD(group->endCharCode))
+        return 1;
+    return 0;
+}
+
+DWORD OpenType_CMAP_GetGlyphIndex(HDC hdc, ScriptCache *psc, DWORD utf32c, LPWORD pgi, DWORD flags)
+{
+    /* BMP: use gdi32 for ease */
+    if (utf32c < 0x10000)
+    {
+        WCHAR ch = utf32c;
+        return GetGlyphIndicesW(hdc,&ch, 1, pgi, flags);
+    }
+
+    if (!psc->CMAP_format12_Table)
+        psc->CMAP_format12_Table = load_CMAP_format12_table(hdc, psc);
+
+    if (flags & GGI_MARK_NONEXISTING_GLYPHS)
+        *pgi = 0xffff;
+    else
+        *pgi = 0;
+
+    if (psc->CMAP_format12_Table)
+    {
+        CMAP_SegmentedCoverage *format = NULL;
+        CMAP_SegmentedCoverage_group *group = NULL;
+
+        format = (CMAP_SegmentedCoverage *)psc->CMAP_format12_Table;
+
+        group = bsearch(&utf32c, format->groups, GET_BE_DWORD(format->nGroups),
+                        sizeof(CMAP_SegmentedCoverage_group), compare_group);
+
+        if (group)
+        {
+            DWORD offset = utf32c - GET_BE_DWORD(group->startCharCode);
+            *pgi = GET_BE_DWORD(group->startGlyphID) + offset;
+            return 0;
+        }
+    }
+    return 0;
+}
+
+/**********
+ * GDEF
+ **********/
+
+static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
+{
+    int offset;
+    WORD class = 0;
+    const GDEF_ClassDefFormat1 *cf1;
+
+    if (!header)
+        return 0;
+
+    offset = GET_BE_WORD(header->GlyphClassDef);
+    if (!offset)
+        return 0;
+
+    cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
+    if (GET_BE_WORD(cf1->ClassFormat) == 1)
+    {
+        if (glyph >= GET_BE_WORD(cf1->StartGlyph))
+        {
+            int index = glyph - GET_BE_WORD(cf1->StartGlyph);
+            if (index < GET_BE_WORD(cf1->GlyphCount))
+                class = GET_BE_WORD(cf1->ClassValueArray[index]);
+        }
+    }
+    else if (GET_BE_WORD(cf1->ClassFormat) == 2)
+    {
+        const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
+        int i, top;
+        top = GET_BE_WORD(cf2->ClassRangeCount);
+        for (i = 0; i < top; i++)
+        {
+            if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
+                glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
+            {
+                class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
+                break;
+            }
+        }
+    }
+    else
+        ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
+
+    return class;
+}
+
+static VOID *load_gdef_table(HDC hdc)
+{
+    VOID* GDEF_Table = NULL;
+    int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
+    if (length != GDI_ERROR)
+    {
+        GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
+        GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
+        TRACE("Loaded GDEF table of %i bytes\n",length);
+    }
+    return GDEF_Table;
+}
+
+void OpenType_GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
+{
+    int i;
+
+    if (!psc->GDEF_Table)
+        psc->GDEF_Table = load_gdef_table(hdc);
+
+    for (i = 0; i < cGlyphs; i++)
+    {
+        WORD class;
+        int char_count = 0;
+        int k;
+
+        for (k = 0; k < cChars; k++)
+            if (pwLogClust[k] == i)
+                char_count++;
+
+        class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
+
+        switch (class)
+        {
+            case 0:
+            case BaseGlyph:
+                pGlyphProp[i].sva.fClusterStart = 1;
+                pGlyphProp[i].sva.fDiacritic = 0;
+                pGlyphProp[i].sva.fZeroWidth = 0;
+                break;
+            case LigatureGlyph:
+                pGlyphProp[i].sva.fClusterStart = 1;
+                pGlyphProp[i].sva.fDiacritic = 0;
+                pGlyphProp[i].sva.fZeroWidth = 0;
+                break;
+            case MarkGlyph:
+                pGlyphProp[i].sva.fClusterStart = 0;
+                pGlyphProp[i].sva.fDiacritic = 1;
+                pGlyphProp[i].sva.fZeroWidth = 1;
+                break;
+            case ComponentGlyph:
+                pGlyphProp[i].sva.fClusterStart = 0;
+                pGlyphProp[i].sva.fDiacritic = 0;
+                pGlyphProp[i].sva.fZeroWidth = 0;
+                break;
+            default:
+                ERR("Unknown glyph class %i\n",class);
+                pGlyphProp[i].sva.fClusterStart = 1;
+                pGlyphProp[i].sva.fDiacritic = 0;
+                pGlyphProp[i].sva.fZeroWidth = 0;
+        }
+
+        if (char_count == 0)
+            pGlyphProp[i].sva.fClusterStart = 0;
+    }
+}
+
+/**********
+ * GSUB
+ **********/
+static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
+
+static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
+{
+    const GSUB_CoverageFormat1* cf1;
+
+    cf1 = table;
+
+    if (GET_BE_WORD(cf1->CoverageFormat) == 1)
+    {
+        int count = GET_BE_WORD(cf1->GlyphCount);
+        int i;
+        TRACE("Coverage Format 1, %i glyphs\n",count);
+        for (i = 0; i < count; i++)
+            if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
+                return i;
+        return -1;
+    }
+    else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
+    {
+        const GSUB_CoverageFormat2* cf2;
+        int i;
+        int count;
+        cf2 = (const GSUB_CoverageFormat2*)cf1;
+
+        count = GET_BE_WORD(cf2->RangeCount);
+        TRACE("Coverage Format 2, %i ranges\n",count);
+        for (i = 0; i < count; i++)
+        {
+            if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
+                return -1;
+            if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
+                (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
+            {
+                return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
+                    glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
+            }
+        }
+        return -1;
+    }
+    else
+        ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
+
+    return -1;
+}
+
+static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+{
+    int j;
+    TRACE("Single Substitution Subtable\n");
+
+    for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
+    {
+        int offset;
+        const GSUB_SingleSubstFormat1 *ssf1;
+        offset = GET_BE_WORD(look->SubTable[j]);
+        ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
+        if (GET_BE_WORD(ssf1->SubstFormat) == 1)
+        {
+            int offset = GET_BE_WORD(ssf1->Coverage);
+            TRACE("  subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
+            if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
+            {
+                TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
+                glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
+                TRACE(" 0x%x\n",glyphs[glyph_index]);
+                return glyph_index + write_dir;
+            }
+        }
+        else
+        {
+            const GSUB_SingleSubstFormat2 *ssf2;
+            INT index;
+            INT offset;
+
+            ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
+            offset = GET_BE_WORD(ssf1->Coverage);
+            TRACE("  subtype 2,  glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
+            index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
+            TRACE("  Coverage index %i\n",index);
+            if (index != -1)
+            {
+                if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
+                    return GSUB_E_NOGLYPH;
+
+                TRACE("    Glyph is 0x%x ->",glyphs[glyph_index]);
+                glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
+                TRACE("0x%x\n",glyphs[glyph_index]);
+                return glyph_index + write_dir;
+            }
+        }
+    }
+    return GSUB_E_NOGLYPH;
+}
+
+static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+{
+    int j;
+    TRACE("Multiple Substitution Subtable\n");
+
+    for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
+    {
+        int offset, index;
+        const GSUB_MultipleSubstFormat1 *msf1;
+        offset = GET_BE_WORD(look->SubTable[j]);
+        msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
+
+        offset = GET_BE_WORD(msf1->Coverage);
+        index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
+        if (index != -1)
+        {
+            const GSUB_Sequence *seq;
+            int sub_count;
+            int j;
+            offset = GET_BE_WORD(msf1->Sequence[index]);
+            seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
+            sub_count = GET_BE_WORD(seq->GlyphCount);
+            TRACE("  Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
+
+            for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
+                    glyphs[j] =glyphs[j-(sub_count-1)];
+
+            for (j = 0; j < sub_count; j++)
+                    if (write_dir < 0)
+                        glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
+                    else
+                        glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
+
+            *glyph_count = *glyph_count + (sub_count - 1);
+
+            if (TRACE_ON(uniscribe))
+            {
+                for (j = 0; j < sub_count; j++)
+                    TRACE(" 0x%x",glyphs[glyph_index+j]);
+                TRACE("\n");
+            }
+
+            return glyph_index + (sub_count * write_dir);
+        }
+    }
+    return GSUB_E_NOGLYPH;
+}
+
+static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+{
+    int j;
+    TRACE("Alternate Substitution Subtable\n");
+
+    for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
+    {
+        int offset;
+        const GSUB_AlternateSubstFormat1 *asf1;
+        INT index;
+
+        offset = GET_BE_WORD(look->SubTable[j]);
+        asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
+        offset = GET_BE_WORD(asf1->Coverage);
+
+        index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
+        if (index != -1)
+        {
+            const GSUB_AlternateSet *as;
+            offset =  GET_BE_WORD(asf1->AlternateSet[index]);
+            as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
+            FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
+            if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
+                return GSUB_E_NOGLYPH;
+
+            TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
+            glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
+            TRACE(" 0x%x\n",glyphs[glyph_index]);
+            return glyph_index + write_dir;
+        }
+    }
+    return GSUB_E_NOGLYPH;
+}
+
+static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+{
+    int j;
+
+    TRACE("Ligature Substitution Subtable\n");
+    for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
+    {
+        const GSUB_LigatureSubstFormat1 *lsf1;
+        int offset,index;
+
+        offset = GET_BE_WORD(look->SubTable[j]);
+        lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
+        offset = GET_BE_WORD(lsf1->Coverage);
+        index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
+        TRACE("  Coverage index %i\n",index);
+        if (index != -1)
+        {
+            const GSUB_LigatureSet *ls;
+            int k, count;
+
+            offset = GET_BE_WORD(lsf1->LigatureSet[index]);
+            ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
+            count = GET_BE_WORD(ls->LigatureCount);
+            TRACE("  LigatureSet has %i members\n",count);
+            for (k = 0; k < count; k++)
+            {
+                const GSUB_Ligature *lig;
+                int CompCount,l,CompIndex;
+
+                offset = GET_BE_WORD(ls->Ligature[k]);
+                lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
+                CompCount = GET_BE_WORD(lig->CompCount) - 1;
+                CompIndex = glyph_index+write_dir;
+                for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
+                {
+                    int CompGlyph;
+                    CompGlyph = GET_BE_WORD(lig->Component[l]);
+                    if (CompGlyph != glyphs[CompIndex])
+                        break;
+                    CompIndex += write_dir;
+                }
+                if (l == CompCount)
+                {
+                    int replaceIdx = glyph_index;
+                    if (write_dir < 0)
+                        replaceIdx = glyph_index - CompCount;
+
+                    TRACE("    Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
+                    glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
+                    TRACE("0x%x\n",glyphs[replaceIdx]);
+                    if (CompCount > 0)
+                    {
+                        int j;
+                        for (j = replaceIdx + 1; j < *glyph_count; j++)
+                            glyphs[j] =glyphs[j+CompCount];
+                        *glyph_count = *glyph_count - CompCount;
+                    }
+                    return replaceIdx + write_dir;
+                }
+            }
+        }
+    }
+    return GSUB_E_NOGLYPH;
+}
+
+static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+{
+    int j;
+    BOOL done = FALSE;
+
+    TRACE("Chaining Contextual Substitution Subtable\n");
+    for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
+    {
+        const GSUB_ChainContextSubstFormat1 *ccsf1;
+        int offset;
+        int dirLookahead = write_dir;
+        int dirBacktrack = -1 * write_dir;
+
+        offset = GET_BE_WORD(look->SubTable[j]);
+        ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
+        if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
+        {
+            FIXME("  TODO: subtype 1 (Simple context glyph substitution)\n");
+            continue;
+        }
+        else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
+        {
+            FIXME("  TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
+            continue;
+        }
+        else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
+        {
+            int k;
+            int indexGlyphs;
+            const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
+            const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
+            const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
+            const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
+            int newIndex = glyph_index;
+
+            ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
+
+            TRACE("  subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
+
+            for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
+            {
+                offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
+                if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
+                    break;
+            }
+            if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
+                continue;
+            TRACE("Matched Backtrack\n");
+
+            ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
+
+            indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
+            for (k = 0; k < indexGlyphs; k++)
+            {
+                offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
+                if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
+                    break;
+            }
+            if (k != indexGlyphs)
+                continue;
+            TRACE("Matched IndexGlyphs\n");
+
+            ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
+
+            for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
+            {
+                offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
+                if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
+                    break;
+            }
+            if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
+                continue;
+            TRACE("Matched LookAhead\n");
+
+            ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
+
+            if (GET_BE_WORD(ccsf3_4->SubstCount))
+            {
+                for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
+                {
+                    int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
+                    int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
+
+                    TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
+                    newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
+                    if (newIndex == -1)
+                    {
+                        ERR("Chain failed to generate a glyph\n");
+                        continue;
+                    }
+                }
+                return newIndex;
+            }
+            else return GSUB_E_NOGLYPH;
+        }
+    }
+    return -1;
+}
+
+static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+{
+    int offset;
+    const GSUB_LookupTable *look;
+
+    offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
+    look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
+    TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
+    switch(GET_BE_WORD(look->LookupType))
+    {
+        case 1:
+            return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
+        case 2:
+            return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
+        case 3:
+            return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
+        case 4:
+            return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
+        case 6:
+            return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
+        default:
+            FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
+    }
+    return GSUB_E_NOGLYPH;
+}
+
+INT OpenType_apply_GSUB_lookup(LPCVOID table, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+{
+    const GSUB_Header *header = (const GSUB_Header *)table;
+    const GSUB_LookupList *lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
+
+    return GSUB_apply_lookup(lookup, lookup_index, glyphs, glyph_index, write_dir, glyph_count);
+}
+
+static void GSUB_initialize_script_cache(ScriptCache *psc)
+{
+    int i;
+
+    if (!psc->script_count)
+    {
+        const GSUB_ScriptList *script;
+        const GSUB_Header* header = (const GSUB_Header*)psc->GSUB_Table;
+        script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
+        psc->script_count = GET_BE_WORD(script->ScriptCount);
+        TRACE("initializing %i scripts in this font\n",psc->script_count);
+        psc->scripts = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LoadedScript) * psc->script_count);
+        for (i = 0; i < psc->script_count; i++)
+        {
+            int offset = GET_BE_WORD(script->ScriptRecord[i].Script);
+            psc->scripts[i].tag = MS_MAKE_TAG(script->ScriptRecord[i].ScriptTag[0], script->ScriptRecord[i].ScriptTag[1], script->ScriptRecord[i].ScriptTag[2], script->ScriptRecord[i].ScriptTag[3]);
+            psc->scripts[i].table = ((const BYTE*)script + offset);
+        }
+    }
+}
+
+HRESULT OpenType_GSUB_GetFontScriptTags(ScriptCache *psc, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags, LPCVOID* script_table)
+{
+    int i;
+    HRESULT rc = S_OK;
+
+    GSUB_initialize_script_cache(psc);
+    *pcTags = psc->script_count;
+
+    if (!searchingFor && cMaxTags < *pcTags)
+        rc = E_OUTOFMEMORY;
+    else if (searchingFor)
+        rc = USP_E_SCRIPT_NOT_IN_FONT;
+
+    for (i = 0; i < psc->script_count; i++)
+    {
+        if (i < cMaxTags)
+            pScriptTags[i] = psc->scripts[i].tag;
+
+        if (searchingFor)
+        {
+            if (searchingFor == psc->scripts[i].tag)
+            {
+                pScriptTags[0] = psc->scripts[i].tag;
+                *pcTags = 1;
+                if (script_table)
+                    *script_table = psc->scripts[i].table;
+                rc = S_OK;
+                break;
+            }
+        }
+    }
+    return rc;
+}
+
+static void GSUB_initialize_language_cache(LoadedScript *script)
+{
+    int i;
+
+    if (!script->language_count)
+    {
+        const GSUB_Script* table = script->table;
+        script->language_count = GET_BE_WORD(table->LangSysCount);
+        script->default_language.tag = MS_MAKE_TAG('d','f','l','t');
+        script->default_language.table = (const BYTE*)table + GET_BE_WORD(table->DefaultLangSys);
+
+        TRACE("Deflang %p, LangCount %i\n",script->default_language.table, script->language_count);
+
+        script->languages = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LoadedLanguage) * script->language_count);
+
+        for (i = 0; i < script->language_count; i++)
+        {
+            int offset = GET_BE_WORD(table->LangSysRecord[i].LangSys);
+            script->languages[i].tag = MS_MAKE_TAG(table->LangSysRecord[i].LangSysTag[0], table->LangSysRecord[i].LangSysTag[1], table->LangSysRecord[i].LangSysTag[2], table->LangSysRecord[i].LangSysTag[3]);
+            script->languages[i].table = ((const BYTE*)table + offset);
+        }
+    }
+}
+
+HRESULT OpenType_GSUB_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pLanguageTags, int *pcTags, LPCVOID* language_table)
+{
+    int i;
+    HRESULT rc = S_OK;
+    LoadedScript *script = NULL;
+
+    GSUB_initialize_script_cache(psc);
+
+    for (i = 0; i < psc->script_count; i++)
+    {
+         if (psc->scripts[i].tag == script_tag)
+         {
+            script = &psc->scripts[i];
+            break;
+         }
+    }
+
+    if (!script)
+        return E_INVALIDARG;
+
+    GSUB_initialize_language_cache(script);
+
+    if (!searchingFor && cMaxTags < script->language_count)
+        rc = E_OUTOFMEMORY;
+    else if (searchingFor)
+        rc = E_INVALIDARG;
+
+    *pcTags = script->language_count;
+
+    for (i = 0; i < script->language_count; i++)
+    {
+        if (i < cMaxTags)
+            pLanguageTags[i] = script->languages[i].tag;
+
+        if (searchingFor)
+        {
+            if (searchingFor == script->languages[i].tag)
+            {
+                pLanguageTags[0] = script->languages[i].tag;
+                *pcTags = 1;
+                if (language_table)
+                    *language_table = script->languages[i].table;
+                rc = S_OK;
+                break;
+            }
+        }
+    }
+
+    if (script->default_language.table)
+    {
+        if (i < cMaxTags)
+            pLanguageTags[i] = script->default_language.tag;
+
+        if (searchingFor  && FAILED(rc))
+        {
+            pLanguageTags[0] = script->default_language.tag;
+            if (language_table)
+                *language_table = script->default_language.table;
+        }
+        i++;
+        *pcTags = (*pcTags) + 1;
+    }
+
+    return rc;
+}
+
+
+static void GSUB_initialize_feature_cache(LPCVOID table, LoadedLanguage *language)
+{
+    int i;
+
+    if (!language->feature_count)
+    {
+        const GSUB_LangSys *lang= language->table;
+        const GSUB_Header *header = (const GSUB_Header *)table;
+        const GSUB_FeatureList *feature_list;
+
+        language->feature_count = GET_BE_WORD(lang->FeatureCount);
+        TRACE("%i features\n",language->feature_count);
+
+        language->features = HeapAlloc(GetProcessHeap(),0,sizeof(LoadedFeature)*language->feature_count);
+
+        feature_list = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
+
+        for (i = 0; i < language->feature_count; i++)
+        {
+            const GSUB_Feature *feature;
+            int j;
+            int index = GET_BE_WORD(lang->FeatureIndex[i]);
+
+            language->features[i].tag = MS_MAKE_TAG(feature_list->FeatureRecord[index].FeatureTag[0], feature_list->FeatureRecord[index].FeatureTag[1], feature_list->FeatureRecord[index].FeatureTag[2], feature_list->FeatureRecord[index].FeatureTag[3]);
+            language->features[i].feature = ((const BYTE*)feature_list + GET_BE_WORD(feature_list->FeatureRecord[index].Feature));
+            feature = (const GSUB_Feature*)language->features[i].feature;
+            language->features[i].lookup_count = GET_BE_WORD(feature->LookupCount);
+            language->features[i].lookups = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * language->features[i].lookup_count);
+            for (j = 0; j < language->features[i].lookup_count; j++)
+                language->features[i].lookups[j] = GET_BE_WORD(feature->LookupListIndex[j]);
+        }
+    }
+}
+
+HRESULT OpenType_GSUB_GetFontFeatureTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG language_tag, BOOL filtered, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags, LoadedFeature** feature)
+{
+    int i;
+    HRESULT rc = S_OK;
+    LoadedScript *script = NULL;
+    LoadedLanguage *language = NULL;
+
+    GSUB_initialize_script_cache(psc);
+
+    for (i = 0; i < psc->script_count; i++)
+    {
+        if (psc->scripts[i].tag == script_tag)
+        {
+            script = &psc->scripts[i];
+            break;
+        }
+    }
+
+    if (!script)
+    {
+        *pcTags = 0;
+        if (!filtered)
+            return S_OK;
+        else
+            return E_INVALIDARG;
+    }
+
+    GSUB_initialize_language_cache(script);
+
+    if (script->default_language.table && script->default_language.tag == language_tag)
+        language = &script->default_language;
+    else
+    {
+        for (i = 0; i < script->language_count; i++)
+        {
+            if (script->languages[i].tag == language_tag)
+            {
+                language = &script->languages[i];
+                break;
+            }
+        }
+    }
+
+    if (!language)
+    {
+        *pcTags = 0;
+        return S_OK;
+    }
+
+    GSUB_initialize_feature_cache(psc->GSUB_Table, language);
+
+    *pcTags = language->feature_count;
+
+    if (!searchingFor && cMaxTags < *pcTags)
+        rc = E_OUTOFMEMORY;
+    else if (searchingFor)
+        rc = E_INVALIDARG;
+
+    for (i = 0; i < language->feature_count; i++)
+    {
+        if (i < cMaxTags)
+            pFeatureTags[i] = language->features[i].tag;
+
+        if (searchingFor)
+        {
+            if (searchingFor == language->features[i].tag)
+            {
+                pFeatureTags[0] = language->features[i].tag;
+                *pcTags = 1;
+                if (feature)
+                    *feature = &language->features[i];
+                rc = S_OK;
+                break;
+            }
+        }
+    }
+    return rc;
+}
index 8d3a355..5f71d6c 100644 (file)
@@ -19,6 +19,7 @@
  *
  */
 #include <stdarg.h>
+#include <stdlib.h>
 
 #include "windef.h"
 #include "winbase.h"
@@ -53,6 +54,8 @@ static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *ps
 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
+static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
+static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
 
 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
 
@@ -71,6 +74,7 @@ static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
 static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
 static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
+static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
 
 extern const unsigned short indic_syllabic_table[];
 extern const unsigned short wine_shaping_table[];
@@ -96,221 +100,6 @@ enum joined_forms {
     Afx
 };
 
-#ifdef WORDS_BIGENDIAN
-#define GET_BE_WORD(x) (x)
-#else
-#define GET_BE_WORD(x) RtlUshortByteSwap(x)
-#endif
-
-/* These are all structures needed for the GSUB table */
-#define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
-#define GSUB_E_NOFEATURE -2
-#define GSUB_E_NOGLYPH -1
-
-typedef struct {
-    DWORD version;
-    WORD ScriptList;
-    WORD FeatureList;
-    WORD LookupList;
-} GSUB_Header;
-
-typedef struct {
-    CHAR ScriptTag[4];
-    WORD Script;
-} GSUB_ScriptRecord;
-
-typedef struct {
-    WORD ScriptCount;
-    GSUB_ScriptRecord ScriptRecord[1];
-} GSUB_ScriptList;
-
-typedef struct {
-    CHAR LangSysTag[4];
-    WORD LangSys;
-} GSUB_LangSysRecord;
-
-typedef struct {
-    WORD DefaultLangSys;
-    WORD LangSysCount;
-    GSUB_LangSysRecord LangSysRecord[1];
-} GSUB_Script;
-
-typedef struct {
-    WORD LookupOrder; /* Reserved */
-    WORD ReqFeatureIndex;
-    WORD FeatureCount;
-    WORD FeatureIndex[1];
-} GSUB_LangSys;
-
-typedef struct {
-    CHAR FeatureTag[4];
-    WORD Feature;
-} GSUB_FeatureRecord;
-
-typedef struct {
-    WORD FeatureCount;
-    GSUB_FeatureRecord FeatureRecord[1];
-} GSUB_FeatureList;
-
-typedef struct {
-    WORD FeatureParams; /* Reserved */
-    WORD LookupCount;
-    WORD LookupListIndex[1];
-} GSUB_Feature;
-
-typedef struct {
-    WORD LookupCount;
-    WORD Lookup[1];
-} GSUB_LookupList;
-
-typedef struct {
-    WORD LookupType;
-    WORD LookupFlag;
-    WORD SubTableCount;
-    WORD SubTable[1];
-} GSUB_LookupTable;
-
-typedef struct {
-    WORD CoverageFormat;
-    WORD GlyphCount;
-    WORD GlyphArray[1];
-} GSUB_CoverageFormat1;
-
-typedef struct {
-    WORD Start;
-    WORD End;
-    WORD StartCoverageIndex;
-} GSUB_RangeRecord;
-
-typedef struct {
-    WORD CoverageFormat;
-    WORD RangeCount;
-    GSUB_RangeRecord RangeRecord[1];
-} GSUB_CoverageFormat2;
-
-typedef struct {
-    WORD SubstFormat; /* = 1 */
-    WORD Coverage;
-    WORD DeltaGlyphID;
-} GSUB_SingleSubstFormat1;
-
-typedef struct {
-    WORD SubstFormat; /* = 2 */
-    WORD Coverage;
-    WORD GlyphCount;
-    WORD Substitute[1];
-}GSUB_SingleSubstFormat2;
-
-typedef struct {
-    WORD SubstFormat; /* = 1 */
-    WORD Coverage;
-    WORD SequenceCount;
-    WORD Sequence[1];
-}GSUB_MultipleSubstFormat1;
-
-typedef struct {
-    WORD GlyphCount;
-    WORD Substitute[1];
-}GSUB_Sequence;
-
-typedef struct {
-    WORD SubstFormat; /* = 1 */
-    WORD Coverage;
-    WORD LigSetCount;
-    WORD LigatureSet[1];
-}GSUB_LigatureSubstFormat1;
-
-typedef struct {
-    WORD LigatureCount;
-    WORD Ligature[1];
-}GSUB_LigatureSet;
-
-typedef struct{
-    WORD LigGlyph;
-    WORD CompCount;
-    WORD Component[1];
-}GSUB_Ligature;
-
-typedef struct{
-    WORD SequenceIndex;
-    WORD LookupListIndex;
-
-}GSUB_SubstLookupRecord;
-
-typedef struct{
-    WORD SubstFormat; /* = 1 */
-    WORD Coverage;
-    WORD ChainSubRuleSetCount;
-    WORD ChainSubRuleSet[1];
-}GSUB_ChainContextSubstFormat1;
-
-typedef struct {
-    WORD SubstFormat; /* = 3 */
-    WORD BacktrackGlyphCount;
-    WORD Coverage[1];
-}GSUB_ChainContextSubstFormat3_1;
-
-typedef struct{
-    WORD InputGlyphCount;
-    WORD Coverage[1];
-}GSUB_ChainContextSubstFormat3_2;
-
-typedef struct{
-    WORD LookaheadGlyphCount;
-    WORD Coverage[1];
-}GSUB_ChainContextSubstFormat3_3;
-
-typedef struct{
-    WORD SubstCount;
-    GSUB_SubstLookupRecord SubstLookupRecord[1];
-}GSUB_ChainContextSubstFormat3_4;
-
-typedef struct {
-    WORD SubstFormat; /* = 1 */
-    WORD Coverage;
-    WORD AlternateSetCount;
-    WORD AlternateSet[1];
-} GSUB_AlternateSubstFormat1;
-
-typedef struct{
-    WORD GlyphCount;
-    WORD Alternate[1];
-} GSUB_AlternateSet;
-
-/* These are all structures needed for the GDEF table */
-#define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
-
-enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
-
-typedef struct {
-    DWORD Version;
-    WORD GlyphClassDef;
-    WORD AttachList;
-    WORD LigCaretList;
-    WORD MarkAttachClassDef;
-} GDEF_Header;
-
-typedef struct {
-    WORD ClassFormat;
-    WORD StartGlyph;
-    WORD GlyphCount;
-    WORD ClassValueArray[1];
-} GDEF_ClassDefFormat1;
-
-typedef struct {
-    WORD Start;
-    WORD End;
-    WORD Class;
-} GDEF_ClassRangeRecord;
-
-typedef struct {
-    WORD ClassFormat;
-    WORD ClassRangeCount;
-    GDEF_ClassRangeRecord ClassRangeRecord[1];
-} GDEF_ClassDefFormat2;
-
-static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
-
 typedef struct tagVowelComponents
 {
     WCHAR base;
@@ -452,6 +241,12 @@ static OPENTYPE_FEATURE_RECORD devanagari_features[] =
     { MS_MAKE_TAG('c','a','l','t'), 1},
 };
 
+static OPENTYPE_FEATURE_RECORD myanmar_features[] =
+{
+    { MS_MAKE_TAG('l','i','g','a'), 1},
+    { MS_MAKE_TAG('c','l','i','g'), 1},
+};
+
 static const char* required_bengali_features[] =
 {
     "nukt",
@@ -539,513 +334,154 @@ static const char* required_telugu_features[] =
     NULL
 };
 
-typedef struct ScriptShapeDataTag {
-    TEXTRANGE_PROPERTIES   defaultTextRange;
-    const char**           requiredFeatures;
-    CHAR                   otTag[5];
-    CHAR                   newOtTag[5];
-    ContextualShapingProc  contextProc;
-    ShapeCharGlyphPropProc charGlyphPropProc;
-} ScriptShapeData;
-
-/* in order of scripts */
-static const ScriptShapeData ShapingData[] =
+static OPENTYPE_FEATURE_RECORD khmer_features[] =
 {
-    {{ standard_features, 2}, NULL, "", "", NULL, NULL},
-    {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
-    {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
-    {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
-    {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
-    {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
-    {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
-    {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
-    {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
-    {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
-    {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
-    {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
-    {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
-    {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
-    {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
-    {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
-    {{ sinhala_features, 3}, NULL, "sinh", "", ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
-    {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
-    {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
-    {{ phags_features, 3}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
-    {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
-    {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
-    {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
-    {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
-    {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
-    {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
-    {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
-    {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
-    {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
-    {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
-    {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
-    {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
-    {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
-    {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
-    {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
-    {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
-    {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
-    {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
-    {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
-    {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
-    {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
-    {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
-    {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
-    {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
-    {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
-    {{ latin_features, 2}, NULL, "latn" , "", NULL, NULL},
-    {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
+    { MS_MAKE_TAG('p','r','e','s'), 1},
+    { MS_MAKE_TAG('b','l','w','s'), 1},
+    { MS_MAKE_TAG('a','b','v','s'), 1},
+    { MS_MAKE_TAG('p','s','t','s'), 1},
+    { MS_MAKE_TAG('c','l','i','g'), 1},
 };
 
-static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
-{
-    const GSUB_CoverageFormat1* cf1;
-
-    cf1 = table;
-
-    if (GET_BE_WORD(cf1->CoverageFormat) == 1)
-    {
-        int count = GET_BE_WORD(cf1->GlyphCount);
-        int i;
-        TRACE("Coverage Format 1, %i glyphs\n",count);
-        for (i = 0; i < count; i++)
-            if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
-                return i;
-        return -1;
-    }
-    else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
-    {
-        const GSUB_CoverageFormat2* cf2;
-        int i;
-        int count;
-        cf2 = (const GSUB_CoverageFormat2*)cf1;
-
-        count = GET_BE_WORD(cf2->RangeCount);
-        TRACE("Coverage Format 2, %i ranges\n",count);
-        for (i = 0; i < count; i++)
-        {
-            if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
-                return -1;
-            if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
-                (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
-            {
-                return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
-                    glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
-            }
-        }
-        return -1;
-    }
-    else
-        ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
-
-    return -1;
-}
-
-static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
-{
-    const GSUB_ScriptList *script;
-    const GSUB_Script *deflt = NULL;
-    int i;
-    script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
-
-    TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
-    for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
-    {
-        const GSUB_Script *scr;
-        int offset;
-
-        offset = GET_BE_WORD(script->ScriptRecord[i].Script);
-        scr = (const GSUB_Script*)((const BYTE*)script + offset);
-
-        if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
-            return scr;
-        if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
-            deflt = scr;
-    }
-    return deflt;
-}
-
-static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
-{
-    int i;
-    int offset;
-    const GSUB_LangSys *Lang;
-
-    TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
-
-    for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
-    {
-        offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
-        Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
-
-        if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
-            return Lang;
-    }
-    offset = GET_BE_WORD(script->DefaultLangSys);
-    if (offset)
-    {
-        Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
-        return Lang;
-    }
-    return NULL;
-}
-
-static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
-{
-    int i;
-    const GSUB_FeatureList *feature;
-    feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
-
-    TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
-    for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
-    {
-        int index = GET_BE_WORD(lang->FeatureIndex[i]);
-        if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
-        {
-            const GSUB_Feature *feat;
-            feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
-            return feat;
-        }
-    }
-    return NULL;
-}
-
-static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
-{
-    int j;
-    TRACE("Single Substitution Subtable\n");
-
-    for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
-    {
-        int offset;
-        const GSUB_SingleSubstFormat1 *ssf1;
-        offset = GET_BE_WORD(look->SubTable[j]);
-        ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
-        if (GET_BE_WORD(ssf1->SubstFormat) == 1)
-        {
-            int offset = GET_BE_WORD(ssf1->Coverage);
-            TRACE("  subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
-            if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
-            {
-                TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
-                glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
-                TRACE(" 0x%x\n",glyphs[glyph_index]);
-                return glyph_index + write_dir;
-            }
-        }
-        else
-        {
-            const GSUB_SingleSubstFormat2 *ssf2;
-            INT index;
-            INT offset;
-
-            ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
-            offset = GET_BE_WORD(ssf1->Coverage);
-            TRACE("  subtype 2,  glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
-            index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
-            TRACE("  Coverage index %i\n",index);
-            if (index != -1)
-            {
-                if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
-                    return GSUB_E_NOGLYPH;
-
-                TRACE("    Glyph is 0x%x ->",glyphs[glyph_index]);
-                glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
-                TRACE("0x%x\n",glyphs[glyph_index]);
-                return glyph_index + write_dir;
-            }
-        }
-    }
-    return GSUB_E_NOGLYPH;
-}
-
-static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+static const char* required_khmer_features[] =
 {
-    int j;
-    TRACE("Multiple Substitution Subtable\n");
-
-    for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
-    {
-        int offset, index;
-        const GSUB_MultipleSubstFormat1 *msf1;
-        offset = GET_BE_WORD(look->SubTable[j]);
-        msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
-
-        offset = GET_BE_WORD(msf1->Coverage);
-        index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
-        if (index != -1)
-        {
-            const GSUB_Sequence *seq;
-            int sub_count;
-            int j;
-            offset = GET_BE_WORD(msf1->Sequence[index]);
-            seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
-            sub_count = GET_BE_WORD(seq->GlyphCount);
-            TRACE("  Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
-
-            for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
-                    glyphs[j] =glyphs[j-(sub_count-1)];
-
-            for (j = 0; j < sub_count; j++)
-                    if (write_dir < 0)
-                        glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
-                    else
-                        glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
-
-            *glyph_count = *glyph_count + (sub_count - 1);
-
-            if (TRACE_ON(uniscribe))
-            {
-                for (j = 0; j < sub_count; j++)
-                    TRACE(" 0x%x",glyphs[glyph_index+j]);
-                TRACE("\n");
-            }
-
-            return glyph_index + (sub_count * write_dir);
-        }
-    }
-    return GSUB_E_NOGLYPH;
-}
-
-static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
-{
-    int j;
-    TRACE("Alternate Substitution Subtable\n");
-
-    for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
-    {
-        int offset;
-        const GSUB_AlternateSubstFormat1 *asf1;
-        INT index;
-
-        offset = GET_BE_WORD(look->SubTable[j]);
-        asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
-        offset = GET_BE_WORD(asf1->Coverage);
+    "pref",
+    "blwf",
+    "abvf",
+    "pstf",
+    "pres",
+    "blws",
+    "abvs",
+    "psts",
+    "clig",
+    NULL
+};
 
-        index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
-        if (index != -1)
-        {
-            const GSUB_AlternateSet *as;
-            offset =  GET_BE_WORD(asf1->AlternateSet[index]);
-            as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
-            FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
-            if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
-                return GSUB_E_NOGLYPH;
-
-            TRACE("  Glyph 0x%x ->",glyphs[glyph_index]);
-            glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
-            TRACE(" 0x%x\n",glyphs[glyph_index]);
-            return glyph_index + write_dir;
-        }
-    }
-    return GSUB_E_NOGLYPH;
-}
+static OPENTYPE_FEATURE_RECORD no_features[] =
+{ };
 
-static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
 {
-    int j;
-
-    TRACE("Ligature Substitution Subtable\n");
-    for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
-    {
-        const GSUB_LigatureSubstFormat1 *lsf1;
-        int offset,index;
-
-        offset = GET_BE_WORD(look->SubTable[j]);
-        lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
-        offset = GET_BE_WORD(lsf1->Coverage);
-        index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
-        TRACE("  Coverage index %i\n",index);
-        if (index != -1)
-        {
-            const GSUB_LigatureSet *ls;
-            int k, count;
-
-            offset = GET_BE_WORD(lsf1->LigatureSet[index]);
-            ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
-            count = GET_BE_WORD(ls->LigatureCount);
-            TRACE("  LigatureSet has %i members\n",count);
-            for (k = 0; k < count; k++)
-            {
-                const GSUB_Ligature *lig;
-                int CompCount,l,CompIndex;
-
-                offset = GET_BE_WORD(ls->Ligature[k]);
-                lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
-                CompCount = GET_BE_WORD(lig->CompCount) - 1;
-                CompIndex = glyph_index+write_dir;
-                for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
-                {
-                    int CompGlyph;
-                    CompGlyph = GET_BE_WORD(lig->Component[l]);
-                    if (CompGlyph != glyphs[CompIndex])
-                        break;
-                    CompIndex += write_dir;
-                }
-                if (l == CompCount)
-                {
-                    int replaceIdx = glyph_index;
-                    if (write_dir < 0)
-                        replaceIdx = glyph_index - CompCount;
-
-                    TRACE("    Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
-                    glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
-                    TRACE("0x%x\n",glyphs[replaceIdx]);
-                    if (CompCount > 0)
-                    {
-                        int j;
-                        for (j = replaceIdx + 1; j < *glyph_count; j++)
-                            glyphs[j] =glyphs[j+CompCount];
-                        *glyph_count = *glyph_count - CompCount;
-                    }
-                    return replaceIdx + write_dir;
-                }
-            }
-        }
-    }
-    return GSUB_E_NOGLYPH;
-}
+    { MS_MAKE_TAG('c','c','m','p'), 1},
+    { MS_MAKE_TAG('l','o','c','l'), 1},
+    { MS_MAKE_TAG('c','a','l','t'), 1},
+    { MS_MAKE_TAG('l','i','g','a'), 1},
+};
 
-static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+static OPENTYPE_FEATURE_RECORD mongolian_features[] =
 {
-    int j;
-    BOOL done = FALSE;
-
-    TRACE("Chaining Contextual Substitution Subtable\n");
-    for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
-    {
-        const GSUB_ChainContextSubstFormat1 *ccsf1;
-        int offset;
-        int dirLookahead = write_dir;
-        int dirBacktrack = -1 * write_dir;
-
-        offset = GET_BE_WORD(look->SubTable[j]);
-        ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
-        if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
-        {
-            FIXME("  TODO: subtype 1 (Simple context glyph substitution)\n");
-            continue;
-        }
-        else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
-        {
-            FIXME("  TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
-            continue;
-        }
-        else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
-        {
-            int k;
-            int indexGlyphs;
-            const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
-            const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
-            const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
-            const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
-            int newIndex = glyph_index;
-
-            ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
-
-            TRACE("  subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
-
-            for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
-            {
-                offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
-                if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
-                    break;
-            }
-            if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
-                continue;
-            TRACE("Matched Backtrack\n");
-
-            ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
-
-            indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
-            for (k = 0; k < indexGlyphs; k++)
-            {
-                offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
-                if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
-                    break;
-            }
-            if (k != indexGlyphs)
-                continue;
-            TRACE("Matched IndexGlyphs\n");
-
-            ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
-
-            for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
-            {
-                offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
-                if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
-                    break;
-            }
-            if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
-                continue;
-            TRACE("Matched LookAhead\n");
-
-            ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
-
-            if (GET_BE_WORD(ccsf3_4->SubstCount))
-            {
-                for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
-                {
-                    int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
-                    int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
+    { MS_MAKE_TAG('c','c','m','p'), 1},
+    { MS_MAKE_TAG('l','o','c','l'), 1},
+    { MS_MAKE_TAG('c','a','l','t'), 1},
+    { MS_MAKE_TAG('r','l','i','g'), 1},
+};
 
-                    TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
-                    newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
-                    if (newIndex == -1)
-                    {
-                        ERR("Chain failed to generate a glyph\n");
-                        continue;
-                    }
-                }
-                return newIndex;
-            }
-            else return GSUB_E_NOGLYPH;
-        }
-    }
-    return -1;
-}
+typedef struct ScriptShapeDataTag {
+    TEXTRANGE_PROPERTIES   defaultTextRange;
+    const char**           requiredFeatures;
+    OPENTYPE_TAG           newOtTag;
+    ContextualShapingProc  contextProc;
+    ShapeCharGlyphPropProc charGlyphPropProc;
+} ScriptShapeData;
 
-static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+/* in order of scripts */
+static const ScriptShapeData ShapingData[] =
 {
-    int offset;
-    const GSUB_LookupTable *look;
+    {{ standard_features, 2}, NULL, 0, NULL, NULL},
+    {{ latin_features, 2}, NULL, 0, NULL, NULL},
+    {{ latin_features, 2}, NULL, 0, NULL, NULL},
+    {{ latin_features, 2}, NULL, 0, NULL, NULL},
+    {{ standard_features, 2}, NULL, 0, NULL, NULL},
+    {{ latin_features, 2}, NULL, 0, NULL, NULL},
+    {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
+    {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
+    {{ hebrew_features, 1}, NULL, 0, NULL, NULL},
+    {{ syriac_features, 4}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
+    {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
+    {{ NULL, 0}, NULL, 0, NULL, ShapeCharGlyphProp_None},
+    {{ standard_features, 2}, NULL, 0, NULL, NULL},
+    {{ standard_features, 2}, NULL, 0, NULL, NULL},
+    {{ standard_features, 2}, NULL, 0, NULL, NULL},
+    {{ standard_features, 2}, NULL, 0, NULL, NULL},
+    {{ sinhala_features, 3}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
+    {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
+    {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
+    {{ phags_features, 3}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
+    {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
+    {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
+    {{ thai_features, 1}, required_lao_features, 0, NULL, ShapeCharGlyphProp_Thai},
+    {{ thai_features, 1}, required_lao_features, 0, NULL, ShapeCharGlyphProp_Thai},
+    {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
+    {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
+    {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
+    {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
+    {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
+    {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
+    {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
+    {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
+    {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
+    {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
+    {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
+    {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
+    {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
+    {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
+    {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
+    {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
+    {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
+    {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
+    {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
+    {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
+    {{ standard_features, 2}, NULL, 0, NULL, NULL},
+    {{ latin_features, 2}, NULL, 0, NULL, NULL},
+    {{ standard_features, 2}, NULL, 0, NULL, NULL},
+    {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
+    {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
+    {{ standard_features, 2}, NULL, 0, NULL, NULL},
+    {{ standard_features, 2}, NULL, 0, NULL, NULL},
+    {{ standard_features, 2}, NULL, 0, NULL, NULL},
+    {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
+    {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
+    {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
+    {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, NULL},
+    {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ no_features, 0}, NULL, 0, NULL, NULL},
+    {{ hebrew_features, 1}, NULL, 0, NULL, NULL},
+    {{ latin_features, 2}, NULL, 0, NULL, NULL},
+    {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
+};
 
-    offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
-    look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
-    TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
-    switch(GET_BE_WORD(look->LookupType))
-    {
-        case 1:
-            return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
-        case 2:
-            return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
-        case 3:
-            return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
-        case 4:
-            return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
-        case 6:
-            return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
-        default:
-            FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
-    }
-    return GSUB_E_NOGLYPH;
-}
+extern scriptData scriptInformation[];
 
-static INT GSUB_apply_feature_all_lookups(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
 {
     int i;
     int out_index = GSUB_E_NOGLYPH;
-    const GSUB_LookupList *lookup;
-
-    lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
 
-    TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
-    for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
+    TRACE("%i lookups\n", feature->lookup_count);
+    for (i = 0; i < feature->lookup_count; i++)
     {
-        out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
+        out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
         if (out_index != GSUB_E_NOGLYPH)
             break;
     }
@@ -1061,23 +497,23 @@ static INT GSUB_apply_feature_all_lookups(const GSUB_Header * header, const GSUB
     return out_index;
 }
 
-static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
+static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
 {
     UINT charset;
 
     if (psc->userScript != 0)
     {
-        if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
+        if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag)
             return ShapingData[psa->eScript].newOtTag;
         else
-            return (char*)&psc->userScript;
+            return psc->userScript;
     }
 
-    if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
+    if (tryNew && ShapingData[psa->eScript].newOtTag != 0)
         return ShapingData[psa->eScript].newOtTag;
 
-    if (ShapingData[psa->eScript].otTag[0] != 0)
-        return ShapingData[psa->eScript].otTag;
+    if (scriptInformation[psa->eScript].scriptTag)
+        return scriptInformation[psa->eScript].scriptTag;
 
     /*
      * fall back to the font charset
@@ -1085,93 +521,62 @@ static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCach
     charset = GetTextCharsetInfo(hdc, NULL, 0x0);
     switch (charset)
     {
-        case ANSI_CHARSET: return "latn";
-        case BALTIC_CHARSET: return "latn"; /* ?? */
-        case CHINESEBIG5_CHARSET: return "hani";
-        case EASTEUROPE_CHARSET: return "latn"; /* ?? */
-        case GB2312_CHARSET: return "hani";
-        case GREEK_CHARSET: return "grek";
-        case HANGUL_CHARSET: return "hang";
-        case RUSSIAN_CHARSET: return "cyrl";
-        case SHIFTJIS_CHARSET: return "kana";
-        case TURKISH_CHARSET: return "latn"; /* ?? */
-        case VIETNAMESE_CHARSET: return "latn";
-        case JOHAB_CHARSET: return "latn"; /* ?? */
-        case ARABIC_CHARSET: return "arab";
-        case HEBREW_CHARSET: return "hebr";
-        case THAI_CHARSET: return "thai";
-        default: return "latn";
-    }
-}
-
-static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
-{
-    const GSUB_Feature *feature;
-    const char* script;
-    int i;
-
-    script = get_opentype_script(hdc,psa,psc,FALSE);
-
-    for (i = 0; i <  psc->feature_count; i++)
-    {
-        if (strncmp(psc->features[i].tag,feat,4)==0 && strncmp(psc->features[i].script,script,4)==0)
-            return psc->features[i].feature;
+        case ANSI_CHARSET:
+        case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
+        case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
+        case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
+        case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
+        case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
+        case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
+        case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
+        case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
+        case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
+        case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
+        case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
+        case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
+        case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
+        case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
+        default: return MS_MAKE_TAG('l','a','t','n');
     }
+}
 
-    feature = NULL;
+static LoadedFeature* load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
+{
+    LoadedFeature *feature = NULL;
 
     if (psc->GSUB_Table)
     {
-        const GSUB_Script *script;
-        const GSUB_LangSys *language;
         int attempt = 2;
+        OPENTYPE_TAG tags;
+        OPENTYPE_TAG language;
+        OPENTYPE_TAG script;
+        int cTags;
 
         do
         {
-            script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
+            script = get_opentype_script(hdc,psa,psc,(attempt==2));
+            if (psc->userLang != 0)
+                language = psc->userLang;
+            else
+                language = MS_MAKE_TAG('d','f','l','t');
             attempt--;
-            if (script)
-            {
-                if (psc->userLang != 0)
-                    language = GSUB_get_lang_table(script,(char*)&psc->userLang);
-                else
-                    language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
-                if (language)
-                    feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
-            }
+
+            OpenType_GSUB_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature);
+
         } while(attempt && !feature);
 
         /* try in the default (latin) table */
         if (!feature)
-        {
-            script = GSUB_get_script_table(psc->GSUB_Table, "latn");
-            if (script)
-            {
-                language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
-                if (language)
-                    feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
-            }
-        }
+            OpenType_GSUB_GetFontFeatureTags(psc, MS_MAKE_TAG('l','a','t','n'), MS_MAKE_TAG('d','f','l','t'), FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature);
     }
 
     TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
-
-    psc->feature_count++;
-
-    if (psc->features)
-        psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
-    else
-        psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
-
-    lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
-    lstrcpynA(psc->features[psc->feature_count - 1].script, script, 5);
-    psc->features[psc->feature_count - 1].feature = feature;
     return feature;
 }
 
 static INT apply_GSUB_feature_to_glyph(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, WORD *glyphs, INT index, INT write_dir, INT* glyph_count, const char* feat)
 {
-    const GSUB_Feature *feature;
+    LoadedFeature *feature;
 
     feature = load_GSUB_feature(hdc, psa, psc, feat);
     if (!feature)
@@ -1184,11 +589,11 @@ static INT apply_GSUB_feature_to_glyph(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCach
 static VOID *load_gsub_table(HDC hdc)
 {
     VOID* GSUB_Table = NULL;
-    int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
+    int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
     if (length != GDI_ERROR)
     {
         GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
-        GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
+        GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
         TRACE("Loaded GSUB table of %i bytes\n",length);
     }
     return GSUB_Table;
@@ -1212,117 +617,6 @@ INT SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, Script
     return rc;
 }
 
-static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
-{
-    int offset;
-    WORD class = 0;
-    const GDEF_ClassDefFormat1 *cf1;
-
-    if (!header)
-        return 0;
-
-    offset = GET_BE_WORD(header->GlyphClassDef);
-    if (!offset)
-        return 0;
-
-    cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
-    if (GET_BE_WORD(cf1->ClassFormat) == 1)
-    {
-        if (glyph >= GET_BE_WORD(cf1->StartGlyph))
-        {
-            int index = glyph - GET_BE_WORD(cf1->StartGlyph);
-            if (index < GET_BE_WORD(cf1->GlyphCount))
-                class = GET_BE_WORD(cf1->ClassValueArray[index]);
-        }
-    }
-    else if (GET_BE_WORD(cf1->ClassFormat) == 2)
-    {
-        const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
-        int i, top;
-        top = GET_BE_WORD(cf2->ClassRangeCount);
-        for (i = 0; i < top; i++)
-        {
-            if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
-                glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
-            {
-                class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
-                break;
-            }
-        }
-    }
-    else
-        ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
-
-    return class;
-}
-
-static VOID *load_gdef_table(HDC hdc)
-{
-    VOID* GDEF_Table = NULL;
-    int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
-    if (length != GDI_ERROR)
-    {
-        GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
-        GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
-        TRACE("Loaded GDEF table of %i bytes\n",length);
-    }
-    return GDEF_Table;
-}
-
-static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
-{
-    int i;
-
-    if (!psc->GDEF_Table)
-        psc->GDEF_Table = load_gdef_table(hdc);
-
-    for (i = 0; i < cGlyphs; i++)
-    {
-        WORD class;
-        int char_count = 0;
-        int k;
-
-        for (k = 0; k < cChars; k++)
-            if (pwLogClust[k] == i)
-                char_count++;
-
-        class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
-
-        switch (class)
-        {
-            case 0:
-            case BaseGlyph:
-                pGlyphProp[i].sva.fClusterStart = 1;
-                pGlyphProp[i].sva.fDiacritic = 0;
-                pGlyphProp[i].sva.fZeroWidth = 0;
-                break;
-            case LigatureGlyph:
-                pGlyphProp[i].sva.fClusterStart = 1;
-                pGlyphProp[i].sva.fDiacritic = 0;
-                pGlyphProp[i].sva.fZeroWidth = 0;
-                break;
-            case MarkGlyph:
-                pGlyphProp[i].sva.fClusterStart = 0;
-                pGlyphProp[i].sva.fDiacritic = 1;
-                pGlyphProp[i].sva.fZeroWidth = 1;
-                break;
-            case ComponentGlyph:
-                pGlyphProp[i].sva.fClusterStart = 0;
-                pGlyphProp[i].sva.fDiacritic = 0;
-                pGlyphProp[i].sva.fZeroWidth = 0;
-                break;
-            default:
-                ERR("Unknown glyph class %i\n",class);
-                pGlyphProp[i].sva.fClusterStart = 1;
-                pGlyphProp[i].sva.fDiacritic = 0;
-                pGlyphProp[i].sva.fZeroWidth = 0;
-        }
-
-        if (char_count == 0)
-            pGlyphProp[i].sva.fClusterStart = 0;
-    }
-}
-
 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
 {
     int i;
@@ -1445,20 +739,15 @@ static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, W
 {
     if (psc->GSUB_Table)
     {
-        const GSUB_Feature *feature;
-        const GSUB_LookupList *lookup;
-        const GSUB_Header *header = psc->GSUB_Table;
-        int lookup_index, lookup_count;
+        LoadedFeature *feature;
+        int lookup_index;
 
         feature = load_GSUB_feature(hdc, psa, psc, feat);
         if (!feature)
             return GSUB_E_NOFEATURE;
 
-        TRACE("applying feature %s\n",debugstr_an(feat,4));
-        lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
-        lookup_count = GET_BE_WORD(feature->LookupCount);
-        TRACE("%i lookups\n", lookup_count);
-        for (lookup_index = 0; lookup_index < lookup_count; lookup_index++)
+        TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
+        for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
         {
             int i;
 
@@ -1466,13 +755,13 @@ static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, W
                 i = 0;
             else
                 i = *pcGlyphs-1;
-            TRACE("applying lookup (%i/%i)\n",lookup_index,lookup_count);
+            TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
             while(i < *pcGlyphs && i >= 0)
             {
                 INT nextIndex;
                 INT prevCount = *pcGlyphs;
 
-                nextIndex = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[lookup_index]), pwOutGlyphs, i, write_dir, pcGlyphs);
+                nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
                 if (*pcGlyphs != prevCount)
                 {
                     UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
@@ -1489,7 +778,13 @@ static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, W
 
 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
 {
-    return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
+    OPENTYPE_TAG tag;
+    HRESULT hr;
+    int count = 0;
+
+    hr = OpenType_GSUB_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count, NULL);
+
+    return(SUCCEEDED(hr));
 }
 
 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
@@ -2157,7 +1452,7 @@ static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT i
         glyph_index->pref+= shift;
 }
 
-static void Apply_Indic_BasicForm(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, const GSUB_Feature *feature )
+static void Apply_Indic_BasicForm(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, LoadedFeature *feature )
 {
     int index = glyph_index->start;
 
@@ -2294,13 +1589,13 @@ static void ShapeIndicSyllables(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa,
 {
     int c;
     int overall_shift = 0;
-    const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
-    const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
-    const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
-    const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
-    const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
-    const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
-    const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
+    LoadedFeature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
+    LoadedFeature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
+    LoadedFeature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
+    LoadedFeature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
+    LoadedFeature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
+    LoadedFeature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
+    LoadedFeature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
     BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
     BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
     BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
@@ -2625,7 +1920,6 @@ static int gurmukhi_lex(WCHAR c)
 
 static const ConsonantComponents Gurmukhi_consonants[] = {
             {{0x0A32,0x0A3C,0x0000}, 0x0A33},
-            {{0x0A38,0x0A3C,0x0000}, 0x0A36},
             {{0x0A16,0x0A3C,0x0000}, 0x0A59},
             {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
             {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
@@ -2958,6 +2252,107 @@ static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
     HeapFree(GetProcessHeap(),0,syllables);
 }
 
+static int khmer_lex(WCHAR c)
+{
+    return unicode_lex(c);
+}
+
+static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
+{
+    int cCount = cChars;
+    WCHAR *input;
+    IndicSyllable *syllables = NULL;
+    int syllable_count = 0;
+
+    if (*pcGlyphs != cChars)
+    {
+        ERR("Number of Glyphs and Chars need to match at the beginning\n");
+        return;
+    }
+
+    input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
+    memcpy(input, pwcChars, cChars * sizeof(WCHAR));
+
+    /* Step 1: Reorder within Syllables */
+    Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
+    TRACE("reordered string %s\n",debugstr_wn(input,cCount));
+    GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
+    *pcGlyphs = cCount;
+
+    /* Step 2: Base Form application to syllables */
+    ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
+
+    HeapFree(GetProcessHeap(),0,input);
+    HeapFree(GetProcessHeap(),0,syllables);
+}
+
+static inline BOOL mongolian_wordbreak(WCHAR chr)
+{
+    return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
+}
+
+static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
+{
+    INT *context_shape;
+    INT dirL;
+    int i;
+
+    if (*pcGlyphs != cChars)
+    {
+        ERR("Number of Glyphs and Chars need to match at the beginning\n");
+        return;
+    }
+
+    if (!psa->fLogicalOrder && psa->fRTL)
+        dirL = -1;
+    else
+        dirL = 1;
+
+    if (!psc->GSUB_Table)
+        psc->GSUB_Table = load_gsub_table(hdc);
+
+    if (!psc->GSUB_Table)
+        return;
+
+    context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
+
+    for (i = 0; i < cChars; i++)
+    {
+        if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
+        {
+            if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
+                context_shape[i] = Xn;
+            else
+                context_shape[i] = Xl;
+        }
+        else
+        {
+            if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
+                context_shape[i] = Xr;
+            else
+                context_shape[i] = Xm;
+        }
+    }
+
+    /* Contextual Shaping */
+    i = 0;
+    while(i < *pcGlyphs)
+    {
+        INT nextIndex;
+        INT prevCount = *pcGlyphs;
+        nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
+        if (nextIndex > GSUB_E_NOGLYPH)
+        {
+            UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
+            i = nextIndex;
+        }
+        else
+            i++;
+    }
+
+    HeapFree(GetProcessHeap(),0,context_shape);
+}
+
 static void ShapeCharGlyphProp_Default( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp)
 {
     int i,k;
@@ -2988,7 +2383,7 @@ static void ShapeCharGlyphProp_Default( HDC hdc, ScriptCache* psc, SCRIPT_ANALYS
             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
     }
 
-    GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
+    OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
 }
 
@@ -3099,7 +2494,7 @@ static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSI
             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
     }
 
-    GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
+    OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
     HeapFree(GetProcessHeap(),0,spaces);
 }
@@ -3135,7 +2530,7 @@ static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
             }
     }
 
-    GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
+    OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
 
     for (i = 0; i < cGlyphs; i++)
     {
@@ -3209,7 +2604,7 @@ static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS*
         else
             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
     }
-    GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
+    OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
 }
 
@@ -3242,7 +2637,7 @@ static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS
         else
             pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
     }
-    GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
+    OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
 
     /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
@@ -3256,11 +2651,11 @@ static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS
     }
 }
 
-static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp, lexical_function lexical, BOOL use_syllables)
+static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp, lexical_function lexical, BOOL use_syllables, BOOL override_gsub)
 {
     int i,k;
 
-    GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
+    OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
     for (i = 0; i < cGlyphs; i++)
     {
         int char_index[20];
@@ -3275,9 +2670,12 @@ static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANAL
             }
         }
 
-        /* Indic scripts do not set fDiacritic or fZeroWidth */
-        pGlyphProp[i].sva.fDiacritic = FALSE;
-        pGlyphProp[i].sva.fZeroWidth = FALSE;
+        if (override_gsub)
+        {
+            /* Most indic scripts do not set fDiacritic or fZeroWidth */
+            pGlyphProp[i].sva.fDiacritic = FALSE;
+            pGlyphProp[i].sva.fZeroWidth = FALSE;
+        }
 
         if (char_count == 0)
             continue;
@@ -3303,7 +2701,11 @@ static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANAL
                     break;
                 case lex_ZWJ:
                 case lex_ZWNJ:
-                    k = char_count;
+                    /* check for dangling joiners */
+                    if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
+                        pGlyphProp[i].sva.fClusterStart = 1;
+                    else
+                        k = char_count;
                     break;
                 default:
                     pGlyphProp[i].sva.fClusterStart = 1;
@@ -3341,52 +2743,57 @@ static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANAL
 
 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
 {
-    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE);
+    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
 }
 
 static void ShapeCharGlyphProp_Devanagari( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
 {
-    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE);
+    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
 }
 
 static void ShapeCharGlyphProp_Bengali( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
 {
-    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE);
+    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
 }
 
 static void ShapeCharGlyphProp_Gurmukhi( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
 {
-    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE);
+    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
 }
 
 static void ShapeCharGlyphProp_Gujarati( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
 {
-    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE);
+    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
 }
 
 static void ShapeCharGlyphProp_Oriya( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
 {
-    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE);
+    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
 }
 
 static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
 {
-    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE);
+    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
 }
 
 static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
 {
-    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE);
+    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
 }
 
 static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
 {
-    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE);
+    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
 }
 
 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
 {
-    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE);
+    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
+}
+
+static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
+{
+    ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
 }
 
 void SHAPE_CharGlyphProp(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp)
@@ -3442,7 +2849,7 @@ rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
 
 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
 {
-    const GSUB_Feature *feature;
+    LoadedFeature *feature;
     int i;
 
     if (!ShapingData[psa->eScript].requiredFeatures)
@@ -3463,3 +2870,75 @@ HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANA
 
     return USP_E_SCRIPT_NOT_IN_FONT;
 }
+
+HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
+                                 SCRIPT_ANALYSIS *psa, int cMaxTags,
+                                 OPENTYPE_TAG *pScriptTags, int *pcTags)
+{
+    HRESULT hr;
+    OPENTYPE_TAG searching = 0x00000000;
+
+    if (!psc->GSUB_Table)
+        psc->GSUB_Table = load_gsub_table(hdc);
+
+    if (psa && scriptInformation[psa->eScript].scriptTag)
+        searching = scriptInformation[psa->eScript].scriptTag;
+
+    hr = OpenType_GSUB_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags, NULL);
+    if (FAILED(hr))
+        *pcTags = 0;
+    return hr;
+}
+
+HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
+                                   SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
+                                   int cMaxTags, OPENTYPE_TAG *pLangSysTags,
+                                   int *pcTags)
+{
+    HRESULT hr;
+    OPENTYPE_TAG searching = 0x00000000;
+    BOOL fellback = FALSE;
+
+    if (!psc->GSUB_Table)
+        psc->GSUB_Table = load_gsub_table(hdc);
+
+    if (psa && psc->userLang != 0)
+        searching = psc->userLang;
+
+    hr = OpenType_GSUB_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags, NULL);
+    if (FAILED(hr))
+    {
+        fellback = TRUE;
+        hr = OpenType_GSUB_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags, NULL);
+    }
+
+    if (FAILED(hr) || fellback)
+        *pcTags = 0;
+    if (SUCCEEDED(hr) && fellback && psa)
+        hr = E_INVALIDARG;
+    return hr;
+}
+
+HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
+                                  SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
+                                  OPENTYPE_TAG tagLangSys, int cMaxTags,
+                                  OPENTYPE_TAG *pFeatureTags, int *pcTags)
+{
+    HRESULT hr;
+    BOOL filter = FALSE;
+
+    if (!psc->GSUB_Table)
+        psc->GSUB_Table = load_gsub_table(hdc);
+
+    if (psa && scriptInformation[psa->eScript].scriptTag)
+    {
+        FIXME("Filtering not implemented\n");
+        filter = TRUE;
+    }
+
+    hr = OpenType_GSUB_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, cMaxTags, pFeatureTags, pcTags, NULL);
+
+    if (FAILED(hr))
+        *pcTags = 0;
+    return hr;
+}
index 422c229..a017baf 100644 (file)
@@ -44,8 +44,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
 typedef struct _scriptRange
 {
     WORD script;
-    WORD rangeFirst;
-    WORD rangeLast;
+    DWORD rangeFirst;
+    DWORD rangeLast;
     WORD numericScript;
     WORD punctScript;
 } scriptRange;
@@ -57,7 +57,8 @@ static const scriptRange scriptRanges[] = {
     /* Latin Extended-A: U+0100–U+017F */
     /* Latin Extended-B: U+0180–U+024F */
     /* IPA Extensions: U+0250–U+02AF */
-    { Script_Latin,      0x80,   0x2af ,  Script_Numeric2, Script_Punctuation},
+    /* Spacing Modifier Letters:U+02B0–U+02FF */
+    { Script_Latin,      0x80,   0x2ff ,  Script_Numeric2, Script_Punctuation},
     /* Combining Diacritical Marks : U+0300–U+036F */
     { Script_Diacritical,0x300,  0x36f,  0, 0},
     /* Greek: U+0370–U+03FF */
@@ -81,6 +82,8 @@ static const scriptRange scriptRanges[] = {
     { Script_Arabic,     0x750,  0x77f,  0, 0},
     /* Thaana: U+0780–U+07BF */
     { Script_Thaana,     0x780,  0x7bf,  0, 0},
+    /* N’Ko: U+07C0–U+07FF */
+    { Script_NKo,        0x7c0,  0x7ff,  0, 0},
     /* Devanagari: U+0900–U+097F */
     { Script_Devanagari, 0x900,  0x97f,  Script_Devanagari_Numeric, 0},
     /* Bengali: U+0980–U+09FF */
@@ -107,8 +110,35 @@ static const scriptRange scriptRanges[] = {
     { Script_Lao,       0xe80,  0xeff,  Script_Lao_Numeric, 0},
     /* Tibetan: U+0F00–U+0FFF */
     { Script_Tibetan,   0xf00,  0xfff,  0, 0},
+    /* Myanmar: U+1000–U+109F */
+    { Script_Myanmar,    0x1000,  0x109f, Script_Myanmar_Numeric, 0},
     /* Georgian: U+10A0–U+10FF */
     { Script_Georgian,   0x10a0,  0x10ff,  0, 0},
+    /* Hangul Jamo: U+1100–U+11FF */
+    { Script_Hangul,     0x1100,  0x11ff,  0, 0},
+    /* Ethiopic: U+1200–U+137F */
+    /* Ethiopic Extensions: U+1380–U+139F */
+    { Script_Ethiopic,   0x1200,  0x139f,  0, 0},
+    /* Cherokee: U+13A0–U+13FF */
+    { Script_Cherokee,   0x13a0,  0x13ff,  0, 0},
+    /* Canadian Aboriginal Syllabics: U+1400–U+167F */
+    { Script_Canadian,   0x1400,  0x167f,  0, 0},
+    /* Ogham: U+1680–U+169F */
+    { Script_Ogham,      0x1680,  0x169f,  0, 0},
+    /* Runic: U+16A0–U+16F0 */
+    { Script_Runic,      0x16a0,  0x16f0,  0, 0},
+    /* Khmer: U+1780–U+17FF */
+    { Script_Khmer,      0x1780,  0x17ff,  Script_Khmer_Numeric, 0},
+    /* Mongolian: U+1800–U+18AF */
+    { Script_Mongolian,  0x1800,  0x18af,  Script_Mongolian_Numeric, 0},
+    /* Canadian Aboriginal Syllabics Extended: U+18B0–U+18FF */
+    { Script_Canadian,   0x18b0,  0x18ff,  0, 0},
+    /* Tai Le: U+1950–U+197F */
+    { Script_Tai_Le,     0x1950,  0x197f,  0, 0},
+    /* New Tai Lue: U+1980–U+19DF */
+    { Script_New_Tai_Lue,0x1980,  0x19df,  Script_New_Tai_Lue_Numeric, 0},
+    /* Khmer Symbols: U+19E0–U+19FF */
+    { Script_Khmer,      0x19e0,  0x19ff,  Script_Khmer_Numeric, 0},
     /* Vedic Extensions: U+1CD0-U+1CFF */
     { Script_Devanagari, 0x1cd0, 0x1cff, Script_Devanagari_Numeric, 0},
     /* Phonetic Extensions: U+1D00–U+1DBF */
@@ -145,6 +175,8 @@ static const scriptRange scriptRanges[] = {
     /* Miscellaneous Mathematical Symbols-A : U+27c0 â€“U+27ef */
     /* Supplemental Arrows-A : U+27f0 â€“U+27ff */
     { Script_Latin,      0x2100, 0x27ff, 0, 0},
+    /* Braille Patterns: U+2800–U+28FF */
+    { Script_Braille,    0x2800, 0x28ff, 0, 0},
     /* Supplemental Arrows-B : U+2900 â€“U+297f */
     /* Miscellaneous Mathematical Symbols-B : U+2980 â€“U+29ff */
     /* Supplemental Mathematical Operators : U+2a00 â€“U+2aff */
@@ -154,8 +186,62 @@ static const scriptRange scriptRanges[] = {
     { Script_Latin,      0x2c60, 0x2c7f, 0, 0},
     /* Georgian: U+2D00–U+2D2F */
     { Script_Georgian,   0x2d00,  0x2d2f,  0, 0},
+    /* Tifinagh: U+2D30–U+2D7F */
+    { Script_Tifinagh,   0x2d30,  0x2d7f,  0, 0},
+    /* Ethiopic Extensions: U+2D80–U+2DDF */
+    { Script_Ethiopic,   0x2d80,  0x2ddf,  0, 0},
     /* Cyrillic Extended-A: U+2DE0–U+2DFF */
     { Script_Cyrillic,   0x2de0, 0x2dff,  0, 0},
+    /* CJK Radicals Supplement: U+2E80–U+2EFF */
+    /* Kangxi Radicals: U+2F00–U+2FDF */
+    { Script_CJK_Han,    0x2e80, 0x2fdf,  0, 0},
+    /* Ideographic Description Characters: U+2FF0–U+2FFF */
+    { Script_Ideograph  ,0x2ff0, 0x2fff,  0, 0},
+    /* CJK Symbols and Punctuation: U+3000–U+303F */
+    { Script_Ideograph  ,0x3000, 0x3004,  0, 0},
+    { Script_CJK_Han    ,0x3005, 0x3005,  0, 0},
+    { Script_Ideograph  ,0x3006, 0x3006,  0, 0},
+    { Script_CJK_Han    ,0x3007, 0x3007,  0, 0},
+    { Script_Ideograph  ,0x3008, 0x3020,  0, 0},
+    { Script_CJK_Han    ,0x3021, 0x3029,  0, 0},
+    { Script_Ideograph  ,0x302a, 0x3030,  0, 0},
+    /* Kana Marks: */
+    { Script_Kana       ,0x3031, 0x3035,  0, 0},
+    { Script_Ideograph  ,0x3036, 0x3037,  0, 0},
+    { Script_CJK_Han    ,0x3038, 0x303b,  0, 0},
+    { Script_Ideograph  ,0x303c, 0x303f,  0, 0},
+    /* Hiragana: U+3040–U+309F */
+    /* Katakana: U+30A0–U+30FF */
+    { Script_Kana       ,0x3040, 0x30ff,  0, 0},
+    /* Bopomofo: U+3100–U+312F */
+    { Script_Bopomofo   ,0x3100, 0x312f,  0, 0},
+    /* Hangul Compatibility Jamo: U+3130–U+318F */
+    { Script_Hangul     ,0x3130, 0x318f,  0, 0},
+    /* Kanbun: U+3190–U+319F */
+    { Script_Ideograph  ,0x3190, 0x319f,  0, 0},
+    /* Bopomofo Extended: U+31A0–U+31BF */
+    { Script_Bopomofo   ,0x31a0, 0x31bf,  0, 0},
+    /* CJK Strokes: U+31C0–U+31EF */
+    { Script_Ideograph  ,0x31c0, 0x31ef,  0, 0},
+    /* Katakana Phonetic Extensions: U+31F0–U+31FF */
+    { Script_Kana       ,0x31f0, 0x31ff,  0, 0},
+    /* Enclosed CJK Letters and Months: U+3200–U+32FF */
+    { Script_Hangul     ,0x3200, 0x321f,  0, 0},
+    { Script_Ideograph  ,0x3220, 0x325f,  0, 0},
+    { Script_Hangul     ,0x3260, 0x327f,  0, 0},
+    { Script_Ideograph  ,0x3280, 0x32ef,  0, 0},
+    { Script_Kana       ,0x32d0, 0x31ff,  0, 0},
+    /* CJK Compatibility: U+3300–U+33FF*/
+    { Script_Kana       ,0x3300, 0x3357,  0, 0},
+    { Script_Ideograph  ,0x3358, 0x33ff,  0, 0},
+    /* CJK Unified Ideographs Extension A: U+3400–U+4DBF */
+    { Script_CJK_Han    ,0x3400, 0x4dbf,  0, 0},
+    /* CJK Unified Ideographs: U+4E00–U+9FFF */
+    { Script_CJK_Han    ,0x4e00, 0x9fff,  0, 0},
+    /* Yi: U+A000–U+A4CF */
+    { Script_Yi         ,0xa000, 0xa4cf,  0, 0},
+    /* Vai: U+A500–U+A63F */
+    { Script_Vai        ,0xa500, 0xa63f,  Script_Vai_Numeric, 0},
     /* Cyrillic Extended-B: U+A640–U+A69F */
     { Script_Cyrillic,   0xa640, 0xa69f,  0, 0},
     /* Modifier Tone Letters: U+A700–U+A71F */
@@ -165,6 +251,22 @@ static const scriptRange scriptRanges[] = {
     { Script_Phags_pa,   0xa840, 0xa87f, 0, 0},
     /* Devanagari Extended: U+A8E0-U+A8FF */
     { Script_Devanagari, 0xa8e0, 0xa8ff, Script_Devanagari_Numeric, 0},
+    /* Myanmar Extended-A: U+AA60–U+AA7F */
+    { Script_Myanmar,    0xaa60,  0xaa7f, Script_Myanmar_Numeric, 0},
+    /* Hangul Jamo Extended-A: U+A960–U+A97F */
+    { Script_Hangul,     0xa960, 0xa97f,  0, 0},
+    /* Hangul Syllables: U+AC00–U+D7A3 */
+    { Script_Hangul,     0xac00, 0xd7a3,  0, 0},
+    /* Hangul Jamo Extended-B: U+D7B0–U+D7FF */
+    { Script_Hangul,     0xd7b0, 0xd7ff,  0, 0},
+    /* Surrogates Area: U+D800–U+DFFF */
+    { Script_Surrogates, 0xd800, 0xdbfe,  0, 0},
+    { Script_Private,    0xdbff, 0xdc00,  0, 0},
+    { Script_Surrogates, 0xdc01, 0xdfff,  0, 0},
+    /* Private Use Area: U+E000–U+F8FF */
+    { Script_Private,    0xe000, 0xf8ff,  0, 0},
+    /* CJK Compatibility Ideographs: U+F900–U+FAFF */
+    { Script_CJK_Han    ,0xf900, 0xfaff,  0, 0},
     /* Latin Ligatures: U+FB00–U+FB06 */
     { Script_Latin,      0xfb00, 0xfb06, 0, 0},
     /* Armenian ligatures U+FB13..U+FB17 */
@@ -173,22 +275,31 @@ static const scriptRange scriptRanges[] = {
     { Script_Hebrew,     0xfb1d, 0xfb4f, 0, 0},
     /* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
     { Script_Arabic,     0xfb50, 0xfdff, 0, 0},
+    /* Vertical Forms: U+FE10–U+FE1F */
+    /* Combining Half Marks: U+FE20–U+FE2F */
+    /* CJK Compatibility Forms: U+FE30–U+FE4F */
+    /* Small Form Variants: U+FE50–U+FE6F */
+    { Script_Ideograph  ,0xfe10, 0xfe6f,  0, 0},
     /* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
     { Script_Arabic,     0xfe70, 0xfeff, 0, 0},
+    /* Halfwidth and Fullwidth Forms: U+FF00–FFEF */
+    { Script_Ideograph  ,0xff00, 0xff64,  Script_Numeric2, 0},
+    { Script_Kana       ,0xff65, 0xff9f,  0, 0},
+    { Script_Hangul     ,0xffa0, 0xffdf,  0, 0},
+    { Script_Ideograph  ,0xffe0, 0xffef,  0, 0},
+    /* Plane - 1 */
+    /* Deseret: U+10400–U+1044F */
+    { Script_Deseret,     0x10400, 0x1044F,  0, 0},
+    /* Osmanya: U+10480–U+104AF */
+    { Script_Osmanya,    0x10480, 0x104AF,  Script_Osmanya_Numeric, 0},
+    /* Mathematical Alphanumeric Symbols: U+1D400–U+1D7FF */
+    { Script_MathAlpha,  0x1D400, 0x1D7FF,  0, 0},
     /* END */
     { SCRIPT_UNDEFINED,  0, 0, 0}
 };
 
-typedef struct _scriptData
-{
-    SCRIPT_ANALYSIS a;
-    SCRIPT_PROPERTIES props;
-    OPENTYPE_TAG scriptTag;
-    WCHAR fallbackFont[LF_FACESIZE];
-} scriptData;
-
 /* the must be in order so that the index matches the Script value */
-static const scriptData scriptInformation[] = {
+const scriptData scriptInformation[] = {
     {{SCRIPT_UNDEFINED, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
      {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
      0x00000000,
@@ -196,7 +307,7 @@ static const scriptData scriptInformation[] = {
     {{Script_Latin, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
      {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
      MS_MAKE_TAG('l','a','t','n'),
-     {0}},
+     {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
     {{Script_CR, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
      {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
      0x00000000,
@@ -204,7 +315,7 @@ static const scriptData scriptInformation[] = {
     {{Script_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
      {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
      0x00000000,
-     {0}},
+     {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
     {{Script_Control, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
      {LANG_ENGLISH, 0, 1, 0, 0, ANSI_CHARSET, 1, 0, 0, 0, 0, 0, 1, 0, 0},
      0x00000000,
@@ -212,7 +323,7 @@ static const scriptData scriptInformation[] = {
     {{Script_Punctuation, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
      {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
      0x00000000,
-     {0}},
+     {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
     {{Script_Arabic, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
      {LANG_ARABIC, 0, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 1, 0},
      MS_MAKE_TAG('a','r','a','b'),
@@ -240,11 +351,11 @@ static const scriptData scriptInformation[] = {
     {{Script_Greek, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
      {LANG_GREEK, 0, 0, 0, 0, GREEK_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
      MS_MAKE_TAG('g','r','e','k'),
-     {0}},
+     {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
     {{Script_Cyrillic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
      {LANG_RUSSIAN, 0, 0, 0, 0, RUSSIAN_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
      MS_MAKE_TAG('c','y','r','l'),
-     {0}},
+     {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
     {{Script_Armenian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
      {LANG_ARMENIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
      MS_MAKE_TAG('a','r','m','n'),
@@ -372,11 +483,151 @@ static const scriptData scriptInformation[] = {
     {{Script_Punctuation2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
      {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
      MS_MAKE_TAG('l','a','t','n'),
-     {0}},
+     {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
     {{Script_Numeric2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
      {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
      0x00000000,
      {0}},
+    {{Script_Myanmar, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0x55, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
+     MS_MAKE_TAG('m','y','m','r'),
+     {0}},
+    {{Script_Myanmar_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0x55, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('m','y','m','r'),
+     {0}},
+    {{Script_Tai_Le, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('t','a','l','e'),
+     {'M','i','c','r','o','s','o','f','t',' ','T','a','i',' ','L','e'}},
+    {{Script_New_Tai_Lue, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('t','a','l','u'),
+     {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e'}},
+    {{Script_New_Tai_Lue_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('t','a','l','u'),
+     {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e'}},
+    {{Script_Khmer, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0x53, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
+     MS_MAKE_TAG('k','h','m','r'),
+     {'D','a','u','n','P','e','n','h'}},
+    {{Script_Khmer, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0x53, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('k','h','m','r'),
+     {'D','a','u','n','P','e','n','h'}},
+    {{Script_CJK_Han, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+     MS_MAKE_TAG('h','a','n','i'),
+     {0}},
+    {{Script_Ideograph, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+     MS_MAKE_TAG('h','a','n','i'),
+     {0}},
+    {{Script_Bopomofo, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+     MS_MAKE_TAG('b','o','p','o'),
+     {0}},
+    {{Script_Kana, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+     MS_MAKE_TAG('k','a','n','a'),
+     {0}},
+    {{Script_Hangul, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {LANG_KOREAN, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+     MS_MAKE_TAG('h','a','n','g'),
+     {0}},
+    {{Script_Yi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {LANG_ENGLISH, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+     MS_MAKE_TAG('y','i',' ',' '),
+     {'M','i','c','r','o','s','o','f','t',' ','Y','i',' ','B','a','i','t','i'}},
+    {{Script_Ethiopic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0x5e, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('e','t','h','i'),
+     {'N','y','a','l','a'}},
+    {{Script_Ethiopic_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0x5e, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('e','t','h','i'),
+     {'N','y','a','l','a'}},
+    {{Script_Mongolian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('m','o','n','g'),
+     {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i'}},
+    {{Script_Mongolian_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {LANG_MONGOLIAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('m','o','n','g'),
+     {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i'}},
+    {{Script_Tifinagh, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('t','f','n','g'),
+     {'E','b','r','i','m','a'}},
+    {{Script_NKo, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
+     {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('n','k','o',' '),
+     {'E','b','r','i','m','a'}},
+    {{Script_Vai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('v','a','i',' '),
+     {'E','b','r','i','m','a'}},
+    {{Script_Vai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('v','a','i',' '),
+     {'E','b','r','i','m','a'}},
+    {{Script_Cherokee, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0x5c, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('c','h','e','r'),
+     {'P','l','a','n','t','a','g','e','n','e','t',' ','C','h','e','r','o','k','e','e'}},
+    {{Script_Canadian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0x5d, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('c','a','n','s'),
+     {'E','u','p','h','e','m','i','a'}},
+    {{Script_Ogham, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('o','g','a','m'),
+     {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l'}},
+    {{Script_Runic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('r','u','n','r'),
+     {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l'}},
+    {{Script_Braille, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {LANG_ENGLISH, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('b','r','a','i'),
+     {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l'}},
+    {{Script_Surrogates, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {LANG_ENGLISH, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+     0x00000000,
+     {0}},
+    {{Script_Private, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 1, 0, 0, 0, 0, 1, 0, 0},
+     0x00000000,
+     {0}},
+    {{Script_Deseret, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('d','s','r','t'),
+     {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l'}},
+    {{Script_Osmanya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('o','s','m','a'),
+     {'E','b','r','i','m','a'}},
+    {{Script_Osmanya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('o','s','m','a'),
+     {'E','b','r','i','m','a'}},
+    {{Script_MathAlpha, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('m','a','t','h'),
+     {'C','a','m','b','r','i','a',' ','M','a','t','h'}},
+    {{Script_Hebrew_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {LANG_HEBREW, 0, 1, 0, 0, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('h','e','b','r'),
+     {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
+    {{Script_Vietnamese_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {LANG_VIETNAMESE, 0, 0, 0, 0, VIETNAMESE_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('l','a','t','n'),
+     {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
+    {{Script_Thai_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
+     {LANG_THAI, 0, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+     MS_MAKE_TAG('t','h','a','i'),
+     {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
 };
 
 static const SCRIPT_PROPERTIES *script_props[] =
@@ -403,7 +654,25 @@ static const SCRIPT_PROPERTIES *script_props[] =
     &scriptInformation[38].props, &scriptInformation[39].props,
     &scriptInformation[40].props, &scriptInformation[41].props,
     &scriptInformation[42].props, &scriptInformation[43].props,
-    &scriptInformation[44].props, &scriptInformation[45].props
+    &scriptInformation[44].props, &scriptInformation[45].props,
+    &scriptInformation[46].props, &scriptInformation[47].props,
+    &scriptInformation[48].props, &scriptInformation[49].props,
+    &scriptInformation[50].props, &scriptInformation[51].props,
+    &scriptInformation[52].props, &scriptInformation[53].props,
+    &scriptInformation[54].props, &scriptInformation[55].props,
+    &scriptInformation[56].props, &scriptInformation[57].props,
+    &scriptInformation[58].props, &scriptInformation[59].props,
+    &scriptInformation[60].props, &scriptInformation[61].props,
+    &scriptInformation[62].props, &scriptInformation[63].props,
+    &scriptInformation[64].props, &scriptInformation[65].props,
+    &scriptInformation[66].props, &scriptInformation[67].props,
+    &scriptInformation[68].props, &scriptInformation[69].props,
+    &scriptInformation[70].props, &scriptInformation[71].props,
+    &scriptInformation[72].props, &scriptInformation[73].props,
+    &scriptInformation[74].props, &scriptInformation[75].props,
+    &scriptInformation[76].props, &scriptInformation[77].props,
+    &scriptInformation[78].props, &scriptInformation[79].props,
+    &scriptInformation[80].props, &scriptInformation[81].props
 };
 
 typedef struct {
@@ -469,7 +738,7 @@ static inline BYTE get_cache_pitch_family(SCRIPT_CACHE *psc)
     return ((ScriptCache *)*psc)->tm.tmPitchAndFamily;
 }
 
-static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, WCHAR c)
+static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, DWORD c)
 {
     WORD *block = ((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT];
 
@@ -535,24 +804,50 @@ static WCHAR mirror_char( WCHAR ch )
     return ch + wine_mirror_map[wine_mirror_map[ch >> 8] + (ch & 0xff)];
 }
 
-static WORD get_char_script( WCHAR ch)
+static inline DWORD decode_surrogate_pair(LPCWSTR str, INT index, INT end)
+{
+    if (index < end-1 && IS_SURROGATE_PAIR(str[index],str[index+1]))
+    {
+        DWORD ch = 0x10000 + ((str[index] - 0xd800) << 10) + (str[index+1] - 0xdc00);
+        TRACE("Surrogate Pair %x %x => %x\n",str[index], str[index+1], ch);
+        return ch;
+    }
+    return 0;
+}
+
+static WORD get_char_script( LPCWSTR str, INT index, INT end, INT *consumed)
 {
     static const WCHAR latin_punc[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
     WORD type = 0;
+    DWORD ch;
     int i;
 
-    if (ch == 0xc || ch == 0x20 || ch == 0x202f)
+    *consumed = 1;
+
+    if (str[index] == 0xc || str[index] == 0x20 || str[index] == 0x202f)
         return Script_CR;
 
     /* These punctuation are separated out as Latin punctuation */
-    if (strchrW(latin_punc,ch))
+    if (strchrW(latin_punc,str[index]))
         return Script_Punctuation2;
 
     /* These chars are itemized as Punctuation by Windows */
-    if (ch == 0x2212 || ch == 0x2044)
+    if (str[index] == 0x2212 || str[index] == 0x2044)
         return Script_Punctuation;
 
-    GetStringTypeW(CT_CTYPE1, &ch, 1, &type);
+    /* Currency Symboles by Unicode point */
+    switch (str[index])
+    {
+        case 0x09f2:
+        case 0x09f3: return Script_Bengali_Currency;
+        case 0x0af1: return Script_Gujarati_Currency;
+        case 0x0e3f: return Script_Thai_Currency;
+        case 0x20aa: return Script_Hebrew_Currency;
+        case 0x20ab: return Script_Vietnamese_Currency;
+        case 0xfb29: return Script_Hebrew_Currency;
+    }
+
+    GetStringTypeW(CT_CTYPE1, &str[index], 1, &type);
 
     if (type == 0)
         return SCRIPT_UNDEFINED;
@@ -560,6 +855,12 @@ static WORD get_char_script( WCHAR ch)
     if (type & C1_CNTRL)
         return Script_Control;
 
+    ch = decode_surrogate_pair(str, index, end);
+    if (ch)
+        *consumed = 2;
+    else
+        ch = str[index];
+
     i = 0;
     do
     {
@@ -623,7 +924,20 @@ HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
         }
         heap_free(((ScriptCache *)*psc)->GSUB_Table);
         heap_free(((ScriptCache *)*psc)->GDEF_Table);
-        heap_free(((ScriptCache *)*psc)->features);
+        heap_free(((ScriptCache *)*psc)->CMAP_Table);
+        for (i = 0; i < ((ScriptCache *)*psc)->script_count; i++)
+        {
+            int j;
+            for (j = 0; j < ((ScriptCache *)*psc)->scripts[i].language_count; j++)
+            {
+                int k;
+                for (k = 0; k < ((ScriptCache *)*psc)->scripts[i].languages[j].feature_count; k++)
+                    heap_free(((ScriptCache *)*psc)->scripts[i].languages[j].features[k].lookups);
+                heap_free(((ScriptCache *)*psc)->scripts[i].languages[j].features);
+            }
+            heap_free(((ScriptCache *)*psc)->scripts[i].languages);
+        }
+        heap_free(((ScriptCache *)*psc)->scripts);
         heap_free(*psc);
         *psc = NULL;
     }
@@ -874,6 +1188,7 @@ HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int
     WORD  last_indic = -1;
     WORD layoutRTL = 0;
     BOOL forceLevels = FALSE;
+    INT consumed = 0;
 
     TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems, 
           psControl, psState, pItems, pcItems);
@@ -887,7 +1202,16 @@ HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int
 
     for (i = 0; i < cInChars; i++)
     {
-        scripts[i] = get_char_script(pwcInChars[i]);
+        if (consumed <= 0)
+        {
+            scripts[i] = get_char_script(pwcInChars,i,cInChars,&consumed);
+            consumed --;
+        }
+        else
+        {
+            scripts[i] = scripts[i-1];
+            consumed --;
+        }
         /* Devanagari danda (U+0964) and double danda (U+0965) are used for
            all Indic scripts */
         if ((pwcInChars[i] == 0x964 || pwcInChars[i] ==0x965) && last_indic > 0)
@@ -1480,12 +1804,16 @@ HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
                 LOGFONTW lf;
                 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), & lf);
                 lf.lfCharSet = scriptInformation[analysis->pItem[i].a.eScript].props.bCharSet;
+                lf.lfFaceName[0] = 0;
                 find_fallback_font(analysis->pItem[i].a.eScript, lf.lfFaceName);
-                analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
-                if (analysis->glyphs[i].fallbackFont)
+                if (lf.lfFaceName[0])
                 {
-                    ScriptFreeCache(sc);
-                    originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
+                    analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
+                    if (analysis->glyphs[i].fallbackFont)
+                    {
+                        ScriptFreeCache(sc);
+                        originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
+                    }
                 }
             }
 
@@ -1578,6 +1906,8 @@ static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
     INT runStart, runEnd;
     INT iGlyph, cGlyphs;
     HFONT oldFont = 0x0;
+    RECT  crc;
+    int i;
 
     TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
          ssa, iX, iY, iItem, cStart, cEnd, uOptions, fSelected, fDisabled);
@@ -1588,6 +1918,7 @@ static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
          (cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd))
             return S_OK;
 
+    CopyRect(&crc,prc);
     if (fSelected)
     {
         BkMode = GetBkMode(analysis->hdc);
@@ -1618,6 +1949,7 @@ static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
             ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x);
         else
             ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x);
+        crc.left = iX + off_x;
     }
     else
     {
@@ -1625,6 +1957,7 @@ static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
             ScriptStringCPtoX(ssa, cStart, FALSE, &off_x);
         else
             ScriptStringCPtoX(ssa, analysis->pItem[iItem].iCharPos, FALSE, &off_x);
+        crc.left = iX + off_x;
     }
 
     if (analysis->pItem[iItem].a.fRTL)
@@ -1639,6 +1972,24 @@ static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
 
     cGlyphs++;
 
+    /* adjust for cluster glyphs when starting */
+    if (analysis->pItem[iItem].a.fRTL)
+        i = analysis->pItem[iItem+1].iCharPos - 1;
+    else
+        i = analysis->pItem[iItem].iCharPos;
+
+    for (; i >=analysis->pItem[iItem].iCharPos && i < analysis->pItem[iItem+1].iCharPos; (analysis->pItem[iItem].a.fRTL)?i--:i++)
+    {
+        if (analysis->glyphs[iItem].pwLogClust[i - analysis->pItem[iItem].iCharPos] == iGlyph)
+        {
+            if (analysis->pItem[iItem].a.fRTL)
+                ScriptStringCPtoX(ssa, i, TRUE, &off_x);
+            else
+                ScriptStringCPtoX(ssa, i, FALSE, &off_x);
+            break;
+        }
+    }
+
     if (cEnd < 0 || scriptInformation[analysis->pItem[iItem].a.eScript].props.fNeedsCaretInfo)
     {
         INT direction;
@@ -1660,7 +2011,7 @@ static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
 
     hr = ScriptTextOut(analysis->hdc,
                        (SCRIPT_CACHE *)&analysis->glyphs[iItem].sc, iX + off_x,
-                       iY, uOptions, prc, &analysis->pItem[iItem].a, NULL, 0,
+                       iY, uOptions, &crc, &analysis->pItem[iItem].a, NULL, 0,
                        &analysis->glyphs[iItem].glyphs[iGlyph], cGlyphs,
                        &analysis->glyphs[iItem].piAdvance[iGlyph], NULL,
                        &analysis->glyphs[iItem].pGoffset[iGlyph]);
@@ -2299,17 +2650,20 @@ HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS
 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
 {
     int i;
+    INT consumed = 0;
 
     TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
 
-    for (i = 0; i < len; i++)
+    for (i = 0; i < len; i+=consumed)
     {
         int script;
+        if (i >= len)
+            break;
 
         if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
             return S_OK;
 
-        script = get_char_script(chars[i]);
+        script = get_char_script(chars,i,len, &consumed);
         if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
             (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
             return S_OK;
@@ -2354,8 +2708,9 @@ HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
                                     SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs)
 {
     HRESULT hr;
-    unsigned int i;
+    unsigned int i,g;
     BOOL rtl;
+    int cluster;
 
     TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
      hdc, psc, psa,
@@ -2382,7 +2737,7 @@ HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
     ((ScriptCache *)*psc)->userLang = tagLangSys;
 
     /* set fNoGlyphIndex non truetype/opentype fonts */
-    if (!psa->fNoGlyphIndex && !((ScriptCache *)*psc)->sfnt)
+    if (psa && !psa->fNoGlyphIndex && !((ScriptCache *)*psc)->sfnt)
         psa->fNoGlyphIndex = TRUE;
 
     /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
@@ -2411,35 +2766,59 @@ HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
 
         rChars = heap_alloc(sizeof(WCHAR) * cChars);
         if (!rChars) return E_OUTOFMEMORY;
-        for (i = 0; i < cChars; i++)
+        for (i = 0, g = 0, cluster = 0; i < cChars; i++)
         {
             int idx = i;
-            WCHAR chInput;
+            DWORD chInput;
+
             if (rtl) idx = cChars - 1 - i;
-            if (psa->fRTL)
-                chInput = mirror_char(pwcChars[idx]);
-            else
-                chInput = pwcChars[idx];
-            /* special case for tabs */
-            if (chInput == 0x0009)
-                chInput = 0x0020;
-            if (!(pwOutGlyphs[i] = get_cache_glyph(psc, chInput)))
+            if (!cluster)
             {
-                WORD glyph;
-                if (!hdc)
+                chInput = decode_surrogate_pair(pwcChars, idx, cChars);
+                if (!chInput)
+                {
+                    if (psa->fRTL)
+                        chInput = mirror_char(pwcChars[idx]);
+                    else
+                        chInput = pwcChars[idx];
+                    /* special case for tabs */
+                    if (chInput == 0x0009)
+                        chInput = 0x0020;
+                    rChars[i] = chInput;
+                }
+                else
                 {
-                    heap_free(rChars);
-                    return E_PENDING;
+                    rChars[i] = pwcChars[idx];
+                    rChars[i+1] = pwcChars[(rtl)?idx-1:idx+1];
+                    cluster = 1;
                 }
-                if (GetGlyphIndicesW(hdc, &chInput, 1, &glyph, 0) == GDI_ERROR)
+                if (!(pwOutGlyphs[g] = get_cache_glyph(psc, chInput)))
                 {
-                    heap_free(rChars);
-                    return S_FALSE;
+                    WORD glyph;
+                    if (!hdc)
+                    {
+                        heap_free(rChars);
+                        return E_PENDING;
+                    }
+                    if (OpenType_CMAP_GetGlyphIndex(hdc, (ScriptCache *)*psc, chInput, &glyph, 0) == GDI_ERROR)
+                    {
+                        heap_free(rChars);
+                        return S_FALSE;
+                    }
+                    pwOutGlyphs[g] = set_cache_glyph(psc, chInput, glyph);
                 }
-                pwOutGlyphs[i] = set_cache_glyph(psc, chInput, glyph);
+                g++;
+            }
+            else
+            {
+                int k;
+                cluster--;
+                pwLogClust[idx] = (rtl)?pwLogClust[idx+1]:pwLogClust[idx-1];
+                for (k = (rtl)?idx-1:idx+1; k >= 0 && k < cChars; (rtl)?k--:k++)
+                    pwLogClust[k]--;
             }
-            rChars[i] = chInput;
         }
+        *pcGlyphs = g;
 
         SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
         SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
@@ -3176,6 +3555,33 @@ HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance,
     return S_OK;
 }
 
+HRESULT WINAPI ScriptGetFontScriptTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags)
+{
+    HRESULT hr;
+    if (!pScriptTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
+    if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
+
+    return SHAPE_GetFontScriptTags(hdc, (ScriptCache *)*psc, psa, cMaxTags, pScriptTags, pcTags);
+}
+
+HRESULT WINAPI ScriptGetFontLanguageTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, int cMaxTags, OPENTYPE_TAG *pLangSysTags, int *pcTags)
+{
+    HRESULT hr;
+    if (!pLangSysTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
+    if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
+
+    return SHAPE_GetFontLanguageTags(hdc, (ScriptCache *)*psc, psa, tagScript, cMaxTags, pLangSysTags, pcTags);
+}
+
+HRESULT WINAPI ScriptGetFontFeatureTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags)
+{
+    HRESULT hr;
+    if (!pFeatureTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
+    if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
+
+    return SHAPE_GetFontFeatureTags(hdc, (ScriptCache *)*psc, psa, tagScript, tagLangSys, cMaxTags, pFeatureTags, pcTags);
+}
+
 BOOL gbLpkPresent = FALSE;
 VOID WINAPI LpkPresent()
 {
index 9c477d1..714ed00 100644 (file)
@@ -13,6 +13,7 @@
        <file>linebreak.c</file>
        <file>indicsyllable.c</file>
        <file>mirror.c</file>
+       <file>opentype.c</file>
        <file>shape.c</file>
        <file>shaping.c</file>
        <library>wine</library>
index 99b3e2b..36a712c 100644 (file)
@@ -7,10 +7,10 @@
 @ stdcall ScriptFreeCache(ptr)
 @ stdcall ScriptGetCMap(ptr ptr ptr long long ptr)
 @ stub ScriptGetFontAlternateGlyphs
-@ stub ScriptGetFontFeatureTags
-@ stub ScriptGetFontLanguageTags
+@ stdcall ScriptGetFontFeatureTags(long ptr ptr long long long ptr ptr)
+@ stdcall ScriptGetFontLanguageTags(long ptr ptr long long ptr ptr)
 @ stdcall ScriptGetFontProperties(long ptr ptr)
-@ stub ScriptGetFontScriptTags
+@ stdcall ScriptGetFontScriptTags(long ptr ptr long ptr ptr)
 @ stdcall ScriptGetGlyphABCWidth(ptr ptr long ptr)
 @ stdcall ScriptGetLogicalWidths(ptr long long ptr ptr ptr ptr)
 @ stdcall ScriptGetProperties(ptr long)
index 6f5d3d1..02beaf6 100644 (file)
 #define Script_Diacritical 44
 #define Script_Punctuation2 45
 #define Script_Numeric2 46
+/* Unicode Chapter 11 continued */
+#define Script_Myanmar 47
+#define Script_Myanmar_Numeric 48
+#define Script_Tai_Le 49
+#define Script_New_Tai_Lue 50
+#define Script_New_Tai_Lue_Numeric 51
+#define Script_Khmer 52
+#define Script_Khmer_Numeric 53
+/* Unicode Chapter 12 */
+#define Script_CJK_Han  54
+#define Script_Ideograph  55
+#define Script_Bopomofo 56
+#define Script_Kana 57
+#define Script_Hangul 58
+#define Script_Yi 59
+/* Unicode Chapter 13 */
+#define Script_Ethiopic 60
+#define Script_Ethiopic_Numeric 61
+#define Script_Mongolian 62
+#define Script_Mongolian_Numeric 63
+#define Script_Tifinagh 64
+#define Script_NKo 65
+#define Script_Vai 66
+#define Script_Vai_Numeric 67
+#define Script_Cherokee 68
+#define Script_Canadian 69
+/* Unicode Chapter 14 */
+#define Script_Ogham 70
+#define Script_Runic 71
+/* Unicode Chapter 15 */
+#define Script_Braille 72
+/* Unicode Chapter 16 */
+#define Script_Surrogates 73
+#define Script_Private 74
+/* Unicode Chapter 13 : Plane 1 */
+#define Script_Deseret 75
+#define Script_Osmanya 76
+#define Script_Osmanya_Numeric 77
+/* Unicode Chapter 15 : Plane 1 */
+#define Script_MathAlpha 78
+/* Additional Currency Scripts */
+#define Script_Hebrew_Currency 79
+#define Script_Vietnamese_Currency 80
+#define Script_Thai_Currency 81
 
 #define GLYPH_BLOCK_SHIFT 8
 #define GLYPH_BLOCK_SIZE  (1UL << GLYPH_BLOCK_SHIFT)
 #define GLYPH_BLOCK_MASK  (GLYPH_BLOCK_SIZE - 1)
 #define GLYPH_MAX         65536
 
+#define GSUB_E_NOFEATURE -2
+#define GSUB_E_NOGLYPH -1
+
 typedef struct {
-    char    tag[5];
-    char    script[5];
+    OPENTYPE_TAG tag;
     LPCVOID  feature;
+    INT lookup_count;
+    WORD *lookups;
 } LoadedFeature;
 
+typedef struct {
+    OPENTYPE_TAG tag;
+    LPCVOID table;
+    INT feature_count;
+    LoadedFeature *features;
+} LoadedLanguage;
+
+typedef struct {
+    OPENTYPE_TAG tag;
+    LPCVOID table;
+    LoadedLanguage default_language;
+    INT language_count;
+    LoadedLanguage *languages;
+} LoadedScript;
+
 typedef struct {
     LOGFONTW lf;
     TEXTMETRICW tm;
@@ -95,13 +158,23 @@ typedef struct {
     ABC *widths[GLYPH_MAX / GLYPH_BLOCK_SIZE];
     LPVOID GSUB_Table;
     LPVOID GDEF_Table;
-    INT feature_count;
-    LoadedFeature *features;
+    LPVOID CMAP_Table;
+    LPVOID CMAP_format12_Table;
+    INT script_count;
+    LoadedScript *scripts;
 
     OPENTYPE_TAG userScript;
     OPENTYPE_TAG userLang;
 } ScriptCache;
 
+typedef struct _scriptData
+{
+    SCRIPT_ANALYSIS a;
+    SCRIPT_PROPERTIES props;
+    OPENTYPE_TAG scriptTag;
+    WCHAR fallbackFont[LF_FACESIZE];
+} scriptData;
+
 typedef struct {
     INT start;
     INT base;
@@ -142,8 +215,18 @@ void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYS
 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa) DECLSPEC_HIDDEN;
 void SHAPE_CharGlyphProp(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp) DECLSPEC_HIDDEN;
 INT SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, const WCHAR *chars, INT write_dir, INT count, const char* feature) DECLSPEC_HIDDEN;
+HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags) DECLSPEC_HIDDEN;
+HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, int cMaxTags, OPENTYPE_TAG *pLangSysTags, int *pcTags) DECLSPEC_HIDDEN;
+HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags) DECLSPEC_HIDDEN;
 
 void Indic_ReorderCharacters( HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LPWSTR input, int cChars, IndicSyllable **syllables, int *syllable_count, lexical_function lexical_f, reorder_function reorder_f, BOOL modern) DECLSPEC_HIDDEN;
-void Indic_ParseSyllables( HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LPCWSTR input, const int cChar, IndicSyllable **syllables, int *syllable_count, lexical_function lex, BOOL modern);
+void Indic_ParseSyllables( HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LPCWSTR input, const int cChar, IndicSyllable **syllables, int *syllable_count, lexical_function lex, BOOL modern) DECLSPEC_HIDDEN;
 
 void BREAK_line(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la) DECLSPEC_HIDDEN;
+
+DWORD OpenType_CMAP_GetGlyphIndex(HDC hdc, ScriptCache *psc, DWORD utf32c, LPWORD pgi, DWORD flags) DECLSPEC_HIDDEN;
+void OpenType_GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp) DECLSPEC_HIDDEN;
+INT OpenType_apply_GSUB_lookup(LPCVOID table, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) DECLSPEC_HIDDEN;
+HRESULT OpenType_GSUB_GetFontScriptTags(ScriptCache *psc, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags, LPCVOID* script_table) DECLSPEC_HIDDEN;
+HRESULT OpenType_GSUB_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pLanguageTags, int *pcTags, LPCVOID* language_table) DECLSPEC_HIDDEN;
+HRESULT OpenType_GSUB_GetFontFeatureTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG language_tag, BOOL filtered, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags, LoadedFeature** feature) DECLSPEC_HIDDEN;