~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/riched20/editor.c

Version: ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * RichEdit - functions dealing with editor object
  3  *
  4  * Copyright 2004 by Krzysztof Foltman
  5  * Copyright 2005 by Cihan Altinay
  6  * Copyright 2005 by Phil Krylov
  7  * Copyright 2008 Eric Pouech
  8  *
  9  * This library is free software; you can redistribute it and/or
 10  * modify it under the terms of the GNU Lesser General Public
 11  * License as published by the Free Software Foundation; either
 12  * version 2.1 of the License, or (at your option) any later version.
 13  *
 14  * This library is distributed in the hope that it will be useful,
 15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17  * Lesser General Public License for more details.
 18  *
 19  * You should have received a copy of the GNU Lesser General Public
 20  * License along with this library; if not, write to the Free Software
 21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 22  */
 23 
 24 /* 
 25   API implementation status:
 26   
 27   Messages (ANSI versions not done yet)
 28   + EM_AUTOURLDETECT 2.0
 29   + EM_CANPASTE
 30   + EM_CANREDO 2.0
 31   + EM_CANUNDO
 32   + EM_CHARFROMPOS
 33   - EM_DISPLAYBAND
 34   + EM_EMPTYUNDOBUFFER
 35   + EM_EXGETSEL
 36   + EM_EXLIMITTEXT
 37   + EM_EXLINEFROMCHAR
 38   + EM_EXSETSEL
 39   + EM_FINDTEXT (only FR_DOWN flag implemented)
 40   + EM_FINDTEXTEX (only FR_DOWN flag implemented)
 41   - EM_FINDWORDBREAK
 42   - EM_FMTLINES
 43   - EM_FORMATRANGE
 44   + EM_GETAUTOURLDETECT 2.0
 45   - EM_GETBIDIOPTIONS 3.0
 46   - EM_GETCHARFORMAT (partly done)
 47   - EM_GETEDITSTYLE
 48   + EM_GETEVENTMASK
 49   + EM_GETFIRSTVISIBLELINE (can be optimized if needed)
 50   - EM_GETIMECOLOR 1.0asian
 51   - EM_GETIMECOMPMODE 2.0
 52   - EM_GETIMEOPTIONS 1.0asian
 53   - EM_GETIMESTATUS
 54   - EM_GETLANGOPTIONS 2.0
 55   + EM_GETLIMITTEXT
 56   + EM_GETLINE
 57   + EM_GETLINECOUNT   returns number of rows, not of paragraphs
 58   + EM_GETMODIFY
 59   - EM_GETOLEINTERFACE
 60   + EM_GETOPTIONS
 61   + EM_GETPARAFORMAT
 62   + EM_GETPASSWORDCHAR 2.0
 63   - EM_GETPUNCTUATION 1.0asian
 64   + EM_GETRECT
 65   - EM_GETREDONAME 2.0
 66   + EM_GETSEL
 67   + EM_GETSELTEXT (ANSI&Unicode)
 68   + EM_GETSCROLLPOS 3.0 (only Y value valid)
 69 ! - EM_GETTHUMB
 70   + EM_GETTEXTEX 2.0
 71   + EM_GETTEXTLENGTHEX (GTL_PRECISE unimplemented)
 72   - EM_GETTEXTMODE 2.0
 73 ? + EM_GETTEXTRANGE (ANSI&Unicode)
 74   - EM_GETTYPOGRAPHYOPTIONS 3.0
 75   - EM_GETUNDONAME
 76   + EM_GETWORDBREAKPROC
 77   - EM_GETWORDBREAKPROCEX
 78   - EM_GETWORDWRAPMODE 1.0asian
 79   + EM_GETZOOM 3.0
 80   + EM_HIDESELECTION
 81   + EM_LIMITTEXT (Also called EM_SETLIMITTEXT)
 82   + EM_LINEFROMCHAR
 83   + EM_LINEINDEX
 84   + EM_LINELENGTH
 85   + EM_LINESCROLL
 86   - EM_PASTESPECIAL
 87   + EM_POSFROMCHAR
 88   + EM_REDO 2.0
 89   + EM_REQUESTRESIZE
 90   + EM_REPLACESEL (proper style?) ANSI&Unicode
 91   + EM_SCROLL
 92   + EM_SCROLLCARET
 93   - EM_SELECTIONTYPE
 94   - EM_SETBIDIOPTIONS 3.0
 95   + EM_SETBKGNDCOLOR
 96   + EM_SETCHARFORMAT (partly done, no ANSI)
 97   - EM_SETEDITSTYLE
 98   + EM_SETEVENTMASK (few notifications supported)
 99   - EM_SETFONTSIZE
100   - EM_SETIMECOLOR 1.0asian
101   - EM_SETIMEOPTIONS 1.0asian
102   - EM_SETLANGOPTIONS 2.0
103   - EM_SETLIMITTEXT
104   + EM_SETMODIFY (not sure if implementation is correct)
105   - EM_SETOLECALLBACK
106   + EM_SETOPTIONS (partially implemented)
107   - EM_SETPALETTE 2.0
108   + EM_SETPARAFORMAT
109   + EM_SETPASSWORDCHAR 2.0
110   - EM_SETPUNCTUATION 1.0asian
111   + EM_SETREADONLY no beep on modification attempt
112   + EM_SETRECT
113   + EM_SETRECTNP (EM_SETRECT without repainting)
114   + EM_SETSEL
115   + EM_SETSCROLLPOS 3.0
116   - EM_SETTABSTOPS 3.0
117   - EM_SETTARGETDEVICE (partial)
118   + EM_SETTEXTEX 3.0 (proper style?)
119   - EM_SETTEXTMODE 2.0
120   - EM_SETTYPOGRAPHYOPTIONS 3.0
121   + EM_SETUNDOLIMIT 2.0
122   + EM_SETWORDBREAKPROC (used only for word movement at the moment)
123   - EM_SETWORDBREAKPROCEX
124   - EM_SETWORDWRAPMODE 1.0asian
125   + EM_SETZOOM 3.0
126   + EM_SHOWSCROLLBAR 2.0
127   + EM_STOPGROUPTYPING 2.0
128   + EM_STREAMIN
129   + EM_STREAMOUT
130   + EM_UNDO
131   + WM_CHAR
132   + WM_CLEAR
133   + WM_COPY
134   + WM_CUT
135   + WM_GETDLGCODE (the current implementation is incomplete)
136   + WM_GETTEXT (ANSI&Unicode)
137   + WM_GETTEXTLENGTH (ANSI version sucks)
138   + WM_PASTE
139   + WM_SETFONT
140   + WM_SETTEXT (resets undo stack !) (proper style?) ANSI&Unicode
141   - WM_STYLECHANGING
142   - WM_STYLECHANGED (things like read-only flag)
143   + WM_UNICHAR
144 
145   Notifications
146 
147   * EN_CHANGE (sent from the wrong place)
148   - EN_CORRECTTEXT
149   - EN_DROPFILES
150   - EN_ERRSPACE
151   - EN_HSCROLL
152   - EN_IMECHANGE
153   + EN_KILLFOCUS
154   - EN_LINK
155   - EN_MAXTEXT
156   - EN_MSGFILTER
157   - EN_OLEOPFAILED
158   - EN_PROTECTED
159   + EN_REQUESTRESIZE
160   - EN_SAVECLIPBOARD
161   + EN_SELCHANGE 
162   + EN_SETFOCUS
163   - EN_STOPNOUNDO
164   * EN_UPDATE (sent from the wrong place)
165   - EN_VSCROLL
166   
167   Styles
168   
169   - ES_AUTOHSCROLL
170   - ES_AUTOVSCROLL
171   - ES_CENTER
172   + ES_DISABLENOSCROLL (scrollbar is always visible)
173   - ES_EX_NOCALLOLEINIT
174   - ES_LEFT
175   - ES_MULTILINE (currently single line controls aren't supported)
176   - ES_NOIME
177   - ES_READONLY (I'm not sure if beeping is the proper behaviour)
178   - ES_RIGHT
179   - ES_SAVESEL
180   - ES_SELFIME
181   - ES_SUNKEN
182   - ES_VERTICAL
183   - ES_WANTRETURN (don't know how to do WM_GETDLGCODE part)
184   - WS_SETFONT
185   - WS_HSCROLL
186   + WS_VSCROLL
187 */
188 
189 /*
190  * RICHED20 TODO (incomplete):
191  *
192  * - messages/styles/notifications listed above 
193  * - add remaining CHARFORMAT/PARAFORMAT fields
194  * - right/center align should strip spaces from the beginning
195  * - pictures/OLE objects (not just smiling faces that lack API support ;-) )
196  * - COM interface (looks like a major pain in the TODO list)
197  * - calculate heights of pictures (half-done)
198  * - horizontal scrolling (not even started)
199  * - hysteresis during wrapping (related to scrollbars appearing/disappearing)
200  * - find/replace
201  * - how to implement EM_FORMATRANGE and EM_DISPLAYBAND ? (Mission Impossible)
202  * - italic caret with italic fonts
203  * - IME
204  * - most notifications aren't sent at all (the most important ones are)
205  * - when should EN_SELCHANGE be sent after text change ? (before/after EN_UPDATE?)
206  * - WM_SETTEXT may use wrong style (but I'm 80% sure it's OK)
207  * - EM_GETCHARFORMAT with SCF_SELECTION may not behave 100% like in original (but very close)
208  * - full justification
209  * - hyphenation
210  * - tables
211  * - ListBox & ComboBox not implemented
212  *
213  * Bugs that are probably fixed, but not so easy to verify:
214  * - EN_UPDATE/EN_CHANGE are handled very incorrectly (should be OK now)
215  * - undo for ME_JoinParagraphs doesn't store paragraph format ? (it does)
216  * - check/fix artificial EOL logic (bCursorAtEnd, hardly logical)
217  * - caret shouldn't be displayed when selection isn't empty
218  * - check refcounting in style management functions (looks perfect now, but no bugs is suspicious)
219  * - undo for setting default format (done, might be buggy)
220  * - styles might be not released properly (looks like they work like charm, but who knows?
221  *
222  */
223 
224 #include "editor.h"
225 #include "commdlg.h"
226 #include "winreg.h"
227 #define NO_SHLWAPI_STREAM 
228 #include "shlwapi.h"
229 #include "rtf.h"
230 #include "imm.h"
231 #include "res.h"
232 
233 #define STACK_SIZE_DEFAULT  100
234 #define STACK_SIZE_MAX     1000
235 
236 #define TEXT_LIMIT_DEFAULT 32767
237  
238 WINE_DEFAULT_DEBUG_CHANNEL(richedit);
239 
240 static BOOL ME_RegisterEditorClass(HINSTANCE);
241 
242 static const WCHAR RichEdit20W[] = {'R', 'i', 'c', 'h', 'E', 'd', 'i', 't', '2', '', 'W', 0};
243 static const WCHAR RichEdit50W[] = {'R', 'i', 'c', 'h', 'E', 'd', 'i', 't', '5', '', 'W', 0};
244 static const WCHAR REListBox20W[] = {'R','E','L','i','s','t','B','o','x','2','','W', 0};
245 static const WCHAR REComboBox20W[] = {'R','E','C','o','m','b','o','B','o','x','2','','W', 0};
246 static HCURSOR hLeft;
247 
248 int me_debug = 0;
249 HANDLE me_heap = NULL;
250 
251 static BOOL ME_ListBoxRegistered = FALSE;
252 static BOOL ME_ComboBoxRegistered = FALSE;
253 
254 static inline int is_version_nt(void)
255 {
256     return !(GetVersion() & 0x80000000);
257 }
258 
259 static ME_TextBuffer *ME_MakeText(void) {
260   
261   ME_TextBuffer *buf = ALLOC_OBJ(ME_TextBuffer);
262 
263   ME_DisplayItem *p1 = ME_MakeDI(diTextStart);
264   ME_DisplayItem *p2 = ME_MakeDI(diTextEnd);
265   
266   p1->prev = NULL;
267   p1->next = p2;
268   p2->prev = p1;
269   p2->next = NULL;
270   p1->member.para.next_para = p2;
271   p2->member.para.prev_para = p1;
272   p2->member.para.nCharOfs = 0;  
273   
274   buf->pFirst = p1;
275   buf->pLast = p2;
276   buf->pCharStyle = NULL;
277   
278   return buf;
279 }
280 
281 
282 static LRESULT ME_StreamInText(ME_TextEditor *editor, DWORD dwFormat, ME_InStream *stream, ME_Style *style)
283 {
284   WCHAR wszText[STREAMIN_BUFFER_SIZE+1];
285   WCHAR *pText;
286   
287   TRACE("%08x %p\n", dwFormat, stream);
288   
289   do {
290     long nWideChars = 0;
291 
292     if (!stream->dwSize)
293     {
294       ME_StreamInFill(stream);
295       if (stream->editstream->dwError)
296         break;
297       if (!stream->dwSize)
298         break;
299     }
300       
301     if (!(dwFormat & SF_UNICODE))
302     {
303       /* FIXME? this is doomed to fail on true MBCS like UTF-8, luckily they're unlikely to be used as CP_ACP */
304       nWideChars = MultiByteToWideChar(CP_ACP, 0, stream->buffer, stream->dwSize, wszText, STREAMIN_BUFFER_SIZE);
305       pText = wszText;
306     }
307     else
308     {
309       nWideChars = stream->dwSize >> 1;
310       pText = (WCHAR *)stream->buffer;
311     }
312     
313     ME_InsertTextFromCursor(editor, 0, pText, nWideChars, style);
314     if (stream->dwSize == 0)
315       break;
316     stream->dwSize = 0;
317   } while(1);
318   ME_CommitUndo(editor);
319   ME_UpdateRepaint(editor);
320   return 0;
321 }
322 
323 static void ME_ApplyBorderProperties(RTF_Info *info,
324                                      ME_BorderRect *borderRect,
325                                      RTFBorder *borderDef)
326 {
327   int i, colorNum;
328   ME_Border *pBorders[] = {&borderRect->top,
329                            &borderRect->left,
330                            &borderRect->bottom,
331                            &borderRect->right};
332   for (i = 0; i < 4; i++)
333   {
334     RTFColor *colorDef = info->colorList;
335     pBorders[i]->width = borderDef[i].width;
336     colorNum = borderDef[i].color;
337     while (colorDef && colorDef->rtfCNum != colorNum)
338       colorDef = colorDef->rtfNextColor;
339     if (colorDef)
340       pBorders[i]->colorRef = RGB(
341                            colorDef->rtfCRed >= 0 ? colorDef->rtfCRed : 0,
342                            colorDef->rtfCGreen >= 0 ? colorDef->rtfCGreen : 0,
343                            colorDef->rtfCBlue >= 0 ? colorDef->rtfCBlue : 0);
344     else
345       pBorders[i]->colorRef = RGB(0, 0, 0);
346   }
347 }
348 
349 void ME_RTFCharAttrHook(RTF_Info *info)
350 {
351   CHARFORMAT2W fmt;
352   fmt.cbSize = sizeof(fmt);
353   fmt.dwMask = 0;
354   fmt.dwEffects = 0;
355 
356   switch(info->rtfMinor)
357   {
358     case rtfPlain:
359       /* FIXME add more flags once they're implemented */
360       fmt.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINETYPE | CFM_STRIKEOUT | CFM_COLOR | CFM_BACKCOLOR | CFM_SIZE | CFM_WEIGHT;
361       fmt.dwEffects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR;
362       fmt.yHeight = 12*20; /* 12pt */
363       fmt.wWeight = FW_NORMAL;
364       fmt.bUnderlineType = CFU_UNDERLINENONE;
365       break;
366     case rtfBold:
367       fmt.dwMask = CFM_BOLD | CFM_WEIGHT;
368       fmt.dwEffects = info->rtfParam ? CFE_BOLD : 0;
369       fmt.wWeight = info->rtfParam ? FW_BOLD : FW_NORMAL;
370       break;
371     case rtfItalic:
372       fmt.dwMask = CFM_ITALIC;
373       fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
374       break;
375     case rtfUnderline:
376       fmt.dwMask = CFM_UNDERLINETYPE;
377       fmt.bUnderlineType = info->rtfParam ? CFU_CF1UNDERLINE : CFU_UNDERLINENONE;
378       break;
379     case rtfDotUnderline:
380       fmt.dwMask = CFM_UNDERLINETYPE;
381       fmt.bUnderlineType = info->rtfParam ? CFU_UNDERLINEDOTTED : CFU_UNDERLINENONE;
382       break;
383     case rtfDbUnderline:
384       fmt.dwMask = CFM_UNDERLINETYPE;
385       fmt.bUnderlineType = info->rtfParam ? CFU_UNDERLINEDOUBLE : CFU_UNDERLINENONE;
386       break;
387     case rtfWordUnderline:
388       fmt.dwMask = CFM_UNDERLINETYPE;
389       fmt.bUnderlineType = info->rtfParam ? CFU_UNDERLINEWORD : CFU_UNDERLINENONE;
390       break;
391     case rtfNoUnderline:
392       fmt.dwMask = CFM_UNDERLINETYPE;
393       fmt.bUnderlineType = CFU_UNDERLINENONE;
394       break;
395     case rtfStrikeThru:
396       fmt.dwMask = CFM_STRIKEOUT;
397       fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
398       break;
399     case rtfSubScript:
400     case rtfSuperScript:
401     case rtfSubScrShrink:
402     case rtfSuperScrShrink:
403     case rtfNoSuperSub:
404       fmt.dwMask = CFM_SUBSCRIPT|CFM_SUPERSCRIPT;
405       if (info->rtfMinor == rtfSubScrShrink) fmt.dwEffects = CFE_SUBSCRIPT;
406       if (info->rtfMinor == rtfSuperScrShrink) fmt.dwEffects = CFE_SUPERSCRIPT;
407       if (info->rtfMinor == rtfNoSuperSub) fmt.dwEffects = 0;
408       break;
409     case rtfInvisible:
410       fmt.dwMask = CFM_HIDDEN;
411       fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
412       break;
413     case rtfBackColor:
414       fmt.dwMask = CFM_BACKCOLOR;
415       fmt.dwEffects = 0;
416       if (info->rtfParam == 0)
417         fmt.dwEffects = CFE_AUTOBACKCOLOR;
418       else if (info->rtfParam != rtfNoParam)
419       {
420         RTFColor *c = RTFGetColor(info, info->rtfParam);
421         fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed);
422       }
423       break;
424     case rtfForeColor:
425       fmt.dwMask = CFM_COLOR;
426       fmt.dwEffects = 0;
427       if (info->rtfParam == 0)
428         fmt.dwEffects = CFE_AUTOCOLOR;
429       else if (info->rtfParam != rtfNoParam)
430       {
431         RTFColor *c = RTFGetColor(info, info->rtfParam);
432         if (c)
433           fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed);
434         else
435           fmt.crTextColor = 0;
436       }
437       break;
438     case rtfFontNum:
439       if (info->rtfParam != rtfNoParam)
440       {
441         RTFFont *f = RTFGetFont(info, info->rtfParam);
442         if (f)
443         {
444           MultiByteToWideChar(CP_ACP, 0, f->rtfFName, -1, fmt.szFaceName, sizeof(fmt.szFaceName)/sizeof(WCHAR));
445           fmt.szFaceName[sizeof(fmt.szFaceName)/sizeof(WCHAR)-1] = '\0';
446           fmt.bCharSet = f->rtfFCharSet;
447           fmt.dwMask = CFM_FACE | CFM_CHARSET;
448           fmt.bPitchAndFamily = f->rtfFPitch | (f->rtfFFamily << 4);
449         }
450       }
451       break;
452     case rtfFontSize:
453       fmt.dwMask = CFM_SIZE;
454       if (info->rtfParam != rtfNoParam)
455         fmt.yHeight = info->rtfParam*10;
456       break;
457   }
458   if (fmt.dwMask) {
459     ME_Style *style2;
460     RTFFlushOutputBuffer(info);
461     /* FIXME too slow ? how come ? */
462     style2 = ME_ApplyStyle(info->style, &fmt);
463     ME_ReleaseStyle(info->style);
464     info->style = style2;
465     info->styleChanged = TRUE;
466   }
467 }
468 
469 /* FIXME this function doesn't get any information about context of the RTF tag, which is very bad,
470    the same tags mean different things in different contexts */
471 void ME_RTFParAttrHook(RTF_Info *info)
472 {
473   PARAFORMAT2 fmt;
474   fmt.cbSize = sizeof(fmt);
475   fmt.dwMask = 0;
476   
477   switch(info->rtfMinor)
478   {
479   case rtfParDef: /* restores default paragraph attributes */
480     if (!info->editor->bEmulateVersion10) /* v4.1 */
481       info->borderType = RTFBorderParaLeft;
482     else /* v1.0 - 3.0 */
483       info->borderType = RTFBorderParaTop;
484     fmt.dwMask = PFM_ALIGNMENT | PFM_BORDER | PFM_LINESPACING | PFM_TABSTOPS |
485         PFM_OFFSET | PFM_RIGHTINDENT | PFM_SPACEAFTER | PFM_SPACEBEFORE |
486         PFM_STARTINDENT;
487     /* TODO: numbering, shading */
488     fmt.wAlignment = PFA_LEFT;
489     fmt.cTabCount = 0;
490     fmt.dxOffset = fmt.dxStartIndent = fmt.dxRightIndent = 0;
491     fmt.wBorderWidth = fmt.wBorders = 0;
492     fmt.wBorderSpace = 0;
493     fmt.bLineSpacingRule = 0;
494     fmt.dySpaceBefore = fmt.dySpaceAfter = 0;
495     fmt.dyLineSpacing = 0;
496     if (!info->editor->bEmulateVersion10) /* v4.1 */
497     {
498       if (info->tableDef && info->tableDef->tableRowStart &&
499           info->tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND)
500       {
501         ME_Cursor cursor;
502         ME_DisplayItem *para;
503         /* We are just after a table row. */
504         RTFFlushOutputBuffer(info);
505         cursor = info->editor->pCursors[0];
506         para = ME_GetParagraph(cursor.pRun);
507         if (para  == info->tableDef->tableRowStart->member.para.next_para
508             && !cursor.nOffset && !cursor.pRun->member.run.nCharOfs)
509         {
510           /* Since the table row end, no text has been inserted, and the \intbl
511            * control word has not be used.  We can confirm that we are not in a
512            * table anymore.
513            */
514           info->tableDef->tableRowStart = NULL;
515           info->canInheritInTbl = FALSE;
516         }
517       }
518     } else { /* v1.0 - v3.0 */
519       fmt.dwMask |= PFM_TABLE;
520       fmt.wEffects &= ~PFE_TABLE;
521     }
522     break;
523   case rtfNestLevel:
524     if (!info->editor->bEmulateVersion10) /* v4.1 */
525     {
526       while (info->rtfParam > info->nestingLevel) {
527         RTFTable *tableDef = ALLOC_OBJ(RTFTable);
528         ZeroMemory(tableDef, sizeof(RTFTable));
529         tableDef->parent = info->tableDef;
530         info->tableDef = tableDef;
531 
532         RTFFlushOutputBuffer(info);
533         if (tableDef->tableRowStart &&
534             tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND)
535         {
536           ME_DisplayItem *para = tableDef->tableRowStart;
537           para = para->member.para.next_para;
538           para = ME_InsertTableRowStartAtParagraph(info->editor, para);
539           tableDef->tableRowStart = para;
540         } else {
541           ME_Cursor cursor;
542           WCHAR endl = '\r';
543           cursor = info->editor->pCursors[0];
544           if (cursor.nOffset || cursor.pRun->member.run.nCharOfs)
545             ME_InsertTextFromCursor(info->editor, 0, &endl, 1, info->style);
546           tableDef->tableRowStart = ME_InsertTableRowStartFromCursor(info->editor);
547         }
548 
549         info->nestingLevel++;
550       }
551       info->canInheritInTbl = FALSE;
552     }
553     break;
554   case rtfInTable:
555   {
556     if (!info->editor->bEmulateVersion10) /* v4.1 */
557     {
558       if (info->nestingLevel < 1)
559       {
560         RTFTable *tableDef;
561         if (!info->tableDef)
562         {
563             info->tableDef = ALLOC_OBJ(RTFTable);
564             ZeroMemory(info->tableDef, sizeof(RTFTable));
565         }
566         tableDef = info->tableDef;
567         RTFFlushOutputBuffer(info);
568         if (tableDef->tableRowStart &&
569             tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND)
570         {
571           ME_DisplayItem *para = tableDef->tableRowStart;
572           para = para->member.para.next_para;
573           para = ME_InsertTableRowStartAtParagraph(info->editor, para);
574           tableDef->tableRowStart = para;
575         } else {
576           ME_Cursor cursor;
577           WCHAR endl = '\r';
578           cursor = info->editor->pCursors[0];
579           if (cursor.nOffset || cursor.pRun->member.run.nCharOfs)
580             ME_InsertTextFromCursor(info->editor, 0, &endl, 1, info->style);
581           tableDef->tableRowStart = ME_InsertTableRowStartFromCursor(info->editor);
582         }
583         info->nestingLevel = 1;
584         info->canInheritInTbl = TRUE;
585       }
586       return;
587     } else { /* v1.0 - v3.0 */
588       fmt.dwMask |= PFM_TABLE;
589       fmt.wEffects |= PFE_TABLE;
590     }
591     break;
592   }
593   case rtfFirstIndent:
594     ME_GetSelectionParaFormat(info->editor, &fmt);
595     fmt.dwMask = PFM_STARTINDENT | PFM_OFFSET;
596     fmt.dxStartIndent += fmt.dxOffset + info->rtfParam;
597     fmt.dxOffset = -info->rtfParam;
598     break;
599   case rtfLeftIndent:
600     ME_GetSelectionParaFormat(info->editor, &fmt);
601     fmt.dwMask = PFM_STARTINDENT;
602     fmt.dxStartIndent = info->rtfParam - fmt.dxOffset;
603     break;
604   case rtfRightIndent:
605     fmt.dwMask = PFM_RIGHTINDENT;
606     fmt.dxRightIndent = info->rtfParam;
607     break;
608   case rtfQuadLeft:
609   case rtfQuadJust:
610     fmt.dwMask = PFM_ALIGNMENT;
611     fmt.wAlignment = PFA_LEFT;
612     break;
613   case rtfQuadRight:
614     fmt.dwMask = PFM_ALIGNMENT;
615     fmt.wAlignment = PFA_RIGHT;
616     break;
617   case rtfQuadCenter:
618     fmt.dwMask = PFM_ALIGNMENT;
619     fmt.wAlignment = PFA_CENTER;
620     break;
621   case rtfTabPos:
622     ME_GetSelectionParaFormat(info->editor, &fmt);
623     if (!(fmt.dwMask & PFM_TABSTOPS))
624     {
625       fmt.cTabCount = 0;
626     }
627     if (fmt.cTabCount < MAX_TAB_STOPS && info->rtfParam < 0x1000000)
628       fmt.rgxTabs[fmt.cTabCount++] = info->rtfParam;
629     fmt.dwMask = PFM_TABSTOPS;
630     break;
631   case rtfKeep:
632     fmt.dwMask = PFM_KEEP;
633     fmt.wEffects = PFE_KEEP;
634     break;
635   case rtfNoWidowControl:
636     fmt.dwMask = PFM_NOWIDOWCONTROL;
637     fmt.wEffects = PFE_NOWIDOWCONTROL;
638     break;
639   case rtfKeepNext:
640     fmt.dwMask = PFM_KEEPNEXT;
641     fmt.wEffects = PFE_KEEPNEXT;
642     break;
643   case rtfSpaceAfter:
644     fmt.dwMask = PFM_SPACEAFTER;
645     fmt.dySpaceAfter = info->rtfParam;
646     break;
647   case rtfSpaceBefore:
648     fmt.dwMask = PFM_SPACEBEFORE;
649     fmt.dySpaceBefore = info->rtfParam;
650     break;
651   case rtfSpaceBetween:
652     fmt.dwMask = PFM_LINESPACING;
653     if ((int)info->rtfParam > 0)
654     {
655       fmt.dyLineSpacing = info->rtfParam;
656       fmt.bLineSpacingRule = 3;
657     }
658     else
659     {
660       fmt.dyLineSpacing = info->rtfParam;
661       fmt.bLineSpacingRule = 4;
662     }
663   case rtfSpaceMultiply:
664     fmt.dwMask = PFM_LINESPACING;
665     fmt.dyLineSpacing = info->rtfParam * 20;
666     fmt.bLineSpacingRule = 5;
667     break;
668   case rtfParBullet:
669     fmt.dwMask = PFM_NUMBERING;
670     fmt.wNumbering = PFN_BULLET;
671     break;
672   case rtfParSimple:
673     fmt.dwMask = PFM_NUMBERING;
674     fmt.wNumbering = 2; /* FIXME: MSDN says it's not used ?? */
675     break;
676   case rtfParNumDecimal:
677     fmt.dwMask = PFM_NUMBERING;
678     fmt.wNumbering = 2; /* FIXME: MSDN says it's not used ?? */
679     break;
680   case rtfParNumIndent:
681     fmt.dwMask = PFM_NUMBERINGTAB;
682     fmt.wNumberingTab = info->rtfParam;
683     break;
684   case rtfParNumStartAt:
685     fmt.dwMask = PFM_NUMBERINGSTART;
686     fmt.wNumberingStart = info->rtfParam;
687     break;
688   case rtfBorderLeft:
689     info->borderType = RTFBorderParaLeft;
690     ME_GetSelectionParaFormat(info->editor, &fmt);
691     if (!(fmt.dwMask & PFM_BORDER))
692     {
693       fmt.wBorderSpace = 0;
694       fmt.wBorderWidth = 1;
695       fmt.wBorders = 0;
696     }
697     fmt.wBorders |= 1;
698     fmt.dwMask = PFM_BORDER;
699     break;
700   case rtfBorderRight:
701     info->borderType = RTFBorderParaRight;
702     ME_GetSelectionParaFormat(info->editor, &fmt);
703     if (!(fmt.dwMask & PFM_BORDER))
704     {
705       fmt.wBorderSpace = 0;
706       fmt.wBorderWidth = 1;
707       fmt.wBorders = 0;
708     }
709     fmt.wBorders |= 2;
710     fmt.dwMask = PFM_BORDER;
711     break;
712   case rtfBorderTop:
713     info->borderType = RTFBorderParaTop;
714     ME_GetSelectionParaFormat(info->editor, &fmt);
715     if (!(fmt.dwMask & PFM_BORDER))
716     {
717       fmt.wBorderSpace = 0;
718       fmt.wBorderWidth = 1;
719       fmt.wBorders = 0;
720     }
721     fmt.wBorders |= 4;
722     fmt.dwMask = PFM_BORDER;
723     break;
724   case rtfBorderBottom:
725     info->borderType = RTFBorderParaBottom;
726     ME_GetSelectionParaFormat(info->editor, &fmt);
727     if (!(fmt.dwMask & PFM_BORDER))
728     {
729       fmt.wBorderSpace = 0;
730       fmt.wBorderWidth = 1;
731       fmt.wBorders = 0;
732     }
733     fmt.wBorders |= 8;
734     fmt.dwMask = PFM_BORDER;
735     break;
736   case rtfBorderSingle:
737     ME_GetSelectionParaFormat(info->editor, &fmt);
738     /* we assume that borders have been created before (RTF spec) */
739     fmt.wBorders &= ~0x700;
740     fmt.wBorders |= 1 << 8;
741     fmt.dwMask = PFM_BORDER;
742     break;
743   case rtfBorderThick:
744     ME_GetSelectionParaFormat(info->editor, &fmt);
745     /* we assume that borders have been created before (RTF spec) */
746     fmt.wBorders &= ~0x700;
747     fmt.wBorders |= 2 << 8;
748     fmt.dwMask = PFM_BORDER;
749     break;
750   case rtfBorderShadow:
751     ME_GetSelectionParaFormat(info->editor, &fmt);
752     /* we assume that borders have been created before (RTF spec) */
753     fmt.wBorders &= ~0x700;
754     fmt.wBorders |= 10 << 8;
755     fmt.dwMask = PFM_BORDER;
756     break;
757   case rtfBorderDouble:
758     ME_GetSelectionParaFormat(info->editor, &fmt);
759     /* we assume that borders have been created before (RTF spec) */
760     fmt.wBorders &= ~0x700;
761     fmt.wBorders |= 7 << 8;
762     fmt.dwMask = PFM_BORDER;
763     break;
764   case rtfBorderDot:
765     ME_GetSelectionParaFormat(info->editor, &fmt);
766     /* we assume that borders have been created before (RTF spec) */
767     fmt.wBorders &= ~0x700;
768     fmt.wBorders |= 11 << 8;
769     fmt.dwMask = PFM_BORDER;
770     break;
771   case rtfBorderWidth:
772   {
773     int borderSide = info->borderType & RTFBorderSideMask;
774     RTFTable *tableDef = info->tableDef;
775     ME_GetSelectionParaFormat(info->editor, &fmt);
776     /* we assume that borders have been created before (RTF spec) */
777     fmt.wBorderWidth |= ((info->rtfParam / 15) & 7) << 8;
778     if ((info->borderType & RTFBorderTypeMask) == RTFBorderTypeCell)
779     {
780       RTFBorder *border;
781       if (!tableDef || tableDef->numCellsDefined >= MAX_TABLE_CELLS)
782         break;
783       border = &tableDef->cells[tableDef->numCellsDefined].border[borderSide];
784       border->width = info->rtfParam;
785       break;
786     }
787     fmt.dwMask = PFM_BORDER;
788     break;
789   }
790   case rtfBorderSpace:
791     ME_GetSelectionParaFormat(info->editor, &fmt);
792     /* we assume that borders have been created before (RTF spec) */
793     fmt.wBorderSpace = info->rtfParam;
794     fmt.dwMask = PFM_BORDER;
795     break;
796   case rtfBorderColor:
797   {
798     RTFTable *tableDef = info->tableDef;
799     int borderSide = info->borderType & RTFBorderSideMask;
800     int borderType = info->borderType & RTFBorderTypeMask;
801     switch(borderType)
802     {
803     case RTFBorderTypePara:
804       if (!info->editor->bEmulateVersion10) /* v4.1 */
805         break;
806       /* v1.0 - 3.0 treat paragraph and row borders the same. */
807     case RTFBorderTypeRow:
808       if (tableDef) {
809         tableDef->border[borderSide].color = info->rtfParam;
810       }
811       break;
812     case RTFBorderTypeCell:
813       if (tableDef && tableDef->numCellsDefined < MAX_TABLE_CELLS) {
814         tableDef->cells[tableDef->numCellsDefined].border[borderSide].color = info->rtfParam;
815       }
816       break;
817     }
818     break;
819   }
820   }
821   if (fmt.dwMask) {
822     RTFFlushOutputBuffer(info);
823     /* FIXME too slow ? how come ?*/
824     ME_SetSelectionParaFormat(info->editor, &fmt);
825   }
826 }
827 
828 void ME_RTFTblAttrHook(RTF_Info *info)
829 {
830   switch (info->rtfMinor)
831   {
832     case rtfRowDef:
833     {
834       if (!info->editor->bEmulateVersion10) /* v4.1 */
835         info->borderType = 0; /* Not sure */
836       else /* v1.0 - 3.0 */
837         info->borderType = RTFBorderRowTop;
838       if (!info->tableDef) {
839         info->tableDef = ME_MakeTableDef(info->editor);
840       } else {
841         ME_InitTableDef(info->editor, info->tableDef);
842       }
843       break;
844     }
845     case rtfCellPos:
846     {
847       int cellNum;
848       if (!info->tableDef)
849       {
850         info->tableDef = ME_MakeTableDef(info->editor);
851       }
852       cellNum = info->tableDef->numCellsDefined;
853       if (cellNum >= MAX_TABLE_CELLS)
854         break;
855       info->tableDef->cells[cellNum].rightBoundary = info->rtfParam;
856       if (cellNum < MAX_TAB_STOPS) {
857         /* Tab stops were used to store cell positions before v4.1 but v4.1
858          * still seems to set the tabstops without using them. */
859         ME_DisplayItem *para = ME_GetParagraph(info->editor->pCursors[0].pRun);
860         PARAFORMAT2 *pFmt = para->member.para.pFmt;
861         pFmt->rgxTabs[cellNum] &= ~0x00FFFFFF;
862         pFmt->rgxTabs[cellNum] = 0x00FFFFFF & info->rtfParam;
863       }
864       info->tableDef->numCellsDefined++;
865       break;
866     }
867     case rtfRowBordTop:
868       info->borderType = RTFBorderRowTop;
869       break;
870     case rtfRowBordLeft:
871       info->borderType = RTFBorderRowLeft;
872       break;
873     case rtfRowBordBottom:
874       info->borderType = RTFBorderRowBottom;
875       break;
876     case rtfRowBordRight:
877       info->borderType = RTFBorderRowRight;
878       break;
879     case rtfCellBordTop:
880       info->borderType = RTFBorderCellTop;
881       break;
882     case rtfCellBordLeft:
883       info->borderType = RTFBorderCellLeft;
884       break;
885     case rtfCellBordBottom:
886       info->borderType = RTFBorderCellBottom;
887       break;
888     case rtfCellBordRight:
889       info->borderType = RTFBorderCellRight;
890       break;
891     case rtfRowGapH:
892       if (info->tableDef)
893         info->tableDef->gapH = info->rtfParam;
894       break;
895     case rtfRowLeftEdge:
896       if (info->tableDef)
897         info->tableDef->leftEdge = info->rtfParam;
898       break;
899   }
900 }
901 
902 void ME_RTFSpecialCharHook(RTF_Info *info)
903 {
904   RTFTable *tableDef = info->tableDef;
905   switch (info->rtfMinor)
906   {
907     case rtfNestCell:
908       if (info->editor->bEmulateVersion10) /* v1.0 - v3.0 */
909         break;
910       /* else fall through since v4.1 treats rtfNestCell and rtfCell the same */