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