[USP10] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / dll / win32 / usp10 / bidi.c
index 8d94fd2..b0df781 100644 (file)
  * has been modified.
  */
 
-#include <windef.h>
-
-#include <wine/list.h>
+#include "config.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winnls.h"
+#include "usp10.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+#include "wine/heap.h"
+#include "wine/list.h"
 
 #include "usp10_internal.h"
 
+extern const unsigned short bidi_bracket_table[] DECLSPEC_HIDDEN;
+
 WINE_DEFAULT_DEBUG_CHANNEL(bidi);
 
 #define ASSERT(x) do { if (!(x)) FIXME("assert failed: %s\n", #x); } while(0)
@@ -135,15 +147,20 @@ static const char debug_type[][4] =
 
 static inline void dump_types(const char* header, WORD *types, int start, int end)
 {
-    int i;
+    int i, len = 0;
     TRACE("%s:",header);
-    for (i = start; i< end; i++)
+    for (i = start; i < end && len < 200; i++)
+    {
         TRACE(" %s",debug_type[types[i]]);
+        len += strlen(debug_type[types[i]])+1;
+    }
+    if (i != end)
+        TRACE("...");
     TRACE("\n");
 }
 
 /* Convert the libwine information to the direction enum */
-static void classify(LPCWSTR lpString, WORD *chartype, DWORD uCount, const SCRIPT_CONTROL *c)
+static void classify(const WCHAR *string, WORD *chartype, DWORD count, const SCRIPT_CONTROL *c)
 {
     static const enum directions dir_map[16] =
     {
@@ -167,14 +184,14 @@ static void classify(LPCWSTR lpString, WORD *chartype, DWORD uCount, const SCRIP
 
     unsigned i;
 
-    for (i = 0; i < uCount; ++i)
+    for (i = 0; i < count; ++i)
     {
-        chartype[i] = dir_map[get_char_typeW(lpString[i]) >> 12];
+        chartype[i] = dir_map[get_char_typeW(string[i]) >> 12];
         switch (chartype[i])
         {
         case ES:
             if (!c->fLegacyBidiClass) break;
-            switch (lpString[i])
+            switch (string[i])
             {
             case '-':
             case '+': chartype[i] = NI; break;
@@ -182,7 +199,7 @@ static void classify(LPCWSTR lpString, WORD *chartype, DWORD uCount, const SCRIP
             }
             break;
         case PDF:
-            switch (lpString[i])
+            switch (string[i])
             {
             case 0x202A: chartype[i] = LRE; break;
             case 0x202B: chartype[i] = RLE; break;
@@ -251,7 +268,7 @@ typedef struct tagStackItem {
 
 #define valid_level(x) (x <= MAX_DEPTH && overflow_isolate_count == 0 && overflow_embedding_count == 0)
 
-static void resolveExplicit(int level, WORD *pclass, WORD *poutLevel, int count)
+static void resolveExplicit(int level, WORD *pclass, WORD *poutLevel, WORD *poutOverrides, int count, BOOL initialOverride)
 {
     /* X1 */
     int overflow_isolate_count = 0;
@@ -266,8 +283,18 @@ static void resolveExplicit(int level, WORD *pclass, WORD *poutLevel, int count)
     stack[stack_top].override = NI;
     stack[stack_top].isolate = FALSE;
 
+    if (initialOverride)
+    {
+        if (odd(level))
+            push_stack(level, R, FALSE);
+        else
+            push_stack(level, L, FALSE);
+    }
+
     for (i = 0; i < count; i++)
     {
+        poutOverrides[i] = stack[stack_top].override;
+
         /* X2 */
         if (pclass[i] == RLE)
         {
@@ -454,6 +481,12 @@ typedef struct tagRun
     WORD e;
 } Run;
 
+typedef struct tagRunChar
+{
+    WCHAR ch;
+    WORD *pcls;
+} RunChar;
+
 typedef struct tagIsolatedRun
 {
     struct list entry;
@@ -462,14 +495,14 @@ typedef struct tagIsolatedRun
     WORD eos;
     WORD e;
 
-    WORD *ppcls[1];
+    RunChar item[1];
 } IsolatedRun;
 
 static inline int iso_nextValidChar(IsolatedRun *iso_run, int index)
 {
     if (index >= (iso_run->length-1)) return -1;
     index ++;
-    while (index < iso_run->length && *iso_run->ppcls[index] == BN) index++;
+    while (index < iso_run->length && *iso_run->item[index].pcls == BN) index++;
     if (index == iso_run->length) return -1;
     return index;
 }
@@ -479,23 +512,22 @@ static inline int iso_previousValidChar(IsolatedRun *iso_run, int index)
 
     if (index <= 0) return -1;
     index --;
-    while (index > -1 && *iso_run->ppcls[index] == BN) index--;
+    while (index > -1 && *iso_run->item[index].pcls == BN) index--;
     return index;
 }
 
-static inline int iso_previousChar(IsolatedRun *iso_run, int index)
-{
-    if (index <= 0) return -1;
-    return index --;
-}
-
 static inline void iso_dump_types(const char* header, IsolatedRun *iso_run)
 {
-    int i;
+    int i, len = 0;
     TRACE("%s:",header);
     TRACE("[ ");
-    for (i = 0; i < iso_run->length; i++)
-        TRACE(" %s",debug_type[*iso_run->ppcls[i]]);
+    for (i = 0; i < iso_run->length && len < 200; i++)
+    {
+        TRACE(" %s",debug_type[*iso_run->item[i].pcls]);
+        len += strlen(debug_type[*iso_run->item[i].pcls])+1;
+    }
+    if (i != iso_run->length)
+        TRACE("...");
     TRACE(" ]\n");
 }
 
@@ -522,30 +554,30 @@ static void resolveWeak(IsolatedRun * iso_run)
     /* W1 */
     for (i=0; i < iso_run->length; i++)
     {
-        if (*iso_run->ppcls[i] == NSM)
+        if (*iso_run->item[i].pcls == NSM)
         {
             int j = iso_previousValidChar(iso_run, i);
             if (j == -1)
-                *iso_run->ppcls[i] = iso_run->sos;
-            else if (*iso_run->ppcls[j] >= LRI)
-                *iso_run->ppcls[i] = ON;
+                *iso_run->item[i].pcls = iso_run->sos;
+            else if (*iso_run->item[j].pcls >= LRI)
+                *iso_run->item[i].pcls = ON;
             else
-                *iso_run->ppcls[i] = *iso_run->ppcls[j];
+                *iso_run->item[i].pcls = *iso_run->item[j].pcls;
         }
     }
 
     /* W2 */
     for (i = 0; i < iso_run->length; i++)
     {
-        if (*iso_run->ppcls[i] == EN)
+        if (*iso_run->item[i].pcls == EN)
         {
             int j = iso_previousValidChar(iso_run, i);
             while (j > -1)
             {
-                if (*iso_run->ppcls[j] == R || *iso_run->ppcls[j] == L || *iso_run->ppcls[j] == AL)
+                if (*iso_run->item[j].pcls == R || *iso_run->item[j].pcls == L || *iso_run->item[j].pcls == AL)
                 {
-                    if (*iso_run->ppcls[j] == AL)
-                        *iso_run->ppcls[i] = AN;
+                    if (*iso_run->item[j].pcls == AL)
+                        *iso_run->item[i].pcls = AN;
                     break;
                 }
                 j = iso_previousValidChar(iso_run, j);
@@ -556,53 +588,53 @@ static void resolveWeak(IsolatedRun * iso_run)
     /* W3 */
     for (i = 0; i < iso_run->length; i++)
     {
-        if (*iso_run->ppcls[i] == AL)
-            *iso_run->ppcls[i] = R;
+        if (*iso_run->item[i].pcls == AL)
+            *iso_run->item[i].pcls = R;
     }
 
     /* W4 */
     for (i = 0; i < iso_run->length; i++)
     {
-        if (*iso_run->ppcls[i] == ES)
+        if (*iso_run->item[i].pcls == ES)
         {
             int b = iso_previousValidChar(iso_run, i);
             int f = iso_nextValidChar(iso_run, i);
 
-            if (b > -1 && f > -1 && *iso_run->ppcls[b] == EN && *iso_run->ppcls[f] == EN)
-                *iso_run->ppcls[i] = EN;
+            if (b > -1 && f > -1 && *iso_run->item[b].pcls == EN && *iso_run->item[f].pcls == EN)
+                *iso_run->item[i].pcls = EN;
         }
-        else if (*iso_run->ppcls[i] == CS)
+        else if (*iso_run->item[i].pcls == CS)
         {
             int b = iso_previousValidChar(iso_run, i);
             int f = iso_nextValidChar(iso_run, i);
 
-            if (b > -1 && f > -1 && *iso_run->ppcls[b] == EN && *iso_run->ppcls[f] == EN)
-                *iso_run->ppcls[i] = EN;
-            else if (b > -1 && f > -1 && *iso_run->ppcls[b] == AN && *iso_run->ppcls[f] == AN)
-                *iso_run->ppcls[i] = AN;
+            if (b > -1 && f > -1 && *iso_run->item[b].pcls == EN && *iso_run->item[f].pcls == EN)
+                *iso_run->item[i].pcls = EN;
+            else if (b > -1 && f > -1 && *iso_run->item[b].pcls == AN && *iso_run->item[f].pcls == AN)
+                *iso_run->item[i].pcls = AN;
         }
     }
 
     /* W5 */
     for (i = 0; i < iso_run->length; i++)
     {
-        if (*iso_run->ppcls[i] == ET)
+        if (*iso_run->item[i].pcls == ET)
         {
             int j;
             for (j = i-1 ; j > -1; j--)
             {
-                if (*iso_run->ppcls[j] == BN) continue;
-                if (*iso_run->ppcls[j] == ET) continue;
-                else if (*iso_run->ppcls[j] == EN) *iso_run->ppcls[i] = EN;
+                if (*iso_run->item[j].pcls == BN) continue;
+                if (*iso_run->item[j].pcls == ET) continue;
+                else if (*iso_run->item[j].pcls == EN) *iso_run->item[i].pcls = EN;
                 else break;
             }
-            if (*iso_run->ppcls[i] == ET)
+            if (*iso_run->item[i].pcls == ET)
             {
                 for (j = i+1; j < iso_run->length; j++)
                 {
-                    if (*iso_run->ppcls[j] == BN) continue;
-                    if (*iso_run->ppcls[j] == ET) continue;
-                    else if (*iso_run->ppcls[j] == EN) *iso_run->ppcls[i] = EN;
+                    if (*iso_run->item[j].pcls == BN) continue;
+                    if (*iso_run->item[j].pcls == ET) continue;
+                    else if (*iso_run->item[j].pcls == EN) *iso_run->item[i].pcls = EN;
                     else break;
                 }
             }
@@ -612,38 +644,119 @@ static void resolveWeak(IsolatedRun * iso_run)
     /* W6 */
     for (i = 0; i < iso_run->length; i++)
     {
-        if (*iso_run->ppcls[i] == ET || *iso_run->ppcls[i] == ES || *iso_run->ppcls[i] == CS || *iso_run->ppcls[i] == ON)
+        if (*iso_run->item[i].pcls == ET || *iso_run->item[i].pcls == ES || *iso_run->item[i].pcls == CS || *iso_run->item[i].pcls == ON)
         {
             int b = i-1;
             int f = i+1;
-            if (b > -1 && *iso_run->ppcls[b] == BN)
-                *iso_run->ppcls[b] = ON;
-            if (f < iso_run->length && *iso_run->ppcls[f] == BN)
-                *iso_run->ppcls[f] = ON;
+            if (b > -1 && *iso_run->item[b].pcls == BN)
+                *iso_run->item[b].pcls = ON;
+            if (f < iso_run->length && *iso_run->item[f].pcls == BN)
+                *iso_run->item[f].pcls = ON;
 
-            *iso_run->ppcls[i] = ON;
+            *iso_run->item[i].pcls = ON;
         }
     }
 
     /* W7 */
     for (i = 0; i < iso_run->length; i++)
     {
-        if (*iso_run->ppcls[i] == EN)
+        if (*iso_run->item[i].pcls == EN)
         {
             int j;
             for (j = iso_previousValidChar(iso_run, i); j > -1; j = iso_previousValidChar(iso_run, j))
-                if (*iso_run->ppcls[j] == R || *iso_run->ppcls[j] == L)
+                if (*iso_run->item[j].pcls == R || *iso_run->item[j].pcls == L)
                 {
-                    if (*iso_run->ppcls[j] == L)
-                        *iso_run->ppcls[i] = L;
+                    if (*iso_run->item[j].pcls == L)
+                        *iso_run->item[i].pcls = L;
                     break;
                 }
             if (iso_run->sos == L &&  j == -1)
-                *iso_run->ppcls[i] = L;
+                *iso_run->item[i].pcls = L;
+        }
+    }
+}
+
+typedef struct tagBracketPair
+{
+    int start;
+    int end;
+} BracketPair;
+
+static int compr(const void *a, const void* b)
+{
+    return ((BracketPair*)a)->start - ((BracketPair*)b)->start;
+}
+
+static BracketPair *computeBracketPairs(IsolatedRun *iso_run)
+{
+    WCHAR *open_stack;
+    int *stack_index;
+    int stack_top = iso_run->length;
+    unsigned int pair_count = 0;
+    BracketPair *out = NULL;
+    SIZE_T out_size = 0;
+    int i;
+
+    open_stack = heap_alloc(iso_run->length * sizeof(*open_stack));
+    stack_index = heap_alloc(iso_run->length * sizeof(*stack_index));
+
+    for (i = 0; i < iso_run->length; i++)
+    {
+        unsigned short ubv = get_table_entry(bidi_bracket_table, iso_run->item[i].ch);
+
+        if (!ubv)
+            continue;
+
+        if ((ubv >> 8) == 0)
+        {
+            --stack_top;
+            open_stack[stack_top] = iso_run->item[i].ch + (signed char)(ubv & 0xff);
+            /* Deal with canonical equivalent U+2329/232A and U+3008/3009. */
+            if (open_stack[stack_top] == 0x232a)
+                open_stack[stack_top] = 0x3009;
+            stack_index[stack_top] = i;
+        }
+        else if ((ubv >> 8) == 1)
+        {
+            unsigned int j;
+
+            for (j = stack_top; j < iso_run->length; ++j)
+            {
+                WCHAR c = iso_run->item[i].ch;
+
+                if (c == 0x232a)
+                    c = 0x3009;
+
+                if (c != open_stack[j])
+                    continue;
+
+                if (!(usp10_array_reserve((void **)&out, &out_size, pair_count + 2, sizeof(*out))))
+                    ERR("Failed to grow output array.\n");
+
+                out[pair_count].start = stack_index[j];
+                out[pair_count].end = i;
+                ++pair_count;
+
+                out[pair_count].start = -1;
+                stack_top = j + 1;
+                break;
+            }
         }
     }
+
+    heap_free(open_stack);
+    heap_free(stack_index);
+
+    if (!pair_count)
+        return NULL;
+
+    qsort(out, pair_count, sizeof(*out), compr);
+
+    return out;
 }
 
+#define N0_TYPE(a) ((a == AN || a == EN)?R:a)
+
 /*------------------------------------------------------------------------
     Function: resolveNeutrals
 
@@ -665,31 +778,87 @@ static void resolveWeak(IsolatedRun * iso_run)
 static void resolveNeutrals(IsolatedRun *iso_run)
 {
     int i;
+    BracketPair *pairs = NULL;
 
     /* Translate isolates into NI */
     for (i = 0; i < iso_run->length; i++)
     {
-        if (*iso_run->ppcls[i] >= LRI)
-            *iso_run->ppcls[i] = NI;
+        if (*iso_run->item[i].pcls >= LRI)
+            *iso_run->item[i].pcls = NI;
 
-        switch(*iso_run->ppcls[i])
+        switch(*iso_run->item[i].pcls)
         {
             case B:
             case S:
-            case WS: *iso_run->ppcls[i] = NI;
+            case WS: *iso_run->item[i].pcls = NI;
         }
 
-        ASSERT(*iso_run->ppcls[i] < 5 || *iso_run->ppcls[i] == BN); /* "Only NI, L, R,  AN, EN and BN are allowed" */
+        ASSERT(*iso_run->item[i].pcls < 5 || *iso_run->item[i].pcls == BN); /* "Only NI, L, R,  AN, EN and BN are allowed" */
     }
 
     /* N0: Skipping bracketed pairs for now */
+    pairs = computeBracketPairs(iso_run);
+    if (pairs)
+    {
+        BracketPair *p = &pairs[0];
+        int i = 0;
+        while (p->start >= 0)
+        {
+            int j;
+            int e = EmbeddingDirection(iso_run->e);
+            int o = EmbeddingDirection(iso_run->e+1);
+            BOOL flag_o = FALSE;
+            TRACE("Bracket Pair [%i - %i]\n",p->start, p->end);
+
+            /* N0.b */
+            for (j = p->start+1; j < p->end; j++)
+            {
+                if (N0_TYPE(*iso_run->item[j].pcls) == e)
+                {
+                    *iso_run->item[p->start].pcls = e;
+                    *iso_run->item[p->end].pcls = e;
+                    break;
+                }
+                else if (N0_TYPE(*iso_run->item[j].pcls) == o)
+                    flag_o = TRUE;
+            }
+            /* N0.c */
+            if (j == p->end && flag_o)
+            {
+                for (j = p->start; j >= 0; j--)
+                {
+                    if (N0_TYPE(*iso_run->item[j].pcls) == o)
+                    {
+                        *iso_run->item[p->start].pcls = o;
+                        *iso_run->item[p->end].pcls = o;
+                        break;
+                    }
+                    else if (N0_TYPE(*iso_run->item[j].pcls) == e)
+                    {
+                        *iso_run->item[p->start].pcls = e;
+                        *iso_run->item[p->end].pcls = e;
+                        break;
+                    }
+                }
+                if ( j < 0 )
+                {
+                    *iso_run->item[p->start].pcls = iso_run->sos;
+                    *iso_run->item[p->end].pcls = iso_run->sos;
+                }
+            }
+
+            i++;
+            p = &pairs[i];
+        }
+        heap_free(pairs);
+    }
 
     /* N1 */
     for (i = 0; i < iso_run->length; i++)
     {
         WORD l,r;
 
-        if (*iso_run->ppcls[i] == NI)
+        if (*iso_run->item[i].pcls == NI)
         {
             int j;
             int b = iso_previousValidChar(iso_run, i);
@@ -701,24 +870,24 @@ static void resolveNeutrals(IsolatedRun *iso_run)
             }
             else
             {
-                if (*iso_run->ppcls[b] == R || *iso_run->ppcls[b] == AN || *iso_run->ppcls[b] == EN)
+                if (*iso_run->item[b].pcls == R || *iso_run->item[b].pcls == AN || *iso_run->item[b].pcls == EN)
                     l = R;
-                else if (*iso_run->ppcls[b] == L)
+                else if (*iso_run->item[b].pcls == L)
                     l = L;
                 else /* No string type */
                     continue;
             }
             j = iso_nextValidChar(iso_run, i);
-            while (j > -1 && *iso_run->ppcls[j] == NI) j = iso_nextValidChar(iso_run, j);
+            while (j > -1 && *iso_run->item[j].pcls == NI) j = iso_nextValidChar(iso_run, j);
 
             if (j == -1)
             {
                 r = iso_run->eos;
                 j = iso_run->length;
             }
-            else if (*iso_run->ppcls[j] == R || *iso_run->ppcls[j] == AN || *iso_run->ppcls[j] == EN)
+            else if (*iso_run->item[j].pcls == R || *iso_run->item[j].pcls == AN || *iso_run->item[j].pcls == EN)
                 r = R;
-            else if (*iso_run->ppcls[j] == L)
+            else if (*iso_run->item[j].pcls == L)
                 r = L;
             else /* No string type */
                 continue;
@@ -726,7 +895,7 @@ static void resolveNeutrals(IsolatedRun *iso_run)
             if (r == l)
             {
                 for (b = i; b < j && b < iso_run->length; b++)
-                    *iso_run->ppcls[b] = r;
+                    *iso_run->item[b].pcls = r;
             }
         }
     }
@@ -734,15 +903,15 @@ static void resolveNeutrals(IsolatedRun *iso_run)
     /* N2 */
     for (i = 0; i < iso_run->length; i++)
     {
-        if (*iso_run->ppcls[i] == NI)
+        if (*iso_run->item[i].pcls == NI)
         {
             int b = i-1;
             int f = i+1;
-            *iso_run->ppcls[i] = EmbeddingDirection(iso_run->e);
-            if (b > -1 && *iso_run->ppcls[b] == BN)
-                *iso_run->ppcls[b] = EmbeddingDirection(iso_run->e);
-            if (f < iso_run->length && *iso_run->ppcls[f] == BN)
-                *iso_run->ppcls[f] = EmbeddingDirection(iso_run->e);
+            *iso_run->item[i].pcls = EmbeddingDirection(iso_run->e);
+            if (b > -1 && *iso_run->item[b].pcls == BN)
+                *iso_run->item[b].pcls = EmbeddingDirection(iso_run->e);
+            if (f < iso_run->length && *iso_run->item[f].pcls == BN)
+                *iso_run->item[f].pcls = EmbeddingDirection(iso_run->e);
         }
     }
 }
@@ -802,6 +971,11 @@ static void resolveResolved(unsigned baselevel, const WORD * pcls, WORD *plevel,
                 plevel[j--] = baselevel;
             plevel[i] = baselevel;
         }
+        else if (pcls[i] == LRE || pcls[i] == RLE || pcls[i] == LRO || pcls[i] == RLO ||
+                 pcls[i] == PDF || pcls[i] == BN)
+        {
+            plevel[i] = i ? plevel[i - 1] : baselevel;
+        }
         if (i == eos &&
             (pcls[i] == WS || pcls[i] == FSI || pcls[i] == LRI || pcls[i] == RLI ||
              pcls[i] == PDI || pcls[i] == LRE || pcls[i] == RLE || pcls[i] == LRO ||
@@ -816,15 +990,16 @@ static void resolveResolved(unsigned baselevel, const WORD * pcls, WORD *plevel,
     }
 }
 
-static void computeIsolatingRunsSet(unsigned baselevel, WORD *pcls, WORD *pLevel, int uCount, struct list *set)
+static void computeIsolatingRunsSet(unsigned baselevel, WORD *pcls, const WORD *pLevel,
+        const WCHAR *string, unsigned int uCount, struct list *set)
 {
     int run_start, run_end, i;
     int run_count = 0;
     Run *runs;
     IsolatedRun *current_isolated;
 
-    runs = HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(Run));
-    if (!runs) return;
+    if (!(runs = heap_alloc(uCount * sizeof(*runs))))
+        return;
 
     list_init(set);
 
@@ -851,15 +1026,19 @@ static void computeIsolatingRunsSet(unsigned baselevel, WORD *pcls, WORD *pLevel
         {
             int type_fence, real_end;
             int j;
-            current_isolated = HeapAlloc(GetProcessHeap(), 0, sizeof(IsolatedRun) + sizeof(WORD*)*uCount);
-            if (!current_isolated) break;
+
+            if (!(current_isolated = heap_alloc(FIELD_OFFSET(IsolatedRun, item[uCount]))))
+                break;
 
             run_start = runs[k].start;
             current_isolated->e = runs[k].e;
             current_isolated->length = (runs[k].end - runs[k].start)+1;
 
             for (j = 0; j < current_isolated->length;  j++)
-                current_isolated->ppcls[j] = &pcls[runs[k].start+j];
+            {
+                current_isolated->item[j].pcls = &pcls[runs[k].start+j];
+                current_isolated->item[j].ch = string[runs[k].start + j];
+            }
 
             run_end = runs[k].end;
 
@@ -886,7 +1065,10 @@ search:
 
                     current_isolated->length += (runs[j].end - runs[j].start)+1;
                     for (m = 0; l < current_isolated->length; l++, m++)
-                        current_isolated->ppcls[l] = &pcls[runs[j].start+m];
+                    {
+                        current_isolated->item[l].pcls = &pcls[runs[j].start+m];
+                        current_isolated->item[l].ch = string[runs[j].start + m];
+                    }
 
                     TRACE("[%i -- %i]",runs[j].start, runs[j].end);
 
@@ -941,18 +1123,19 @@ search:
         i++;
     }
 
-    HeapFree(GetProcessHeap(), 0, runs);
+    heap_free(runs);
 }
 
 /*************************************************************
  *    BIDI_DeterminLevels
  */
 BOOL BIDI_DetermineLevels(
-                LPCWSTR lpString,       /* [in] The string for which information is to be returned */
-                INT uCount,     /* [in] Number of WCHARs in string. */
+                const WCHAR *lpString,  /* [in] The string for which information is to be returned */
+                unsigned int uCount,    /* [in] Number of WCHARs in string. */
                 const SCRIPT_STATE *s,
                 const SCRIPT_CONTROL *c,
-                WORD *lpOutLevels /* [out] final string levels */
+                WORD *lpOutLevels, /* [out] final string levels */
+                WORD *lpOutOverrides /* [out] final string overrides */
     )
 {
     WORD *chartype;
@@ -962,8 +1145,7 @@ BOOL BIDI_DetermineLevels(
 
     TRACE("%s, %d\n", debugstr_wn(lpString, uCount), uCount);
 
-    chartype = HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(WORD));
-    if (!chartype)
+    if (!(chartype = heap_alloc(uCount * sizeof(*chartype))))
     {
         WARN("Out of memory\n");
         return FALSE;
@@ -974,12 +1156,14 @@ BOOL BIDI_DetermineLevels(
     classify(lpString, chartype, uCount, c);
     if (TRACE_ON(bidi)) dump_types("Start ", chartype, 0, uCount);
 
+    memset(lpOutOverrides, 0, sizeof(WORD) * uCount);
+
     /* resolve explicit */
-    resolveExplicit(baselevel, chartype, lpOutLevels, uCount);
+    resolveExplicit(baselevel, chartype, lpOutLevels, lpOutOverrides, uCount, s->fOverrideDirection);
     if (TRACE_ON(bidi)) dump_types("After Explicit", chartype, 0, uCount);
 
     /* X10/BD13: Computer Isolating runs */
-    computeIsolatingRunsSet(baselevel, chartype, lpOutLevels, uCount, &IsolatingRuns);
+    computeIsolatingRunsSet(baselevel, chartype, lpOutLevels, lpString, uCount, &IsolatingRuns);
 
     LIST_FOR_EACH_ENTRY_SAFE(iso_run, next, &IsolatingRuns, IsolatedRun, entry)
     {
@@ -994,7 +1178,7 @@ BOOL BIDI_DetermineLevels(
         if (TRACE_ON(bidi)) iso_dump_types("After Neutrals", iso_run);
 
         list_remove(&iso_run->entry);
-        HeapFree(GetProcessHeap(),0,iso_run);
+        heap_free(iso_run);
     }
 
     if (TRACE_ON(bidi)) dump_types("Before Implicit", chartype, 0, uCount);
@@ -1005,7 +1189,7 @@ BOOL BIDI_DetermineLevels(
     classify(lpString, chartype, uCount, c);
     resolveResolved(baselevel, chartype, lpOutLevels, 0, uCount-1);
 
-    HeapFree(GetProcessHeap(), 0, chartype);
+    heap_free(chartype);
     return TRUE;
 }
 
@@ -1106,15 +1290,14 @@ int BIDI_ReorderL2vLevel(int level, int *pIndexs, const BYTE* plevel, int cch, B
     return ich;
 }
 
-BOOL BIDI_GetStrengths(LPCWSTR lpString, INT uCount, const SCRIPT_CONTROL *c,
-                      WORD* lpStrength)
+BOOL BIDI_GetStrengths(const WCHAR *string, unsigned int count, const SCRIPT_CONTROL *c, WORD *strength)
 {
-    int i;
-    classify(lpString, lpStrength, uCount, c);
+    unsigned int i;
 
-    for ( i = 0; i < uCount; i++)
+    classify(string, strength, count, c);
+    for (i = 0; i < count; i++)
     {
-        switch(lpStrength[i])
+        switch (strength[i])
         {
             case L:
             case LRE:
@@ -1123,7 +1306,7 @@ BOOL BIDI_GetStrengths(LPCWSTR lpString, INT uCount, const SCRIPT_CONTROL *c,
             case AL:
             case RLE:
             case RLO:
-                lpStrength[i] = BIDI_STRONG;
+                strength[i] = BIDI_STRONG;
                 break;
             case PDF:
             case EN:
@@ -1132,14 +1315,14 @@ BOOL BIDI_GetStrengths(LPCWSTR lpString, INT uCount, const SCRIPT_CONTROL *c,
             case AN:
             case CS:
             case BN:
-                lpStrength[i] = BIDI_WEAK;
+                strength[i] = BIDI_WEAK;
                 break;
             case B:
             case S:
             case WS:
             case ON:
             default: /* Neutrals and NSM */
-                lpStrength[i] = BIDI_NEUTRAL;
+                strength[i] = BIDI_NEUTRAL;
         }
     }
     return TRUE;