user32: Use Uniscribe in the multiline edit control.

This commit is contained in:
Aric Stewart 2011-10-21 11:29:05 -05:00 committed by Alexandre Julliard
parent d5090fd975
commit 3b5e14a9b0

View file

@ -98,6 +98,7 @@ typedef struct tagLINEDEF {
LINE_END ending; LINE_END ending;
INT width; /* width of the line in pixels */ INT width; /* width of the line in pixels */
INT index; /* line index into the buffer */ INT index; /* line index into the buffer */
SCRIPT_STRING_ANALYSIS ssa; /* Uniscribe Data */
struct tagLINEDEF *next; struct tagLINEDEF *next;
} LINEDEF; } LINEDEF;
@ -176,6 +177,7 @@ typedef struct
} while(0) } while(0)
static const WCHAR empty_stringW[] = {0}; static const WCHAR empty_stringW[] = {0};
static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap);
/********************************************************************* /*********************************************************************
* *
@ -366,8 +368,23 @@ static INT EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count
return ret; return ret;
} }
static inline void EDIT_InvalidateUniscribeData_linedef(LINEDEF *line_def)
{
if (line_def->ssa)
{
ScriptStringFree(&line_def->ssa);
line_def->ssa = NULL;
}
}
static inline void EDIT_InvalidateUniscribeData(EDITSTATE *es) static inline void EDIT_InvalidateUniscribeData(EDITSTATE *es)
{ {
LINEDEF *line_def = es->first_line_def;
while (line_def)
{
EDIT_InvalidateUniscribeData_linedef(line_def);
line_def = line_def->next;
}
if (es->ssa) if (es->ssa)
{ {
ScriptStringFree(&es->ssa); ScriptStringFree(&es->ssa);
@ -375,8 +392,43 @@ static inline void EDIT_InvalidateUniscribeData(EDITSTATE *es)
} }
} }
static SCRIPT_STRING_ANALYSIS EDIT_UpdateUniscribeData_linedef(EDITSTATE *es, HDC dc, LINEDEF *line_def)
{
if (!line_def)
return NULL;
if (line_def->net_length && !line_def->ssa)
{
int index = line_def->index;
HFONT old_font = NULL;
HDC udc = dc;
SCRIPT_TABDEF tabdef;
if (!udc)
udc = GetDC(es->hwndSelf);
if (es->font)
old_font = SelectObject(udc, es->font);
tabdef.cTabStops = es->tabs_count;
tabdef.iScale = 0;
tabdef.pTabStops = es->tabs;
tabdef.iTabOrigin = 0;
ScriptStringAnalyse(udc, &es->text[index], line_def->net_length, (1.5*line_def->net_length+16), -1, SSA_LINK|SSA_FALLBACK|SSA_GLYPHS|SSA_TAB, -1, NULL, NULL, NULL, &tabdef, NULL, &line_def->ssa);
if (es->font)
SelectObject(udc, old_font);
if (udc != dc)
ReleaseDC(es->hwndSelf, udc);
}
return line_def->ssa;
}
static SCRIPT_STRING_ANALYSIS EDIT_UpdateUniscribeData(EDITSTATE *es, HDC dc, INT line) static SCRIPT_STRING_ANALYSIS EDIT_UpdateUniscribeData(EDITSTATE *es, HDC dc, INT line)
{ {
LINEDEF *line_def;
if (!(es->style & ES_MULTILINE)) if (!(es->style & ES_MULTILINE))
{ {
if (!es->ssa) if (!es->ssa)
@ -404,7 +456,14 @@ static SCRIPT_STRING_ANALYSIS EDIT_UpdateUniscribeData(EDITSTATE *es, HDC dc, IN
} }
else else
{ {
return NULL; line_def = es->first_line_def;
while (line_def && line)
{
line_def = line_def->next;
line--;
}
return EDIT_UpdateUniscribeData_linedef(es,dc,line_def);
} }
} }
@ -419,8 +478,6 @@ static SCRIPT_STRING_ANALYSIS EDIT_UpdateUniscribeData(EDITSTATE *es, HDC dc, IN
*/ */
static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta, HRGN hrgn) static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta, HRGN hrgn)
{ {
HDC dc;
HFONT old_font = 0;
LPWSTR current_position, cp; LPWSTR current_position, cp;
INT fw; INT fw;
LINEDEF *current_line; LINEDEF *current_line;
@ -434,10 +491,6 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta
if (istart == iend && delta == 0) if (istart == iend && delta == 0)
return; return;
dc = GetDC(es->hwndSelf);
if (es->font)
old_font = SelectObject(dc, es->font);
previous_line = NULL; previous_line = NULL;
current_line = es->first_line_def; current_line = es->first_line_def;
@ -456,7 +509,6 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta
if (!current_line) /* Error occurred start is not inside previous buffer */ if (!current_line) /* Error occurred start is not inside previous buffer */
{ {
FIXME(" modification occurred outside buffer\n"); FIXME(" modification occurred outside buffer\n");
ReleaseDC(es->hwndSelf, dc);
return; return;
} }
@ -482,7 +534,7 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta
{ {
/* The buffer has been expanded, create a new line and /* The buffer has been expanded, create a new line and
insert it into the link list */ insert it into the link list */
LINEDEF *new_line = HeapAlloc(GetProcessHeap(), 0, sizeof(LINEDEF)); LINEDEF *new_line = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LINEDEF));
new_line->next = previous_line->next; new_line->next = previous_line->next;
previous_line->next = new_line; previous_line->next = new_line;
current_line = new_line; current_line = new_line;
@ -532,33 +584,63 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta
current_line->net_length = cp - current_position; current_line->net_length = cp - current_position;
} }
/* Calculate line width */ if (current_line->net_length)
current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, {
current_position, current_line->net_length, const SIZE *sz;
es->tabs_count, es->tabs)); EDIT_InvalidateUniscribeData_linedef(current_line);
EDIT_UpdateUniscribeData_linedef(es, NULL, current_line);
sz = ScriptString_pSize(current_line->ssa);
/* Calculate line width */
current_line->width = sz->cx;
}
else current_line->width = 0;
/* FIXME: check here for lines that are too wide even in AUTOHSCROLL (> 32767 ???) */ /* FIXME: check here for lines that are too wide even in AUTOHSCROLL (> 32767 ???) */
/* Line breaks just look back from the end and find the next break and try that. */
if (!(es->style & ES_AUTOHSCROLL)) { if (!(es->style & ES_AUTOHSCROLL)) {
if (current_line->width > fw) { if (current_line->width > fw) {
INT next = 0;
INT prev; INT prev;
int w;
const SIZE *sz;
prev = current_line->net_length - 1;
w = current_line->net_length;
do { do {
prev = next; prev = EDIT_CallWordBreakProc(es, current_position - es->text,
next = EDIT_CallWordBreakProc(es, current_position - es->text, prev-1, current_line->net_length, WB_LEFT);
prev + 1, current_line->net_length, WB_RIGHT); current_line->net_length = prev;
current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, EDIT_InvalidateUniscribeData_linedef(current_line);
current_position, next, es->tabs_count, es->tabs)); EDIT_UpdateUniscribeData_linedef(es, NULL, current_line);
} while (current_line->width <= fw); sz = ScriptString_pSize(current_line->ssa);
if (!prev) { /* Didn't find a line break so force a break */ if (sz)
next = 0; current_line->width = sz->cx;
else
prev = 0;
} while (prev && current_line->width > fw);
current_line->net_length = w;
if (prev == 0) { /* Didn't find a line break so force a break */
INT *piDx;
const INT *count;
EDIT_InvalidateUniscribeData_linedef(current_line);
EDIT_UpdateUniscribeData_linedef(es, NULL, current_line);
count = ScriptString_pcOutChars(current_line->ssa);
piDx = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * (*count));
ScriptStringGetLogicalWidths(current_line->ssa,piDx);
prev = current_line->net_length-1;
do { do {
prev = next; current_line->width -= piDx[prev];
next++; prev--;
current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, } while ( prev > 0 && current_line->width > fw);
current_position, next, es->tabs_count, es->tabs)); if (prev==0)
} while (current_line->width <= fw);
if (!prev)
prev = 1; prev = 1;
HeapFree(GetProcessHeap(),0,piDx);
} }
/* If the first line we are calculating, wrapped before istart, we must /* If the first line we are calculating, wrapped before istart, we must
@ -579,8 +661,14 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta
current_line->net_length = prev; current_line->net_length = prev;
current_line->ending = END_WRAP; current_line->ending = END_WRAP;
current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, current_position,
current_line->net_length, es->tabs_count, es->tabs)); if (current_line->net_length > 0)
{
EDIT_UpdateUniscribeData_linedef(es, NULL, current_line);
sz = ScriptString_pSize(current_line->ssa);
current_line->width = sz->cx;
}
else current_line->width = 0;
} }
else if (current_line == start_line && else if (current_line == start_line &&
current_line->index != nstart_index && current_line->index != nstart_index &&
@ -627,6 +715,7 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta
while (current_line) while (current_line)
{ {
pnext = current_line->next; pnext = current_line->next;
EDIT_InvalidateUniscribeData_linedef(current_line);
HeapFree(GetProcessHeap(), 0, current_line); HeapFree(GetProcessHeap(), 0, current_line);
current_line = pnext; current_line = pnext;
es->line_count--; es->line_count--;
@ -656,9 +745,7 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta
if ((es->style & ES_CENTER) || (es->style & ES_RIGHT)) if ((es->style & ES_CENTER) || (es->style & ES_RIGHT))
rc.left = es->format_rect.left; rc.left = es->format_rect.left;
else else
rc.left = es->format_rect.left + (INT)LOWORD(GetTabbedTextExtentW(dc, rc.left = LOWORD(EDIT_EM_PosFromChar(es, nstart_index, FALSE));
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; rc.right = es->format_rect.right;
SetRectRgn(hrgn, rc.left, rc.top, rc.right, rc.bottom); SetRectRgn(hrgn, rc.left, rc.top, rc.right, rc.bottom);
@ -681,11 +768,6 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta
CombineRgn(hrgn, hrgn, tmphrgn, RGN_OR); CombineRgn(hrgn, hrgn, tmphrgn, RGN_OR);
DeleteObject(tmphrgn); DeleteObject(tmphrgn);
} }
if (es->font)
SelectObject(dc, old_font);
ReleaseDC(es->hwndSelf, dc);
} }
/********************************************************************* /*********************************************************************
@ -718,20 +800,19 @@ static void EDIT_CalcLineWidth_SL(EDITSTATE *es)
static INT EDIT_CharFromPos(EDITSTATE *es, INT x, INT y, LPBOOL after_wrap) static INT EDIT_CharFromPos(EDITSTATE *es, INT x, INT y, LPBOOL after_wrap)
{ {
INT index; INT index;
INT x_high = 0, x_low = 0;
if (es->style & ES_MULTILINE) { if (es->style & ES_MULTILINE) {
HDC dc; int trailing;
HFONT old_font = 0;
INT line = (y - es->format_rect.top) / es->line_height + es->y_offset; INT line = (y - es->format_rect.top) / es->line_height + es->y_offset;
INT line_index = 0; INT line_index = 0;
LINEDEF *line_def = es->first_line_def; LINEDEF *line_def = es->first_line_def;
INT low, high; EDIT_UpdateUniscribeData(es, NULL, line);
while ((line > 0) && line_def->next) { while ((line > 0) && line_def->next) {
line_index += line_def->length; line_index += line_def->length;
line_def = line_def->next; line_def = line_def->next;
line--; line--;
} }
x += es->x_offset - es->format_rect.left; x += es->x_offset - es->format_rect.left;
if (es->style & ES_RIGHT) if (es->style & ES_RIGHT)
x -= (es->format_rect.right - es->format_rect.left) - line_def->width; x -= (es->format_rect.right - es->format_rect.left) - line_def->width;
@ -747,34 +828,13 @@ static INT EDIT_CharFromPos(EDITSTATE *es, INT x, INT y, LPBOOL after_wrap)
*after_wrap = FALSE; *after_wrap = FALSE;
return line_index; return line_index;
} }
dc = GetDC(es->hwndSelf);
if (es->font)
old_font = SelectObject(dc, es->font);
low = line_index;
high = line_index + line_def->net_length + 1;
while (low < high - 1)
{
INT mid = (low + high) / 2;
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;
}
}
if (abs(x_high - x) + 1 <= abs(x_low - x))
index = high;
else
index = low;
ScriptStringXtoCP(line_def->ssa, x , &index, &trailing);
if (trailing) index++;
index += line_index;
if (after_wrap) if (after_wrap)
*after_wrap = ((index == line_index + line_def->net_length) && *after_wrap = ((index == line_index + line_def->net_length) &&
(line_def->ending == END_WRAP)); (line_def->ending == END_WRAP));
if (es->font)
SelectObject(dc, old_font);
ReleaseDC(es->hwndSelf, dc);
} else { } else {
INT xoff = 0; INT xoff = 0;
INT trailing; INT trailing;
@ -963,21 +1023,17 @@ static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap)
INT len = get_text_length(es); INT len = get_text_length(es);
INT l; INT l;
INT li; INT li;
INT x; INT x = 0;
INT y = 0; INT y = 0;
INT w; INT w;
INT lw = 0; INT lw = 0;
INT ll = 0;
HDC dc;
HFONT old_font = 0;
LINEDEF *line_def; LINEDEF *line_def;
index = min(index, len); index = min(index, len);
dc = GetDC(es->hwndSelf);
if (es->font)
old_font = SelectObject(dc, es->font);
if (es->style & ES_MULTILINE) { if (es->style & ES_MULTILINE) {
l = EDIT_EM_LineFromChar(es, index); l = EDIT_EM_LineFromChar(es, index);
EDIT_UpdateUniscribeData(es, NULL, l);
y = (l - es->y_offset) * es->line_height; y = (l - es->y_offset) * es->line_height;
li = EDIT_EM_LineIndex(es, l); li = EDIT_EM_LineIndex(es, l);
if (after_wrap && (li == index) && l) { if (after_wrap && (li == index) && l) {
@ -998,27 +1054,15 @@ static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap)
while (line_def->index != li) while (line_def->index != li)
line_def = line_def->next; line_def = line_def->next;
ll = line_def->net_length;
lw = line_def->width; lw = line_def->width;
w = es->format_rect.right - es->format_rect.left; w = es->format_rect.right - es->format_rect.left;
ScriptStringCPtoX(line_def->ssa, (index - 1) - li, TRUE, &x);
x -= es->x_offset;
if (es->style & ES_RIGHT) if (es->style & ES_RIGHT)
{ x = w - (lw - x);
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) 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; 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 { } else {
INT xoff = 0; INT xoff = 0;
INT xi = 0; INT xi = 0;
@ -1063,9 +1107,6 @@ static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap)
} }
x += es->format_rect.left; x += es->format_rect.left;
y += es->format_rect.top; y += es->format_rect.top;
if (es->font)
SelectObject(dc, old_font);
ReleaseDC(es->hwndSelf, dc);
return MAKELONG((INT16)x, (INT16)y); return MAKELONG((INT16)x, (INT16)y);
} }
@ -2102,6 +2143,32 @@ static void EDIT_PaintLine(EDITSTATE *es, HDC dc, INT line, BOOL rev)
pos = EDIT_EM_PosFromChar(es, EDIT_EM_LineIndex(es, line), FALSE); pos = EDIT_EM_PosFromChar(es, EDIT_EM_LineIndex(es, line), FALSE);
x = (short)LOWORD(pos); x = (short)LOWORD(pos);
y = (short)HIWORD(pos); y = (short)HIWORD(pos);
if (es->style & ES_MULTILINE)
{
int line_idx = line;
x = -es->x_offset;
if (es->style & ES_RIGHT || es->style & ES_CENTER)
{
LINEDEF *line_def = es->first_line_def;
int w, lw;
while (line_def && line_idx)
{
line_def = line_def->next;
line_idx--;
}
w = es->format_rect.right - es->format_rect.left;
lw = line_def->width;
if (es->style & ES_RIGHT)
x = w - (lw - x);
else if (es->style & ES_CENTER)
x += (w - lw) / 2;
}
x += es->format_rect.left;
}
li = EDIT_EM_LineIndex(es, line); li = EDIT_EM_LineIndex(es, line);
ll = EDIT_EM_LineLength(es, li); ll = EDIT_EM_LineLength(es, li);
s = min(es->selection_start, es->selection_end); s = min(es->selection_start, es->selection_end);
@ -2811,6 +2878,7 @@ static BOOL EDIT_EM_SetTabStops(EDITSTATE *es, INT count, const INT *tabs)
es->tabs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT)); es->tabs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
memcpy(es->tabs, tabs, count * sizeof(INT)); memcpy(es->tabs, tabs, count * sizeof(INT));
} }
EDIT_InvalidateUniscribeData(es);
return TRUE; return TRUE;
} }