winmm/tests: Replace some '#if 0's with 'if (0)'s.
[wine] / dlls / user32 / edit.c
1 /*
2  *      Edit control
3  *
4  *      Copyright  David W. Metcalfe, 1994
5  *      Copyright  William Magro, 1995, 1996
6  *      Copyright  Frans van Dorsselaer, 1996, 1997
7  *
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  * NOTES
24  *
25  * This code was audited for completeness against the documented features
26  * of Comctl32.dll version 6.0 on Oct. 8, 2004, by Dimitrie O. Paun.
27  * 
28  * Unless otherwise noted, we believe this code to be complete, as per
29  * the specification mentioned above.
30  * If you discover missing features, or bugs, please note them below.
31  *
32  * TODO:
33  *   - EDITBALLOONTIP structure
34  *   - EM_GETCUEBANNER/Edit_GetCueBannerText
35  *   - EM_HIDEBALLOONTIP/Edit_HideBalloonTip
36  *   - EM_SETCUEBANNER/Edit_SetCueBannerText
37  *   - EM_SHOWBALLOONTIP/Edit_ShowBalloonTip
38  *   - EM_GETIMESTATUS, EM_SETIMESTATUS
39  *   - EN_ALIGN_LTR_EC
40  *   - EN_ALIGN_RTL_EC
41  *   - ES_OEMCONVERT
42  *
43  */
44
45 #include "config.h"
46
47 #include <stdarg.h>
48 #include <string.h>
49 #include <stdlib.h>
50
51 #include "windef.h"
52 #include "winbase.h"
53 #include "winnt.h"
54 #include "wownt32.h"
55 #include "win.h"
56 #include "imm.h"
57 #include "wine/winbase16.h"
58 #include "wine/winuser16.h"
59 #include "wine/unicode.h"
60 #include "controls.h"
61 #include "user_private.h"
62 #include "wine/debug.h"
63
64 WINE_DEFAULT_DEBUG_CHANNEL(edit);
65 WINE_DECLARE_DEBUG_CHANNEL(combo);
66 WINE_DECLARE_DEBUG_CHANNEL(relay);
67
68 #define BUFLIMIT_MULTI          65534   /* maximum buffer size (not including '\0')
69                                            FIXME: BTW, new specs say 65535 (do you dare ???) */
70 #define BUFLIMIT_SINGLE         32766   /* maximum buffer size (not including '\0') */
71 #define GROWLENGTH              32      /* buffers granularity in bytes: must be power of 2 */
72 #define ROUND_TO_GROW(size)     (((size) + (GROWLENGTH - 1)) & ~(GROWLENGTH - 1))
73 #define HSCROLL_FRACTION        3       /* scroll window by 1/3 width */
74
75 /*
76  *      extra flags for EDITSTATE.flags field
77  */
78 #define EF_MODIFIED             0x0001  /* text has been modified */
79 #define EF_FOCUSED              0x0002  /* we have input focus */
80 #define EF_UPDATE               0x0004  /* notify parent of changed state */
81 #define EF_VSCROLL_TRACK        0x0008  /* don't SetScrollPos() since we are tracking the thumb */
82 #define EF_HSCROLL_TRACK        0x0010  /* don't SetScrollPos() since we are tracking the thumb */
83 #define EF_AFTER_WRAP           0x0080  /* the caret is displayed after the last character of a
84                                            wrapped line, instead of in front of the next character */
85 #define EF_USE_SOFTBRK          0x0100  /* Enable soft breaks in text. */
86
87 typedef enum
88 {
89         END_0 = 0,                      /* line ends with terminating '\0' character */
90         END_WRAP,                       /* line is wrapped */
91         END_HARD,                       /* line ends with a hard return '\r\n' */
92         END_SOFT,                       /* line ends with a soft return '\r\r\n' */
93         END_RICH                        /* line ends with a single '\n' */
94 } LINE_END;
95
96 typedef struct tagLINEDEF {
97         INT length;                     /* bruto length of a line in bytes */
98         INT net_length;                 /* netto length of a line in visible characters */
99         LINE_END ending;
100         INT width;                      /* width of the line in pixels */
101         INT index;                      /* line index into the buffer */
102         struct tagLINEDEF *next;
103 } LINEDEF;
104
105 typedef struct
106 {
107         BOOL is_unicode;                /* how the control was created */
108         LPWSTR text;                    /* the actual contents of the control */
109         UINT buffer_size;               /* the size of the buffer in characters */
110         UINT buffer_limit;              /* the maximum size to which the buffer may grow in characters */
111         HFONT font;                     /* NULL means standard system font */
112         INT x_offset;                   /* scroll offset        for multi lines this is in pixels
113                                                                 for single lines it's in characters */
114         INT line_height;                /* height of a screen line in pixels */
115         INT char_width;                 /* average character width in pixels */
116         DWORD style;                    /* sane version of wnd->dwStyle */
117         WORD flags;                     /* flags that are not in es->style or wnd->flags (EF_XXX) */
118         INT undo_insert_count;          /* number of characters inserted in sequence */
119         UINT undo_position;             /* character index of the insertion and deletion */
120         LPWSTR undo_text;               /* deleted text */
121         UINT undo_buffer_size;          /* size of the deleted text buffer */
122         INT selection_start;            /* == selection_end if no selection */
123         INT selection_end;              /* == current caret position */
124         WCHAR password_char;            /* == 0 if no password char, and for multi line controls */
125         INT left_margin;                /* in pixels */
126         INT right_margin;               /* in pixels */
127         RECT format_rect;
128         INT text_width;                 /* width of the widest line in pixels for multi line controls
129                                            and just line width for single line controls */
130         INT region_posx;                /* Position of cursor relative to region: */
131         INT region_posy;                /* -1: to left, 0: within, 1: to right */
132         EDITWORDBREAKPROC16 word_break_proc16;
133         void *word_break_proc;          /* 32-bit word break proc: ANSI or Unicode */
134         INT line_count;                 /* number of lines */
135         INT y_offset;                   /* scroll offset in number of lines */
136         BOOL bCaptureState;             /* flag indicating whether mouse was captured */
137         BOOL bEnableState;              /* flag keeping the enable state */
138         HWND hwndSelf;                  /* the our window handle */
139         HWND hwndParent;                /* Handle of parent for sending EN_* messages.
140                                            Even if parent will change, EN_* messages
141                                            should be sent to the first parent. */
142         HWND hwndListBox;               /* handle of ComboBox's listbox or NULL */
143         /*
144          *      only for multi line controls
145          */
146         INT lock_count;                 /* amount of re-entries in the EditWndProc */
147         INT tabs_count;
148         LPINT tabs;
149         LINEDEF *first_line_def;        /* linked list of (soft) linebreaks */
150         HLOCAL hloc32W;                 /* our unicode local memory block */
151         HLOCAL16 hloc16;                /* alias for 16-bit control receiving EM_GETHANDLE16
152                                            or EM_SETHANDLE16 */
153         HLOCAL hloc32A;                 /* alias for ANSI control receiving EM_GETHANDLE
154                                            or EM_SETHANDLE */
155         /*
156          * IME Data
157          */
158         UINT composition_len;   /* length of composition, 0 == no composition */
159         int composition_start;  /* the character position for the composition */
160 } EDITSTATE;
161
162
163 #define SWAP_UINT32(x,y) do { UINT temp = (UINT)(x); (x) = (UINT)(y); (y) = temp; } while(0)
164 #define ORDER_UINT(x,y) do { if ((UINT)(y) < (UINT)(x)) SWAP_UINT32((x),(y)); } while(0)
165
166 /* used for disabled or read-only edit control */
167 #define EDIT_NOTIFY_PARENT(es, wNotifyCode) \
168         do \
169         { /* Notify parent which has created this edit control */ \
170             TRACE("notification " #wNotifyCode " sent to hwnd=%p\n", es->hwndParent); \
171             SendMessageW(es->hwndParent, WM_COMMAND, \
172                      MAKEWPARAM(GetWindowLongPtrW((es->hwndSelf),GWLP_ID), wNotifyCode), \
173                      (LPARAM)(es->hwndSelf)); \
174         } while(0)
175
176 /*********************************************************************
177  *
178  *      Declarations
179  *
180  */
181
182 /*
183  *      These functions have trivial implementations
184  *      We still like to call them internally
185  *      "static inline" makes them more like macro's
186  */
187 static inline BOOL      EDIT_EM_CanUndo(EDITSTATE *es);
188 static inline void      EDIT_EM_EmptyUndoBuffer(EDITSTATE *es);
189 static inline void      EDIT_WM_Clear(EDITSTATE *es);
190 static inline void      EDIT_WM_Cut(EDITSTATE *es);
191
192 /*
193  *      Helper functions only valid for one type of control
194  */
195 static void     EDIT_BuildLineDefs_ML(EDITSTATE *es, INT iStart, INT iEnd, INT delta, HRGN hrgn);
196 static void     EDIT_CalcLineWidth_SL(EDITSTATE *es);
197 static LPWSTR   EDIT_GetPasswordPointer_SL(EDITSTATE *es);
198 static void     EDIT_MoveDown_ML(EDITSTATE *es, BOOL extend);
199 static void     EDIT_MovePageDown_ML(EDITSTATE *es, BOOL extend);
200 static void     EDIT_MovePageUp_ML(EDITSTATE *es, BOOL extend);
201 static void     EDIT_MoveUp_ML(EDITSTATE *es, BOOL extend);
202 /*
203  *      Helper functions valid for both single line _and_ multi line controls
204  */
205 static INT      EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count, INT action);
206 static INT      EDIT_CharFromPos(EDITSTATE *es, INT x, INT y, LPBOOL after_wrap);
207 static void     EDIT_ConfinePoint(EDITSTATE *es, LPINT x, LPINT y);
208 static void     EDIT_GetLineRect(EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc);
209 static void     EDIT_InvalidateText(EDITSTATE *es, INT start, INT end);
210 static void     EDIT_LockBuffer(EDITSTATE *es);
211 static BOOL     EDIT_MakeFit(EDITSTATE *es, UINT size);
212 static BOOL     EDIT_MakeUndoFit(EDITSTATE *es, UINT size);
213 static void     EDIT_MoveBackward(EDITSTATE *es, BOOL extend);
214 static void     EDIT_MoveEnd(EDITSTATE *es, BOOL extend);
215 static void     EDIT_MoveForward(EDITSTATE *es, BOOL extend);
216 static void     EDIT_MoveHome(EDITSTATE *es, BOOL extend);
217 static void     EDIT_MoveWordBackward(EDITSTATE *es, BOOL extend);
218 static void     EDIT_MoveWordForward(EDITSTATE *es, BOOL extend);
219 static void     EDIT_PaintLine(EDITSTATE *es, HDC hdc, INT line, BOOL rev);
220 static INT      EDIT_PaintText(EDITSTATE *es, HDC hdc, INT x, INT y, INT line, INT col, INT count, BOOL rev);
221 static void     EDIT_SetCaretPos(EDITSTATE *es, INT pos, BOOL after_wrap);
222 static void     EDIT_AdjustFormatRect(EDITSTATE *es);
223 static void     EDIT_SetRectNP(EDITSTATE *es, LPRECT lprc);
224 static void     EDIT_UnlockBuffer(EDITSTATE *es, BOOL force);
225 static void     EDIT_UpdateScrollInfo(EDITSTATE *es);
226 static INT CALLBACK EDIT_WordBreakProc(LPWSTR s, INT index, INT count, INT action);
227 /*
228  *      EM_XXX message handlers
229  */
230 static LRESULT  EDIT_EM_CharFromPos(EDITSTATE *es, INT x, INT y);
231 static BOOL     EDIT_EM_FmtLines(EDITSTATE *es, BOOL add_eol);
232 static HLOCAL   EDIT_EM_GetHandle(EDITSTATE *es);
233 static HLOCAL16 EDIT_EM_GetHandle16(EDITSTATE *es);
234 static INT      EDIT_EM_GetLine(EDITSTATE *es, INT line, LPWSTR dst, BOOL unicode);
235 static LRESULT  EDIT_EM_GetSel(EDITSTATE *es, PUINT start, PUINT end);
236 static LRESULT  EDIT_EM_GetThumb(EDITSTATE *es);
237 static INT      EDIT_EM_LineFromChar(EDITSTATE *es, INT index);
238 static INT      EDIT_EM_LineIndex(EDITSTATE *es, INT line);
239 static INT      EDIT_EM_LineLength(EDITSTATE *es, INT index);
240 static BOOL     EDIT_EM_LineScroll(EDITSTATE *es, INT dx, INT dy);
241 static BOOL     EDIT_EM_LineScroll_internal(EDITSTATE *es, INT dx, INT dy);
242 static LRESULT  EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap);
243 static void     EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replace, BOOL send_update, BOOL honor_limit);
244 static LRESULT  EDIT_EM_Scroll(EDITSTATE *es, INT action);
245 static void     EDIT_EM_ScrollCaret(EDITSTATE *es);
246 static void     EDIT_EM_SetHandle(EDITSTATE *es, HLOCAL hloc);
247 static void     EDIT_EM_SetHandle16(EDITSTATE *es, HLOCAL16 hloc);
248 static void     EDIT_EM_SetLimitText(EDITSTATE *es, INT limit);
249 static void     EDIT_EM_SetMargins(EDITSTATE *es, INT action, WORD left, WORD right, BOOL repaint);
250 static void     EDIT_EM_SetPasswordChar(EDITSTATE *es, WCHAR c);
251 static void     EDIT_EM_SetSel(EDITSTATE *es, UINT start, UINT end, BOOL after_wrap);
252 static BOOL     EDIT_EM_SetTabStops(EDITSTATE *es, INT count, LPINT tabs);
253 static BOOL     EDIT_EM_SetTabStops16(EDITSTATE *es, INT count, LPINT16 tabs);
254 static void     EDIT_EM_SetWordBreakProc(EDITSTATE *es, void *wbp);
255 static void     EDIT_EM_SetWordBreakProc16(EDITSTATE *es, EDITWORDBREAKPROC16 wbp);
256 static BOOL     EDIT_EM_Undo(EDITSTATE *es);
257 /*
258  *      WM_XXX message handlers
259  */
260 static void     EDIT_WM_Char(EDITSTATE *es, WCHAR c);
261 static void     EDIT_WM_Command(EDITSTATE *es, INT code, INT id, HWND conrtol);
262 static void     EDIT_WM_ContextMenu(EDITSTATE *es, INT x, INT y);
263 static void     EDIT_WM_Copy(EDITSTATE *es);
264 static LRESULT  EDIT_WM_Create(EDITSTATE *es, LPCWSTR name);
265 static LRESULT  EDIT_WM_Destroy(EDITSTATE *es);
266 static LRESULT  EDIT_WM_EraseBkGnd(EDITSTATE *es, HDC dc);
267 static INT      EDIT_WM_GetText(EDITSTATE *es, INT count, LPWSTR dst, BOOL unicode);
268 static LRESULT  EDIT_WM_HScroll(EDITSTATE *es, INT action, INT pos);
269 static LRESULT  EDIT_WM_KeyDown(EDITSTATE *es, INT key);
270 static LRESULT  EDIT_WM_KillFocus(EDITSTATE *es);
271 static LRESULT  EDIT_WM_LButtonDblClk(EDITSTATE *es);
272 static LRESULT  EDIT_WM_LButtonDown(EDITSTATE *es, DWORD keys, INT x, INT y);
273 static LRESULT  EDIT_WM_LButtonUp(EDITSTATE *es);
274 static LRESULT  EDIT_WM_MButtonDown(EDITSTATE *es);
275 static LRESULT  EDIT_WM_MouseMove(EDITSTATE *es, INT x, INT y);
276 static LRESULT  EDIT_WM_NCCreate(HWND hwnd, LPCREATESTRUCTW lpcs, BOOL unicode);
277 static void     EDIT_WM_Paint(EDITSTATE *es, HDC hdc);
278 static void     EDIT_WM_Paste(EDITSTATE *es);
279 static void     EDIT_WM_SetFocus(EDITSTATE *es);
280 static void     EDIT_WM_SetFont(EDITSTATE *es, HFONT font, BOOL redraw);
281 static void     EDIT_WM_SetText(EDITSTATE *es, LPCWSTR text, BOOL unicode);
282 static void     EDIT_WM_Size(EDITSTATE *es, UINT action, INT width, INT height);
283 static LRESULT  EDIT_WM_StyleChanged(EDITSTATE *es, WPARAM which, const STYLESTRUCT *style);
284 static LRESULT  EDIT_WM_SysKeyDown(EDITSTATE *es, INT key, DWORD key_data);
285 static void     EDIT_WM_Timer(EDITSTATE *es);
286 static LRESULT  EDIT_WM_VScroll(EDITSTATE *es, INT action, INT pos);
287 static void     EDIT_UpdateText(EDITSTATE *es, LPRECT rc, BOOL bErase);
288 static void     EDIT_UpdateTextRegion(EDITSTATE *es, HRGN hrgn, BOOL bErase);
289 static void EDIT_ImeComposition(HWND hwnd, LPARAM CompFlag, EDITSTATE *es);
290
291 LRESULT WINAPI EditWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
292 LRESULT WINAPI EditWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
293
294 /*********************************************************************
295  * edit class descriptor
296  */
297 const struct builtin_class_descr EDIT_builtin_class =
298 {
299     "Edit",               /* name */
300     CS_DBLCLKS | CS_PARENTDC,   /* style */
301     EditWndProcA,         /* procA */
302     EditWndProcW,         /* procW */
303     sizeof(EDITSTATE *),  /* extra */
304     IDC_IBEAM,            /* cursor */
305     0                     /* brush */
306 };
307
308
309 /*********************************************************************
310  *
311  *      EM_CANUNDO
312  *
313  */
314 static inline BOOL EDIT_EM_CanUndo(EDITSTATE *es)
315 {
316         return (es->undo_insert_count || strlenW(es->undo_text));
317 }
318
319
320 /*********************************************************************
321  *
322  *      EM_EMPTYUNDOBUFFER
323  *
324  */
325 static inline void EDIT_EM_EmptyUndoBuffer(EDITSTATE *es)
326 {
327         es->undo_insert_count = 0;
328         *es->undo_text = '\0';
329 }
330
331
332 /*********************************************************************
333  *
334  *      WM_CLEAR
335  *
336  */
337 static inline void EDIT_WM_Clear(EDITSTATE *es)
338 {
339         static const WCHAR empty_stringW[] = {0};
340
341         /* Protect read-only edit control from modification */
342         if(es->style & ES_READONLY)
343             return;
344
345         EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE);
346 }
347
348
349 /*********************************************************************
350  *
351  *      WM_CUT
352  *
353  */
354 static inline void EDIT_WM_Cut(EDITSTATE *es)
355 {
356         EDIT_WM_Copy(es);
357         EDIT_WM_Clear(es);
358 }
359
360
361 /**********************************************************************
362  *         get_app_version
363  *
364  * Returns the window version in case Wine emulates a later version
365  * of windows than the application expects.
366  *
367  * In a number of cases when windows runs an application that was
368  * designed for an earlier windows version, windows reverts
369  * to "old" behaviour of that earlier version.
370  *
371  * An example is a disabled  edit control that needs to be painted.
372  * Old style behaviour is to send a WM_CTLCOLOREDIT message. This was
373  * changed in Win95, NT4.0 by a WM_CTLCOLORSTATIC message _only_ for
374  * applications with an expected version 0f 4.0 or higher.
375  *
376  */
377 static DWORD get_app_version(void)
378 {
379     static DWORD version;
380     if (!version)
381     {
382         DWORD dwEmulatedVersion;
383         OSVERSIONINFOW info;
384         DWORD dwProcVersion = GetProcessVersion(0);
385
386         info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
387         GetVersionExW( &info );
388         dwEmulatedVersion = MAKELONG( info.dwMinorVersion, info.dwMajorVersion );
389         /* FIXME: this may not be 100% correct; see discussion on the
390          * wine developer list in Nov 1999 */
391         version = dwProcVersion < dwEmulatedVersion ? dwProcVersion : dwEmulatedVersion;
392     }
393     return version;
394 }
395
396
397 static HBRUSH EDIT_NotifyCtlColor(EDITSTATE *es, HDC hdc)
398 {
399         HBRUSH hbrush;
400         UINT msg;
401
402         if ( get_app_version() >= 0x40000 && (!es->bEnableState || (es->style & ES_READONLY)))
403                 msg = WM_CTLCOLORSTATIC;
404         else
405                 msg = WM_CTLCOLOREDIT;
406
407         /* why do we notify to es->hwndParent, and we send this one to GetParent()? */
408         hbrush = (HBRUSH)SendMessageW(GetParent(es->hwndSelf), msg, (WPARAM)hdc, (LPARAM)es->hwndSelf);
409         if (!hbrush)
410             hbrush = (HBRUSH)DefWindowProcW(GetParent(es->hwndSelf), msg, (WPARAM)hdc, (LPARAM)es->hwndSelf);
411         return hbrush;
412 }
413
414 static inline LRESULT DefWindowProcT(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode)
415 {
416         if(unicode)
417                 return DefWindowProcW(hwnd, msg, wParam, lParam);
418         else
419                 return DefWindowProcA(hwnd, msg, wParam, lParam);
420 }
421
422 /*********************************************************************
423  *
424  *      EditWndProc_common
425  *
426  *      The messages are in the order of the actual integer values
427  *      (which can be found in include/windows.h)
428  *      Wherever possible the 16 bit versions are converted to
429  *      the 32 bit ones, so that we can 'fall through' to the
430  *      helper functions.  These are mostly 32 bit (with a few
431  *      exceptions, clearly indicated by a '16' extension to their
432  *      names).
433  *
434  */
435 static LRESULT WINAPI EditWndProc_common( HWND hwnd, UINT msg,
436                                           WPARAM wParam, LPARAM lParam, BOOL unicode )
437 {
438         EDITSTATE *es = (EDITSTATE *)GetWindowLongPtrW( hwnd, 0 );
439         LRESULT result = 0;
440
441         TRACE("hwnd=%p msg=%x (%s) wparam=%x lparam=%lx\n", hwnd, msg, SPY_GetMsgName(msg, hwnd), wParam, lParam);
442         
443         if (!es && msg != WM_NCCREATE)
444                 return DefWindowProcT(hwnd, msg, wParam, lParam, unicode);
445
446         if (es && (msg != WM_DESTROY)) EDIT_LockBuffer(es);
447
448         switch (msg) {
449         case EM_GETSEL16:
450                 wParam = 0;
451                 lParam = 0;
452                 /* fall through */
453         case EM_GETSEL:
454                 result = EDIT_EM_GetSel(es, (PUINT)wParam, (PUINT)lParam);
455                 break;
456
457         case EM_SETSEL16:
458                 if ((short)LOWORD(lParam) == -1)
459                         EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
460                 else
461                         EDIT_EM_SetSel(es, LOWORD(lParam), HIWORD(lParam), FALSE);
462                 if (!wParam)
463                         EDIT_EM_ScrollCaret(es);
464                 result = 1;
465                 break;
466         case EM_SETSEL:
467                 EDIT_EM_SetSel(es, wParam, lParam, FALSE);
468                 EDIT_EM_ScrollCaret(es);
469                 result = 1;
470                 break;
471
472         case EM_GETRECT16:
473                 if (lParam)
474                 {
475                     RECT16 *r16 = MapSL(lParam);
476                     r16->left   = es->format_rect.left;
477                     r16->top    = es->format_rect.top;
478                     r16->right  = es->format_rect.right;
479                     r16->bottom = es->format_rect.bottom;
480                 }
481                 break;
482         case EM_GETRECT:
483                 if (lParam)
484                         CopyRect((LPRECT)lParam, &es->format_rect);
485                 break;
486
487         case EM_SETRECT16:
488                 if ((es->style & ES_MULTILINE) && lParam) {
489                         RECT rc;
490                         RECT16 *r16 = MapSL(lParam);
491                         rc.left   = r16->left;
492                         rc.top    = r16->top;
493                         rc.right  = r16->right;
494                         rc.bottom = r16->bottom;
495                         EDIT_SetRectNP(es, &rc);
496                         EDIT_UpdateText(es, NULL, TRUE);
497                 }
498                 break;
499         case EM_SETRECT:
500                 if ((es->style & ES_MULTILINE) && lParam) {
501                         EDIT_SetRectNP(es, (LPRECT)lParam);
502                         EDIT_UpdateText(es, NULL, TRUE);
503                 }
504                 break;
505
506         case EM_SETRECTNP16:
507                 if ((es->style & ES_MULTILINE) && lParam) {
508                         RECT rc;
509                         RECT16 *r16 = MapSL(lParam);
510                         rc.left   = r16->left;
511                         rc.top    = r16->top;
512                         rc.right  = r16->right;
513                         rc.bottom = r16->bottom;
514                         EDIT_SetRectNP(es, &rc);
515                 }
516                 break;
517         case EM_SETRECTNP:
518                 if ((es->style & ES_MULTILINE) && lParam)
519                         EDIT_SetRectNP(es, (LPRECT)lParam);
520                 break;
521
522         case EM_SCROLL16:
523         case EM_SCROLL:
524                 result = EDIT_EM_Scroll(es, (INT)wParam);
525                 break;
526
527         case EM_LINESCROLL16:
528                 wParam = (WPARAM)(INT)(SHORT)HIWORD(lParam);
529                 lParam = (LPARAM)(INT)(SHORT)LOWORD(lParam);
530                 /* fall through */
531         case EM_LINESCROLL:
532                 result = (LRESULT)EDIT_EM_LineScroll(es, (INT)wParam, (INT)lParam);
533                 break;
534
535         case EM_SCROLLCARET16:
536         case EM_SCROLLCARET:
537                 EDIT_EM_ScrollCaret(es);
538                 result = 1;
539                 break;
540
541         case EM_GETMODIFY16:
542         case EM_GETMODIFY:
543                 result = ((es->flags & EF_MODIFIED) != 0);
544                 break;
545
546         case EM_SETMODIFY16:
547         case EM_SETMODIFY:
548                 if (wParam)
549                         es->flags |= EF_MODIFIED;
550                 else
551                         es->flags &= ~(EF_MODIFIED | EF_UPDATE);  /* reset pending updates */
552                 break;
553
554         case EM_GETLINECOUNT16:
555         case EM_GETLINECOUNT:
556                 result = (es->style & ES_MULTILINE) ? es->line_count : 1;
557                 break;
558
559         case EM_LINEINDEX16:
560                 if ((INT16)wParam == -1)
561                         wParam = (WPARAM)-1;
562                 /* fall through */
563         case EM_LINEINDEX:
564                 result = (LRESULT)EDIT_EM_LineIndex(es, (INT)wParam);
565                 break;
566
567         case EM_SETHANDLE16:
568                 EDIT_EM_SetHandle16(es, (HLOCAL16)wParam);
569                 break;
570         case EM_SETHANDLE:
571                 EDIT_EM_SetHandle(es, (HLOCAL)wParam);
572                 break;
573
574         case EM_GETHANDLE16:
575                 result = (LRESULT)EDIT_EM_GetHandle16(es);
576                 break;
577         case EM_GETHANDLE:
578                 result = (LRESULT)EDIT_EM_GetHandle(es);
579                 break;
580
581         case EM_GETTHUMB16:
582         case EM_GETTHUMB:
583                 result = EDIT_EM_GetThumb(es);
584                 break;
585
586         /* these messages missing from specs */
587         case WM_USER+15:
588         case 0x00bf:
589         case WM_USER+16:
590         case 0x00c0:
591         case WM_USER+19:
592         case 0x00c3:
593         case WM_USER+26:
594         case 0x00ca:
595                 FIXME("undocumented message 0x%x, please report\n", msg);
596                 result = DefWindowProcW(hwnd, msg, wParam, lParam);
597                 break;
598                 
599         case EM_LINELENGTH16:
600         case EM_LINELENGTH:
601                 result = (LRESULT)EDIT_EM_LineLength(es, (INT)wParam);
602                 break;
603
604         case EM_REPLACESEL16:
605                 lParam = (LPARAM)MapSL(lParam);
606                 unicode = FALSE;  /* 16-bit message is always ascii */
607                 /* fall through */
608         case EM_REPLACESEL:
609         {
610                 LPWSTR textW;
611
612                 if(unicode)
613                     textW = (LPWSTR)lParam;
614                 else
615                 {
616                     LPSTR textA = (LPSTR)lParam;
617                     INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
618                     if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
619                         MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
620                 }
621
622                 EDIT_EM_ReplaceSel(es, (BOOL)wParam, textW, TRUE, TRUE);
623                 result = 1;
624
625                 if(!unicode)
626                     HeapFree(GetProcessHeap(), 0, textW);
627                 break;
628         }
629
630         case EM_GETLINE16:
631                 lParam = (LPARAM)MapSL(lParam);
632                 unicode = FALSE;  /* 16-bit message is always ascii */
633                 /* fall through */
634         case EM_GETLINE:
635                 result = (LRESULT)EDIT_EM_GetLine(es, (INT)wParam, (LPWSTR)lParam, unicode);
636                 break;
637
638         case EM_LIMITTEXT16:
639         case EM_SETLIMITTEXT:
640                 EDIT_EM_SetLimitText(es, (INT)wParam);
641                 break;
642
643         case EM_CANUNDO16:
644         case EM_CANUNDO:
645                 result = (LRESULT)EDIT_EM_CanUndo(es);
646                 break;
647
648         case EM_UNDO16:
649         case EM_UNDO:
650         case WM_UNDO:
651                 result = (LRESULT)EDIT_EM_Undo(es);
652                 break;
653
654         case EM_FMTLINES16:
655         case EM_FMTLINES:
656                 result = (LRESULT)EDIT_EM_FmtLines(es, (BOOL)wParam);
657                 break;
658
659         case EM_LINEFROMCHAR16:
660         case EM_LINEFROMCHAR:
661                 result = (LRESULT)EDIT_EM_LineFromChar(es, (INT)wParam);
662                 break;
663
664         case EM_SETTABSTOPS16:
665                 result = (LRESULT)EDIT_EM_SetTabStops16(es, (INT)wParam, MapSL(lParam));
666                 break;
667         case EM_SETTABSTOPS:
668                 result = (LRESULT)EDIT_EM_SetTabStops(es, (INT)wParam, (LPINT)lParam);
669                 break;
670
671         case EM_SETPASSWORDCHAR16:
672                 unicode = FALSE;  /* 16-bit message is always ascii */
673                 /* fall through */
674         case EM_SETPASSWORDCHAR:
675         {
676                 WCHAR charW = 0;
677
678                 if(unicode)
679                     charW = (WCHAR)wParam;
680                 else
681                 {
682                     CHAR charA = wParam;
683                     MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
684                 }
685
686                 EDIT_EM_SetPasswordChar(es, charW);
687                 break;
688         }
689
690         case EM_EMPTYUNDOBUFFER16:
691         case EM_EMPTYUNDOBUFFER:
692                 EDIT_EM_EmptyUndoBuffer(es);
693                 break;
694
695         case EM_GETFIRSTVISIBLELINE16:
696                 result = es->y_offset;
697                 break;
698         case EM_GETFIRSTVISIBLELINE:
699                 result = (es->style & ES_MULTILINE) ? es->y_offset : es->x_offset;
700                 break;
701
702         case EM_SETREADONLY16:
703         case EM_SETREADONLY:
704                 if (wParam) {
705                     SetWindowLongW( hwnd, GWL_STYLE,
706                                     GetWindowLongW( hwnd, GWL_STYLE ) | ES_READONLY );
707                     es->style |= ES_READONLY;
708                 } else {
709                     SetWindowLongW( hwnd, GWL_STYLE,
710                                     GetWindowLongW( hwnd, GWL_STYLE ) & ~ES_READONLY );
711                     es->style &= ~ES_READONLY;
712                 }
713                 result = 1;
714                 break;
715
716         case EM_SETWORDBREAKPROC16:
717                 EDIT_EM_SetWordBreakProc16(es, (EDITWORDBREAKPROC16)lParam);
718                 break;
719         case EM_SETWORDBREAKPROC:
720                 EDIT_EM_SetWordBreakProc(es, (void *)lParam);
721                 break;
722
723         case EM_GETWORDBREAKPROC16:
724                 result = (LRESULT)es->word_break_proc16;
725                 break;
726         case EM_GETWORDBREAKPROC:
727                 result = (LRESULT)es->word_break_proc;
728                 break;
729
730         case EM_GETPASSWORDCHAR16:
731                 unicode = FALSE;  /* 16-bit message is always ascii */
732                 /* fall through */
733         case EM_GETPASSWORDCHAR:
734         {
735                 if(unicode)
736                     result = es->password_char;
737                 else
738                 {
739                     WCHAR charW = es->password_char;
740                     CHAR charA = 0;
741                     WideCharToMultiByte(CP_ACP, 0, &charW, 1, &charA, 1, NULL, NULL);
742                     result = charA;
743                 }
744                 break;
745         }
746
747         /* The following EM_xxx are new to win95 and don't exist for 16 bit */
748
749         case EM_SETMARGINS:
750                 EDIT_EM_SetMargins(es, (INT)wParam, LOWORD(lParam), HIWORD(lParam), TRUE);
751                 break;
752
753         case EM_GETMARGINS:
754                 result = MAKELONG(es->left_margin, es->right_margin);
755                 break;
756
757         case EM_GETLIMITTEXT:
758                 result = es->buffer_limit;
759                 break;
760
761         case EM_POSFROMCHAR:
762                 result = strlenW(es->text);
763                 if ((INT)wParam >= result) result = -1;
764                 else result = EDIT_EM_PosFromChar(es, (INT)wParam, FALSE);
765                 break;
766
767         case EM_CHARFROMPOS:
768                 result = EDIT_EM_CharFromPos(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
769                 break;
770
771         /* End of the EM_ messages which were in numerical order; what order
772          * are these in?  vaguely alphabetical?
773          */
774
775         case WM_NCCREATE:
776                 result = EDIT_WM_NCCreate(hwnd, (LPCREATESTRUCTW)lParam, unicode);
777                 break;
778
779         case WM_DESTROY:
780                 result = EDIT_WM_Destroy(es);
781                 es = NULL;
782                 break;
783
784         case WM_GETDLGCODE:
785                 result = DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
786                 
787                 if (es->style & ES_MULTILINE)
788                 {
789                    result |= DLGC_WANTALLKEYS;
790                    break;
791                 }
792
793                 if (lParam && (((LPMSG)lParam)->message == WM_KEYDOWN))
794                 {
795                    int vk = (int)((LPMSG)lParam)->wParam;
796
797                    if (es->hwndListBox && (vk == VK_RETURN || vk == VK_ESCAPE))
798                    {
799                       if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0))
800                          result |= DLGC_WANTMESSAGE;
801                    }
802                 }
803                 break;
804
805         case WM_IME_CHAR:
806             if (!unicode)
807             {
808                 WCHAR charW;
809                 CHAR  strng[2];
810
811                 strng[0] = wParam >> 8;
812                 strng[1] = wParam & 0xff;
813                 if (strng[0]) MultiByteToWideChar(CP_ACP, 0, strng, 2, &charW, 1);
814                 else MultiByteToWideChar(CP_ACP, 0, &strng[1], 1, &charW, 1);
815                 EDIT_WM_Char(es, charW);
816                 break;
817             }
818             /* fall through */
819         case WM_CHAR:
820         {
821                 WCHAR charW;
822
823                 if(unicode)
824                     charW = wParam;
825                 else
826                 {
827                     CHAR charA = wParam;
828                     MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
829                 }
830
831                 if ((charW == VK_RETURN || charW == VK_ESCAPE) && es->hwndListBox)
832                 {
833                    if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0))
834                       SendMessageW(GetParent(hwnd), WM_KEYDOWN, charW, 0);
835                    break;
836                 }
837                 EDIT_WM_Char(es, charW);
838                 break;
839         }
840
841         case WM_CLEAR:
842                 EDIT_WM_Clear(es);
843                 break;
844
845         case WM_COMMAND:
846                 EDIT_WM_Command(es, HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
847                 break;
848
849         case WM_CONTEXTMENU:
850                 EDIT_WM_ContextMenu(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
851                 break;
852
853         case WM_COPY:
854                 EDIT_WM_Copy(es);
855                 break;
856
857         case WM_CREATE:
858                 if(unicode)
859                     result = EDIT_WM_Create(es, ((LPCREATESTRUCTW)lParam)->lpszName);
860                 else
861                 {
862                     LPCSTR nameA = ((LPCREATESTRUCTA)lParam)->lpszName;
863                     LPWSTR nameW = NULL;
864                     if(nameA)
865                     {
866                         INT countW = MultiByteToWideChar(CP_ACP, 0, nameA, -1, NULL, 0);
867                         if((nameW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
868                             MultiByteToWideChar(CP_ACP, 0, nameA, -1, nameW, countW);
869                     }
870                     result = EDIT_WM_Create(es, nameW);
871                     HeapFree(GetProcessHeap(), 0, nameW);
872                 }
873                 break;
874
875         case WM_CUT:
876                 EDIT_WM_Cut(es);
877                 break;
878
879         case WM_ENABLE:
880                 es->bEnableState = (BOOL) wParam;
881                 EDIT_UpdateText(es, NULL, TRUE);
882                 break;
883
884         case WM_ERASEBKGND:
885                 result = EDIT_WM_EraseBkGnd(es, (HDC)wParam);
886                 break;
887
888         case WM_GETFONT:
889                 result = (LRESULT)es->font;
890                 break;
891
892         case WM_GETTEXT:
893                 result = (LRESULT)EDIT_WM_GetText(es, (INT)wParam, (LPWSTR)lParam, unicode);
894                 break;
895
896         case WM_GETTEXTLENGTH:
897                 if (unicode) result = strlenW(es->text);
898                 else result = WideCharToMultiByte( CP_ACP, 0, es->text, strlenW(es->text),
899                                                    NULL, 0, NULL, NULL );
900                 break;
901
902         case WM_HSCROLL:
903                 result = EDIT_WM_HScroll(es, LOWORD(wParam), (short)HIWORD(wParam));
904                 break;
905
906         case WM_KEYDOWN:
907                 result = EDIT_WM_KeyDown(es, (INT)wParam);
908                 break;
909
910         case WM_KILLFOCUS:
911                 result = EDIT_WM_KillFocus(es);
912                 break;
913
914         case WM_LBUTTONDBLCLK:
915                 result = EDIT_WM_LButtonDblClk(es);
916                 break;
917
918         case WM_LBUTTONDOWN:
919                 result = EDIT_WM_LButtonDown(es, wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));
920                 break;
921
922         case WM_LBUTTONUP:
923                 result = EDIT_WM_LButtonUp(es);
924                 break;
925
926         case WM_MBUTTONDOWN:
927                 result = EDIT_WM_MButtonDown(es);
928                 break;
929
930         case WM_MOUSEMOVE:
931                 result = EDIT_WM_MouseMove(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
932                 break;
933
934         case WM_PRINTCLIENT:
935         case WM_PAINT:
936                 EDIT_WM_Paint(es, (HDC)wParam);
937                 break;
938
939         case WM_PASTE:
940                 EDIT_WM_Paste(es);
941                 break;
942
943         case WM_SETFOCUS:
944                 EDIT_WM_SetFocus(es);
945                 break;
946
947         case WM_SETFONT:
948                 EDIT_WM_SetFont(es, (HFONT)wParam, LOWORD(lParam) != 0);
949                 break;
950
951         case WM_SETREDRAW:
952                 /* FIXME: actually set an internal flag and behave accordingly */
953                 break;
954
955         case WM_SETTEXT:
956                 EDIT_WM_SetText(es, (LPCWSTR)lParam, unicode);
957                 result = TRUE;
958                 break;
959
960         case WM_SIZE:
961                 EDIT_WM_Size(es, (UINT)wParam, LOWORD(lParam), HIWORD(lParam));
962                 break;
963
964         case WM_STYLECHANGED:
965                 result = EDIT_WM_StyleChanged(es, wParam, (const STYLESTRUCT *)lParam);
966                 break;
967
968         case WM_STYLECHANGING:
969                 result = 0; /* See EDIT_WM_StyleChanged */
970                 break;
971
972         case WM_SYSKEYDOWN:
973                 result = EDIT_WM_SysKeyDown(es, (INT)wParam, (DWORD)lParam);
974                 break;
975
976         case WM_TIMER:
977                 EDIT_WM_Timer(es);
978                 break;
979
980         case WM_VSCROLL:
981                 result = EDIT_WM_VScroll(es, LOWORD(wParam), (short)HIWORD(wParam));
982                 break;
983
984         case WM_MOUSEWHEEL:
985                 {
986                     int gcWheelDelta = 0;
987                     UINT pulScrollLines = 3;
988                     SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
989
990                     if (wParam & (MK_SHIFT | MK_CONTROL)) {
991                         result = DefWindowProcW(hwnd, msg, wParam, lParam);
992                         break;
993                     }
994                     gcWheelDelta -= GET_WHEEL_DELTA_WPARAM(wParam);
995                     if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
996                     {
997                         int cLineScroll= (int) min((UINT) es->line_count, pulScrollLines);
998                         cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
999                         result = EDIT_EM_LineScroll(es, 0, cLineScroll);
1000                     }
1001                 }
1002                 break;
1003
1004             
1005         /* IME messages to make the edit control IME aware */           
1006         case WM_IME_SETCONTEXT:
1007                 break;
1008
1009         case WM_IME_STARTCOMPOSITION:
1010         /* 
1011          * FIXME in IME: This message is not always sent like it should be
1012          */
1013                 if (es->selection_start != es->selection_end)
1014                 {
1015                         static const WCHAR empty_stringW[] = {0};
1016                         EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE);
1017                 }
1018                 es->composition_start = es->selection_end;
1019                 es->composition_len = 0;
1020                 break;
1021
1022         case WM_IME_COMPOSITION:
1023                 if (es->composition_len == 0)
1024                 {
1025                         if (es->selection_start != es->selection_end)
1026                         {    
1027                                 static const WCHAR empty_stringW[] = {0};
1028                                 EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE);
1029                         }
1030
1031                         es->composition_start = es->selection_end;
1032                 }
1033                 EDIT_ImeComposition(hwnd,lParam,es);
1034                 break;
1035
1036         case WM_IME_ENDCOMPOSITION:
1037                 es->composition_len= 0;
1038                 break;
1039
1040         case WM_IME_COMPOSITIONFULL:
1041                 break;
1042
1043         case WM_IME_SELECT:
1044                 break;
1045
1046         case WM_IME_CONTROL:
1047                 break;
1048                 
1049         default:
1050                 result = DefWindowProcT(hwnd, msg, wParam, lParam, unicode);
1051                 break;
1052         }
1053         
1054         if (es) EDIT_UnlockBuffer(es, FALSE);
1055
1056         TRACE("hwnd=%p msg=%x (%s) -- 0x%08lx\n", hwnd, msg, SPY_GetMsgName(msg, hwnd), result);
1057
1058         return result;
1059 }
1060
1061 /*********************************************************************
1062  *
1063  *      EditWndProcW   (USER32.@)
1064  */
1065 LRESULT WINAPI EditWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1066 {
1067     return EditWndProc_common(hWnd, uMsg, wParam, lParam, TRUE);
1068 }
1069
1070 /*********************************************************************
1071  *
1072  *      EditWndProc   (USER32.@)
1073  */
1074 LRESULT WINAPI EditWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1075 {
1076     return EditWndProc_common(hWnd, uMsg, wParam, lParam, FALSE);
1077 }
1078
1079 /*********************************************************************
1080  *
1081  *      EDIT_BuildLineDefs_ML
1082  *
1083  *      Build linked list of text lines.
1084  *      Lines can end with '\0' (last line), a character (if it is wrapped),
1085  *      a soft return '\r\r\n' or a hard return '\r\n'
1086  *
1087  */
1088 static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta, HRGN hrgn)
1089 {
1090         HDC dc;
1091         HFONT old_font = 0;
1092         LPWSTR current_position, cp;
1093         INT fw;
1094         LINEDEF *current_line;
1095         LINEDEF *previous_line;
1096         LINEDEF *start_line;
1097         INT line_index = 0, nstart_line = 0, nstart_index = 0;
1098         INT line_count = es->line_count;
1099         INT orig_net_length;
1100         RECT rc;
1101
1102         if (istart == iend && delta == 0)
1103                 return;
1104
1105         dc = GetDC(es->hwndSelf);
1106         if (es->font)
1107                 old_font = SelectObject(dc, es->font);
1108
1109         previous_line = NULL;
1110         current_line = es->first_line_def;
1111
1112         /* Find starting line. istart must lie inside an existing line or
1113          * at the end of buffer */
1114         do {
1115                 if (istart < current_line->index + current_line->length ||
1116                                 current_line->ending == END_0)
1117                         break;
1118
1119                 previous_line = current_line;
1120                 current_line = current_line->next;
1121                 line_index++;
1122         } while (current_line);
1123
1124         if (!current_line) /* Error occurred start is not inside previous buffer */
1125         {
1126                 FIXME(" modification occurred outside buffer\n");
1127                 ReleaseDC(es->hwndSelf, dc);
1128                 return;
1129         }
1130
1131         /* Remember start of modifications in order to calculate update region */
1132         nstart_line = line_index;
1133         nstart_index = current_line->index;
1134
1135         /* We must start to reformat from the previous line since the modifications
1136          * may have caused the line to wrap upwards. */
1137         if (!(es->style & ES_AUTOHSCROLL) && line_index > 0)
1138         {
1139                 line_index--;
1140                 current_line = previous_line;
1141         }
1142         start_line = current_line;
1143
1144         fw = es->format_rect.right - es->format_rect.left;
1145         current_position = es->text + current_line->index;
1146         do {
1147                 if (current_line != start_line)
1148                 {
1149                         if (!current_line || current_line->index + delta > current_position - es->text)
1150                         {
1151                                 /* The buffer has been expanded, create a new line and
1152                                    insert it into the link list */
1153                                 LINEDEF *new_line = HeapAlloc(GetProcessHeap(), 0, sizeof(LINEDEF));
1154                                 new_line->next = previous_line->next;
1155                                 previous_line->next = new_line;
1156                                 current_line = new_line;
1157                                 es->line_count++;
1158                         }
1159                         else if (current_line->index + delta < current_position - es->text)
1160                         {
1161                                 /* The previous line merged with this line so we delete this extra entry */
1162                                 previous_line->next = current_line->next;
1163                                 HeapFree(GetProcessHeap(), 0, current_line);
1164                                 current_line = previous_line->next;
1165                                 es->line_count--;
1166                                 continue;
1167                         }
1168                         else /* current_line->index + delta == current_position */
1169                         {
1170                                 if (current_position - es->text > iend)
1171                                         break; /* We reached end of line modifications */
1172                                 /* else recalulate this line */
1173                         }
1174                 }
1175
1176                 current_line->index = current_position - es->text;
1177                 orig_net_length = current_line->net_length;
1178
1179                 /* Find end of line */
1180                 cp = current_position;
1181                 while (*cp) {
1182                     if (*cp == '\n') break;
1183                         if ((*cp == '\r') && (*(cp + 1) == '\n'))
1184                                 break;
1185                         cp++;
1186                 }
1187
1188                 /* Mark type of line termination */
1189                 if (!(*cp)) {
1190                         current_line->ending = END_0;
1191                         current_line->net_length = strlenW(current_position);
1192                 } else if ((cp > current_position) && (*(cp - 1) == '\r')) {
1193                         current_line->ending = END_SOFT;
1194                         current_line->net_length = cp - current_position - 1;
1195                 } else if (*cp == '\n') {
1196                         current_line->ending = END_RICH;
1197                         current_line->net_length = cp - current_position;
1198                 } else {
1199                         current_line->ending = END_HARD;
1200                         current_line->net_length = cp - current_position;
1201                 }
1202
1203                 /* Calculate line width */
1204                 current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc,
1205                                         current_position, current_line->net_length,
1206                                         es->tabs_count, es->tabs));
1207
1208                 /* FIXME: check here for lines that are too wide even in AUTOHSCROLL (> 32767 ???) */
1209                 if (!(es->style & ES_AUTOHSCROLL)) {
1210                    if (current_line->width > fw) {
1211                         INT next = 0;
1212                         INT prev;
1213                         do {
1214                                 prev = next;
1215                                 next = EDIT_CallWordBreakProc(es, current_position - es->text,
1216                                                 prev + 1, current_line->net_length, WB_RIGHT);
1217                                 current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc,
1218                                                         current_position, next, es->tabs_count, es->tabs));
1219                         } while (current_line->width <= fw);
1220                         if (!prev) { /* Didn't find a line break so force a break */
1221                                 next = 0;
1222                                 do {
1223                                         prev = next;
1224                                         next++;
1225                                         current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc,
1226                                                                 current_position, next, es->tabs_count, es->tabs));
1227                                 } while (current_line->width <= fw);
1228                                 if (!prev)
1229                                         prev = 1;
1230                         }
1231
1232                         /* If the first line we are calculating, wrapped before istart, we must
1233                          * adjust istart in order for this to be reflected in the update region. */
1234                         if (current_line->index == nstart_index && istart > current_line->index + prev)
1235                                 istart = current_line->index + prev;
1236                         /* else if we are updating the previous line before the first line we
1237                          * are re-calculating and it expanded */
1238                         else if (current_line == start_line &&
1239                                         current_line->index != nstart_index && orig_net_length < prev)
1240                         {
1241                           /* Line expanded due to an upwards line wrap so we must partially include
1242                            * previous line in update region */
1243                                 nstart_line = line_index;
1244                                 nstart_index = current_line->index;
1245                                 istart = current_line->index + orig_net_length;
1246                         }
1247
1248                         current_line->net_length = prev;
1249                         current_line->ending = END_WRAP;
1250                         current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, current_position,
1251                                         current_line->net_length, es->tabs_count, es->tabs));
1252                     }
1253                     else if (orig_net_length <  current_line->net_length  &&
1254                         current_line == start_line &&
1255                         current_line->index != nstart_index) {
1256                         /* The previous line expanded but it's still not as wide as the client rect */
1257                         /* The expansion is due to an upwards line wrap so we must partially include
1258                            it in the update region */
1259                         nstart_line = line_index;
1260                         nstart_index = current_line->index;
1261                         istart = current_line->index + orig_net_length;
1262                     }
1263                 }
1264
1265
1266                 /* Adjust length to include line termination */
1267                 switch (current_line->ending) {
1268                 case END_SOFT:
1269                         current_line->length = current_line->net_length + 3;
1270                         break;
1271                 case END_RICH:
1272                         current_line->length = current_line->net_length + 1;
1273                         break;
1274                 case END_HARD:
1275                         current_line->length = current_line->net_length + 2;
1276                         break;
1277                 case END_WRAP:
1278                 case END_0:
1279                         current_line->length = current_line->net_length;
1280                         break;
1281                 }
1282                 es->text_width = max(es->text_width, current_line->width);
1283                 current_position += current_line->length;
1284                 previous_line = current_line;
1285                 current_line = current_line->next;
1286                 line_index++;
1287         } while (previous_line->ending != END_0);
1288
1289         /* Finish adjusting line indexes by delta or remove hanging lines */
1290         if (previous_line->ending == END_0)
1291         {
1292                 LINEDEF *pnext = NULL;
1293
1294                 previous_line->next = NULL;
1295                 while (current_line)
1296                 {
1297                         pnext = current_line->next;
1298                         HeapFree(GetProcessHeap(), 0, current_line);
1299                         current_line = pnext;
1300                         es->line_count--;
1301                 }
1302         }
1303         else if (delta != 0)
1304         {
1305                 while (current_line)
1306                 {
1307                         current_line->index += delta;
1308                         current_line = current_line->next;
1309                 }
1310         }
1311
1312         /* Calculate rest of modification rectangle */
1313         if (hrgn)
1314         {
1315                 HRGN tmphrgn;
1316            /*
1317                 * We calculate two rectangles. One for the first line which may have
1318                 * an indent with respect to the format rect. The other is a format-width
1319                 * rectangle that spans the rest of the lines that changed or moved.
1320                 */
1321                 rc.top = es->format_rect.top + nstart_line * es->line_height -
1322                         (es->y_offset * es->line_height); /* Adjust for vertical scrollbar */
1323                 rc.bottom = rc.top + es->line_height;
1324                 if ((es->style & ES_CENTER) || (es->style & ES_RIGHT))
1325                         rc.left = es->format_rect.left;
1326                 else
1327                         rc.left = es->format_rect.left + (INT)LOWORD(GetTabbedTextExtentW(dc,
1328                                         es->text + nstart_index, istart - nstart_index,
1329                                         es->tabs_count, es->tabs)) - es->x_offset; /* Adjust for horz scroll */
1330                 rc.right = es->format_rect.right;
1331                 SetRectRgn(hrgn, rc.left, rc.top, rc.right, rc.bottom);
1332
1333                 rc.top = rc.bottom;
1334                 rc.left = es->format_rect.left;
1335                 rc.right = es->format_rect.right;
1336            /*
1337                 * If lines were added or removed we must re-paint the remainder of the
1338             * lines since the remaining lines were either shifted up or down.
1339                 */
1340                 if (line_count < es->line_count) /* We added lines */
1341                         rc.bottom = es->line_count * es->line_height;
1342                 else if (line_count > es->line_count) /* We removed lines */
1343                         rc.bottom = line_count * es->line_height;
1344                 else
1345                         rc.bottom = line_index * es->line_height;
1346                 rc.bottom += es->format_rect.top;
1347                 rc.bottom -= (es->y_offset * es->line_height); /* Adjust for vertical scrollbar */
1348                 tmphrgn = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
1349                 CombineRgn(hrgn, hrgn, tmphrgn, RGN_OR);
1350                 DeleteObject(tmphrgn);
1351         }
1352
1353         if (es->font)
1354                 SelectObject(dc, old_font);
1355
1356         ReleaseDC(es->hwndSelf, dc);
1357 }
1358
1359 /*********************************************************************
1360  *
1361  *      EDIT_CalcLineWidth_SL
1362  *
1363  */
1364 static void EDIT_CalcLineWidth_SL(EDITSTATE *es)
1365 {
1366         SIZE size;
1367         LPWSTR text;
1368         HDC dc;
1369         HFONT old_font = 0;
1370
1371         text = EDIT_GetPasswordPointer_SL(es);
1372
1373         dc = GetDC(es->hwndSelf);
1374         if (es->font)
1375                 old_font = SelectObject(dc, es->font);
1376
1377         GetTextExtentPoint32W(dc, text, strlenW(text), &size);
1378
1379         if (es->font)
1380                 SelectObject(dc, old_font);
1381         ReleaseDC(es->hwndSelf, dc);
1382
1383         if (es->style & ES_PASSWORD)
1384                 HeapFree(GetProcessHeap(), 0, text);
1385
1386         es->text_width = size.cx;
1387 }
1388
1389 /*********************************************************************
1390  *
1391  *      EDIT_CallWordBreakProc
1392  *
1393  *      Call appropriate WordBreakProc (internal or external).
1394  *
1395  *      Note: The "start" argument should always be an index referring
1396  *              to es->text.  The actual wordbreak proc might be
1397  *              16 bit, so we can't always pass any 32 bit LPSTR.
1398  *              Hence we assume that es->text is the buffer that holds
1399  *              the string under examination (we can decide this for ourselves).
1400  *
1401  */
1402 static INT EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count, INT action)
1403 {
1404         INT ret;
1405
1406         if (es->word_break_proc16) {
1407             HGLOBAL16 hglob16;
1408             SEGPTR segptr;
1409             INT countA;
1410             WORD args[5];
1411             DWORD result;
1412
1413             countA = WideCharToMultiByte(CP_ACP, 0, es->text + start, count, NULL, 0, NULL, NULL);
1414             hglob16 = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT, countA);
1415             segptr = WOWGlobalLock16(hglob16);
1416             WideCharToMultiByte(CP_ACP, 0, es->text + start, count, MapSL(segptr), countA, NULL, NULL);
1417             args[4] = SELECTOROF(segptr);
1418             args[3] = OFFSETOF(segptr);
1419             args[2] = index;
1420             args[1] = countA;
1421             args[0] = action;
1422             WOWCallback16Ex((DWORD)es->word_break_proc16, WCB16_PASCAL, sizeof(args), args, &result);
1423             ret = LOWORD(result);
1424             GlobalUnlock16(hglob16);
1425             GlobalFree16(hglob16);
1426         }
1427         else if (es->word_break_proc)
1428         {
1429             if(es->is_unicode)
1430             {
1431                 EDITWORDBREAKPROCW wbpW = (EDITWORDBREAKPROCW)es->word_break_proc;
1432
1433                 TRACE_(relay)("(UNICODE wordbrk=%p,str=%s,idx=%d,cnt=%d,act=%d)\n",
1434                         es->word_break_proc, debugstr_wn(es->text + start, count), index, count, action);
1435                 ret = wbpW(es->text + start, index, count, action);
1436             }
1437             else
1438             {
1439                 EDITWORDBREAKPROCA wbpA = (EDITWORDBREAKPROCA)es->word_break_proc;
1440                 INT countA;
1441                 CHAR *textA;
1442
1443                 countA = WideCharToMultiByte(CP_ACP, 0, es->text + start, count, NULL, 0, NULL, NULL);
1444                 textA = HeapAlloc(GetProcessHeap(), 0, countA);
1445                 WideCharToMultiByte(CP_ACP, 0, es->text + start, count, textA, countA, NULL, NULL);
1446                 TRACE_(relay)("(ANSI wordbrk=%p,str=%s,idx=%d,cnt=%d,act=%d)\n",
1447                         es->word_break_proc, debugstr_an(textA, countA), index, countA, action);
1448                 ret = wbpA(textA, index, countA, action);
1449                 HeapFree(GetProcessHeap(), 0, textA);
1450             }
1451         }
1452         else
1453             ret = EDIT_WordBreakProc(es->text + start, index, count, action);
1454
1455         return ret;
1456 }
1457
1458
1459 /*********************************************************************
1460  *
1461  *      EDIT_CharFromPos
1462  *
1463  *      Beware: This is not the function called on EM_CHARFROMPOS
1464  *              The position _can_ be outside the formatting / client
1465  *              rectangle
1466  *              The return value is only the character index
1467  *
1468  */
1469 static INT EDIT_CharFromPos(EDITSTATE *es, INT x, INT y, LPBOOL after_wrap)
1470 {
1471         INT index;
1472         HDC dc;
1473         HFONT old_font = 0;
1474         INT x_high = 0, x_low = 0;
1475
1476         if (es->style & ES_MULTILINE) {
1477                 INT line = (y - es->format_rect.top) / es->line_height + es->y_offset;
1478                 INT line_index = 0;
1479                 LINEDEF *line_def = es->first_line_def;
1480                 INT low, high;
1481                 while ((line > 0) && line_def->next) {
1482                         line_index += line_def->length;
1483                         line_def = line_def->next;
1484                         line--;
1485                 }
1486                 x += es->x_offset - es->format_rect.left;
1487                 if (es->style & ES_RIGHT)
1488                         x -= (es->format_rect.right - es->format_rect.left) - line_def->width;
1489                 else if (es->style & ES_CENTER)
1490                         x -= ((es->format_rect.right - es->format_rect.left) - line_def->width) / 2;
1491                 if (x >= line_def->width) {
1492                         if (after_wrap)
1493                                 *after_wrap = (line_def->ending == END_WRAP);
1494                         return line_index + line_def->net_length;
1495                 }
1496                 if (x <= 0) {
1497                         if (after_wrap)
1498                                 *after_wrap = FALSE;
1499                         return line_index;
1500                 }
1501                 dc = GetDC(es->hwndSelf);
1502                 if (es->font)
1503                         old_font = SelectObject(dc, es->font);
1504                     low = line_index;
1505                     high = line_index + line_def->net_length + 1;
1506                     while (low < high - 1)
1507                     {
1508                         INT mid = (low + high) / 2;
1509                         INT x_now = LOWORD(GetTabbedTextExtentW(dc, es->text + line_index, mid - line_index, es->tabs_count, es->tabs));
1510                         if (x_now > x) {
1511                             high = mid;
1512                             x_high = x_now;
1513                         } else {
1514                             low = mid;
1515                             x_low = x_now;
1516                         }
1517                     }
1518                     if (abs(x_high - x) + 1 <= abs(x_low - x))
1519                         index = high;
1520                     else
1521                         index = low;
1522
1523                 if (after_wrap)
1524                         *after_wrap = ((index == line_index + line_def->net_length) &&
1525                                                         (line_def->ending == END_WRAP));
1526         } else {
1527                 LPWSTR text;
1528                 SIZE size;
1529                 if (after_wrap)
1530                         *after_wrap = FALSE;
1531                 x -= es->format_rect.left;
1532                 if (!x)
1533                         return es->x_offset;
1534
1535                 if (!es->x_offset)
1536                 {
1537                         INT indent = (es->format_rect.right - es->format_rect.left) - es->text_width;
1538                         if (es->style & ES_RIGHT)
1539                                 x -= indent;
1540                         else if (es->style & ES_CENTER)
1541                                 x -= indent / 2;
1542                 }
1543
1544                 text = EDIT_GetPasswordPointer_SL(es);
1545                 dc = GetDC(es->hwndSelf);
1546                 if (es->font)
1547                         old_font = SelectObject(dc, es->font);
1548                 if (x < 0)
1549                 {
1550                     INT low = 0;
1551                     INT high = es->x_offset;
1552                     while (low < high - 1)
1553                     {
1554                         INT mid = (low + high) / 2;
1555                         GetTextExtentPoint32W( dc, text + mid,
1556                                                es->x_offset - mid, &size );
1557                         if (size.cx > -x) {
1558                             low = mid;
1559                             x_low = size.cx;
1560                         } else {
1561                             high = mid;
1562                             x_high = size.cx;
1563                         }
1564                     }
1565                     if (abs(x_high + x) <= abs(x_low + x) + 1)
1566                         index = high;
1567                     else
1568                         index = low;
1569                 }
1570                 else
1571                 {
1572                     INT low = es->x_offset;
1573                     INT high = strlenW(es->text) + 1;
1574                     while (low < high - 1)
1575                     {
1576                         INT mid = (low + high) / 2;
1577                         GetTextExtentPoint32W( dc, text + es->x_offset,
1578                                                mid - es->x_offset, &size );
1579                         if (size.cx > x) {
1580                                high = mid;
1581                                x_high = size.cx;
1582                         } else {
1583                                low = mid;
1584                                x_low = size.cx;
1585                        }
1586                     }
1587                    if (abs(x_high - x) <= abs(x_low - x) + 1)
1588                        index = high;
1589                    else
1590                        index = low;
1591                 }
1592                 if (es->style & ES_PASSWORD)
1593                         HeapFree(GetProcessHeap(), 0, text);
1594         }
1595         if (es->font)
1596                 SelectObject(dc, old_font);
1597         ReleaseDC(es->hwndSelf, dc);
1598         return index;
1599 }
1600
1601
1602 /*********************************************************************
1603  *
1604  *      EDIT_ConfinePoint
1605  *
1606  *      adjusts the point to be within the formatting rectangle
1607  *      (so CharFromPos returns the nearest _visible_ character)
1608  *
1609  */
1610 static void EDIT_ConfinePoint(EDITSTATE *es, LPINT x, LPINT y)
1611 {
1612         *x = min(max(*x, es->format_rect.left), es->format_rect.right - 1);
1613         *y = min(max(*y, es->format_rect.top), es->format_rect.bottom - 1);
1614 }
1615
1616
1617 /*********************************************************************
1618  *
1619  *      EDIT_GetLineRect
1620  *
1621  *      Calculates the bounding rectangle for a line from a starting
1622  *      column to an ending column.
1623  *
1624  */
1625 static void EDIT_GetLineRect(EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc)
1626 {
1627         INT line_index =  EDIT_EM_LineIndex(es, line);
1628
1629         if (es->style & ES_MULTILINE)
1630                 rc->top = es->format_rect.top + (line - es->y_offset) * es->line_height;
1631         else
1632                 rc->top = es->format_rect.top;
1633         rc->bottom = rc->top + es->line_height;
1634         rc->left = (scol == 0) ? es->format_rect.left : (short)LOWORD(EDIT_EM_PosFromChar(es, line_index + scol, TRUE));
1635         rc->right = (ecol == -1) ? es->format_rect.right : (short)LOWORD(EDIT_EM_PosFromChar(es, line_index + ecol, TRUE));
1636 }
1637
1638
1639 /*********************************************************************
1640  *
1641  *      EDIT_GetPasswordPointer_SL
1642  *
1643  *      note: caller should free the (optionally) allocated buffer
1644  *
1645  */
1646 static LPWSTR EDIT_GetPasswordPointer_SL(EDITSTATE *es)
1647 {
1648         if (es->style & ES_PASSWORD) {
1649                 INT len = strlenW(es->text);
1650                 LPWSTR text = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1651                 text[len] = '\0';
1652                 while(len) text[--len] = es->password_char;
1653                 return text;
1654         } else
1655                 return es->text;
1656 }
1657
1658
1659 /*********************************************************************
1660  *
1661  *      EDIT_LockBuffer
1662  *
1663  *      This acts as a LocalLock16(), but it locks only once.  This way
1664  *      you can call it whenever you like, without unlocking.
1665  *
1666  *      Initially the edit control allocates a HLOCAL32 buffer 
1667  *      (32 bit linear memory handler).  However, 16 bit application
1668  *      might send an EM_GETHANDLE message and expect a HLOCAL16 (16 bit SEG:OFF
1669  *      handler).  From that moment on we have to keep using this 16 bit memory
1670  *      handler, because it is supposed to be valid at all times after EM_GETHANDLE.
1671  *      What we do is create a HLOCAL16 buffer, copy the text, and do pointer
1672  *      conversion.
1673  *
1674  */
1675 static void EDIT_LockBuffer(EDITSTATE *es)
1676 {
1677         STACK16FRAME* stack16 = MapSL((SEGPTR)NtCurrentTeb()->WOW32Reserved);
1678         HINSTANCE16 hInstance = GetWindowLongPtrW( es->hwndSelf, GWLP_HINSTANCE );
1679
1680         if (!es->text) {
1681             CHAR *textA = NULL;
1682             UINT countA = 0;
1683             BOOL _16bit = FALSE;
1684
1685             if(es->hloc32W)
1686             {
1687                 if(es->hloc32A)
1688                 {
1689                     TRACE("Synchronizing with 32-bit ANSI buffer\n");
1690                     textA = LocalLock(es->hloc32A);
1691                     countA = strlen(textA) + 1;
1692                 }
1693                 else if(es->hloc16)
1694                 {
1695                     HANDLE16 oldDS = stack16->ds;
1696                     TRACE("Synchronizing with 16-bit ANSI buffer\n");
1697                     stack16->ds = hInstance;
1698                     textA = MapSL(LocalLock16(es->hloc16));
1699                     stack16->ds = oldDS;
1700                     countA = strlen(textA) + 1;
1701                     _16bit = TRUE;
1702                 }
1703             }
1704             else {
1705                 ERR("no buffer ... please report\n");
1706                 return;
1707             }
1708
1709             if(textA)
1710             {
1711                 HLOCAL hloc32W_new;
1712                 UINT countW_new = MultiByteToWideChar(CP_ACP, 0, textA, countA, NULL, 0);
1713                 TRACE("%d bytes translated to %d WCHARs\n", countA, countW_new);
1714                 if(countW_new > es->buffer_size + 1)
1715                 {
1716                     UINT alloc_size = ROUND_TO_GROW(countW_new * sizeof(WCHAR));
1717                     TRACE("Resizing 32-bit UNICODE buffer from %d+1 to %d WCHARs\n", es->buffer_size, countW_new);
1718                     hloc32W_new = LocalReAlloc(es->hloc32W, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT);
1719                     if(hloc32W_new)
1720                     {
1721                         es->hloc32W = hloc32W_new;
1722                         es->buffer_size = LocalSize(hloc32W_new)/sizeof(WCHAR) - 1;
1723                         TRACE("Real new size %d+1 WCHARs\n", es->buffer_size);
1724                     }
1725                     else
1726                         WARN("FAILED! Will synchronize partially\n");
1727                 }
1728             }
1729
1730             /*TRACE("Locking 32-bit UNICODE buffer\n");*/
1731             es->text = LocalLock(es->hloc32W);
1732
1733             if(textA)
1734             {
1735                 MultiByteToWideChar(CP_ACP, 0, textA, countA, es->text, es->buffer_size + 1);
1736                 if(_16bit)
1737                 {
1738                     HANDLE16 oldDS = stack16->ds;
1739                     stack16->ds = hInstance;
1740                     LocalUnlock16(es->hloc16);
1741                     stack16->ds = oldDS;
1742                 }
1743                 else
1744                     LocalUnlock(es->hloc32A);
1745             }
1746         }
1747         es->lock_count++;
1748 }
1749
1750
1751 /*********************************************************************
1752  *
1753  *      EDIT_SL_InvalidateText
1754  *
1755  *      Called from EDIT_InvalidateText().
1756  *      Does the job for single-line controls only.
1757  *
1758  */
1759 static void EDIT_SL_InvalidateText(EDITSTATE *es, INT start, INT end)
1760 {
1761         RECT line_rect;
1762         RECT rc;
1763
1764         EDIT_GetLineRect(es, 0, start, end, &line_rect);
1765         if (IntersectRect(&rc, &line_rect, &es->format_rect))
1766                 EDIT_UpdateText(es, &rc, TRUE);
1767 }
1768
1769
1770 /*********************************************************************
1771  *
1772  *      EDIT_ML_InvalidateText
1773  *
1774  *      Called from EDIT_InvalidateText().
1775  *      Does the job for multi-line controls only.
1776  *
1777  */
1778 static void EDIT_ML_InvalidateText(EDITSTATE *es, INT start, INT end)
1779 {
1780         INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
1781         INT sl = EDIT_EM_LineFromChar(es, start);
1782         INT el = EDIT_EM_LineFromChar(es, end);
1783         INT sc;
1784         INT ec;
1785         RECT rc1;
1786         RECT rcWnd;
1787         RECT rcLine;
1788         RECT rcUpdate;
1789         INT l;
1790
1791         if ((el < es->y_offset) || (sl > es->y_offset + vlc))
1792                 return;
1793
1794         sc = start - EDIT_EM_LineIndex(es, sl);
1795         ec = end - EDIT_EM_LineIndex(es, el);
1796         if (sl < es->y_offset) {
1797                 sl = es->y_offset;
1798                 sc = 0;
1799         }
1800         if (el > es->y_offset + vlc) {
1801                 el = es->y_offset + vlc;
1802                 ec = EDIT_EM_LineLength(es, EDIT_EM_LineIndex(es, el));
1803         }
1804         GetClientRect(es->hwndSelf, &rc1);
1805         IntersectRect(&rcWnd, &rc1, &es->format_rect);
1806         if (sl == el) {
1807                 EDIT_GetLineRect(es, sl, sc, ec, &rcLine);
1808                 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
1809                         EDIT_UpdateText(es, &rcUpdate, TRUE);
1810         } else {
1811                 EDIT_GetLineRect(es, sl, sc,
1812                                 EDIT_EM_LineLength(es,
1813                                         EDIT_EM_LineIndex(es, sl)),
1814                                 &rcLine);
1815                 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
1816                         EDIT_UpdateText(es, &rcUpdate, TRUE);
1817                 for (l = sl + 1 ; l < el ; l++) {
1818                         EDIT_GetLineRect(es, l, 0,
1819                                 EDIT_EM_LineLength(es,
1820                                         EDIT_EM_LineIndex(es, l)),
1821                                 &rcLine);
1822                         if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
1823                                 EDIT_UpdateText(es, &rcUpdate, TRUE);
1824                 }
1825                 EDIT_GetLineRect(es, el, 0, ec, &rcLine);
1826                 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
1827                         EDIT_UpdateText(es, &rcUpdate, TRUE);
1828         }
1829 }
1830
1831
1832 /*********************************************************************
1833  *
1834  *      EDIT_InvalidateText
1835  *
1836  *      Invalidate the text from offset start up to, but not including,
1837  *      offset end.  Useful for (re)painting the selection.
1838  *      Regions outside the linewidth are not invalidated.
1839  *      end == -1 means end == TextLength.
1840  *      start and end need not be ordered.
1841  *
1842  */
1843 static void EDIT_InvalidateText(EDITSTATE *es, INT start, INT end)
1844 {
1845         if (end == start)
1846                 return;
1847
1848         if (end == -1)
1849                 end = strlenW(es->text);
1850
1851         if (end < start) {
1852             INT tmp = start;
1853             start = end;
1854             end = tmp;
1855         }
1856
1857         if (es->style & ES_MULTILINE)
1858                 EDIT_ML_InvalidateText(es, start, end);
1859         else
1860                 EDIT_SL_InvalidateText(es, start, end);
1861 }
1862
1863
1864 /*********************************************************************
1865  *
1866  *      EDIT_MakeFit
1867  *
1868  * Try to fit size + 1 characters in the buffer.
1869  */
1870 static BOOL EDIT_MakeFit(EDITSTATE *es, UINT size)
1871 {
1872         HLOCAL hNew32W;
1873
1874         if (size <= es->buffer_size)
1875                 return TRUE;
1876
1877         TRACE("trying to ReAlloc to %d+1 characters\n", size);
1878
1879         /* Force edit to unlock it's buffer. es->text now NULL */
1880         EDIT_UnlockBuffer(es, TRUE);
1881
1882         if (es->hloc32W) {
1883             UINT alloc_size = ROUND_TO_GROW((size + 1) * sizeof(WCHAR));
1884             if ((hNew32W = LocalReAlloc(es->hloc32W, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT))) {
1885                 TRACE("Old 32 bit handle %p, new handle %p\n", es->hloc32W, hNew32W);
1886                 es->hloc32W = hNew32W;
1887                 es->buffer_size = LocalSize(hNew32W)/sizeof(WCHAR) - 1;
1888             }
1889         }
1890
1891         EDIT_LockBuffer(es);
1892
1893         if (es->buffer_size < size) {
1894                 WARN("FAILED !  We now have %d+1\n", es->buffer_size);
1895                 EDIT_NOTIFY_PARENT(es, EN_ERRSPACE);
1896                 return FALSE;
1897         } else {
1898                 TRACE("We now have %d+1\n", es->buffer_size);
1899                 return TRUE;
1900         }
1901 }
1902
1903
1904 /*********************************************************************
1905  *
1906  *      EDIT_MakeUndoFit
1907  *
1908  *      Try to fit size + 1 bytes in the undo buffer.
1909  *
1910  */
1911 static BOOL EDIT_MakeUndoFit(EDITSTATE *es, UINT size)
1912 {
1913         UINT alloc_size;
1914
1915         if (size <= es->undo_buffer_size)
1916                 return TRUE;
1917
1918         TRACE("trying to ReAlloc to %d+1\n", size);
1919
1920         alloc_size = ROUND_TO_GROW((size + 1) * sizeof(WCHAR));
1921         if ((es->undo_text = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, es->undo_text, alloc_size))) {
1922                 es->undo_buffer_size = alloc_size/sizeof(WCHAR) - 1;
1923                 return TRUE;
1924         }
1925         else
1926         {
1927                 WARN("FAILED !  We now have %d+1\n", es->undo_buffer_size);
1928                 return FALSE;
1929         }
1930 }
1931
1932
1933 /*********************************************************************
1934  *
1935  *      EDIT_MoveBackward
1936  *
1937  */
1938 static void EDIT_MoveBackward(EDITSTATE *es, BOOL extend)
1939 {
1940         INT e = es->selection_end;
1941
1942         if (e) {
1943                 e--;
1944                 if ((es->style & ES_MULTILINE) && e &&
1945                                 (es->text[e - 1] == '\r') && (es->text[e] == '\n')) {
1946                         e--;
1947                         if (e && (es->text[e - 1] == '\r'))
1948                                 e--;
1949                 }
1950         }
1951         EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, FALSE);
1952         EDIT_EM_ScrollCaret(es);
1953 }
1954
1955
1956 /*********************************************************************
1957  *
1958  *      EDIT_MoveDown_ML
1959  *
1960  *      Only for multi line controls
1961  *      Move the caret one line down, on a column with the nearest
1962  *      x coordinate on the screen (might be a different column).
1963  *
1964  */
1965 static void EDIT_MoveDown_ML(EDITSTATE *es, BOOL extend)
1966 {
1967         INT s = es->selection_start;
1968         INT e = es->selection_end;
1969         BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
1970         LRESULT pos = EDIT_EM_PosFromChar(es, e, after_wrap);
1971         INT x = (short)LOWORD(pos);
1972         INT y = (short)HIWORD(pos);
1973
1974         e = EDIT_CharFromPos(es, x, y + es->line_height, &after_wrap);
1975         if (!extend)
1976                 s = e;
1977         EDIT_EM_SetSel(es, s, e, after_wrap);
1978         EDIT_EM_ScrollCaret(es);
1979 }
1980
1981
1982 /*********************************************************************
1983  *
1984  *      EDIT_MoveEnd
1985  *
1986  */
1987 static void EDIT_MoveEnd(EDITSTATE *es, BOOL extend)
1988 {
1989         BOOL after_wrap = FALSE;
1990         INT e;
1991
1992         /* Pass a high value in x to make sure of receiving the end of the line */
1993         if (es->style & ES_MULTILINE)
1994                 e = EDIT_CharFromPos(es, 0x3fffffff,
1995                         HIWORD(EDIT_EM_PosFromChar(es, es->selection_end, es->flags & EF_AFTER_WRAP)), &after_wrap);
1996         else
1997                 e = strlenW(es->text);
1998         EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, after_wrap);
1999         EDIT_EM_ScrollCaret(es);
2000 }
2001
2002
2003 /*********************************************************************
2004  *
2005  *      EDIT_MoveForward
2006  *
2007  */
2008 static void EDIT_MoveForward(EDITSTATE *es, BOOL extend)
2009 {
2010         INT e = es->selection_end;
2011
2012         if (es->text[e]) {
2013                 e++;
2014                 if ((es->style & ES_MULTILINE) && (es->text[e - 1] == '\r')) {
2015                         if (es->text[e] == '\n')
2016                                 e++;
2017                         else if ((es->text[e] == '\r') && (es->text[e + 1] == '\n'))
2018                                 e += 2;
2019                 }
2020         }
2021         EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, FALSE);
2022         EDIT_EM_ScrollCaret(es);
2023 }
2024
2025
2026 /*********************************************************************
2027  *
2028  *      EDIT_MoveHome
2029  *
2030  *      Home key: move to beginning of line.
2031  *
2032  */
2033 static void EDIT_MoveHome(EDITSTATE *es, BOOL extend)
2034 {
2035         INT e;
2036
2037         /* Pass the x_offset in x to make sure of receiving the first position of the line */
2038         if (es->style & ES_MULTILINE)
2039                 e = EDIT_CharFromPos(es, -es->x_offset,
2040                         HIWORD(EDIT_EM_PosFromChar(es, es->selection_end, es->flags & EF_AFTER_WRAP)), NULL);
2041         else
2042                 e = 0;
2043         EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, FALSE);
2044         EDIT_EM_ScrollCaret(es);
2045 }
2046
2047
2048 /*********************************************************************
2049  *
2050  *      EDIT_MovePageDown_ML
2051  *
2052  *      Only for multi line controls
2053  *      Move the caret one page down, on a column with the nearest
2054  *      x coordinate on the screen (might be a different column).
2055  *
2056  */
2057 static void EDIT_MovePageDown_ML(EDITSTATE *es, BOOL extend)
2058 {
2059         INT s = es->selection_start;
2060         INT e = es->selection_end;
2061         BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
2062         LRESULT pos = EDIT_EM_PosFromChar(es, e, after_wrap);
2063         INT x = (short)LOWORD(pos);
2064         INT y = (short)HIWORD(pos);
2065
2066         e = EDIT_CharFromPos(es, x,
2067                 y + (es->format_rect.bottom - es->format_rect.top),
2068                 &after_wrap);
2069         if (!extend)
2070                 s = e;
2071         EDIT_EM_SetSel(es, s, e, after_wrap);
2072         EDIT_EM_ScrollCaret(es);
2073 }
2074
2075
2076 /*********************************************************************
2077  *
2078  *      EDIT_MovePageUp_ML
2079  *
2080  *      Only for multi line controls
2081  *      Move the caret one page up, on a column with the nearest
2082  *      x coordinate on the screen (might be a different column).
2083  *
2084  */
2085 static void EDIT_MovePageUp_ML(EDITSTATE *es, BOOL extend)
2086 {
2087         INT s = es->selection_start;
2088         INT e = es->selection_end;
2089         BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
2090         LRESULT pos = EDIT_EM_PosFromChar(es, e, after_wrap);
2091         INT x = (short)LOWORD(pos);
2092         INT y = (short)HIWORD(pos);
2093
2094         e = EDIT_CharFromPos(es, x,
2095                 y - (es->format_rect.bottom - es->format_rect.top),
2096                 &after_wrap);
2097         if (!extend)
2098                 s = e;
2099         EDIT_EM_SetSel(es, s, e, after_wrap);
2100         EDIT_EM_ScrollCaret(es);
2101 }
2102
2103
2104 /*********************************************************************
2105  *
2106  *      EDIT_MoveUp_ML
2107  *
2108  *      Only for multi line controls
2109  *      Move the caret one line up, on a column with the nearest
2110  *      x coordinate on the screen (might be a different column).
2111  *
2112  */
2113 static void EDIT_MoveUp_ML(EDITSTATE *es, BOOL extend)
2114 {
2115         INT s = es->selection_start;
2116         INT e = es->selection_end;
2117         BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
2118         LRESULT pos = EDIT_EM_PosFromChar(es, e, after_wrap);
2119         INT x = (short)LOWORD(pos);
2120         INT y = (short)HIWORD(pos);
2121
2122         e = EDIT_CharFromPos(es, x, y - es->line_height, &after_wrap);
2123         if (!extend)
2124                 s = e;
2125         EDIT_EM_SetSel(es, s, e, after_wrap);
2126         EDIT_EM_ScrollCaret(es);
2127 }
2128
2129
2130 /*********************************************************************
2131  *
2132  *      EDIT_MoveWordBackward
2133  *
2134  */
2135 static void EDIT_MoveWordBackward(EDITSTATE *es, BOOL extend)
2136 {
2137         INT s = es->selection_start;
2138         INT e = es->selection_end;
2139         INT l;
2140         INT ll;
2141         INT li;
2142
2143         l = EDIT_EM_LineFromChar(es, e);
2144         ll = EDIT_EM_LineLength(es, e);
2145         li = EDIT_EM_LineIndex(es, l);
2146         if (e - li == 0) {
2147                 if (l) {
2148                         li = EDIT_EM_LineIndex(es, l - 1);
2149                         e = li + EDIT_EM_LineLength(es, li);
2150                 }
2151         } else {
2152                 e = li + (INT)EDIT_CallWordBreakProc(es,
2153                                 li, e - li, ll, WB_LEFT);
2154         }
2155         if (!extend)
2156                 s = e;
2157         EDIT_EM_SetSel(es, s, e, FALSE);
2158         EDIT_EM_ScrollCaret(es);
2159 }
2160
2161
2162 /*********************************************************************
2163  *
2164  *      EDIT_MoveWordForward
2165  *
2166  */
2167 static void EDIT_MoveWordForward(EDITSTATE *es, BOOL extend)
2168 {
2169         INT s = es->selection_start;
2170         INT e = es->selection_end;
2171         INT l;
2172         INT ll;
2173         INT li;
2174
2175         l = EDIT_EM_LineFromChar(es, e);
2176         ll = EDIT_EM_LineLength(es, e);
2177         li = EDIT_EM_LineIndex(es, l);
2178         if (e - li == ll) {
2179                 if ((es->style & ES_MULTILINE) && (l != es->line_count - 1))
2180                         e = EDIT_EM_LineIndex(es, l + 1);
2181         } else {
2182                 e = li + EDIT_CallWordBreakProc(es,
2183                                 li, e - li + 1, ll, WB_RIGHT);
2184         }
2185         if (!extend)
2186                 s = e;
2187         EDIT_EM_SetSel(es, s, e, FALSE);
2188         EDIT_EM_ScrollCaret(es);
2189 }
2190
2191
2192 /*********************************************************************
2193  *
2194  *      EDIT_PaintLine
2195  *
2196  */
2197 static void EDIT_PaintLine(EDITSTATE *es, HDC dc, INT line, BOOL rev)
2198 {
2199         INT s = es->selection_start;
2200         INT e = es->selection_end;
2201         INT li;
2202         INT ll;
2203         INT x;
2204         INT y;
2205         LRESULT pos;
2206
2207         if (es->style & ES_MULTILINE) {
2208                 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
2209                 if ((line < es->y_offset) || (line > es->y_offset + vlc) || (line >= es->line_count))
2210                         return;
2211         } else if (line)
2212                 return;
2213
2214         TRACE("line=%d\n", line);
2215
2216         pos = EDIT_EM_PosFromChar(es, EDIT_EM_LineIndex(es, line), FALSE);
2217         x = (short)LOWORD(pos);
2218         y = (short)HIWORD(pos);
2219         li = EDIT_EM_LineIndex(es, line);
2220         ll = EDIT_EM_LineLength(es, li);
2221         s = min(es->selection_start, es->selection_end);
2222         e = max(es->selection_start, es->selection_end);
2223         s = min(li + ll, max(li, s));
2224         e = min(li + ll, max(li, e));
2225         if (rev && (s != e) &&
2226                         ((es->flags & EF_FOCUSED) || (es->style & ES_NOHIDESEL))) {
2227                 x += EDIT_PaintText(es, dc, x, y, line, 0, s - li, FALSE);
2228                 x += EDIT_PaintText(es, dc, x, y, line, s - li, e - s, TRUE);
2229                 x += EDIT_PaintText(es, dc, x, y, line, e - li, li + ll - e, FALSE);
2230         } else
2231                 x += EDIT_PaintText(es, dc, x, y, line, 0, ll, FALSE);
2232 }
2233
2234
2235 /*********************************************************************
2236  *
2237  *      EDIT_PaintText
2238  *
2239  */
2240 static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col, INT count, BOOL rev)
2241 {
2242         COLORREF BkColor;
2243         COLORREF TextColor;
2244         LOGFONTW underline_font;
2245         HFONT hUnderline = 0;
2246         HFONT old_font = 0;
2247         INT ret;
2248         INT li;
2249         INT BkMode;
2250         SIZE size;
2251
2252         if (!count)
2253                 return 0;
2254         BkMode = GetBkMode(dc);
2255         BkColor = GetBkColor(dc);
2256         TextColor = GetTextColor(dc);
2257         if (rev) {
2258                 if (es->composition_len == 0)
2259                 {
2260                         SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));
2261                         SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2262                         SetBkMode( dc, OPAQUE);
2263                 }
2264                 else
2265                 {
2266                         HFONT current = GetCurrentObject(dc,OBJ_FONT);
2267                         GetObjectW(current,sizeof(LOGFONTW),&underline_font);
2268                         underline_font.lfUnderline = TRUE;
2269                         hUnderline = CreateFontIndirectW(&underline_font);
2270                         old_font = SelectObject(dc,hUnderline);
2271                 }
2272         }
2273         li = EDIT_EM_LineIndex(es, line);
2274         if (es->style & ES_MULTILINE) {
2275                 ret = (INT)LOWORD(TabbedTextOutW(dc, x, y, es->text + li + col, count,
2276                                         es->tabs_count, es->tabs, es->format_rect.left - es->x_offset));
2277         } else {
2278                 LPWSTR text = EDIT_GetPasswordPointer_SL(es);
2279                 TextOutW(dc, x, y, text + li + col, count);
2280                 GetTextExtentPoint32W(dc, text + li + col, count, &size);
2281                 ret = size.cx;
2282                 if (es->style & ES_PASSWORD)
2283                         HeapFree(GetProcessHeap(), 0, text);
2284         }
2285         if (rev) {
2286                 if (es->composition_len == 0)
2287                 {
2288                         SetBkColor(dc, BkColor);
2289                         SetTextColor(dc, TextColor);
2290                         SetBkMode( dc, BkMode);
2291                 }
2292                 else
2293                 {
2294                         if (old_font)
2295                                 SelectObject(dc,old_font);
2296                         if (hUnderline)
2297                                 DeleteObject(hUnderline);
2298                 }
2299         }
2300         return ret;
2301 }
2302
2303
2304 /*********************************************************************
2305  *
2306  *      EDIT_SetCaretPos
2307  *
2308  */
2309 static void EDIT_SetCaretPos(EDITSTATE *es, INT pos,
2310                              BOOL after_wrap)
2311 {
2312         LRESULT res = EDIT_EM_PosFromChar(es, pos, after_wrap);
2313         TRACE("%d - %dx%d\n", pos, (short)LOWORD(res), (short)HIWORD(res));
2314         SetCaretPos((short)LOWORD(res), (short)HIWORD(res));
2315 }
2316
2317
2318 /*********************************************************************
2319  *
2320  *      EDIT_AdjustFormatRect
2321  *
2322  *      Adjusts the format rectangle for the current font and the
2323  *      current client rectangle.
2324  *
2325  */
2326 static void EDIT_AdjustFormatRect(EDITSTATE *es)
2327 {
2328         RECT ClientRect;
2329
2330         es->format_rect.right = max(es->format_rect.right, es->format_rect.left + es->char_width);
2331         if (es->style & ES_MULTILINE)
2332         {
2333             INT fw, vlc, max_x_offset, max_y_offset;
2334
2335             vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
2336             es->format_rect.bottom = es->format_rect.top + max(1, vlc) * es->line_height;
2337
2338             /* correct es->x_offset */
2339             fw = es->format_rect.right - es->format_rect.left;
2340             max_x_offset = es->text_width - fw;
2341             if(max_x_offset < 0) max_x_offset = 0;
2342             if(es->x_offset > max_x_offset)
2343                 es->x_offset = max_x_offset;
2344
2345             /* correct es->y_offset */
2346             max_y_offset = es->line_count - vlc;
2347             if(max_y_offset < 0) max_y_offset = 0;
2348             if(es->y_offset > max_y_offset)
2349                 es->y_offset = max_y_offset;
2350
2351             /* force scroll info update */
2352             EDIT_UpdateScrollInfo(es);
2353         }
2354         else
2355         /* Windows doesn't care to fix text placement for SL controls */
2356                 es->format_rect.bottom = es->format_rect.top + es->line_height;
2357
2358         /* Always stay within the client area */
2359         GetClientRect(es->hwndSelf, &ClientRect);
2360         es->format_rect.bottom = min(es->format_rect.bottom, ClientRect.bottom);
2361
2362         if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL))
2363                 EDIT_BuildLineDefs_ML(es, 0, strlenW(es->text), 0, NULL);
2364         
2365         EDIT_SetCaretPos(es, es->selection_end, es->flags & EF_AFTER_WRAP);
2366 }
2367
2368
2369 /*********************************************************************
2370  *
2371  *      EDIT_SetRectNP
2372  *
2373  *      note:   this is not (exactly) the handler called on EM_SETRECTNP
2374  *              it is also used to set the rect of a single line control
2375  *
2376  */
2377 static void EDIT_SetRectNP(EDITSTATE *es, LPRECT rc)
2378 {
2379         LONG_PTR ExStyle;
2380         INT bw, bh;
2381         ExStyle = GetWindowLongPtrW(es->hwndSelf, GWL_EXSTYLE);
2382         
2383         CopyRect(&es->format_rect, rc);
2384         
2385         if (ExStyle & WS_EX_CLIENTEDGE) {
2386                 es->format_rect.left++;
2387                 es->format_rect.right--;
2388                 
2389                 if (es->format_rect.bottom - es->format_rect.top
2390                     >= es->line_height + 2)
2391                 {
2392                         es->format_rect.top++;
2393                         es->format_rect.bottom--;
2394                 }
2395         }
2396         else if (es->style & WS_BORDER) {
2397                 bw = GetSystemMetrics(SM_CXBORDER) + 1;
2398                 bh = GetSystemMetrics(SM_CYBORDER) + 1;
2399                 es->format_rect.left += bw;
2400                 es->format_rect.right -= bw;
2401                 if (es->format_rect.bottom - es->format_rect.top
2402                   >= es->line_height + 2 * bh)
2403                 {
2404                     es->format_rect.top += bh;
2405                     es->format_rect.bottom -= bh;
2406                 }
2407         }
2408         
2409         es->format_rect.left += es->left_margin;
2410         es->format_rect.right -= es->right_margin;
2411         EDIT_AdjustFormatRect(es);
2412 }
2413
2414
2415 /*********************************************************************
2416  *
2417  *      EDIT_UnlockBuffer
2418  *
2419  */
2420 static void EDIT_UnlockBuffer(EDITSTATE *es, BOOL force)
2421 {
2422
2423         /* Edit window might be already destroyed */
2424         if(!IsWindow(es->hwndSelf))
2425         {
2426             WARN("edit hwnd %p already destroyed\n", es->hwndSelf);
2427             return;
2428         }
2429
2430         if (!es->lock_count) {
2431                 ERR("lock_count == 0 ... please report\n");
2432                 return;
2433         }
2434         if (!es->text) {
2435                 ERR("es->text == 0 ... please report\n");
2436                 return;
2437         }
2438
2439         if (force || (es->lock_count == 1)) {
2440             if (es->hloc32W) {
2441                 CHAR *textA = NULL;
2442                 UINT countA = 0;
2443                 UINT countW = strlenW(es->text) + 1;
2444                 STACK16FRAME* stack16 = NULL;
2445                 HANDLE16 oldDS = 0;
2446
2447                 if(es->hloc32A)
2448                 {
2449                     UINT countA_new = WideCharToMultiByte(CP_ACP, 0, es->text, countW, NULL, 0, NULL, NULL);
2450                     TRACE("Synchronizing with 32-bit ANSI buffer\n");
2451                     TRACE("%d WCHARs translated to %d bytes\n", countW, countA_new);
2452                     countA = LocalSize(es->hloc32A);
2453                     if(countA_new > countA)
2454                     {
2455                         HLOCAL hloc32A_new;
2456                         UINT alloc_size = ROUND_TO_GROW(countA_new);
2457                         TRACE("Resizing 32-bit ANSI buffer from %d to %d bytes\n", countA, alloc_size);
2458                         hloc32A_new = LocalReAlloc(es->hloc32A, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT);
2459                         if(hloc32A_new)
2460                         {
2461                             es->hloc32A = hloc32A_new;
2462                             countA = LocalSize(hloc32A_new);
2463                             TRACE("Real new size %d bytes\n", countA);
2464                         }
2465                         else
2466                             WARN("FAILED! Will synchronize partially\n");
2467                     }
2468                     textA = LocalLock(es->hloc32A);
2469                 }
2470                 else if(es->hloc16)
2471                 {
2472                     UINT countA_new = WideCharToMultiByte(CP_ACP, 0, es->text, countW, NULL, 0, NULL, NULL);
2473
2474                     TRACE("Synchronizing with 16-bit ANSI buffer\n");
2475                     TRACE("%d WCHARs translated to %d bytes\n", countW, countA_new);
2476
2477                     stack16 = MapSL((SEGPTR)NtCurrentTeb()->WOW32Reserved);
2478                     oldDS = stack16->ds;
2479                     stack16->ds = GetWindowLongPtrW( es->hwndSelf, GWLP_HINSTANCE );
2480
2481                     countA = LocalSize16(es->hloc16);
2482                     if(countA_new > countA)
2483                     {
2484                         HLOCAL16 hloc16_new;
2485                         UINT alloc_size = ROUND_TO_GROW(countA_new);
2486                         TRACE("Resizing 16-bit ANSI buffer from %d to %d bytes\n", countA, alloc_size);
2487                         hloc16_new = LocalReAlloc16(es->hloc16, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT);
2488                         if(hloc16_new)
2489                         {
2490                             es->hloc16 = hloc16_new;
2491                             countA = LocalSize16(hloc16_new);
2492                             TRACE("Real new size %d bytes\n", countA);
2493                         }
2494                         else
2495                             WARN("FAILED! Will synchronize partially\n");
2496                     }
2497                     textA = MapSL(LocalLock16(es->hloc16));
2498                 }
2499
2500                 if(textA)
2501                 {
2502                     WideCharToMultiByte(CP_ACP, 0, es->text, countW, textA, countA, NULL, NULL);
2503                     if(stack16)
2504                         LocalUnlock16(es->hloc16);
2505                     else
2506                         LocalUnlock(es->hloc32A);
2507                 }
2508
2509                 if (stack16) stack16->ds = oldDS;
2510                 LocalUnlock(es->hloc32W);
2511                 es->text = NULL;
2512             }
2513             else {
2514                 ERR("no buffer ... please report\n");
2515                 return;
2516             }
2517         }
2518         es->lock_count--;
2519 }
2520
2521
2522 /*********************************************************************
2523  *
2524  *      EDIT_UpdateScrollInfo
2525  *
2526  */
2527 static void EDIT_UpdateScrollInfo(EDITSTATE *es)
2528 {
2529     if ((es->style & WS_VSCROLL) && !(es->flags & EF_VSCROLL_TRACK))
2530     {
2531         SCROLLINFO si;
2532         si.cbSize       = sizeof(SCROLLINFO);
2533         si.fMask        = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
2534         si.nMin         = 0;
2535         si.nMax         = es->line_count - 1;
2536         si.nPage        = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
2537         si.nPos         = es->y_offset;
2538         TRACE("SB_VERT, nMin=%d, nMax=%d, nPage=%d, nPos=%d\n",
2539                 si.nMin, si.nMax, si.nPage, si.nPos);
2540         SetScrollInfo(es->hwndSelf, SB_VERT, &si, TRUE);
2541     }
2542
2543     if ((es->style & WS_HSCROLL) && !(es->flags & EF_HSCROLL_TRACK))
2544     {
2545         SCROLLINFO si;
2546         si.cbSize       = sizeof(SCROLLINFO);
2547         si.fMask        = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
2548         si.nMin         = 0;
2549         si.nMax         = es->text_width - 1;
2550         si.nPage        = es->format_rect.right - es->format_rect.left;
2551         si.nPos         = es->x_offset;
2552         TRACE("SB_HORZ, nMin=%d, nMax=%d, nPage=%d, nPos=%d\n",
2553                 si.nMin, si.nMax, si.nPage, si.nPos);
2554         SetScrollInfo(es->hwndSelf, SB_HORZ, &si, TRUE);
2555     }
2556 }
2557
2558 /*********************************************************************
2559  *
2560  *      EDIT_WordBreakProc
2561  *
2562  *      Find the beginning of words.
2563  *      Note:   unlike the specs for a WordBreakProc, this function only
2564  *              allows to be called without linebreaks between s[0] up to
2565  *              s[count - 1].  Remember it is only called
2566  *              internally, so we can decide this for ourselves.
2567  *
2568  */
2569 static INT CALLBACK EDIT_WordBreakProc(LPWSTR s, INT index, INT count, INT action)
2570 {
2571         INT ret = 0;
2572
2573         TRACE("s=%p, index=%d, count=%d, action=%d\n", s, index, count, action);
2574
2575         if(!s) return 0;
2576
2577         switch (action) {
2578         case WB_LEFT:
2579                 if (!count)
2580                         break;
2581                 if (index)
2582                         index--;
2583                 if (s[index] == ' ') {
2584                         while (index && (s[index] == ' '))
2585                                 index--;
2586                         if (index) {
2587                                 while (index && (s[index] != ' '))
2588                                         index--;
2589                                 if (s[index] == ' ')
2590                                         index++;
2591                         }
2592                 } else {
2593                         while (index && (s[index] != ' '))
2594                                 index--;
2595                         if (s[index] == ' ')
2596                                 index++;
2597                 }
2598                 ret = index;
2599                 break;
2600         case WB_RIGHT:
2601                 if (!count)
2602                         break;
2603                 if (index)
2604                         index--;
2605                 if (s[index] == ' ')
2606                         while ((index < count) && (s[index] == ' ')) index++;
2607                 else {
2608                         while (s[index] && (s[index] != ' ') && (index < count))
2609                                 index++;
2610                         while ((s[index] == ' ') && (index < count)) index++;
2611                 }
2612                 ret = index;
2613                 break;
2614         case WB_ISDELIMITER:
2615                 ret = (s[index] == ' ');
2616                 break;
2617         default:
2618                 ERR("unknown action code, please report !\n");
2619                 break;
2620         }
2621         return ret;
2622 }
2623
2624
2625 /*********************************************************************
2626  *
2627  *      EM_CHARFROMPOS
2628  *
2629  *      returns line number (not index) in high-order word of result.
2630  *      NB : Q137805 is unclear about this. POINT * pointer in lParam apply
2631  *      to Richedit, not to the edit control. Original documentation is valid.
2632  *      FIXME: do the specs mean to return -1 if outside client area or
2633  *              if outside formatting rectangle ???
2634  *
2635  */
2636 static LRESULT EDIT_EM_CharFromPos(EDITSTATE *es, INT x, INT y)
2637 {
2638         POINT pt;
2639         RECT rc;
2640         INT index;
2641
2642         pt.x = x;
2643         pt.y = y;
2644         GetClientRect(es->hwndSelf, &rc);
2645         if (!PtInRect(&rc, pt))
2646                 return -1;
2647
2648         index = EDIT_CharFromPos(es, x, y, NULL);
2649         return MAKELONG(index, EDIT_EM_LineFromChar(es, index));
2650 }
2651
2652
2653 /*********************************************************************
2654  *
2655  *      EM_FMTLINES
2656  *
2657  * Enable or disable soft breaks.
2658  * 
2659  * This means: insert or remove the soft linebreak character (\r\r\n).
2660  * Take care to check if the text still fits the buffer after insertion.
2661  * If not, notify with EN_ERRSPACE.
2662  * 
2663  */
2664 static BOOL EDIT_EM_FmtLines(EDITSTATE *es, BOOL add_eol)
2665 {
2666         es->flags &= ~EF_USE_SOFTBRK;
2667         if (add_eol) {
2668                 es->flags |= EF_USE_SOFTBRK;
2669                 FIXME("soft break enabled, not implemented\n");
2670         }
2671         return add_eol;
2672 }
2673
2674
2675 /*********************************************************************
2676  *
2677  *      EM_GETHANDLE
2678  *
2679  *      Hopefully this won't fire back at us.
2680  *      We always start with a fixed buffer in the local heap.
2681  *      Despite of the documentation says that the local heap is used
2682  *      only if DS_LOCALEDIT flag is set, NT and 2000 always allocate
2683  *      buffer on the local heap.
2684  *
2685  */
2686 static HLOCAL EDIT_EM_GetHandle(EDITSTATE *es)
2687 {
2688         HLOCAL hLocal;
2689
2690         if (!(es->style & ES_MULTILINE))
2691                 return 0;
2692
2693         if(es->is_unicode)
2694             hLocal = es->hloc32W;
2695         else
2696         {
2697             if(!es->hloc32A)
2698             {
2699                 CHAR *textA;
2700                 UINT countA, alloc_size;
2701                 TRACE("Allocating 32-bit ANSI alias buffer\n");
2702                 countA = WideCharToMultiByte(CP_ACP, 0, es->text, -1, NULL, 0, NULL, NULL);
2703                 alloc_size = ROUND_TO_GROW(countA);
2704                 if(!(es->hloc32A = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size)))
2705                 {
2706                     ERR("Could not allocate %d bytes for 32-bit ANSI alias buffer\n", alloc_size);
2707                     return 0;
2708                 }
2709                 textA = LocalLock(es->hloc32A);
2710                 WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, countA, NULL, NULL);
2711                 LocalUnlock(es->hloc32A);
2712             }
2713             hLocal = es->hloc32A;
2714         }
2715
2716         TRACE("Returning %p, LocalSize() = %ld\n", hLocal, LocalSize(hLocal));
2717         return hLocal;
2718 }
2719
2720
2721 /*********************************************************************
2722  *
2723  *      EM_GETHANDLE16
2724  *
2725  *      Hopefully this won't fire back at us.
2726  *      We always start with a buffer in 32 bit linear memory.
2727  *      However, with this message a 16 bit application requests
2728  *      a handle of 16 bit local heap memory, where it expects to find
2729  *      the text.
2730  *      It's a pitty that from this moment on we have to use this
2731  *      local heap, because applications may rely on the handle
2732  *      in the future.
2733  *
2734  *      In this function we'll try to switch to local heap.
2735  */
2736 static HLOCAL16 EDIT_EM_GetHandle16(EDITSTATE *es)
2737 {
2738         CHAR *textA;
2739         UINT countA, alloc_size;
2740         STACK16FRAME* stack16;
2741         HANDLE16 oldDS;
2742
2743         if (!(es->style & ES_MULTILINE))
2744                 return 0;
2745
2746         if (es->hloc16)
2747                 return es->hloc16;
2748
2749         stack16 = MapSL((SEGPTR)NtCurrentTeb()->WOW32Reserved);
2750         oldDS = stack16->ds;
2751         stack16->ds = GetWindowLongPtrW( es->hwndSelf, GWLP_HINSTANCE );
2752
2753         if (!LocalHeapSize16()) {
2754
2755                 if (!LocalInit16(stack16->ds, 0, GlobalSize16(stack16->ds))) {
2756                         ERR("could not initialize local heap\n");
2757                         goto done;
2758                 }
2759                 TRACE("local heap initialized\n");
2760         }
2761
2762         countA = WideCharToMultiByte(CP_ACP, 0, es->text, -1, NULL, 0, NULL, NULL);
2763         alloc_size = ROUND_TO_GROW(countA);
2764
2765         TRACE("Allocating 16-bit ANSI alias buffer\n");
2766         if (!(es->hloc16 = LocalAlloc16(LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size))) {
2767                 ERR("could not allocate new 16 bit buffer\n");
2768                 goto done;
2769         }
2770
2771         if (!(textA = MapSL(LocalLock16( es->hloc16)))) {
2772                 ERR("could not lock new 16 bit buffer\n");
2773                 LocalFree16(es->hloc16);
2774                 es->hloc16 = 0;
2775                 goto done;
2776         }
2777
2778         WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, countA, NULL, NULL);
2779         LocalUnlock16(es->hloc16);
2780
2781         TRACE("Returning %04X, LocalSize() = %d\n", es->hloc16, LocalSize16(es->hloc16));
2782
2783 done:
2784         stack16->ds = oldDS;
2785         return es->hloc16;
2786 }
2787
2788
2789 /*********************************************************************
2790  *
2791  *      EM_GETLINE
2792  *
2793  */
2794 static INT EDIT_EM_GetLine(EDITSTATE *es, INT line, LPWSTR dst, BOOL unicode)
2795 {
2796         LPWSTR src;
2797         INT line_len, dst_len;
2798         INT i;
2799
2800         if (es->style & ES_MULTILINE) {
2801                 if (line >= es->line_count)
2802                         return 0;
2803         } else
2804                 line = 0;
2805         i = EDIT_EM_LineIndex(es, line);
2806         src = es->text + i;
2807         line_len = EDIT_EM_LineLength(es, i);
2808         dst_len = *(WORD *)dst;
2809         if(unicode)
2810         {
2811             if(dst_len <= line_len)
2812             {
2813                 memcpy(dst, src, dst_len * sizeof(WCHAR));
2814                 return dst_len;
2815             }
2816             else /* Append 0 if enough space */
2817             {
2818                 memcpy(dst, src, line_len * sizeof(WCHAR));
2819                 dst[line_len] = 0;
2820                 return line_len;
2821             }
2822         }
2823         else
2824         {
2825             INT ret = WideCharToMultiByte(CP_ACP, 0, src, line_len, (LPSTR)dst, dst_len, NULL, NULL);
2826             if(!ret && line_len) /* Insufficient buffer size */
2827                 return dst_len;
2828             if(ret < dst_len) /* Append 0 if enough space */
2829                 ((LPSTR)dst)[ret] = 0;
2830             return ret;
2831         }
2832 }
2833
2834
2835 /*********************************************************************
2836  *
2837  *      EM_GETSEL
2838  *
2839  */
2840 static LRESULT EDIT_EM_GetSel(EDITSTATE *es, PUINT start, PUINT end)
2841 {
2842         UINT s = es->selection_start;
2843         UINT e = es->selection_end;
2844
2845         ORDER_UINT(s, e);
2846         if (start)
2847                 *start = s;
2848         if (end)
2849                 *end = e;
2850         return MAKELONG(s, e);
2851 }
2852
2853
2854 /*********************************************************************
2855  *
2856  *      EM_GETTHUMB
2857  *
2858  *      FIXME: is this right ?  (or should it be only VSCROLL)
2859  *      (and maybe only for edit controls that really have their
2860  *      own scrollbars) (and maybe only for multiline controls ?)
2861  *      All in all: very poorly documented
2862  *
2863  */
2864 static LRESULT EDIT_EM_GetThumb(EDITSTATE *es)
2865 {
2866         return MAKELONG(EDIT_WM_VScroll(es, EM_GETTHUMB16, 0),
2867                 EDIT_WM_HScroll(es, EM_GETTHUMB16, 0));
2868 }
2869
2870
2871 /*********************************************************************
2872  *
2873  *      EM_LINEFROMCHAR
2874  *
2875  */
2876 static INT EDIT_EM_LineFromChar(EDITSTATE *es, INT index)
2877 {
2878         INT line;
2879         LINEDEF *line_def;
2880
2881         if (!(es->style & ES_MULTILINE))
2882                 return 0;
2883         if (index > (INT)strlenW(es->text))
2884                 return es->line_count - 1;
2885         if (index == -1)
2886                 index = min(es->selection_start, es->selection_end);
2887
2888         line = 0;
2889         line_def = es->first_line_def;
2890         index -= line_def->length;
2891         while ((index >= 0) && line_def->next) {
2892                 line++;
2893                 line_def = line_def->next;
2894                 index -= line_def->length;
2895         }
2896         return line;
2897 }
2898
2899
2900 /*********************************************************************
2901  *
2902  *      EM_LINEINDEX
2903  *
2904  */
2905 static INT EDIT_EM_LineIndex(EDITSTATE *es, INT line)
2906 {
2907         INT line_index;
2908         LINEDEF *line_def;
2909
2910         if (!(es->style & ES_MULTILINE))
2911                 return 0;
2912         if (line >= es->line_count)
2913                 return -1;
2914
2915         line_index = 0;
2916         line_def = es->first_line_def;
2917         if (line == -1) {
2918                 INT index = es->selection_end - line_def->length;
2919                 while ((index >= 0) && line_def->next) {
2920                         line_index += line_def->length;
2921                         line_def = line_def->next;
2922                         index -= line_def->length;
2923                 }
2924         } else {
2925                 while (line > 0) {
2926                         line_index += line_def->length;
2927                         line_def = line_def->next;
2928                         line--;
2929                 }
2930         }
2931         return line_index;
2932 }
2933
2934
2935 /*********************************************************************
2936  *
2937  *      EM_LINELENGTH
2938  *
2939  */
2940 static INT EDIT_EM_LineLength(EDITSTATE *es, INT index)
2941 {
2942         LINEDEF *line_def;
2943
2944         if (!(es->style & ES_MULTILINE))
2945                 return strlenW(es->text);
2946
2947         if (index == -1) {
2948                 /* get the number of remaining non-selected chars of selected lines */
2949                 INT32 l; /* line number */
2950                 INT32 li; /* index of first char in line */
2951                 INT32 count;
2952                 l = EDIT_EM_LineFromChar(es, es->selection_start);
2953                 /* # chars before start of selection area */
2954                 count = es->selection_start - EDIT_EM_LineIndex(es, l);
2955                 l = EDIT_EM_LineFromChar(es, es->selection_end);
2956                 /* # chars after end of selection */
2957                 li = EDIT_EM_LineIndex(es, l);
2958                 count += li + EDIT_EM_LineLength(es, li) - es->selection_end;
2959                 return count;
2960         }
2961         line_def = es->first_line_def;
2962         index -= line_def->length;
2963         while ((index >= 0) && line_def->next) {
2964                 line_def = line_def->next;
2965                 index -= line_def->length;
2966         }
2967         return line_def->net_length;
2968 }
2969
2970
2971 /*********************************************************************
2972  *
2973  *      EM_LINESCROLL
2974  *
2975  *      NOTE: dx is in average character widths, dy - in lines;
2976  *
2977  */
2978 static BOOL EDIT_EM_LineScroll(EDITSTATE *es, INT dx, INT dy)
2979 {
2980         if (!(es->style & ES_MULTILINE))
2981                 return FALSE;
2982
2983         dx *= es->char_width;
2984         return EDIT_EM_LineScroll_internal(es, dx, dy);
2985 }
2986
2987 /*********************************************************************
2988  *
2989  *      EDIT_EM_LineScroll_internal
2990  *
2991  *      Version of EDIT_EM_LineScroll for internal use.
2992  *      It doesn't refuse if ES_MULTILINE is set and assumes that
2993  *      dx is in pixels, dy - in lines.
2994  *
2995  */
2996 static BOOL EDIT_EM_LineScroll_internal(EDITSTATE *es, INT dx, INT dy)
2997 {
2998         INT nyoff;
2999         INT x_offset_in_pixels;
3000         INT lines_per_page = (es->format_rect.bottom - es->format_rect.top) /
3001                               es->line_height;
3002
3003         if (es->style & ES_MULTILINE)
3004         {
3005             x_offset_in_pixels = es->x_offset;
3006         }
3007         else
3008         {
3009             dy = 0;
3010             x_offset_in_pixels = (short)LOWORD(EDIT_EM_PosFromChar(es, es->x_offset, FALSE));
3011         }
3012
3013         if (-dx > x_offset_in_pixels)
3014                 dx = -x_offset_in_pixels;
3015         if (dx > es->text_width - x_offset_in_pixels)
3016                 dx = es->text_width - x_offset_in_pixels;
3017         nyoff = max(0, es->y_offset + dy);
3018         if (nyoff >= es->line_count - lines_per_page)
3019                 nyoff = max(0, es->line_count - lines_per_page);
3020         dy = (es->y_offset - nyoff) * es->line_height;
3021         if (dx || dy) {
3022                 RECT rc1;
3023                 RECT rc;
3024
3025                 es->y_offset = nyoff;
3026                 if(es->style & ES_MULTILINE)
3027                     es->x_offset += dx;
3028                 else
3029                     es->x_offset += dx / es->char_width;
3030
3031                 GetClientRect(es->hwndSelf, &rc1);
3032                 IntersectRect(&rc, &rc1, &es->format_rect);
3033                 ScrollWindowEx(es->hwndSelf, -dx, dy,
3034                                 NULL, &rc, NULL, NULL, SW_INVALIDATE);
3035                 /* force scroll info update */
3036                 EDIT_UpdateScrollInfo(es);
3037         }
3038         if (dx && !(es->flags & EF_HSCROLL_TRACK))
3039                 EDIT_NOTIFY_PARENT(es, EN_HSCROLL);
3040         if (dy && !(es->flags & EF_VSCROLL_TRACK))
3041                 EDIT_NOTIFY_PARENT(es, EN_VSCROLL);
3042         return TRUE;
3043 }
3044
3045
3046 /*********************************************************************
3047  *
3048  *      EM_POSFROMCHAR
3049  *
3050  */
3051 static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap)
3052 {
3053         INT len = strlenW(es->text);
3054         INT l;
3055         INT li;
3056         INT x;
3057         INT y = 0;
3058         INT w;
3059         INT lw = 0;
3060         INT ll = 0;
3061         HDC dc;
3062         HFONT old_font = 0;
3063         SIZE size;
3064         LINEDEF *line_def;
3065
3066         index = min(index, len);
3067         dc = GetDC(es->hwndSelf);
3068         if (es->font)
3069                 old_font = SelectObject(dc, es->font);
3070         if (es->style & ES_MULTILINE) {
3071                 l = EDIT_EM_LineFromChar(es, index);
3072                 y = (l - es->y_offset) * es->line_height;
3073                 li = EDIT_EM_LineIndex(es, l);
3074                 if (after_wrap && (li == index) && l) {
3075                         INT l2 = l - 1;
3076                         line_def = es->first_line_def;
3077                         while (l2) {
3078                                 line_def = line_def->next;
3079                                 l2--;
3080                         }
3081                         if (line_def->ending == END_WRAP) {
3082                                 l--;
3083                                 y -= es->line_height;
3084                                 li = EDIT_EM_LineIndex(es, l);
3085                         }
3086                 }
3087
3088                 line_def = es->first_line_def;
3089                 while (line_def->index != li)
3090                         line_def = line_def->next;
3091
3092                 ll = line_def->net_length;
3093                 lw = line_def->width;
3094
3095                 w = es->format_rect.right - es->format_rect.left;
3096                 if (es->style & ES_RIGHT)
3097                 {
3098                         x = LOWORD(GetTabbedTextExtentW(dc, es->text + li + (index - li), ll - (index - li),
3099                                 es->tabs_count, es->tabs)) - es->x_offset;
3100                         x = w - x;
3101                 }
3102                 else if (es->style & ES_CENTER)
3103                 {
3104                         x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li,
3105                                 es->tabs_count, es->tabs)) - es->x_offset;
3106                         x += (w - lw) / 2;
3107                 }
3108                 else /* ES_LEFT */
3109                 {
3110                     x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li,
3111                                 es->tabs_count, es->tabs)) - es->x_offset;
3112                 }
3113         } else {
3114                 LPWSTR text = EDIT_GetPasswordPointer_SL(es);
3115                 if (index < es->x_offset) {
3116                         GetTextExtentPoint32W(dc, text + index,
3117                                         es->x_offset - index, &size);
3118                         x = -size.cx;
3119                 } else {
3120                         GetTextExtentPoint32W(dc, text + es->x_offset,
3121                                         index - es->x_offset, &size);
3122                          x = size.cx;
3123
3124                         if (!es->x_offset && (es->style & (ES_RIGHT | ES_CENTER)))
3125                         {
3126                                 w = es->format_rect.right - es->format_rect.left;
3127                                 if (w > es->text_width)
3128                                 {
3129                                         if (es->style & ES_RIGHT)
3130                                                 x += w - es->text_width;
3131                                         else if (es->style & ES_CENTER)
3132                                                 x += (w - es->text_width) / 2;
3133                                 }
3134                         }
3135                 }
3136                 y = 0;
3137                 if (es->style & ES_PASSWORD)
3138                         HeapFree(GetProcessHeap(), 0, text);
3139         }
3140         x += es->format_rect.left;
3141         y += es->format_rect.top;
3142         if (es->font)
3143                 SelectObject(dc, old_font);
3144         ReleaseDC(es->hwndSelf, dc);
3145         return MAKELONG((INT16)x, (INT16)y);
3146 }
3147
3148
3149 /*********************************************************************
3150  *
3151  *      EM_REPLACESEL
3152  *
3153  *      FIXME: handle ES_NUMBER and ES_OEMCONVERT here
3154  *
3155  */
3156 static void EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replace, BOOL send_update, BOOL honor_limit)
3157 {
3158         UINT strl = strlenW(lpsz_replace);
3159         UINT tl = strlenW(es->text);
3160         UINT utl;
3161         UINT s;
3162         UINT e;
3163         UINT i;
3164         UINT size;
3165         LPWSTR p;
3166         HRGN hrgn = 0;
3167         LPWSTR buf = NULL;
3168         UINT bufl = 0;
3169
3170         TRACE("%s, can_undo %d, send_update %d\n",
3171             debugstr_w(lpsz_replace), can_undo, send_update);
3172
3173         s = es->selection_start;
3174         e = es->selection_end;
3175
3176         if ((s == e) && !strl)
3177                 return;
3178
3179         ORDER_UINT(s, e);
3180
3181         size = tl - (e - s) + strl;
3182         if (!size)
3183                 es->text_width = 0;
3184
3185         /* Issue the EN_MAXTEXT notification and continue with replacing text
3186          * such that buffer limit is honored. */
3187         if ((honor_limit) && (es->buffer_limit > 0) && (size > es->buffer_limit)) {
3188                 EDIT_NOTIFY_PARENT(es, EN_MAXTEXT);
3189                 strl = es->buffer_limit - (tl - (e-s));
3190         }
3191
3192         if (!EDIT_MakeFit(es, tl - (e - s) + strl))
3193                 return;
3194
3195         if (e != s) {
3196                 /* there is something to be deleted */
3197                 TRACE("deleting stuff.\n");
3198                 bufl = e - s;
3199                 buf = HeapAlloc(GetProcessHeap(), 0, (bufl + 1) * sizeof(WCHAR));
3200                 if (!buf) return;
3201                 memcpy(buf, es->text + s, bufl * sizeof(WCHAR));
3202                 buf[bufl] = 0; /* ensure 0 termination */
3203                 /* now delete */
3204                 strcpyW(es->text + s, es->text + e);
3205         }
3206         if (strl) {
3207                 /* there is an insertion */
3208                 tl = strlenW(es->text);
3209                 TRACE("inserting stuff (tl %d, strl %d, selstart %d ('%s'), text '%s')\n", tl, strl, s, debugstr_w(es->text + s), debugstr_w(es->text));
3210                 for (p = es->text + tl ; p >= es->text + s ; p--)
3211                         p[strl] = p[0];
3212                 for (i = 0 , p = es->text + s ; i < strl ; i++)
3213                         p[i] = lpsz_replace[i];
3214                 if(es->style & ES_UPPERCASE)
3215                         CharUpperBuffW(p, strl);
3216                 else if(es->style & ES_LOWERCASE)
3217                         CharLowerBuffW(p, strl);
3218         }
3219         if (es->style & ES_MULTILINE)
3220         {
3221                 INT st = min(es->selection_start, es->selection_end);
3222                 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
3223
3224                 hrgn = CreateRectRgn(0, 0, 0, 0);
3225                 EDIT_BuildLineDefs_ML(es, st, st + strl,
3226                                 strl - abs(es->selection_end - es->selection_start), hrgn);
3227                 /* if text is too long undo all changes */
3228                 if (honor_limit && !(es->style & ES_AUTOVSCROLL) && (es->line_count > vlc)) {
3229                         if (strl)
3230                                 strcpyW(es->text + e, es->text + e + strl);
3231                         if (e != s)
3232                                 for (i = 0 , p = es->text ; i < e - s ; i++)
3233                                         p[i + s] = buf[i];
3234                         EDIT_BuildLineDefs_ML(es, s, e, 
3235                                 abs(es->selection_end - es->selection_start) - strl, hrgn);
3236                         strl = 0;
3237                         e = s;
3238                         hrgn = CreateRectRgn(0, 0, 0, 0);
3239                         EDIT_NOTIFY_PARENT(es, EN_MAXTEXT);
3240                 }
3241         }
3242         else {
3243                 INT fw = es->format_rect.right - es->format_rect.left;
3244                 EDIT_CalcLineWidth_SL(es);
3245                 /* remove chars that don't fit */
3246                 if (honor_limit && !(es->style & ES_AUTOHSCROLL) && (es->text_width > fw)) {
3247                         while ((es->text_width > fw) && s + strl >= s) {
3248                                 strcpyW(es->text + s + strl - 1, es->text + s + strl);
3249                                 strl--;
3250                                 EDIT_CalcLineWidth_SL(es);
3251                         }
3252                         EDIT_NOTIFY_PARENT(es, EN_MAXTEXT);
3253                 }
3254         }
3255         
3256         if (e != s) {
3257                 if (can_undo) {
3258                         utl = strlenW(es->undo_text);
3259                         if (!es->undo_insert_count && (*es->undo_text && (s == es->undo_position))) {
3260                                 /* undo-buffer is extended to the right */
3261                                 EDIT_MakeUndoFit(es, utl + e - s);
3262                                 memcpy(es->undo_text + utl, buf, (e - s)*sizeof(WCHAR));
3263                                 (es->undo_text + utl)[e - s] = 0; /* ensure 0 termination */
3264                         } else if (!es->undo_insert_count && (*es->undo_text && (e == es->undo_position))) {
3265                                 /* undo-buffer is extended to the left */
3266                                 EDIT_MakeUndoFit(es, utl + e - s);
3267                                 for (p = es->undo_text + utl ; p >= es->undo_text ; p--)
3268                                         p[e - s] = p[0];
3269                                 for (i = 0 , p = es->undo_text ; i < e - s ; i++)
3270                                         p[i] = buf[i];
3271                                 es->undo_position = s;
3272                         } else {
3273                                 /* new undo-buffer */
3274                                 EDIT_MakeUndoFit(es, e - s);
3275                                 memcpy(es->undo_text, buf, (e - s)*sizeof(WCHAR));
3276                                 es->undo_text[e - s] = 0; /* ensure 0 termination */
3277                                 es->undo_position = s;
3278                         }
3279                         /* any deletion makes the old insertion-undo invalid */
3280                         es->undo_insert_count = 0;
3281                 } else
3282                         EDIT_EM_EmptyUndoBuffer(es);
3283         }
3284         if (strl) {
3285                 if (can_undo) {
3286                         if ((s == es->undo_position) ||
3287                                 ((es->undo_insert_count) &&
3288                                 (s == es->undo_position + es->undo_insert_count)))
3289                                 /*
3290                                  * insertion is new and at delete position or
3291                                  * an extension to either left or right
3292                                  */
3293                                 es->undo_insert_count += strl;
3294                         else {
3295                                 /* new insertion undo */
3296                                 es->undo_position = s;
3297                                 es->undo_insert_count = strl;
3298                                 /* new insertion makes old delete-buffer invalid */
3299                                 *es->undo_text = '\0';
3300                         }
3301                 } else
3302                         EDIT_EM_EmptyUndoBuffer(es);
3303         }
3304
3305         if (bufl)
3306                 HeapFree(GetProcessHeap(), 0, buf);
3307  
3308         s += strl;
3309
3310         /* If text has been deleted and we're right or center aligned then scroll rightward */
3311         if (es->style & (ES_RIGHT | ES_CENTER))
3312         {
3313                 INT delta = strl - abs(es->selection_end - es->selection_start);
3314
3315                 if (delta < 0 && es->x_offset)
3316                 {
3317                         if (abs(delta) > es->x_offset)
3318                                 es->x_offset = 0;
3319                         else
3320                                 es->x_offset += delta;
3321                 }
3322         }
3323
3324         EDIT_EM_SetSel(es, s, s, FALSE);
3325         es->flags |= EF_MODIFIED;
3326         if (send_update) es->flags |= EF_UPDATE;
3327         if (hrgn)
3328         {
3329                 EDIT_UpdateTextRegion(es, hrgn, TRUE);
3330                 DeleteObject(hrgn);
3331         }
3332         else
3333             EDIT_UpdateText(es, NULL, TRUE);
3334
3335         EDIT_EM_ScrollCaret(es);
3336
3337         /* force scroll info update */
3338         EDIT_UpdateScrollInfo(es);
3339
3340
3341         if(send_update || (es->flags & EF_UPDATE))
3342         {
3343             es->flags &= ~EF_UPDATE;
3344             EDIT_NOTIFY_PARENT(es, EN_CHANGE);
3345         }
3346 }
3347
3348
3349 /*********************************************************************
3350  *
3351  *      EM_SCROLL
3352  *
3353  */
3354 static LRESULT EDIT_EM_Scroll(EDITSTATE *es, INT action)
3355 {
3356         INT dy;
3357
3358         if (!(es->style & ES_MULTILINE))
3359                 return (LRESULT)FALSE;
3360
3361         dy = 0;
3362
3363         switch (action) {
3364         case SB_LINEUP:
3365                 if (es->y_offset)
3366                         dy = -1;
3367                 break;
3368         case SB_LINEDOWN:
3369                 if (es->y_offset < es->line_count - 1)
3370                         dy = 1;
3371                 break;
3372         case SB_PAGEUP:
3373                 if (es->y_offset)
3374                         dy = -(es->format_rect.bottom - es->format_rect.top) / es->line_height;
3375                 break;
3376         case SB_PAGEDOWN:
3377                 if (es->y_offset < es->line_count - 1)
3378                         dy = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
3379                 break;
3380         default:
3381                 return (LRESULT)FALSE;
3382         }
3383         if (dy) {
3384             INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
3385             /* check if we are going to move too far */
3386             if(es->y_offset + dy > es->line_count - vlc)
3387                 dy = es->line_count - vlc - es->y_offset;
3388
3389             /* Notification is done in EDIT_EM_LineScroll */
3390             if(dy)
3391                 EDIT_EM_LineScroll(es, 0, dy);
3392         }
3393         return MAKELONG((INT16)dy, (BOOL16)TRUE);
3394 }
3395
3396
3397 /*********************************************************************
3398  *
3399  *      EM_SCROLLCARET
3400  *
3401  */
3402 static void EDIT_EM_ScrollCaret(EDITSTATE *es)
3403 {
3404         if (es->style & ES_MULTILINE) {
3405                 INT l;
3406                 INT li;
3407                 INT vlc;
3408                 INT ww;
3409                 INT cw = es->char_width;
3410                 INT x;
3411                 INT dy = 0;
3412                 INT dx = 0;
3413
3414                 l = EDIT_EM_LineFromChar(es, es->selection_end);
3415                 li = EDIT_EM_LineIndex(es, l);
3416                 x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, es->flags & EF_AFTER_WRAP));
3417                 vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
3418                 if (l >= es->y_offset + vlc)
3419                         dy = l - vlc + 1 - es->y_offset;
3420                 if (l < es->y_offset)
3421                         dy = l - es->y_offset;
3422                 ww = es->format_rect.right - es->format_rect.left;
3423                 if (x < es->format_rect.left)
3424                         dx = x - es->format_rect.left - ww / HSCROLL_FRACTION / cw * cw;
3425                 if (x > es->format_rect.right)
3426                         dx = x - es->format_rect.left - (HSCROLL_FRACTION - 1) * ww / HSCROLL_FRACTION / cw * cw;
3427                 if (dy || dx || (es->y_offset && (es->line_count - es->y_offset < vlc)))
3428                 {
3429                     /* check if we are going to move too far */
3430                     if(es->x_offset + dx + ww > es->text_width)
3431                         dx = es->text_width - ww - es->x_offset;
3432                     if(dx || dy || (es->y_offset && (es->line_count - es->y_offset < vlc)))
3433                         EDIT_EM_LineScroll_internal(es, dx, dy);
3434                 }
3435         } else {
3436                 INT x;
3437                 INT goal;
3438                 INT format_width;
3439
3440                 x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, FALSE));
3441                 format_width = es->format_rect.right - es->format_rect.left;
3442                 if (x < es->format_rect.left) {
3443                         goal = es->format_rect.left + format_width / HSCROLL_FRACTION;
3444                         do {
3445                                 es->x_offset--;
3446                                 x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, FALSE));
3447                         } while ((x < goal) && es->x_offset);
3448                         /* FIXME: use ScrollWindow() somehow to improve performance */
3449                         EDIT_UpdateText(es, NULL, TRUE);
3450                 } else if (x > es->format_rect.right) {
3451                         INT x_last;
3452                         INT len = strlenW(es->text);
3453                         goal = es->format_rect.right - format_width / HSCROLL_FRACTION;
3454                         do {
3455                                 es->x_offset++;
3456                                 x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, FALSE));
3457                                 x_last = (short)LOWORD(EDIT_EM_PosFromChar(es, len, FALSE));
3458                         } while ((x > goal) && (x_last > es->format_rect.right));
3459                         /* FIXME: use ScrollWindow() somehow to improve performance */
3460                         EDIT_UpdateText(es, NULL, TRUE);
3461                 }
3462         }
3463
3464     if(es->flags & EF_FOCUSED)
3465         EDIT_SetCaretPos(es, es->selection_end, es->flags & EF_AFTER_WRAP);
3466 }
3467
3468
3469 /*********************************************************************
3470  *
3471  *      EM_SETHANDLE
3472  *
3473  *      FIXME:  ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???
3474  *
3475  */
3476 static void EDIT_EM_SetHandle(EDITSTATE *es, HLOCAL hloc)
3477 {
3478         if (!(es->style & ES_MULTILINE))
3479                 return;
3480
3481         if (!hloc) {
3482                 WARN("called with NULL handle\n");
3483                 return;
3484         }
3485
3486         EDIT_UnlockBuffer(es, TRUE);
3487
3488         if(es->hloc16)
3489         {
3490             STACK16FRAME* stack16 = MapSL((SEGPTR)NtCurrentTeb()->WOW32Reserved);
3491             HANDLE16 oldDS = stack16->ds;
3492         
3493             stack16->ds = GetWindowLongPtrW( es->hwndSelf, GWLP_HINSTANCE );
3494             LocalFree16(es->hloc16);
3495             stack16->ds = oldDS;
3496             es->hloc16 = 0;
3497         }
3498
3499         if(es->is_unicode)
3500         {
3501             if(es->hloc32A)
3502             {
3503                 LocalFree(es->hloc32A);
3504                 es->hloc32A = NULL;
3505             }
3506             es->hloc32W = hloc;
3507         }
3508         else
3509         {
3510             INT countW, countA;
3511             HLOCAL hloc32W_new;
3512             WCHAR *textW;
3513             CHAR *textA;
3514
3515             countA = LocalSize(hloc);
3516             textA = LocalLock(hloc);
3517             countW = MultiByteToWideChar(CP_ACP, 0, textA, countA, NULL, 0);
3518             if(!(hloc32W_new = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, countW * sizeof(WCHAR))))
3519             {
3520                 ERR("Could not allocate new unicode buffer\n");
3521                 return;
3522             }
3523             textW = LocalLock(hloc32W_new);
3524             MultiByteToWideChar(CP_ACP, 0, textA, countA, textW, countW);
3525             LocalUnlock(hloc32W_new);
3526             LocalUnlock(hloc);
3527
3528             if(es->hloc32W)
3529                 LocalFree(es->hloc32W);
3530
3531             es->hloc32W = hloc32W_new;
3532             es->hloc32A = hloc;
3533         }
3534
3535         es->buffer_size = LocalSize(es->hloc32W)/sizeof(WCHAR) - 1;
3536
3537         EDIT_LockBuffer(es);
3538
3539         es->x_offset = es->y_offset = 0;
3540         es->selection_start = es->selection_end = 0;
3541         EDIT_EM_EmptyUndoBuffer(es);
3542         es->flags &= ~EF_MODIFIED;
3543         es->flags &= ~EF_UPDATE;
3544         EDIT_BuildLineDefs_ML(es, 0, strlenW(es->text), 0, NULL);
3545         EDIT_UpdateText(es, NULL, TRUE);
3546         EDIT_EM_ScrollCaret(es);
3547         /* force scroll info update */
3548         EDIT_UpdateScrollInfo(es);
3549 }
3550
3551
3552 /*********************************************************************
3553  *
3554  *      EM_SETHANDLE16
3555  *
3556  *      FIXME:  ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???
3557  *
3558  */
3559 static void EDIT_EM_SetHandle16(EDITSTATE *es, HLOCAL16 hloc)
3560 {
3561         STACK16FRAME* stack16 = MapSL((SEGPTR)NtCurrentTeb()->WOW32Reserved);
3562         HINSTANCE16 hInstance = GetWindowLongPtrW( es->hwndSelf, GWLP_HINSTANCE );
3563         HANDLE16 oldDS = stack16->ds;
3564         INT countW, countA;
3565         HLOCAL hloc32W_new;
3566         WCHAR *textW;
3567         CHAR *textA;
3568
3569         if (!(es->style & ES_MULTILINE))
3570                 return;
3571
3572         if (!hloc) {
3573                 WARN("called with NULL handle\n");
3574                 return;
3575         }
3576
3577         EDIT_UnlockBuffer(es, TRUE);
3578
3579         if(es->hloc32A)
3580         {
3581             LocalFree(es->hloc32A);
3582             es->hloc32A = NULL;
3583         }
3584
3585         stack16->ds = hInstance;
3586         countA = LocalSize16(hloc);
3587         textA = MapSL(LocalLock16(hloc));
3588         countW = MultiByteToWideChar(CP_ACP, 0, textA, countA, NULL, 0);
3589         if(!(hloc32W_new = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, countW * sizeof(WCHAR))))
3590         {
3591             ERR("Could not allocate new unicode buffer\n");
3592             return;
3593         }
3594         textW = LocalLock(hloc32W_new);
3595         MultiByteToWideChar(CP_ACP, 0, textA, countA, textW, countW);
3596         LocalUnlock(hloc32W_new);
3597         LocalUnlock16(hloc);
3598         stack16->ds = oldDS;
3599
3600         if(es->hloc32W)
3601             LocalFree(es->hloc32W);
3602
3603         es->hloc32W = hloc32W_new;
3604         es->hloc16 = hloc;
3605
3606         es->buffer_size = LocalSize(es->hloc32W)/sizeof(WCHAR) - 1;
3607
3608         EDIT_LockBuffer(es);
3609
3610         es->x_offset = es->y_offset = 0;
3611         es->selection_start = es->selection_end = 0;
3612         EDIT_EM_EmptyUndoBuffer(es);
3613         es->flags &= ~EF_MODIFIED;
3614         es->flags &= ~EF_UPDATE;
3615         EDIT_BuildLineDefs_ML(es, 0, strlenW(es->text), 0, NULL);
3616         EDIT_UpdateText(es, NULL, TRUE);
3617         EDIT_EM_ScrollCaret(es);
3618         /* force scroll info update */
3619         EDIT_UpdateScrollInfo(es);
3620 }
3621
3622
3623 /*********************************************************************
3624  *
3625  *      EM_SETLIMITTEXT
3626  *
3627  *      FIXME: in WinNT maxsize is 0x7FFFFFFF / 0xFFFFFFFF
3628  *      However, the windows version is not complied to yet in all of edit.c
3629  *
3630  *  Additionally as the wrapper for RichEdit controls we need larger buffers
3631  *  at present -1 will represent nolimit
3632  */
3633 static void EDIT_EM_SetLimitText(EDITSTATE *es, INT limit)
3634 {
3635     if (limit == 0xFFFFFFFF)
3636         es->buffer_limit = -1;
3637     else if (es->style & ES_MULTILINE) {
3638                 if (limit)
3639                         es->buffer_limit = min(limit, BUFLIMIT_MULTI);
3640                 else
3641                         es->buffer_limit = BUFLIMIT_MULTI;
3642         } else {
3643                 if (limit)
3644                         es->buffer_limit = min(limit, BUFLIMIT_SINGLE);
3645                 else
3646                         es->buffer_limit = BUFLIMIT_SINGLE;
3647         }
3648 }
3649
3650
3651 /*********************************************************************
3652  *
3653  *      EM_SETMARGINS
3654  *
3655  * EC_USEFONTINFO is used as a left or right value i.e. lParam and not as an
3656  * action wParam despite what the docs say. EC_USEFONTINFO calculates the
3657  * margin according to the textmetrics of the current font.
3658  *
3659  * FIXME - With TrueType or vector fonts EC_USEFONTINFO currently sets one third
3660  * of the char's width as the margin, but this is not how Windows handles this.
3661  * For all other fonts Windows sets the margins to zero.
3662  *
3663  * FIXME - When EC_USEFONTINFO is used the margins only change if the
3664  * edit control is equal to or larger than a certain size.
3665  * Interestingly if one subtracts both the left and right margins from
3666  * this size one always seems to get an even number.  The extents of
3667  * the (four character) string "'**'" match this quite closely, so
3668  * we'll use this until we come up with a better idea.
3669  */
3670 static int calc_min_set_margin_size(HDC dc, INT left, INT right)
3671 {
3672     WCHAR magic_string[] = {'\'','*','*','\'', 0};
3673     SIZE sz;
3674
3675     GetTextExtentPointW(dc, magic_string, sizeof(magic_string)/sizeof(WCHAR) - 1, &sz);
3676     return sz.cx + left + right;
3677 }
3678
3679 static void EDIT_EM_SetMargins(EDITSTATE *es, INT action,
3680                                WORD left, WORD right, BOOL repaint)
3681 {
3682         TEXTMETRICW tm;
3683         INT default_left_margin  = 0; /* in pixels */
3684         INT default_right_margin = 0; /* in pixels */
3685
3686         /* Set the default margins depending on the font */
3687         if (es->font && (left == EC_USEFONTINFO || right == EC_USEFONTINFO)) {
3688             HDC dc = GetDC(es->hwndSelf);
3689             HFONT old_font = SelectObject(dc, es->font);
3690             GetTextMetricsW(dc, &tm);
3691             /* The default margins are only non zero for TrueType or Vector fonts */
3692             if (tm.tmPitchAndFamily & ( TMPF_VECTOR | TMPF_TRUETYPE )) {
3693                 int min_size;
3694                 RECT rc;
3695                 /* This must be calculated more exactly! But how? */
3696                 default_left_margin = tm.tmAveCharWidth / 2;
3697                 default_right_margin = tm.tmAveCharWidth / 2;
3698                 min_size = calc_min_set_margin_size(dc, default_left_margin, default_right_margin);
3699                 GetClientRect(es->hwndSelf, &rc);
3700                 if(rc.right - rc.left < min_size) {
3701                     default_left_margin = es->left_margin;
3702                     default_right_margin = es->right_margin;
3703                 }
3704             }
3705             SelectObject(dc, old_font);
3706             ReleaseDC(es->hwndSelf, dc);
3707         }
3708
3709         if (action & EC_LEFTMARGIN) {
3710                 es->format_rect.left -= es->left_margin;
3711                 if (left != EC_USEFONTINFO)
3712                         es->left_margin = left;
3713                 else
3714                         es->left_margin = default_left_margin;
3715                 es->format_rect.left += es->left_margin;
3716         }
3717
3718         if (action & EC_RIGHTMARGIN) {
3719                 es->format_rect.right += es->right_margin;
3720                 if (right != EC_USEFONTINFO)
3721                         es->right_margin = right;
3722                 else
3723                         es->right_margin = default_right_margin;
3724                 es->format_rect.right -= es->right_margin;
3725         }
3726         
3727         if (action & (EC_LEFTMARGIN | EC_RIGHTMARGIN)) {
3728                 EDIT_AdjustFormatRect(es);
3729                 if (repaint) EDIT_UpdateText(es, NULL, TRUE);
3730         }
3731         
3732         TRACE("left=%d, right=%d\n", es->left_margin, es->right_margin);
3733 }
3734
3735
3736 /*********************************************************************
3737  *
3738  *      EM_SETPASSWORDCHAR
3739  *
3740  */
3741 static void EDIT_EM_SetPasswordChar(EDITSTATE *es, WCHAR c)
3742 {
3743         LONG style;
3744
3745         if (es->style & ES_MULTILINE)
3746                 return;
3747
3748         if (es->password_char == c)
3749                 return;
3750
3751         style = GetWindowLongW( es->hwndSelf, GWL_STYLE );
3752         es->password_char = c;
3753         if (c) {
3754             SetWindowLongW( es->hwndSelf, GWL_STYLE, style | ES_PASSWORD );
3755             es->style |= ES_PASSWORD;
3756         } else {
3757             SetWindowLongW( es->hwndSelf, GWL_STYLE, style & ~ES_PASSWORD );
3758             es->style &= ~ES_PASSWORD;
3759         }
3760         EDIT_UpdateText(es, NULL, TRUE);
3761 }
3762
3763
3764 /*********************************************************************
3765  *
3766  *      EDIT_EM_SetSel
3767  *
3768  *      note:   unlike the specs say: the order of start and end
3769  *              _is_ preserved in Windows.  (i.e. start can be > end)
3770  *              In other words: this handler is OK
3771  *
3772  */
3773 static void EDIT_EM_SetSel(EDITSTATE *es, UINT start, UINT end, BOOL after_wrap)
3774 {
3775         UINT old_start = es->selection_start;
3776         UINT old_end = es->selection_end;
3777         UINT len = strlenW(es->text);
3778
3779         if (start == (UINT)-1) {
3780                 start = es->selection_end;
3781                 end = es->selection_end;
3782         } else {
3783                 start = min(start, len);
3784                 end = min(end, len);
3785         }
3786         es->selection_start = start;
3787         es->selection_end = end;
3788         if (after_wrap)
3789                 es->flags |= EF_AFTER_WRAP;
3790         else
3791                 es->flags &= ~EF_AFTER_WRAP;
3792         /* Compute the necessary invalidation region. */
3793         /* Note that we don't need to invalidate regions which have
3794          * "never" been selected, or those which are "still" selected.
3795          * In fact, every time we hit a selection boundary, we can
3796          * *toggle* whether we need to invalidate.  Thus we can optimize by
3797          * *sorting* the interval endpoints.  Let's assume that we sort them
3798          * in this order:
3799          *        start <= end <= old_start <= old_end
3800          * Knuth 5.3.1 (p 183) asssures us that this can be done optimally
3801          * in 5 comparisons; ie it's impossible to do better than the
3802          * following: */
3803         ORDER_UINT(end, old_end);
3804         ORDER_UINT(start, old_start);
3805         ORDER_UINT(old_start, old_end);
3806         ORDER_UINT(start, end);
3807         /* Note that at this point 'end' and 'old_start' are not in order, but
3808          * start is definitely the min. and old_end is definitely the max. */
3809         if (end != old_start)
3810         {
3811 /*
3812  * One can also do
3813  *          ORDER_UINT32(end, old_start);
3814  *          EDIT_InvalidateText(es, start, end);
3815  *          EDIT_InvalidateText(es, old_start, old_end);
3816  * in place of the following if statement.
3817  * (That would complete the optimal five-comparison four-element sort.)
3818  */
3819             if (old_start > end )
3820             {
3821                 EDIT_InvalidateText(es, start, end);
3822                 EDIT_InvalidateText(es, old_start, old_end);
3823             }
3824             else
3825             {
3826                 EDIT_InvalidateText(es, start, old_start);
3827                 EDIT_InvalidateText(es, end, old_end);
3828             }
3829         }
3830         else EDIT_InvalidateText(es, start, old_end);
3831 }
3832
3833
3834 /*********************************************************************
3835  *
3836  *      EM_SETTABSTOPS
3837  *
3838  */
3839 static BOOL EDIT_EM_SetTabStops(EDITSTATE *es, INT count, LPINT tabs)
3840 {
3841         if (!(es->style & ES_MULTILINE))
3842                 return FALSE;
3843         HeapFree(GetProcessHeap(), 0, es->tabs);
3844         es->tabs_count = count;
3845         if (!count)
3846                 es->tabs = NULL;
3847         else {
3848                 es->tabs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
3849                 memcpy(es->tabs, tabs, count * sizeof(INT));
3850         }
3851         return TRUE;
3852 }
3853
3854
3855 /*********************************************************************
3856  *
3857  *      EM_SETTABSTOPS16
3858  *
3859  */
3860 static BOOL EDIT_EM_SetTabStops16(EDITSTATE *es, INT count, LPINT16 tabs)
3861 {
3862         if (!(es->style & ES_MULTILINE))
3863                 return FALSE;
3864         HeapFree(GetProcessHeap(), 0, es->tabs);
3865         es->tabs_count = count;
3866         if (!count)
3867                 es->tabs = NULL;
3868         else {
3869                 INT i;
3870                 es->tabs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
3871                 for (i = 0 ; i < count ; i++)
3872                         es->tabs[i] = *tabs++;
3873         }
3874         return TRUE;
3875 }
3876
3877
3878 /*********************************************************************
3879  *
3880  *      EM_SETWORDBREAKPROC
3881  *
3882  */
3883 static void EDIT_EM_SetWordBreakProc(EDITSTATE *es, void *wbp)
3884 {
3885         if (es->word_break_proc == wbp)
3886                 return;
3887
3888         es->word_break_proc = wbp;
3889         es->word_break_proc16 = NULL;
3890
3891         if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) {
3892                 EDIT_BuildLineDefs_ML(es, 0, strlenW(es->text), 0, NULL);
3893                 EDIT_UpdateText(es, NULL, TRUE);
3894         }
3895 }
3896
3897
3898 /*********************************************************************
3899  *
3900  *      EM_SETWORDBREAKPROC16
3901  *
3902  */
3903 static void EDIT_EM_SetWordBreakProc16(EDITSTATE *es, EDITWORDBREAKPROC16 wbp)
3904 {
3905         if (es->word_break_proc16 == wbp)
3906                 return;
3907
3908         es->word_break_proc = NULL;
3909         es->word_break_proc16 = wbp;
3910         if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) {
3911                 EDIT_BuildLineDefs_ML(es, 0, strlenW(es->text), 0, NULL);
3912                 EDIT_UpdateText(es, NULL, TRUE);
3913         }
3914 }
3915
3916
3917 /*********************************************************************
3918  *
3919  *      EM_UNDO / WM_UNDO
3920  *
3921  */
3922 static BOOL EDIT_EM_Undo(EDITSTATE *es)
3923 {
3924         INT ulength;
3925         LPWSTR utext;
3926
3927         /* As per MSDN spec, for a single-line edit control,
3928            the return value is always TRUE */
3929         if( es->style & ES_READONLY )
3930             return !(es->style & ES_MULTILINE);
3931
3932         ulength = strlenW(es->undo_text);
3933
3934         utext = HeapAlloc(GetProcessHeap(), 0, (ulength + 1) * sizeof(WCHAR));
3935
3936         strcpyW(utext, es->undo_text);
3937
3938         TRACE("before UNDO:insertion length = %d, deletion buffer = %s\n",
3939                      es->undo_insert_count, debugstr_w(utext));
3940
3941         EDIT_EM_SetSel(es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
3942         EDIT_EM_EmptyUndoBuffer(es);
3943         EDIT_EM_ReplaceSel(es, TRUE, utext, TRUE, TRUE);
3944         EDIT_EM_SetSel(es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
3945         /* send the notification after the selection start and end are set */
3946         EDIT_NOTIFY_PARENT(es, EN_CHANGE);
3947         EDIT_EM_ScrollCaret(es);
3948         HeapFree(GetProcessHeap(), 0, utext);
3949
3950         TRACE("after UNDO:insertion length = %d, deletion buffer = %s\n",
3951                         es->undo_insert_count, debugstr_w(es->undo_text));
3952         return TRUE;
3953 }
3954
3955
3956 /*********************************************************************
3957  *
3958  *      WM_CHAR
3959  *
3960  */
3961 static void EDIT_WM_Char(EDITSTATE *es, WCHAR c)
3962 {
3963         BOOL control;
3964
3965         control = GetKeyState(VK_CONTROL) & 0x8000;
3966
3967         switch (c) {
3968         case '\r':
3969             /* If the edit doesn't want the return and it's not a multiline edit, do nothing */
3970             if(!(es->style & ES_MULTILINE) && !(es->style & ES_WANTRETURN))
3971                 break;
3972         case '\n':
3973                 if (es->style & ES_MULTILINE) {
3974                         if (es->style & ES_READONLY) {
3975                                 EDIT_MoveHome(es, FALSE);
3976                                 EDIT_MoveDown_ML(es, FALSE);
3977                         } else {
3978                                 static const WCHAR cr_lfW[] = {'\r','\n',0};
3979                                 EDIT_EM_ReplaceSel(es, TRUE, cr_lfW, TRUE, TRUE);
3980                         }
3981                 }
3982                 break;
3983         case '\t':
3984                 if ((es->style & ES_MULTILINE) && !(es->style & ES_READONLY))
3985                 {
3986                         static const WCHAR tabW[] = {'\t',0};
3987                         EDIT_EM_ReplaceSel(es, TRUE, tabW, TRUE, TRUE);
3988                 }
3989                 break;
3990         case VK_BACK:
3991                 if (!(es->style & ES_READONLY) && !control) {
3992                         if (es->selection_start != es->selection_end)
3993                                 EDIT_WM_Clear(es);
3994                         else {
3995                                 /* delete character left of caret */
3996                                 EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
3997                                 EDIT_MoveBackward(es, TRUE);
3998                                 EDIT_WM_Clear(es);
3999                         }
4000                 }
4001                 break;
4002         case 0x03: /* ^C */
4003                 SendMessageW(es->hwndSelf, WM_COPY, 0, 0);
4004                 break;
4005         case 0x16: /* ^V */
4006                 if (!(es->style & ES_READONLY))
4007                     SendMessageW(es->hwndSelf, WM_PASTE, 0, 0);
4008                 break;
4009         case 0x18: /* ^X */
4010                 if (!(es->style & ES_READONLY))
4011                     SendMessageW(es->hwndSelf, WM_CUT, 0, 0);
4012                 break;
4013
4014         default:
4015                 /*If Edit control style is ES_NUMBER allow users to key in only numeric values*/
4016                 if( (es->style & ES_NUMBER) && !( c >= '0' && c <= '9') )
4017                         break;
4018                         
4019                 if (!(es->style & ES_READONLY) && (c >= ' ') && (c != 127)) {
4020                         WCHAR str[2];
4021                         str[0] = c;
4022                         str[1] = '\0';
4023                         EDIT_EM_ReplaceSel(es, TRUE, str, TRUE, TRUE);
4024                 }
4025                 break;
4026         }
4027 }
4028
4029
4030 /*********************************************************************
4031  *
4032  *      WM_COMMAND
4033  *
4034  */
4035 static void EDIT_WM_Command(EDITSTATE *es, INT code, INT id, HWND control)
4036 {
4037         if (code || control)
4038                 return;
4039
4040         switch (id) {
4041                 case EM_UNDO:
4042                         EDIT_EM_Undo(es);
4043                         break;
4044                 case WM_CUT:
4045                         EDIT_WM_Cut(es);
4046                         break;
4047                 case WM_COPY:
4048                         EDIT_WM_Copy(es);
4049                         break;
4050                 case WM_PASTE:
4051                         EDIT_WM_Paste(es);
4052                         break;
4053                 case WM_CLEAR:
4054                         EDIT_WM_Clear(es);
4055                         break;
4056                 case EM_SETSEL:
4057                         EDIT_EM_SetSel(es, 0, (UINT)-1, FALSE);
4058                         EDIT_EM_ScrollCaret(es);
4059                         break;
4060                 default:
4061                         ERR("unknown menu item, please report\n");
4062                         break;
4063         }
4064 }
4065
4066
4067 /*********************************************************************
4068  *
4069  *      WM_CONTEXTMENU
4070  *
4071  *      Note: the resource files resource/sysres_??.rc cannot define a
4072  *              single popup menu.  Hence we use a (dummy) menubar
4073  *              containing the single popup menu as its first item.
4074  *
4075  *      FIXME: the message identifiers have been chosen arbitrarily,
4076  *              hence we use MF_BYPOSITION.
4077  *              We might as well use the "real" values (anybody knows ?)
4078  *              The menu definition is in resources/sysres_??.rc.
4079  *              Once these are OK, we better use MF_BYCOMMAND here
4080  *              (as we do in EDIT_WM_Command()).
4081  *
4082  */
4083 static void EDIT_WM_ContextMenu(EDITSTATE *es, INT x, INT y)
4084 {
4085         HMENU menu = LoadMenuA(user32_module, "EDITMENU");
4086         HMENU popup = GetSubMenu(menu, 0);
4087         UINT start = es->selection_start;
4088         UINT end = es->selection_end;
4089
4090         ORDER_UINT(start, end);
4091
4092         /* undo */
4093         EnableMenuItem(popup, 0, MF_BYPOSITION | (EDIT_EM_CanUndo(es) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
4094         /* cut */
4095         EnableMenuItem(popup, 2, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
4096         /* copy */
4097         EnableMenuItem(popup, 3, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) ? MF_ENABLED : MF_GRAYED));
4098         /* paste */
4099         EnableMenuItem(popup, 4, MF_BYPOSITION | (IsClipboardFormatAvailable(CF_UNICODETEXT) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
4100         /* delete */
4101         EnableMenuItem(popup, 5, MF_BYPOSITION | ((end - start) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
4102         /* select all */
4103         EnableMenuItem(popup, 7, MF_BYPOSITION | (start || (end != strlenW(es->text)) ? MF_ENABLED : MF_GRAYED));
4104
4105         if (x == -1 && y == -1) /* passed via VK_APPS press/release */
4106         {
4107             RECT rc;
4108             /* Windows places the menu at the edit's center in this case */
4109             GetClientRect(es->hwndSelf, &rc);
4110             MapWindowPoints(es->hwndSelf, 0, (POINT *)&rc, 2);
4111             x = rc.left + (rc.right - rc.left) / 2;
4112             y = rc.top + (rc.bottom - rc.top) / 2;
4113         }
4114
4115         TrackPopupMenu(popup, TPM_LEFTALIGN | TPM_RIGHTBUTTON, x, y, 0, es->hwndSelf, NULL);
4116         DestroyMenu(menu);
4117 }
4118
4119
4120 /*********************************************************************
4121  *
4122  *      WM_COPY
4123  *
4124  */
4125 static void EDIT_WM_Copy(EDITSTATE *es)
4126 {
4127         INT s = min(es->selection_start, es->selection_end);
4128         INT e = max(es->selection_start, es->selection_end);
4129         HGLOBAL hdst;
4130         LPWSTR dst;
4131         DWORD len;
4132
4133         if (e == s) return;
4134
4135         len = e - s;
4136         hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (len + 1) * sizeof(WCHAR));
4137         dst = GlobalLock(hdst);
4138         memcpy(dst, es->text + s, len * sizeof(WCHAR));
4139         dst[len] = 0; /* ensure 0 termination */
4140         TRACE("%s\n", debugstr_w(dst));
4141         GlobalUnlock(hdst);
4142         OpenClipboard(es->hwndSelf);
4143         EmptyClipboard();
4144         SetClipboardData(CF_UNICODETEXT, hdst);
4145         CloseClipboard();
4146 }
4147
4148
4149 /*********************************************************************
4150  *
4151  *      WM_CREATE
4152  *
4153  */
4154 static LRESULT EDIT_WM_Create(EDITSTATE *es, LPCWSTR name)
4155 {
4156         RECT clientRect;
4157         
4158         TRACE("%s\n", debugstr_w(name));
4159        /*
4160         *       To initialize some final structure members, we call some helper
4161         *       functions.  However, since the EDITSTATE is not consistent (i.e.
4162         *       not fully initialized), we should be very careful which
4163         *       functions can be called, and in what order.
4164         */
4165         EDIT_WM_SetFont(es, 0, FALSE);
4166         EDIT_EM_EmptyUndoBuffer(es);
4167         
4168         /* We need to calculate the format rect
4169            (applications may send EM_SETMARGINS before the control gets visible) */
4170         GetClientRect(es->hwndSelf, &clientRect);
4171         EDIT_SetRectNP(es, &clientRect);
4172
4173        if (name && *name) {
4174            EDIT_EM_ReplaceSel(es, FALSE, name, FALSE, FALSE);
4175            /* if we insert text to the editline, the text scrolls out
4176             * of the window, as the caret is placed after the insert
4177             * pos normally; thus we reset es->selection... to 0 and
4178             * update caret
4179             */
4180            es->selection_start = es->selection_end = 0;
4181            /* Adobe Photoshop does NOT like this. and MSDN says that EN_CHANGE
4182             * Messages are only to be sent when the USER does something to
4183             * change the contents. So I am removing this EN_CHANGE
4184             *
4185             * EDIT_NOTIFY_PARENT(es, EN_CHANGE);
4186             */
4187            EDIT_EM_ScrollCaret(es);
4188        }
4189        /* force scroll info update */
4190        EDIT_UpdateScrollInfo(es);
4191        /* The rule seems to return 1 here for success */
4192        /* Power Builder masked edit controls will crash  */
4193        /* if not. */
4194        /* FIXME: is that in all cases so ? */
4195        return 1;
4196 }
4197
4198
4199 /*********************************************************************
4200  *
4201  *      WM_DESTROY
4202  *
4203  */
4204 static LRESULT EDIT_WM_Destroy(EDITSTATE *es)
4205 {
4206         LINEDEF *pc, *pp;
4207
4208         if (es->hloc32W) {
4209                 while (LocalUnlock(es->hloc32W)) ;
4210                 LocalFree(es->hloc32W);
4211         }
4212         if (es->hloc32A) {
4213                 while (LocalUnlock(es->hloc32A)) ;
4214                 LocalFree(es->hloc32A);
4215         }
4216         if (es->hloc16) {
4217                 STACK16FRAME* stack16 = MapSL((SEGPTR)NtCurrentTeb()->WOW32Reserved);
4218                 HANDLE16 oldDS = stack16->ds;
4219
4220                 stack16->ds = GetWindowLongPtrW( es->hwndSelf, GWLP_HINSTANCE );
4221                 while (LocalUnlock16(es->hloc16)) ;
4222                 LocalFree16(es->hloc16);
4223                 stack16->ds = oldDS;
4224         }
4225
4226         pc = es->first_line_def;
4227         while (pc)
4228         {
4229                 pp = pc->next;
4230                 HeapFree(GetProcessHeap(), 0, pc);
4231                 pc = pp;
4232         }
4233
4234         SetWindowLongPtrW( es->hwndSelf, 0, 0 );
4235         HeapFree(GetProcessHeap(), 0, es);
4236
4237         return 0;
4238 }
4239
4240
4241 /*********************************************************************
4242  *
4243  *      WM_ERASEBKGND
4244  *
4245  */
4246 static LRESULT EDIT_WM_EraseBkGnd(EDITSTATE *es, HDC dc)
4247 {
4248     /* we do the proper erase in EDIT_WM_Paint */
4249     return 1;
4250 }
4251
4252
4253 /*********************************************************************
4254  *
4255  *      WM_GETTEXT
4256  *
4257  */
4258 static INT EDIT_WM_GetText(EDITSTATE *es, INT count, LPWSTR dst, BOOL unicode)
4259 {
4260     if(!count) return 0;
4261
4262     if(unicode)
4263     {
4264         lstrcpynW(dst, es->text, count);
4265         return strlenW(dst);
4266     }
4267     else
4268     {
4269         LPSTR textA = (LPSTR)dst;
4270         if (!WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, count, NULL, NULL))
4271             textA[count - 1] = 0; /* ensure 0 termination */
4272         return strlen(textA);
4273     }
4274 }
4275
4276 /*********************************************************************
4277  *
4278  *      WM_HSCROLL
4279  *
4280  */
4281 static LRESULT EDIT_WM_HScroll(EDITSTATE *es, INT action, INT pos)
4282 {
4283         INT dx;
4284         INT fw;
4285
4286         if (!(es->style & ES_MULTILINE))
4287                 return 0;
4288
4289         if (!(es->style & ES_AUTOHSCROLL))
4290                 return 0;
4291
4292         dx = 0;
4293         fw = es->format_rect.right - es->format_rect.left;
4294         switch (action) {
4295         case SB_LINELEFT:
4296                 TRACE("SB_LINELEFT\n");
4297                 if (es->x_offset)
4298                         dx = -es->char_width;
4299                 break;
4300         case SB_LINERIGHT:
4301                 TRACE("SB_LINERIGHT\n");
4302                 if (es->x_offset < es->text_width)
4303                         dx = es->char_width;
4304                 break;
4305         case SB_PAGELEFT:
4306                 TRACE("SB_PAGELEFT\n");
4307                 if (es->x_offset)
4308                         dx = -fw / HSCROLL_FRACTION / es->char_width * es->char_width;
4309                 break;
4310         case SB_PAGERIGHT:
4311                 TRACE("SB_PAGERIGHT\n");
4312                 if (es->x_offset < es->text_width)
4313                         dx = fw / HSCROLL_FRACTION / es->char_width * es->char_width;
4314                 break;
4315         case SB_LEFT:
4316                 TRACE("SB_LEFT\n");
4317                 if (es->x_offset)
4318                         dx = -es->x_offset;
4319                 break;
4320         case SB_RIGHT:
4321                 TRACE("SB_RIGHT\n");
4322                 if (es->x_offset < es->text_width)
4323                         dx = es->text_width - es->x_offset;
4324                 break;
4325         case SB_THUMBTRACK:
4326                 TRACE("SB_THUMBTRACK %d\n", pos);
4327                 es->flags |= EF_HSCROLL_TRACK;
4328                 if(es->style & WS_HSCROLL)
4329                     dx = pos - es->x_offset;
4330                 else
4331                 {
4332                     INT fw, new_x;
4333                     /* Sanity check */
4334                     if(pos < 0 || pos > 100) return 0;
4335                     /* Assume default scroll range 0-100 */
4336                     fw = es->format_rect.right - es->format_rect.left;
4337                     new_x = pos * (es->text_width - fw) / 100;
4338                     dx = es->text_width ? (new_x - es->x_offset) : 0;
4339                 }
4340                 break;
4341         case SB_THUMBPOSITION:
4342                 TRACE("SB_THUMBPOSITION %d\n", pos);
4343                 es->flags &= ~EF_HSCROLL_TRACK;
4344                 if(GetWindowLongW( es->hwndSelf, GWL_STYLE ) & WS_HSCROLL)
4345                     dx = pos - es->x_offset;
4346                 else
4347                 {
4348                     INT fw, new_x;
4349                     /* Sanity check */
4350                     if(pos < 0 || pos > 100) return 0;
4351                     /* Assume default scroll range 0-100 */
4352                     fw = es->format_rect.right - es->format_rect.left;
4353                     new_x = pos * (es->text_width - fw) / 100;
4354                     dx = es->text_width ? (new_x - es->x_offset) : 0;
4355                 }
4356                 if (!dx) {
4357                         /* force scroll info update */
4358                         EDIT_UpdateScrollInfo(es);
4359                         EDIT_NOTIFY_PARENT(es, EN_HSCROLL);
4360                 }
4361                 break;
4362         case SB_ENDSCROLL:
4363                 TRACE("SB_ENDSCROLL\n");
4364                 break;
4365         /*
4366          *      FIXME : the next two are undocumented !
4367          *      Are we doing the right thing ?
4368          *      At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
4369          *      although it's also a regular control message.
4370          */
4371         case EM_GETTHUMB: /* this one is used by NT notepad */
4372         case EM_GETTHUMB16:
4373         {
4374                 LRESULT ret;
4375                 if(GetWindowLongW( es->hwndSelf, GWL_STYLE ) & WS_HSCROLL)
4376                     ret = GetScrollPos(es->hwndSelf, SB_HORZ);
4377                 else
4378                 {
4379                     /* Assume default scroll range 0-100 */
4380                     INT fw = es->format_rect.right - es->format_rect.left;
4381                     ret = es->text_width ? es->x_offset * 100 / (es->text_width - fw) : 0;
4382                 }
4383                 TRACE("EM_GETTHUMB: returning %ld\n", ret);
4384                 return ret;
4385         }
4386         case EM_LINESCROLL16:
4387                 TRACE("EM_LINESCROLL16\n");
4388                 dx = pos;
4389                 break;
4390
4391         default:
4392                 ERR("undocumented WM_HSCROLL action %d (0x%04x), please report\n",
4393                     action, action);
4394                 return 0;
4395         }
4396         if (dx)
4397         {
4398             INT fw = es->format_rect.right - es->format_rect.left;
4399             /* check if we are going to move too far */
4400             if(es->x_offset + dx + fw > es->text_width)
4401                 dx = es->text_width - fw - es->x_offset;
4402             if(dx)
4403                 EDIT_EM_LineScroll_internal(es, dx, 0);
4404         }
4405         return 0;
4406 }
4407
4408
4409 /*********************************************************************
4410  *
4411  *      EDIT_CheckCombo
4412  *
4413  */
4414 static BOOL EDIT_CheckCombo(EDITSTATE *es, UINT msg, INT key)
4415 {
4416    HWND hLBox = es->hwndListBox;
4417    HWND hCombo;
4418    BOOL bDropped;
4419    int  nEUI;
4420
4421    if (!hLBox)
4422       return FALSE;
4423
4424    hCombo   = GetParent(es->hwndSelf);
4425    bDropped = TRUE;
4426    nEUI     = 0;
4427
4428    TRACE_(combo)("[%p]: handling msg %x (%x)\n", es->hwndSelf, msg, key);
4429
4430    if (key == VK_UP || key == VK_DOWN)
4431    {
4432       if (SendMessageW(hCombo, CB_GETEXTENDEDUI, 0, 0))
4433          nEUI = 1;
4434
4435       if (msg == WM_KEYDOWN || nEUI)
4436           bDropped = (BOOL)SendMessageW(hCombo, CB_GETDROPPEDSTATE, 0, 0);
4437    }
4438
4439    switch (msg)
4440    {
4441       case WM_KEYDOWN:
4442          if (!bDropped && nEUI && (key == VK_UP || key == VK_DOWN))
4443          {
4444             /* make sure ComboLBox pops up */
4445             SendMessageW(hCombo, CB_SETEXTENDEDUI, FALSE, 0);
4446             key = VK_F4;
4447             nEUI = 2;
4448          }
4449
4450          SendMessageW(hLBox, WM_KEYDOWN, (WPARAM)key, 0);
4451          break;
4452
4453       case WM_SYSKEYDOWN: /* Handle Alt+up/down arrows */
4454          if (nEUI)
4455             SendMessageW(hCombo, CB_SHOWDROPDOWN, bDropped ? FALSE : TRUE, 0);
4456          else
4457             SendMessageW(hLBox, WM_KEYDOWN, (WPARAM)VK_F4, 0);
4458          break;
4459    }
4460
4461    if(nEUI == 2)
4462       SendMessageW(hCombo, CB_SETEXTENDEDUI, TRUE, 0);
4463
4464    return TRUE;
4465 }
4466
4467
4468 /*********************************************************************
4469  *
4470  *      WM_KEYDOWN
4471  *
4472  *      Handling of special keys that don't produce a WM_CHAR
4473  *      (i.e. non-printable keys) & Backspace & Delete
4474  *
4475  */
4476 static LRESULT EDIT_WM_KeyDown(EDITSTATE *es, INT key)
4477 {
4478         BOOL shift;
4479         BOOL control;
4480
4481         if (GetKeyState(VK_MENU) & 0x8000)
4482                 return 0;
4483
4484         shift = GetKeyState(VK_SHIFT) & 0x8000;
4485         control = GetKeyState(VK_CONTROL) & 0x8000;
4486
4487         switch (key) {
4488         case VK_F4:
4489         case VK_UP:
4490                 if (EDIT_CheckCombo(es, WM_KEYDOWN, key) || key == VK_F4)
4491                         break;
4492
4493                 /* fall through */
4494         case VK_LEFT:
4495                 if ((es->style & ES_MULTILINE) && (key == VK_UP))
4496                         EDIT_MoveUp_ML(es, shift);
4497                 else
4498                         if (control)
4499                                 EDIT_MoveWordBackward(es, shift);
4500                         else
4501                                 EDIT_MoveBackward(es, shift);
4502                 break;
4503         case VK_DOWN:
4504                 if (EDIT_CheckCombo(es, WM_KEYDOWN, key))
4505                         break;
4506                 /* fall through */
4507         case VK_RIGHT:
4508                 if ((es->style & ES_MULTILINE) && (key == VK_DOWN))
4509                         EDIT_MoveDown_ML(es, shift);
4510                 else if (control)
4511                         EDIT_MoveWordForward(es, shift);
4512                 else
4513                         EDIT_MoveForward(es, shift);
4514                 break;
4515         case VK_HOME:
4516                 EDIT_MoveHome(es, shift);
4517                 break;
4518         case VK_END:
4519                 EDIT_MoveEnd(es, shift);
4520                 break;
4521         case VK_PRIOR:
4522                 if (es->style & ES_MULTILINE)
4523                         EDIT_MovePageUp_ML(es, shift);
4524                 else
4525                         EDIT_CheckCombo(es, WM_KEYDOWN, key);
4526                 break;
4527         case VK_NEXT:
4528                 if (es->style & ES_MULTILINE)
4529                         EDIT_MovePageDown_ML(es, shift);
4530                 else
4531                         EDIT_CheckCombo(es, WM_KEYDOWN, key);
4532                 break;
4533         case VK_DELETE:
4534                 if (!(es->style & ES_READONLY) && !(shift && control)) {
4535                         if (es->selection_start != es->selection_end) {
4536                                 if (shift)
4537                                         EDIT_WM_Cut(es);
4538                                 else
4539                                         EDIT_WM_Clear(es);
4540                         } else {
4541                                 if (shift) {
4542                                         /* delete character left of caret */
4543                                         EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
4544                                         EDIT_MoveBackward(es, TRUE);
4545                                         EDIT_WM_Clear(es);
4546                                 } else if (control) {
4547                                         /* delete to end of line */
4548                                         EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
4549                                         EDIT_MoveEnd(es, TRUE);
4550                                         EDIT_WM_Clear(es);
4551                                 } else {
4552                                         /* delete character right of caret */
4553                                         EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
4554                                         EDIT_MoveForward(es, TRUE);
4555                                         EDIT_WM_Clear(es);
4556                                 }
4557                         }
4558                 }
4559                 break;
4560         case VK_INSERT:
4561                 if (shift) {
4562                         if (!(es->style & ES_READONLY))
4563                                 EDIT_WM_Paste(es);
4564                 } else if (control)
4565                         EDIT_WM_Copy(es);
4566                 break;
4567         case VK_RETURN:
4568             /* If the edit doesn't want the return send a message to the default object */
4569             if(!(es->style & ES_WANTRETURN))
4570             {
4571                 HWND hwndParent = GetParent(es->hwndSelf);
4572                 DWORD dw = SendMessageW( hwndParent, DM_GETDEFID, 0, 0 );
4573                 if (HIWORD(dw) == DC_HASDEFID)
4574                 {
4575                     SendMessageW( hwndParent, WM_COMMAND,
4576                                   MAKEWPARAM( LOWORD(dw), BN_CLICKED ),
4577                               (LPARAM)GetDlgItem( hwndParent, LOWORD(dw) ) );
4578                 }
4579             }
4580             break;
4581         }
4582         return 0;
4583 }
4584
4585
4586 /*********************************************************************
4587  *
4588  *      WM_KILLFOCUS
4589  *
4590  */
4591 static LRESULT EDIT_WM_KillFocus(EDITSTATE *es)
4592 {
4593         es->flags &= ~EF_FOCUSED;
4594         DestroyCaret();
4595         if(!(es->style & ES_NOHIDESEL))
4596                 EDIT_InvalidateText(es, es->selection_start, es->selection_end);
4597         EDIT_NOTIFY_PARENT(es, EN_KILLFOCUS);
4598         return 0;
4599 }
4600
4601
4602 /*********************************************************************
4603  *
4604  *      WM_LBUTTONDBLCLK
4605  *
4606  *      The caret position has been set on the WM_LBUTTONDOWN message
4607  *
4608  */
4609 static LRESULT EDIT_WM_LButtonDblClk(EDITSTATE *es)
4610 {
4611         INT s;
4612         INT e = es->selection_end;
4613         INT l;
4614         INT li;
4615         INT ll;
4616
4617         es->bCaptureState = TRUE;
4618         SetCapture(es->hwndSelf);
4619
4620         l = EDIT_EM_LineFromChar(es, e);
4621         li = EDIT_EM_LineIndex(es, l);
4622         ll = EDIT_EM_LineLength(es, e);
4623         s = li + EDIT_CallWordBreakProc(es, li, e - li, ll, WB_LEFT);
4624         e = li + EDIT_CallWordBreakProc(es, li, e - li, ll, WB_RIGHT);
4625         EDIT_EM_SetSel(es, s, e, FALSE);
4626         EDIT_EM_ScrollCaret(es);
4627         es->region_posx = es->region_posy = 0;
4628         SetTimer(es->hwndSelf, 0, 100, NULL);
4629         return 0;
4630 }
4631
4632
4633 /*********************************************************************
4634  *
4635  *      WM_LBUTTONDOWN
4636  *
4637  */
4638 static LRESULT EDIT_WM_LButtonDown(EDITSTATE *es, DWORD keys, INT x, INT y)
4639 {
4640         INT e;
4641         BOOL after_wrap;
4642
4643         es->bCaptureState = TRUE;
4644         SetCapture(es->hwndSelf);
4645         EDIT_ConfinePoint(es, &x, &y);
4646         e = EDIT_CharFromPos(es, x, y, &after_wrap);
4647         EDIT_EM_SetSel(es, (keys & MK_SHIFT) ? es->selection_start : e, e, after_wrap);
4648         EDIT_EM_ScrollCaret(es);
4649         es->region_posx = es->region_posy = 0;
4650         SetTimer(es->hwndSelf, 0, 100, NULL);
4651
4652         if (!(es->flags & EF_FOCUSED))
4653             SetFocus(es->hwndSelf);
4654
4655         return 0;
4656 }
4657
4658
4659 /*********************************************************************
4660  *
4661  *      WM_LBUTTONUP
4662  *
4663  */
4664 static LRESULT EDIT_WM_LButtonUp(EDITSTATE *es)
4665 {
4666         if (es->bCaptureState) {
4667                 KillTimer(es->hwndSelf, 0);
4668                 if (GetCapture() == es->hwndSelf) ReleaseCapture();
4669         }
4670         es->bCaptureState = FALSE;
4671         return 0;
4672 }
4673
4674
4675 /*********************************************************************
4676  *
4677  *      WM_MBUTTONDOWN
4678  *
4679  */
4680 static LRESULT EDIT_WM_MButtonDown(EDITSTATE *es)
4681 {
4682     SendMessageW(es->hwndSelf, WM_PASTE, 0, 0);
4683     return 0;
4684 }
4685
4686
4687 /*********************************************************************
4688  *
4689  *      WM_MOUSEMOVE
4690  *
4691  */
4692 static LRESULT EDIT_WM_MouseMove(EDITSTATE *es, INT x, INT y)
4693 {
4694         INT e;
4695         BOOL after_wrap;
4696         INT prex, prey;
4697
4698         /* If the mouse has been captured by process other than the edit control itself,
4699          * the windows edit controls will not select the strings with mouse move.
4700          */
4701         if (!es->bCaptureState || GetCapture() != es->hwndSelf)
4702                 return 0;
4703
4704         /*
4705          *      FIXME: gotta do some scrolling if outside client
4706          *              area.  Maybe reset the timer ?
4707          */
4708         prex = x; prey = y;
4709         EDIT_ConfinePoint(es, &x, &y);
4710         es->region_posx = (prex < x) ? -1 : ((prex > x) ? 1 : 0);
4711         es->region_posy = (prey < y) ? -1 : ((prey > y) ? 1 : 0);
4712         e = EDIT_CharFromPos(es, x, y, &after_wrap);
4713         EDIT_EM_SetSel(es, es->selection_start, e, after_wrap);
4714         EDIT_SetCaretPos(es,es->selection_end,es->flags & EF_AFTER_WRAP);
4715         return 0;
4716 }
4717
4718
4719 /*********************************************************************
4720  *
4721  *      WM_NCCREATE
4722  *
4723  * See also EDIT_WM_StyleChanged
4724  */
4725 static LRESULT EDIT_WM_NCCreate(HWND hwnd, LPCREATESTRUCTW lpcs, BOOL unicode)
4726 {
4727         EDITSTATE *es;
4728         UINT alloc_size;
4729
4730         TRACE("Creating %s edit control, style = %08x\n",
4731                 unicode ? "Unicode" : "ANSI", lpcs->style);
4732
4733         if (!(es = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*es))))
4734                 return FALSE;
4735         SetWindowLongPtrW( hwnd, 0, (LONG_PTR)es );
4736
4737        /*
4738         *      Note: since the EDITSTATE has not been fully initialized yet,
4739         *            we can't use any API calls that may send
4740         *            WM_XXX messages before WM_NCCREATE is completed.
4741         */
4742
4743         es->is_unicode = unicode;
4744         es->style = lpcs->style;
4745
4746         es->bEnableState = !(es->style & WS_DISABLED);
4747
4748         es->hwndSelf = hwnd;
4749         /* Save parent, which will be notified by EN_* messages */
4750         es->hwndParent = lpcs->hwndParent;
4751
4752         if (es->style & ES_COMBO)
4753            es->hwndListBox = GetDlgItem(es->hwndParent, ID_CB_LISTBOX);
4754
4755         /* Number overrides lowercase overrides uppercase (at least it
4756          * does in Win95).  However I'll bet that ES_NUMBER would be
4757          * invalid under Win 3.1.
4758          */
4759         if (es->style & ES_NUMBER) {
4760                 ; /* do not override the ES_NUMBER */
4761         }  else if (es->style & ES_LOWERCASE) {
4762                 es->style &= ~ES_UPPERCASE;
4763         }
4764         if (es->style & ES_MULTILINE) {
4765                 es->buffer_limit = BUFLIMIT_MULTI;
4766                 if (es->style & WS_VSCROLL)
4767                         es->style |= ES_AUTOVSCROLL;
4768                 if (es->style & WS_HSCROLL)
4769                         es->style |= ES_AUTOHSCROLL;
4770                 es->style &= ~ES_PASSWORD;
4771                 if ((es->style & ES_CENTER) || (es->style & ES_RIGHT)) {
4772                         /* Confirmed - RIGHT overrides CENTER */
4773                         if (es->style & ES_RIGHT)
4774                                 es->style &= ~ES_CENTER;
4775                         es->style &= ~WS_HSCROLL;
4776                         es->style &= ~ES_AUTOHSCROLL;
4777                 }
4778         } else {
4779                 es->buffer_limit = BUFLIMIT_SINGLE;
4780                 if ((es->style & ES_RIGHT) && (es->style & ES_CENTER))
4781                         es->style &= ~ES_CENTER;
4782                 es->style &= ~WS_HSCROLL;
4783                 es->style &= ~WS_VSCROLL;
4784                 if (es->style & ES_PASSWORD)
4785                         es->password_char = '*';
4786         }
4787
4788         alloc_size = ROUND_TO_GROW((es->buffer_size + 1) * sizeof(WCHAR));
4789         if(!(es->hloc32W = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size)))
4790             return FALSE;
4791         es->buffer_size = LocalSize(es->hloc32W)/sizeof(WCHAR) - 1;
4792
4793         if (!(es->undo_text = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (es->buffer_size + 1) * sizeof(WCHAR))))
4794                 return FALSE;
4795         es->undo_buffer_size = es->buffer_size;
4796
4797         if (es->style & ES_MULTILINE)
4798                 if (!(es->first_line_def = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LINEDEF))))
4799                         return FALSE;
4800         es->line_count = 1;
4801
4802         /*
4803          * In Win95 look and feel, the WS_BORDER style is replaced by the
4804          * WS_EX_CLIENTEDGE style for the edit control. This gives the edit
4805          * control a nonclient area so we don't need to draw the border.
4806          * If WS_BORDER without WS_EX_CLIENTEDGE is specified we shouldn't have
4807          * a nonclient area and we should handle painting the border ourselves.
4808          *
4809          * When making modifications please ensure that the code still works 
4810          * for edit controls created directly with style 0x50800000, exStyle 0
4811          * (which should have a single pixel border)
4812          */
4813         if (lpcs->dwExStyle & WS_EX_CLIENTEDGE)
4814                 es->style &= ~WS_BORDER;
4815         else if (es->style & WS_BORDER)
4816                 SetWindowLongW(hwnd, GWL_STYLE, es->style & ~WS_BORDER);
4817
4818         return TRUE;
4819 }
4820
4821 /*********************************************************************
4822  *
4823  *      WM_PAINT
4824  *
4825  */
4826 static void EDIT_WM_Paint(EDITSTATE *es, HDC hdc)
4827 {
4828         PAINTSTRUCT ps;
4829         INT i;
4830         HDC dc;
4831         HFONT old_font = 0;
4832         RECT rc;
4833         RECT rcClient;
4834         RECT rcLine;
4835         RECT rcRgn;
4836         HBRUSH brush;
4837         HBRUSH old_brush;
4838         INT bw, bh;
4839         BOOL rev = es->bEnableState &&
4840                                 ((es->flags & EF_FOCUSED) ||
4841                                         (es->style & ES_NOHIDESEL));
4842         dc = hdc ? hdc : BeginPaint(es->hwndSelf, &ps);
4843
4844         GetClientRect(es->hwndSelf, &rcClient);
4845
4846         /* get the background brush */
4847         brush = EDIT_NotifyCtlColor(es, dc);
4848
4849         /* paint the border and the background */
4850         IntersectClipRect(dc, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
4851         
4852         if(es->style & WS_BORDER) {
4853                 bw = GetSystemMetrics(SM_CXBORDER);
4854                 bh = GetSystemMetrics(SM_CYBORDER);
4855                 rc = rcClient;
4856                 if(es->style & ES_MULTILINE) {
4857                         if(es->style & WS_HSCROLL) rc.bottom+=bh;
4858                         if(es->style & WS_VSCROLL) rc.right+=bw;
4859                 }
4860                 
4861                 /* Draw the frame. Same code as in nonclient.c */
4862                 old_brush = SelectObject(dc, GetSysColorBrush(COLOR_WINDOWFRAME));
4863                 PatBlt(dc, rc.left, rc.top, rc.right - rc.left, bh, PATCOPY);
4864                 PatBlt(dc, rc.left, rc.top, bw, rc.bottom - rc.top, PATCOPY);
4865                 PatBlt(dc, rc.left, rc.bottom - 1, rc.right - rc.left, -bw, PATCOPY);
4866                 PatBlt(dc, rc.right - 1, rc.top, -bw, rc.bottom - rc.top, PATCOPY);
4867                 SelectObject(dc, old_brush);
4868                 
4869                 /* Keep the border clean */
4870                 IntersectClipRect(dc, rc.left+bw, rc.top+bh,
4871                     max(rc.right-bw, rc.left+bw), max(rc.bottom-bh, rc.top+bh));
4872         }
4873         
4874         GetClipBox(dc, &rc);
4875         FillRect(dc, &rc, brush);
4876
4877         IntersectClipRect(dc, es->format_rect.left,
4878                                 es->format_rect.top,
4879                                 es->format_rect.right,
4880                                 es->format_rect.bottom);
4881         if (es->style & ES_MULTILINE) {
4882                 rc = rcClient;
4883                 IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom);
4884         }
4885         if (es->font)
4886                 old_font = SelectObject(dc, es->font);
4887
4888         if (!es->bEnableState)
4889                 SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
4890         GetClipBox(dc, &rcRgn);
4891         if (es->style & ES_MULTILINE) {
4892                 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
4893                 for (i = es->y_offset ; i <= min(es->y_offset + vlc, es->y_offset + es->line_count - 1) ; i++) {
4894                         EDIT_GetLineRect(es, i, 0, -1, &rcLine);
4895                         if (IntersectRect(&rc, &rcRgn, &rcLine))
4896                                 EDIT_PaintLine(es, dc, i, rev);
4897                 }
4898         } else {
4899                 EDIT_GetLineRect(es, 0, 0, -1, &rcLine);
4900                 if (IntersectRect(&rc, &rcRgn, &rcLine))
4901                         EDIT_PaintLine(es, dc, 0, rev);
4902         }
4903         if (es->font)
4904                 SelectObject(dc, old_font);
4905
4906         if (!hdc)
4907             EndPaint(es->hwndSelf, &ps);
4908 }
4909
4910
4911 /*********************************************************************
4912  *
4913  *      WM_PASTE
4914  *
4915  */
4916 static void EDIT_WM_Paste(EDITSTATE *es)
4917 {
4918         HGLOBAL hsrc;
4919         LPWSTR src;
4920
4921         /* Protect read-only edit control from modification */
4922         if(es->style & ES_READONLY)
4923             return;
4924
4925         OpenClipboard(es->hwndSelf);
4926         if ((hsrc = GetClipboardData(CF_UNICODETEXT))) {
4927                 src = (LPWSTR)GlobalLock(hsrc);
4928                 EDIT_EM_ReplaceSel(es, TRUE, src, TRUE, TRUE);
4929                 GlobalUnlock(hsrc);
4930         }
4931         CloseClipboard();
4932 }
4933
4934
4935 /*********************************************************************
4936  *
4937  *      WM_SETFOCUS
4938  *
4939  */
4940 static void EDIT_WM_SetFocus(EDITSTATE *es)
4941 {
4942         es->flags |= EF_FOCUSED;
4943
4944         if (!(es->style & ES_NOHIDESEL))
4945             EDIT_InvalidateText(es, es->selection_start, es->selection_end);
4946
4947         /* single line edit updates itself */
4948         if (!(es->style & ES_MULTILINE))
4949         {
4950             HDC hdc = GetDC(es->hwndSelf);
4951             EDIT_WM_Paint(es, hdc);
4952             ReleaseDC(es->hwndSelf, hdc);
4953         }
4954
4955         CreateCaret(es->hwndSelf, 0, 2, es->line_height);
4956         EDIT_SetCaretPos(es, es->selection_end,
4957                          es->flags & EF_AFTER_WRAP);
4958         ShowCaret(es->hwndSelf);
4959         EDIT_NOTIFY_PARENT(es, EN_SETFOCUS);
4960 }
4961
4962
4963 /*********************************************************************
4964  *
4965  *      WM_SETFONT
4966  *
4967  * With Win95 look the margins are set to default font value unless
4968  * the system font (font == 0) is being set, in which case they are left
4969  * unchanged.
4970  *
4971  */
4972 static void EDIT_WM_SetFont(EDITSTATE *es, HFONT font, BOOL redraw)
4973 {
4974         TEXTMETRICW tm;
4975         HDC dc;
4976         HFONT old_font = 0;
4977         RECT clientRect;
4978
4979         es->font = font;
4980         dc = GetDC(es->hwndSelf);
4981         if (font)
4982                 old_font = SelectObject(dc, font);
4983         GetTextMetricsW(dc, &tm);
4984         es->line_height = tm.tmHeight;
4985         es->char_width = tm.tmAveCharWidth;
4986         if (font)
4987                 SelectObject(dc, old_font);
4988         ReleaseDC(es->hwndSelf, dc);
4989         
4990         /* Reset the format rect and the margins */
4991         GetClientRect(es->hwndSelf, &clientRect);
4992         EDIT_SetRectNP(es, &clientRect);
4993         EDIT_EM_SetMargins(es, EC_LEFTMARGIN | EC_RIGHTMARGIN,
4994                            EC_USEFONTINFO, EC_USEFONTINFO, FALSE);
4995
4996         if (es->style & ES_MULTILINE)
4997                 EDIT_BuildLineDefs_ML(es, 0, strlenW(es->text), 0, NULL);
4998         else
4999             EDIT_CalcLineWidth_SL(es);
5000
5001         if (redraw)
5002                 EDIT_UpdateText(es, NULL, TRUE);
5003         if (es->flags & EF_FOCUSED) {
5004                 DestroyCaret();
5005                 CreateCaret(es->hwndSelf, 0, 2, es->line_height);
5006                 EDIT_SetCaretPos(es, es->selection_end,
5007                                  es->flags & EF_AFTER_WRAP);
5008                 ShowCaret(es->hwndSelf);
5009         }
5010 }
5011
5012
5013 /*********************************************************************
5014  *
5015  *      WM_SETTEXT
5016  *
5017  * NOTES
5018  *  For multiline controls (ES_MULTILINE), reception of WM_SETTEXT triggers:
5019  *  The modified flag is reset. No notifications are sent.
5020  *
5021  *  For single-line controls, reception of WM_SETTEXT triggers:
5022  *  The modified flag is reset. EN_UPDATE and EN_CHANGE notifications are sent.
5023  *
5024  */
5025 static void EDIT_WM_SetText(EDITSTATE *es, LPCWSTR text, BOOL unicode)
5026 {
5027     LPWSTR textW = NULL;
5028     if (!unicode && text)
5029     {
5030         LPCSTR textA = (LPCSTR)text;
5031         INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
5032         textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR));
5033         if (textW)
5034             MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
5035         text = textW;
5036     }
5037
5038     if (es->flags & EF_UPDATE)
5039         /* fixed this bug once; complain if we see it about to happen again. */
5040         ERR("SetSel may generate UPDATE message whose handler may reset "
5041             "selection.\n");
5042
5043     EDIT_EM_SetSel(es, 0, (UINT)-1, FALSE);
5044     if (text) 
5045     {
5046         TRACE("%s\n", debugstr_w(text));
5047         EDIT_EM_ReplaceSel(es, FALSE, text, FALSE, FALSE);
5048         if(!unicode)
5049             HeapFree(GetProcessHeap(), 0, textW);
5050     } 
5051     else 
5052     {
5053         static const WCHAR empty_stringW[] = {0};
5054         TRACE("<NULL>\n");
5055         EDIT_EM_ReplaceSel(es, FALSE, empty_stringW, FALSE, FALSE);
5056     }
5057     es->x_offset = 0;
5058     es->flags &= ~EF_MODIFIED;
5059     EDIT_EM_SetSel(es, 0, 0, FALSE);
5060
5061     /* Send the notification after the selection start and end have been set
5062      * edit control doesn't send notification on WM_SETTEXT
5063      * if it is multiline, or it is part of combobox
5064      */
5065     if( !((es->style & ES_MULTILINE) || es->hwndListBox))
5066     {
5067         EDIT_NOTIFY_PARENT(es, EN_UPDATE);
5068         EDIT_NOTIFY_PARENT(es, EN_CHANGE);
5069     }
5070     EDIT_EM_ScrollCaret(es);
5071     EDIT_UpdateScrollInfo(es);    
5072 }
5073
5074
5075 /*********************************************************************
5076  *
5077  *      WM_SIZE
5078  *
5079  */
5080 static void EDIT_WM_Size(EDITSTATE *es, UINT action, INT width, INT height)
5081 {
5082         if ((action == SIZE_MAXIMIZED) || (action == SIZE_RESTORED)) {
5083                 RECT rc;
5084                 TRACE("width = %d, height = %d\n", width, height);
5085                 SetRect(&rc, 0, 0, width, height);
5086                 EDIT_SetRectNP(es, &rc);
5087                 EDIT_UpdateText(es, NULL, TRUE);
5088         }
5089 }
5090
5091
5092 /*********************************************************************
5093  *
5094  *      WM_STYLECHANGED
5095  *
5096  * This message is sent by SetWindowLong on having changed either the Style
5097  * or the extended style.
5098  *
5099  * We ensure that the window's version of the styles and the EDITSTATE's agree.
5100  *
5101  * See also EDIT_WM_NCCreate
5102  *
5103  * It appears that the Windows version of the edit control allows the style
5104  * (as retrieved by GetWindowLong) to be any value and maintains an internal
5105  * style variable which will generally be different.  In this function we
5106  * update the internal style based on what changed in the externally visible
5107  * style.
5108  *
5109  * Much of this content as based upon the MSDN, especially:
5110  *  Platform SDK Documentation -> User Interface Services ->
5111  *      Windows User Interface -> Edit Controls -> Edit Control Reference ->
5112  *      Edit Control Styles
5113  */
5114 static LRESULT  EDIT_WM_StyleChanged ( EDITSTATE *es, WPARAM which, const STYLESTRUCT *style)
5115 {
5116         if (GWL_STYLE == which) {
5117                 DWORD style_change_mask;
5118                 DWORD new_style;
5119                 /* Only a subset of changes can be applied after the control
5120                  * has been created.
5121                  */
5122                 style_change_mask = ES_UPPERCASE | ES_LOWERCASE |
5123                                     ES_NUMBER;
5124                 if (es->style & ES_MULTILINE)
5125                         style_change_mask |= ES_WANTRETURN;
5126
5127                 new_style = style->styleNew & style_change_mask;
5128
5129                 /* Number overrides lowercase overrides uppercase (at least it
5130                  * does in Win95).  However I'll bet that ES_NUMBER would be
5131                  * invalid under Win 3.1.
5132                  */
5133                 if (new_style & ES_NUMBER) {
5134                         ; /* do not override the ES_NUMBER */
5135                 }  else if (new_style & ES_LOWERCASE) {
5136                         new_style &= ~ES_UPPERCASE;
5137                 }
5138
5139                 es->style = (es->style & ~style_change_mask) | new_style;
5140         } else if (GWL_EXSTYLE == which) {
5141                 ; /* FIXME - what is needed here */
5142         } else {
5143                 WARN ("Invalid style change %d\n",which);
5144         }
5145
5146         return 0;
5147 }
5148
5149 /*********************************************************************
5150  *
5151  *      WM_SYSKEYDOWN
5152  *
5153  */
5154 static LRESULT EDIT_WM_SysKeyDown(EDITSTATE *es, INT key, DWORD key_data)
5155 {
5156         if ((key == VK_BACK) && (key_data & 0x2000)) {
5157                 if (EDIT_EM_CanUndo(es))
5158                         EDIT_EM_Undo(es);
5159                 return 0;
5160         } else if (key == VK_UP || key == VK_DOWN) {
5161                 if (EDIT_CheckCombo(es, WM_SYSKEYDOWN, key))
5162                         return 0;
5163         }
5164         return DefWindowProcW(es->hwndSelf, WM_SYSKEYDOWN, (WPARAM)key, (LPARAM)key_data);
5165 }
5166
5167
5168 /*********************************************************************
5169  *
5170  *      WM_TIMER
5171  *
5172  */
5173 static void EDIT_WM_Timer(EDITSTATE *es)
5174 {
5175         if (es->region_posx < 0) {
5176                 EDIT_MoveBackward(es, TRUE);
5177         } else if (es->region_posx > 0) {
5178                 EDIT_MoveForward(es, TRUE);
5179         }
5180 /*
5181  *      FIXME: gotta do some vertical scrolling here, like
5182  *              EDIT_EM_LineScroll(hwnd, 0, 1);
5183  */
5184 }
5185
5186 /*********************************************************************
5187  *
5188  *      WM_VSCROLL
5189  *
5190  */
5191 static LRESULT EDIT_WM_VScroll(EDITSTATE *es, INT action, INT pos)
5192 {
5193         INT dy;
5194
5195         if (!(es->style & ES_MULTILINE))
5196                 return 0;
5197
5198         if (!(es->style & ES_AUTOVSCROLL))
5199                 return 0;
5200
5201         dy = 0;
5202         switch (action) {
5203         case SB_LINEUP:
5204         case SB_LINEDOWN:
5205         case SB_PAGEUP:
5206         case SB_PAGEDOWN:
5207                 TRACE("action %d (%s)\n", action, (action == SB_LINEUP ? "SB_LINEUP" :
5208                                                    (action == SB_LINEDOWN ? "SB_LINEDOWN" :
5209                                                     (action == SB_PAGEUP ? "SB_PAGEUP" :
5210                                                      "SB_PAGEDOWN"))));
5211                 EDIT_EM_Scroll(es, action);
5212                 return 0;
5213         case SB_TOP:
5214                 TRACE("SB_TOP\n");
5215                 dy = -es->y_offset;
5216                 break;
5217         case SB_BOTTOM:
5218                 TRACE("SB_BOTTOM\n");
5219                 dy = es->line_count - 1 - es->y_offset;
5220                 break;
5221         case SB_THUMBTRACK:
5222                 TRACE("SB_THUMBTRACK %d\n", pos);
5223                 es->flags |= EF_VSCROLL_TRACK;
5224                 if(es->style & WS_VSCROLL)
5225                     dy = pos - es->y_offset;
5226                 else
5227                 {
5228                     /* Assume default scroll range 0-100 */
5229                     INT vlc, new_y;
5230                     /* Sanity check */
5231                     if(pos < 0 || pos > 100) return 0;
5232                     vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
5233                     new_y = pos * (es->line_count - vlc) / 100;
5234                     dy = es->line_count ? (new_y - es->y_offset) : 0;
5235                     TRACE("line_count=%d, y_offset=%d, pos=%d, dy = %d\n",
5236                             es->line_count, es->y_offset, pos, dy);
5237                 }
5238                 break;
5239         case SB_THUMBPOSITION:
5240                 TRACE("SB_THUMBPOSITION %d\n", pos);
5241                 es->flags &= ~EF_VSCROLL_TRACK;
5242                 if(es->style & WS_VSCROLL)
5243                     dy = pos - es->y_offset;
5244                 else
5245                 {
5246                     /* Assume default scroll range 0-100 */
5247                     INT vlc, new_y;
5248                     /* Sanity check */
5249                     if(pos < 0 || pos > 100) return 0;
5250                     vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
5251                     new_y = pos * (es->line_count - vlc) / 100;
5252                     dy = es->line_count ? (new_y - es->y_offset) : 0;
5253                     TRACE("line_count=%d, y_offset=%d, pos=%d, dy = %d\n",
5254                             es->line_count, es->y_offset, pos, dy);
5255                 }
5256                 if (!dy)
5257                 {
5258                         /* force scroll info update */
5259                         EDIT_UpdateScrollInfo(es);
5260                         EDIT_NOTIFY_PARENT(es, EN_VSCROLL);
5261                 }
5262                 break;
5263         case SB_ENDSCROLL:
5264                 TRACE("SB_ENDSCROLL\n");
5265                 break;
5266         /*
5267          *      FIXME : the next two are undocumented !
5268          *      Are we doing the right thing ?
5269          *      At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
5270          *      although it's also a regular control message.
5271          */
5272         case EM_GETTHUMB: /* this one is used by NT notepad */
5273         case EM_GETTHUMB16:
5274         {
5275                 LRESULT ret;
5276                 if(GetWindowLongW( es->hwndSelf, GWL_STYLE ) & WS_VSCROLL)
5277                     ret = GetScrollPos(es->hwndSelf, SB_VERT);
5278                 else
5279                 {
5280                     /* Assume default scroll range 0-100 */
5281                     INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
5282                     ret = es->line_count ? es->y_offset * 100 / (es->line_count - vlc) : 0;
5283                 }
5284                 TRACE("EM_GETTHUMB: returning %ld\n", ret);
5285                 return ret;
5286         }
5287         case EM_LINESCROLL16:
5288                 TRACE("EM_LINESCROLL16 %d\n", pos);
5289                 dy = pos;
5290                 break;
5291
5292         default:
5293                 ERR("undocumented WM_VSCROLL action %d (0x%04x), please report\n",
5294                     action, action);
5295                 return 0;
5296         }
5297         if (dy)
5298                 EDIT_EM_LineScroll(es, 0, dy);
5299         return 0;
5300 }
5301
5302 /*********************************************************************
5303  *
5304  *      EDIT_UpdateText
5305  *
5306  */
5307 static void EDIT_UpdateTextRegion(EDITSTATE *es, HRGN hrgn, BOOL bErase)
5308 {
5309     if (es->flags & EF_UPDATE) {
5310         es->flags &= ~EF_UPDATE;
5311         EDIT_NOTIFY_PARENT(es, EN_UPDATE);
5312     }
5313     InvalidateRgn(es->hwndSelf, hrgn, bErase);
5314 }
5315
5316
5317 /*********************************************************************
5318  *
5319  *      EDIT_UpdateText
5320  *
5321  */
5322 static void EDIT_UpdateText(EDITSTATE *es, LPRECT rc, BOOL bErase)
5323 {
5324     if (es->flags & EF_UPDATE) {
5325         es->flags &= ~EF_UPDATE;
5326         EDIT_NOTIFY_PARENT(es, EN_UPDATE);
5327     }
5328     InvalidateRect(es->hwndSelf, rc, bErase);
5329 }
5330
5331 /********************************************************************
5332  * 
5333  * The Following code is to handle inline editing from IMEs
5334  */
5335
5336 static void EDIT_GetCompositionStr(HWND hwnd, LPARAM CompFlag, EDITSTATE *es)
5337 {
5338     DWORD dwBufLen;
5339     LPWSTR lpCompStr = NULL;
5340     HIMC hIMC;
5341     LPSTR lpCompStrAttr = NULL;
5342     DWORD dwBufLenAttr;
5343
5344     if (!(hIMC = ImmGetContext(hwnd)))
5345         return;
5346
5347     dwBufLen = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0);
5348
5349     if (dwBufLen < 0)
5350     {
5351         ImmReleaseContext(hwnd, hIMC);
5352         return;
5353     }
5354
5355     lpCompStr = HeapAlloc(GetProcessHeap(),0,dwBufLen + sizeof(WCHAR));
5356     if (!lpCompStr)
5357     {
5358         ERR("Unable to allocate IME CompositionString\n");
5359         ImmReleaseContext(hwnd,hIMC);
5360         return;
5361     }
5362
5363     if (dwBufLen)
5364         ImmGetCompositionStringW(hIMC, GCS_COMPSTR, lpCompStr, dwBufLen);
5365     lpCompStr[dwBufLen/sizeof(WCHAR)] = 0;
5366
5367     if (CompFlag & GCS_COMPATTR)
5368     {
5369         /* 
5370          * We do not use the attributes yet. it would tell us what characters
5371          * are in transition and which are converted or decided upon
5372          */
5373         dwBufLenAttr = ImmGetCompositionStringW(hIMC, GCS_COMPATTR, NULL, 0);
5374         if (dwBufLenAttr)
5375         {
5376             dwBufLenAttr ++;
5377             lpCompStrAttr = HeapAlloc(GetProcessHeap(),0,dwBufLenAttr+1);
5378             if (!lpCompStrAttr)
5379             {
5380                 ERR("Unable to allocate IME Attribute String\n");
5381                 HeapFree(GetProcessHeap(),0,lpCompStr);
5382                 ImmReleaseContext(hwnd,hIMC);
5383                 return;
5384             }
5385             ImmGetCompositionStringW(hIMC,GCS_COMPATTR, lpCompStrAttr, 
5386                     dwBufLenAttr);
5387             lpCompStrAttr[dwBufLenAttr] = 0;
5388         }
5389         else
5390             lpCompStrAttr = NULL;
5391     }
5392
5393     /* check for change in composition start */
5394     if (es->selection_end < es->composition_start)
5395         es->composition_start = es->selection_end;
5396     
5397     /* replace existing selection string */
5398     es->selection_start = es->composition_start;
5399
5400     if (es->composition_len > 0)
5401         es->selection_end = es->composition_start + es->composition_len;
5402     else
5403         es->selection_end = es->selection_start;
5404
5405     EDIT_EM_ReplaceSel(es, FALSE, lpCompStr, TRUE, TRUE);
5406     es->composition_len = abs(es->composition_start - es->selection_end);
5407
5408     es->selection_start = es->composition_start;
5409     es->selection_end = es->selection_start + es->composition_len;
5410
5411     HeapFree(GetProcessHeap(),0,lpCompStrAttr);
5412     HeapFree(GetProcessHeap(),0,lpCompStr);
5413     ImmReleaseContext(hwnd,hIMC);
5414 }
5415
5416 static void EDIT_GetResultStr(HWND hwnd, EDITSTATE *es)
5417 {
5418     DWORD dwBufLen;
5419     LPWSTR lpResultStr;
5420     HIMC    hIMC;
5421
5422     if ( !(hIMC = ImmGetContext(hwnd)))
5423         return;
5424
5425     dwBufLen = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0);
5426     if (dwBufLen <= 0)
5427     {
5428         ImmReleaseContext(hwnd, hIMC);
5429         return;
5430     }
5431
5432     lpResultStr = HeapAlloc(GetProcessHeap(),0, dwBufLen+sizeof(WCHAR));
5433     if (!lpResultStr)
5434     {
5435         ERR("Unable to alloc buffer for IME string\n");
5436         ImmReleaseContext(hwnd, hIMC);
5437         return;
5438     }
5439
5440     ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, lpResultStr, dwBufLen);
5441     lpResultStr[dwBufLen/sizeof(WCHAR)] = 0;
5442
5443     /* check for change in composition start */
5444     if (es->selection_end < es->composition_start)
5445         es->composition_start = es->selection_end;
5446
5447     es->selection_start = es->composition_start;
5448     es->selection_end = es->composition_start + es->composition_len;
5449     EDIT_EM_ReplaceSel(es, TRUE, lpResultStr, TRUE, TRUE);
5450     es->composition_start = es->selection_end;
5451     es->composition_len = 0;
5452
5453     HeapFree(GetProcessHeap(),0,lpResultStr);
5454     ImmReleaseContext(hwnd, hIMC);
5455 }
5456
5457 static void EDIT_ImeComposition(HWND hwnd, LPARAM CompFlag, EDITSTATE *es)
5458 {
5459     if (CompFlag & GCS_RESULTSTR)
5460         EDIT_GetResultStr(hwnd,es);
5461     if (CompFlag & GCS_COMPSTR)
5462         EDIT_GetCompositionStr(hwnd, CompFlag, es);
5463 }