[USP10] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / dll / win32 / usp10 / shape.c
index e7d1558..ca084e7 100644 (file)
  * 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"
+#include "wine/heap.h"
+
 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
 
 #define FIRST_ARABIC_CHAR 0x0600
@@ -72,9 +85,9 @@ static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYS
 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[];
-extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
+extern const unsigned short indic_syllabic_table[] DECLSPEC_HIDDEN;
+extern const unsigned short wine_shaping_table[] DECLSPEC_HIDDEN;
+extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4] DECLSPEC_HIDDEN;
 
 enum joining_types {
     jtU,
@@ -108,12 +121,13 @@ typedef struct tagConsonantComponents
     WCHAR output;
 } ConsonantComponents;
 
-typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
+typedef void (*second_reorder_function)(const WCHAR *chars, const IndicSyllable *syllable,
+        WORD *glyphs, const IndicSyllable *glyph_index, lexical_function lex);
 
 typedef int (*combining_lexical_function)(WCHAR c);
 
 /* the orders of joined_forms and contextual_features need to line up */
-static const char* contextual_features[] =
+static const char *const contextual_features[] =
 {
     "isol",
     "fina",
@@ -156,7 +170,7 @@ static OPENTYPE_FEATURE_RECORD arabic_features[] =
     { MS_MAKE_TAG('m','s','e','t'), 1},
 };
 
-static const char* required_arabic_features[] =
+static const char *const required_arabic_features[] =
 {
     "fina",
     "init",
@@ -193,7 +207,7 @@ static OPENTYPE_FEATURE_RECORD syriac_features[] =
     { MS_MAKE_TAG('d','l','i','g'), 1},
 };
 
-static const char* required_syriac_features[] =
+static const char *const required_syriac_features[] =
 {
     "fina",
     "fin2",
@@ -251,13 +265,13 @@ static OPENTYPE_FEATURE_RECORD thai_gpos_features[] =
     { MS_MAKE_TAG('m','k','m','k'), 1},
 };
 
-static const char* required_lao_features[] =
+static const char *const required_lao_features[] =
 {
     "ccmp",
     NULL
 };
 
-static const char* required_devanagari_features[] =
+static const char *const required_devanagari_features[] =
 {
     "nukt",
     "akhn",
@@ -297,7 +311,7 @@ static OPENTYPE_FEATURE_RECORD myanmar_features[] =
     { MS_MAKE_TAG('c','l','i','g'), 1},
 };
 
-static const char* required_bengali_features[] =
+static const char *const required_bengali_features[] =
 {
     "nukt",
     "akhn",
@@ -314,7 +328,7 @@ static const char* required_bengali_features[] =
     NULL
 };
 
-static const char* required_gurmukhi_features[] =
+static const char *const required_gurmukhi_features[] =
 {
     "nukt",
     "akhn",
@@ -333,7 +347,7 @@ static const char* required_gurmukhi_features[] =
     NULL
 };
 
-static const char* required_oriya_features[] =
+static const char *const required_oriya_features[] =
 {
     "nukt",
     "akhn",
@@ -350,7 +364,7 @@ static const char* required_oriya_features[] =
     NULL
 };
 
-static const char* required_tamil_features[] =
+static const char *const required_tamil_features[] =
 {
     "nukt",
     "akhn",
@@ -366,7 +380,7 @@ static const char* required_tamil_features[] =
     NULL
 };
 
-static const char* required_telugu_features[] =
+static const char *const required_telugu_features[] =
 {
     "nukt",
     "akhn",
@@ -393,7 +407,7 @@ static OPENTYPE_FEATURE_RECORD khmer_features[] =
     { MS_MAKE_TAG('c','l','i','g'), 1},
 };
 
-static const char* required_khmer_features[] =
+static const char *const required_khmer_features[] =
 {
     "pref",
     "blwf",
@@ -434,7 +448,7 @@ static OPENTYPE_FEATURE_RECORD mongolian_features[] =
 typedef struct ScriptShapeDataTag {
     TEXTRANGE_PROPERTIES   defaultTextRange;
     TEXTRANGE_PROPERTIES   defaultGPOSTextRange;
-    const char**           requiredFeatures;
+    const char *const *requiredFeatures;
     OPENTYPE_TAG           newOtTag;
     ContextualShapingProc  contextProc;
     ShapeCharGlyphPropProc charGlyphPropProc;
@@ -529,7 +543,8 @@ static const ScriptShapeData ShapingData[] =
 
 extern scriptData scriptInformation[];
 
-static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
+static int GSUB_apply_feature_all_lookups(const void *header, LoadedFeature *feature,
+        WORD *glyphs, unsigned int glyph_index, int write_dir, int *glyph_count)
 {
     int i;
     int out_index = GSUB_E_NOGLYPH;
@@ -553,19 +568,21 @@ static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature
     return out_index;
 }
 
-static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
+static OPENTYPE_TAG get_opentype_script(HDC hdc, const SCRIPT_ANALYSIS *psa,
+        const ScriptCache *script_cache, BOOL try_new)
 {
     UINT charset;
 
-    if (psc->userScript != 0)
+    if (script_cache->userScript)
     {
-        if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag)
+        if (try_new && ShapingData[psa->eScript].newOtTag
+                && script_cache->userScript == scriptInformation[psa->eScript].scriptTag)
             return ShapingData[psa->eScript].newOtTag;
-        else
-            return psc->userScript;
+
+        return script_cache->userScript;
     }
 
-    if (tryNew && ShapingData[psa->eScript].newOtTag != 0)
+    if (try_new && ShapingData[psa->eScript].newOtTag)
         return ShapingData[psa->eScript].newOtTag;
 
     if (scriptInformation[psa->eScript].scriptTag)
@@ -622,8 +639,12 @@ static LoadedFeature* load_OT_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache
         } while(attempt && !feature);
 
         /* try in the default (latin) table */
-        if (!feature && !script)
-            OpenType_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]), tableType, 1, &tags, &cTags, &feature);
+        if (!feature)
+        {
+            if (!script)
+                script = MS_MAKE_TAG('l','a','t','n');
+            OpenType_GetFontFeatureTags(psc, script, MS_MAKE_TAG('d','f','l','t'), FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
+        }
     }
 
     TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
@@ -648,7 +669,7 @@ static VOID *load_gsub_table(HDC hdc)
     int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
     if (length != GDI_ERROR)
     {
-        GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
+        GSUB_Table = heap_alloc(length);
         GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
         TRACE("Loaded GSUB table of %i bytes\n",length);
     }
@@ -661,7 +682,7 @@ static VOID *load_gpos_table(HDC hdc)
     int length = GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0);
     if (length != GDI_ERROR)
     {
-        GPOS_Table = HeapAlloc(GetProcessHeap(),0,length);
+        GPOS_Table = heap_alloc(length);
         GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, GPOS_Table, length);
         TRACE("Loaded GPOS table of %i bytes\n",length);
     }
@@ -674,7 +695,7 @@ static VOID *load_gdef_table(HDC hdc)
     int length = GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, NULL, 0);
     if (length != GDI_ERROR)
     {
-        GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
+        GDEF_Table = heap_alloc(length);
         GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, GDEF_Table, length);
         TRACE("Loaded GDEF table of %i bytes\n",length);
     }
@@ -697,7 +718,7 @@ INT SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, Script
     INT glyph_count = count;
     INT rc;
 
-    glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
+    glyphs = heap_alloc(2 * count * sizeof(*glyphs));
     GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
     rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
     if (rc > GSUB_E_NOGLYPH)
@@ -705,7 +726,7 @@ INT SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, Script
     else
         rc = 0;
 
-    HeapFree(GetProcessHeap(),0,glyphs);
+    heap_free(glyphs);
     return rc;
 }
 
@@ -739,13 +760,12 @@ static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int ch
         return;
     else
     {
+        int cluster_dir = pwLogClust[0] < pwLogClust[chars-1] ? 1 : -1;
         int i;
         int target_glyph = nextIndex - write_dir;
-        int seeking_glyph;
         int target_index = -1;
         int replacing_glyph = -1;
         int changed = 0;
-        int top_logclust = 0;
 
         if (changeCount > 0)
         {
@@ -755,35 +775,7 @@ static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int ch
                 target_glyph = nextIndex + (changeCount + 1);
         }
 
-        seeking_glyph = target_glyph;
-        for (i = 0; i < chars; i++)
-            if (pwLogClust[i] > top_logclust)
-                top_logclust = pwLogClust[i];
-
-        do {
-            if (write_dir > 0)
-                for (i = 0; i < chars; i++)
-                {
-                    if (pwLogClust[i] == seeking_glyph)
-                    {
-                        target_index = i;
-                        break;
-                    }
-                }
-            else
-                for (i = chars - 1; i >= 0; i--)
-                {
-                    if (pwLogClust[i] == seeking_glyph)
-                    {
-                        target_index = i;
-                        break;
-                    }
-                }
-            if (target_index == -1)
-                seeking_glyph ++;
-        }
-        while (target_index == -1 && seeking_glyph <= top_logclust);
-
+        target_index = USP10_FindGlyphInLogClust(pwLogClust, chars, target_glyph);
         if (target_index == -1)
         {
             ERR("Unable to find target glyph\n");
@@ -793,7 +785,7 @@ static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int ch
         if (changeCount < 0)
         {
             /* merge glyphs */
-            for(i = target_index; i < chars && i >= 0; i+=write_dir)
+            for (i = target_index; i < chars && i >= 0; i += cluster_dir)
             {
                 if (pwLogClust[i] == target_glyph)
                     continue;
@@ -812,8 +804,8 @@ static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int ch
                 }
             }
 
-            /* renumber trailing indexes*/
-            for(i = target_index; i < chars && i >= 0; i+=write_dir)
+            /* renumber trailing indexes */
+            for (i = target_index; i < chars && i >= 0; i += cluster_dir)
             {
                 if (pwLogClust[i] != target_glyph)
                     pwLogClust[i] += changeCount;
@@ -821,8 +813,8 @@ static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int ch
         }
         else
         {
-            for(i = target_index; i < chars && i >= 0; i+=write_dir)
-                    pwLogClust[i] += changeCount;
+            for (i = target_index; i < chars && i >= 0; i += cluster_dir)
+                pwLogClust[i] += changeCount;
         }
     }
 }
@@ -868,16 +860,21 @@ static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, W
     return GSUB_E_NOFEATURE;
 }
 
-static VOID GPOS_apply_feature(ScriptCache *psc, LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, const SCRIPT_ANALYSIS *analysis, INT* piAdvance, LoadedFeature *feature, const WORD *glyphs, INT glyph_count, GOFFSET *pGoffset)
+static void GPOS_apply_feature(const ScriptCache *psc, const OUTLINETEXTMETRICW *otm,
+        const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance,
+        const LoadedFeature *feature, const WORD *glyphs, int glyph_count, GOFFSET *goffset)
 {
-    int i;
+    int dir = analysis->fLogicalOrder && analysis->fRTL ? -1 : 1;
+    unsigned int start_idx, i, j;
 
     TRACE("%i lookups\n", feature->lookup_count);
+
+    start_idx = dir < 0 ? glyph_count - 1 : 0;
     for (i = 0; i < feature->lookup_count; i++)
     {
-        int j;
         for (j = 0; j < glyph_count; )
-            j = OpenType_apply_GPOS_lookup(psc, lpotm, lplogfont, analysis, piAdvance, feature->lookups[i], glyphs, j, glyph_count, pGoffset);
+            j += OpenType_apply_GPOS_lookup(psc, otm, logfont, analysis, advance,
+                    feature->lookups[i], glyphs, start_idx + dir * j, glyph_count, goffset);
     }
 }
 
@@ -912,7 +909,7 @@ static void mark_invalid_combinations(HDC hdc, const WCHAR* pwcChars, INT cChars
     WCHAR invalid = 0x25cc;
     WORD invalid_glyph;
 
-    context_type = HeapAlloc(GetProcessHeap(),0,cChars);
+    context_type = heap_alloc(cChars);
 
     /* Mark invalid combinations */
     for (i = 0; i < cChars; i++)
@@ -928,7 +925,7 @@ static void mark_invalid_combinations(HDC hdc, const WCHAR* pwcChars, INT cChars
         }
     }
 
-    HeapFree(GetProcessHeap(),0,context_type);
+    heap_free(context_type);
 }
 
 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
@@ -938,7 +935,10 @@ static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *
     {
         switch (pwcChars[i])
         {
-            case 0x000D: pwOutGlyphs[i] = psc->sfp.wgBlank; break;
+            case 0x000A:
+            case 0x000D:
+                pwOutGlyphs[i] = psc->sfp.wgBlank;
+                break;
             default:
                 if (pwcChars[i] < 0x1C)
                     pwOutGlyphs[i] = psc->sfp.wgDefault;
@@ -1057,6 +1057,8 @@ static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *p
     INT *context_shape;
     INT dirR, dirL;
     int i;
+    int char_index;
+    int glyph_index;
 
     if (*pcGlyphs != cChars)
     {
@@ -1064,21 +1066,21 @@ static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *p
         return;
     }
 
-    if (!psa->fLogicalOrder && psa->fRTL)
+    if (psa->fLogicalOrder && psa->fRTL)
     {
-        dirR = 1;
-        dirL = -1;
+        dirR = -1;
+        dirL = 1;
     }
     else
     {
-        dirR = -1;
-        dirL = 1;
+        dirR = 1;
+        dirL = -1;
     }
 
     load_ot_tables(hdc, psc);
 
-    context_type = HeapAlloc(GetProcessHeap(),0,cChars);
-    context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
+    context_type = heap_alloc(cChars);
+    context_shape = heap_alloc(cChars * sizeof(*context_shape));
 
     for (i = 0; i < cChars; i++)
         context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
@@ -1100,43 +1102,74 @@ static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *p
     }
 
     /* Contextual Shaping */
-    i = 0;
-    while(i < *pcGlyphs)
+    if (dirL > 0)
+        char_index = glyph_index = 0;
+    else
+        char_index = glyph_index = cChars-1;
+
+    while(char_index < cChars && char_index >= 0)
     {
         BOOL shaped = FALSE;
 
         if (psc->GSUB_Table)
         {
-            INT nextIndex;
+            INT nextIndex, offset = 0;
             INT prevCount = *pcGlyphs;
-            nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
+
+            /* Apply CCMP first */
+            apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
+
+            if (prevCount != *pcGlyphs)
+            {
+                offset = *pcGlyphs - prevCount;
+                if (dirL < 0)
+                    glyph_index -= offset * dirL;
+            }
+
+            /* Apply the contextual feature */
+            nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
+
             if (nextIndex > GSUB_E_NOGLYPH)
             {
-                i = nextIndex;
-                UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
+                UpdateClusters(glyph_index, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
+                char_index += dirL;
+                if (!offset)
+                    glyph_index = nextIndex;
+                else
+                {
+                    offset = *pcGlyphs - prevCount;
+                    glyph_index += dirL * (offset + 1);
+                }
+                shaped = TRUE;
+            }
+            else if (nextIndex == GSUB_E_NOGLYPH)
+            {
+                char_index += dirL;
+                glyph_index += dirL;
+                shaped = TRUE;
             }
-            shaped = (nextIndex > GSUB_E_NOGLYPH);
         }
 
         if (!shaped)
         {
-            if (context_shape[i] == Xn)
+            if (context_shape[char_index] == Xn)
             {
-                WORD newGlyph = pwOutGlyphs[i];
-                if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
+                WORD newGlyph = pwOutGlyphs[glyph_index];
+                if (pwcChars[char_index] >= FIRST_ARABIC_CHAR && pwcChars[char_index] <= LAST_ARABIC_CHAR)
                 {
                     /* fall back to presentation form B */
-                    WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
-                    if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
-                        pwOutGlyphs[i] = newGlyph;
+                    WCHAR context_char = wine_shaping_forms[pwcChars[char_index] - FIRST_ARABIC_CHAR][context_shape[char_index]];
+                    if (context_char != pwcChars[char_index] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
+                        pwOutGlyphs[glyph_index] = newGlyph;
                 }
             }
-            i++;
+            char_index += dirL;
+            glyph_index += dirL;
         }
     }
 
-    HeapFree(GetProcessHeap(),0,context_shape);
-    HeapFree(GetProcessHeap(),0,context_type);
+    heap_free(context_shape);
+    heap_free(context_type);
 
     mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
 }
@@ -1278,6 +1311,8 @@ static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *p
     INT *context_shape;
     INT dirR, dirL;
     int i;
+    int char_index;
+    int glyph_index;
 
     if (*pcGlyphs != cChars)
     {
@@ -1301,8 +1336,8 @@ static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *p
     if (!psc->GSUB_Table)
         return;
 
-    context_type = HeapAlloc(GetProcessHeap(),0,cChars);
-    context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
+    context_type = heap_alloc(cChars);
+    context_shape = heap_alloc(cChars * sizeof(*context_shape));
 
     for (i = 0; i < cChars; i++)
         context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
@@ -1340,23 +1375,49 @@ right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
     }
 
     /* Contextual Shaping */
-    i = 0;
-    while(i < *pcGlyphs)
+    if (dirL > 0)
+        char_index = glyph_index = 0;
+    else
+        char_index = glyph_index = cChars-1;
+
+    while(char_index < cChars && char_index >= 0)
     {
-        INT nextIndex;
+        INT nextIndex, offset = 0;
         INT prevCount = *pcGlyphs;
-        nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
+
+        /* Apply CCMP first */
+        apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
+
+        if (prevCount != *pcGlyphs)
+        {
+            offset = *pcGlyphs - prevCount;
+            if (dirL < 0)
+                glyph_index -= offset * dirL;
+        }
+
+        /* Apply the contextual feature */
+        nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
         if (nextIndex > GSUB_E_NOGLYPH)
         {
             UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
-            i = nextIndex;
+            char_index += dirL;
+            if (!offset)
+                glyph_index = nextIndex;
+            else
+            {
+                offset = *pcGlyphs - prevCount;
+                glyph_index += dirL * (offset + 1);
+            }
         }
         else
-            i++;
+        {
+            char_index += dirL;
+            glyph_index += dirL;
+        }
     }
 
-    HeapFree(GetProcessHeap(),0,context_shape);
-    HeapFree(GetProcessHeap(),0,context_type);
+    heap_free(context_shape);
+    heap_free(context_type);
 
     mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
 }
@@ -1412,6 +1473,8 @@ static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
     INT *context_shape;
     INT dirR, dirL;
     int i;
+    int char_index;
+    int glyph_index;
 
     if (*pcGlyphs != cChars)
     {
@@ -1435,7 +1498,7 @@ static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
     if (!psc->GSUB_Table)
         return;
 
-    context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
+    context_shape = heap_alloc(cChars * sizeof(*context_shape));
 
     for (i = 0; i < cChars; i++)
     {
@@ -1460,27 +1523,39 @@ static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
     }
 
     /* Contextual Shaping */
-    i = 0;
-    while(i < *pcGlyphs)
+    if (dirL > 0)
+        char_index = glyph_index = 0;
+    else
+        char_index = glyph_index = cChars-1;
+
+    while(char_index < cChars && char_index >= 0)
     {
-        if (context_shape[i] >= 0)
+        if (context_shape[char_index] >= 0)
         {
             INT nextIndex;
             INT prevCount = *pcGlyphs;
-            nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
+            nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
+
             if (nextIndex > GSUB_E_NOGLYPH)
             {
                 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
-                i = nextIndex;
+                glyph_index = nextIndex;
+                char_index += dirL;
             }
             else
-                i++;
+            {
+                char_index += dirL;
+                glyph_index += dirL;
+            }
         }
         else
-            i++;
+        {
+            char_index += dirL;
+            glyph_index += dirL;
+        }
     }
 
-    HeapFree(GetProcessHeap(),0,context_shape);
+    heap_free(context_shape);
 }
 
 static int combining_lexical_Thai(WCHAR c)
@@ -1581,7 +1656,7 @@ static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutCha
     cWalk=cWalk+1;
 
     /* Insert */
-    for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
+    for (i = 1; i < 3 && replacements[i] != 0x0000; i++)
     {
         int j;
         for (j = *pcChars; j > cWalk; j--)
@@ -1649,7 +1724,7 @@ static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const Co
     }
 }
 
-static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
+static void Reorder_Ra_follows_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
 {
     if (s->ralf >= 0)
     {
@@ -1668,7 +1743,7 @@ static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_fun
     }
 }
 
-static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
+static void Reorder_Ra_follows_matra(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
 {
     if (s->ralf >= 0)
     {
@@ -1693,7 +1768,7 @@ static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_fu
     }
 }
 
-static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
+static void Reorder_Ra_follows_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
 {
     if (s->ralf >= 0)
     {
@@ -1714,7 +1789,7 @@ static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical
     }
 }
 
-static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
+static void Reorder_Matra_precede_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
 {
     int i;
 
@@ -1741,7 +1816,7 @@ static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_
     }
 }
 
-static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
+static void Reorder_Matra_precede_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
 {
     int i;
 
@@ -1768,14 +1843,16 @@ static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexi
     }
 }
 
-static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
+static void SecondReorder_Blwf_follows_matra(const WCHAR *chars, const IndicSyllable *s,
+        WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
 {
     if (s->blwf >= 0 && g->blwf > g->base)
     {
         int j,loc;
         int g_offset;
         for (loc = s->end; loc > s->blwf; loc--)
-            if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
+            if (lexical(chars[loc]) == lex_Matra_below || lexical(chars[loc]) == lex_Matra_above
+                    || lexical(chars[loc]) == lex_Matra_post)
                 break;
 
         g_offset = (loc - s->blwf) - 1;
@@ -1792,14 +1869,15 @@ static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WO
     }
 }
 
-static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
+static void SecondReorder_Matra_precede_base(const WCHAR *chars, const IndicSyllable *s,
+        WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
 {
     int i;
 
     /* reorder previously moved Matras to correct position*/
     for (i = s->start; i < s->base; i++)
     {
-        if (lexical(pwChar[i]) == lex_Matra_pre)
+        if (lexical(chars[i]) == lex_Matra_pre)
         {
             int j;
             int g_start = g->start + i - s->start;
@@ -1815,7 +1893,8 @@ static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WO
     }
 }
 
-static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
+static void SecondReorder_Pref_precede_base(const IndicSyllable *s,
+        WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
 {
     if (s->pref >= 0 && g->pref > g->base)
     {
@@ -1828,7 +1907,7 @@ static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WOR
     }
 }
 
-static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
+static void Reorder_Like_Sinhala(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
 {
     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
     if (s->start == s->base && s->base == s->end)  return;
@@ -1838,7 +1917,7 @@ static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_functi
     Reorder_Matra_precede_base(pwChar, s, lexical);
 }
 
-static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
+static void Reorder_Like_Devanagari(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
 {
     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
     if (s->start == s->base && s->base == s->end)  return;
@@ -1848,7 +1927,7 @@ static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_fun
     Reorder_Matra_precede_syllable(pwChar, s, lexical);
 }
 
-static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
+static void Reorder_Like_Bengali(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
 {
     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
     if (s->start == s->base && s->base == s->end)  return;
@@ -1858,7 +1937,7 @@ static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_functi
     Reorder_Matra_precede_syllable(pwChar, s, lexical);
 }
 
-static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
+static void Reorder_Like_Kannada(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
 {
     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
     if (s->start == s->base && s->base == s->end)  return;
@@ -1868,25 +1947,27 @@ static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_functi
     Reorder_Matra_precede_syllable(pwChar, s, lexical);
 }
 
-static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
+static void SecondReorder_Like_Telugu(const WCHAR *chars, const IndicSyllable *s,
+        WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
 {
     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
     TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
     if (s->start == s->base && s->base == s->end)  return;
-    if (lexical(pwChar[s->base]) == lex_Vowel) return;
+    if (lexical(chars[s->base]) == lex_Vowel) return;
 
-    SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
+    SecondReorder_Blwf_follows_matra(chars, s, glyphs, g, lexical);
 }
 
-static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
+static void SecondReorder_Like_Tamil(const WCHAR *chars, const IndicSyllable *s,
+        WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
 {
     TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
     TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
     if (s->start == s->base && s->base == s->end)  return;
-    if (lexical(pwChar[s->base]) == lex_Vowel) return;
+    if (lexical(chars[s->base]) == lex_Vowel) return;
 
-    SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
-    SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
+    SecondReorder_Matra_precede_base(chars, s, glyphs, g, lexical);
+    SecondReorder_Pref_precede_base(s, glyphs, g, lexical);
 }
 
 
@@ -2140,7 +2221,7 @@ static inline int unicode_lex(WCHAR c)
     switch( type )
     {
         case 0x0d07: /* Unknown */
-        case 0x0e07: /* Unknwon */
+        case 0x0e07: /* Unknown */
         default: return lex_Generic;
         case 0x0001:
         case 0x0002:
@@ -2172,7 +2253,8 @@ static inline int unicode_lex(WCHAR c)
         case 0x0407: return lex_Composed_Vowel;
         case 0x0507: return lex_Matra_above;
         case 0x0607: return lex_Matra_below;
-        case 0x000c: return lex_Ra;
+        case 0x000c:
+        case 0x0015: return lex_Ra;
     };
 }
 
@@ -2210,7 +2292,7 @@ static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *
         return;
     }
 
-    input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
+    input = heap_alloc(3 * cChars * sizeof(*input));
 
     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
 
@@ -2236,8 +2318,8 @@ static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *
     *pcGlyphs = cCount;
     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
 
-    HeapFree(GetProcessHeap(),0,input);
-    HeapFree(GetProcessHeap(),0,syllables);
+    heap_free(input);
+    heap_free(syllables);
 }
 
 static int devanagari_lex(WCHAR c)
@@ -2277,7 +2359,7 @@ static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSI
         return;
     }
 
-    input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
+    input = heap_alloc(cChars * sizeof(*input));
     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
 
     /* Step 1: Compose Consonant and Nukta */
@@ -2293,8 +2375,8 @@ static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSI
     /* Step 3: Base Form application to syllables */
     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
 
-    HeapFree(GetProcessHeap(),0,input);
-    HeapFree(GetProcessHeap(),0,syllables);
+    heap_free(input);
+    heap_free(syllables);
 }
 
 static int bengali_lex(WCHAR c)
@@ -2333,7 +2415,7 @@ static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *
         return;
     }
 
-    input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
+    input = heap_alloc(2 * cChars * sizeof(*input));
     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
 
     /* Step 1: Decompose Vowels and Compose Consonants */
@@ -2363,8 +2445,8 @@ static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *
     /* Step 4: Base Form application to syllables */
     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
 
-    HeapFree(GetProcessHeap(),0,input);
-    HeapFree(GetProcessHeap(),0,syllables);
+    heap_free(input);
+    heap_free(syllables);
 }
 
 static int gurmukhi_lex(WCHAR c)
@@ -2397,7 +2479,7 @@ static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
         return;
     }
 
-    input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
+    input = heap_alloc(cChars * sizeof(*input));
     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
 
     /* Step 1: Compose Consonants */
@@ -2413,8 +2495,8 @@ static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
     /* Step 3: Base Form application to syllables */
     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
 
-    HeapFree(GetProcessHeap(),0,input);
-    HeapFree(GetProcessHeap(),0,syllables);
+    heap_free(input);
+    heap_free(syllables);
 }
 
 static int gujarati_lex(WCHAR c)
@@ -2441,7 +2523,7 @@ static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
         return;
     }
 
-    input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
+    input = heap_alloc(cChars * sizeof(*input));
     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
 
     /* Step 1: Reorder within Syllables */
@@ -2453,8 +2535,8 @@ static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
     /* Step 2: Base Form application to syllables */
     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
 
-    HeapFree(GetProcessHeap(),0,input);
-    HeapFree(GetProcessHeap(),0,syllables);
+    heap_free(input);
+    heap_free(syllables);
 }
 
 static int oriya_lex(WCHAR c)
@@ -2492,7 +2574,7 @@ static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *ps
         return;
     }
 
-    input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
+    input = heap_alloc(2 * cChars * sizeof(*input));
     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
 
     /* Step 1: Decompose Vowels and Compose Consonants */
@@ -2509,8 +2591,8 @@ static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *ps
     /* Step 3: Base Form application to syllables */
     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
 
-    HeapFree(GetProcessHeap(),0,input);
-    HeapFree(GetProcessHeap(),0,syllables);
+    heap_free(input);
+    heap_free(syllables);
 }
 
 static int tamil_lex(WCHAR c)
@@ -2542,7 +2624,7 @@ static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *ps
         return;
     }
 
-    input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
+    input = heap_alloc(2 * cChars * sizeof(*input));
     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
 
     /* Step 1: Decompose Vowels and Compose Consonants */
@@ -2559,8 +2641,8 @@ static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *ps
     /* Step 3: Base Form application to syllables */
     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
 
-    HeapFree(GetProcessHeap(),0,input);
-    HeapFree(GetProcessHeap(),0,syllables);
+    heap_free(input);
+    heap_free(syllables);
 }
 
 static int telugu_lex(WCHAR c)
@@ -2592,7 +2674,7 @@ static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *p
         return;
     }
 
-    input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
+    input = heap_alloc(2 * cChars * sizeof(*input));
     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
 
     /* Step 1: Decompose Vowels */
@@ -2608,8 +2690,8 @@ static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *p
     /* Step 3: Base Form application to syllables */
     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
 
-    HeapFree(GetProcessHeap(),0,input);
-    HeapFree(GetProcessHeap(),0,syllables);
+    heap_free(input);
+    heap_free(syllables);
 }
 
 static int kannada_lex(WCHAR c)
@@ -2644,7 +2726,7 @@ static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *
         return;
     }
 
-    input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
+    input = heap_alloc(3 * cChars * sizeof(*input));
     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
 
     /* Step 1: Decompose Vowels */
@@ -2660,8 +2742,8 @@ static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *
     /* Step 3: Base Form application to syllables */
     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
 
-    HeapFree(GetProcessHeap(),0,input);
-    HeapFree(GetProcessHeap(),0,syllables);
+    heap_free(input);
+    heap_free(syllables);
 }
 
 static int malayalam_lex(WCHAR c)
@@ -2689,7 +2771,7 @@ static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
         return;
     }
 
-    input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
+    input = heap_alloc(2 * cChars * sizeof(*input));
     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
 
     /* Step 1: Decompose Vowels */
@@ -2705,8 +2787,8 @@ static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
     /* Step 3: Base Form application to syllables */
     ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
 
-    HeapFree(GetProcessHeap(),0,input);
-    HeapFree(GetProcessHeap(),0,syllables);
+    heap_free(input);
+    heap_free(syllables);
 }
 
 static int khmer_lex(WCHAR c)
@@ -2727,7 +2809,7 @@ static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *ps
         return;
     }
 
-    input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
+    input = heap_alloc(cChars * sizeof(*input));
     memcpy(input, pwcChars, cChars * sizeof(WCHAR));
 
     /* Step 1: Reorder within Syllables */
@@ -2739,8 +2821,8 @@ static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *ps
     /* 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);
+    heap_free(input);
+    heap_free(syllables);
 }
 
 static inline BOOL mongolian_wordbreak(WCHAR chr)
@@ -2753,6 +2835,8 @@ static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
     INT *context_shape;
     INT dirL;
     int i;
+    int char_index;
+    int glyph_index;
 
     if (*pcGlyphs != cChars)
     {
@@ -2768,7 +2852,7 @@ static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
     if (!psc->GSUB_Table)
         return;
 
-    context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
+    context_shape = heap_alloc(cChars * sizeof(*context_shape));
 
     for (i = 0; i < cChars; i++)
     {
@@ -2789,22 +2873,31 @@ static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS
     }
 
     /* Contextual Shaping */
-    i = 0;
-    while(i < *pcGlyphs)
+    if (dirL > 0)
+        char_index = glyph_index = 0;
+    else
+        char_index = glyph_index = cChars-1;
+
+    while(char_index < cChars && char_index >= 0)
     {
         INT nextIndex;
         INT prevCount = *pcGlyphs;
-        nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
+        nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
+
         if (nextIndex > GSUB_E_NOGLYPH)
         {
             UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
-            i = nextIndex;
+            glyph_index = nextIndex;
+            char_index += dirL;
         }
         else
-            i++;
+        {
+            char_index += dirL;
+            glyph_index += dirL;
+        }
     }
 
-    HeapFree(GetProcessHeap(),0,context_shape);
+    heap_free(context_shape);
 }
 
 static void ShapeCharGlyphProp_Default( 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)
@@ -2873,23 +2966,23 @@ static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSI
     INT dirR, dirL;
     BYTE *spaces;
 
-    spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
+    spaces = heap_alloc(cGlyphs);
     memset(spaces,0,cGlyphs);
 
-    if (!psa->fLogicalOrder && psa->fRTL)
-    {
-        initGlyph = cGlyphs-1;
-        finaGlyph = 0;
-        dirR = 1;
-        dirL = -1;
-    }
-    else
+    if (psa->fLogicalOrder && psa->fRTL)
     {
         initGlyph = 0;
         finaGlyph = cGlyphs-1;
         dirR = -1;
         dirL = 1;
     }
+    else
+    {
+        initGlyph = cGlyphs-1;
+        finaGlyph = 0;
+        dirR = 1;
+        dirL = -1;
+    }
 
     for (i = 0; i < cGlyphs; i++)
     {
@@ -2973,7 +3066,7 @@ static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSI
 
     OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
-    HeapFree(GetProcessHeap(),0,spaces);
+    heap_free(spaces);
 }
 
 static void ShapeCharGlyphProp_Hebrew( 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 )
@@ -3221,7 +3314,7 @@ static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANAL
             }
         }
 
-        HeapFree(GetProcessHeap(), 0, syllables);
+        heap_free(syllables);
     }
 
     UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
@@ -3313,7 +3406,7 @@ static void SHAPE_ApplyOpenTypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYS
     if (!psc->GSUB_Table)
         return;
 
-    if (!psa->fLogicalOrder && psa->fRTL)
+    if (scriptInformation[psa->eScript].a.fRTL && (!psa->fLogicalOrder || !psa->fRTL))
         dirL = -1;
     else
         dirL = 1;
@@ -3335,14 +3428,9 @@ rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
 
 void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset )
 {
-    const TEXTRANGE_PROPERTIES *rpRangeProperties;
+    const TEXTRANGE_PROPERTIES *rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange;
     int i;
 
-    rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange;
-
-    if (!rpRangeProperties)
-        return;
-
     load_ot_tables(hdc, psc);
 
     if (!psc->GPOS_Table || !psc->otm)