Uniscribe improvements
* *
richardvoigt at gmail.com
Tue Jan 2 12:42:25 CST 2007
StringAnalysis should have a cache object, not save the HDC directly.
One of the important things about the cache, which wine currently
doesn't do, is that the caller is free to select a different font into
the HDC after calling ScriptStringAnalyse and Uniscribe is supposed to
use the right one.
I had also implemented ScriptStringOut, but while messing with
Direct3D crashes, someone beat me to the patch. I had been calling
ScriptTextOut for each run returned by ScriptItemize, I still think
that is more correct than combining everything into a single string.
But I used the accepted version of ScriptStringOut with just a couple
additions.
-------------- next part --------------
From 233c6a2bc519c15b0a383ce3d227cd69d6206c98 Mon Sep 17 00:00:00 2001
From: Richard Voigt richardvoigt at gmail.com <ben at gondor.lan>
Date: Tue, 2 Jan 2007 12:40:59 -0600
Subject: In Uniscribe, save cache and not HDC directly, also cleanup ScriptItemize and fix buffer overflow caused by bad info on MSDN
---
dlls/usp10/usp10.c | 180 +++++++++++++++++++++++++++------------------------
1 files changed, 95 insertions(+), 85 deletions(-)
diff --git a/dlls/usp10/usp10.c b/dlls/usp10/usp10.c
index 0334e93..02ec3be 100644
--- a/dlls/usp10/usp10.c
+++ b/dlls/usp10/usp10.c
@@ -159,7 +159,7 @@ typedef struct {
typedef struct {
BOOL invalid;
- HDC hdc;
+ SCRIPT_CACHE cache;
int cItems;
int cMaxGlyphs;
SCRIPT_ITEM* pItem;
@@ -402,8 +402,12 @@ HRESULT WINAPI ScriptItemize(const WCHAR
#define Script_Latin 1
#define Script_Numeric 5
- int cnt = 0, index = 0;
- int New_Script = SCRIPT_UNDEFINED;
+ int cnt = 0;
+ int New_Script;
+ int PrevScript = -1;
+ SCRIPT_ITEM *pItem = pItems;
+ SCRIPT_ITEM *pEndItem = pItems + cMaxItems; /* points to required extra "terminal item" */
+ WCHAR wc;
TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems,
psControl, psState, pItems, pcItems);
@@ -411,75 +415,50 @@ HRESULT WINAPI ScriptItemize(const WCHAR
if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
return E_INVALIDARG;
- pItems[index].iCharPos = 0;
- memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
-
- if (pwcInChars[cnt] >= Numeric_start && pwcInChars[cnt] <= Numeric_stop)
- pItems[index].a.eScript = Script_Numeric;
- else
- if (pwcInChars[cnt] >= Arabic_start && pwcInChars[cnt] <= Arabic_stop)
- pItems[index].a.eScript = Script_Arabic;
- else
- if (pwcInChars[cnt] >= Latin_start && pwcInChars[cnt] <= Latin_stop)
- pItems[index].a.eScript = Script_Latin;
-
- if (pItems[index].a.eScript == Script_Arabic)
- pItems[index].a.s.uBidiLevel = 1;
+ wc = *pwcInChars;
+ goto DetermineScript;
+
+ do {
+ TRACE("New_Script=%d, cnt=%d\n", New_Script, cnt);
+ pItem->iCharPos = cnt;
+ memset(&pItem->a, 0, sizeof(SCRIPT_ANALYSIS));
+ pItem->a.eScript = PrevScript = New_Script;
+ if (New_Script == Script_Arabic)
+ pItem->a.s.uBidiLevel = 1;
+ pItem++;
+
+ do {
+ /* From MSDN, "The function always adds a terminal item to the item analysis array..." */
+ if (++cnt >= cInChars) {
+ pItem->iCharPos = cnt;
+ memset(&pItem->a, 0, sizeof(SCRIPT_ANALYSIS));
+ *pcItems = pItem - pItems;
+
+ return S_OK;
+ }
- TRACE("New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
- New_Script, pItems[index].a.eScript, index, cnt,
- pItems[index].iCharPos = cnt);
+ wc = pwcInChars[cnt];
+ if (wc == Numeric_space) {
+ /* space character can't change script */;
+ continue;
+ }
- for (cnt=0; cnt < cInChars; cnt++)
- {
- if ((pwcInChars[cnt] >= Numeric_start && pwcInChars[cnt] <= Numeric_stop)
- || (New_Script == Script_Numeric && pwcInChars[cnt] == Numeric_space))
+ DetermineScript:
+ if (wc >= Numeric_start && wc <= Numeric_stop)
New_Script = Script_Numeric;
else
- if ((pwcInChars[cnt] >= Arabic_start && pwcInChars[cnt] <= Arabic_stop)
- || (New_Script == Script_Arabic && pwcInChars[cnt] == Numeric_space))
+ if (wc >= Arabic_start && wc <= Arabic_stop)
New_Script = Script_Arabic;
else
- if ((WCHAR) pwcInChars[cnt] >= Latin_start && (WCHAR) pwcInChars[cnt] <= Latin_stop)
+ if (wc >= Latin_start && wc <= Latin_stop)
New_Script = Script_Latin;
else
New_Script = SCRIPT_UNDEFINED;
-
- if (New_Script != pItems[index].a.eScript)
- {
- TRACE("New_Script=%d, eScript=%d ", New_Script, pItems[index].a.eScript);
- index++;
- if (index+1 > cMaxItems)
- return E_OUTOFMEMORY;
-
- pItems[index].iCharPos = cnt;
- memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
-
- if (New_Script == Script_Arabic)
- pItems[index].a.s.uBidiLevel = 1;
-
- pItems[index].a.eScript = New_Script;
- if (New_Script == Script_Arabic)
- pItems[index].a.s.uBidiLevel = 1;
-
- TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos = cnt);
- }
- }
-
- /* 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));
-
- TRACE("index=%d cnt=%d iCharPos=%d\n", index+1, cnt, pItems[index+1].iCharPos = cnt);
+ } while (New_Script == PrevScript);
+ /* script changed, advance pItem, if space permits */
+ } while (pItem < pEndItem);
- /* Set one SCRIPT_STATE item being returned */
- *pcItems = index + 1;
-
- /* Set SCRIPT_ITEM */
- pItems[index+1].iCharPos = cnt; /* the last + 1 item
- contains the ptr to the lastchar */
- return S_OK;
+ return E_OUTOFMEMORY;
}
/***********************************************************************
@@ -504,7 +483,7 @@ HRESULT WINAPI ScriptStringAnalyse(HDC h
StringAnalysis* analysis;
int numItemizedItems;
int i;
- SCRIPT_CACHE* sc = 0;
+ SCRIPT_CACHE* sc = NULL;
TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
hdc, pString, cString, cGlyphs, iCharset, dwFlags,
@@ -519,21 +498,30 @@ HRESULT WINAPI ScriptStringAnalyse(HDC h
analysis = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(StringAnalysis));
- analysis->hdc = hdc;
+ sc = &analysis->cache;
+ *sc = NULL;
+ get_script_cache(hdc, sc);
+ if (analysis->cache == NULL) {
+ TRACE("Couldn't make cache object\n");
+ }
numItemizedItems = 255;
analysis->pItem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
- numItemizedItems*sizeof(SCRIPT_ITEM)+1);
-
- hr = ScriptItemize(pString, cString, numItemizedItems, psControl,
- psState, analysis->pItem, &analysis->numItems);
+ (numItemizedItems+1)*sizeof(SCRIPT_ITEM));
+ if (analysis->pItem == NULL) {
+ HeapFree(GetProcessHeap(), 0, analysis);
+ return E_OUTOFMEMORY;
+ }
- while(hr == E_OUTOFMEMORY)
+ while(E_OUTOFMEMORY == ScriptItemize(pString, cString, numItemizedItems, psControl,
+ psState, analysis->pItem, &analysis->numItems))
{
numItemizedItems *= 2;
- HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, analysis->pItem,
- numItemizedItems*sizeof(SCRIPT_ITEM)+1);
- hr = ScriptItemize(pString, cString, numItemizedItems, psControl,
- psState, analysis->pItem, &analysis->numItems);
+ if (NULL == HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, analysis->pItem,
+ (numItemizedItems+1)*sizeof(SCRIPT_ITEM))) {
+ HeapFree(GetProcessHeap(), 0, analysis->pItem);
+ HeapFree(GetProcessHeap(), 0, analysis);
+ return E_OUTOFMEMORY;
+ }
}
if ((analysis->logattrs = HeapAlloc(GetProcessHeap(), 0, sizeof(SCRIPT_LOGATTR) * cString)))
@@ -541,7 +529,6 @@ HRESULT WINAPI ScriptStringAnalyse(HDC h
analysis->glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(StringGlyphs)*analysis->numItems);
- sc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SCRIPT_CACHE));
for(i=0; i<analysis->numItems; i++)
{
@@ -572,10 +559,10 @@ HRESULT WINAPI ScriptStringAnalyse(HDC h
analysis->glyphs[i].abc = abc;
}
- HeapFree(GetProcessHeap(), 0, sc);
-
*pssa = analysis;
+ TRACE("ScriptStringAnalyse success, StringAnalysis struct at %p\n", analysis);
+
return S_OK;
}
@@ -612,14 +599,32 @@ HRESULT WINAPI ScriptStringOut(SCRIPT_ST
StringAnalysis *analysis;
WORD *glyphs;
int item, cnt, x;
+ HDC hdc;
HRESULT hr;
SCRIPT_CACHE sc = 0;
- TRACE("(%p,%d,%d,0x%1x,%p,%d,%d,%d)\n",
- ssa, iX, iY, uOptions, prc, iMinSel, iMaxSel, fDisabled);
+ if (iMinSel < iMaxSel) {
+ FIXME("(%p,%d,%d,0x%1x,%p,%d,%d,%d): semi-stub, selection highlight not implemented\n",
+ ssa, iX, iY, uOptions, prc, iMinSel, iMaxSel, fDisabled);
+ }
+ else
+ TRACE("(%p,%d,%d,0x%1x,%p,%d,%d,%d)\n",
+ ssa, iX, iY, uOptions, prc, iMinSel, iMaxSel, fDisabled);
analysis = ssa; /* map ptr to string_analysis struct */
+ hdc = ((ScriptCache*)analysis->cache)->hdc;
+ if (uOptions & ETO_OPAQUE) {
+ /* if ETO_OPAQUE is set, fill rectangle with background once beforehand, then draw text transparently */
+ /* this allows runs of text to overlap properly */
+ WCHAR c;
+ ExtTextOutW(hdc, iX, iY, prc, ETO_OPAQUE, &c, 0, NULL);
+ uOptions &= ~ETO_OPAQUE;
+ }
+
+ /* TODO: handle hard line breaks and word wrap */
+ /* TODO: handle highlights */
+
/*
* Get storage for the output buffer for the consolidated strings
*/
@@ -656,7 +661,7 @@ HRESULT WINAPI ScriptStringOut(SCRIPT_ST
cnt += analysis->glyphs[item].numGlyphs; /* point to the end of the copied text */
}
- hr = ScriptTextOut(analysis->hdc, &sc, iX, iY, uOptions, prc, &analysis->pItem->a,
+ hr = ScriptTextOut(hdc, &sc, iX, iY, uOptions, prc, &analysis->pItem->a,
NULL, 0, glyphs, cnt, analysis->glyphs->piAdvance, NULL,
analysis->glyphs->pGoffset);
TRACE("ScriptTextOut hr=%08x\n", hr);
@@ -807,6 +812,7 @@ HRESULT WINAPI ScriptStringFree(SCRIPT_S
HeapFree(GetProcessHeap(), 0, analysis->pItem);
HeapFree(GetProcessHeap(), 0, analysis->logattrs);
HeapFree(GetProcessHeap(), 0, analysis->sz);
+ ScriptFreeCache(&analysis->cache);
HeapFree(GetProcessHeap(), 0, analysis);
if(invalid)
@@ -1140,9 +1146,11 @@ HRESULT WINAPI ScriptShape(HDC hdc, SCRI
if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
if ((hr = get_script_cache(hdc, psc))) return hr;
- TRACE("Before: ");
- for (cnt = 0; cnt < cChars; cnt++)
- TRACE("%4x",pwcChars[cnt]);
+ TRACE("Before:");
+ for( cnt = 0; cnt < cChars; cnt++ ) {
+ if ((cChars > 16) && ((cnt & 0xf) == 0)) TRACE("\n");
+ TRACE(" %04x",pwcChars[cnt]);
+ }
TRACE("\n");
if (!psa->fNoGlyphIndex) { /* Glyph translate */
@@ -1151,15 +1159,17 @@ HRESULT WINAPI ScriptShape(HDC hdc, SCRI
TRACE("After: ");
for (cnt = 0; cnt < cChars; cnt++) {
- TRACE("%04x",pwOutGlyphs[cnt]);
+ if ((cChars > 16) && ((cnt & 0xf) == 0)) TRACE("\n");
+ TRACE(" %04x",pwOutGlyphs[cnt]);
}
TRACE("\n");
}
else {
TRACE("After: ");
for (cnt = 0; cnt < cChars; cnt++) { /* no translate so set up */
+ if ((cChars > 16) && ((cnt & 0xf) == 0)) TRACE("\n");
pwOutGlyphs[cnt] = pwcChars[cnt]; /* copy in to out and */
- TRACE("%04x",pwOutGlyphs[cnt]);
+ TRACE(" %04x",pwOutGlyphs[cnt]);
}
TRACE("\n");
}
@@ -1483,7 +1493,7 @@ const SIZE * WINAPI ScriptString_pSize(S
* appropriate place so that we can just pass cached
* values here.
*/
- if (!GetTextMetricsW(analysis->hdc, &metric))
+ if (!GetTextMetricsW(((ScriptCache*)analysis->cache)->hdc, &metric))
{
HeapFree(GetProcessHeap(), 0, analysis->sz);
analysis->sz = NULL;
--
1.4.4.1
More information about the wine-patches
mailing list