usp10 1/3: Implement ScriptStringAnalysis and ScriptStringFree

Jeff L lats at yless4u.com.au
Wed Oct 11 16:06:55 CDT 2006


The patch is the first implementing ScriptString functions.  It replaces
the previous patch by reducing the functionality to the smallest
meaningful set.  The functions test out ok using scriptstring.exe from
http://www.catch22.net/tuts/editor12.asp .  Testing this function is
difficult as the results are intermediate and opaque.

All documentation has been written by me.

Jeff Latimer

Changelog:
Implement ScriptStringAnalysis and ScriptStringFree

-------------- next part --------------
>From adf54a287046a8072e635701241bc638b11f3e45 Mon Sep 17 00:00:00 2001
From: Jeff Latimer <lats at yless4u.com.au>
Date: Wed, 11 Oct 2006 20:12:54 +1000
Subject: [PATCH] Implement ScriptStringAnalysis and ScriptStringFree
---
 dlls/usp10/tests/usp10.c |   39 ++++---
 dlls/usp10/usp10.c       |  268 ++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 278 insertions(+), 29 deletions(-)

diff --git a/dlls/usp10/tests/usp10.c b/dlls/usp10/tests/usp10.c
index 378bf68..0c32bd0 100644
--- a/dlls/usp10/tests/usp10.c
+++ b/dlls/usp10/tests/usp10.c
@@ -606,11 +606,10 @@ static void test_ScriptString(void)
     HRESULT         hr;
     HWND            hwnd;
     HDC             hdc = 0;
-    WCHAR           teststr[] = {'T', 'e', 's', 't', 'a', '\0'};
-    void            *pString = (WCHAR *) &teststr;
-    int             cString = 5;
+    WCHAR           teststr[] = {'T','e','s','t','1',' ','a','2','b','3', '\0'};
+    int             cString = (sizeof(teststr)/sizeof(WCHAR))-1;
     int             cGlyphs = cString * 2 + 16;
-    int             iCharset = -1;
+    int             iCharset;
     DWORD           dwFlags = SSA_GLYPHS;
     int             iReqWidth = 100;
     SCRIPT_CONTROL  psControl;
@@ -647,31 +646,39 @@ static void test_ScriptString(void)
     lf.lfOrientation = 0;
     lf.lfUnderline = 0;
     lf.lfStrikeOut = 0;
-    lf.lfWeight = 3;
+    lf.lfWeight = 300;
     lf.lfWidth = 10;
 
     zfont = (HFONT) SelectObject(hdc, CreateFontIndirectA(&lf));
  
+    iCharset = -1;    /* indicate unicode input */
     /* Test without hdc to get E_INVALIDARG */
-    hr = ScriptStringAnalyse( NULL, pString, cString, cGlyphs, iCharset, dwFlags,
+    hr = ScriptStringAnalyse( NULL, teststr, cString, cGlyphs, iCharset, dwFlags,
                              iReqWidth, &psControl, &psState, piDx, &pTabdef,
                              &pbInClass, &pssa);
     ok(hr == E_PENDING, "ScriptStringAnalyse Stub should return E_PENDING not %08x\n", hr);
 
     /* test with hdc, this should be a valid test  */
-    hr = ScriptStringAnalyse( hdc, pString, cString, cGlyphs, iCharset, dwFlags,
+    hr = ScriptStringAnalyse( hdc, teststr, cString, cGlyphs, iCharset, dwFlags,
+                              iReqWidth, &psControl, &psState, piDx, &pTabdef,
+                              &pbInClass, &pssa);
+    ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
+
+    /* test makes sure that a call with a valid pssa still works */
+    hr = ScriptStringAnalyse( hdc, teststr, cString, cGlyphs, iCharset, dwFlags,
                               iReqWidth, &psControl, &psState, piDx, &pTabdef,
                               &pbInClass, &pssa);
-    ok(hr == E_NOTIMPL, "ScriptStringAnalyse Stub should return E_NOTIMPL not %08x\n", hr);
-/*    Commented code it pending new code in ScriptStringAnalysis */
-/*    ok(hr == S_OK, "ScriptStringAnalyse Stub should return S_OK not %08x\n", (unsigned int) hr);*/
-/*    ok(pssa != NULL, "ScriptStringAnalyse pssa should not be NULL\n");*/
+    ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08lx\n", hr);
+    ok(pssa != NULL, "ScriptStringAnalyse pssa should not be NULL\n");
+
     if  (hr == 0)
     {
         hr = ScriptStringOut(pssa, iX, iY, uOptions, &prc, iMinSel, iMaxSel,fDisabled);
-        ok(hr == E_NOTIMPL, "ScriptStringOut Stub should return E_NOTIMPL not %08x\n", hr);
+        todo_wine {
+            ok(hr == S_OK, "ScriptStringOut should return S_OK not %08x\n", hr);
+        }
         hr = ScriptStringFree(&pssa);
-        ok(hr == S_OK, "ScriptStringFree Stub should return S_OK not %08x\n", hr);
+        ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
     }
 }
 
@@ -1049,9 +1056,6 @@ START_TEST(usp10)
     test_ScriptCacheGetHeight(hdc);
     test_ScriptGetGlyphABCWidth(hdc);
 
-    ReleaseDC(hwnd, hdc);
-    DestroyWindow(hwnd);
-
     test_ScriptGetFontProperties();
     test_ScriptTextOut();
     test_ScriptXtoX();
@@ -1059,4 +1063,7 @@ START_TEST(usp10)
     test_ScriptLayout();
 
     test_digit_substitution();
+
+    ReleaseDC(hwnd, hdc);
+    DestroyWindow(hwnd);
 }
diff --git a/dlls/usp10/usp10.c b/dlls/usp10/usp10.c
index 8bcd38b..b814cb2 100644
--- a/dlls/usp10/usp10.c
+++ b/dlls/usp10/usp10.c
@@ -73,6 +73,36 @@ typedef struct scriptcache {
        HDC hdc;
 } Scriptcache;
 
+/*
+ * This structure contains the intermediate results from processing string elements
+ * within ScriptStringAnalyse
+ */
+typedef struct script_string_analysis_ptrs
+{
+    int     Glyphs;         /* number of glyphs in an item   */
+    SCRIPT_VISATTR *sva;    /* array of visual attribs       */
+    int     *Advance;       /* array of adavance widths      */
+    ABC     ABC;            /* total ABC widths for the item */     
+    WORD    *LogClust;      /* logical clusters for item     */
+    GOFFSET *Goffset;       /* x and y offsets               */
+    WORD    *OutGlyphs;     /* the generated glyphs          */
+} script_blk;
+
+/*
+ * This structure contains the global attribtutes for the entire string
+ * representd by SCRIPT_STRING_ANALYSIS pointer.  This structure is created by
+ * ScriptStringAnalysis
+ */
+typedef struct script_string_analysis 
+{
+    HDC     hdc;
+    SCRIPT_CACHE sc;        /* script cache used by intermediate script functions */
+    int     num_Items;      /* number of string items found */
+    int     num_Glyphs;     /* number of glyphs generated   */
+    script_blk *script_blk; /* ptr to the array of attribs matching the s_Items */
+    SCRIPT_ITEM *s_Item;    /* ptr to the array of string items from ScriptIemize */
+} string_analysis;
+
 /***********************************************************************
  *      DllMain
  *
@@ -89,6 +119,35 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, 
     return TRUE;
 }
 
+void print_ssa (SCRIPT_STRING_ANALYSIS *pssa)
+{
+    /*
+     * Output the contents of the script string analysis cache for diagnostics
+     */
+    int  item;
+    string_analysis *analysis;
+    analysis = (string_analysis*)pssa;
+    TRACE("Start print of SCRIPT_STRING_ANALYSIS\n");
+    TRACE("    analysis(%p): ", analysis);
+    if  (analysis)
+    {
+        TRACE(" hdc:%08lx num_Items:%d num_Glyphs:%d script_blk(%p) s_Item(%p)", 
+             (unsigned long int)analysis->hdc, analysis->num_Items,
+             analysis->num_Glyphs,
+             &analysis->script_blk, &analysis->s_Item);
+        if  (analysis->script_blk)
+        {
+            for (item=0; item < analysis->num_Items; item++)
+            {
+                TRACE(" {item:%d Glyphs:%d OutGlyphs(%p)}", item,
+                      analysis->script_blk[item].Glyphs,
+                      analysis->script_blk[item].OutGlyphs);
+            }
+        }
+        TRACE("\n");
+    }
+}
+
 /***********************************************************************
  *      ScriptFreeCache (USP10.@)
  *
@@ -447,18 +506,160 @@ HRESULT WINAPI ScriptStringAnalyse(HDC h
 				   SCRIPT_TABDEF *pTabdef,
 				   const BYTE *pbInClass,
 				   SCRIPT_STRING_ANALYSIS *pssa)
+/******************************************************************************
+ *
+ * Analyse a string using the Uniscribe primatives and store the results for 
+ * further processing.  Each has its own SCRIPT_STRING_ANALYSIS structure that 
+ * stores all the details of the run.  The processing is:
+ *     call ScriptItemize to analyse the string
+ *     repeatedly call ScriptShape and ScriptPlace to process the string items.
+ *
+ * Parameters:
+ *  hdc       [I] Device Context
+ *  pString   [I] pointer to the string to analyse
+ *  cString   [I] length of the string
+ *  cGlyphs   [I} length of the glyph buffer
+ *  iCharset  [I] character set descriptor
+ *  dwFlags   [I] flags controling analysis processing
+ *  iReqWidth [I] width required after clipping
+ *  psControl [I] control structure
+ *  psState   [I] state structure
+ *  piDx      [I] a logical array of Dx values
+ *  pTabDef   [I] a TabDef structure
+ *  pbInClass [I] GetCharacterPlacement classes
+ *  pssa      [O] buffer to hold the analysed string components
+ */
+
 {
-  FIXME("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p): stub\n",
-	hdc, pString, cString, cGlyphs, iCharset, dwFlags,
-	iReqWidth, psControl, psState, piDx, pTabdef, pbInClass, pssa);
-  if (1 > cString || NULL == pString) {
-    return E_INVALIDARG;
-  }
-  if ((dwFlags & SSA_GLYPHS) && NULL == hdc) {
-    return E_PENDING;
-  }
-
-  return E_NOTIMPL;
+    HRESULT hr;
+    WCHAR   *Str;
+    int     max_Items;
+    int     fnd_Items;
+    string_analysis *analysis;
+    int     item, item_len, max_glyphs;
+
+    TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
+         hdc, pString, cString, cGlyphs, iCharset, dwFlags,
+         iReqWidth, psControl, psState, piDx, pTabdef, pbInClass, pssa);
+
+    /*
+     *  Check parameters meet the API spec
+     */
+    if  (cString < 1 ||  pString == NULL) /* Must have a string and at least one charater */
+        return E_INVALIDARG;
+
+
+    if  ((dwFlags & SSA_GLYPHS) && hdc == NULL)
+    {
+        TRACE("For SSA_GLYPHS, hdc can't be NULL - dwFlags=%08lx, hdc(%p)\n", dwFlags, hdc);
+        return E_PENDING;
+    }
+
+    if  (iCharset != -1)
+    {
+        FIXME("ASCII Charsets not implemented - Charset=%08x\n", iCharset);
+        return E_NOTIMPL;
+    }
+
+    /*
+     * This pssa could be different to the one that was used to allocate the storage
+     * initially.  Ideally we should free the storage but we don't know if the point
+     * is still valid.  To fix this we need to use an object list to record valid 
+     * storage objects so that an accurate check of allocated storage can be done.
+     */
+    if  (*pssa)                     /* If allocated, clean it out and start again  */
+        FIXME("Should call ScriptStringFree but can't be sure that it has not already been called\n");
+
+    /* 
+     * Allocate the block to contain the global parameters for the string and the pointers
+     * to individual string elements and save the address as *pssa
+     */
+    analysis = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(string_analysis));
+    *pssa = analysis;
+
+    analysis->hdc = hdc;
+    max_Items = 256;                /* Pick an abritary number of s_Items */
+    analysis->s_Item = HeapAlloc( GetProcessHeap(), 0, sizeof(SCRIPT_ITEM)*max_Items );
+
+    /* 
+     * Here we break the string into items using ScriptItemize.  The array of s_Item 
+     * contains the details of the break of each item.  If there are too many items for 
+     * the array it must be reallocated.
+     */
+
+    hr = ScriptItemize(pString, cString, max_Items, psControl, psState, analysis->s_Item, &fnd_Items);
+
+    while (hr == E_OUTOFMEMORY)     /* too many items for the the array of s_Items realloc it */
+    {
+        max_Items *= 2;             /* double the count and reallocate the buffer */  
+        analysis->s_Item = HeapReAlloc( GetProcessHeap(), 0, analysis->s_Item, 
+                                       sizeof(SCRIPT_ITEM)*max_Items );
+        hr = ScriptItemize(pString, cString, max_Items, psControl, psState, 
+                           analysis->s_Item, &fnd_Items);
+        TRACE("ScriptItemize hr=%08lx max_Items=%d\n", hr, max_Items);
+    }
+
+    analysis->num_Items = fnd_Items;     /* Save the count of items found in the string */
+    /*
+     * Now we know the number of items we can allocate storage for the script_blk structures 
+     * to contain the information relating to the item as returned by ScriptShape and 
+     * ScriptPlace
+     */
+    analysis->script_blk = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
+                                      sizeof(script_blk)*fnd_Items);
+    TRACE("(%p) (%p) num_Items %d, fnd_Items=%d\n", analysis, &analysis->script_blk, 
+                                                    analysis->num_Items, fnd_Items);
+
+    /*
+     * For each item found in the string, allocate storage for the outputs of ScriptShape and
+     * ScriptPlace in the matching script_blk.  Note, in the section pString is of type void
+     * and can't be used with subscripts, hence Str of type WCHAR is used instead.
+     */
+
+    Str = (WCHAR *)pString;                       /* cast from void to WCHAR for ptr arithmetic */
+    analysis->sc = NULL;                          /* initialise script cache for script functions */
+    for (item = 0; item < fnd_Items; item++)
+    {
+        /*
+         * calc the length of the item from the start and end positions and the size
+         * of the buffer to contain glyphs and the supporting data
+         */
+        item_len = analysis->s_Item[item+1].iCharPos - analysis->s_Item[item].iCharPos;
+        max_glyphs = item_len * 1.5 + 16;
+
+        analysis->script_blk[item].OutGlyphs = HeapAlloc( GetProcessHeap(), 
+                                                          0, sizeof(WORD)*max_glyphs);
+        analysis->script_blk[item].Advance = HeapAlloc( GetProcessHeap(), 
+                                                          0, sizeof(WORD)*max_glyphs);
+        analysis->script_blk[item].Goffset = HeapAlloc( GetProcessHeap(), 
+                                                          0, sizeof(GOFFSET)*max_glyphs);
+        analysis->script_blk[item].sva = HeapAlloc( GetProcessHeap(), 
+                                                          0, sizeof(SCRIPT_VISATTR)*max_glyphs);
+        analysis->script_blk[item].LogClust = HeapAlloc( GetProcessHeap(), 
+                                                          0, sizeof(WORD)*max_glyphs);
+
+        hr = ScriptShape(hdc, &analysis->sc, &Str[analysis->s_Item[item].iCharPos], item_len, 
+                        max_glyphs, &analysis->s_Item[item].a,
+                        analysis->script_blk[item].OutGlyphs, 
+                        analysis->script_blk[item].LogClust, 
+                        analysis->script_blk[item].sva, 
+                        &analysis->script_blk[item].Glyphs);
+        hr = ScriptPlace(hdc, &analysis->sc, analysis->script_blk[item].OutGlyphs, 
+                        analysis->script_blk[item].Glyphs, 
+                        analysis->script_blk[item].sva, 
+                        &analysis->s_Item[item].a,
+                        analysis->script_blk[item].Advance, 
+                        analysis->script_blk[item].Goffset, 
+                        &analysis->script_blk[item].ABC);
+
+        /* 
+         * add the number of glyphs from this item to the total glyph count 
+         */
+        analysis->num_Glyphs += analysis->script_blk[item].Glyphs;
+    }
+
+    print_ssa(*pssa);                             /* Trace the analysis structure */
+    return S_OK;
 }
 
 /***********************************************************************
@@ -510,8 +711,49 @@ HRESULT WINAPI ScriptStringXtoCP(SCRIPT_
  *      ScriptStringFree (USP10.@)
  *
  */
-HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa) {
-    FIXME("(%p): stub\n",pssa);
+HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa) 
+/******************************************************************************
+ *
+ * Free storage associated ScriptString functions
+ *
+ * Parameter:
+ *  pssa      [I/O] buffer to hold the analysed string components
+ *
+ */
+{
+    string_analysis *analysis;
+    int  item;
+
+    TRACE("(%p)\n", pssa);
+
+    if  (!*pssa)
+    {
+        return E_INVALIDARG;
+    }
+    else
+    {
+        print_ssa(*pssa);
+        analysis = * pssa;                                     /* map ptr to string_analysis */
+        HeapFree(GetProcessHeap(), 0, analysis->s_Item);
+        if  (analysis->script_blk)
+        {
+            for (item = 0; item < analysis->num_Items; item++) /* Free the storage associated */
+            {                                                  /* with each script_blk        */
+                HeapFree(GetProcessHeap(), 0, analysis->script_blk[item].sva);
+                HeapFree(GetProcessHeap(), 0, analysis->script_blk[item].Advance);
+                HeapFree(GetProcessHeap(), 0, analysis->script_blk[item].Goffset);
+                HeapFree(GetProcessHeap(), 0, analysis->script_blk[item].OutGlyphs);
+            }
+            HeapFree(GetProcessHeap(), 0, analysis->script_blk);
+        }
+
+        if  (analysis->sc)
+            ScriptFreeCache(analysis->sc);  /* clean up the sc as we have finished this run */
+
+        HeapFree(GetProcessHeap(), 0, analysis);
+        *pssa = NULL;
+    }
+
     return S_OK;
 }
 
-- 
1.4.1



More information about the wine-patches mailing list