kernel: Added a test for QueryDosDeviceA.
[wine] / dlls / user / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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, INT left, INT 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, (short)LOWORD(lParam), (short)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  */
3664 static void EDIT_EM_SetMargins(EDITSTATE *es, INT action,
3665                                INT left, INT right, BOOL repaint)
3666 {
3667         TEXTMETRICW tm;
3668         INT default_left_margin  = 0; /* in pixels */
3669         INT default_right_margin = 0; /* in pixels */
3670
3671         /* Set the default margins depending on the font */
3672         if (es->font && (left == EC_USEFONTINFO || right == EC_USEFONTINFO)) {
3673             HDC dc = GetDC(es->hwndSelf);
3674             HFONT old_font = SelectObject(dc, es->font);
3675             GetTextMetricsW(dc, &tm);
3676             /* The default margins are only non zero for TrueType or Vector fonts */
3677             if (tm.tmPitchAndFamily & ( TMPF_VECTOR | TMPF_TRUETYPE )) {
3678                 /* This must be calculated more exactly! But how? */
3679                 default_left_margin = tm.tmAveCharWidth / 3;
3680                 default_right_margin = tm.tmAveCharWidth / 3;
3681             }
3682             SelectObject(dc, old_font);
3683             ReleaseDC(es->hwndSelf, dc);
3684         }
3685
3686         if (action & EC_LEFTMARGIN) {
3687                 es->format_rect.left -= es->left_margin;
3688                 if (left != EC_USEFONTINFO)
3689                         es->left_margin = left;
3690                 else
3691                         es->left_margin = default_left_margin;
3692                 es->format_rect.left += es->left_margin;
3693         }
3694
3695         if (action & EC_RIGHTMARGIN) {
3696                 es->format_rect.right += es->right_margin;
3697                 if (right != EC_USEFONTINFO)
3698                         es->right_margin = right;
3699                 else
3700                         es->right_margin = default_right_margin;
3701                 es->format_rect.right -= es->right_margin;
3702         }
3703         
3704         if (action & (EC_LEFTMARGIN | EC_RIGHTMARGIN)) {
3705                 EDIT_AdjustFormatRect(es);
3706                 if (repaint) EDIT_UpdateText(es, NULL, TRUE);
3707         }
3708         
3709         TRACE("left=%d, right=%d\n", es->left_margin, es->right_margin);
3710 }
3711
3712
3713 /*********************************************************************
3714  *
3715  *      EM_SETPASSWORDCHAR
3716  *
3717  */
3718 static void EDIT_EM_SetPasswordChar(EDITSTATE *es, WCHAR c)
3719 {
3720         LONG style;
3721
3722         if (es->style & ES_MULTILINE)
3723                 return;
3724
3725         if (es->password_char == c)
3726                 return;
3727
3728         style = GetWindowLongW( es->hwndSelf, GWL_STYLE );
3729         es->password_char = c;
3730         if (c) {
3731             SetWindowLongW( es->hwndSelf, GWL_STYLE, style | ES_PASSWORD );
3732             es->style |= ES_PASSWORD;
3733         } else {
3734             SetWindowLongW( es->hwndSelf, GWL_STYLE, style & ~ES_PASSWORD );
3735             es->style &= ~ES_PASSWORD;
3736         }
3737         EDIT_UpdateText(es, NULL, TRUE);
3738 }
3739
3740
3741 /*********************************************************************
3742  *
3743  *      EDIT_EM_SetSel
3744  *
3745  *      note:   unlike the specs say: the order of start and end
3746  *              _is_ preserved in Windows.  (i.e. start can be > end)
3747  *              In other words: this handler is OK
3748  *
3749  */
3750 static void EDIT_EM_SetSel(EDITSTATE *es, UINT start, UINT end, BOOL after_wrap)
3751 {
3752         UINT old_start = es->selection_start;
3753         UINT old_end = es->selection_end;
3754         UINT len = strlenW(es->text);
3755
3756         if (start == (UINT)-1) {
3757                 start = es->selection_end;
3758                 end = es->selection_end;
3759         } else {
3760                 start = min(start, len);
3761                 end = min(end, len);
3762         }
3763         es->selection_start = start;
3764         es->selection_end = end;
3765         if (after_wrap)
3766                 es->flags |= EF_AFTER_WRAP;
3767         else
3768                 es->flags &= ~EF_AFTER_WRAP;
3769         /* Compute the necessary invalidation region. */
3770         /* Note that we don't need to invalidate regions which have
3771          * "never" been selected, or those which are "still" selected.
3772          * In fact, every time we hit a selection boundary, we can
3773          * *toggle* whether we need to invalidate.  Thus we can optimize by
3774          * *sorting* the interval endpoints.  Let's assume that we sort them
3775          * in this order:
3776          *        start <= end <= old_start <= old_end
3777          * Knuth 5.3.1 (p 183) asssures us that this can be done optimally
3778          * in 5 comparisons; ie it's impossible to do better than the
3779          * following: */
3780         ORDER_UINT(end, old_end);
3781         ORDER_UINT(start, old_start);
3782         ORDER_UINT(old_start, old_end);
3783         ORDER_UINT(start, end);
3784         /* Note that at this point 'end' and 'old_start' are not in order, but
3785          * start is definitely the min. and old_end is definitely the max. */
3786         if (end != old_start)
3787         {
3788 /*
3789  * One can also do
3790  *          ORDER_UINT32(end, old_start);
3791  *          EDIT_InvalidateText(es, start, end);
3792  *          EDIT_InvalidateText(es, old_start, old_end);
3793  * in place of the following if statement.
3794  * (That would complete the optimal five-comparison four-element sort.)
3795  */
3796             if (old_start > end )
3797             {
3798                 EDIT_InvalidateText(es, start, end);
3799                 EDIT_InvalidateText(es, old_start, old_end);
3800             }
3801             else
3802             {
3803                 EDIT_InvalidateText(es, start, old_start);
3804                 EDIT_InvalidateText(es, end, old_end);
3805             }
3806         }
3807         else EDIT_InvalidateText(es, start, old_end);
3808 }
3809
3810
3811 /*********************************************************************
3812  *
3813  *      EM_SETTABSTOPS
3814  *
3815  */
3816 static BOOL EDIT_EM_SetTabStops(EDITSTATE *es, INT count, LPINT tabs)
3817 {
3818         if (!(es->style & ES_MULTILINE))
3819                 return FALSE;
3820         HeapFree(GetProcessHeap(), 0, es->tabs);
3821         es->tabs_count = count;
3822         if (!count)
3823                 es->tabs = NULL;
3824         else {
3825                 es->tabs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
3826                 memcpy(es->tabs, tabs, count * sizeof(INT));
3827         }
3828         return TRUE;
3829 }
3830
3831
3832 /*********************************************************************
3833  *
3834  *      EM_SETTABSTOPS16
3835  *
3836  */
3837 static BOOL EDIT_EM_SetTabStops16(EDITSTATE *es, INT count, LPINT16 tabs)
3838 {
3839         if (!(es->style & ES_MULTILINE))
3840                 return FALSE;
3841         HeapFree(GetProcessHeap(), 0, es->tabs);
3842         es->tabs_count = count;
3843         if (!count)
3844                 es->tabs = NULL;
3845         else {
3846                 INT i;
3847                 es->tabs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
3848                 for (i = 0 ; i < count ; i++)
3849                         es->tabs[i] = *tabs++;
3850         }
3851         return TRUE;
3852 }
3853
3854
3855 /*********************************************************************
3856  *
3857  *      EM_SETWORDBREAKPROC
3858  *
3859  */
3860 static void EDIT_EM_SetWordBreakProc(EDITSTATE *es, void *wbp)
3861 {
3862         if (es->word_break_proc == wbp)
3863                 return;
3864
3865         es->word_break_proc = wbp;
3866         es->word_break_proc16 = NULL;
3867
3868         if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) {
3869                 EDIT_BuildLineDefs_ML(es, 0, strlenW(es->text), 0, NULL);
3870                 EDIT_UpdateText(es, NULL, TRUE);
3871         }
3872 }
3873
3874
3875 /*********************************************************************
3876  *
3877  *      EM_SETWORDBREAKPROC16
3878  *
3879  */
3880 static void EDIT_EM_SetWordBreakProc16(EDITSTATE *es, EDITWORDBREAKPROC16 wbp)
3881 {
3882         if (es->word_break_proc16 == wbp)
3883                 return;
3884
3885         es->word_break_proc = NULL;
3886         es->word_break_proc16 = wbp;
3887         if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) {
3888                 EDIT_BuildLineDefs_ML(es, 0, strlenW(es->text), 0, NULL);
3889                 EDIT_UpdateText(es, NULL, TRUE);
3890         }
3891 }
3892
3893
3894 /*********************************************************************
3895  *
3896  *      EM_UNDO / WM_UNDO
3897  *
3898  */
3899 static BOOL EDIT_EM_Undo(EDITSTATE *es)
3900 {
3901         INT ulength;
3902         LPWSTR utext;
3903
3904         /* As per MSDN spec, for a single-line edit control,
3905            the return value is always TRUE */
3906         if( es->style & ES_READONLY )
3907             return !(es->style & ES_MULTILINE);
3908
3909         ulength = strlenW(es->undo_text);
3910
3911         utext = HeapAlloc(GetProcessHeap(), 0, (ulength + 1) * sizeof(WCHAR));
3912
3913         strcpyW(utext, es->undo_text);
3914
3915         TRACE("before UNDO:insertion length = %d, deletion buffer = %s\n",
3916                      es->undo_insert_count, debugstr_w(utext));
3917
3918         EDIT_EM_SetSel(es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
3919         EDIT_EM_EmptyUndoBuffer(es);
3920         EDIT_EM_ReplaceSel(es, TRUE, utext, TRUE, TRUE);
3921         EDIT_EM_SetSel(es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
3922         /* send the notification after the selection start and end are set */
3923         EDIT_NOTIFY_PARENT(es, EN_CHANGE);
3924         EDIT_EM_ScrollCaret(es);
3925         HeapFree(GetProcessHeap(), 0, utext);
3926
3927         TRACE("after UNDO:insertion length = %d, deletion buffer = %s\n",
3928                         es->undo_insert_count, debugstr_w(es->undo_text));
3929         return TRUE;
3930 }
3931
3932
3933 /*********************************************************************
3934  *
3935  *      WM_CHAR
3936  *
3937  */
3938 static void EDIT_WM_Char(EDITSTATE *es, WCHAR c)
3939 {
3940         BOOL control;
3941
3942         control = GetKeyState(VK_CONTROL) & 0x8000;
3943
3944         switch (c) {
3945         case '\r':
3946             /* If the edit doesn't want the return and it's not a multiline edit, do nothing */
3947             if(!(es->style & ES_MULTILINE) && !(es->style & ES_WANTRETURN))
3948                 break;
3949         case '\n':
3950                 if (es->style & ES_MULTILINE) {
3951                         if (es->style & ES_READONLY) {
3952                                 EDIT_MoveHome(es, FALSE);
3953                                 EDIT_MoveDown_ML(es, FALSE);
3954                         } else {
3955                                 static const WCHAR cr_lfW[] = {'\r','\n',0};
3956                                 EDIT_EM_ReplaceSel(es, TRUE, cr_lfW, TRUE, TRUE);
3957                         }
3958                 }
3959                 break;
3960         case '\t':
3961                 if ((es->style & ES_MULTILINE) && !(es->style & ES_READONLY))
3962                 {
3963                         static const WCHAR tabW[] = {'\t',0};
3964                         EDIT_EM_ReplaceSel(es, TRUE, tabW, TRUE, TRUE);
3965                 }
3966                 break;
3967         case VK_BACK:
3968                 if (!(es->style & ES_READONLY) && !control) {
3969                         if (es->selection_start != es->selection_end)
3970                                 EDIT_WM_Clear(es);
3971                         else {
3972                                 /* delete character left of caret */
3973                                 EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
3974                                 EDIT_MoveBackward(es, TRUE);
3975                                 EDIT_WM_Clear(es);
3976                         }
3977                 }
3978                 break;
3979         case 0x03: /* ^C */
3980                 SendMessageW(es->hwndSelf, WM_COPY, 0, 0);
3981                 break;
3982         case 0x16: /* ^V */
3983                 if (!(es->style & ES_READONLY))
3984                     SendMessageW(es->hwndSelf, WM_PASTE, 0, 0);
3985                 break;
3986         case 0x18: /* ^X */
3987                 if (!(es->style & ES_READONLY))
3988                     SendMessageW(es->hwndSelf, WM_CUT, 0, 0);
3989                 break;
3990
3991         default:
3992                 /*If Edit control style is ES_NUMBER allow users to key in only numeric values*/
3993                 if( (es->style & ES_NUMBER) && !( c >= '0' && c <= '9') )
3994                         break;
3995                         
3996                 if (!(es->style & ES_READONLY) && (c >= ' ') && (c != 127)) {
3997                         WCHAR str[2];
3998                         str[0] = c;
3999                         str[1] = '\0';
4000                         EDIT_EM_ReplaceSel(es, TRUE, str, TRUE, TRUE);
4001                 }
4002                 break;
4003         }
4004 }
4005
4006
4007 /*********************************************************************
4008  *
4009  *      WM_COMMAND
4010  *
4011  */
4012 static void EDIT_WM_Command(EDITSTATE *es, INT code, INT id, HWND control)
4013 {
4014         if (code || control)
4015                 return;
4016
4017         switch (id) {
4018                 case EM_UNDO:
4019                         EDIT_EM_Undo(es);
4020                         break;
4021                 case WM_CUT:
4022                         EDIT_WM_Cut(es);
4023                         break;
4024                 case WM_COPY:
4025                         EDIT_WM_Copy(es);
4026                         break;
4027                 case WM_PASTE:
4028                         EDIT_WM_Paste(es);
4029                         break;
4030                 case WM_CLEAR:
4031                         EDIT_WM_Clear(es);
4032                         break;
4033                 case EM_SETSEL:
4034                         EDIT_EM_SetSel(es, 0, (UINT)-1, FALSE);
4035                         EDIT_EM_ScrollCaret(es);
4036                         break;
4037                 default:
4038                         ERR("unknown menu item, please report\n");
4039                         break;
4040         }
4041 }
4042
4043
4044 /*********************************************************************
4045  *
4046  *      WM_CONTEXTMENU
4047  *
4048  *      Note: the resource files resource/sysres_??.rc cannot define a
4049  *              single popup menu.  Hence we use a (dummy) menubar
4050  *              containing the single popup menu as its first item.
4051  *
4052  *      FIXME: the message identifiers have been chosen arbitrarily,
4053  *              hence we use MF_BYPOSITION.
4054  *              We might as well use the "real" values (anybody knows ?)
4055  *              The menu definition is in resources/sysres_??.rc.
4056  *              Once these are OK, we better use MF_BYCOMMAND here
4057  *              (as we do in EDIT_WM_Command()).
4058  *
4059  */
4060 static void EDIT_WM_ContextMenu(EDITSTATE *es, INT x, INT y)
4061 {
4062         HMENU menu = LoadMenuA(user32_module, "EDITMENU");
4063         HMENU popup = GetSubMenu(menu, 0);
4064         UINT start = es->selection_start;
4065         UINT end = es->selection_end;
4066
4067         ORDER_UINT(start, end);
4068
4069         /* undo */
4070         EnableMenuItem(popup, 0, MF_BYPOSITION | (EDIT_EM_CanUndo(es) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
4071         /* cut */
4072         EnableMenuItem(popup, 2, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
4073         /* copy */
4074         EnableMenuItem(popup, 3, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) ? MF_ENABLED : MF_GRAYED));
4075         /* paste */
4076         EnableMenuItem(popup, 4, MF_BYPOSITION | (IsClipboardFormatAvailable(CF_UNICODETEXT) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
4077         /* delete */
4078         EnableMenuItem(popup, 5, MF_BYPOSITION | ((end - start) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
4079         /* select all */
4080         EnableMenuItem(popup, 7, MF_BYPOSITION | (start || (end != strlenW(es->text)) ? MF_ENABLED : MF_GRAYED));
4081
4082         TrackPopupMenu(popup, TPM_LEFTALIGN | TPM_RIGHTBUTTON, x, y, 0, es->hwndSelf, NULL);
4083         DestroyMenu(menu);
4084 }
4085
4086
4087 /*********************************************************************
4088  *
4089  *      WM_COPY
4090  *
4091  */
4092 static void EDIT_WM_Copy(EDITSTATE *es)
4093 {
4094         INT s = min(es->selection_start, es->selection_end);
4095         INT e = max(es->selection_start, es->selection_end);
4096         HGLOBAL hdst;
4097         LPWSTR dst;
4098         DWORD len;
4099
4100         if (e == s) return;
4101
4102         len = e - s;
4103         hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (len + 1) * sizeof(WCHAR));
4104         dst = GlobalLock(hdst);
4105         memcpy(dst, es->text + s, len * sizeof(WCHAR));
4106         dst[len] = 0; /* ensure 0 termination */
4107         TRACE("%s\n", debugstr_w(dst));
4108         GlobalUnlock(hdst);
4109         OpenClipboard(es->hwndSelf);
4110         EmptyClipboard();
4111         SetClipboardData(CF_UNICODETEXT, hdst);
4112         CloseClipboard();
4113 }
4114
4115
4116 /*********************************************************************
4117  *
4118  *      WM_CREATE
4119  *
4120  */
4121 static LRESULT EDIT_WM_Create(EDITSTATE *es, LPCWSTR name)
4122 {
4123         RECT clientRect;
4124         
4125         TRACE("%s\n", debugstr_w(name));
4126        /*
4127         *       To initialize some final structure members, we call some helper
4128         *       functions.  However, since the EDITSTATE is not consistent (i.e.
4129         *       not fully initialized), we should be very careful which
4130         *       functions can be called, and in what order.
4131         */
4132         EDIT_WM_SetFont(es, 0, FALSE);
4133         EDIT_EM_EmptyUndoBuffer(es);
4134         
4135         /* We need to calculate the format rect
4136            (applications may send EM_SETMARGINS before the control gets visible) */
4137         GetClientRect(es->hwndSelf, &clientRect);
4138         EDIT_SetRectNP(es, &clientRect);
4139
4140        if (name && *name) {
4141            EDIT_EM_ReplaceSel(es, FALSE, name, FALSE, FALSE);
4142            /* if we insert text to the editline, the text scrolls out
4143             * of the window, as the caret is placed after the insert
4144             * pos normally; thus we reset es->selection... to 0 and
4145             * update caret
4146             */
4147            es->selection_start = es->selection_end = 0;
4148            /* Adobe Photoshop does NOT like this. and MSDN says that EN_CHANGE
4149             * Messages are only to be sent when the USER does something to
4150             * change the contents. So I am removing this EN_CHANGE
4151             *
4152             * EDIT_NOTIFY_PARENT(es, EN_CHANGE);
4153             */
4154            EDIT_EM_ScrollCaret(es);
4155        }
4156        /* force scroll info update */
4157        EDIT_UpdateScrollInfo(es);
4158        /* The rule seems to return 1 here for success */
4159        /* Power Builder masked edit controls will crash  */
4160        /* if not. */
4161        /* FIXME: is that in all cases so ? */
4162        return 1;
4163 }
4164
4165
4166 /*********************************************************************
4167  *
4168  *      WM_DESTROY
4169  *
4170  */
4171 static LRESULT EDIT_WM_Destroy(EDITSTATE *es)
4172 {
4173         LINEDEF *pc, *pp;
4174
4175         if (es->hloc32W) {
4176                 while (LocalUnlock(es->hloc32W)) ;
4177                 LocalFree(es->hloc32W);
4178         }
4179         if (es->hloc32A) {
4180                 while (LocalUnlock(es->hloc32A)) ;
4181                 LocalFree(es->hloc32A);
4182         }
4183         if (es->hloc16) {
4184                 STACK16FRAME* stack16 = MapSL((SEGPTR)NtCurrentTeb()->WOW32Reserved);
4185                 HANDLE16 oldDS = stack16->ds;
4186
4187                 stack16->ds = GetWindowLongPtrW( es->hwndSelf, GWLP_HINSTANCE );
4188                 while (LocalUnlock16(es->hloc16)) ;
4189                 LocalFree16(es->hloc16);
4190                 stack16->ds = oldDS;
4191         }
4192
4193         pc = es->first_line_def;
4194         while (pc)
4195         {
4196                 pp = pc->next;
4197                 HeapFree(GetProcessHeap(), 0, pc);
4198                 pc = pp;
4199         }
4200
4201         SetWindowLongPtrW( es->hwndSelf, 0, 0 );
4202         HeapFree(GetProcessHeap(), 0, es);
4203
4204         return 0;
4205 }
4206
4207
4208 /*********************************************************************
4209  *
4210  *      WM_ERASEBKGND
4211  *
4212  */
4213 static LRESULT EDIT_WM_EraseBkGnd(EDITSTATE *es, HDC dc)
4214 {
4215     /* we do the proper erase in EDIT_WM_Paint */
4216     return 1;
4217 }
4218
4219
4220 /*********************************************************************
4221  *
4222  *      WM_GETTEXT
4223  *
4224  */
4225 static INT EDIT_WM_GetText(EDITSTATE *es, INT count, LPWSTR dst, BOOL unicode)
4226 {
4227     if(!count) return 0;
4228
4229     if(unicode)
4230     {
4231         lstrcpynW(dst, es->text, count);
4232         return strlenW(dst);
4233     }
4234     else
4235     {
4236         LPSTR textA = (LPSTR)dst;
4237         if (!WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, count, NULL, NULL))
4238             textA[count - 1] = 0; /* ensure 0 termination */
4239         return strlen(textA);
4240     }
4241 }
4242
4243 /*********************************************************************
4244  *
4245  *      WM_HSCROLL
4246  *
4247  */
4248 static LRESULT EDIT_WM_HScroll(EDITSTATE *es, INT action, INT pos)
4249 {
4250         INT dx;
4251         INT fw;
4252
4253         if (!(es->style & ES_MULTILINE))
4254                 return 0;
4255
4256         if (!(es->style & ES_AUTOHSCROLL))
4257                 return 0;
4258
4259         dx = 0;
4260         fw = es->format_rect.right - es->format_rect.left;
4261         switch (action) {
4262         case SB_LINELEFT:
4263                 TRACE("SB_LINELEFT\n");
4264                 if (es->x_offset)
4265                         dx = -es->char_width;
4266                 break;
4267         case SB_LINERIGHT:
4268                 TRACE("SB_LINERIGHT\n");
4269                 if (es->x_offset < es->text_width)
4270                         dx = es->char_width;
4271                 break;
4272         case SB_PAGELEFT:
4273                 TRACE("SB_PAGELEFT\n");
4274                 if (es->x_offset)
4275                         dx = -fw / HSCROLL_FRACTION / es->char_width * es->char_width;
4276                 break;
4277         case SB_PAGERIGHT:
4278                 TRACE("SB_PAGERIGHT\n");
4279                 if (es->x_offset < es->text_width)
4280                         dx = fw / HSCROLL_FRACTION / es->char_width * es->char_width;
4281                 break;
4282         case SB_LEFT:
4283                 TRACE("SB_LEFT\n");
4284                 if (es->x_offset)
4285                         dx = -es->x_offset;
4286                 break;
4287         case SB_RIGHT:
4288                 TRACE("SB_RIGHT\n");
4289                 if (es->x_offset < es->text_width)
4290                         dx = es->text_width - es->x_offset;
4291                 break;
4292         case SB_THUMBTRACK:
4293                 TRACE("SB_THUMBTRACK %d\n", pos);
4294                 es->flags |= EF_HSCROLL_TRACK;
4295                 if(es->style & WS_HSCROLL)
4296                     dx = pos - es->x_offset;
4297                 else
4298                 {
4299                     INT fw, new_x;
4300                     /* Sanity check */
4301                     if(pos < 0 || pos > 100) return 0;
4302                     /* Assume default scroll range 0-100 */
4303                     fw = es->format_rect.right - es->format_rect.left;
4304                     new_x = pos * (es->text_width - fw) / 100;
4305                     dx = es->text_width ? (new_x - es->x_offset) : 0;
4306                 }
4307                 break;
4308         case SB_THUMBPOSITION:
4309                 TRACE("SB_THUMBPOSITION %d\n", pos);
4310                 es->flags &= ~EF_HSCROLL_TRACK;
4311                 if(GetWindowLongW( es->hwndSelf, GWL_STYLE ) & WS_HSCROLL)
4312                     dx = pos - es->x_offset;
4313                 else
4314                 {
4315                     INT fw, new_x;
4316                     /* Sanity check */
4317                     if(pos < 0 || pos > 100) return 0;
4318                     /* Assume default scroll range 0-100 */
4319                     fw = es->format_rect.right - es->format_rect.left;
4320                     new_x = pos * (es->text_width - fw) / 100;
4321                     dx = es->text_width ? (new_x - es->x_offset) : 0;
4322                 }
4323                 if (!dx) {
4324                         /* force scroll info update */
4325                         EDIT_UpdateScrollInfo(es);
4326                         EDIT_NOTIFY_PARENT(es, EN_HSCROLL);
4327                 }
4328                 break;
4329         case SB_ENDSCROLL:
4330                 TRACE("SB_ENDSCROLL\n");
4331                 break;
4332         /*
4333          *      FIXME : the next two are undocumented !
4334          *      Are we doing the right thing ?
4335          *      At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
4336          *      although it's also a regular control message.
4337          */
4338         case EM_GETTHUMB: /* this one is used by NT notepad */
4339         case EM_GETTHUMB16:
4340         {
4341                 LRESULT ret;
4342                 if(GetWindowLongW( es->hwndSelf, GWL_STYLE ) & WS_HSCROLL)
4343                     ret = GetScrollPos(es->hwndSelf, SB_HORZ);
4344                 else
4345                 {
4346                     /* Assume default scroll range 0-100 */
4347                     INT fw = es->format_rect.right - es->format_rect.left;
4348                     ret = es->text_width ? es->x_offset * 100 / (es->text_width - fw) : 0;
4349                 }
4350                 TRACE("EM_GETTHUMB: returning %ld\n", ret);
4351                 return ret;
4352         }
4353         case EM_LINESCROLL16:
4354                 TRACE("EM_LINESCROLL16\n");
4355                 dx = pos;
4356                 break;
4357
4358         default:
4359                 ERR("undocumented WM_HSCROLL action %d (0x%04x), please report\n",
4360                     action, action);
4361                 return 0;
4362         }
4363         if (dx)
4364         {
4365             INT fw = es->format_rect.right - es->format_rect.left;
4366             /* check if we are going to move too far */
4367             if(es->x_offset + dx + fw > es->text_width)
4368                 dx = es->text_width - fw - es->x_offset;
4369             if(dx)
4370                 EDIT_EM_LineScroll_internal(es, dx, 0);
4371         }
4372         return 0;
4373 }
4374
4375
4376 /*********************************************************************
4377  *
4378  *      EDIT_CheckCombo
4379  *
4380  */
4381 static BOOL EDIT_CheckCombo(EDITSTATE *es, UINT msg, INT key)
4382 {
4383    HWND hLBox = es->hwndListBox;
4384    HWND hCombo;
4385    BOOL bDropped;
4386    int  nEUI;
4387
4388    if (!hLBox)
4389       return FALSE;
4390
4391    hCombo   = GetParent(es->hwndSelf);
4392    bDropped = TRUE;
4393    nEUI     = 0;
4394
4395    TRACE_(combo)("[%p]: handling msg %x (%x)\n", es->hwndSelf, msg, key);
4396
4397    if (key == VK_UP || key == VK_DOWN)
4398    {
4399       if (SendMessageW(hCombo, CB_GETEXTENDEDUI, 0, 0))
4400          nEUI = 1;
4401
4402       if (msg == WM_KEYDOWN || nEUI)
4403           bDropped = (BOOL)SendMessageW(hCombo, CB_GETDROPPEDSTATE, 0, 0);
4404    }
4405
4406    switch (msg)
4407    {
4408       case WM_KEYDOWN:
4409          if (!bDropped && nEUI && (key == VK_UP || key == VK_DOWN))
4410          {
4411             /* make sure ComboLBox pops up */
4412             SendMessageW(hCombo, CB_SETEXTENDEDUI, FALSE, 0);
4413             key = VK_F4;
4414             nEUI = 2;
4415          }
4416
4417          SendMessageW(hLBox, WM_KEYDOWN, (WPARAM)key, 0);
4418          break;
4419
4420       case WM_SYSKEYDOWN: /* Handle Alt+up/down arrows */
4421          if (nEUI)
4422             SendMessageW(hCombo, CB_SHOWDROPDOWN, bDropped ? FALSE : TRUE, 0);
4423          else
4424             SendMessageW(hLBox, WM_KEYDOWN, (WPARAM)VK_F4, 0);
4425          break;
4426    }
4427
4428    if(nEUI == 2)
4429       SendMessageW(hCombo, CB_SETEXTENDEDUI, TRUE, 0);
4430
4431    return TRUE;
4432 }
4433
4434
4435 /*********************************************************************
4436  *
4437  *      WM_KEYDOWN
4438  *
4439  *      Handling of special keys that don't produce a WM_CHAR
4440  *      (i.e. non-printable keys) & Backspace & Delete
4441  *
4442  */
4443 static LRESULT EDIT_WM_KeyDown(EDITSTATE *es, INT key)
4444 {
4445         BOOL shift;
4446         BOOL control;
4447
4448         if (GetKeyState(VK_MENU) & 0x8000)
4449                 return 0;
4450
4451         shift = GetKeyState(VK_SHIFT) & 0x8000;
4452         control = GetKeyState(VK_CONTROL) & 0x8000;
4453
4454         switch (key) {
4455         case VK_F4:
4456         case VK_UP:
4457                 if (EDIT_CheckCombo(es, WM_KEYDOWN, key) || key == VK_F4)
4458                         break;
4459
4460                 /* fall through */
4461         case VK_LEFT:
4462                 if ((es->style & ES_MULTILINE) && (key == VK_UP))
4463                         EDIT_MoveUp_ML(es, shift);
4464                 else
4465                         if (control)
4466                                 EDIT_MoveWordBackward(es, shift);
4467                         else
4468                                 EDIT_MoveBackward(es, shift);
4469                 break;
4470         case VK_DOWN:
4471                 if (EDIT_CheckCombo(es, WM_KEYDOWN, key))
4472                         break;
4473                 /* fall through */
4474         case VK_RIGHT:
4475                 if ((es->style & ES_MULTILINE) && (key == VK_DOWN))
4476                         EDIT_MoveDown_ML(es, shift);
4477                 else if (control)
4478                         EDIT_MoveWordForward(es, shift);
4479                 else
4480                         EDIT_MoveForward(es, shift);
4481                 break;
4482         case VK_HOME:
4483                 EDIT_MoveHome(es, shift);
4484                 break;
4485         case VK_END:
4486                 EDIT_MoveEnd(es, shift);
4487                 break;
4488         case VK_PRIOR:
4489                 if (es->style & ES_MULTILINE)
4490                         EDIT_MovePageUp_ML(es, shift);
4491                 else
4492                         EDIT_CheckCombo(es, WM_KEYDOWN, key);
4493                 break;
4494         case VK_NEXT:
4495                 if (es->style & ES_MULTILINE)
4496                         EDIT_MovePageDown_ML(es, shift);
4497                 else
4498                         EDIT_CheckCombo(es, WM_KEYDOWN, key);
4499                 break;
4500         case VK_DELETE:
4501                 if (!(es->style & ES_READONLY) && !(shift && control)) {
4502                         if (es->selection_start != es->selection_end) {
4503                                 if (shift)
4504                                         EDIT_WM_Cut(es);
4505                                 else
4506                                         EDIT_WM_Clear(es);
4507                         } else {
4508                                 if (shift) {
4509                                         /* delete character left of caret */
4510                                         EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
4511                                         EDIT_MoveBackward(es, TRUE);
4512                                         EDIT_WM_Clear(es);
4513                                 } else if (control) {
4514                                         /* delete to end of line */
4515                                         EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
4516                                         EDIT_MoveEnd(es, TRUE);
4517                                         EDIT_WM_Clear(es);
4518                                 } else {
4519                                         /* delete character right of caret */
4520                                         EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
4521                                         EDIT_MoveForward(es, TRUE);
4522                                         EDIT_WM_Clear(es);
4523                                 }
4524                         }
4525                 }
4526                 break;
4527         case VK_INSERT:
4528                 if (shift) {
4529                         if (!(es->style & ES_READONLY))
4530                                 EDIT_WM_Paste(es);
4531                 } else if (control)
4532                         EDIT_WM_Copy(es);
4533                 break;
4534         case VK_RETURN:
4535             /* If the edit doesn't want the return send a message to the default object */
4536             if(!(es->style & ES_WANTRETURN))
4537             {
4538                 HWND hwndParent = GetParent(es->hwndSelf);
4539                 DWORD dw = SendMessageW( hwndParent, DM_GETDEFID, 0, 0 );
4540                 if (HIWORD(dw) == DC_HASDEFID)
4541                 {
4542                     SendMessageW( hwndParent, WM_COMMAND,
4543                                   MAKEWPARAM( LOWORD(dw), BN_CLICKED ),
4544                               (LPARAM)GetDlgItem( hwndParent, LOWORD(dw) ) );
4545                 }
4546             }
4547             break;
4548         }
4549         return 0;
4550 }
4551
4552
4553 /*********************************************************************
4554  *
4555  *      WM_KILLFOCUS
4556  *
4557  */
4558 static LRESULT EDIT_WM_KillFocus(EDITSTATE *es)
4559 {
4560         es->flags &= ~EF_FOCUSED;
4561         DestroyCaret();
4562         if(!(es->style & ES_NOHIDESEL))
4563                 EDIT_InvalidateText(es, es->selection_start, es->selection_end);
4564         EDIT_NOTIFY_PARENT(es, EN_KILLFOCUS);
4565         return 0;
4566 }
4567
4568
4569 /*********************************************************************
4570  *
4571  *      WM_LBUTTONDBLCLK
4572  *
4573  *      The caret position has been set on the WM_LBUTTONDOWN message
4574  *
4575  */
4576 static LRESULT EDIT_WM_LButtonDblClk(EDITSTATE *es)
4577 {
4578         INT s;
4579         INT e = es->selection_end;
4580         INT l;
4581         INT li;
4582         INT ll;
4583
4584         es->bCaptureState = TRUE;
4585         SetCapture(es->hwndSelf);
4586
4587         l = EDIT_EM_LineFromChar(es, e);
4588         li = EDIT_EM_LineIndex(es, l);
4589         ll = EDIT_EM_LineLength(es, e);
4590         s = li + EDIT_CallWordBreakProc(es, li, e - li, ll, WB_LEFT);
4591         e = li + EDIT_CallWordBreakProc(es, li, e - li, ll, WB_RIGHT);
4592         EDIT_EM_SetSel(es, s, e, FALSE);
4593         EDIT_EM_ScrollCaret(es);
4594         es->region_posx = es->region_posy = 0;
4595         SetTimer(es->hwndSelf, 0, 100, NULL);
4596         return 0;
4597 }
4598
4599
4600 /*********************************************************************
4601  *
4602  *      WM_LBUTTONDOWN
4603  *
4604  */
4605 static LRESULT EDIT_WM_LButtonDown(EDITSTATE *es, DWORD keys, INT x, INT y)
4606 {
4607         INT e;
4608         BOOL after_wrap;
4609
4610         es->bCaptureState = TRUE;
4611         SetCapture(es->hwndSelf);
4612         EDIT_ConfinePoint(es, &x, &y);
4613         e = EDIT_CharFromPos(es, x, y, &after_wrap);
4614         EDIT_EM_SetSel(es, (keys & MK_SHIFT) ? es->selection_start : e, e, after_wrap);
4615         EDIT_EM_ScrollCaret(es);
4616         es->region_posx = es->region_posy = 0;
4617         SetTimer(es->hwndSelf, 0, 100, NULL);
4618
4619         if (!(es->flags & EF_FOCUSED))
4620             SetFocus(es->hwndSelf);
4621
4622         return 0;
4623 }
4624
4625
4626 /*********************************************************************
4627  *
4628  *      WM_LBUTTONUP
4629  *
4630  */
4631 static LRESULT EDIT_WM_LButtonUp(EDITSTATE *es)
4632 {
4633         if (es->bCaptureState) {
4634                 KillTimer(es->hwndSelf, 0);
4635                 if (GetCapture() == es->hwndSelf) ReleaseCapture();
4636         }
4637         es->bCaptureState = FALSE;
4638         return 0;
4639 }
4640
4641
4642 /*********************************************************************
4643  *
4644  *      WM_MBUTTONDOWN
4645  *
4646  */
4647 static LRESULT EDIT_WM_MButtonDown(EDITSTATE *es)
4648 {
4649     SendMessageW(es->hwndSelf, WM_PASTE, 0, 0);
4650     return 0;
4651 }
4652
4653
4654 /*********************************************************************
4655  *
4656  *      WM_MOUSEMOVE
4657  *
4658  */
4659 static LRESULT EDIT_WM_MouseMove(EDITSTATE *es, INT x, INT y)
4660 {
4661         INT e;
4662         BOOL after_wrap;
4663         INT prex, prey;
4664
4665         /* If the mouse has been captured by process other than the edit control itself,
4666          * the windows edit controls will not select the strings with mouse move.
4667          */
4668         if (!es->bCaptureState || GetCapture() != es->hwndSelf)
4669                 return 0;
4670
4671         /*
4672          *      FIXME: gotta do some scrolling if outside client
4673          *              area.  Maybe reset the timer ?
4674          */
4675         prex = x; prey = y;
4676         EDIT_ConfinePoint(es, &x, &y);
4677         es->region_posx = (prex < x) ? -1 : ((prex > x) ? 1 : 0);
4678         es->region_posy = (prey < y) ? -1 : ((prey > y) ? 1 : 0);
4679         e = EDIT_CharFromPos(es, x, y, &after_wrap);
4680         EDIT_EM_SetSel(es, es->selection_start, e, after_wrap);
4681         EDIT_SetCaretPos(es,es->selection_end,es->flags & EF_AFTER_WRAP);
4682         return 0;
4683 }
4684
4685
4686 /*********************************************************************
4687  *
4688  *      WM_NCCREATE
4689  *
4690  * See also EDIT_WM_StyleChanged
4691  */
4692 static LRESULT EDIT_WM_NCCreate(HWND hwnd, LPCREATESTRUCTW lpcs, BOOL unicode)
4693 {
4694         EDITSTATE *es;
4695         UINT alloc_size;
4696
4697         TRACE("Creating %s edit control, style = %08lx\n",
4698                 unicode ? "Unicode" : "ANSI", lpcs->style);
4699
4700         if (!(es = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*es))))
4701                 return FALSE;
4702         SetWindowLongPtrW( hwnd, 0, (LONG_PTR)es );
4703
4704        /*
4705         *      Note: since the EDITSTATE has not been fully initialized yet,
4706         *            we can't use any API calls that may send
4707         *            WM_XXX messages before WM_NCCREATE is completed.
4708         */
4709
4710         es->is_unicode = unicode;
4711         es->style = lpcs->style;
4712
4713         es->bEnableState = !(es->style & WS_DISABLED);
4714
4715         es->hwndSelf = hwnd;
4716         /* Save parent, which will be notified by EN_* messages */
4717         es->hwndParent = lpcs->hwndParent;
4718
4719         if (es->style & ES_COMBO)
4720            es->hwndListBox = GetDlgItem(es->hwndParent, ID_CB_LISTBOX);
4721
4722         /* Number overrides lowercase overrides uppercase (at least it
4723          * does in Win95).  However I'll bet that ES_NUMBER would be
4724          * invalid under Win 3.1.
4725          */
4726         if (es->style & ES_NUMBER) {
4727                 ; /* do not override the ES_NUMBER */
4728         }  else if (es->style & ES_LOWERCASE) {
4729                 es->style &= ~ES_UPPERCASE;
4730         }
4731         if (es->style & ES_MULTILINE) {
4732                 es->buffer_limit = BUFLIMIT_MULTI;
4733                 if (es->style & WS_VSCROLL)
4734                         es->style |= ES_AUTOVSCROLL;
4735                 if (es->style & WS_HSCROLL)
4736                         es->style |= ES_AUTOHSCROLL;
4737                 es->style &= ~ES_PASSWORD;
4738                 if ((es->style & ES_CENTER) || (es->style & ES_RIGHT)) {
4739                         /* Confirmed - RIGHT overrides CENTER */
4740                         if (es->style & ES_RIGHT)
4741                                 es->style &= ~ES_CENTER;
4742                         es->style &= ~WS_HSCROLL;
4743                         es->style &= ~ES_AUTOHSCROLL;
4744                 }
4745         } else {
4746                 es->buffer_limit = BUFLIMIT_SINGLE;
4747                 if ((es->style & ES_RIGHT) && (es->style & ES_CENTER))
4748                         es->style &= ~ES_CENTER;
4749                 es->style &= ~WS_HSCROLL;
4750                 es->style &= ~WS_VSCROLL;
4751                 if (es->style & ES_PASSWORD)
4752                         es->password_char = '*';
4753         }
4754
4755         alloc_size = ROUND_TO_GROW((es->buffer_size + 1) * sizeof(WCHAR));
4756         if(!(es->hloc32W = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size)))
4757             return FALSE;
4758         es->buffer_size = LocalSize(es->hloc32W)/sizeof(WCHAR) - 1;
4759
4760         if (!(es->undo_text = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (es->buffer_size + 1) * sizeof(WCHAR))))
4761                 return FALSE;
4762         es->undo_buffer_size = es->buffer_size;
4763
4764         if (es->style & ES_MULTILINE)
4765                 if (!(es->first_line_def = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LINEDEF))))
4766                         return FALSE;
4767         es->line_count = 1;
4768
4769         /*
4770          * In Win95 look and feel, the WS_BORDER style is replaced by the
4771          * WS_EX_CLIENTEDGE style for the edit control. This gives the edit
4772          * control a nonclient area so we don't need to draw the border.
4773          * If WS_BORDER without WS_EX_CLIENTEDGE is specified we shouldn't have
4774          * a nonclient area and we should handle painting the border ourselves.
4775          *
4776          * When making modifications please ensure that the code still works 
4777          * for edit controls created directly with style 0x50800000, exStyle 0
4778          * (which should have a single pixel border)
4779          */
4780         if (lpcs->dwExStyle & WS_EX_CLIENTEDGE)
4781                 es->style &= ~WS_BORDER;
4782         else if (es->style & WS_BORDER)
4783                 SetWindowLongW(hwnd, GWL_STYLE, es->style & ~WS_BORDER);
4784
4785         return TRUE;
4786 }
4787
4788 /*********************************************************************
4789  *
4790  *      WM_PAINT
4791  *
4792  */
4793 static void EDIT_WM_Paint(EDITSTATE *es, HDC hdc)
4794 {
4795         PAINTSTRUCT ps;
4796         INT i;
4797         HDC dc;
4798         HFONT old_font = 0;
4799         RECT rc;
4800         RECT rcClient;
4801         RECT rcLine;
4802         RECT rcRgn;
4803         HBRUSH brush;
4804         HBRUSH old_brush;
4805         INT bw, bh;
4806         BOOL rev = es->bEnableState &&
4807                                 ((es->flags & EF_FOCUSED) ||
4808                                         (es->style & ES_NOHIDESEL));
4809         dc = hdc ? hdc : BeginPaint(es->hwndSelf, &ps);
4810
4811         GetClientRect(es->hwndSelf, &rcClient);
4812
4813         /* get the background brush */
4814         brush = EDIT_NotifyCtlColor(es, dc);
4815
4816         /* paint the border and the background */
4817         IntersectClipRect(dc, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
4818         
4819         if(es->style & WS_BORDER) {
4820                 bw = GetSystemMetrics(SM_CXBORDER);
4821                 bh = GetSystemMetrics(SM_CYBORDER);
4822                 rc = rcClient;
4823                 if(es->style & ES_MULTILINE) {
4824                         if(es->style & WS_HSCROLL) rc.bottom+=bh;
4825                         if(es->style & WS_VSCROLL) rc.right+=bw;
4826                 }
4827                 
4828                 /* Draw the frame. Same code as in nonclient.c */
4829                 old_brush = SelectObject(dc, GetSysColorBrush(COLOR_WINDOWFRAME));
4830                 PatBlt(dc, rc.left, rc.top, rc.right - rc.left, bh, PATCOPY);
4831                 PatBlt(dc, rc.left, rc.top, bw, rc.bottom - rc.top, PATCOPY);
4832                 PatBlt(dc, rc.left, rc.bottom - 1, rc.right - rc.left, -bw, PATCOPY);
4833                 PatBlt(dc, rc.right - 1, rc.top, -bw, rc.bottom - rc.top, PATCOPY);
4834                 SelectObject(dc, old_brush);
4835                 
4836                 /* Keep the border clean */
4837                 IntersectClipRect(dc, rc.left+bw, rc.top+bh,
4838                     max(rc.right-bw, rc.left+bw), max(rc.bottom-bh, rc.top+bh));
4839         }
4840         
4841         GetClipBox(dc, &rc);
4842         FillRect(dc, &rc, brush);
4843
4844         IntersectClipRect(dc, es->format_rect.left,
4845                                 es->format_rect.top,
4846                                 es->format_rect.right,
4847                                 es->format_rect.bottom);
4848         if (es->style & ES_MULTILINE) {
4849                 rc = rcClient;
4850                 IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom);
4851         }
4852         if (es->font)
4853                 old_font = SelectObject(dc, es->font);
4854
4855         if (!es->bEnableState)
4856                 SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
4857         GetClipBox(dc, &rcRgn);
4858         if (es->style & ES_MULTILINE) {
4859                 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
4860                 for (i = es->y_offset ; i <= min(es->y_offset + vlc, es->y_offset + es->line_count - 1) ; i++) {
4861                         EDIT_GetLineRect(es, i, 0, -1, &rcLine);
4862                         if (IntersectRect(&rc, &rcRgn, &rcLine))
4863                                 EDIT_PaintLine(es, dc, i, rev);
4864                 }
4865         } else {
4866                 EDIT_GetLineRect(es, 0, 0, -1, &rcLine);
4867                 if (IntersectRect(&rc, &rcRgn, &rcLine))
4868                         EDIT_PaintLine(es, dc, 0, rev);
4869         }
4870         if (es->font)
4871                 SelectObject(dc, old_font);
4872
4873         if (!hdc)
4874             EndPaint(es->hwndSelf, &ps);
4875 }
4876
4877
4878 /*********************************************************************
4879  *
4880  *      WM_PASTE
4881  *
4882  */
4883 static void EDIT_WM_Paste(EDITSTATE *es)
4884 {
4885         HGLOBAL hsrc;
4886         LPWSTR src;
4887
4888         /* Protect read-only edit control from modification */
4889         if(es->style & ES_READONLY)
4890             return;
4891
4892         OpenClipboard(es->hwndSelf);
4893         if ((hsrc = GetClipboardData(CF_UNICODETEXT))) {
4894                 src = (LPWSTR)GlobalLock(hsrc);
4895                 EDIT_EM_ReplaceSel(es, TRUE, src, TRUE, TRUE);
4896                 GlobalUnlock(hsrc);
4897         }
4898         CloseClipboard();
4899 }
4900
4901
4902 /*********************************************************************
4903  *
4904  *      WM_SETFOCUS
4905  *
4906  */
4907 static void EDIT_WM_SetFocus(EDITSTATE *es)
4908 {
4909         es->flags |= EF_FOCUSED;
4910
4911         if (!(es->style & ES_NOHIDESEL))
4912             EDIT_InvalidateText(es, es->selection_start, es->selection_end);
4913
4914         /* single line edit updates itself */
4915         if (!(es->style & ES_MULTILINE))
4916         {
4917             HDC hdc = GetDC(es->hwndSelf);
4918             EDIT_WM_Paint(es, hdc);
4919             ReleaseDC(es->hwndSelf, hdc);
4920         }
4921
4922         CreateCaret(es->hwndSelf, 0, 2, es->line_height);
4923         EDIT_SetCaretPos(es, es->selection_end,
4924                          es->flags & EF_AFTER_WRAP);
4925         ShowCaret(es->hwndSelf);
4926         EDIT_NOTIFY_PARENT(es, EN_SETFOCUS);
4927 }
4928
4929
4930 /*********************************************************************
4931  *
4932  *      WM_SETFONT
4933  *
4934  * With Win95 look the margins are set to default font value unless
4935  * the system font (font == 0) is being set, in which case they are left
4936  * unchanged.
4937  *
4938  */
4939 static void EDIT_WM_SetFont(EDITSTATE *es, HFONT font, BOOL redraw)
4940 {
4941         TEXTMETRICW tm;
4942         HDC dc;
4943         HFONT old_font = 0;
4944         RECT clientRect;
4945
4946         es->font = font;
4947         dc = GetDC(es->hwndSelf);
4948         if (font)
4949                 old_font = SelectObject(dc, font);
4950         GetTextMetricsW(dc, &tm);
4951         es->line_height = tm.tmHeight;
4952         es->char_width = tm.tmAveCharWidth;
4953         if (font)
4954                 SelectObject(dc, old_font);
4955         ReleaseDC(es->hwndSelf, dc);
4956         
4957         /* Reset the format rect and the margins */
4958         GetClientRect(es->hwndSelf, &clientRect);
4959         EDIT_SetRectNP(es, &clientRect);
4960         EDIT_EM_SetMargins(es, EC_LEFTMARGIN | EC_RIGHTMARGIN,
4961                            EC_USEFONTINFO, EC_USEFONTINFO, FALSE);
4962
4963         if (es->style & ES_MULTILINE)
4964                 EDIT_BuildLineDefs_ML(es, 0, strlenW(es->text), 0, NULL);
4965         else
4966             EDIT_CalcLineWidth_SL(es);
4967
4968         if (redraw)
4969                 EDIT_UpdateText(es, NULL, TRUE);
4970         if (es->flags & EF_FOCUSED) {
4971                 DestroyCaret();
4972                 CreateCaret(es->hwndSelf, 0, 2, es->line_height);
4973                 EDIT_SetCaretPos(es, es->selection_end,
4974                                  es->flags & EF_AFTER_WRAP);
4975                 ShowCaret(es->hwndSelf);
4976         }
4977 }
4978
4979
4980 /*********************************************************************
4981  *
4982  *      WM_SETTEXT
4983  *
4984  * NOTES
4985  *  For multiline controls (ES_MULTILINE), reception of WM_SETTEXT triggers:
4986  *  The modified flag is reset. No notifications are sent.
4987  *
4988  *  For single-line controls, reception of WM_SETTEXT triggers:
4989  *  The modified flag is reset. EN_UPDATE and EN_CHANGE notifications are sent.
4990  *
4991  */
4992 static void EDIT_WM_SetText(EDITSTATE *es, LPCWSTR text, BOOL unicode)
4993 {
4994     if (!unicode && text)
4995     {
4996         LPCSTR textA = (LPCSTR)text;
4997         INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
4998         LPWSTR textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR));
4999         if (textW)
5000             MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
5001         text = textW;
5002     }
5003
5004     if (es->flags & EF_UPDATE)
5005         /* fixed this bug once; complain if we see it about to happen again. */
5006         ERR("SetSel may generate UPDATE message whose handler may reset "
5007             "selection.\n");
5008
5009     EDIT_EM_SetSel(es, 0, (UINT)-1, FALSE);
5010     if (text) 
5011     {
5012         TRACE("%s\n", debugstr_w(text));
5013         EDIT_EM_ReplaceSel(es, FALSE, text, FALSE, FALSE);
5014         if(!unicode)
5015             HeapFree(GetProcessHeap(), 0, (LPWSTR)text);
5016     } 
5017     else 
5018     {
5019         static const WCHAR empty_stringW[] = {0};
5020         TRACE("<NULL>\n");
5021         EDIT_EM_ReplaceSel(es, FALSE, empty_stringW, FALSE, FALSE);
5022     }
5023     es->x_offset = 0;
5024     es->flags &= ~EF_MODIFIED;
5025     EDIT_EM_SetSel(es, 0, 0, FALSE);
5026
5027     /* Send the notification after the selection start and end have been set
5028      * edit control doesn't send notification on WM_SETTEXT
5029      * if it is multiline, or it is part of combobox
5030      */
5031     if( !((es->style & ES_MULTILINE) || es->hwndListBox))
5032     {
5033         EDIT_NOTIFY_PARENT(es, EN_UPDATE);
5034         EDIT_NOTIFY_PARENT(es, EN_CHANGE);
5035     }
5036     EDIT_EM_ScrollCaret(es);
5037     EDIT_UpdateScrollInfo(es);    
5038 }
5039
5040
5041 /*********************************************************************
5042  *
5043  *      WM_SIZE
5044  *
5045  */
5046 static void EDIT_WM_Size(EDITSTATE *es, UINT action, INT width, INT height)
5047 {
5048         if ((action == SIZE_MAXIMIZED) || (action == SIZE_RESTORED)) {
5049                 RECT rc;
5050                 TRACE("width = %d, height = %d\n", width, height);
5051                 SetRect(&rc, 0, 0, width, height);
5052                 EDIT_SetRectNP(es, &rc);
5053                 EDIT_UpdateText(es, NULL, TRUE);
5054         }
5055 }
5056
5057
5058 /*********************************************************************
5059  *
5060  *      WM_STYLECHANGED
5061  *
5062  * This message is sent by SetWindowLong on having changed either the Style
5063  * or the extended style.
5064  *
5065  * We ensure that the window's version of the styles and the EDITSTATE's agree.
5066  *
5067  * See also EDIT_WM_NCCreate
5068  *
5069  * It appears that the Windows version of the edit control allows the style
5070  * (as retrieved by GetWindowLong) to be any value and maintains an internal
5071  * style variable which will generally be different.  In this function we
5072  * update the internal style based on what changed in the externally visible
5073  * style.
5074  *
5075  * Much of this content as based upon the MSDN, especially:
5076  *  Platform SDK Documentation -> User Interface Services ->
5077  *      Windows User Interface -> Edit Controls -> Edit Control Reference ->
5078  *      Edit Control Styles
5079  */
5080 static LRESULT  EDIT_WM_StyleChanged ( EDITSTATE *es, WPARAM which, const STYLESTRUCT *style)
5081 {
5082         if (GWL_STYLE == which) {
5083                 DWORD style_change_mask;
5084                 DWORD new_style;
5085                 /* Only a subset of changes can be applied after the control
5086                  * has been created.
5087                  */
5088                 style_change_mask = ES_UPPERCASE | ES_LOWERCASE |
5089                                     ES_NUMBER;
5090                 if (es->style & ES_MULTILINE)
5091                         style_change_mask |= ES_WANTRETURN;
5092
5093                 new_style = style->styleNew & style_change_mask;
5094
5095                 /* Number overrides lowercase overrides uppercase (at least it
5096                  * does in Win95).  However I'll bet that ES_NUMBER would be
5097                  * invalid under Win 3.1.
5098                  */
5099                 if (new_style & ES_NUMBER) {
5100                         ; /* do not override the ES_NUMBER */
5101                 }  else if (new_style & ES_LOWERCASE) {
5102                         new_style &= ~ES_UPPERCASE;
5103                 }
5104
5105                 es->style = (es->style & ~style_change_mask) | new_style;
5106         } else if (GWL_EXSTYLE == which) {
5107                 ; /* FIXME - what is needed here */
5108         } else {
5109                 WARN ("Invalid style change %d\n",which);
5110         }
5111
5112         return 0;
5113 }
5114
5115 /*********************************************************************
5116  *
5117  *      WM_SYSKEYDOWN
5118  *
5119  */
5120 static LRESULT EDIT_WM_SysKeyDown(EDITSTATE *es, INT key, DWORD key_data)
5121 {
5122         if ((key == VK_BACK) && (key_data & 0x2000)) {
5123                 if (EDIT_EM_CanUndo(es))
5124                         EDIT_EM_Undo(es);
5125                 return 0;
5126         } else if (key == VK_UP || key == VK_DOWN) {
5127                 if (EDIT_CheckCombo(es, WM_SYSKEYDOWN, key))
5128                         return 0;
5129         }
5130         return DefWindowProcW(es->hwndSelf, WM_SYSKEYDOWN, (WPARAM)key, (LPARAM)key_data);
5131 }
5132
5133
5134 /*********************************************************************
5135  *
5136  *      WM_TIMER
5137  *
5138  */
5139 static void EDIT_WM_Timer(EDITSTATE *es)
5140 {
5141         if (es->region_posx < 0) {
5142                 EDIT_MoveBackward(es, TRUE);
5143         } else if (es->region_posx > 0) {
5144                 EDIT_MoveForward(es, TRUE);
5145         }
5146 /*
5147  *      FIXME: gotta do some vertical scrolling here, like
5148  *              EDIT_EM_LineScroll(hwnd, 0, 1);
5149  */
5150 }
5151
5152 /*********************************************************************
5153  *
5154  *      WM_VSCROLL
5155  *
5156  */
5157 static LRESULT EDIT_WM_VScroll(EDITSTATE *es, INT action, INT pos)
5158 {
5159         INT dy;
5160
5161         if (!(es->style & ES_MULTILINE))
5162                 return 0;
5163
5164         if (!(es->style & ES_AUTOVSCROLL))
5165                 return 0;
5166
5167         dy = 0;
5168         switch (action) {
5169         case SB_LINEUP:
5170         case SB_LINEDOWN:
5171         case SB_PAGEUP:
5172         case SB_PAGEDOWN:
5173                 TRACE("action %d (%s)\n", action, (action == SB_LINEUP ? "SB_LINEUP" :
5174                                                    (action == SB_LINEDOWN ? "SB_LINEDOWN" :
5175                                                     (action == SB_PAGEUP ? "SB_PAGEUP" :
5176                                                      "SB_PAGEDOWN"))));
5177                 EDIT_EM_Scroll(es, action);
5178                 return 0;
5179         case SB_TOP:
5180                 TRACE("SB_TOP\n");
5181                 dy = -es->y_offset;
5182                 break;
5183         case SB_BOTTOM:
5184                 TRACE("SB_BOTTOM\n");
5185                 dy = es->line_count - 1 - es->y_offset;
5186                 break;
5187         case SB_THUMBTRACK:
5188                 TRACE("SB_THUMBTRACK %d\n", pos);
5189                 es->flags |= EF_VSCROLL_TRACK;
5190                 if(es->style & WS_VSCROLL)
5191                     dy = pos - es->y_offset;
5192                 else
5193                 {
5194                     /* Assume default scroll range 0-100 */
5195                     INT vlc, new_y;
5196                     /* Sanity check */
5197                     if(pos < 0 || pos > 100) return 0;
5198                     vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
5199                     new_y = pos * (es->line_count - vlc) / 100;
5200                     dy = es->line_count ? (new_y - es->y_offset) : 0;
5201                     TRACE("line_count=%d, y_offset=%d, pos=%d, dy = %d\n",
5202                             es->line_count, es->y_offset, pos, dy);
5203                 }
5204                 break;
5205         case SB_THUMBPOSITION:
5206                 TRACE("SB_THUMBPOSITION %d\n", pos);
5207                 es->flags &= ~EF_VSCROLL_TRACK;
5208                 if(es->style & WS_VSCROLL)
5209                     dy = pos - es->y_offset;
5210                 else
5211                 {
5212                     /* Assume default scroll range 0-100 */
5213                     INT vlc, new_y;
5214                     /* Sanity check */
5215                     if(pos < 0 || pos > 100) return 0;
5216                     vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
5217                     new_y = pos * (es->line_count - vlc) / 100;
5218                     dy = es->line_count ? (new_y - es->y_offset) : 0;
5219                     TRACE("line_count=%d, y_offset=%d, pos=%d, dy = %d\n",
5220                             es->line_count, es->y_offset, pos, dy);
5221                 }
5222                 if (!dy)
5223                 {
5224                         /* force scroll info update */
5225                         EDIT_UpdateScrollInfo(es);
5226                         EDIT_NOTIFY_PARENT(es, EN_VSCROLL);
5227                 }
5228                 break;
5229         case SB_ENDSCROLL:
5230                 TRACE("SB_ENDSCROLL\n");
5231                 break;
5232         /*
5233          *      FIXME : the next two are undocumented !
5234          *      Are we doing the right thing ?
5235          *      At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
5236          *      although it's also a regular control message.
5237          */
5238         case EM_GETTHUMB: /* this one is used by NT notepad */
5239         case EM_GETTHUMB16:
5240         {
5241                 LRESULT ret;
5242                 if(GetWindowLongW( es->hwndSelf, GWL_STYLE ) & WS_VSCROLL)
5243                     ret = GetScrollPos(es->hwndSelf, SB_VERT);
5244                 else
5245                 {
5246                     /* Assume default scroll range 0-100 */
5247                     INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
5248                     ret = es->line_count ? es->y_offset * 100 / (es->line_count - vlc) : 0;
5249                 }
5250                 TRACE("EM_GETTHUMB: returning %ld\n", ret);
5251                 return ret;
5252         }
5253         case EM_LINESCROLL16:
5254                 TRACE("EM_LINESCROLL16 %d\n", pos);
5255                 dy = pos;
5256                 break;
5257
5258         default:
5259                 ERR("undocumented WM_VSCROLL action %d (0x%04x), please report\n",
5260                     action, action);
5261                 return 0;
5262         }
5263         if (dy)
5264                 EDIT_EM_LineScroll(es, 0, dy);
5265         return 0;
5266 }
5267
5268 /*********************************************************************
5269  *
5270  *      EDIT_UpdateText
5271  *
5272  */
5273 static void EDIT_UpdateTextRegion(EDITSTATE *es, HRGN hrgn, BOOL bErase)
5274 {
5275     if (es->flags & EF_UPDATE) {
5276         es->flags &= ~EF_UPDATE;
5277         EDIT_NOTIFY_PARENT(es, EN_UPDATE);
5278     }
5279     InvalidateRgn(es->hwndSelf, hrgn, bErase);
5280 }
5281
5282
5283 /*********************************************************************
5284  *
5285  *      EDIT_UpdateText
5286  *
5287  */
5288 static void EDIT_UpdateText(EDITSTATE *es, LPRECT rc, BOOL bErase)
5289 {
5290     if (es->flags & EF_UPDATE) {
5291         es->flags &= ~EF_UPDATE;
5292         EDIT_NOTIFY_PARENT(es, EN_UPDATE);
5293     }
5294     InvalidateRect(es->hwndSelf, rc, bErase);
5295 }
5296
5297 /********************************************************************
5298  * 
5299  * The Following code is to handle inline editing from IMEs
5300  */
5301
5302 static void EDIT_GetCompositionStr(HWND hwnd, LPARAM CompFlag, EDITSTATE *es)
5303 {
5304     DWORD dwBufLen;
5305     LPWSTR lpCompStr = NULL;
5306     HIMC hIMC;
5307     LPSTR lpCompStrAttr = NULL;
5308     DWORD dwBufLenAttr;
5309
5310     if (!(hIMC = ImmGetContext(hwnd)))
5311         return;
5312
5313     dwBufLen = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0);
5314
5315     if (dwBufLen <= 0)
5316     {
5317         ImmReleaseContext(hwnd, hIMC);
5318         return;
5319     }
5320
5321     lpCompStr = HeapAlloc(GetProcessHeap(),0,dwBufLen);
5322     if (!lpCompStr)
5323     {
5324         ERR("Unable to allocate IME CompositionString\n");
5325         ImmReleaseContext(hwnd,hIMC);
5326         return;
5327     }
5328
5329     ImmGetCompositionStringW(hIMC, GCS_COMPSTR, lpCompStr, dwBufLen);
5330     lpCompStr[dwBufLen/sizeof(WCHAR)] = 0;
5331
5332     if (CompFlag & GCS_COMPATTR)
5333     {
5334         /* 
5335          * We do not use the attributes yet. it would tell us what characters
5336          * are in transition and which are converted or decided upon
5337          */
5338         dwBufLenAttr = ImmGetCompositionStringW(hIMC, GCS_COMPATTR, NULL, 0);
5339         if (dwBufLenAttr)
5340         {
5341             dwBufLenAttr ++;
5342             lpCompStrAttr = HeapAlloc(GetProcessHeap(),0,dwBufLenAttr);
5343             if (!lpCompStrAttr)
5344             {
5345                 ERR("Unable to allocate IME Attribute String\n");
5346                 HeapFree(GetProcessHeap(),0,lpCompStr);
5347                 ImmReleaseContext(hwnd,hIMC);
5348                 return;
5349             }
5350             ImmGetCompositionStringW(hIMC,GCS_COMPATTR, lpCompStrAttr, 
5351                     dwBufLenAttr);
5352             lpCompStrAttr[dwBufLenAttr] = 0;
5353         }
5354         else
5355             lpCompStrAttr = NULL;
5356     }
5357
5358     /* check for change in composition start */
5359     if (es->selection_end < es->composition_start)
5360         es->composition_start = es->selection_end;
5361     
5362     /* replace existing selection string */
5363     es->selection_start = es->composition_start;
5364
5365     if (es->composition_len > 0)
5366         es->selection_end = es->composition_start + es->composition_len;
5367     else
5368         es->selection_end = es->selection_start;
5369
5370     EDIT_EM_ReplaceSel(es, FALSE, lpCompStr, TRUE, TRUE);
5371     es->composition_len = abs(es->composition_start - es->selection_end);
5372
5373     es->selection_start = es->composition_start;
5374     es->selection_end = es->selection_start + es->composition_len;
5375
5376     HeapFree(GetProcessHeap(),0,lpCompStrAttr);
5377     HeapFree(GetProcessHeap(),0,lpCompStr);
5378     ImmReleaseContext(hwnd,hIMC);
5379 }
5380
5381 static void EDIT_GetResultStr(HWND hwnd, EDITSTATE *es)
5382 {
5383     DWORD dwBufLen;
5384     LPWSTR lpResultStr;
5385     HIMC    hIMC;
5386
5387     if ( !(hIMC = ImmGetContext(hwnd)))
5388         return;
5389
5390     dwBufLen = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0);
5391     if (dwBufLen <= 0)
5392     {
5393         ImmReleaseContext(hwnd, hIMC);
5394         return;
5395     }
5396
5397     lpResultStr = HeapAlloc(GetProcessHeap(),0, dwBufLen);
5398     if (!lpResultStr)
5399     {
5400         ERR("Unable to alloc buffer for IME string\n");
5401         ImmReleaseContext(hwnd, hIMC);
5402         return;
5403     }
5404
5405     ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, lpResultStr, dwBufLen);
5406     lpResultStr[dwBufLen/sizeof(WCHAR)] = 0;
5407
5408     /* check for change in composition start */
5409     if (es->selection_end < es->composition_start)
5410         es->composition_start = es->selection_end;
5411
5412     es->selection_start = es->composition_start;
5413     es->selection_end = es->composition_start + es->composition_len;
5414     EDIT_EM_ReplaceSel(es, TRUE, lpResultStr, TRUE, TRUE);
5415     es->composition_start = es->selection_end;
5416     es->composition_len = 0;
5417
5418     HeapFree(GetProcessHeap(),0,lpResultStr);
5419     ImmReleaseContext(hwnd, hIMC);
5420 }
5421
5422 static void EDIT_ImeComposition(HWND hwnd, LPARAM CompFlag, EDITSTATE *es)
5423 {
5424     if (CompFlag & GCS_RESULTSTR)
5425         EDIT_GetResultStr(hwnd,es);
5426     if (CompFlag & GCS_COMPSTR)
5427         EDIT_GetCompositionStr(hwnd, CompFlag, es);
5428 }