RICHEDIT: RTF reader improvements and optimizations

Krzysztof Foltman kfoltman at portal.onet.pl
Wed Mar 16 14:05:04 CST 2005


ChangeLog:
  * RTF reader doesn't use RichEdit messages anymore (which saves on 
unnecessary repaints)
  * added unicode character support to RTF import (like: \u12345 ?)
  * small fixes
  * fixed embarassing ALLOC_N_OBJ bug (redundant, someone else submitted 
it too)
  * fixed whitespace identification bug
  * removed drawing of paragraph marks
  * improved stub implementations for IRichEditOle

Krzysztof
-------------- next part --------------
Index: caret.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/caret.c,v
retrieving revision 1.5
diff -u -r1.5 caret.c
--- caret.c	14 Mar 2005 10:08:00 -0000	1.5
+++ caret.c	16 Mar 2005 19:41:54 -0000
@@ -300,12 +300,6 @@
   assert(style);
   editor->bCaretAtEnd = FALSE;
 
-  /*
-  if (!style)
-    style = ME_GetInsertStyle(editor, nCursor);
-  else
-    ME_AddRefStyle(style);
-    */
   ME_AddRefStyle(style);
   
   /* FIXME really HERE ? */
@@ -800,8 +794,6 @@
     editor->pCursors[1] = editor->pCursors[0];
   else
     editor->pCursors[0] = editor->pCursors[1];
-  /* FIXME optimize */
-  ME_MarkAllForWrapping(editor);
   ME_Repaint(editor);
   return TRUE;
 }
@@ -809,14 +801,6 @@
 void ME_RepaintSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
 {
   ME_Cursor old_anchor = editor->pCursors[1];
-  BOOL bRedraw = FALSE;
-  bRedraw = memcmp(&editor->pCursors[0], &editor->pCursors[1], sizeof(ME_Cursor));
-  
-  if (bRedraw)
-  {
-    /* FIXME optimize */
-    ME_MarkAllForWrapping(editor);
-  }
   
   if (GetKeyState(VK_SHIFT)>=0) /* cancelling selection */
   {
@@ -915,6 +899,7 @@
       }
       if (ME_ArrowLeft(editor, p)) {
         editor->bCaretAtEnd = FALSE; /* FIXME or maybe not */
+        ME_ClearTempStyle(editor);
         ME_MoveCaret(editor);
         ME_DeleteTextAtCursor(editor, nCursor, 1);
         ME_UpdateRepaint(editor);
@@ -928,10 +913,12 @@
       if (ME_IsSelection(editor))
       {
         ME_DeleteSelection(editor);
+        ME_ClearTempStyle(editor);
         ME_UpdateRepaint(editor);
         return TRUE;
       }
       ME_DeleteTextAtCursor(editor, nCursor, 1);
+      ME_ClearTempStyle(editor);
       ME_UpdateRepaint(editor);
       return TRUE;
     }
Index: editor.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/editor.c,v
retrieving revision 1.13
diff -u -r1.13 editor.c
--- editor.c	16 Mar 2005 11:27:43 -0000	1.13
+++ editor.c	16 Mar 2005 19:41:54 -0000
@@ -277,7 +277,7 @@
 
 void ME_RTFCharAttrHook(RTF_Info *info)
 {
-  CHARFORMAT2A fmt;
+  CHARFORMAT2W fmt;
   fmt.cbSize = sizeof(fmt);
   fmt.dwMask = 0;
   
@@ -334,8 +334,8 @@
         RTFFont *f = RTFGetFont(info, info->rtfParam);
         if (f)
         {
-          strncpy(fmt.szFaceName, f->rtfFName, sizeof(fmt.szFaceName)-1);
-          fmt.szFaceName[sizeof(fmt.szFaceName)-1] = '\0';
+          MultiByteToWideChar(CP_ACP, 0, f->rtfFName, -1, fmt.szFaceName, sizeof(fmt.szFaceName)/sizeof(WCHAR));
+          fmt.szFaceName[sizeof(fmt.szFaceName)/sizeof(WCHAR)-1] = '\0';
           fmt.dwMask = CFM_FACE;
         }
       }
@@ -347,8 +347,12 @@
       break;
   }
   if (fmt.dwMask) {
+    ME_Style *style2;
     RTFFlushOutputBuffer(info);
-    SendMessageW(info->hwndEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
+    /* FIXME too slow ? how come ? */
+    style2 = ME_ApplyStyle(info->style, &fmt);
+    ME_ReleaseStyle(info->style);
+    info->style = style2;
   }
 }
 
@@ -380,7 +384,8 @@
   }  
   if (fmt.dwMask) {
     RTFFlushOutputBuffer(info);
-    SendMessageW(info->hwndEdit, EM_SETPARAFORMAT, 0, (LPARAM)&fmt);
+    /* FIXME too slow ? how come ?*/
+    ME_SetSelectionParaFormat(info->editor, &fmt);
   }
 }
 
@@ -393,17 +398,21 @@
         case rtfBeginGroup:
           if (info->formatStackTop < maxCharFormatStack) {
             info->formatStack[info->formatStackTop].cbSize = sizeof(info->formatStack[0]);
-            SendMessageW(info->hwndEdit, EM_GETCHARFORMAT, 1, (LPARAM)&info->formatStack[info->formatStackTop]);
+            memcpy(&info->formatStack[info->formatStackTop], &info->style->fmt, sizeof(CHARFORMAT2W));
           }
           info->formatStackTop++;
           break;
         case rtfEndGroup:
+        {
+          ME_Style *s;
           RTFFlushOutputBuffer(info);
           info->formatStackTop--;
-          if (info->formatStackTop < maxCharFormatStack) {
-            SendMessageW(info->hwndEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&info->formatStack[info->formatStackTop]);
-          }
+          /* FIXME too slow ? how come ? */
+          s = ME_ApplyStyle(info->style, &info->formatStack[info->formatStackTop]);
+          ME_ReleaseStyle(info->style);
+          info->style = s;
           break;
+        }
       }
       break;
     case rtfControl:
@@ -426,8 +435,10 @@
   ME_Style *style;
   int from, to, to2, nUndoMode;
   ME_UndoItem *pUI;
+  int nEventMask = editor->nEventMask;
 
   TRACE("%p %p\n", stream, editor->hWnd);
+  editor->nEventMask = 0;
   
   ME_GetSelection(editor, &from, &to);
   if (format & SFF_SELECTION) {
@@ -442,6 +453,7 @@
     ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor));
     from = to = 0;
     ME_ClearTempStyle(editor);
+    /* FIXME restore default paragraph formatting ! */
   }
   
   nUndoMode = editor->nUndoMode;
@@ -452,6 +464,8 @@
     RTFSetEditStream(&parser, stream);
     parser.rtfFormat = format&(SF_TEXT|SF_RTF);
     parser.hwndEdit = editor->hWnd;
+    parser.editor = editor;
+    parser.style = style;
     WriterInit(&parser);
     RTFInit(&parser);
     RTFSetReadHook(&parser, ME_RTFReadHook);
@@ -460,6 +474,8 @@
     /* do the parsing */
     RTFRead(&parser);
     RTFFlushOutputBuffer(&parser);
+
+    style = parser.style;
   }
   else if (format & SF_TEXT)
     ME_StreamInText(editor, format, stream, style);
@@ -483,7 +499,15 @@
     pUI->nLen = to-from;
   }
   ME_CommitUndo(editor);
-  ME_ReleaseStyle(style);
+  ME_ReleaseStyle(style); 
+  editor->nEventMask = nEventMask;
+  ME_UpdateRepaint(editor);
+  if (!(format & SFF_SELECTION)) {
+    ME_ClearTempStyle(editor);
+    ME_EnsureVisible(editor, editor->pCursors[0].pRun);
+  }
+  ME_MoveCaret(editor);
+  ME_SendSelChange(editor);
 
   return 0;
 }
@@ -817,6 +841,7 @@
   case EM_SETCHARFORMAT:
   {
     CHARFORMAT2W buf, *p;
+    BOOL bRepaint = TRUE;
     p = ME_ToCF2W(&buf, (CHARFORMAT2W *)lParam);
     if (!wParam)
       ME_SetDefaultCharFormat(editor, p);
@@ -824,10 +849,15 @@
       FIXME("word selection not supported\n");
     else if (wParam == SCF_ALL)
       ME_SetCharFormat(editor, 0, ME_GetTextLength(editor), p);
-    else
+    else {
+      int from, to;
+      ME_GetSelection(editor, &from, &to);
+      bRepaint = (from != to);
       ME_SetSelectionCharFormat(editor, p);
+    }
     ME_CommitUndo(editor);
-    ME_UpdateRepaint(editor);
+    if (bRepaint)
+      ME_UpdateRepaint(editor);
     return 0;
   }
   case EM_GETCHARFORMAT:
@@ -843,6 +873,7 @@
   }
   case EM_SETPARAFORMAT:
     ME_SetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam);
+    ME_UpdateRepaint(editor);
     ME_CommitUndo(editor);
     return 0;
   case EM_GETPARAFORMAT:
Index: editor.h
===================================================================
RCS file: /home/wine/wine/dlls/riched20/editor.h,v
retrieving revision 1.7
diff -u -r1.7 editor.h
--- editor.h	14 Mar 2005 21:41:16 -0000	1.7
+++ editor.h	16 Mar 2005 19:41:54 -0000
@@ -21,7 +21,7 @@
 #include "editstr.h"
 
 #define ALLOC_OBJ(type) (type *)HeapAlloc(me_heap, 0, sizeof(type))
-#define ALLOC_N_OBJ(type, count) (type *)HeapAlloc(me_heap, 0, count*sizeof(type))
+#define ALLOC_N_OBJ(type, count) (type *)HeapAlloc(me_heap, 0, (count)*sizeof(type))
 #define FREE_OBJ(ptr) HeapFree(me_heap, 0, ptr)
 
 /* style.c */
@@ -85,6 +85,10 @@
 LPSTR ME_ToAnsi(HWND hWnd, LPVOID psz);
 void ME_EndToAnsi(HWND hWnd, LPVOID psz);
 
+static inline int ME_IsWSpace(WCHAR ch)
+{
+  return ch > '\0' && ch <= ' ';
+}
 
 /* note: those two really return the first matching offset (starting from EOS)+1 
  * in other words, an offset of the first trailing white/black */
Index: paint.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/paint.c,v
retrieving revision 1.5
diff -u -r1.5 paint.c
--- paint.c	9 Mar 2005 18:43:18 -0000	1.5
+++ paint.c	16 Mar 2005 19:41:54 -0000
@@ -146,8 +146,8 @@
   ME_DisplayItem *pRun = NULL;
   int nOffset = -1;
   HDC hDC;
-  
   int nCharOfs = ME_CharOfsFromRunOfs(editor, pCursor->pRun, pCursor->nOffset);
+  
   ME_RunOfsFromCharOfs(editor, nCharOfs, &pRun, &nOffset);
   assert(pRun == pCursor->pRun);
   assert(nOffset == pCursor->nOffset);
@@ -244,6 +244,9 @@
   ME_Run *run = &rundi->member.run;
   int runofs = run->nCharOfs+para->nCharOfs;
   
+  /* you can always comment it out if you need visible paragraph marks */
+  if (run->nFlags & MERF_ENDPARA) 
+    return;
   if (run->nFlags & MERF_GRAPHICS) {
     int blfrom, blto;
     ME_GetSelection(c->editor, &blfrom, &blto);
Index: para.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/para.c,v
retrieving revision 1.2
diff -u -r1.2 para.c
--- para.c	9 Mar 2005 11:48:59 -0000	1.2
+++ para.c	16 Mar 2005 19:41:54 -0000
@@ -310,7 +310,6 @@
       break;
     para = para->member.para.next_para;
   } while(1);
-  ME_Repaint(editor);
 }
 
 void ME_GetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *pFmt)
Index: reader.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/reader.c,v
retrieving revision 1.6
diff -u -r1.6 reader.c
--- reader.c	16 Mar 2005 11:27:43 -0000	1.6
+++ reader.c	16 Mar 2005 19:41:55 -0000
@@ -42,12 +42,13 @@
 #include <stdlib.h>
 #include <assert.h>
 
-#include "rtf.h"
-
 #include "windef.h"
 #include "winbase.h"
 #include "wine/debug.h"
 
+#include "editor.h"
+#include "rtf.h"
+
 WINE_DEFAULT_DEBUG_CHANNEL(richedit);
 
 extern HANDLE me_heap;
@@ -68,6 +69,7 @@
 
 static void	CharSetInit (RTF_Info *);
 static void	ReadCharSetMaps (RTF_Info *);
+static void RTFOutputUnicodeString( RTF_Info *info, WCHAR *str, int len );
 
 
 /*
@@ -2452,6 +2454,7 @@
 	{ rtfSpecialChar,	rtfNoWidthNonJoiner,	"zwnj",		0 },
 	/* is this valid? */
 	{ rtfSpecialChar,	rtfCurHeadPict,		"chpict",	0 },
+	{ rtfSpecialChar,	rtfUnicode,		"u",	0 },
 
 	/*
 	 * Character formatting attributes
@@ -3698,7 +3701,6 @@
 		RTFSkipGroup (info);    
 }
 
-
 /*
  * The reason these use the rtfSC_xxx thingies instead of just writing
  * out ' ', '-', '"', etc., is so that the mapping for these characters
@@ -3721,6 +3723,22 @@
 		else
 			RTFRouteToken(info); /* "\*" is ignored with known destinations */
 		break;
+	case rtfUnicode:
+	{
+    WCHAR buf[2];
+    buf[0] = info->rtfParam;
+    buf[1] = 0;
+    RTFFlushOutputBuffer(info);
+    RTFOutputUnicodeString(info, buf, 1);
+    
+    RTFGetToken(info);
+	  if (info->rtfClass != rtfText && info->rtfMajor != '?')
+	  {
+	    ERR("The character behind \\u is not a question mark, but (%d,%d,%d)\n",
+	      info->rtfClass, info->rtfMajor, info->rtfMinor);
+	  }
+	  break;
+	}
 	case rtfPage:
 	case rtfSect:
 	case rtfRow:
@@ -3801,10 +3819,32 @@
 	info->OutputBuffer[info->dwOutputCount++] = c;
 }
 
+void RTFOutputANSIStringOrig( RTF_Info *info, char *str, int len )
+{
+	assert(str[len] == '\0');
+	if (len) {
+    SendMessageA( info->hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) str);
+  }
+}
+
 void RTFOutputANSIString( RTF_Info *info, char *str, int len )
 {
 	assert(str[len] == '\0');
-	if (len) SendMessageA( info->hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) str);
+	if (len) {
+    WCHAR *buf = ALLOC_N_OBJ(WCHAR, len);
+    
+    len = MultiByteToWideChar(CP_ACP, 0, str, len, buf, len);
+    ME_InsertTextFromCursor( info->editor, 0, buf, len, info->style );	  
+	  FREE_OBJ(buf);
+  }
+}
+
+void RTFOutputUnicodeString( RTF_Info *info, WCHAR *str, int len )
+{
+	assert(str[len] == '\0');
+	if (len) {
+    ME_InsertTextFromCursor( info->editor, 0, str, len, info->style );	  
+  }
 }
 
 void RTFFlushOutputBuffer( RTF_Info *info )
Index: richole.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/richole.c,v
retrieving revision 1.3
diff -u -r1.3 richole.c
--- richole.c	8 Mar 2005 16:46:00 -0000	1.3
+++ richole.c	16 Mar 2005 19:41:55 -0000
@@ -64,6 +64,7 @@
         *ppvObj = (LPVOID) This;
         return S_OK;
     }
+    FIXME("%p: unhandled interface %s\n", This, debugstr_guid(riid) );
  
     return E_NOINTERFACE;   
 }
@@ -215,7 +216,7 @@
                LPCSTR lpstrContainerApp, LPCSTR lpstrContainerObj)
 {
     IRichEditOleImpl *This = (IRichEditOleImpl *)me;
-    FIXME("stub %p\n",This);
+    FIXME("stub %p %s %s\n",This, lpstrContainerApp, lpstrContainerObj);
     return E_NOTIMPL;
 }
 
Index: rtf.h
===================================================================
RCS file: /home/wine/wine/dlls/riched20/rtf.h,v
retrieving revision 1.4
diff -u -r1.4 rtf.h
--- rtf.h	16 Mar 2005 11:27:43 -0000	1.4
+++ rtf.h	16 Mar 2005 19:41:55 -0000
@@ -625,6 +625,7 @@
 # define		rtfNoWidthNonJoiner	56	/* new in 1.10 */
 # define		rtfCurHeadPict		57	/* valid? */
 /*# define		rtfCurAnnot		58*/	/* apparently not used */
+# define    rtfUnicode      58  /* no better category*/
 
 # define	rtfStyleAttr	7
 # define		rtfAdditive		0	/* new in 1.10 */
@@ -1452,6 +1453,9 @@
 
     /* edit window to output to */
     HWND hwndEdit;
+    
+    ME_TextEditor *editor;
+    ME_Style *style;
 
     /*
      * These arrays are used to map RTF input character values onto the standard
Index: run.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/run.c,v
retrieving revision 1.5
diff -u -r1.5 run.c
--- run.c	11 Mar 2005 10:24:56 -0000	1.5
+++ run.c	16 Mar 2005 19:41:55 -0000
@@ -321,11 +321,6 @@
   return pDI;
 }
 
-static inline int ME_IsWSpace(WCHAR ch)
-{
-  return ch <= ' ';
-}
-
 void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run)
 {
   assert(run->nCharOfs != -1);
Index: string.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/string.c,v
retrieving revision 1.1
diff -u -r1.1 string.c
--- string.c	5 Mar 2005 11:19:14 -0000	1.1
+++ string.c	16 Mar 2005 19:41:55 -0000
@@ -112,7 +112,7 @@
 {
   /* FIXME multibyte */
   WCHAR *pos = s->szData;
-  while(*pos++ == ' ')
+  while(ME_IsWSpace(*pos++))
     ;
   pos--;
   if (*pos)
@@ -126,12 +126,12 @@
   /* FIXME multibyte */
   WCHAR *pos = s->szData;
   WCHAR ch;
-  while(*pos++ == L' ')
+  while(ME_IsWSpace(*pos++))
     ;
   pos--;
   while((ch = *pos++) != 0)
   {
-    if (ch == L' ')
+    if (ME_IsWSpace(*pos++))
       return 1;
   }
   return 0;
Index: wrap.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/wrap.c,v
retrieving revision 1.4
diff -u -r1.4 wrap.c
--- wrap.c	9 Mar 2005 18:43:18 -0000	1.4
+++ wrap.c	16 Mar 2005 19:41:56 -0000
@@ -274,10 +274,6 @@
         wc->bOverflown = FALSE;
         pp = ME_SplitRun(wc->context, p, black);
         p->member.run.nFlags |= MERF_SKIPPED;
-/*
-        run->pt = wc->pt;
-        wc->pt.x += run->nWidth;
-        */
         ME_InsertRowStart(wc, pp);
         return pp;
       }


More information about the wine-patches mailing list