Module: wine Branch: refs/heads/master Commit: b4ee2ad0e4210861df16c30062cbb6af9b406914 URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=b4ee2ad0e4210861df16c300...
Author: Lei Zhang leiz@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},