Lei Zhang : riched20: Implements FR_WHOLEWORD for EM_FINDTEXT.
Alexandre Julliard
julliard at wine.codeweavers.com
Tue Mar 21 13:21:48 CST 2006
Module: wine
Branch: refs/heads/master
Commit: b4ee2ad0e4210861df16c30062cbb6af9b406914
URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=b4ee2ad0e4210861df16c30062cbb6af9b406914
Author: Lei Zhang <leiz at ucla.edu>
Date: Tue Mar 21 03:43:56 2006 -0800
riched20: Implements FR_WHOLEWORD for EM_FINDTEXT.
Add FR_WHOLEWORD to riched20's EM_FINDTEXT and fix a couple small bugs
introduced in earlier patches for EM_FINDTEXT. Additional test cases
have been added to check for corner cases. Also improve input
validation.
---
dlls/riched20/editor.c | 125 ++++++++++++++++++++++++++++++++++++++----
dlls/riched20/tests/editor.c | 10 +++
2 files changed, 121 insertions(+), 14 deletions(-)
diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c
index 506c706..bcb2a5c 100644
--- a/dlls/riched20/editor.c
+++ b/dlls/riched20/editor.c
@@ -764,34 +764,38 @@ ME_FindItemAtOffset(ME_TextEditor *edito
static int
ME_FindText(ME_TextEditor *editor, DWORD flags, CHARRANGE *chrg, WCHAR *text, CHARRANGE *chrgText)
{
+ const int nLen = lstrlenW(text);
+ const int nTextLen = ME_GetTextLength(editor);
int nStart, nEnd;
- int nLen = lstrlenW(text);
int nMin, nMax;
ME_DisplayItem *item;
ME_DisplayItem *para;
+ WCHAR wLastChar = ' ';
TRACE("flags==0x%08lx, chrg->cpMin==%ld, chrg->cpMax==%ld text==%s\n",
flags, chrg->cpMin, chrg->cpMax, debugstr_w(text));
- if (flags & ~(FR_DOWN | FR_MATCHCASE))
- FIXME("Flags 0x%08lx not implemented\n", flags & ~(FR_DOWN | FR_MATCHCASE));
+ if (flags & ~(FR_DOWN | FR_MATCHCASE | FR_WHOLEWORD))
+ FIXME("Flags 0x%08lx not implemented\n",
+ flags & ~(FR_DOWN | FR_MATCHCASE | FR_WHOLEWORD));
nMin = chrg->cpMin;
if (chrg->cpMax == -1)
- nMax = ME_GetTextLength(editor);
+ nMax = nTextLen;
else
- nMax = chrg->cpMax;
+ nMax = chrg->cpMax > nTextLen ? nTextLen : chrg->cpMax;
/* when searching up, if cpMin < cpMax, then instead of searching
* on [cpMin,cpMax], we search on [0,cpMin], otherwise, search on
- * [cpMax, cpMin]
+ * [cpMax, cpMin]. The exception is when cpMax is -1, in which
+ * case, it is always bigger than cpMin.
*/
if (!(flags & FR_DOWN))
{
int nSwap = nMax;
- nMax = nMin;
- if (nMin < nSwap)
+ nMax = nMin > nTextLen ? nTextLen : nMin;
+ if (nMin < nSwap || chrg->cpMax == -1)
nMin = 0;
else
nMin = nSwap;
@@ -806,6 +810,20 @@ ME_FindText(ME_TextEditor *editor, DWORD
if (flags & FR_DOWN) /* Forward search */
{
+ /* If possible, find the character before where the search starts */
+ if ((flags & FR_WHOLEWORD) && nMin)
+ {
+ nStart = nMin - 1;
+ item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart);
+ if (!item)
+ {
+ if (chrgText)
+ chrgText->cpMin = chrgText->cpMax = -1;
+ return -1;
+ }
+ wLastChar = item->member.run.strText->szData[nStart];
+ }
+
nStart = nMin;
item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart);
if (!item)
@@ -825,10 +843,35 @@ ME_FindText(ME_TextEditor *editor, DWORD
while (pCurItem && ME_CharCompare(pCurItem->member.run.strText->szData[nCurStart + nMatched], text[nMatched], (flags & FR_MATCHCASE)))
{
+ if ((flags & FR_WHOLEWORD) && isalnumW(wLastChar))
+ break;
+
nMatched++;
if (nMatched == nLen)
{
- nStart += para->member.para.nCharOfs + item->member.run.nCharOfs;
+ ME_DisplayItem *pNextItem = pCurItem;
+ int nNextStart = nCurStart;
+ WCHAR wNextChar;
+
+ /* Check to see if next character is a whitespace */
+ if (flags & FR_WHOLEWORD)
+ {
+ if (nCurStart + nMatched == ME_StrLen(pCurItem->member.run.strText))
+ {
+ pNextItem = ME_FindItemFwd(pCurItem, diRun);
+ nNextStart = -nMatched;
+ }
+
+ if (pNextItem)
+ wNextChar = pNextItem->member.run.strText->szData[nNextStart + nMatched];
+ else
+ wNextChar = ' ';
+
+ if (isalnumW(wNextChar))
+ break;
+ }
+
+ nStart += para->member.para.nCharOfs + pCurItem->member.run.nCharOfs;
if (chrgText)
{
chrgText->cpMin = nStart;
@@ -844,6 +887,11 @@ ME_FindText(ME_TextEditor *editor, DWORD
nCurStart = -nMatched;
}
}
+ if (pCurItem)
+ wLastChar = pCurItem->member.run.strText->szData[nCurStart + nMatched];
+ else
+ wLastChar = ' ';
+
nStart++;
if (nStart == ME_StrLen(item->member.run.strText))
{
@@ -855,9 +903,24 @@ ME_FindText(ME_TextEditor *editor, DWORD
}
else /* Backward search */
{
+ /* If possible, find the character after where the search ends */
+ if ((flags & FR_WHOLEWORD) && nMax < nTextLen - 1)
+ {
+ nEnd = nMax + 1;
+ item = ME_FindItemAtOffset(editor, diRun, nEnd, &nEnd);
+ if (!item)
+ {
+ if (chrgText)
+ chrgText->cpMin = chrgText->cpMax = -1;
+ return -1;
+ }
+ wLastChar = item->member.run.strText->szData[nEnd];
+ }
+
nEnd = nMax;
item = ME_FindItemAtOffset(editor, diRun, nEnd, &nEnd);
- if (!item) {
+ if (!item)
+ {
if (chrgText)
chrgText->cpMin = chrgText->cpMax = -1;
return -1;
@@ -872,12 +935,45 @@ ME_FindText(ME_TextEditor *editor, DWORD
int nCurEnd = nEnd;
int nMatched = 0;
- while (ME_CharCompare(pCurItem->member.run.strText->szData[nCurEnd - nMatched - 1], text[nLen - nMatched - 1], (flags & FR_MATCHCASE)))
+ if (nCurEnd - nMatched == 0)
{
+ pCurItem = ME_FindItemBack(pCurItem, diRun);
+ para = ME_GetParagraph(pCurItem);
+ nCurEnd = ME_StrLen(pCurItem->member.run.strText) + nMatched;
+ }
+
+ while (pCurItem && ME_CharCompare(pCurItem->member.run.strText->szData[nCurEnd - nMatched - 1], text[nLen - nMatched - 1], (flags & FR_MATCHCASE)))
+ {
+ if ((flags & FR_WHOLEWORD) && isalnumW(wLastChar))
+ break;
+
nMatched++;
if (nMatched == nLen)
{
- nStart = para->member.para.nCharOfs + item->member.run.nCharOfs + nCurEnd - nMatched;
+ ME_DisplayItem *pPrevItem = pCurItem;
+ int nPrevEnd = nCurEnd;
+ WCHAR wPrevChar;
+
+ /* Check to see if previous character is a whitespace */
+ if (flags & FR_WHOLEWORD)
+ {
+ if (nPrevEnd - nMatched == 0)
+ {
+ pPrevItem = ME_FindItemBack(pCurItem, diRun);
+ if (pPrevItem)
+ nPrevEnd = ME_StrLen(pPrevItem->member.run.strText) + nMatched;
+ }
+
+ if (pPrevItem)
+ wPrevChar = pPrevItem->member.run.strText->szData[nPrevEnd - nMatched - 1];
+ else
+ wPrevChar = ' ';
+
+ if (isalnumW(wPrevChar))
+ break;
+ }
+
+ nStart = para->member.para.nCharOfs + pCurItem->member.run.nCharOfs + nCurEnd - nMatched;
if (chrgText)
{
chrgText->cpMin = nStart;
@@ -895,6 +991,11 @@ ME_FindText(ME_TextEditor *editor, DWORD
nCurEnd = ME_StrLen(pCurItem->member.run.strText) + nMatched;
}
}
+ if (pCurItem)
+ wLastChar = pCurItem->member.run.strText->szData[nCurEnd - nMatched - 1];
+ else
+ wLastChar = ' ';
+
nEnd--;
if (nEnd < 0)
{
diff --git a/dlls/riched20/tests/editor.c b/dlls/riched20/tests/editor.c
index 95cf705..fa5abca 100644
--- a/dlls/riched20/tests/editor.c
+++ b/dlls/riched20/tests/editor.c
@@ -92,10 +92,16 @@ struct find_s find_tests2[] = {
{10, 5, "", 0, -1, 0},
/* Whole-word search */
- {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 1},
- {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1, 1},
+ {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0},
+ {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1, 0},
+ {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0},
+ {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0, 0},
+ {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23, 0},
+ {11, -1, "winewine", FR_WHOLEWORD, 0, 0},
+ {31, -1, "winewine", FR_WHOLEWORD, 23, 0},
/* Bad ranges */
+ {5, 200, "XXX", FR_DOWN, -1, 0},
{-20, 20, "Wine", FR_DOWN, -1, 0},
{-20, 20, "Wine", FR_DOWN, -1, 0},
{-15, -20, "Wine", FR_DOWN, -1, 0},
More information about the wine-cvs
mailing list