usp10 3/3: Implement ScriptStringXtoCP and ScriptStringCPtoX

Jeff L lats at yless4u.com.au
Thu Sep 21 06:24:49 CDT 2006


ScriptStringXtoCP and ScriptStringCPtoX use the results of 
ScriptStringAnalysis to determine X positions and Character Posistions 
within a string.  A good example of how this works is in 
scriptstring.exe from http://www.catch22.net/tuts/editor12.asp which 
uses the functions extensively.  The tests that are part of this patch 
use the results of one function as input to the other as teh metrics are 
not consistent between wine and Windows.

Jeff Latimer

Changelog: Implement ScriptStringXtoCP and ScriptStringCPtoX
-------------- next part --------------
>From 863f645f92dab80c26118094be9ac339cef7a5e3 Mon Sep 17 00:00:00 2001
From: Jeff Latimer <lats at yless4u.com.au>
Date: Wed, 20 Sep 2006 23:06:00 +1000
Subject: [PATCH] Implement ScriptStringXtoCP and ScriptStringCPtoX
---
 dlls/usp10/tests/usp10.c |   86 +++++++++++++++++++++++++++++
 dlls/usp10/usp10.c       |  136 ++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 216 insertions(+), 6 deletions(-)

diff --git a/dlls/usp10/tests/usp10.c b/dlls/usp10/tests/usp10.c
index 44aa472..9ea17f1 100644
--- a/dlls/usp10/tests/usp10.c
+++ b/dlls/usp10/tests/usp10.c
@@ -984,6 +984,91 @@ static void test_digit_substitution(void
     }
 }
 
+void test_ScriptStringXtoCP_CPtoX(HDC hdc)
+{
+    HRESULT         hr;
+    WCHAR           teststr1[] = {'T', 'e', 's', 't', 'e', '\0'};
+    void            *pString = (WCHAR *) &teststr1;
+    int             cString = (sizeof(teststr1)/2)-1;
+    int             cGlyphs = cString * 2 + 16;
+    int             iCharset = -1;
+    DWORD           dwFlags = SSA_GLYPHS;
+    int             iReqWidth = 100;
+    SCRIPT_CONTROL  psControl;
+    SCRIPT_STATE    psState;
+    SCRIPT_TABDEF   pTabdef;
+    const BYTE      pbInClass = 0;
+    SCRIPT_STRING_ANALYSIS ssa = NULL;
+
+    int             iCh;
+    int             iTrailing;
+    int             iCp;
+    int             X;
+    BOOL            fTrailing;
+
+    LOGFONTA        lf;
+    HFONT           zfont;
+
+    lstrcpyA(lf.lfFaceName, "Symbol");
+    lf.lfHeight = 10;
+    lf.lfCharSet = 0;
+    lf.lfItalic = 0;
+    lf.lfEscapement = 0;
+    lf.lfOrientation = 0;
+    lf.lfUnderline = 0;
+    lf.lfStrikeOut = 0;
+    lf.lfWeight = 400;
+    lf.lfWidth = 0;
+    lf.lfPitchAndFamily = 0;
+
+    zfont = (HFONT) SelectObject(hdc, CreateFontIndirectA(&lf));
+
+    /* test with hdc, this should be a valid test  */
+    hr = ScriptStringAnalyse( hdc, pString, cString, cGlyphs, iCharset, dwFlags,
+                              iReqWidth, &psControl, &psState, NULL, &pTabdef,
+                              &pbInClass, &ssa);
+    ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08lx\n", hr);
+    ok(ssa != NULL, "ScriptStringAnalyse ssa should not be NULL\n");
+    if  (hr == 0)
+    {
+        for (iCp=0; iCp < cString; iCp++)
+        {
+            fTrailing = FALSE;
+            hr = ScriptStringCPtoX(ssa, iCp, fTrailing, &X);
+            ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08lx\n", hr);
+            hr = ScriptStringXtoCP(ssa, X, &iCh, &iTrailing);
+            ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08lx\n", hr);
+            ok(iCp == iCh, "ScriptStringXtoCP should return iCh = %d not %d for X = %d\n", iCh, iCp, X);
+            ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n", 
+                                  iTrailing, X);
+            fTrailing = TRUE;
+            hr = ScriptStringCPtoX(ssa, iCp, fTrailing, &X);
+            ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08lx\n", hr);
+            hr = ScriptStringXtoCP(ssa, X, &iCh, &iTrailing);
+            ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08lx\n", hr);
+            ok(iCp+1 == iCh, "ScriptStringXtoCP should return iCh = %d not %d for X = %d\n", iCh, iCp+1, X);
+            ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n", 
+                                   iTrailing, X);
+        }
+
+        hr = ScriptStringFree(&ssa);
+        ok(hr == S_OK, "ScriptStringFree should return S_OK not %08lx\n", hr);
+
+        /* Test to see that exceeding the number of chars returnS E_INVALIDARG */
+        hr = ScriptStringAnalyse( hdc, pString, cString, cGlyphs, iCharset, dwFlags,
+                                  iReqWidth, &psControl, &psState, NULL, &pTabdef,
+                                  &pbInClass, &ssa);
+        ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08lx\n", hr);
+
+        fTrailing = FALSE;
+        iCp = cString + 1; 
+        hr = ScriptStringCPtoX(ssa, iCp, fTrailing, &X);
+        ok(hr == E_INVALIDARG, "ScriptStringCPtoX should return E_INVALIDARG not %08lx\n", hr);
+
+        hr = ScriptStringFree(&ssa);
+        ok(hr == E_INVALIDARG, "ScriptStringFree should return E_INVALIDARG not %08lx\n", hr);    }
+}
+
 START_TEST(usp10)
 {
     HWND            hwnd;
@@ -1012,6 +1097,7 @@ START_TEST(usp10)
     test_ScriptXtoX();
     test_ScriptString();
     test_digit_substitution();
+    test_ScriptStringXtoCP_CPtoX(hdc);
 
     ReleaseDC(hwnd, hdc);
     DestroyWindow(hwnd);
diff --git a/dlls/usp10/usp10.c b/dlls/usp10/usp10.c
index e8fbe4f..df8c6c6 100644
--- a/dlls/usp10/usp10.c
+++ b/dlls/usp10/usp10.c
@@ -80,12 +80,13 @@ typedef struct script_string_analysis_pt
     int     *piAdvance;
     ABC     pABC;
     WORD    *pwLogClust;
-   GOFFSET *pGoffset;
+    GOFFSET *pGoffset;
     WORD    *pwOutGlyphs;
 } script_blk;
 
 typedef struct script_string_analysis 
 {
+    SCRIPT_STRING_ANALYSIS *self_pointer;
     HDC     hdc;
     int     cItems;
     int     cMaxGlyphs;
@@ -515,6 +516,7 @@ HRESULT WINAPI ScriptStringAnalyse(HDC h
     analysis = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(string_analysis));
     *pssa = analysis;
 
+    analysis->self_pointer = pssa;  /* required when to free up when not passed */
     analysis->hdc = hdc;
     analysis->pItem = HeapAlloc( GetProcessHeap(), 0, sizeof(SCRIPT_ITEM)*cMaxItems );
     hr = ScriptItemize(pString, cString, cMaxItems, psControl, 
@@ -632,8 +634,58 @@ HRESULT WINAPI ScriptStringOut(SCRIPT_ST
  */
 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
 {
-    FIXME("(%p), %d, %d, (%p): stub\n", ssa, icp, fTrailing, pX);
-    *pX = 0;                             /* Set a reasonable value */
+    string_analysis *analysis;
+    int   item, cnt = 0;
+    int   iPosX = 0;
+    float fMaxPosX = 0;
+    int   iMaxGlyphs = 0;
+    int   iGlyphs = 0;
+
+    TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
+
+    if  (!ssa) {
+        return E_INVALIDARG;
+    }
+    analysis = ssa;
+
+    print_ssa(ssa);
+
+    if  (icp < 0)                                      /* Before first char         */
+    {
+        *pX = 0;                                       /* Point to first char's     */
+        return S_OK;                                   /* leading edge              */
+    }
+
+    for (item = 0; item < analysis->cItems; item++)
+    {                                                  /* total piAdvance           */
+        for (cnt=0; cnt < analysis->script_blk[item].cGlyphs; cnt++)
+            fMaxPosX += analysis->script_blk[item].piAdvance[cnt];
+        iMaxGlyphs += analysis->script_blk[item].cGlyphs;
+    }
+
+    if  (icp >= iMaxGlyphs)                            /* Greater char count than   */
+    {                                                  /* is in the ssa structure.  */
+        ScriptStringFree(analysis->self_pointer);      /* Free the ssa using the    */
+        return E_INVALIDARG;                           /* addrees of the orig ssa   */
+    }
+
+    for (item = 0; item < analysis->cItems && iGlyphs <= icp; item++)
+    {                                                  /* Count piAdvance till posn reached */
+        for (cnt=0; cnt < analysis->script_blk[item].cGlyphs  
+                    &&  iGlyphs <= icp; cnt++, iGlyphs++)
+        {
+            iPosX += analysis->script_blk[item].piAdvance[cnt];
+            TRACE("cnt=%d iPosX=%d iGlyphs=%d\n", cnt, iPosX, iGlyphs);
+        }
+    }
+
+    if  (!fTrailing)                                   /* point to the leading edge */
+        iPosX -= analysis->script_blk[item-1].piAdvance[cnt-1];
+
+    *pX = iPosX;                                       /* Return the cursor posn */
+
+    TRACE("cnt=%d *pX=%d\n", cnt, *pX);
+
     return S_OK;
 }
 
@@ -643,9 +695,81 @@ HRESULT WINAPI ScriptStringCPtoX(SCRIPT_
  */
 HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing) 
 {
-    FIXME("(%p), %d, (%p), (%p): stub\n", ssa, iX, piCh, piTrailing);
-    *piCh = 0;                          /* Set a reasonable value */
-    *piTrailing = 0;
+    string_analysis *analysis;
+    int   item, cnt = 0;
+    int   iPosX = 0;
+    int   cChars = 0;
+    float fMaxPosX = 0;
+
+    TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
+
+    if  (!ssa) {
+        return E_INVALIDARG;
+    }
+
+    analysis = ssa;
+
+    if  (iX < 0)                                    /* iX is before start of run */
+    {
+        *piCh = -1;
+        *piTrailing = TRUE;
+        TRACE("iX=%d, *piCh=%d\n", iX, *piCh);
+        return S_OK;
+    }
+
+    if  (iX == 0)                                   /* iX is at the start, do no more */
+    {
+        *piCh = 0;
+        *piTrailing = FALSE;
+        TRACE("iX=%d, *piCh=%d\n", iX, *piCh);
+        return S_OK;
+    } 
+
+    for (item = 0; item < analysis->cItems; item++)
+    {                                               /* total piAdvance           */
+        for (cnt=0; cnt < analysis->script_blk[item].cGlyphs; cnt++)                {
+            fMaxPosX +=  analysis->script_blk[item].piAdvance[cnt];
+        }
+        cChars += analysis->pItem[item+1].iCharPos 
+                  - analysis->pItem[item].iCharPos;
+     }
+
+    if  (iX >= fMaxPosX)                            /* iX too large              */
+    {
+        *piCh = cChars;
+        *piTrailing = FALSE;
+        TRACE("iX=%d, fMaxPosX=%f, cChars=%d\n", iX, fMaxPosX, cChars);
+        return S_OK;
+    }        
+
+    cChars = 0;
+    for (item = 0; item < analysis->cItems  && iPosX < iX; item++)
+    {                                               /* total piAdvance           */
+        for (cnt=0; cnt < analysis->script_blk[item].cGlyphs
+                    && iPosX <= iX; cnt++)
+        {
+            TRACE("cnt=%d,  cGlyphs=%d, piAdvance=%d\n" , cnt, 
+                  analysis->script_blk[item].cGlyphs,
+                  analysis->script_blk[item].piAdvance[cnt]);
+            iPosX +=  analysis->script_blk[item].piAdvance[cnt];
+        }
+        if  (iPosX < iX)
+        {   /* keep track of the characters in script_items before this one.  cnt is the * 
+             * index to this script_item                                                 */
+            cChars += analysis->pItem[item+1].iCharPos - analysis->pItem[item].iCharPos;
+            TRACE("item=%d,  cChars=%d, cStr=%d\n" , item, cChars,
+                  analysis->pItem[item+1].iCharPos - analysis->pItem[item].iCharPos);
+        } 
+    }
+
+    if  (iPosX - iX > analysis->script_blk[item-1].piAdvance[cnt-1]/2)
+        *piTrailing = FALSE;
+    else
+        *piTrailing = TRUE;                         /* yep we are over half way  */
+    
+    *piCh = cChars + cnt -1;                        /* Return character position */
+    TRACE("*piCH=%d iPosX=%d piTrailing=%d (iPosX-iX)=%d\n", *piCh, iPosX, *piTrailing,
+          (iPosX-iX));
     return S_OK;
 }
 
-- 
1.4.1



More information about the wine-patches mailing list