Apologies I sent this to the wrong list just now.

Ok, Thanks to Dan I have found and corrected the issues that this created with the tests. I believe all the tests should continue to pass with this version of the patch.

Has anyone tried it live in any applications?

-aric

---
dlls/user32/edit.c | 252 +++++++++++++++++++++++++++++-----------------------
 1 files changed, 142 insertions(+), 110 deletions(-)


diff --git a/dlls/user32/edit.c b/dlls/user32/edit.c
index e02a268..78c89fe 100644
--- a/dlls/user32/edit.c
+++ b/dlls/user32/edit.c
@@ -158,6 +158,7 @@ typedef struct
 	 * Uniscribe Data
 	 */
 	SCRIPT_LOGATTR *logAttr;
+	SCRIPT_STRING_ANALYSIS ssa; /* Uniscribe Data for single line controls */
 } EDITSTATE;
 
 
@@ -365,6 +366,48 @@ static INT EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count
 	return ret;
 }
 
+static inline void EDIT_InvalidateUniscribeData(EDITSTATE *es)
+{
+	if (es->ssa)
+	{
+		ScriptStringFree(&es->ssa);
+		es->ssa = NULL;
+	}
+}
+
+static SCRIPT_STRING_ANALYSIS EDIT_UpdateUniscribeData(EDITSTATE *es, HDC dc, INT line)
+{
+	if (!(es->style & ES_MULTILINE))
+	{
+		if (!es->ssa)
+		{
+			INT length = get_text_length(es);
+			HFONT old_font = NULL;
+			HDC udc = dc;
+
+			if (!udc)
+				udc = GetDC(es->hwndSelf);
+			if (es->font)
+				old_font = SelectObject(udc, es->font);
+
+			if (es->style & ES_PASSWORD)
+				ScriptStringAnalyse(udc, &es->password_char, length, (1.5*length+16), -1, SSA_LINK|SSA_FALLBACK|SSA_GLYPHS|SSA_PASSWORD, -1, NULL, NULL, NULL, NULL, NULL, &es->ssa);
+			else
+				ScriptStringAnalyse(udc, es->text, length, (1.5*length+16), -1, SSA_LINK|SSA_FALLBACK|SSA_GLYPHS, -1, NULL, NULL, NULL, NULL, NULL, &es->ssa);
+
+			if (es->font)
+				SelectObject(udc, old_font);
+			if (udc != dc)
+				ReleaseDC(es->hwndSelf, udc);
+		}
+		return es->ssa;
+	}
+	else
+	{
+		return NULL;
+	}
+}
+
 /*********************************************************************
  *
  *	EDIT_BuildLineDefs_ML
@@ -647,52 +690,19 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta
 
 /*********************************************************************
  *
- *	EDIT_GetPasswordPointer_SL
- *
- *	note: caller should free the (optionally) allocated buffer
- *
- */
-static LPWSTR EDIT_GetPasswordPointer_SL(EDITSTATE *es)
-{
-	if (es->style & ES_PASSWORD) {
-		INT len = get_text_length(es);
-		LPWSTR text = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
-		text[len] = '\0';
-		while(len) text[--len] = es->password_char;
-		return text;
-	} else
-		return es->text;
-}
-
-
-/*********************************************************************
- *
  *	EDIT_CalcLineWidth_SL
  *
  */
 static void EDIT_CalcLineWidth_SL(EDITSTATE *es)
 {
-	SIZE size;
-	LPWSTR text;
-	HDC dc;
-	HFONT old_font = 0;
-
-	text = EDIT_GetPasswordPointer_SL(es);
+	const SIZE *size;
 
-	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;
+	EDIT_UpdateUniscribeData(es, NULL, 0);
+	size = ScriptString_pSize(es->ssa);
+	if (size)
+		es->text_width = size->cx;
+	else
+		es->text_width = 0;
 }
 
 /*********************************************************************
@@ -708,11 +718,11 @@ static void EDIT_CalcLineWidth_SL(EDITSTATE *es)
 static INT EDIT_CharFromPos(EDITSTATE *es, INT x, INT y, LPBOOL after_wrap)
 {
 	INT index;
-	HDC dc;
-	HFONT old_font = 0;
 	INT x_high = 0, x_low = 0;
 
 	if (es->style & ES_MULTILINE) {
+		HDC dc;
+		HFONT old_font = 0;
 		INT line = (y - es->format_rect.top) / es->line_height + es->y_offset;
 		INT line_index = 0;
 		LINEDEF *line_def = es->first_line_def;
@@ -762,9 +772,12 @@ static INT EDIT_CharFromPos(EDITSTATE *es, INT x, INT y, LPBOOL after_wrap)
 		if (after_wrap)
 			*after_wrap = ((index == line_index + line_def->net_length) &&
 							(line_def->ending == END_WRAP));
+		if (es->font)
+			SelectObject(dc, old_font);
+		ReleaseDC(es->hwndSelf, dc);
 	} else {
-		LPWSTR text;
-		SIZE size;
+		INT xoff = 0;
+		INT trailing;
 		if (after_wrap)
 			*after_wrap = FALSE;
 		x -= es->format_rect.left;
@@ -780,60 +793,47 @@ static INT EDIT_CharFromPos(EDITSTATE *es, INT x, INT y, LPBOOL after_wrap)
 				x -= indent / 2;
 		}
 
-		text = EDIT_GetPasswordPointer_SL(es);
-		dc = GetDC(es->hwndSelf);
-		if (es->font)
-			old_font = SelectObject(dc, es->font);
+		EDIT_UpdateUniscribeData(es, NULL, 0);
+		if (es->x_offset)
+		{
+			if (es->x_offset>= get_text_length(es))
+			{
+				const SIZE *size;
+				size = ScriptString_pSize(es->ssa);
+				xoff = size->cx;
+			}
+			ScriptStringCPtoX(es->ssa, es->x_offset, FALSE, &xoff);
+		}
 		if (x < 0)
-                {
-                    INT low = 0;
-                    INT high = es->x_offset;
-                    while (low < high - 1)
-                    {
-                        INT mid = (low + high) / 2;
-                        GetTextExtentPoint32W( dc, text + mid,
-                                               es->x_offset - mid, &size );
-                        if (size.cx > -x) {
-                            low = mid;
-                            x_low = size.cx;
-                        } else {
-                            high = mid;
-                            x_high = size.cx;
-                        }
-                    }
-                    if (abs(x_high + x) <= abs(x_low + x) + 1)
-                        index = high;
-                    else
-                        index = low;
+		{
+			if (x + xoff > 0)
+			{
+				ScriptStringXtoCP(es->ssa, x+xoff, &index, &trailing);
+				if (trailing) index++;
+			}
+			else
+				index = 0;
 		}
-                else
-                {
-                    INT low = es->x_offset;
-                    INT high = get_text_length(es) + 1;
-                    while (low < high - 1)
-                    {
-                        INT mid = (low + high) / 2;
-                        GetTextExtentPoint32W( dc, text + es->x_offset,
-                                               mid - es->x_offset, &size );
-                        if (size.cx > x) {
-                               high = mid;
-                               x_high = size.cx;
-                        } else {
-                               low = mid;
-                               x_low = size.cx;
-                       }
-                    }
-                   if (abs(x_high - x) <= abs(x_low - x) + 1)
-                       index = high;
-                   else
-                       index = low;
+		else
+		{
+			if (x)
+			{
+				const SIZE *size;
+				size = ScriptString_pSize(es->ssa);
+				if (!size)
+					index = 0;
+				else if (x > size->cx)
+					index = get_text_length(es);
+				else
+				{
+					ScriptStringXtoCP(es->ssa, x+xoff, &index, &trailing);
+					if (trailing) index++;
+				}
+			}
+			else
+				index = es->x_offset;
 		}
-		if (es->style & ES_PASSWORD)
-			HeapFree(GetProcessHeap(), 0, text);
 	}
-	if (es->font)
-		SelectObject(dc, old_font);
-	ReleaseDC(es->hwndSelf, dc);
 	return index;
 }
 
@@ -970,7 +970,6 @@ static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap)
 	INT ll = 0;
 	HDC dc;
 	HFONT old_font = 0;
-	SIZE size;
 	LINEDEF *line_def;
 
 	index = min(index, len);
@@ -1021,16 +1020,33 @@ static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap)
 				es->tabs_count, es->tabs)) - es->x_offset;
 		}
 	} else {
-		LPWSTR text = EDIT_GetPasswordPointer_SL(es);
-		if (index < es->x_offset) {
-			GetTextExtentPoint32W(dc, text + index,
-					es->x_offset - index, &size);
-			x = -size.cx;
-		} else {
-			GetTextExtentPoint32W(dc, text + es->x_offset,
-					index - es->x_offset, &size);
-			 x = size.cx;
+		INT xoff = 0;
+		INT xi = 0;
+		EDIT_UpdateUniscribeData(es, NULL, 0);
+		if (es->x_offset)
+		{
+			if (es->x_offset>= get_text_length(es))
+			{
+				const SIZE *size;
+				size = ScriptString_pSize(es->ssa);
+				xoff = size->cx;
+			}
+			ScriptStringCPtoX(es->ssa, es->x_offset, FALSE, &xoff);
+		}
+		if (index)
+		{
+			if (index >= get_text_length(es))
+			{
+				const SIZE *size;
+				size = ScriptString_pSize(es->ssa);
+				xi = size->cx;
+			}
+			else
+				ScriptStringCPtoX(es->ssa, index, FALSE, &xi);
+		}
+		x = xi - xoff;
 
+		if (index >= es->x_offset) {
 			if (!es->x_offset && (es->style & (ES_RIGHT | ES_CENTER)))
 			{
 				w = es->format_rect.right - es->format_rect.left;
@@ -1044,8 +1060,6 @@ static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap)
 			}
 		}
 		y = 0;
-		if (es->style & ES_PASSWORD)
-			HeapFree(GetProcessHeap(), 0, text);
 	}
 	x += es->format_rect.left;
 	y += es->format_rect.top;
@@ -1067,14 +1081,17 @@ static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap)
 static void EDIT_GetLineRect(EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc)
 {
 	INT line_index =  EDIT_EM_LineIndex(es, line);
+	INT pt1, pt2;
 
 	if (es->style & ES_MULTILINE)
 		rc->top = es->format_rect.top + (line - es->y_offset) * es->line_height;
 	else
 		rc->top = es->format_rect.top;
 	rc->bottom = rc->top + es->line_height;
-	rc->left = (scol == 0) ? es->format_rect.left : (short)LOWORD(EDIT_EM_PosFromChar(es, line_index + scol, TRUE));
-	rc->right = (ecol == -1) ? es->format_rect.right : (short)LOWORD(EDIT_EM_PosFromChar(es, line_index + ecol, TRUE));
+	pt1 = (scol == 0) ? es->format_rect.left : (short)LOWORD(EDIT_EM_PosFromChar(es, line_index + scol, TRUE));
+	pt2 = (ecol == -1) ? es->format_rect.right : (short)LOWORD(EDIT_EM_PosFromChar(es, line_index + ecol, TRUE));
+	rc->right = max(pt1 , pt2);
+	rc->left = min(pt1, pt2);
 }
 
 
@@ -1084,6 +1101,7 @@ static inline void text_buffer_changed(EDITSTATE *es)
 
     HeapFree( GetProcessHeap(), 0, es->logAttr );
     es->logAttr = NULL;
+    EDIT_InvalidateUniscribeData(es);
 }
 
 /*********************************************************************
@@ -2028,7 +2046,7 @@ static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col
 		ret = (INT)LOWORD(TabbedTextOutW(dc, x, y, es->text + li + col, count,
 					es->tabs_count, es->tabs, es->format_rect.left - es->x_offset));
 	} else {
-		LPWSTR text = EDIT_GetPasswordPointer_SL(es);
+		LPWSTR text = es->text;
 		TextOutW(dc, x, y, text + li + col, count);
 		GetTextExtentPoint32W(dc, text + li + col, count, &size);
 		ret = size.cx;
@@ -2068,6 +2086,7 @@ static void EDIT_PaintLine(EDITSTATE *es, HDC dc, INT line, BOOL rev)
 	INT x;
 	INT y;
 	LRESULT pos;
+	SCRIPT_STRING_ANALYSIS ssa;
 
 	if (es->style & ES_MULTILINE) {
 		INT vlc = get_vertical_line_count(es);
@@ -2079,6 +2098,7 @@ static void EDIT_PaintLine(EDITSTATE *es, HDC dc, INT line, BOOL rev)
 
 	TRACE("line=%d\n", line);
 
+	ssa = EDIT_UpdateUniscribeData(es, dc, line);
 	pos = EDIT_EM_PosFromChar(es, EDIT_EM_LineIndex(es, line), FALSE);
 	x = (short)LOWORD(pos);
 	y = (short)HIWORD(pos);
@@ -2088,7 +2108,9 @@ static void EDIT_PaintLine(EDITSTATE *es, HDC dc, INT line, BOOL rev)
 	e = max(es->selection_start, es->selection_end);
 	s = min(li + ll, max(li, s));
 	e = min(li + ll, max(li, e));
-	if (rev && (s != e) &&
+	if (ssa)
+		ScriptStringOut(ssa, x, y, 0, &es->format_rect, s - li, e - li, FALSE);
+	else if (rev && (s != e) &&
 			((es->flags & EF_FOCUSED) || (es->style & ES_NOHIDESEL))) {
 		x += EDIT_PaintText(es, dc, x, y, line, 0, s - li, FALSE);
 		x += EDIT_PaintText(es, dc, x, y, line, s - li, e - s, TRUE);
@@ -2384,6 +2406,7 @@ static void EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replac
 	s = es->selection_start;
 	e = es->selection_end;
 
+	EDIT_InvalidateUniscribeData(es);
 	if ((s == e) && !strl)
 		return;
 
@@ -2459,12 +2482,14 @@ static void EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replac
 	}
 	else {
 		INT fw = es->format_rect.right - es->format_rect.left;
+		EDIT_InvalidateUniscribeData(es);
 		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_InvalidateUniscribeData(es);
 				EDIT_CalcLineWidth_SL(es);
 			}
                         text_buffer_changed(es);
@@ -2562,6 +2587,7 @@ static void EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replac
 	    es->flags &= ~EF_UPDATE;
 	    EDIT_NOTIFY_PARENT(es, EN_CHANGE);
 	}
+	EDIT_InvalidateUniscribeData(es);
 }
 
 
@@ -2762,6 +2788,7 @@ static void EDIT_EM_SetPasswordChar(EDITSTATE *es, WCHAR c)
             SetWindowLongW( es->hwndSelf, GWL_STYLE, style & ~ES_PASSWORD );
             es->style &= ~ES_PASSWORD;
 	}
+	EDIT_InvalidateUniscribeData(es);
 	EDIT_UpdateText(es, NULL, TRUE);
 }
 
@@ -3490,6 +3517,8 @@ static void EDIT_WM_Paint(EDITSTATE *es, HDC hdc)
 					(es->style & ES_NOHIDESEL));
         dc = hdc ? hdc : BeginPaint(es->hwndSelf, &ps);
 
+	if (hdc) /* Not using our window DC */
+		EDIT_InvalidateUniscribeData(es);
 	GetClientRect(es->hwndSelf, &rcClient);
 
 	/* get the background brush */
@@ -3602,6 +3631,7 @@ static void EDIT_WM_SetFont(EDITSTATE *es, HFONT font, BOOL redraw)
 	RECT clientRect;
 
 	es->font = font;
+	EDIT_InvalidateUniscribeData(es);
 	dc = GetDC(es->hwndSelf);
 	if (font)
 		old_font = SelectObject(dc, font);
@@ -3693,6 +3723,7 @@ static void EDIT_WM_SetText(EDITSTATE *es, LPCWSTR text, BOOL unicode)
     }
     EDIT_EM_ScrollCaret(es);
     EDIT_UpdateScrollInfo(es);    
+    EDIT_InvalidateUniscribeData(es);
 }
 
 
@@ -4313,6 +4344,7 @@ static LRESULT EDIT_WM_NCCreate(HWND hwnd, LPCREATESTRUCTW lpcs, BOOL unicode)
 
 cleanup:
 	SetWindowLongPtrW(es->hwndSelf, 0, 0);
+	EDIT_InvalidateUniscribeData(es);
 	HeapFree(GetProcessHeap(), 0, es->first_line_def);
 	HeapFree(GetProcessHeap(), 0, es->undo_text);
 	if (es->hloc32W) LocalFree(es->hloc32W);



Reply via email to