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