merged changes from wine to edit control.
Modified: trunk/reactos/lib/user32/controls/edit.c

Modified: trunk/reactos/lib/user32/controls/edit.c
--- trunk/reactos/lib/user32/controls/edit.c	2005-12-10 19:22:43 UTC (rev 20041)
+++ trunk/reactos/lib/user32/controls/edit.c	2005-12-10 20:44:57 UTC (rev 20042)
@@ -20,20 +20,26 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
+ * NOTES
+ *
+ * This code was audited for completeness against the documented features
+ * of Comctl32.dll version 6.0 on Oct. 8, 2004, by Dimitrie O. Paun.
+ * 
+ * Unless otherwise noted, we believe this code to be complete, as per
+ * the specification mentioned above.
+ * If you discover missing features, or bugs, please note them below.
+ *
  * TODO:
- *   - ES_CENTER
- *   - ES_RIGHT
+ *   - EDITBALLOONTIP structure
+ *   - EM_GETCUEBANNER/Edit_GetCueBannerText
+ *   - EM_HIDEBALLOONTIP/Edit_HideBalloonTip
+ *   - EM_SETCUEBANNER/Edit_SetCueBannerText
+ *   - EM_SHOWBALLOONTIP/Edit_ShowBalloonTip
+ *   - EM_GETIMESTATUS, EM_SETIMESTATUS
+ *   - EN_ALIGN_LTR_EC
+ *   - EN_ALIGN_RTL_EC
  *   - ES_OEMCONVERT
- *   -!ES_AUTOVSCROLL (every multi line control *is* auto vscroll)
- *   -!ES_AUTOHSCROLL (every single line control *is* auto hscroll)
  *
- * When there is no autoscrolling, the control should first check whether
- * the new text would fit.  If not, an EN_MAXTEXT should be sent.
- * However, currently this would require the actual change to be made,
- * then call EDIT_BuildLineDefs() and then find out that the new text doesn't
- * fit.  After all this, things should be put back in the state before the
- * changes. Note that for multi line controls !ES_AUTOHSCROLL works : wordwrap.
- *
  */
 
 #include <user32.h>
@@ -142,12 +148,12 @@
 #define ORDER_UINT(x,y) do { if ((UINT)(y) < (UINT)(x)) SWAP_UINT32((x),(y)); } while(0)
 
 /* used for disabled or read-only edit control */
-#define EDIT_NOTIFY_PARENT(es, wNotifyCode, str) \
+#define EDIT_NOTIFY_PARENT(es, wNotifyCode) \
 	do \
 	{ /* Notify parent which has created this edit control */ \
-	    TRACE("notification " str " sent to hwnd=%p\n", es->hwndParent); \
+	    TRACE("notification " #wNotifyCode " sent to hwnd=%p\n", es->hwndParent); \
 	    SendMessageW(es->hwndParent, WM_COMMAND, \
-		     MAKEWPARAM(GetWindowLongW((es->hwndSelf),GWL_ID), wNotifyCode), \
+		     MAKEWPARAM(GetWindowLongPtrW((es->hwndSelf),GWLP_ID), wNotifyCode), \
 		     (LPARAM)(es->hwndSelf)); \
 	} while(0)
 
@@ -210,7 +216,7 @@
 #ifndef __REACTOS__
 static HLOCAL16	EDIT_EM_GetHandle16(EDITSTATE *es);
 #endif
-static INT	EDIT_EM_GetLine(EDITSTATE *es, INT line, LPARAM lParam, BOOL unicode);
+static INT	EDIT_EM_GetLine(EDITSTATE *es, INT line, LPWSTR dst, BOOL unicode);
 static LRESULT	EDIT_EM_GetSel(EDITSTATE *es, PUINT start, PUINT end);
 static LRESULT	EDIT_EM_GetThumb(EDITSTATE *es);
 static INT	EDIT_EM_LineFromChar(EDITSTATE *es, INT index);
@@ -227,14 +233,14 @@
 static void	EDIT_EM_SetHandle16(EDITSTATE *es, HLOCAL16 hloc);
 #endif
 static void	EDIT_EM_SetLimitText(EDITSTATE *es, INT limit);
-static void	EDIT_EM_SetMargins(EDITSTATE *es, INT action, INT left, INT right);
+static void	EDIT_EM_SetMargins(EDITSTATE *es, INT action, INT left, INT right, BOOL repaint);
 static void	EDIT_EM_SetPasswordChar(EDITSTATE *es, WCHAR c);
 static void	EDIT_EM_SetSel(EDITSTATE *es, UINT start, UINT end, BOOL after_wrap);
 static BOOL	EDIT_EM_SetTabStops(EDITSTATE *es, INT count, LPINT tabs);
 #ifndef __REACTOS__
 static BOOL	EDIT_EM_SetTabStops16(EDITSTATE *es, INT count, LPINT16 tabs);
 #endif
-static void	EDIT_EM_SetWordBreakProc(EDITSTATE *es, LPARAM lParam);
+static void	EDIT_EM_SetWordBreakProc(EDITSTATE *es, void *wbp);
 #ifndef __REACTOS__
 static void	EDIT_EM_SetWordBreakProc16(EDITSTATE *es, EDITWORDBREAKPROC16 wbp);
 #endif
@@ -249,7 +255,7 @@
 static LRESULT	EDIT_WM_Create(EDITSTATE *es, LPCWSTR name);
 static LRESULT	EDIT_WM_Destroy(EDITSTATE *es);
 static LRESULT	EDIT_WM_EraseBkGnd(EDITSTATE *es, HDC dc);
-static INT	EDIT_WM_GetText(EDITSTATE *es, INT count, LPARAM lParam, BOOL unicode);
+static INT	EDIT_WM_GetText(EDITSTATE *es, INT count, LPWSTR dst, BOOL unicode);
 static LRESULT	EDIT_WM_HScroll(EDITSTATE *es, INT action, INT pos);
 static LRESULT	EDIT_WM_KeyDown(EDITSTATE *es, INT key);
 static LRESULT	EDIT_WM_KillFocus(EDITSTATE *es);
@@ -259,11 +265,11 @@
 static LRESULT	EDIT_WM_MButtonDown(EDITSTATE *es);
 static LRESULT	EDIT_WM_MouseMove(EDITSTATE *es, INT x, INT y);
 static LRESULT	EDIT_WM_NCCreate(HWND hwnd, LPCREATESTRUCTW lpcs, BOOL unicode);
-static void	EDIT_WM_Paint(EDITSTATE *es, WPARAM wParam);
+static void	EDIT_WM_Paint(EDITSTATE *es, HDC hdc);
 static void	EDIT_WM_Paste(EDITSTATE *es);
 static void	EDIT_WM_SetFocus(EDITSTATE *es);
 static void	EDIT_WM_SetFont(EDITSTATE *es, HFONT font, BOOL redraw);
-static void	EDIT_WM_SetText(EDITSTATE *es, LPARAM lParam, BOOL unicode);
+static void	EDIT_WM_SetText(EDITSTATE *es, LPCWSTR text, BOOL unicode);
 static void	EDIT_WM_Size(EDITSTATE *es, UINT action, INT width, INT height);
 static LRESULT  EDIT_WM_StyleChanged(EDITSTATE *es, WPARAM which, const STYLESTRUCT *style);
 static LRESULT	EDIT_WM_SysKeyDown(EDITSTATE *es, INT key, DWORD key_data);
@@ -390,6 +396,7 @@
 
 static HBRUSH EDIT_NotifyCtlColor(EDITSTATE *es, HDC hdc)
 {
+        HBRUSH hbrush;
 	UINT msg;
 
         if ( get_app_version() >= 0x40000 && (!es->bEnableState || (es->style & ES_READONLY)))
@@ -398,7 +405,10 @@
 		msg = WM_CTLCOLOREDIT;
 
 	/* why do we notify to es->hwndParent, and we send this one to GetParent()? */
-	return (HBRUSH)SendMessageW(GetParent(es->hwndSelf), msg, (WPARAM)hdc, (LPARAM)es->hwndSelf);
+        hbrush = (HBRUSH)SendMessageW(GetParent(es->hwndSelf), msg, (WPARAM)hdc, (LPARAM)es->hwndSelf);
+        if (!hbrush)
+            hbrush = (HBRUSH)DefWindowProcW(GetParent(es->hwndSelf), msg, (WPARAM)hdc, (LPARAM)es->hwndSelf);
+        return hbrush;
 }
 
 static __inline LRESULT DefWindowProcT(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode)
@@ -425,21 +435,16 @@
 static LRESULT WINAPI EditWndProc_common( HWND hwnd, UINT msg,
                                           WPARAM wParam, LPARAM lParam, BOOL unicode )
 {
-	EDITSTATE *es = (EDITSTATE *)GetWindowLongW( hwnd, 0 );
+	EDITSTATE *es = (EDITSTATE *)GetWindowLongPtrW( hwnd, 0 );
 	LRESULT result = 0;
 
         //TRACE("hwnd=%p msg=%x (%s) wparam=%x lparam=%lx\n", hwnd, msg, SPY_GetMsgName(msg, hwnd), wParam, lParam);
 
 	if (!es && msg != WM_NCCREATE)
 		return DefWindowProcT(hwnd, msg, wParam, lParam, unicode);
-	else if (msg == WM_NCCREATE)
-		return EDIT_WM_NCCreate(hwnd, (LPCREATESTRUCTW)lParam, unicode);
-	else if (msg == WM_DESTROY)
-		return EDIT_WM_Destroy(es);
 
+	if (es && (msg != WM_DESTROY)) EDIT_LockBuffer(es);
 
-	if (es) EDIT_LockBuffer(es);
-
 	switch (msg) {
 #ifndef __REACTOS__
 	case EM_GETSEL16:
@@ -649,7 +654,7 @@
 		/* fall through */
 #endif
 	case EM_GETLINE:
-		result = (LRESULT)EDIT_EM_GetLine(es, (INT)wParam, lParam, unicode);
+		result = (LRESULT)EDIT_EM_GetLine(es, (INT)wParam, (LPWSTR)lParam, unicode);
 		break;
 
 #ifndef __REACTOS__
@@ -756,7 +761,7 @@
 		break;
 #endif
 	case EM_SETWORDBREAKPROC:
-		EDIT_EM_SetWordBreakProc(es, lParam);
+		EDIT_EM_SetWordBreakProc(es, (void *)lParam);
 		break;
 
 #ifndef __REACTOS__
@@ -790,7 +795,7 @@
 	/* The following EM_xxx are new to win95 and don't exist for 16 bit */
 
 	case EM_SETMARGINS:
-		EDIT_EM_SetMargins(es, (INT)wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));
+		EDIT_EM_SetMargins(es, (INT)wParam, (short)LOWORD(lParam), (short)HIWORD(lParam), TRUE);
 		break;
 
 	case EM_GETMARGINS:
@@ -802,7 +807,9 @@
 		break;
 
 	case EM_POSFROMCHAR:
-		result = EDIT_EM_PosFromChar(es, (INT)wParam, FALSE);
+                result = strlenW(es->text);
+		if ((INT)wParam >= result) result = -1;
+		else result = EDIT_EM_PosFromChar(es, (INT)wParam, FALSE);
 		break;
 
 	case EM_CHARFROMPOS:
@@ -813,6 +820,15 @@
          * are these in?  vaguely alphabetical?
          */
 
+	case WM_NCCREATE:
+		result = EDIT_WM_NCCreate(hwnd, (LPCREATESTRUCTW)lParam, unicode);
+		break;
+
+	case WM_DESTROY:
+		result = EDIT_WM_Destroy(es);
+		es = NULL;
+		break;
+
 	case WM_GETDLGCODE:
 		result = DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
 
@@ -900,8 +916,7 @@
 			    MultiByteToWideChar(CP_ACP, 0, nameA, -1, nameW, countW);
 		    }
 		    result = EDIT_WM_Create(es, nameW);
-		    if(nameW)
-			HeapFree(GetProcessHeap(), 0, nameW);
+		    HeapFree(GetProcessHeap(), 0, nameW);
 		}
 		break;
 
@@ -923,7 +938,7 @@
 		break;
 
 	case WM_GETTEXT:
-		result = (LRESULT)EDIT_WM_GetText(es, (INT)wParam, lParam, unicode);
+		result = (LRESULT)EDIT_WM_GetText(es, (INT)wParam, (LPWSTR)lParam, unicode);
 		break;
 
 	case WM_GETTEXTLENGTH:
@@ -960,16 +975,13 @@
   		result = EDIT_WM_MButtonDown(es);
 		break;
 
-	case WM_MOUSEACTIVATE:
-		result = MA_ACTIVATE;
-		break;
-
 	case WM_MOUSEMOVE:
 		result = EDIT_WM_MouseMove(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
 		break;
 
+	case WM_PRINTCLIENT:
 	case WM_PAINT:
-	        EDIT_WM_Paint(es, wParam);
+	        EDIT_WM_Paint(es, (HDC)wParam);
 		break;
 
 	case WM_PASTE:
@@ -989,7 +1001,7 @@
 		break;
 
 	case WM_SETTEXT:
-		EDIT_WM_SetText(es, lParam, unicode);
+		EDIT_WM_SetText(es, (LPCWSTR)lParam, unicode);
 		result = TRUE;
 		break;
 
@@ -1309,7 +1321,10 @@
 		rc.top = es->format_rect.top + nstart_line * es->line_height -
 			(es->y_offset * es->line_height); /* Adjust for vertical scrollbar */
 		rc.bottom = rc.top + es->line_height;
-		rc.left = es->format_rect.left + (INT)LOWORD(GetTabbedTextExtentW(dc,
+		if ((es->style & ES_CENTER) || (es->style & ES_RIGHT))
+			rc.left = es->format_rect.left;
+		else
+			rc.left = es->format_rect.left + (INT)LOWORD(GetTabbedTextExtentW(dc,
 					es->text + nstart_index, istart - nstart_index,
 					es->tabs_count, es->tabs)) - es->x_offset; /* Adjust for horz scroll */
 		rc.right = es->format_rect.right;
@@ -1328,6 +1343,7 @@
 			rc.bottom = line_count * es->line_height;
 		else
 			rc.bottom = line_index * es->line_height;
+		rc.bottom += es->format_rect.top;
 		rc.bottom -= (es->y_offset * es->line_height); /* Adjust for vertical scrollbar */
 		tmphrgn = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
 		CombineRgn(hrgn, hrgn, tmphrgn, RGN_OR);
@@ -1347,7 +1363,27 @@
  */
 static void EDIT_CalcLineWidth_SL(EDITSTATE *es)
 {
-    es->text_width = (short)LOWORD(EDIT_EM_PosFromChar(es, strlenW(es->text), FALSE));
+	SIZE size;
+	LPWSTR text;
+	HDC dc;
+	HFONT old_font = 0;
+
+	text = EDIT_GetPasswordPointer_SL(es);
+
+	dc = GetDC(es->hwndSelf);
+	if (es->font)
+		old_font = SelectObject(dc, es->font);
+
+	GetTextExtentPoint32W(dc, text, strlenW(text), &size);
+
+	if (es->font)
+		SelectObject(dc, old_font);
+	ReleaseDC(es->hwndSelf, dc);
+
+	if (es->style & ES_PASSWORD)
+		HeapFree(GetProcessHeap(), 0, text);
+
+	es->text_width = size.cx;
 }
 
 /*********************************************************************
@@ -1450,6 +1486,7 @@
 	INT index;
 	HDC dc;
 	HFONT old_font = 0;
+	INT x_high = 0, x_low = 0;
 
 	if (es->style & ES_MULTILINE) {
 		INT line = (y - es->format_rect.top) / es->line_height + es->y_offset;
@@ -1462,6 +1499,10 @@
 			line--;
 		}
 		x += es->x_offset - es->format_rect.left;
+		if (es->style & ES_RIGHT)
+			x -= (es->format_rect.right - es->format_rect.left) - line_def->width;
+		else if (es->style & ES_CENTER)
+			x -= ((es->format_rect.right - es->format_rect.left) - line_def->width) / 2;
 		if (x >= line_def->width) {
 			if (after_wrap)
 				*after_wrap = (line_def->ending == END_WRAP);
@@ -1475,15 +1516,24 @@
 		dc = GetDC(es->hwndSelf);
 		if (es->font)
 			old_font = SelectObject(dc, es->font);
-                    low = line_index + 1;
+                    low = line_index;
                     high = line_index + line_def->net_length + 1;
                     while (low < high - 1)
                     {
                         INT mid = (low + high) / 2;
-			if (LOWORD(GetTabbedTextExtentW(dc, es->text + line_index,mid - line_index, es->tabs_count, es->tabs)) > x) high = mid;
-                        else low = mid;
+                        INT x_now = LOWORD(GetTabbedTextExtentW(dc, es->text + line_index, mid - line_index, es->tabs_count, es->tabs));
+                        if (x_now > x) {
+                            high = mid;
+                            x_high = x_now;
+                        } else {
+                            low = mid;
+                            x_low = x_now;
+                        }
                     }
-                    index = low;
+                    if (abs(x_high - x) + 1 <= abs(x_low - x))
+                        index = high;
+                    else
+                        index = low;
 
 		if (after_wrap)
 			*after_wrap = ((index == line_index + line_def->net_length) &&
@@ -1496,6 +1546,16 @@
 		x -= es->format_rect.left;
 		if (!x)
 			return es->x_offset;
+
+		if (!es->x_offset)
+		{
+			INT indent = (es->format_rect.right - es->format_rect.left) - es->text_width;
+			if (es->style & ES_RIGHT)
+				x -= indent;
+			else if (es->style & ES_CENTER)
+				x -= indent / 2;
+		}
+
 		text = EDIT_GetPasswordPointer_SL(es);
 		dc = GetDC(es->hwndSelf);
 		if (es->font)
@@ -1509,10 +1569,18 @@
                         INT mid = (low + high) / 2;
                         GetTextExtentPoint32W( dc, text + mid,
                                                es->x_offset - mid, &size );
-                        if (size.cx > -x) low = mid;
-                        else high = mid;
+                        if (size.cx > -x) {
+                            low = mid;
+                            x_low = size.cx;
+                        } else {
+                            high = mid;
+                            x_high = size.cx;
+                        }
                     }
-                    index = low;
+                    if (abs(x_high + x) <= abs(x_low + x) + 1)
+                        index = high;
+                    else
+                        index = low;
 		}
                 else
                 {
@@ -1523,10 +1591,18 @@
                         INT mid = (low + high) / 2;
                         GetTextExtentPoint32W( dc, text + es->x_offset,
                                                mid - es->x_offset, &size );
-                        if (size.cx > x) high = mid;
-                        else low = mid;
+                        if (size.cx > x) {
+                               high = mid;
+                               x_high = size.cx;
+                        } else {
+                               low = mid;
+                               x_low = size.cx;
+                       }
                     }
-                    index = low;
+                   if (abs(x_high - x) <= abs(x_low - x) + 1)
+                       index = high;
+                   else
+                       index = low;
 		}
 		if (es->style & ES_PASSWORD)
 			HeapFree(GetProcessHeap(), 0, text);
@@ -1829,7 +1905,7 @@
 
 	if (es->buffer_size < size) {
 		WARN("FAILED !  We now have %d+1\n", es->buffer_size);
-		EDIT_NOTIFY_PARENT(es, EN_ERRSPACE, "EN_ERRSPACE");
+		EDIT_NOTIFY_PARENT(es, EN_ERRSPACE);
 		return FALSE;
 	} else {
 		TRACE("We now have %d+1\n", es->buffer_size);
@@ -2230,50 +2306,16 @@
 
 /*********************************************************************
  *
- *	EDIT_SetRectNP
+ *	EDIT_AdjustFormatRect
  *
- *	note:	this is not (exactly) the handler called on EM_SETRECTNP
- *		it is also used to set the rect of a single line control
+ *	Adjusts the format rectangle for the current font and the
+ *	current client rectangle.
  *
  */
-static void EDIT_SetRectNP(EDITSTATE *es, LPRECT rc)
+static void EDIT_AdjustFormatRect(EDITSTATE *es)
 {
 	RECT ClientRect;
-	LONG_PTR ExStyle;
-
-	CopyRect(&es->format_rect, rc);
-	if (es->style & ES_MULTILINE)
-	{
-		if (es->style & WS_BORDER) {
-			INT bw = GetSystemMetrics(SM_CXBORDER) + 1;
-			es->format_rect.left += bw;
-			es->format_rect.right -= bw;
-			es->format_rect.top += bw;
-			es->format_rect.bottom -= bw;
-		}
-	}
-	else
-	{
-		ExStyle = GetWindowLongPtrW(es->hwndSelf, GWL_EXSTYLE);
-		if (ExStyle & WS_EX_CLIENTEDGE) {
-			if (es->line_height + 2 <=
-			    es->format_rect.bottom - es->format_rect.top) {
-				es->format_rect.top++;
-				es->format_rect.bottom--;
-			}
-		} else if (es->style & WS_BORDER) {
-			INT bw = GetSystemMetrics(SM_CXBORDER) + 1;
-			es->format_rect.left += bw;
-			es->format_rect.right -= bw;
-			if (es->line_height + 2 * bw <=
-			    es->format_rect.bottom - es->format_rect.top) {
-				es->format_rect.top += bw;
-				es->format_rect.bottom -= bw;
-			}
-		}
-	}
-	es->format_rect.left += es->left_margin;
-	es->format_rect.right -= es->right_margin;
+	
 	es->format_rect.right = max(es->format_rect.right, es->format_rect.left + es->char_width);
 	if (es->style & ES_MULTILINE)
 	{
@@ -2308,11 +2350,59 @@
 
 	if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL))
 		EDIT_BuildLineDefs_ML(es, 0, strlenW(es->text), 0, NULL);
+	
+	EDIT_SetCaretPos(es, es->selection_end, es->flags & EF_AFTER_WRAP);
 }
 
 
 /*********************************************************************
  *
+ *	EDIT_SetRectNP
+ *
+ *	note:	this is not (exactly) the handler called on EM_SETRECTNP
+ *		it is also used to set the rect of a single line control
+ *
+ */
+static void EDIT_SetRectNP(EDITSTATE *es, LPRECT rc)
+{
+	LONG_PTR ExStyle;
+	INT bw, bh;
+	ExStyle = GetWindowLongPtrW(es->hwndSelf, GWL_EXSTYLE);
+	
+	CopyRect(&es->format_rect, rc);
+	
+	if (ExStyle & WS_EX_CLIENTEDGE) {
+		es->format_rect.left++;
+		es->format_rect.right--;
+		
+		if (es->format_rect.bottom - es->format_rect.top
+		    >= es->line_height + 2)
+		{
+			es->format_rect.top++;
+			es->format_rect.bottom--;
+		}
+	}
+	else if (es->style & WS_BORDER) {
+		bw = GetSystemMetrics(SM_CXBORDER) + 1;
+		bh = GetSystemMetrics(SM_CYBORDER) + 1;
+		es->format_rect.left += bw;
+		es->format_rect.right -= bw;
+		if (es->format_rect.bottom - es->format_rect.top
+		  >= es->line_height + 2 * bh)
+		{
+		    es->format_rect.top += bh;
+		    es->format_rect.bottom -= bh;
+		}
+	}
+	
+	es->format_rect.left += es->left_margin;
+	es->format_rect.right -= es->right_margin;
+	EDIT_AdjustFormatRect(es);
+}
+
+
+/*********************************************************************
+ *
  *	EDIT_UnlockBuffer
  *
  */
@@ -2686,7 +2776,7 @@
  *	EM_GETLINE
  *
  */
-static INT EDIT_EM_GetLine(EDITSTATE *es, INT line, LPARAM lParam, BOOL unicode)
+static INT EDIT_EM_GetLine(EDITSTATE *es, INT line, LPWSTR dst, BOOL unicode)
 {
 	LPWSTR src;
 	INT line_len, dst_len;
@@ -2700,10 +2790,9 @@
 	i = EDIT_EM_LineIndex(es, line);
 	src = es->text + i;
 	line_len = EDIT_EM_LineLength(es, i);
-	dst_len = *(WORD *)lParam;
+	dst_len = *(WORD *)dst;
 	if(unicode)
 	{
-	    LPWSTR dst = (LPWSTR)lParam;
 	    if(dst_len <= line_len)
 	    {
 		memcpy(dst, src, dst_len * sizeof(WCHAR));
@@ -2718,13 +2807,11 @@
 	}
 	else
 	{
-	    LPSTR dst = (LPSTR)lParam;
-	    INT ret;
-	    ret = WideCharToMultiByte(CP_ACP, 0, src, line_len, dst, dst_len, NULL, NULL);
-	    if(!ret) /* Insufficient buffer size */
+	    INT ret = WideCharToMultiByte(CP_ACP, 0, src, line_len, (LPSTR)dst, dst_len, NULL, NULL);
+	    if(!ret && line_len) /* Insufficient buffer size */
 		return dst_len;
 	    if(ret < dst_len) /* Append 0 if enough space */
-		dst[ret] = 0;
+		((LPSTR)dst)[ret] = 0;
 	    return ret;
 	}
 }
@@ -2939,9 +3026,9 @@
 		EDIT_UpdateScrollInfo(es);
 	}
 	if (dx && !(es->flags & EF_HSCROLL_TRACK))
-		EDIT_NOTIFY_PARENT(es, EN_HSCROLL, "EN_HSCROLL");
+		EDIT_NOTIFY_PARENT(es, EN_HSCROLL);
 	if (dy && !(es->flags & EF_VSCROLL_TRACK))
-		EDIT_NOTIFY_PARENT(es, EN_VSCROLL, "EN_VSCROLL");
+		EDIT_NOTIFY_PARENT(es, EN_VSCROLL);
 	return TRUE;
 }
 
@@ -2958,9 +3045,13 @@
 	INT li;
 	INT x;
 	INT y = 0;
+	INT w;
+	INT lw = 0;
+	INT ll = 0;
 	HDC dc;
 	HFONT old_font = 0;
 	SIZE size;
+	LINEDEF *line_def;
 
 	index = min(index, len);
 	dc = GetDC(es->hwndSelf);
@@ -2972,7 +3063,7 @@
 		li = EDIT_EM_LineIndex(es, l);
 		if (after_wrap && (li == index) && l) {
 			INT l2 = l - 1;
-			LINEDEF *line_def = es->first_line_def;
+			line_def = es->first_line_def;
 			while (l2) {
 				line_def = line_def->next;
 				l2--;
@@ -2983,8 +3074,32 @@
 				li = EDIT_EM_LineIndex(es, l);
 			}
 		}
-		x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li,
+
+		line_def = es->first_line_def;
+		while (line_def->index != li)
+			line_def = line_def->next;
+
+		ll = line_def->net_length;
+		lw = line_def->width;
+
+		w = es->format_rect.right - es->format_rect.left;
+		if (es->style & ES_RIGHT)
+		{
+			x = LOWORD(GetTabbedTextExtentW(dc, es->text + li + (index - li), ll - (index - li),
 				es->tabs_count, es->tabs)) - es->x_offset;
+			x = w - x;
+		}
+		else if (es->style & ES_CENTER)
+		{
+			x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li,
+				es->tabs_count, es->tabs)) - es->x_offset;
+			x += (w - lw) / 2;
+		}
+		else /* ES_LEFT */
+		{
+		    x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li,
+				es->tabs_count, es->tabs)) - es->x_offset;
+		}
 	} else {
 		LPWSTR text = EDIT_GetPasswordPointer_SL(es);
 		if (index < es->x_offset) {
@@ -2995,6 +3110,18 @@
 			GetTextExtentPoint32W(dc, text + es->x_offset,
 					index - es->x_offset, &size);
 			 x = size.cx;
+
+			if (!es->x_offset && (es->style & (ES_RIGHT | ES_CENTER)))
+			{
+				w = es->format_rect.right - es->format_rect.left;
+				if (w > es->text_width)
+				{
+					if (es->style & ES_RIGHT)
+						x += w - es->text_width;
+					else if (es->style & ES_CENTER)
+						x += (w - es->text_width) / 2;
+				}
+			}
 		}
 		y = 0;
 		if (es->style & ES_PASSWORD)
@@ -3027,6 +3154,8 @@
 	UINT size;
 	LPWSTR p;
 	HRGN hrgn = 0;
+	LPWSTR buf = NULL;
+	UINT bufl = 0;
 
 	TRACE("%s, can_undo %d, send_update %d\n",
 	    debugstr_w(lpsz_replace), can_undo, send_update);
@@ -3039,11 +3168,14 @@
 
 	ORDER_UINT(s, e);
 
+	size = tl - (e - s) + strl;
+	if (!size)
+		es->text_width = 0;
+
 	/* Issue the EN_MAXTEXT notification and continue with replacing text
 	 * such that buffer limit is honored. */
-	size = tl - (e - s) + strl;
 	if ((honor_limit) && (es->buffer_limit > 0) && (size > es->buffer_limit)) {
-		EDIT_NOTIFY_PARENT(es, EN_MAXTEXT, "EN_MAXTEXT");
+		EDIT_NOTIFY_PARENT(es, EN_MAXTEXT);
 		strl = es->buffer_limit - (tl - (e-s));
 	}
 
@@ -3053,12 +3185,71 @@
 	if (e != s) {
 		/* there is something to be deleted */
 		TRACE("deleting stuff.\n");
+		bufl = e - s;
+		buf = HeapAlloc(GetProcessHeap(), 0, (bufl + 1) * sizeof(WCHAR));
+		if (!buf) return;
+		memcpy(buf, es->text + s, bufl * sizeof(WCHAR));
+		buf[bufl] = 0; /* ensure 0 termination */
+		/* now delete */
+		strcpyW(es->text + s, es->text + e);
+	}
+	if (strl) {
+		/* there is an insertion */
+		tl = strlenW(es->text);
+		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));
+		for (p = es->text + tl ; p >= es->text + s ; p--)
+			p[strl] = p[0];
+		for (i = 0 , p = es->text + s ; i < strl ; i++)
+			p[i] = lpsz_replace[i];
+		if(es->style & ES_UPPERCASE)
+			CharUpperBuffW(p, strl);
+		else if(es->style & ES_LOWERCASE)
+			CharLowerBuffW(p, strl);
+	}
+	if (es->style & ES_MULTILINE)
+	{
+		INT st = min(es->selection_start, es->selection_end);
+		INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+
+		hrgn = CreateRectRgn(0, 0, 0, 0);
+		EDIT_BuildLineDefs_ML(es, st, st + strl,
+				strl - abs(es->selection_end - es->selection_start), hrgn);
+		/* if text is too long undo all changes */
+		if (honor_limit && !(es->style & ES_AUTOVSCROLL) && (es->line_count > vlc)) {
+			if (strl)
+				strcpyW(es->text + e, es->text + e + strl);
+			if (e != s)
+				for (i = 0 , p = es->text ; i < e - s ; i++)
+					p[i + s] = buf[i];
+			EDIT_BuildLineDefs_ML(es, s, e, 
+				abs(es->selection_end - es->selection_start) - strl, hrgn);
+			strl = 0;
+			e = s;
+			hrgn = CreateRectRgn(0, 0, 0, 0);
+			EDIT_NOTIFY_PARENT(es, EN_MAXTEXT);
+		}
+	}
+	else {
+		INT fw = es->format_rect.right - es->format_rect.left;
+		EDIT_CalcLineWidth_SL(es);
+		/* remove chars that don't fit */
+		if (honor_limit && !(es->style & ES_AUTOHSCROLL) && (es->text_width > fw)) {
+			while ((es->text_width > fw) && s + strl >= s) {
+				strcpyW(es->text + s + strl - 1, es->text + s + strl);
+				strl--;
+				EDIT_CalcLineWidth_SL(es);
+			}
+			EDIT_NOTIFY_PARENT(es, EN_MAXTEXT);
+		}
+	}
+	
+	if (e != s) {
 		if (can_undo) {
 			utl = strlenW(es->undo_text);
 			if (!es->undo_insert_count && (*es->undo_text && (s == es->undo_position))) {
 				/* undo-buffer is extended to the right */
 				EDIT_MakeUndoFit(es, utl + e - s);
-				strncpyW(es->undo_text + utl, es->text + s, e - s + 1);
+				memcpy(es->undo_text + utl, buf, (e - s)*sizeof(WCHAR));
 				(es->undo_text + utl)[e - s] = 0; /* ensure 0 termination */
 			} else if (!es->undo_insert_count && (*es->undo_text && (e == es->undo_position))) {
 				/* undo-buffer is extended to the left */
@@ -3066,12 +3257,12 @@
 				for (p = es->undo_text + utl ; p >= es->undo_text ; p--)
 					p[e - s] = p[0];
 				for (i = 0 , p = es->undo_text ; i < e - s ; i++)
-					p[i] = (es->text + s)[i];
+					p[i] = buf[i];
 				es->undo_position = s;
 			} else {
 				/* new undo-buffer */
 				EDIT_MakeUndoFit(es, e - s);
-				strncpyW(es->undo_text, es->text + s, e - s + 1);
+				memcpy(es->undo_text, buf, (e - s)*sizeof(WCHAR));
 				es->undo_text[e - s] = 0; /* ensure 0 termination */
 				es->undo_position = s;
 			}
@@ -3079,16 +3270,12 @@
 			es->undo_insert_count = 0;
 		} else
 			EDIT_EM_EmptyUndoBuffer(es);
-
-		/* now delete */
-		strcpyW(es->text + s, es->text + e);
 	}
 	if (strl) {
-		/* there is an insertion */
 		if (can_undo) {
 			if ((s == es->undo_position) ||
-					((es->undo_insert_count) &&
-					(s == es->undo_position + es->undo_insert_count)))
+				((es->undo_insert_count) &&
+				(s == es->undo_position + es->undo_insert_count)))
 				/*
 				 * insertion is new and at delete position or
 				 * an extension to either left or right
@@ -3103,30 +3290,26 @@
 			}
 		} else
 			EDIT_EM_EmptyUndoBuffer(es);
+	}
 
-		/* now insert */
-		tl = strlenW(es->text);
-		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));
-		for (p = es->text + tl ; p >= es->text + s ; p--)
-			p[strl] = p[0];
-		for (i = 0 , p = es->text + s ; i < strl ; i++)
-			p[i] = lpsz_replace[i];
-		if(es->style & ES_UPPERCASE)
-			CharUpperBuffW(p, strl);
-		else if(es->style & ES_LOWERCASE)
-			CharLowerBuffW(p, strl);
-		s += strl;
-	}
-	if (es->style & ES_MULTILINE)
+	if (bufl)
+		HeapFree(GetProcessHeap(), 0, buf);
+ 
+	s += strl;
+
+	/* If text has been deleted and we're right or center aligned then scroll rightward */
+	if (es->style & (ES_RIGHT | ES_CENTER))
 	{
-		INT s = min(es->selection_start, es->selection_end);
+		INT delta = strl - abs(es->selection_end - es->selection_start);
 
-		hrgn = CreateRectRgn(0, 0, 0, 0);
-		EDIT_BuildLineDefs_ML(es, s, s + strl,
-				strl - abs(es->selection_end - es->selection_start), hrgn);
+		if (delta < 0 && es->x_offset)
+		{
+			if (abs(delta) > es->x_offset)
+				es->x_offset = 0;
+			else
+				es->x_offset += delta;
+		}
 	}
-	else
-	    EDIT_CalcLineWidth_SL(es);
 
 	EDIT_EM_SetSel(es, s, s, FALSE);
 	es->flags |= EF_MODIFIED;
@@ -3145,10 +3328,10 @@
 	EDIT_UpdateScrollInfo(es);
 
 
-	if(es->flags & EF_UPDATE)
+        if(send_update || (es->flags & EF_UPDATE))
 	{
 	    es->flags &= ~EF_UPDATE;
-	    EDIT_NOTIFY_PARENT(es, EN_CHANGE, "EN_CHANGE");
+	    EDIT_NOTIFY_PARENT(es, EN_CHANGE);
 	}
 }
 
@@ -3235,12 +3418,12 @@
 			dx = x - es->format_rect.left - ww / HSCROLL_FRACTION / cw * cw;
 		if (x > es->format_rect.right)
 			dx = x - es->format_rect.left - (HSCROLL_FRACTION - 1) * ww / HSCROLL_FRACTION / cw * cw;
-		if (dy || dx)
+		if (dy || dx || (es->y_offset && (es->line_count - es->y_offset < vlc)))
 		{
 		    /* check if we are going to move too far */
 		    if(es->x_offset + dx + ww > es->text_width)
 			dx = es->text_width - ww - es->x_offset;
-		    if(dx || dy)
+		    if(dx || dy || (es->y_offset && (es->line_count - es->y_offset < vlc)))
 			EDIT_EM_LineScroll_internal(es, dx, dy);
 		}
 	} else {
@@ -3248,9 +3431,6 @@
 		INT goal;
 		INT format_width;
 
-		if (!(es->style & ES_AUTOHSCROLL))
-			return;
-
 		x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, FALSE));
 		format_width = es->format_rect.right - es->format_rect.left;
 		if (x < es->format_rect.left) {
@@ -3475,7 +3655,7 @@
  *
  */
 static void EDIT_EM_SetMargins(EDITSTATE *es, INT action,
-			       INT left, INT right)
+			       INT left, INT right, BOOL repaint)
 {
 	TEXTMETRICW tm;
 	INT default_left_margin  = 0; /* in pixels */
@@ -3497,18 +3677,28 @@
         }
 
 	if (action & EC_LEFTMARGIN) {
+		es->format_rect.left -= es->left_margin;
 		if (left != EC_USEFONTINFO)
 			es->left_margin = left;
 		else
 			es->left_margin = default_left_margin;
+		es->format_rect.left += es->left_margin;
 	}
 
 	if (action & EC_RIGHTMARGIN) {
+		es->format_rect.right += es->right_margin;
 		if (right != EC_USEFONTINFO)
  			es->right_margin = right;
 		else
 			es->right_margin = default_right_margin;
+		es->format_rect.right -= es->right_margin;
 	}
+	
+	if (action & (EC_LEFTMARGIN | EC_RIGHTMARGIN)) {
+		EDIT_AdjustFormatRect(es);
+		if (repaint) EDIT_UpdateText(es, NULL, TRUE);
+	}
+
 	TRACE("left=%d, right=%d\n", es->left_margin, es->right_margin);
 }
 
@@ -3569,11 +3759,23 @@
 		es->flags |= EF_AFTER_WRAP;
 	else
 		es->flags &= ~EF_AFTER_WRAP;
-/* This is a little bit more efficient than before, not sure if it can be improved. FIXME? */
-        ORDER_UINT(start, end);
+	/* Compute the necessary invalidation region. */
+	/* Note that we don't need to invalidate regions which have
+	 * "never" been selected, or those which are "still" selected.
+	 * In fact, every time we hit a selection boundary, we can
+	 * *toggle* whether we need to invalidate.  Thus we can optimize by
+	 * *sorting* the interval endpoints.  Let's assume that we sort them
+	 * in this order:
+	 *        start <= end <= old_start <= old_end
+	 * Knuth 5.3.1 (p 183) asssures us that this can be done optimally
+	 * in 5 comparisons; ie it's impossible to do better than the
+	 * following: */
         ORDER_UINT(end, old_end);
         ORDER_UINT(start, old_start);
         ORDER_UINT(old_start, old_end);
+        ORDER_UINT(start, end);
+	/* Note that at this point 'end' and 'old_start' are not in order, but
+	 * start is definitely the min. and old_end is definitely the max. */
 	if (end != old_start)
         {
 /*
@@ -3582,6 +3784,7 @@
  *          EDIT_InvalidateText(es, start, end);
  *          EDIT_InvalidateText(es, old_start, old_end);
  * in place of the following if statement.
+ * (That would complete the optimal five-comparison four-element sort.)
  */
             if (old_start > end )
             {
@@ -3607,8 +3810,7 @@
 {
 	if (!(es->style & ES_MULTILINE))
 		return FALSE;
-	if (es->tabs)
-		HeapFree(GetProcessHeap(), 0, es->tabs);
+	HeapFree(GetProcessHeap(), 0, es->tabs);
 	es->tabs_count = count;
 	if (!count)
 		es->tabs = NULL;
@@ -3651,12 +3853,12 @@
  *	EM_SETWORDBREAKPROC
  *
  */
-static void EDIT_EM_SetWordBreakProc(EDITSTATE *es, LPARAM lParam)
+static void EDIT_EM_SetWordBreakProc(EDITSTATE *es, void *wbp)
 {
-	if (es->word_break_proc == (void *)lParam)
+	if (es->word_break_proc == wbp)
 		return;
 
-	es->word_break_proc = (void *)lParam;
+	es->word_break_proc = wbp;
 #ifndef __REACTOS__
 	es->word_break_proc16 = NULL;
 #endif
@@ -3718,7 +3920,7 @@
 	EDIT_EM_ReplaceSel(es, TRUE, utext, TRUE, TRUE);
 	EDIT_EM_SetSel(es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
         /* send the notification after the selection start and end are set */
-        EDIT_NOTIFY_PARENT(es, EN_CHANGE, "EN_CHANGE");
+        EDIT_NOTIFY_PARENT(es, EN_CHANGE);
 	EDIT_EM_ScrollCaret(es);
 	HeapFree(GetProcessHeap(), 0, utext);
 
@@ -3897,13 +4099,15 @@
 	INT e = max(es->selection_start, es->selection_end);
 	HGLOBAL hdst;
 	LPWSTR dst;
+	DWORD len;
 
 	if (e == s) return;
 
-	hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (DWORD)(e - s + 1) * sizeof(WCHAR));
+	len = e - s;
+	hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (len + 1) * sizeof(WCHAR));
 	dst = GlobalLock(hdst);
-	strncpyW(dst, es->text + s, e - s);
-	dst[e - s] = 0; /* ensure 0 termination */
[truncated at 1000 lines; 468 more skipped]