Sync with trunk (r48008)
[reactos.git] / dll / win32 / usp10 / usp10.c
index 8595714..cb82f91 100644 (file)
@@ -141,18 +141,6 @@ static const SCRIPT_PROPERTIES *script_props[] =
     &props[73]
 };
 
-#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
-
-typedef struct {
-    LOGFONTW lf;
-    TEXTMETRICW tm;
-    WORD *glyphs[GLYPH_MAX / GLYPH_BLOCK_SIZE];
-    ABC *widths[GLYPH_MAX / GLYPH_BLOCK_SIZE];
-} ScriptCache;
-
 typedef struct {
     int numGlyphs;
     WORD* glyphs;
@@ -271,6 +259,12 @@ static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
     return S_OK;
 }
 
+static WCHAR mirror_char( WCHAR ch )
+{
+    extern const WCHAR wine_mirror_map[];
+    return ch + wine_mirror_map[wine_mirror_map[ch >> 8] + (ch & 0xff)];
+}
+
 /***********************************************************************
  *      DllMain
  *
@@ -312,6 +306,7 @@ HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
             heap_free(((ScriptCache *)*psc)->glyphs[i]);
             heap_free(((ScriptCache *)*psc)->widths[i]);
         }
+        heap_free(((ScriptCache *)*psc)->GSUB_Table);
         heap_free(*psc);
         *psc = NULL;
     }
@@ -517,17 +512,17 @@ HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItem
 #define Numeric_space 0x0020
 #define Arabic_start  0x0600
 #define Arabic_stop   0x06ff
+#define Hebrew_start  0x0590
+#define Hebrew_stop   0x05ff
+#define Syriac_start  0x0700
+#define Syriac_stop   0x074f
 #define Latin_start   0x0001
 #define Latin_stop    0x024f
-#define Script_Arabic  6
-#define Script_Latin   1
-#define Script_Numeric 5
-#define Script_CR      22
-#define Script_LF      23
 
     int   cnt = 0, index = 0;
     int   New_Script = SCRIPT_UNDEFINED;
     WORD  *levels = NULL;
+    WORD  baselevel = 0;
 
     TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems, 
           psControl, psState, pItems, pcItems);
@@ -543,6 +538,7 @@ HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItem
             return E_OUTOFMEMORY;
 
         BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels);
+        baselevel = levels[0];
         for (i = 0; i < cInChars; i++)
             if (levels[i]!=levels[0])
                 break;
@@ -568,6 +564,12 @@ HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItem
     if  (pwcInChars[cnt] >= Arabic_start && pwcInChars[cnt] <= Arabic_stop)
         pItems[index].a.eScript = Script_Arabic;
     else
+    if  (pwcInChars[cnt] >= Hebrew_start && pwcInChars[cnt] <= Hebrew_stop)
+        pItems[index].a.eScript = Script_Hebrew;
+    else
+    if  (pwcInChars[cnt] >= Syriac_start && pwcInChars[cnt] <= Syriac_stop)
+        pItems[index].a.eScript = Script_Syriac;
+    else
     if  (pwcInChars[cnt] >= Latin_start && pwcInChars[cnt] <= Latin_stop)
         pItems[index].a.eScript = Script_Latin;
 
@@ -577,13 +579,20 @@ HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItem
         pItems[index].a.fLayoutRTL = odd(levels[cnt]);
         pItems[index].a.s.uBidiLevel = levels[cnt];
     }
-    else if (pItems[index].a.eScript  == Script_Arabic)
+    else if ((pItems[index].a.eScript  == Script_Arabic) ||
+             (pItems[index].a.eScript  == Script_Hebrew) ||
+             (pItems[index].a.eScript  == Script_Syriac))
     {
         pItems[index].a.s.uBidiLevel = 1;
         pItems[index].a.fRTL = 1;
         pItems[index].a.fLayoutRTL = 1;
     }
-
+    else
+    {
+        pItems[index].a.s.uBidiLevel = baselevel;
+        pItems[index].a.fLayoutRTL = odd(baselevel);
+        pItems[index].a.fRTL = odd(baselevel);
+    }
 
     TRACE("New_Level=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
           levels?levels[cnt]:-1, New_Script, pItems[index].a.eScript, index, cnt,
@@ -608,6 +617,14 @@ HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItem
              || (New_Script == Script_Arabic && pwcInChars[cnt] == Numeric_space))
             New_Script = Script_Arabic;
         else
+        if  ((pwcInChars[cnt] >= Hebrew_start && pwcInChars[cnt] <= Hebrew_stop)
+             || (New_Script == Script_Hebrew && pwcInChars[cnt] == Numeric_space))
+            New_Script = Script_Hebrew;
+        else
+        if  ((pwcInChars[cnt] >= Syriac_start && pwcInChars[cnt] <= Syriac_stop)
+             || (New_Script == Script_Syriac && pwcInChars[cnt] == Numeric_space))
+            New_Script = Script_Syriac;
+        else
         if  ((pwcInChars[cnt] >= Latin_start && pwcInChars[cnt] <= Latin_stop)
              || (New_Script == Script_Latin && pwcInChars[cnt] == Numeric_space))
             New_Script = Script_Latin;
@@ -630,12 +647,21 @@ HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItem
                 pItems[index].a.fLayoutRTL = odd(levels[cnt]);
                 pItems[index].a.s.uBidiLevel = levels[cnt];
             }
-            else if  (New_Script == Script_Arabic)
+            else if  ((New_Script == Script_Arabic) ||
+                      (New_Script == Script_Hebrew) ||
+                      (New_Script == Script_Syriac))
             {
                 pItems[index].a.s.uBidiLevel = 1;
                 pItems[index].a.fRTL = 1;
                 pItems[index].a.fLayoutRTL = 1;
             }
+            else
+            {
+                pItems[index].a.s.uBidiLevel = baselevel;
+                pItems[index].a.fLayoutRTL = odd(baselevel);
+                pItems[index].a.fRTL = odd(baselevel);
+            }
+
             pItems[index].a.eScript = New_Script;
 
             TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
@@ -645,16 +671,17 @@ HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItem
     /* While not strictly necessary according to the spec, make sure the n+1
      * item is set up to prevent random behaviour if the caller erroneously
      * checks the n+1 structure                                              */
-    memset(&pItems[index+1].a, 0, sizeof(SCRIPT_ANALYSIS));
+    index++;
+    memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
 
-    TRACE("index=%d cnt=%d iCharPos=%d\n", index+1, cnt, pItems[index+1].iCharPos);
+    TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
 
     /*  Set one SCRIPT_STATE item being returned  */
-    if (pcItems) *pcItems = index + 1;
+    if  (index + 1 > cMaxItems) return E_OUTOFMEMORY;
+    if (pcItems) *pcItems = index;
 
     /*  Set SCRIPT_ITEM                                     */
-    pItems[index+1].iCharPos = cnt;       /* the last + 1 item
-                                             contains the ptr to the lastchar */
+    pItems[index].iCharPos = cnt;         /* the last item contains the ptr to the lastchar */
     heap_free(levels);
     return S_OK;
 }
@@ -1350,18 +1377,28 @@ HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars,
 
     if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE) && !psa->fNoGlyphIndex)
     {
+        WCHAR *rChars = heap_alloc(sizeof(WCHAR) * cChars);
+        if (!rChars) return E_OUTOFMEMORY;
         for (i = 0; i < cChars; i++)
         {
             int idx = i;
+            WCHAR chInput;
             if (rtl) idx = cChars - 1 - i;
-            if (!(pwOutGlyphs[i] = get_cache_glyph(psc, pwcChars[idx])))
+            if (psa->fRTL)
+                chInput = mirror_char(pwcChars[idx]);
+            else
+                chInput = pwcChars[idx];
+            if (!(pwOutGlyphs[i] = get_cache_glyph(psc, chInput)))
             {
                 WORD glyph;
                 if (!hdc) return E_PENDING;
-                if (GetGlyphIndicesW(hdc, &pwcChars[idx], 1, &glyph, 0) == GDI_ERROR) return S_FALSE;
-                pwOutGlyphs[i] = set_cache_glyph(psc, pwcChars[idx], glyph);
+                if (GetGlyphIndicesW(hdc, &chInput, 1, &glyph, 0) == GDI_ERROR) return S_FALSE;
+                pwOutGlyphs[i] = set_cache_glyph(psc, chInput, glyph);
             }
+            rChars[i] = chInput;
         }
+        SHAPE_ShapeArabicGlyphs(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs);
+        heap_free(rChars);
     }
     else
     {
@@ -1369,6 +1406,7 @@ HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars,
         for (i = 0; i < cChars; i++)
         {
             int idx = i;
+            /* No mirroring done here */
             if (rtl) idx = cChars - 1 - i;
             pwOutGlyphs[i] = pwcChars[idx];
         }
@@ -1489,25 +1527,45 @@ HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars
 
     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
 
+    hr = S_OK;
+
     if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
     {
         for (i = 0; i < cChars; i++)
         {
-            if (!(pwOutGlyphs[i] = get_cache_glyph(psc, pwcInChars[i])))
+            WCHAR inChar;
+            if (dwFlags == SGCM_RTL)
+                inChar = mirror_char(pwcInChars[i]);
+            else
+                inChar = pwcInChars[i];
+            if (!(pwOutGlyphs[i] = get_cache_glyph(psc, inChar)))
             {
                 WORD glyph;
                 if (!hdc) return E_PENDING;
-                if (GetGlyphIndicesW(hdc, &pwcInChars[i], 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
-                pwOutGlyphs[i] = set_cache_glyph(psc, pwcInChars[i], glyph);
+                if (GetGlyphIndicesW(hdc, &inChar, 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
+                if (glyph == 0xffff)
+                {
+                    hr = S_FALSE;
+                    glyph = 0x0;
+                }
+                pwOutGlyphs[i] = set_cache_glyph(psc, inChar, glyph);
             }
         }
     }
     else
     {
         TRACE("no glyph translation\n");
-        for (i = 0; i < cChars; i++) pwOutGlyphs[i] = pwcInChars[i];
+        for (i = 0; i < cChars; i++)
+        {
+            WCHAR inChar;
+            if (dwFlags == SGCM_RTL)
+                inChar = mirror_char(pwcInChars[i]);
+            else
+                inChar = pwcInChars[i];
+            pwOutGlyphs[i] = inChar;
+        }
     }
-    return S_OK;
+    return hr;
 }
 
 /***********************************************************************
@@ -1529,11 +1587,29 @@ HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UIN
     if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
 
     fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
+    fuOptions |= ETO_IGNORELANGUAGE;
     if  (!psa->fNoGlyphIndex)                                     /* Have Glyphs?                      */
         fuOptions |= ETO_GLYPH_INDEX;                             /* Say don't do translation to glyph */
 
-    if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, pwGlyphs, cGlyphs, NULL))
-        hr = S_FALSE;
+    if (psa->fRTL && psa->fLogicalOrder)
+    {
+        int i;
+        WORD *rtlGlyphs;
+
+        rtlGlyphs = heap_alloc(cGlyphs * sizeof(WORD));
+        if (!rtlGlyphs)
+            return E_OUTOFMEMORY;
+
+        for (i = 0; i < cGlyphs; i++)
+            rtlGlyphs[i] = pwGlyphs[cGlyphs-1-i];
+
+        if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, rtlGlyphs, cGlyphs, NULL))
+            hr = S_FALSE;
+        heap_free(rtlGlyphs);
+    }
+    else
+        if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, pwGlyphs, cGlyphs, NULL))
+            hr = S_FALSE;
 
     return hr;
 }
@@ -1913,3 +1989,9 @@ HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance,
     for (i = 0; i < num_glyphs; i++) justify[i] = advance[i];
     return S_OK;
 }
+
+BOOL gbLpkPresent = FALSE;
+VOID WINAPI LpkPresent()
+{
+    gbLpkPresent = TRUE; /* Turn it on this way! Wine is out of control! */
+}